diff options
author | isaacs <i@izs.me> | 2012-05-15 19:53:16 -0700 |
---|---|---|
committer | isaacs <i@izs.me> | 2012-05-16 14:22:33 -0700 |
commit | 3f3f958c14cf4e963a73d6f037ac381c77fe78bb (patch) | |
tree | 391e35b59e76d038534fbd375f1bbe0dc55076cf | |
parent | 4099d1eebae4e78864a6879c0b9e08f31d48d8cb (diff) | |
download | node-new-3f3f958c14cf4e963a73d6f037ac381c77fe78bb.tar.gz |
Upgrade V8 to 3.11.1
297 files changed, 25594 insertions, 6834 deletions
diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index dfefad129f..6e46b3d621 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -23,6 +23,7 @@ Daniel James <dnljms@gmail.com> Dineel D Sule <dsule@codeaurora.org> Erich Ocean <erich.ocean@me.com> Fedor Indutny <fedor@indutny.com> +Filipe David Manana <fdmanana@gmail.com> Ioseb Dzmanashvili <ioseb.dzmanashvili@gmail.com> Jan de Mooij <jandemooij@gmail.com> Jay Freeman <saurik@saurik.com> diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 2240ec0e68..c52a5abc5f 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,208 @@ +2012-05-15: Version 3.11.1 + + Added a readbuffer function to d8 that reads a file into an ArrayBuffer. + + Fix freebsd build. (V8 issue 2126) + + Performance and stability improvements on all platforms. + + +2012-05-11: Version 3.11.0 + + Fixed compose-discard crasher from r11524 (issue 2123). + + Activated new global semantics by default. Global variables can + now shadow properties of the global object (ES5.1 erratum). + + Properly set ElementsKind of empty FAST_DOUBLE_ELEMENTS arrays when + transitioning (Chromium issue 117409). + + Made Error.prototype.name writable again, as required by the spec and + the web (Chromium issue 69187). + + Implemented map collection with incremental marking (issue 1465). + + Regexp: Fixed overflow in min-match-length calculation + (Chromium issue 126412). + + MIPS: Fixed illegal instruction use on Loongson in code for + Math.random() (issue 2115). + + Fixed crash bug in VisitChoice (Chromium issue 126272). + + Fixed unsigned-Smi check in MappedArgumentsLookup + (Chromium issue 126414). + + Fixed LiveEdit for function with no locals (issue 825). + + Fixed register clobbering in LoadIC for interceptors + (Chromium issue 125988). + + Implemented clearing of CompareICs (issue 2102). + + Performance and stability improvements on all platforms. + + +2012-05-03: Version 3.10.8 + + Enabled MIPS cross-compilation. + + Ensured reload of elements pointer in StoreFastDoubleElement stub. + (Chromium issue 125515) + + Fixed corner cases in truncation behavior when storing to + TypedArrays. (issue 2110) + + Fixed failure to properly recognize and report out-of-memory + conditions when allocating code space pages. (Chromium issue + 118625) + + Fixed idle notifications to perform a round of incremental GCs + after context disposal. (issue 2107) + + Fixed preparser for try statement. (issue 2109) + + Performance and stability improvements on all platforms. + + +2012-04-30: Version 3.10.7 + + Performance and stability improvements on all platforms. + + +2012-04-26: Version 3.10.6 + + Fixed some bugs in accessing details of the last regexp match. + + Fixed source property of empty RegExp objects. (issue 1982) + + Enabled inlining some V8 API functions. + + Performance and stability improvements on all platforms. + + +2012-04-23: Version 3.10.5 + + Put new global var semantics behind a flag until WebKit tests are + cleaned up. + + Enabled stepping into callback passed to builtins. + (Chromium issue 109564) + + Performance and stability improvements on all platforms. + + +2012-04-19: Version 3.10.4 + + Fixed issues when stressing compaction with WeakMaps. + + Fixed missing GVN flag for new-space promotion. (Chromium issue 123919) + + Simplify invocation sequence at monomorphic function invocation sites. + (issue 2079) + + Performance and stability improvements on all platforms. + + +2012-04-17: Version 3.10.3 + + Fixed several bugs in heap profiles (including issue 2078). + + Throw syntax errors on illegal escape sequences. + + Implemented rudimentary module linking (behind --harmony flag) + + Implemented ES5 erratum: Global declarations should shadow + inherited properties. + + Made handling of const more consistent when combined with 'eval' + and 'with'. + + Fixed V8 on MinGW-x64 (issue 2026). + + Performance and stability improvements on all platforms. + + +2012-04-13: Version 3.10.2 + + Fixed native ARM build (issues 1744, 539) + + Return LOOKUP variable instead of CONTEXT for non-context allocated + outer scope parameters (Chromium issue 119609). + + Fixed regular and ElementsKind transitions interfering with each other + (Chromium issue 122271). + + Improved performance of keyed loads/stores which have a HeapNumber + index (issues 1388, 1295). + + Fixed WeakMap processing for evacuation candidates (issue 2060). + + Bailout on possible direct eval calls (Chromium issue 122681). + + Do not assume that names of function expressions are context-allocated + (issue 2051). + + Performance and stability improvements on all platforms. + + +2012-04-10: Version 3.10.1 + + Fixed bug with arguments object in inlined functions (issue 2045). + + Fixed performance bug with lazy initialization (Chromium issue + 118686). + + Added suppport for Mac OS X 64bit builds with GYP. + (Patch contributed by Filipe David Manana <fdmanana@gmail.com>) + + Fixed bug with hidden properties (issue 2034). + + Fixed a performance bug when reloading pages (Chromium issue 117767, + V8 issue 1902). + + Fixed bug when optimizing throw in top-level code (issue 2054). + + Fixed two bugs with array literals (issue 2055, Chromium issue 121407). + + Fixed bug with Math.min/Math.max with NaN inputs (issue 2056). + + Fixed a bug with the new runtime profiler (Chromium issue 121147). + + Fixed compilation of V8 using uClibc. + + Optimized boot-up memory use. + + Optimized regular expressions. + + +2012-03-30: Version 3.10.0 + + Fixed store IC writability check in strict mode + (Chromium issue 120099). + + Resynchronize timers if the Windows system time was changed. + (Chromium issue 119815) + + Removed "-mfloat-abi=hard" from host compiler cflags when building for + hardfp ARM + (https://code.google.com/p/chrome-os-partner/issues/detail?id=8539) + + Fixed edge case for case independent regexp character classes + (issue 2032). + + Reset function info counters after context disposal. + (Chromium issue 117767, V8 issue 1902) + + Fixed missing write barrier in CopyObjectToObjectElements. + (Chromium issue 119926) + + Fixed missing bounds check in HasElementImpl. + (Chromium issue 119925) + + Performance and stability improvements on all platforms. + + 2012-03-23: Version 3.9.24 Activated count-based profiler for ARM. diff --git a/deps/v8/DEPS b/deps/v8/DEPS new file mode 100644 index 0000000000..e50d1d20f6 --- /dev/null +++ b/deps/v8/DEPS @@ -0,0 +1,27 @@ +# Note: The buildbots evaluate this file with CWD set to the parent +# directory and assume that the root of the checkout is in ./v8/, so +# all paths in here must match this assumption. + +deps = { + # Remember to keep the revision in sync with the Makefile. + "v8/build/gyp": + "http://gyp.googlecode.com/svn/trunk@1282", +} + +deps_os = { + "win": { + "v8/third_party/cygwin": + "http://src.chromium.org/svn/trunk/deps/third_party/cygwin@66844", + + "v8/third_party/python_26": + "http://src.chromium.org/svn/trunk/tools/third_party/python_26@89111", + } +} + +hooks = [ + { + # A change to a .gyp, .gypi, or to GYP itself should run the generator. + "pattern": ".", + "action": ["python", "v8/build/gyp_v8"], + }, +] diff --git a/deps/v8/Makefile b/deps/v8/Makefile index 5dc6ca5ad6..fbca56644c 100644 --- a/deps/v8/Makefile +++ b/deps/v8/Makefile @@ -137,6 +137,12 @@ ENVFILE = $(OUTDIR)/environment # Target definitions. "all" is the default. all: $(MODES) +# Special target for the buildbots to use. Depends on $(OUTDIR)/Makefile +# having been created before. +buildbot: + $(MAKE) -C "$(OUTDIR)" BUILDTYPE=$(BUILDTYPE) \ + builddir="$(abspath $(OUTDIR))/$(BUILDTYPE)" + # Compile targets. MODES and ARCHES are convenience targets. .SECONDEXPANSION: $(MODES): $(addsuffix .$$@,$(DEFAULT_ARCHES)) @@ -144,21 +150,21 @@ $(MODES): $(addsuffix .$$@,$(DEFAULT_ARCHES)) $(ARCHES): $(addprefix $$@.,$(MODES)) # Defines how to build a particular target (e.g. ia32.release). -$(BUILDS): $(OUTDIR)/Makefile-$$(basename $$@) - @$(MAKE) -C "$(OUTDIR)" -f Makefile-$(basename $@) \ +$(BUILDS): $(OUTDIR)/Makefile.$$(basename $$@) + @$(MAKE) -C "$(OUTDIR)" -f Makefile.$(basename $@) \ CXX="$(CXX)" LINK="$(LINK)" \ BUILDTYPE=$(shell echo $(subst .,,$(suffix $@)) | \ python -c "print raw_input().capitalize()") \ builddir="$(shell pwd)/$(OUTDIR)/$@" -native: $(OUTDIR)/Makefile-native - @$(MAKE) -C "$(OUTDIR)" -f Makefile-native \ +native: $(OUTDIR)/Makefile.native + @$(MAKE) -C "$(OUTDIR)" -f Makefile.native \ CXX="$(CXX)" LINK="$(LINK)" BUILDTYPE=Release \ builddir="$(shell pwd)/$(OUTDIR)/$@" # TODO(jkummerow): add "android.debug" when we need it. -android android.release: $(OUTDIR)/Makefile-android - @$(MAKE) -C "$(OUTDIR)" -f Makefile-android \ +android android.release: $(OUTDIR)/Makefile.android + @$(MAKE) -C "$(OUTDIR)" -f Makefile.android \ CXX="$(ANDROID_TOOL_PREFIX)-g++" \ AR="$(ANDROID_TOOL_PREFIX)-ar" \ RANLIB="$(ANDROID_TOOL_PREFIX)-ranlib" \ @@ -191,55 +197,40 @@ native.check: native --arch-and-mode=. $(TESTFLAGS) # Clean targets. You can clean each architecture individually, or everything. -$(addsuffix .clean,$(ARCHES)): - rm -f $(OUTDIR)/Makefile-$(basename $@) +$(addsuffix .clean,$(ARCHES)) android.clean: + rm -f $(OUTDIR)/Makefile.$(basename $@) rm -rf $(OUTDIR)/$(basename $@).release rm -rf $(OUTDIR)/$(basename $@).debug - find $(OUTDIR) -regex '.*\(host\|target\)-$(basename $@)\.mk' -delete + find $(OUTDIR) -regex '.*\(host\|target\).$(basename $@)\.mk' -delete native.clean: - rm -f $(OUTDIR)/Makefile-native + rm -f $(OUTDIR)/Makefile.native rm -rf $(OUTDIR)/native - find $(OUTDIR) -regex '.*\(host\|target\)-native\.mk' -delete - -android.clean: - rm -f $(OUTDIR)/Makefile-android - rm -rf $(OUTDIR)/android.release - find $(OUTDIR) -regex '.*\(host\|target\)-android\.mk' -delete + find $(OUTDIR) -regex '.*\(host\|target\).native\.mk' -delete -clean: $(addsuffix .clean,$(ARCHES)) native.clean +clean: $(addsuffix .clean,$(ARCHES)) native.clean android.clean # GYP file generation targets. -$(OUTDIR)/Makefile-ia32: $(GYPFILES) $(ENVFILE) - build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ - -Ibuild/standalone.gypi --depth=. -Dtarget_arch=ia32 \ - -S-ia32 $(GYPFLAGS) - -$(OUTDIR)/Makefile-x64: $(GYPFILES) $(ENVFILE) - build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ - -Ibuild/standalone.gypi --depth=. -Dtarget_arch=x64 \ - -S-x64 $(GYPFLAGS) - -$(OUTDIR)/Makefile-arm: $(GYPFILES) $(ENVFILE) build/armu.gypi - build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ - -Ibuild/standalone.gypi --depth=. -Ibuild/armu.gypi \ - -S-arm $(GYPFLAGS) - -$(OUTDIR)/Makefile-mips: $(GYPFILES) $(ENVFILE) build/mipsu.gypi +MAKEFILES = $(addprefix $(OUTDIR)/Makefile.,$(ARCHES)) +$(MAKEFILES): $(GYPFILES) $(ENVFILE) + GYP_GENERATORS=make \ build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ - -Ibuild/standalone.gypi --depth=. -Ibuild/mipsu.gypi \ - -S-mips $(GYPFLAGS) + -Ibuild/standalone.gypi --depth=. \ + -Dv8_target_arch=$(subst .,,$(suffix $@)) \ + -S.$(subst .,,$(suffix $@)) $(GYPFLAGS) -$(OUTDIR)/Makefile-native: $(GYPFILES) $(ENVFILE) +$(OUTDIR)/Makefile.native: $(GYPFILES) $(ENVFILE) + GYP_GENERATORS=make \ build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ - -Ibuild/standalone.gypi --depth=. -S-native $(GYPFLAGS) + -Ibuild/standalone.gypi --depth=. -S.native $(GYPFLAGS) -$(OUTDIR)/Makefile-android: $(GYPFILES) $(ENVFILE) build/android.gypi \ +$(OUTDIR)/Makefile.android: $(GYPFILES) $(ENVFILE) build/android.gypi \ must-set-ANDROID_NDK_ROOT + GYP_GENERATORS=make \ CC="${ANDROID_TOOL_PREFIX}-gcc" \ build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ -Ibuild/standalone.gypi --depth=. -Ibuild/android.gypi \ - -S-android $(GYPFLAGS) + -S.android $(GYPFLAGS) must-set-ANDROID_NDK_ROOT: ifndef ANDROID_NDK_ROOT @@ -255,9 +246,10 @@ $(ENVFILE): $(ENVFILE).new # Stores current GYPFLAGS in a file. $(ENVFILE).new: - @mkdir -p $(OUTDIR); echo "GYPFLAGS=$(GYPFLAGS)" > $(ENVFILE).new; + @mkdir -p $(OUTDIR); echo "GYPFLAGS=$(GYPFLAGS)" > $(ENVFILE).new; \ + echo "CXX=$(CXX)" >> $(ENVFILE).new # Dependencies. dependencies: svn checkout --force http://gyp.googlecode.com/svn/trunk build/gyp \ - --revision 1026 + --revision 1282 diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index 34d0efc5ff..b0d1344700 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -1601,4 +1601,17 @@ except: pass +def WarnAboutDeprecation(): + print """ +####################################################### +# WARNING: Building V8 with SCons is deprecated and # +# will not work much longer. Please switch to using # +# the GYP-based build now. Instructions are at # +# http://code.google.com/p/v8/wiki/BuildingWithGYP. # +####################################################### + """ + +WarnAboutDeprecation() +import atexit +atexit.register(WarnAboutDeprecation) Build() diff --git a/deps/v8/build/armu.gypi b/deps/v8/build/armu.gypi deleted file mode 100644 index d15b8ab705..0000000000 --- a/deps/v8/build/armu.gypi +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2011 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -# OWNER 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. - -{ - 'variables': { - 'target_arch': 'ia32', - 'v8_target_arch': 'arm', - 'armv7': 1, - 'arm_neon': 0, - 'arm_fpu': 'vfpv3', - }, -} diff --git a/deps/v8/build/common.gypi b/deps/v8/build/common.gypi index f2bb465c1e..4a9d45dd14 100644 --- a/deps/v8/build/common.gypi +++ b/deps/v8/build/common.gypi @@ -142,8 +142,10 @@ 'USE_EABI_HARDFLOAT=1', 'CAN_USE_VFP_INSTRUCTIONS', ], - 'cflags': [ - '-mfloat-abi=hard', + 'target_conditions': [ + ['_toolset=="target"', { + 'cflags': ['-mfloat-abi=hard',], + }], ], }, { 'defines': [ @@ -171,8 +173,11 @@ 'defines': [ 'V8_TARGET_ARCH_MIPS', ], + 'variables': { + 'mipscompiler': '<!($(echo ${CXX:-$(which g++)}) -v 2>&1 | grep -q "^Target: mips-" && echo "yes" || echo "no")', + }, 'conditions': [ - [ 'target_arch=="mips"', { + ['mipscompiler=="yes"', { 'target_conditions': [ ['_toolset=="target"', { 'cflags': ['-EL'], @@ -236,6 +241,19 @@ ], }], ], + }, { # Section for OS=="mac". + 'conditions': [ + ['target_arch=="ia32"', { + 'xcode_settings': { + 'ARCHS': ['i386'], + } + }], + ['target_arch=="x64"', { + 'xcode_settings': { + 'ARCHS': ['x86_64'], + } + }], + ], }], ['v8_use_liveobjectlist=="true"', { 'defines': [ @@ -262,12 +280,23 @@ }, }, }], + ['OS=="win" and v8_target_arch=="x64"', { + 'msvs_settings': { + 'VCLinkerTool': { + 'StackReserveSize': '2097152', + }, + }, + }], ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \ or OS=="netbsd"', { 'conditions': [ - [ 'target_arch=="ia32"', { - 'cflags': [ '-m32' ], - 'ldflags': [ '-m32' ], + [ 'v8_target_arch!="x64"', { + # Pass -m32 to the compiler iff it understands the flag. + 'variables': { + 'm32flag': '<!((echo | $(echo ${CXX:-$(which g++)}) -m32 -E - > /dev/null 2>&1) && echo -n "-m32" || true)', + }, + 'cflags': [ '<(m32flag)' ], + 'ldflags': [ '<(m32flag)' ], }], [ 'v8_no_strict_aliasing==1', { 'cflags': [ '-fno-strict-aliasing' ], @@ -300,10 +329,6 @@ }, 'VCLinkerTool': { 'LinkIncremental': '2', - # For future reference, the stack size needs to be increased - # when building for Windows 64-bit, otherwise some test cases - # can cause stack overflow. - # 'StackReserveSize': '297152', }, }, 'conditions': [ @@ -314,7 +339,7 @@ 'cflags': [ '-I/usr/pkg/include' ], }], ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { - 'cflags': [ '-Wno-unused-parameter', + 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', '-Wnon-virtual-dtor', '-Woverloaded-virtual' ], }], ], @@ -361,6 +386,7 @@ }], # OS=="mac" ['OS=="win"', { 'msvs_configuration_attributes': { + 'OutputDirectory': '<(DEPTH)\\build\\$(ConfigurationName)', 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)', 'CharacterSet': '1', }, @@ -384,12 +410,7 @@ 'VCLinkerTool': { 'LinkIncremental': '1', 'OptimizeReferences': '2', - 'OptimizeForWindows98': '1', 'EnableCOMDATFolding': '2', - # For future reference, the stack size needs to be - # increased when building for Windows 64-bit, otherwise - # some test cases can cause stack overflow. - # 'StackReserveSize': '297152', }, }, }], # OS=="win" diff --git a/deps/v8/build/gyp_v8 b/deps/v8/build/gyp_v8 index 4293e7637e..345f777d79 100755 --- a/deps/v8/build/gyp_v8 +++ b/deps/v8/build/gyp_v8 @@ -1,6 +1,6 @@ #!/usr/bin/python # -# Copyright 2010 the V8 project authors. All rights reserved. +# Copyright 2012 the V8 project authors. All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: @@ -38,6 +38,11 @@ import sys script_dir = os.path.dirname(__file__) v8_root = os.path.normpath(os.path.join(script_dir, os.pardir)) +if __name__ == '__main__': + os.chdir(v8_root) + script_dir = os.path.dirname(__file__) + v8_root = '.' + sys.path.insert(0, os.path.join(v8_root, 'tools')) import utils @@ -93,7 +98,7 @@ def additional_include_files(args=[]): result.append(path) # Always include standalone.gypi - AddInclude(os.path.join(script_dir, 'standalone.gypi')) + AddInclude(os.path.join(v8_root, 'build', 'standalone.gypi')) # Optionally add supplemental .gypi files if present. supplements = glob.glob(os.path.join(v8_root, '*', 'supplement.gypi')) @@ -135,7 +140,10 @@ if __name__ == '__main__': # path separators even on Windows due to the use of shlex.split(). args.extend(shlex.split(gyp_file)) else: - args.append(os.path.join(script_dir, 'all.gyp')) + # Note that this must not start with "./" or things break. + # So we rely on having done os.chdir(v8_root) above and use the + # relative path. + args.append(os.path.join('build', 'all.gyp')) args.extend(['-I' + i for i in additional_include_files(args)]) @@ -156,23 +164,6 @@ if __name__ == '__main__': # Generate for the architectures supported on the given platform. gyp_args = list(args) - gyp_args.append('-Dtarget_arch=ia32') if utils.GuessOS() == 'linux': - gyp_args.append('-S-ia32') + gyp_args.append('--generator-output=out') run_gyp(gyp_args) - - if utils.GuessOS() == 'linux': - gyp_args = list(args) - gyp_args.append('-Dtarget_arch=x64') - gyp_args.append('-S-x64') - run_gyp(gyp_args) - - gyp_args = list(args) - gyp_args.append('-I' + v8_root + '/build/armu.gypi') - gyp_args.append('-S-armu') - run_gyp(gyp_args) - - gyp_args = list(args) - gyp_args.append('-I' + v8_root + '/build/mipsu.gypi') - gyp_args.append('-S-mipsu') - run_gyp(gyp_args) diff --git a/deps/v8/build/mipsu.gypi b/deps/v8/build/mipsu.gypi deleted file mode 100644 index 637ff841e4..0000000000 --- a/deps/v8/build/mipsu.gypi +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2012 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -# OWNER 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. - -{ - 'variables': { - 'target_arch': 'ia32', - 'v8_target_arch': 'mips', - }, -} diff --git a/deps/v8/build/standalone.gypi b/deps/v8/build/standalone.gypi index e9b056580d..ebdf557230 100644 --- a/deps/v8/build/standalone.gypi +++ b/deps/v8/build/standalone.gypi @@ -37,8 +37,9 @@ 'variables': { 'variables': { 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { - # This handles the Linux platforms we generally deal with. + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or \ + OS=="netbsd" or OS=="mac"', { + # This handles the Unix platforms we generally deal with. # Anything else gets passed through, which probably won't work # very well; such hosts should pass an explicit target_arch # to gyp. @@ -46,7 +47,8 @@ '<!(uname -m | sed -e "s/i.86/ia32/;\ s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/;s/mips.*/mips/")', }, { - # OS!="linux" and OS!="freebsd" and OS!="openbsd" and OS!="netbsd" + # OS!="linux" and OS!="freebsd" and OS!="openbsd" and + # OS!="netbsd" and OS!="mac" 'host_arch%': 'ia32', }], ], @@ -71,6 +73,10 @@ 'want_separate_host_toolset': 0, }], ], + # Default ARM variable settings. + 'armv7%': 1, + 'arm_neon%': 0, + 'arm_fpu%': 'vfpv3', }, 'target_defaults': { 'default_configuration': 'Debug', @@ -165,6 +171,9 @@ }, }], # OS=="win" ['OS=="mac"', { + 'xcode_settings': { + 'SYMROOT': '<(DEPTH)/xcodebuild', + }, 'target_defaults': { 'xcode_settings': { 'ALWAYS_SEARCH_USER_PATHS': 'NO', @@ -184,6 +193,7 @@ 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof 'MACOSX_DEPLOYMENT_TARGET': '10.4', # -mmacosx-version-min=10.4 'PREBINDING': 'NO', # No -Wl,-prebind + 'SYMROOT': '<(DEPTH)/xcodebuild', 'USE_HEADERMAP': 'NO', 'OTHER_CFLAGS': [ '-fno-strict-aliasing', diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index 2499bbf050..8f380f2094 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -64,6 +64,7 @@ */ namespace v8 { +typedef uint32_t SnapshotObjectId; /** * CpuProfileNode represents a node in a call graph. @@ -274,7 +275,7 @@ class V8EXPORT HeapGraphNode { * Returns node id. For the same heap object, the id remains the same * across all snapshots. */ - uint64_t GetId() const; + SnapshotObjectId GetId() const; /** Returns node's own size, in bytes. */ int GetSelfSize() const; @@ -338,7 +339,7 @@ class V8EXPORT HeapSnapshot { const HeapGraphNode* GetRoot() const; /** Returns a node by its id. */ - const HeapGraphNode* GetNodeById(uint64_t id) const; + const HeapGraphNode* GetNodeById(SnapshotObjectId id) const; /** Returns total nodes count in the snapshot. */ int GetNodesCount() const; @@ -346,6 +347,9 @@ class V8EXPORT HeapSnapshot { /** Returns a node by index. */ const HeapGraphNode* GetNode(int index) const; + /** Returns a max seen JS object Id. */ + SnapshotObjectId GetMaxSnapshotJSObjectId() const; + /** * Deletes the snapshot and removes it from HeapProfiler's list. * All pointers to nodes, edges and paths previously returned become @@ -364,16 +368,20 @@ class V8EXPORT HeapSnapshot { * with the following structure: * * { - * snapshot: {title: "...", uid: nnn}, - * nodes: [ - * meta-info (JSON string), - * nodes themselves - * ], - * strings: [strings] + * snapshot: { + * title: "...", + * uid: nnn, + * meta: { meta-info }, + * node_count: nnn, + * edge_count: nnn + * }, + * nodes: [nodes array], + * edges: [edges array], + * strings: [strings array] * } * - * Outgoing node links are stored after each node. Nodes reference strings - * and other nodes by their indexes in corresponding arrays. + * Nodes reference strings, other nodes, and edges by their indexes + * in corresponding arrays. */ void Serialize(OutputStream* stream, SerializationFormat format) const; }; @@ -405,6 +413,19 @@ class V8EXPORT HeapProfiler { static const HeapSnapshot* FindSnapshot(unsigned uid); /** + * Returns SnapshotObjectId for a heap object referenced by |value| if + * it has been seen by the heap profiler, kUnknownObjectId otherwise. + */ + static SnapshotObjectId GetSnapshotObjectId(Handle<Value> value); + + /** + * A constant for invalid SnapshotObjectId. GetSnapshotObjectId will return + * it in case heap profiler cannot find id for the object passed as + * parameter. HeapSnapshot::GetNodeById will always return NULL for such id. + */ + static const SnapshotObjectId kUnknownObjectId = 0; + + /** * Takes a heap snapshot and returns it. Title may be an empty string. * See HeapSnapshot::Type for types description. */ @@ -414,6 +435,33 @@ class V8EXPORT HeapProfiler { ActivityControl* control = NULL); /** + * Starts tracking of heap objects population statistics. After calling + * this method, all heap objects relocations done by the garbage collector + * are being registered. + */ + static void StartHeapObjectsTracking(); + + /** + * Adds a new time interval entry to the aggregated statistics array. The + * time interval entry contains information on the current heap objects + * population size. The method also updates aggregated statistics and + * reports updates for all previous time intervals via the OutputStream + * object. Updates on each time interval are provided as a stream of the + * HeapStatsUpdate structure instances. + * + * StartHeapObjectsTracking must be called before the first call to this + * method. + */ + static void PushHeapObjectsStats(OutputStream* stream); + + /** + * Stops tracking of heap objects population statistics, cleans up all + * collected data. StartHeapObjectsTracking must be called again prior to + * calling PushHeapObjectsStats next time. + */ + static void StopHeapObjectsTracking(); + + /** * Deletes all snapshots taken. All previously returned pointers to * snapshots and their contents become invalid after this call. */ @@ -510,6 +558,19 @@ class V8EXPORT RetainedObjectInfo { // NOLINT }; +/** + * A struct for exporting HeapStats data from V8, using "push" model. + * See HeapProfiler::PushHeapObjectsStats. + */ +struct HeapStatsUpdate { + HeapStatsUpdate(uint32_t index, uint32_t count, uint32_t size) + : index(index), count(count), size(size) { } + uint32_t index; // Index of the time interval that was changed. + uint32_t count; // New value of count field for the interval with this index. + uint32_t size; // New value of size field for the interval with this index. +}; + + } // namespace v8 diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 33179f5bf0..9024531992 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -107,6 +107,7 @@ class Data; class AccessorInfo; class StackTrace; class StackFrame; +class Isolate; namespace internal { @@ -862,13 +863,13 @@ class Value : public Data { * Returns true if this value is the undefined value. See ECMA-262 * 4.3.10. */ - V8EXPORT bool IsUndefined() const; + inline bool IsUndefined() const; /** * Returns true if this value is the null value. See ECMA-262 * 4.3.11. */ - V8EXPORT bool IsNull() const; + inline bool IsNull() const; /** * Returns true if this value is true. @@ -982,7 +983,11 @@ class Value : public Data { V8EXPORT bool StrictEquals(Handle<Value> that) const; private: + inline bool QuickIsUndefined() const; + inline bool QuickIsNull() const; inline bool QuickIsString() const; + V8EXPORT bool FullIsUndefined() const; + V8EXPORT bool FullIsNull() const; V8EXPORT bool FullIsString() const; }; @@ -1079,6 +1084,7 @@ class String : public Primitive { * A zero length string. */ V8EXPORT static v8::Local<v8::String> Empty(); + inline static v8::Local<v8::String> Empty(Isolate* isolate); /** * Returns true if the string is external @@ -1236,8 +1242,7 @@ class String : public Primitive { * this function should not otherwise delete or modify the resource. Neither * should the underlying buffer be deallocated or modified except through the * destructor of the external string resource. - */ - V8EXPORT static Local<String> NewExternal( + */ V8EXPORT static Local<String> NewExternal( ExternalAsciiStringResource* resource); /** @@ -1968,10 +1973,13 @@ class Arguments { inline Local<Object> Holder() const; inline bool IsConstructCall() const; inline Local<Value> Data() const; + inline Isolate* GetIsolate() const; + private: - static const int kDataIndex = 0; - static const int kCalleeIndex = -1; - static const int kHolderIndex = -2; + static const int kIsolateIndex = 0; + static const int kDataIndex = -1; + static const int kCalleeIndex = -2; + static const int kHolderIndex = -3; friend class ImplementationUtilities; inline Arguments(internal::Object** implicit_args, @@ -1993,9 +2001,11 @@ class V8EXPORT AccessorInfo { public: inline AccessorInfo(internal::Object** args) : args_(args) { } + inline Isolate* GetIsolate() const; inline Local<Value> Data() const; inline Local<Object> This() const; inline Local<Object> Holder() const; + private: internal::Object** args_; }; @@ -2552,6 +2562,11 @@ Handle<Primitive> V8EXPORT Null(); Handle<Boolean> V8EXPORT True(); Handle<Boolean> V8EXPORT False(); +inline Handle<Primitive> Undefined(Isolate* isolate); +inline Handle<Primitive> Null(Isolate* isolate); +inline Handle<Boolean> True(Isolate* isolate); +inline Handle<Boolean> False(Isolate* isolate); + /** * A set of constraints that specifies the limits of the runtime's memory use. @@ -2802,13 +2817,13 @@ class V8EXPORT Isolate { /** * Associate embedder-specific data with the isolate */ - void SetData(void* data); + inline void SetData(void* data); /** - * Retrive embedder-specific data from the isolate. + * Retrieve embedder-specific data from the isolate. * Returns NULL if SetData has never been called. */ - void* GetData(); + inline void* GetData(); private: Isolate(); @@ -3153,7 +3168,8 @@ class V8EXPORT V8 { * that is kept alive by JavaScript objects. * \returns the adjusted value. */ - static int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes); + static intptr_t AdjustAmountOfExternalAllocatedMemory( + intptr_t change_in_bytes); /** * Suspends recording of tick samples in the profiler. @@ -3736,6 +3752,12 @@ class V8EXPORT Locker { /** + * A struct for exporting HeapStats data from V8, using "push" model. + */ +struct HeapStatsUpdate; + + +/** * An interface for exporting data from V8, using "push" model. */ class V8EXPORT OutputStream { // NOLINT @@ -3760,6 +3782,14 @@ class V8EXPORT OutputStream { // NOLINT * will not be called in case writing was aborted. */ virtual WriteResult WriteAsciiChunk(char* data, int size) = 0; + /** + * Writes the next chunk of heap stats data into the stream. Writing + * can be stopped by returning kAbort as function result. EndOfStream + * will not be called in case writing was aborted. + */ + virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate* data, int count) { + return kAbort; + }; }; @@ -3848,18 +3878,6 @@ const uintptr_t kEncodablePointerMask = PlatformSmiTagging::kEncodablePointerMask; const int kPointerToSmiShift = PlatformSmiTagging::kPointerToSmiShift; -template <size_t ptr_size> struct InternalConstants; - -// Internal constants for 32-bit systems. -template <> struct InternalConstants<4> { - static const int kStringResourceOffset = 3 * kApiPointerSize; -}; - -// Internal constants for 64-bit systems. -template <> struct InternalConstants<8> { - static const int kStringResourceOffset = 3 * kApiPointerSize; -}; - /** * This class exports constants and functionality from within v8 that * is necessary to implement inline functions in the v8 api. Don't @@ -3871,18 +3889,31 @@ class Internals { // the implementation of v8. static const int kHeapObjectMapOffset = 0; static const int kMapInstanceTypeOffset = 1 * kApiPointerSize + kApiIntSize; - static const int kStringResourceOffset = - InternalConstants<kApiPointerSize>::kStringResourceOffset; + static const int kStringResourceOffset = 3 * kApiPointerSize; + static const int kOddballKindOffset = 3 * kApiPointerSize; static const int kForeignAddressOffset = kApiPointerSize; static const int kJSObjectHeaderSize = 3 * kApiPointerSize; static const int kFullStringRepresentationMask = 0x07; static const int kExternalTwoByteRepresentationTag = 0x02; + static const int kIsolateStateOffset = 0; + static const int kIsolateEmbedderDataOffset = 1 * kApiPointerSize; + static const int kIsolateRootsOffset = 3 * kApiPointerSize; + static const int kUndefinedValueRootIndex = 5; + static const int kNullValueRootIndex = 7; + static const int kTrueValueRootIndex = 8; + static const int kFalseValueRootIndex = 9; + static const int kEmptySymbolRootIndex = 128; + static const int kJSObjectType = 0xaa; static const int kFirstNonstringType = 0x80; + static const int kOddballType = 0x82; static const int kForeignType = 0x85; + static const int kUndefinedOddballKind = 5; + static const int kNullOddballKind = 3; + static inline bool HasHeapObjectTag(internal::Object* value) { return ((reinterpret_cast<intptr_t>(value) & kHeapObjectTagMask) == kHeapObjectTag); @@ -3902,6 +3933,11 @@ class Internals { return ReadField<uint8_t>(map, kMapInstanceTypeOffset); } + static inline int GetOddballKind(internal::Object* obj) { + typedef internal::Object O; + return SmiValue(ReadField<O*>(obj, kOddballKindOffset)); + } + static inline void* GetExternalPointerFromSmi(internal::Object* value) { const uintptr_t address = reinterpret_cast<uintptr_t>(value); return reinterpret_cast<void*>(address >> kPointerToSmiShift); @@ -3922,6 +3958,28 @@ class Internals { return representation == kExternalTwoByteRepresentationTag; } + static inline bool IsInitialized(v8::Isolate* isolate) { + uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) + kIsolateStateOffset; + return *reinterpret_cast<int*>(addr) == 1; + } + + static inline void SetEmbedderData(v8::Isolate* isolate, void* data) { + uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) + + kIsolateEmbedderDataOffset; + *reinterpret_cast<void**>(addr) = data; + } + + static inline void* GetEmbedderData(v8::Isolate* isolate) { + uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) + + kIsolateEmbedderDataOffset; + return *reinterpret_cast<void**>(addr); + } + + static inline internal::Object** GetRoot(v8::Isolate* isolate, int index) { + uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) + kIsolateRootsOffset; + return reinterpret_cast<internal::Object**>(addr + index * kApiPointerSize); + } + template <typename T> static inline T ReadField(Object* ptr, int offset) { uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag; @@ -4048,6 +4106,11 @@ Local<Value> Arguments::Data() const { } +Isolate* Arguments::GetIsolate() const { + return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]); +} + + bool Arguments::IsConstructCall() const { return is_construct_call_; } @@ -4160,6 +4223,15 @@ String* String::Cast(v8::Value* value) { } +Local<String> String::Empty(Isolate* isolate) { + typedef internal::Object* S; + typedef internal::Internals I; + if (!I::IsInitialized(isolate)) return Empty(); + S* slot = I::GetRoot(isolate, I::kEmptySymbolRootIndex); + return Local<String>(reinterpret_cast<String*>(slot)); +} + + String::ExternalStringResource* String::GetExternalStringResource() const { typedef internal::Object O; typedef internal::Internals I; @@ -4178,6 +4250,42 @@ String::ExternalStringResource* String::GetExternalStringResource() const { } +bool Value::IsUndefined() const { +#ifdef V8_ENABLE_CHECKS + return FullIsUndefined(); +#else + return QuickIsUndefined(); +#endif +} + +bool Value::QuickIsUndefined() const { + typedef internal::Object O; + typedef internal::Internals I; + O* obj = *reinterpret_cast<O**>(const_cast<Value*>(this)); + if (!I::HasHeapObjectTag(obj)) return false; + if (I::GetInstanceType(obj) != I::kOddballType) return false; + return (I::GetOddballKind(obj) == I::kUndefinedOddballKind); +} + + +bool Value::IsNull() const { +#ifdef V8_ENABLE_CHECKS + return FullIsNull(); +#else + return QuickIsNull(); +#endif +} + +bool Value::QuickIsNull() const { + typedef internal::Object O; + typedef internal::Internals I; + O* obj = *reinterpret_cast<O**>(const_cast<Value*>(this)); + if (!I::HasHeapObjectTag(obj)) return false; + if (I::GetInstanceType(obj) != I::kOddballType) return false; + return (I::GetOddballKind(obj) == I::kNullOddballKind); +} + + bool Value::IsString() const { #ifdef V8_ENABLE_CHECKS return FullIsString(); @@ -4283,6 +4391,11 @@ External* External::Cast(v8::Value* value) { } +Isolate* AccessorInfo::GetIsolate() const { + return *reinterpret_cast<Isolate**>(&args_[-3]); +} + + Local<Value> AccessorInfo::Data() const { return Local<Value>(reinterpret_cast<Value*>(&args_[-2])); } @@ -4298,6 +4411,54 @@ Local<Object> AccessorInfo::Holder() const { } +Handle<Primitive> Undefined(Isolate* isolate) { + typedef internal::Object* S; + typedef internal::Internals I; + if (!I::IsInitialized(isolate)) return Undefined(); + S* slot = I::GetRoot(isolate, I::kUndefinedValueRootIndex); + return Handle<Primitive>(reinterpret_cast<Primitive*>(slot)); +} + + +Handle<Primitive> Null(Isolate* isolate) { + typedef internal::Object* S; + typedef internal::Internals I; + if (!I::IsInitialized(isolate)) return Null(); + S* slot = I::GetRoot(isolate, I::kNullValueRootIndex); + return Handle<Primitive>(reinterpret_cast<Primitive*>(slot)); +} + + +Handle<Boolean> True(Isolate* isolate) { + typedef internal::Object* S; + typedef internal::Internals I; + if (!I::IsInitialized(isolate)) return True(); + S* slot = I::GetRoot(isolate, I::kTrueValueRootIndex); + return Handle<Boolean>(reinterpret_cast<Boolean*>(slot)); +} + + +Handle<Boolean> False(Isolate* isolate) { + typedef internal::Object* S; + typedef internal::Internals I; + if (!I::IsInitialized(isolate)) return False(); + S* slot = I::GetRoot(isolate, I::kFalseValueRootIndex); + return Handle<Boolean>(reinterpret_cast<Boolean*>(slot)); +} + + +void Isolate::SetData(void* data) { + typedef internal::Internals I; + I::SetEmbedderData(this, data); +} + + +void* Isolate::GetData() { + typedef internal::Internals I; + return I::GetEmbedderData(this); +} + + /** * \example shell.cc * A simple shell that takes a list of expressions on the diff --git a/deps/v8/samples/lineprocessor.cc b/deps/v8/samples/lineprocessor.cc index 1606a8f99c..7a84a2a0ff 100644 --- a/deps/v8/samples/lineprocessor.cc +++ b/deps/v8/samples/lineprocessor.cc @@ -1,4 +1,4 @@ -// Copyright 2009 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -434,9 +434,9 @@ v8::Handle<v8::String> ReadLine() { } if (res == NULL) { v8::Handle<v8::Primitive> t = v8::Undefined(); - return reinterpret_cast<v8::Handle<v8::String>&>(t); + return v8::Handle<v8::String>(v8::String::Cast(*t)); } - // remove newline char + // Remove newline char for (char* pos = buffer; *pos != '\0'; pos++) { if (*pos == '\n') { *pos = '\0'; diff --git a/deps/v8/samples/samples.gyp b/deps/v8/samples/samples.gyp index 55b2a98acd..3c720a748a 100644 --- a/deps/v8/samples/samples.gyp +++ b/deps/v8/samples/samples.gyp @@ -1,4 +1,4 @@ -# Copyright 2011 the V8 project authors. All rights reserved. +# Copyright 2012 the V8 project authors. All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: @@ -48,6 +48,12 @@ 'sources': [ 'process.cc', ], + }, + { + 'target_name': 'lineprocessor', + 'sources': [ + 'lineprocessor.cc', + ], } ], } diff --git a/deps/v8/samples/shell.cc b/deps/v8/samples/shell.cc index b40eca2f7c..db0cc1a930 100644 --- a/deps/v8/samples/shell.cc +++ b/deps/v8/samples/shell.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -67,17 +67,20 @@ static bool run_shell; int main(int argc, char* argv[]) { v8::V8::SetFlagsFromCommandLine(&argc, argv, true); run_shell = (argc == 1); - v8::HandleScope handle_scope; - v8::Persistent<v8::Context> context = CreateShellContext(); - if (context.IsEmpty()) { - printf("Error creating context\n"); - return 1; + int result; + { + v8::HandleScope handle_scope; + v8::Persistent<v8::Context> context = CreateShellContext(); + if (context.IsEmpty()) { + printf("Error creating context\n"); + return 1; + } + context->Enter(); + result = RunMain(argc, argv); + if (run_shell) RunShell(context); + context->Exit(); + context.Dispose(); } - context->Enter(); - int result = RunMain(argc, argv); - if (run_shell) RunShell(context); - context->Exit(); - context.Dispose(); v8::V8::Dispose(); return result; } diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 49a026be20..52a84edfda 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -512,6 +512,16 @@ void RegisteredExtension::Register(RegisteredExtension* that) { } +void RegisteredExtension::UnregisterAll() { + RegisteredExtension* re = first_extension_; + while (re != NULL) { + RegisteredExtension* next = re->next(); + delete re; + re = next; + } +} + + void RegisterExtension(Extension* that) { RegisteredExtension* extension = new RegisteredExtension(that); RegisteredExtension::Register(extension); @@ -2091,17 +2101,21 @@ bool StackFrame::IsConstructor() const { // --- D a t a --- -bool Value::IsUndefined() const { +bool Value::FullIsUndefined() const { if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsUndefined()")) { return false; } - return Utils::OpenHandle(this)->IsUndefined(); + bool result = Utils::OpenHandle(this)->IsUndefined(); + ASSERT_EQ(result, QuickIsUndefined()); + return result; } -bool Value::IsNull() const { +bool Value::FullIsNull() const { if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsNull()")) return false; - return Utils::OpenHandle(this)->IsNull(); + bool result = Utils::OpenHandle(this)->IsNull(); + ASSERT_EQ(result, QuickIsNull()); + return result; } @@ -2799,9 +2813,13 @@ bool v8::Object::ForceDelete(v8::Handle<Value> key) { i::Handle<i::JSObject> self = Utils::OpenHandle(this); i::Handle<i::Object> key_obj = Utils::OpenHandle(*key); - // When turning on access checks for a global object deoptimize all functions - // as optimized code does not always handle access checks. - i::Deoptimizer::DeoptimizeGlobalObject(*self); + // When deleting a property on the global object using ForceDelete + // deoptimize all functions as optimized code does not check for the hole + // value with DontDelete properties. We have to deoptimize all contexts + // because of possible cross-context inlined functions. + if (self->IsJSGlobalProxy() || self->IsGlobalObject()) { + i::Deoptimizer::DeoptimizeAll(); + } EXCEPTION_PREAMBLE(isolate); i::Handle<i::Object> obj = i::ForceDeleteProperty(self, key_obj); @@ -4170,7 +4188,7 @@ void v8::Object::SetPointerInInternalField(int index, void* value) { bool v8::V8::Initialize() { - i::Isolate* isolate = i::Isolate::Current(); + i::Isolate* isolate = i::Isolate::UncheckedCurrent(); if (isolate != NULL && isolate->IsInitialized()) { return true; } @@ -4277,6 +4295,7 @@ Persistent<Context> v8::Context::New( v8::ExtensionConfiguration* extensions, v8::Handle<ObjectTemplate> global_template, v8::Handle<Value> global_object) { + i::Isolate::EnsureDefaultIsolate(); i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::Context::New()"); LOG_API(isolate, "Context::New"); @@ -4611,7 +4630,9 @@ void* External::Value() const { Local<String> v8::String::Empty() { i::Isolate* isolate = i::Isolate::Current(); - EnsureInitializedForIsolate(isolate, "v8::String::Empty()"); + if (!EnsureInitializedForIsolate(isolate, "v8::String::Empty()")) { + return v8::Local<String>(); + } LOG_API(isolate, "String::Empty()"); return Utils::ToLocal(isolate->factory()->empty_symbol()); } @@ -5063,7 +5084,7 @@ Local<Number> v8::Number::New(double value) { Local<Integer> v8::Integer::New(int32_t value) { - i::Isolate* isolate = i::Isolate::Current(); + i::Isolate* isolate = i::Isolate::UncheckedCurrent(); EnsureInitializedForIsolate(isolate, "v8::Integer::New()"); if (i::Smi::IsValid(value)) { return Utils::IntegerToLocal(i::Handle<i::Object>(i::Smi::FromInt(value), @@ -5197,7 +5218,7 @@ void V8::AddImplicitReferences(Persistent<Object> parent, } -int V8::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) { +intptr_t V8::AdjustAmountOfExternalAllocatedMemory(intptr_t change_in_bytes) { i::Isolate* isolate = i::Isolate::Current(); if (IsDeadCheck(isolate, "v8::V8::AdjustAmountOfExternalAllocatedMemory()")) { return 0; @@ -5269,6 +5290,7 @@ void V8::RemoveMemoryAllocationCallback(MemoryAllocationCallback callback) { void V8::AddCallCompletedCallback(CallCompletedCallback callback) { if (callback == NULL) return; + i::Isolate::EnsureDefaultIsolate(); i::Isolate* isolate = i::Isolate::Current(); if (IsDeadCheck(isolate, "v8::V8::AddLeaveScriptCallback()")) return; i::V8::AddCallCompletedCallback(callback); @@ -5276,6 +5298,7 @@ void V8::AddCallCompletedCallback(CallCompletedCallback callback) { void V8::RemoveCallCompletedCallback(CallCompletedCallback callback) { + i::Isolate::EnsureDefaultIsolate(); i::Isolate* isolate = i::Isolate::Current(); if (IsDeadCheck(isolate, "v8::V8::RemoveLeaveScriptCallback()")) return; i::V8::RemoveCallCompletedCallback(callback); @@ -5341,7 +5364,7 @@ bool V8::IsExecutionTerminating(Isolate* isolate) { Isolate* Isolate::GetCurrent() { - i::Isolate* isolate = i::Isolate::Current(); + i::Isolate* isolate = i::Isolate::UncheckedCurrent(); return reinterpret_cast<Isolate*>(isolate); } @@ -5375,17 +5398,6 @@ void Isolate::Exit() { } -void Isolate::SetData(void* data) { - i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); - isolate->SetData(data); -} - -void* Isolate::GetData() { - i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); - return isolate->GetData(); -} - - String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) : str_(NULL), length_(0) { i::Isolate* isolate = i::Isolate::Current(); @@ -5985,7 +5997,7 @@ Handle<Value> HeapGraphEdge::GetName() const { const HeapGraphNode* HeapGraphEdge::GetFromNode() const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapGraphEdge::GetFromNode"); - const i::HeapEntry* from = ToInternal(this)->From(); + const i::HeapEntry* from = ToInternal(this)->from(); return reinterpret_cast<const HeapGraphNode*>(from); } @@ -6019,7 +6031,7 @@ Handle<String> HeapGraphNode::GetName() const { } -uint64_t HeapGraphNode::GetId() const { +SnapshotObjectId HeapGraphNode::GetId() const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapGraphNode::GetId"); return ToInternal(this)->id(); @@ -6051,7 +6063,7 @@ const HeapGraphEdge* HeapGraphNode::GetChild(int index) const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapSnapshot::GetChild"); return reinterpret_cast<const HeapGraphEdge*>( - &ToInternal(this)->children()[index]); + ToInternal(this)->children()[index]); } @@ -6134,18 +6146,18 @@ const HeapGraphNode* HeapSnapshot::GetRoot() const { } -const HeapGraphNode* HeapSnapshot::GetNodeById(uint64_t id) const { +const HeapGraphNode* HeapSnapshot::GetNodeById(SnapshotObjectId id) const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapSnapshot::GetNodeById"); return reinterpret_cast<const HeapGraphNode*>( - ToInternal(this)->GetEntryById(static_cast<i::SnapshotObjectId>(id))); + ToInternal(this)->GetEntryById(id)); } int HeapSnapshot::GetNodesCount() const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapSnapshot::GetNodesCount"); - return ToInternal(this)->entries()->length(); + return ToInternal(this)->entries().length(); } @@ -6153,7 +6165,14 @@ const HeapGraphNode* HeapSnapshot::GetNode(int index) const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapSnapshot::GetNode"); return reinterpret_cast<const HeapGraphNode*>( - ToInternal(this)->entries()->at(index)); + &ToInternal(this)->entries().at(index)); +} + + +SnapshotObjectId HeapSnapshot::GetMaxSnapshotJSObjectId() const { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::HeapSnapshot::GetMaxSnapshotJSObjectId"); + return ToInternal(this)->max_snapshot_js_object_id(); } @@ -6198,6 +6217,14 @@ const HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) { } +SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Value> value) { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::HeapProfiler::GetSnapshotObjectId"); + i::Handle<i::Object> obj = Utils::OpenHandle(*value); + return i::HeapProfiler::GetSnapshotObjectId(obj); +} + + const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title, HeapSnapshot::Type type, ActivityControl* control) { @@ -6217,6 +6244,27 @@ const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title, } +void HeapProfiler::StartHeapObjectsTracking() { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::HeapProfiler::StartHeapObjectsTracking"); + i::HeapProfiler::StartHeapObjectsTracking(); +} + + +void HeapProfiler::StopHeapObjectsTracking() { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::HeapProfiler::StopHeapObjectsTracking"); + i::HeapProfiler::StopHeapObjectsTracking(); +} + + +void HeapProfiler::PushHeapObjectsStats(OutputStream* stream) { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::HeapProfiler::PushHeapObjectsStats"); + return i::HeapProfiler::PushHeapObjectsStats(stream); +} + + void HeapProfiler::DeleteAllSnapshots() { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::DeleteAllSnapshots"); @@ -6264,7 +6312,11 @@ static void SetFlagsFromString(const char* flags) { void Testing::PrepareStressRun(int run) { static const char* kLazyOptimizations = - "--prepare-always-opt --nolimit-inlining --noalways-opt"; + "--prepare-always-opt " + "--max-inlined-source-size=999999 " + "--max-inlined-nodes=999999 " + "--max-inlined-nodes-cumulative=999999 " + "--noalways-opt"; static const char* kForcedOptimizations = "--always-opt"; // If deoptimization stressed turn on frequent deoptimization. If no value diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index 89cf0c864c..3ad57f4657 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -146,6 +146,7 @@ class RegisteredExtension { public: explicit RegisteredExtension(Extension* extension); static void Register(RegisteredExtension* that); + static void UnregisterAll(); Extension* extension() { return extension_; } RegisteredExtension* next() { return next_; } RegisteredExtension* next_auto() { return next_auto_; } diff --git a/deps/v8/src/apiutils.h b/deps/v8/src/apiutils.h index 68579af1b3..71c0e1c2c4 100644 --- a/deps/v8/src/apiutils.h +++ b/deps/v8/src/apiutils.h @@ -1,4 +1,4 @@ -// Copyright 2009 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -40,14 +40,17 @@ class ImplementationUtilities { } // Packs additional parameters for the NewArguments function. |implicit_args| - // is a pointer to the last element of 3-elements array controlled by GC. + // is a pointer to the last element of 4-elements array controlled by GC. static void PrepareArgumentsData(internal::Object** implicit_args, + internal::Isolate* isolate, internal::Object* data, internal::JSFunction* callee, internal::Object* holder) { implicit_args[v8::Arguments::kDataIndex] = data; implicit_args[v8::Arguments::kCalleeIndex] = callee; implicit_args[v8::Arguments::kHolderIndex] = holder; + implicit_args[v8::Arguments::kIsolateIndex] = + reinterpret_cast<internal::Object*>(isolate); } static v8::Arguments NewArguments(internal::Object** implicit_args, @@ -55,6 +58,8 @@ class ImplementationUtilities { bool is_construct_call) { ASSERT(implicit_args[v8::Arguments::kCalleeIndex]->IsJSFunction()); ASSERT(implicit_args[v8::Arguments::kHolderIndex]->IsHeapObject()); + // The implicit isolate argument is not tagged and looks like a SMI. + ASSERT(implicit_args[v8::Arguments::kIsolateIndex]->IsSmi()); return v8::Arguments(implicit_args, argv, argc, is_construct_call); } diff --git a/deps/v8/src/arguments.h b/deps/v8/src/arguments.h index e9a32702cf..f8fb00c575 100644 --- a/deps/v8/src/arguments.h +++ b/deps/v8/src/arguments.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -91,9 +91,11 @@ class CustomArguments : public Relocatable { Object* data, Object* self, JSObject* holder) : Relocatable(isolate) { - values_[2] = self; - values_[1] = holder; - values_[0] = data; + ASSERT(reinterpret_cast<Object*>(isolate)->IsSmi()); + values_[3] = self; + values_[2] = holder; + values_[1] = data; + values_[0] = reinterpret_cast<Object*>(isolate); } inline explicit CustomArguments(Isolate* isolate) : Relocatable(isolate) { @@ -106,8 +108,9 @@ class CustomArguments : public Relocatable { void IterateInstance(ObjectVisitor* v); Object** end() { return values_ + ARRAY_SIZE(values_) - 1; } + private: - Object* values_[3]; + Object* values_[4]; }; diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index f772db9be2..ad2ab7e09d 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -5169,9 +5169,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); __ b(ne, &call); // Patch the receiver on the stack with the global receiver object. - __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); - __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); - __ str(r2, MemOperand(sp, argc_ * kPointerSize)); + __ ldr(r3, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalReceiverOffset)); + __ str(r3, MemOperand(sp, argc_ * kPointerSize)); __ bind(&call); } @@ -5179,9 +5179,13 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { // r1: pushed function (to be verified) __ JumpIfSmi(r1, &non_function); // Get the map of the function object. - __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); + __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); __ b(ne, &slow); + if (RecordCallTarget()) { + GenerateRecordCallTarget(masm); + } + // Fast-case: Invoke the function now. // r1: pushed function ParameterCount actual(argc_); @@ -5205,8 +5209,17 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { // Slow-case: Non-function called. __ bind(&slow); + if (RecordCallTarget()) { + // If there is a call target cache, mark it megamorphic in the + // non-function case. MegamorphicSentinel is an immortal immovable + // object (undefined) so no write barrier is needed. + ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), + masm->isolate()->heap()->undefined_value()); + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); + __ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); + } // Check for function proxy. - __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE)); + __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE)); __ b(ne, &non_function); __ push(r1); // put proxy as additional argument __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE)); @@ -5873,36 +5886,12 @@ void SubStringStub::Generate(MacroAssembler* masm) { // r2: result string length __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset)); __ cmp(r2, Operand(r4, ASR, 1)); + // Return original string. __ b(eq, &return_r0); + // Longer than original string's length or negative: unsafe arguments. + __ b(hi, &runtime); + // Shorter than original string's length: an actual substring. - Label result_longer_than_two; - // Check for special case of two character ASCII string, in which case - // we do a lookup in the symbol table first. - __ cmp(r2, Operand(2)); - __ b(gt, &result_longer_than_two); - __ b(lt, &runtime); - - __ JumpIfInstanceTypeIsNotSequentialAscii(r1, r1, &runtime); - - // Get the two characters forming the sub string. - __ add(r0, r0, Operand(r3)); - __ ldrb(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); - __ ldrb(r4, FieldMemOperand(r0, SeqAsciiString::kHeaderSize + 1)); - - // Try to lookup two character string in symbol table. - Label make_two_character_string; - StringHelper::GenerateTwoCharacterSymbolTableProbe( - masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string); - __ jmp(&return_r0); - - // r2: result string length. - // r3: two characters combined into halfword in little endian byte order. - __ bind(&make_two_character_string); - __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); - __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); - __ jmp(&return_r0); - - __ bind(&result_longer_than_two); // Deal with different string types: update the index if necessary // and put the underlying string into r5. // r0: original string diff --git a/deps/v8/src/arm/debug-arm.cc b/deps/v8/src/arm/debug-arm.cc index 96139a2597..3e7a1e9d0e 100644 --- a/deps/v8/src/arm/debug-arm.cc +++ b/deps/v8/src/arm/debug-arm.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -125,6 +125,8 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() { Assembler::kDebugBreakSlotInstructions); } +const bool Debug::FramePaddingLayout::kIsSupported = false; + #define __ ACCESS_MASM(masm) diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index 7b2a3c4fc1..699e6aa4b1 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -457,6 +457,8 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator, void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, int frame_index) { + Builtins* builtins = isolate_->builtins(); + Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); unsigned height = iterator->Next(); unsigned height_in_bytes = height * kPointerSize; @@ -464,7 +466,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, PrintF(" translating construct stub => height=%d\n", height_in_bytes); } - unsigned fixed_frame_size = 7 * kPointerSize; + unsigned fixed_frame_size = 8 * kPointerSize; unsigned output_frame_size = height_in_bytes + fixed_frame_size; // Allocate and store the output frame description. @@ -529,6 +531,15 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, top_address + output_offset, output_offset, value); } + // The output frame reflects a JSConstructStubGeneric frame. + output_offset -= kPointerSize; + value = reinterpret_cast<intptr_t>(construct_stub); + output_frame->SetFrameSlot(output_offset, value); + if (FLAG_trace_deopt) { + PrintF(" 0x%08x: [top + %d] <- 0x%08x ; code object\n", + top_address + output_offset, output_offset, value); + } + // Number of incoming arguments. output_offset -= kPointerSize; value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1)); @@ -559,8 +570,6 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, ASSERT(0 == output_offset); - Builtins* builtins = isolate_->builtins(); - Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); uint32_t pc = reinterpret_cast<uint32_t>( construct_stub->instruction_start() + isolate_->heap()->construct_stub_deopt_pc_offset()->value()); diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 0cbd46ed1d..9f448720cc 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -70,6 +70,7 @@ class JumpPatchSite BASE_EMBEDDED { // the inlined smi code. void EmitJumpIfNotSmi(Register reg, Label* target) { ASSERT(!patch_site_.is_bound() && !info_emitted_); + Assembler::BlockConstPoolScope block_const_pool(masm_); __ bind(&patch_site_); __ cmp(reg, Operand(reg)); // Don't use b(al, ...) as that might emit the constant pool right after the @@ -82,6 +83,7 @@ class JumpPatchSite BASE_EMBEDDED { // the inlined smi code. void EmitJumpIfSmi(Register reg, Label* target) { ASSERT(!patch_site_.is_bound() && !info_emitted_); + Assembler::BlockConstPoolScope block_const_pool(masm_); __ bind(&patch_site_); __ cmp(reg, Operand(reg)); __ b(ne, target); // Never taken before patched. @@ -110,13 +112,6 @@ class JumpPatchSite BASE_EMBEDDED { }; -// TODO(jkummerow): Obsolete as soon as x64 is updated. Remove. -int FullCodeGenerator::self_optimization_header_size() { - UNREACHABLE(); - return 24; -} - - // Generate code for a JS function. On entry to the function the receiver // and arguments have been pushed on the stack left to right. The actual // argument count matches the formal parameter count expected by the @@ -273,11 +268,11 @@ void FullCodeGenerator::Generate() { // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - VariableProxy* proxy = scope()->function(); - ASSERT(proxy->var()->mode() == CONST || - proxy->var()->mode() == CONST_HARMONY); - ASSERT(proxy->var()->location() != Variable::UNALLOCATED); - EmitDeclaration(proxy, proxy->var()->mode(), NULL); + VariableDeclaration* function = scope()->function(); + ASSERT(function->proxy()->var()->mode() == CONST || + function->proxy()->var()->mode() == CONST_HARMONY); + ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); + VisitVariableDeclaration(function); } VisitDeclarations(scope()->declarations()); } @@ -787,62 +782,51 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, } -void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function) { +void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { + // The variable in the declaration always resides in the current function + // context. + ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); + if (FLAG_debug_code) { + // Check that we're not inside a with or catch context. + __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); + __ CompareRoot(r1, Heap::kWithContextMapRootIndex); + __ Check(ne, "Declaration in with context."); + __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); + __ Check(ne, "Declaration in catch context."); + } +} + + +void FullCodeGenerator::VisitVariableDeclaration( + VariableDeclaration* declaration) { // If it was not possible to allocate the variable at compile time, we // need to "declare" it at runtime to make sure it actually exists in the // local context. + VariableProxy* proxy = declaration->proxy(); + VariableMode mode = declaration->mode(); Variable* variable = proxy->var(); - bool binding_needs_init = (function == NULL) && - (mode == CONST || mode == CONST_HARMONY || mode == LET); + bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; switch (variable->location()) { case Variable::UNALLOCATED: - ++global_count_; + globals_->Add(variable->name()); + globals_->Add(variable->binding_needs_init() + ? isolate()->factory()->the_hole_value() + : isolate()->factory()->undefined_value()); break; case Variable::PARAMETER: case Variable::LOCAL: - if (function != NULL) { - Comment cmnt(masm_, "[ Declaration"); - VisitForAccumulatorValue(function); - __ str(result_register(), StackOperand(variable)); - } else if (binding_needs_init) { - Comment cmnt(masm_, "[ Declaration"); + if (hole_init) { + Comment cmnt(masm_, "[ VariableDeclaration"); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ str(ip, StackOperand(variable)); } break; case Variable::CONTEXT: - // The variable in the decl always resides in the current function - // context. - ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); - if (FLAG_debug_code) { - // Check that we're not inside a with or catch context. - __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); - __ CompareRoot(r1, Heap::kWithContextMapRootIndex); - __ Check(ne, "Declaration in with context."); - __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); - __ Check(ne, "Declaration in catch context."); - } - if (function != NULL) { - Comment cmnt(masm_, "[ Declaration"); - VisitForAccumulatorValue(function); - __ str(result_register(), ContextOperand(cp, variable->index())); - int offset = Context::SlotOffset(variable->index()); - // We know that we have written a function, which is not a smi. - __ RecordWriteContextSlot(cp, - offset, - result_register(), - r2, - kLRHasBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - PrepareForBailoutForId(proxy->id(), NO_REGISTERS); - } else if (binding_needs_init) { - Comment cmnt(masm_, "[ Declaration"); + if (hole_init) { + Comment cmnt(masm_, "[ VariableDeclaration"); + EmitDebugCheckDeclarationContext(variable); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ str(ip, ContextOperand(cp, variable->index())); // No write barrier since the_hole_value is in old space. @@ -851,13 +835,11 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, break; case Variable::LOOKUP: { - Comment cmnt(masm_, "[ Declaration"); + Comment cmnt(masm_, "[ VariableDeclaration"); __ mov(r2, Operand(variable->name())); // Declaration nodes are always introduced in one of four modes. - ASSERT(mode == VAR || - mode == CONST || - mode == CONST_HARMONY || - mode == LET); + ASSERT(mode == VAR || mode == LET || + mode == CONST || mode == CONST_HARMONY); PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; __ mov(r1, Operand(Smi::FromInt(attr))); @@ -865,11 +847,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, // Note: For variables we must not push an initial value (such as // 'undefined') because we may have a (legal) redeclaration and we // must not destroy the current value. - if (function != NULL) { - __ Push(cp, r2, r1); - // Push initial value for function declaration. - VisitForStackValue(function); - } else if (binding_needs_init) { + if (hole_init) { __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); __ Push(cp, r2, r1, r0); } else { @@ -883,6 +861,122 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, } +void FullCodeGenerator::VisitFunctionDeclaration( + FunctionDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: { + globals_->Add(variable->name()); + Handle<SharedFunctionInfo> function = + Compiler::BuildFunctionInfo(declaration->fun(), script()); + // Check for stack-overflow exception. + if (function.is_null()) return SetStackOverflow(); + globals_->Add(function); + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + VisitForAccumulatorValue(declaration->fun()); + __ str(result_register(), StackOperand(variable)); + break; + } + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + EmitDebugCheckDeclarationContext(variable); + VisitForAccumulatorValue(declaration->fun()); + __ str(result_register(), ContextOperand(cp, variable->index())); + int offset = Context::SlotOffset(variable->index()); + // We know that we have written a function, which is not a smi. + __ RecordWriteContextSlot(cp, + offset, + result_register(), + r2, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); + break; + } + + case Variable::LOOKUP: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + __ mov(r2, Operand(variable->name())); + __ mov(r1, Operand(Smi::FromInt(NONE))); + __ Push(cp, r2, r1); + // Push initial value for function declaration. + VisitForStackValue(declaration->fun()); + __ CallRuntime(Runtime::kDeclareContextSlot, 4); + break; + } + } +} + + +void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + Handle<JSModule> instance = declaration->module()->interface()->Instance(); + ASSERT(!instance.is_null()); + + switch (variable->location()) { + case Variable::UNALLOCATED: { + Comment cmnt(masm_, "[ ModuleDeclaration"); + globals_->Add(variable->name()); + globals_->Add(instance); + Visit(declaration->module()); + break; + } + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ ModuleDeclaration"); + EmitDebugCheckDeclarationContext(variable); + __ mov(r1, Operand(instance)); + __ str(r1, ContextOperand(cp, variable->index())); + Visit(declaration->module()); + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::LOOKUP: + UNREACHABLE(); + } +} + + +void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: + // TODO(rossberg) + break; + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ ImportDeclaration"); + EmitDebugCheckDeclarationContext(variable); + // TODO(rossberg) + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::LOOKUP: + UNREACHABLE(); + } +} + + +void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { + // TODO(rossberg) +} + + void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { // Call the runtime to declare the globals. // The context is the first argument. @@ -2269,6 +2363,18 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { } // Record source position for debugger. SetSourcePosition(expr->position()); + + // Record call targets in unoptimized code, but not in the snapshot. + if (!Serializer::enabled()) { + flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); + Handle<Object> uninitialized = + TypeFeedbackCells::UninitializedSentinel(isolate()); + Handle<JSGlobalPropertyCell> cell = + isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); + RecordTypeFeedbackCell(expr->id(), cell); + __ mov(r2, Operand(cell)); + } + CallFunctionStub stub(arg_count, flags); __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ CallStub(&stub); @@ -3660,7 +3766,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset)); - __ add(string_length, string_length, Operand(scratch1)); + __ add(string_length, string_length, Operand(scratch1), SetCC); __ b(vs, &bailout); __ cmp(element, elements_end); __ b(lt, &loop); @@ -3697,7 +3803,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ b(ne, &bailout); __ tst(scratch2, Operand(0x80000000)); __ b(ne, &bailout); - __ add(string_length, string_length, Operand(scratch2)); + __ add(string_length, string_length, Operand(scratch2), SetCC); __ b(vs, &bailout); __ SmiUntag(string_length); @@ -4453,7 +4559,8 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) { void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { Scope* declaration_scope = scope()->DeclarationScope(); - if (declaration_scope->is_global_scope()) { + if (declaration_scope->is_global_scope() || + declaration_scope->is_module_scope()) { // Contexts nested in the global context have a canonical empty function // as their closure, not the anonymous closure containing the global // code. Pass a smi sentinel and let the runtime look up the empty diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index e84365789b..c12c16754d 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -774,7 +774,7 @@ static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, __ b(lt, slow_case); // Check that the key is a positive smi. - __ tst(key, Operand(0x8000001)); + __ tst(key, Operand(0x80000001)); __ b(ne, slow_case); // Load the elements into scratch1 and check its map. @@ -1690,12 +1690,12 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { // Activate inlined smi code. if (previous_state == UNINITIALIZED) { - PatchInlinedSmiCode(address()); + PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); } } -void PatchInlinedSmiCode(Address address) { +void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { Address cmp_instruction_address = address + Assembler::kCallTargetAddressOffset; @@ -1729,34 +1729,31 @@ void PatchInlinedSmiCode(Address address) { Instr instr_at_patch = Assembler::instr_at(patch_address); Instr branch_instr = Assembler::instr_at(patch_address + Instruction::kInstrSize); - ASSERT(Assembler::IsCmpRegister(instr_at_patch)); - ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(), - Assembler::GetRm(instr_at_patch).code()); + // This is patching a conditional "jump if not smi/jump if smi" site. + // Enabling by changing from + // cmp rx, rx + // b eq/ne, <target> + // to + // tst rx, #kSmiTagMask + // b ne/eq, <target> + // and vice-versa to be disabled again. + CodePatcher patcher(patch_address, 2); + Register reg = Assembler::GetRn(instr_at_patch); + if (check == ENABLE_INLINED_SMI_CHECK) { + ASSERT(Assembler::IsCmpRegister(instr_at_patch)); + ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(), + Assembler::GetRm(instr_at_patch).code()); + patcher.masm()->tst(reg, Operand(kSmiTagMask)); + } else { + ASSERT(check == DISABLE_INLINED_SMI_CHECK); + ASSERT(Assembler::IsTstImmediate(instr_at_patch)); + patcher.masm()->cmp(reg, reg); + } ASSERT(Assembler::IsBranch(branch_instr)); if (Assembler::GetCondition(branch_instr) == eq) { - // This is patching a "jump if not smi" site to be active. - // Changing - // cmp rx, rx - // b eq, <target> - // to - // tst rx, #kSmiTagMask - // b ne, <target> - CodePatcher patcher(patch_address, 2); - Register reg = Assembler::GetRn(instr_at_patch); - patcher.masm()->tst(reg, Operand(kSmiTagMask)); patcher.EmitCondition(ne); } else { ASSERT(Assembler::GetCondition(branch_instr) == ne); - // This is patching a "jump if smi" site to be active. - // Changing - // cmp rx, rx - // b ne, <target> - // to - // tst rx, #kSmiTagMask - // b eq, <target> - CodePatcher patcher(patch_address, 2); - Register reg = Assembler::GetRn(instr_at_patch); - patcher.masm()->tst(reg, Operand(kSmiTagMask)); patcher.EmitCondition(eq); } } diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index cdc1947d4e..5c60f5321c 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -108,22 +108,17 @@ void LInstruction::PrintTo(StringStream* stream) { } -template<int R, int I, int T> -void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) { +void LInstruction::PrintDataTo(StringStream* stream) { stream->Add("= "); - for (int i = 0; i < inputs_.length(); i++) { + for (int i = 0; i < InputCount(); i++) { if (i > 0) stream->Add(" "); - inputs_[i]->PrintTo(stream); + InputAt(i)->PrintTo(stream); } } -template<int R, int I, int T> -void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) { - for (int i = 0; i < results_.length(); i++) { - if (i > 0) stream->Add(" "); - results_[i]->PrintTo(stream); - } +void LInstruction::PrintOutputOperandTo(StringStream* stream) { + if (HasResult()) result()->PrintTo(stream); } @@ -732,22 +727,6 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { } -LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( - LInstruction* instr, int ast_id) { - ASSERT(instruction_pending_deoptimization_environment_ == NULL); - ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); - instruction_pending_deoptimization_environment_ = instr; - pending_deoptimization_ast_id_ = ast_id; - return instr; -} - - -void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { - instruction_pending_deoptimization_environment_ = NULL; - pending_deoptimization_ast_id_ = AstNode::kNoNumber; -} - - LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, HInstruction* hinstr, CanDeoptimize can_deoptimize) { @@ -760,8 +739,10 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, if (hinstr->HasObservableSideEffects()) { ASSERT(hinstr->next()->IsSimulate()); HSimulate* sim = HSimulate::cast(hinstr->next()); - instr = SetInstructionPendingDeoptimizationEnvironment( - instr, sim->ast_id()); + ASSERT(instruction_pending_deoptimization_environment_ == NULL); + ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); + instruction_pending_deoptimization_environment_ = instr; + pending_deoptimization_ast_id_ = sim->ast_id(); } // If instruction does not have side-effects lazy deoptimization @@ -779,12 +760,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, } -LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) { - instr->MarkAsSaveDoubles(); - return instr; -} - - LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) { ASSERT(!instr->HasPointerMap()); instr->set_pointer_map(new(zone()) LPointerMap(position_)); @@ -1295,6 +1270,7 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { ASSERT(instr->value()->representation().IsInteger32()); ASSERT(instr->representation().IsInteger32()); + if (instr->HasNoUses()) return NULL; LOperand* value = UseRegisterAtStart(instr->value()); return DefineAsRegister(new(zone()) LBitNotI(value)); } @@ -1319,6 +1295,75 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { } +bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) { + uint32_t divisor_abs = abs(divisor); + // Dividing by 0, 1, and powers of 2 is easy. + // Note that IsPowerOf2(0) returns true; + ASSERT(IsPowerOf2(0) == true); + if (IsPowerOf2(divisor_abs)) return true; + + // We have magic numbers for a few specific divisors. + // Details and proofs can be found in: + // - Hacker's Delight, Henry S. Warren, Jr. + // - The PowerPC Compiler Writer’s Guide + // and probably many others. + // + // We handle + // <divisor with magic numbers> * <power of 2> + // but not + // <divisor with magic numbers> * <other divisor with magic numbers> + int32_t power_of_2_factor = + CompilerIntrinsics::CountTrailingZeros(divisor_abs); + DivMagicNumbers magic_numbers = + DivMagicNumberFor(divisor_abs >> power_of_2_factor); + if (magic_numbers.M != InvalidDivMagicNumber.M) return true; + + return false; +} + + +HValue* LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(HValue* dividend) { + // A value with an integer representation does not need to be transformed. + if (dividend->representation().IsInteger32()) { + return dividend; + // A change from an integer32 can be replaced by the integer32 value. + } else if (dividend->IsChange() && + HChange::cast(dividend)->from().IsInteger32()) { + return HChange::cast(dividend)->value(); + } + return NULL; +} + + +HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) { + // Only optimize when we have magic numbers for the divisor. + // The standard integer division routine is usually slower than transitionning + // to VFP. + if (divisor->IsConstant() && + HConstant::cast(divisor)->HasInteger32Value()) { + HConstant* constant_val = HConstant::cast(divisor); + int32_t int32_val = constant_val->Integer32Value(); + if (LChunkBuilder::HasMagicNumberForDivisor(int32_val)) { + return constant_val->CopyToRepresentation(Representation::Integer32()); + } + } + return NULL; +} + + +LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) { + HValue* right = instr->right(); + LOperand* dividend = UseRegister(instr->left()); + LOperand* divisor = UseRegisterOrConstant(right); + LOperand* remainder = TempRegister(); + ASSERT(right->IsConstant() && + HConstant::cast(right)->HasInteger32Value() && + HasMagicNumberForDivisor(HConstant::cast(right)->Integer32Value())); + return AssignEnvironment(DefineAsRegister( + new LMathFloorOfDiv(dividend, divisor, remainder))); +} + + LInstruction* LChunkBuilder::DoMod(HMod* instr) { if (instr->representation().IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); @@ -1753,9 +1798,9 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { } -LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) { +LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LOperand* value = UseRegisterAtStart(instr->value()); - LInstruction* result = new(zone()) LCheckMap(value); + LInstruction* result = new(zone()) LCheckMaps(value); return AssignEnvironment(result); } @@ -2242,9 +2287,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { if (pending_deoptimization_ast_id_ == instr->ast_id()) { LInstruction* result = new(zone()) LLazyBailout; result = AssignEnvironment(result); + // Store the lazy deopt environment with the instruction if needed. Right + // now it is only used for LInstanceOfKnownGlobal. instruction_pending_deoptimization_environment_-> - set_deoptimization_environment(result->environment()); - ClearInstructionPendingDeoptimizationEnvironment(); + SetDeferredLazyDeoptimizationEnvironment(result->environment()); + instruction_pending_deoptimization_environment_ = NULL; + pending_deoptimization_ast_id_ = AstNode::kNoNumber; return result; } @@ -2271,6 +2319,9 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { undefined, instr->call_kind(), instr->is_construct()); + if (instr->arguments_var() != NULL) { + inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject()); + } current_block_->UpdateEnvironment(inner); chunk_->AddInlinedClosure(instr->closure()); return NULL; @@ -2278,10 +2329,21 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { + LInstruction* pop = NULL; + + HEnvironment* env = current_block_->last_environment(); + + if (instr->arguments_pushed()) { + int argument_count = env->arguments_environment()->parameter_count(); + pop = new(zone()) LDrop(argument_count); + argument_count_ -= argument_count; + } + HEnvironment* outer = current_block_->last_environment()-> DiscardInlined(false); current_block_->UpdateEnvironment(outer); - return NULL; + + return pop; } diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index 62cde6e249..ec8aac8036 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -72,7 +72,7 @@ class LCodeGen; V(CheckFunction) \ V(CheckInstanceType) \ V(CheckNonSmi) \ - V(CheckMap) \ + V(CheckMaps) \ V(CheckPrototypeMaps) \ V(CheckSmi) \ V(ClampDToUint8) \ @@ -132,6 +132,7 @@ class LCodeGen; V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ + V(MathFloorOfDiv) \ V(ModI) \ V(MulI) \ V(NumberTagD) \ @@ -179,7 +180,8 @@ class LCodeGen; V(CheckMapValue) \ V(LoadFieldByIndex) \ V(DateField) \ - V(WrapReceiver) + V(WrapReceiver) \ + V(Drop) #define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \ @@ -203,15 +205,14 @@ class LInstruction: public ZoneObject { LInstruction() : environment_(NULL), hydrogen_value_(NULL), - is_call_(false), - is_save_doubles_(false) { } + is_call_(false) { } virtual ~LInstruction() { } virtual void CompileToNative(LCodeGen* generator) = 0; virtual const char* Mnemonic() const = 0; virtual void PrintTo(StringStream* stream); - virtual void PrintDataTo(StringStream* stream) = 0; - virtual void PrintOutputOperandTo(StringStream* stream) = 0; + virtual void PrintDataTo(StringStream* stream); + virtual void PrintOutputOperandTo(StringStream* stream); enum Opcode { // Declare a unique enum value for each instruction. @@ -246,22 +247,12 @@ class LInstruction: public ZoneObject { void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; } HValue* hydrogen_value() const { return hydrogen_value_; } - void set_deoptimization_environment(LEnvironment* env) { - deoptimization_environment_.set(env); - } - LEnvironment* deoptimization_environment() const { - return deoptimization_environment_.get(); - } - bool HasDeoptimizationEnvironment() const { - return deoptimization_environment_.is_set(); - } + virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { } void MarkAsCall() { is_call_ = true; } - void MarkAsSaveDoubles() { is_save_doubles_ = true; } // Interface to the register allocator and iterators. bool IsMarkedAsCall() const { return is_call_; } - bool IsMarkedAsSaveDoubles() const { return is_save_doubles_; } virtual bool HasResult() const = 0; virtual LOperand* result() = 0; @@ -282,9 +273,7 @@ class LInstruction: public ZoneObject { LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; - SetOncePointer<LEnvironment> deoptimization_environment_; bool is_call_; - bool is_save_doubles_; }; @@ -306,9 +295,6 @@ class LTemplateInstruction: public LInstruction { int TempCount() { return T; } LOperand* TempAt(int i) { return temps_[i]; } - virtual void PrintDataTo(StringStream* stream); - virtual void PrintOutputOperandTo(StringStream* stream); - protected: EmbeddedContainer<LOperand*, R> results_; EmbeddedContainer<LOperand*, I> inputs_; @@ -534,9 +520,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { class LArgumentsElements: public LTemplateInstruction<1, 0, 0> { public: - LArgumentsElements() { } - DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements") + DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements) }; @@ -582,6 +567,21 @@ class LDivI: public LTemplateInstruction<1, 2, 0> { }; +class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> { + public: + LMathFloorOfDiv(LOperand* left, + LOperand* right, + LOperand* temp = NULL) { + inputs_[0] = left; + inputs_[1] = right; + temps_[0] = temp; + } + + DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div") + DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv) +}; + + class LMulI: public LTemplateInstruction<1, 2, 1> { public: LMulI(LOperand* left, LOperand* right, LOperand* temp) { @@ -834,6 +834,15 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) Handle<JSFunction> function() const { return hydrogen()->function(); } + LEnvironment* GetDeferredLazyDeoptimizationEnvironment() { + return lazy_deopt_env_; + } + virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { + lazy_deopt_env_ = env; + } + + private: + LEnvironment* lazy_deopt_env_; }; @@ -1378,6 +1387,19 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { }; +class LDrop: public LTemplateInstruction<0, 0, 0> { + public: + explicit LDrop(int count) : count_(count) { } + + int count() const { return count_; } + + DECLARE_CONCRETE_INSTRUCTION(Drop, "drop") + + private: + int count_; +}; + + class LThisFunction: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function") @@ -1460,6 +1482,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> { virtual void PrintDataTo(StringStream* stream); int arity() const { return hydrogen()->argument_count() - 1; } + Handle<JSFunction> known_function() { return hydrogen()->known_function(); } }; @@ -1739,6 +1762,8 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } + + bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } }; @@ -1889,14 +1914,14 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> { }; -class LCheckMap: public LTemplateInstruction<0, 1, 0> { +class LCheckMaps: public LTemplateInstruction<0, 1, 0> { public: - explicit LCheckMap(LOperand* value) { + explicit LCheckMaps(LOperand* value) { inputs_[0] = value; } - DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map") - DECLARE_HYDROGEN_ACCESSOR(CheckMap) + DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps") + DECLARE_HYDROGEN_ACCESSOR(CheckMaps) }; @@ -2274,6 +2299,10 @@ class LChunkBuilder BASE_EMBEDDED { HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) #undef DECLARE_DO + static bool HasMagicNumberForDivisor(int32_t divisor); + static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val); + static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val); + private: enum Status { UNUSED, @@ -2369,11 +2398,6 @@ class LChunkBuilder BASE_EMBEDDED { LInstruction* instr, HInstruction* hinstr, CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); - LInstruction* MarkAsSaveDoubles(LInstruction* instr); - - LInstruction* SetInstructionPendingDeoptimizationEnvironment( - LInstruction* instr, int ast_id); - void ClearInstructionPendingDeoptimizationEnvironment(); LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, int* argument_index_accumulator); diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 82b80a2b80..bf11ab9bea 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -1034,6 +1034,100 @@ void LCodeGen::DoModI(LModI* instr) { } +void LCodeGen::EmitSignedIntegerDivisionByConstant( + Register result, + Register dividend, + int32_t divisor, + Register remainder, + Register scratch, + LEnvironment* environment) { + ASSERT(!AreAliased(dividend, scratch, ip)); + ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor)); + + uint32_t divisor_abs = abs(divisor); + + int32_t power_of_2_factor = + CompilerIntrinsics::CountTrailingZeros(divisor_abs); + + switch (divisor_abs) { + case 0: + DeoptimizeIf(al, environment); + return; + + case 1: + if (divisor > 0) { + __ Move(result, dividend); + } else { + __ rsb(result, dividend, Operand(0), SetCC); + DeoptimizeIf(vs, environment); + } + // Compute the remainder. + __ mov(remainder, Operand(0)); + return; + + default: + if (IsPowerOf2(divisor_abs)) { + // Branch and condition free code for integer division by a power + // of two. + int32_t power = WhichPowerOf2(divisor_abs); + if (power > 1) { + __ mov(scratch, Operand(dividend, ASR, power - 1)); + } + __ add(scratch, dividend, Operand(scratch, LSR, 32 - power)); + __ mov(result, Operand(scratch, ASR, power)); + // Negate if necessary. + // We don't need to check for overflow because the case '-1' is + // handled separately. + if (divisor < 0) { + ASSERT(divisor != -1); + __ rsb(result, result, Operand(0)); + } + // Compute the remainder. + if (divisor > 0) { + __ sub(remainder, dividend, Operand(result, LSL, power)); + } else { + __ add(remainder, dividend, Operand(result, LSL, power)); + } + return; + } else { + // Use magic numbers for a few specific divisors. + // Details and proofs can be found in: + // - Hacker's Delight, Henry S. Warren, Jr. + // - The PowerPC Compiler Writer’s Guide + // and probably many others. + // + // We handle + // <divisor with magic numbers> * <power of 2> + // but not + // <divisor with magic numbers> * <other divisor with magic numbers> + DivMagicNumbers magic_numbers = + DivMagicNumberFor(divisor_abs >> power_of_2_factor); + // Branch and condition free code for integer division by a power + // of two. + const int32_t M = magic_numbers.M; + const int32_t s = magic_numbers.s + power_of_2_factor; + + __ mov(ip, Operand(M)); + __ smull(ip, scratch, dividend, ip); + if (M < 0) { + __ add(scratch, scratch, Operand(dividend)); + } + if (s > 0) { + __ mov(scratch, Operand(scratch, ASR, s)); + } + __ add(result, scratch, Operand(dividend, LSR, 31)); + if (divisor < 0) __ rsb(result, result, Operand(0)); + // Compute the remainder. + __ mov(ip, Operand(divisor)); + // This sequence could be replaced with 'mls' when + // it gets implemented. + __ mul(scratch, result, ip); + __ sub(remainder, dividend, scratch); + } + } +} + + void LCodeGen::DoDivI(LDivI* instr) { class DeferredDivI: public LDeferredCode { public: @@ -1115,6 +1209,34 @@ void LCodeGen::DoDivI(LDivI* instr) { } +void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { + const Register result = ToRegister(instr->result()); + const Register left = ToRegister(instr->InputAt(0)); + const Register remainder = ToRegister(instr->TempAt(0)); + const Register scratch = scratch0(); + + // We only optimize this for division by constants, because the standard + // integer division routine is usually slower than transitionning to VFP. + // This could be optimized on processors with SDIV available. + ASSERT(instr->InputAt(1)->IsConstantOperand()); + int32_t divisor = ToInteger32(LConstantOperand::cast(instr->InputAt(1))); + if (divisor < 0) { + __ cmp(left, Operand(0)); + DeoptimizeIf(eq, instr->environment()); + } + EmitSignedIntegerDivisionByConstant(result, + left, + divisor, + remainder, + scratch, + instr->environment()); + // We operated a truncating division. Correct the result if necessary. + __ cmp(remainder, Operand(0)); + __ teq(remainder, Operand(divisor), ne); + __ sub(result, result, Operand(1), LeaveCC, mi); +} + + template<int T> void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, Token::Value op) { @@ -2267,8 +2389,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, RelocInfo::CODE_TARGET, instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); - ASSERT(instr->HasDeoptimizationEnvironment()); - LEnvironment* env = instr->deoptimization_environment(); + LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment(); safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); // Put the result value into the result register slot and // restore all registers. @@ -2466,42 +2587,38 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { Register object = ToRegister(instr->object()); Register result = ToRegister(instr->result()); Register scratch = scratch0(); + int map_count = instr->hydrogen()->types()->length(); + bool need_generic = instr->hydrogen()->need_generic(); + + if (map_count == 0 && !need_generic) { + DeoptimizeIf(al, instr->environment()); + return; + } Handle<String> name = instr->hydrogen()->name(); - if (map_count == 0) { - ASSERT(instr->hydrogen()->need_generic()); - __ mov(r2, Operand(name)); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); - } else { - Label done; - __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); - for (int i = 0; i < map_count - 1; ++i) { - Handle<Map> map = instr->hydrogen()->types()->at(i); + Label done; + __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); + for (int i = 0; i < map_count; ++i) { + bool last = (i == map_count - 1); + Handle<Map> map = instr->hydrogen()->types()->at(i); + __ cmp(scratch, Operand(map)); + if (last && !need_generic) { + DeoptimizeIf(ne, instr->environment()); + EmitLoadFieldOrConstantFunction(result, object, map, name); + } else { Label next; - __ cmp(scratch, Operand(map)); __ b(ne, &next); EmitLoadFieldOrConstantFunction(result, object, map, name); __ b(&done); __ bind(&next); } - Handle<Map> map = instr->hydrogen()->types()->last(); - __ cmp(scratch, Operand(map)); - if (instr->hydrogen()->need_generic()) { - Label generic; - __ b(ne, &generic); - EmitLoadFieldOrConstantFunction(result, object, map, name); - __ b(&done); - __ bind(&generic); - __ mov(r2, Operand(name)); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); - } else { - DeoptimizeIf(ne, instr->environment()); - EmitLoadFieldOrConstantFunction(result, object, map, name); - } - __ bind(&done); } + if (need_generic) { + __ mov(r2, Operand(name)); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + CallCode(ic, RelocInfo::CODE_TARGET, instr); + } + __ bind(&done); } @@ -2764,16 +2881,20 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { Register scratch = scratch0(); Register result = ToRegister(instr->result()); - // Check if the calling frame is an arguments adaptor frame. - Label done, adapted; - __ ldr(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); - __ ldr(result, MemOperand(scratch, StandardFrameConstants::kContextOffset)); - __ cmp(result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); + if (instr->hydrogen()->from_inlined()) { + __ sub(result, sp, Operand(2 * kPointerSize)); + } else { + // Check if the calling frame is an arguments adaptor frame. + Label done, adapted; + __ ldr(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); + __ ldr(result, MemOperand(scratch, StandardFrameConstants::kContextOffset)); + __ cmp(result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); - // Result is the frame pointer for the frame if not adapted and for the real - // frame below the adaptor frame if adapted. - __ mov(result, fp, LeaveCC, ne); - __ mov(result, scratch, LeaveCC, eq); + // Result is the frame pointer for the frame if not adapted and for the real + // frame below the adaptor frame if adapted. + __ mov(result, fp, LeaveCC, ne); + __ mov(result, scratch, LeaveCC, eq); + } } @@ -2882,7 +3003,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { __ b(ne, &loop); __ bind(&invoke); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator( @@ -2907,6 +3028,11 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) { } +void LCodeGen::DoDrop(LDrop* instr) { + __ Drop(instr->count()); +} + + void LCodeGen::DoThisFunction(LThisFunction* instr) { Register result = ToRegister(instr->result()); __ LoadHeapObject(result, instr->hydrogen()->closure()); @@ -2953,7 +3079,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { void LCodeGen::CallKnownFunction(Handle<JSFunction> function, int arity, LInstruction* instr, - CallKind call_kind) { + CallKind call_kind, + R1State r1_state) { bool can_invoke_directly = !function->NeedsArgumentsAdaption() || function->shared()->formal_parameter_count() == arity; @@ -2961,7 +3088,10 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, RecordPosition(pointers->position()); if (can_invoke_directly) { - __ LoadHeapObject(r1, function); + if (r1_state == R1_UNINITIALIZED) { + __ LoadHeapObject(r1, function); + } + // Change context if needed. bool change_context = (info()->closure()->context() != function->context()) || @@ -3000,7 +3130,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { CallKnownFunction(instr->function(), instr->arity(), instr, - CALL_AS_METHOD); + CALL_AS_METHOD, + R1_UNINITIALIZED); } @@ -3424,13 +3555,21 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { ASSERT(ToRegister(instr->function()).is(r1)); ASSERT(instr->HasPointerMap()); - ASSERT(instr->HasDeoptimizationEnvironment()); - LPointerMap* pointers = instr->pointer_map(); - RecordPosition(pointers->position()); - SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); - ParameterCount count(instr->arity()); - __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD); - __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + + if (instr->known_function().is_null()) { + LPointerMap* pointers = instr->pointer_map(); + RecordPosition(pointers->position()); + SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); + ParameterCount count(instr->arity()); + __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD); + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } else { + CallKnownFunction(instr->known_function(), + instr->arity(), + instr, + CALL_AS_METHOD, + R1_CONTAINS_TARGET); + } } @@ -3485,7 +3624,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { ASSERT(ToRegister(instr->result()).is(r0)); - CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); + CallKnownFunction(instr->target(), + instr->arity(), + instr, + CALL_AS_FUNCTION, + R1_UNINITIALIZED); } @@ -3615,7 +3758,6 @@ void LCodeGen::DoStoreKeyedFastDoubleElement( Register scratch = scratch0(); bool key_is_constant = instr->key()->IsConstantOperand(); int constant_key = 0; - Label not_nan; // Calculate the effective address of the slot in the array to store the // double value. @@ -3638,13 +3780,15 @@ void LCodeGen::DoStoreKeyedFastDoubleElement( Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); } - // Check for NaN. All NaNs must be canonicalized. - __ VFPCompareAndSetFlags(value, value); - - // Only load canonical NaN if the comparison above set the overflow. - __ Vmov(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double(), vs); + if (instr->NeedsCanonicalization()) { + // Check for NaN. All NaNs must be canonicalized. + __ VFPCompareAndSetFlags(value, value); + // Only load canonical NaN if the comparison above set the overflow. + __ Vmov(value, + FixedDoubleArray::canonical_not_the_hole_nan_as_double(), + vs); + } - __ bind(¬_nan); __ vstr(value, scratch, 0); } @@ -4338,14 +4482,22 @@ void LCodeGen::DoCheckMapCommon(Register reg, } -void LCodeGen::DoCheckMap(LCheckMap* instr) { +void LCodeGen::DoCheckMaps(LCheckMaps* instr) { Register scratch = scratch0(); LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister()); Register reg = ToRegister(input); - Handle<Map> map = instr->hydrogen()->map(); - DoCheckMapCommon(reg, scratch, map, instr->hydrogen()->mode(), - instr->environment()); + + Label success; + SmallMapList* map_set = instr->hydrogen()->map_set(); + for (int i = 0; i < map_set->length() - 1; i++) { + Handle<Map> map = map_set->at(i); + __ CompareMap(reg, scratch, map, &success, REQUIRE_EXACT_MAP); + __ b(eq, &success); + } + Handle<Map> map = map_set->last(); + DoCheckMapCommon(reg, scratch, map, REQUIRE_EXACT_MAP, instr->environment()); + __ bind(&success); } @@ -4464,6 +4616,14 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { deferred->entry(), TAG_OBJECT); + __ bind(deferred->exit()); + if (FLAG_debug_code) { + Label is_in_new_space; + __ JumpIfInNewSpace(result, scratch, &is_in_new_space); + __ Abort("Allocated object is not in new-space"); + __ bind(&is_in_new_space); + } + // Load the initial map. Register map = scratch; __ LoadHeapObject(map, constructor); @@ -4482,14 +4642,14 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { __ str(scratch, FieldMemOperand(result, property_offset)); } } - - __ bind(deferred->exit()); } void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { Register result = ToRegister(instr->result()); Handle<JSFunction> constructor = instr->hydrogen()->constructor(); + Handle<Map> initial_map(constructor->initial_map()); + int instance_size = initial_map->instance_size(); // TODO(3095996): Get rid of this. For now, we need to make the // result register contain a valid pointer because it is already @@ -4497,9 +4657,9 @@ void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { __ mov(result, Operand(0)); PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); - __ LoadHeapObject(r0, constructor); + __ mov(r0, Operand(Smi::FromInt(instance_size))); __ push(r0); - CallRuntimeFromDeferred(Runtime::kNewObject, 1, instr); + CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); __ StoreToSafepointRegisterSlot(r0, result); } @@ -4633,9 +4793,10 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, __ str(r2, FieldMemOperand(result, total_offset + 4)); } } else if (elements->IsFixedArray()) { + Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); for (int i = 0; i < elements_length; i++) { int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i); - Handle<Object> value = JSObject::GetElement(object, i); + Handle<Object> value(fast_elements->get(i)); if (value->IsJSObject()) { Handle<JSObject> value_object = Handle<JSObject>::cast(value); __ add(r2, result, Operand(*offset)); @@ -4659,6 +4820,23 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, void LCodeGen::DoFastLiteral(LFastLiteral* instr) { int size = instr->hydrogen()->total_size(); + ElementsKind boilerplate_elements_kind = + instr->hydrogen()->boilerplate()->GetElementsKind(); + + // Deopt if the literal boilerplate ElementsKind is of a type different than + // the expected one. The check isn't necessary if the boilerplate has already + // been converted to FAST_ELEMENTS. + if (boilerplate_elements_kind != FAST_ELEMENTS) { + __ LoadHeapObject(r1, instr->hydrogen()->boilerplate()); + // Load map into r2. + __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); + // Load the map's "bit field 2". + __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset)); + // Retrieve elements_kind from bit field 2. + __ ubfx(r2, r2, Map::kElementsKindShift, Map::kElementsKindBitCount); + __ cmp(r2, Operand(boilerplate_elements_kind)); + DeoptimizeIf(ne, instr->environment()); + } // Allocate all objects that are part of the literal in one big // allocation. This avoids multiple limit checks. @@ -4954,7 +5132,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { Register strict = scratch0(); __ mov(strict, Operand(Smi::FromInt(strict_mode_flag()))); __ Push(object, key, strict); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator( @@ -4967,7 +5145,7 @@ void LCodeGen::DoIn(LIn* instr) { Register obj = ToRegister(instr->object()); Register key = ToRegister(instr->key()); __ Push(key, obj); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); diff --git a/deps/v8/src/arm/lithium-codegen-arm.h b/deps/v8/src/arm/lithium-codegen-arm.h index adb6e1bb73..c6a3af7e02 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.h +++ b/deps/v8/src/arm/lithium-codegen-arm.h @@ -215,12 +215,18 @@ class LCodeGen BASE_EMBEDDED { int argc, LInstruction* instr); + enum R1State { + R1_UNINITIALIZED, + R1_CONTAINS_TARGET + }; + // Generate a direct call to a known function. Expects the function // to be in r1. void CallKnownFunction(Handle<JSFunction> function, int arity, LInstruction* instr, - CallKind call_kind); + CallKind call_kind, + R1State r1_state); void LoadHeapObject(Register result, Handle<HeapObject> object); @@ -317,6 +323,17 @@ class LCodeGen BASE_EMBEDDED { Register source, int* offset); + // Emit optimized code for integer division. + // Inputs are signed. + // All registers are clobbered. + // If 'remainder' is no_reg, it is not computed. + void EmitSignedIntegerDivisionByConstant(Register result, + Register dividend, + int32_t divisor, + Register remainder, + Register scratch, + LEnvironment* environment); + struct JumpTableEntry { explicit inline JumpTableEntry(Address entry) : label(), diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 857c2bf770..4da2fece03 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -3710,22 +3710,35 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) { } -bool AreAliased(Register r1, Register r2, Register r3, Register r4) { - if (r1.is(r2)) return true; - if (r1.is(r3)) return true; - if (r1.is(r4)) return true; - if (r2.is(r3)) return true; - if (r2.is(r4)) return true; - if (r3.is(r4)) return true; - return false; +#ifdef DEBUG +bool AreAliased(Register reg1, + Register reg2, + Register reg3, + Register reg4, + Register reg5, + Register reg6) { + int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + + reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid(); + + RegList regs = 0; + if (reg1.is_valid()) regs |= reg1.bit(); + if (reg2.is_valid()) regs |= reg2.bit(); + if (reg3.is_valid()) regs |= reg3.bit(); + if (reg4.is_valid()) regs |= reg4.bit(); + if (reg5.is_valid()) regs |= reg5.bit(); + if (reg6.is_valid()) regs |= reg6.bit(); + int n_of_non_aliasing_regs = NumRegs(regs); + + return n_of_valid_regs != n_of_non_aliasing_regs; } +#endif CodePatcher::CodePatcher(byte* address, int instructions) : address_(address), instructions_(instructions), size_(instructions * Assembler::kInstrSize), - masm_(Isolate::Current(), address, size_ + Assembler::kGap) { + masm_(NULL, address, size_ + Assembler::kGap) { // Create a new macro assembler pointing to the address of the code to patch. // The size is adjusted with kGap on order for the assembler to generate size // bytes of instructions without failing with buffer size constraints. diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 47afa93a6e..360f4c128c 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -85,7 +85,14 @@ enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved }; -bool AreAliased(Register r1, Register r2, Register r3, Register r4); +#ifdef DEBUG +bool AreAliased(Register reg1, + Register reg2, + Register reg3 = no_reg, + Register reg4 = no_reg, + Register reg5 = no_reg, + Register reg6 = no_reg); +#endif // MacroAssembler implements a collection of frequently used macros. @@ -1321,7 +1328,6 @@ class MacroAssembler: public Assembler { }; -#ifdef ENABLE_DEBUGGER_SUPPORT // The code patcher is used to patch (typically) small parts of code e.g. for // debugging and other types of instrumentation. When using the code patcher // the exact number of bytes specified must be emitted. It is not legal to emit @@ -1351,7 +1357,6 @@ class CodePatcher { int size_; // Number of bytes of the expected patch size. MacroAssembler masm_; // Macro assembler used to generate the code. }; -#endif // ENABLE_DEBUGGER_SUPPORT // ----------------------------------------------------------------------------- diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index 10ff2dd96c..a833624ceb 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -452,8 +452,12 @@ void RegExpMacroAssemblerARM::CheckNotCharacter(unsigned c, void RegExpMacroAssemblerARM::CheckCharacterAfterAnd(uint32_t c, uint32_t mask, Label* on_equal) { - __ and_(r0, current_character(), Operand(mask)); - __ cmp(r0, Operand(c)); + if (c == 0) { + __ tst(current_character(), Operand(mask)); + } else { + __ and_(r0, current_character(), Operand(mask)); + __ cmp(r0, Operand(c)); + } BranchOrBacktrack(eq, on_equal); } @@ -461,8 +465,12 @@ void RegExpMacroAssemblerARM::CheckCharacterAfterAnd(uint32_t c, void RegExpMacroAssemblerARM::CheckNotCharacterAfterAnd(unsigned c, unsigned mask, Label* on_not_equal) { - __ and_(r0, current_character(), Operand(mask)); - __ cmp(r0, Operand(c)); + if (c == 0) { + __ tst(current_character(), Operand(mask)); + } else { + __ and_(r0, current_character(), Operand(mask)); + __ cmp(r0, Operand(c)); + } BranchOrBacktrack(ne, on_not_equal); } @@ -480,6 +488,44 @@ void RegExpMacroAssemblerARM::CheckNotCharacterAfterMinusAnd( } +void RegExpMacroAssemblerARM::CheckCharacterInRange( + uc16 from, + uc16 to, + Label* on_in_range) { + __ sub(r0, current_character(), Operand(from)); + __ cmp(r0, Operand(to - from)); + BranchOrBacktrack(ls, on_in_range); // Unsigned lower-or-same condition. +} + + +void RegExpMacroAssemblerARM::CheckCharacterNotInRange( + uc16 from, + uc16 to, + Label* on_not_in_range) { + __ sub(r0, current_character(), Operand(from)); + __ cmp(r0, Operand(to - from)); + BranchOrBacktrack(hi, on_not_in_range); // Unsigned higher condition. +} + + +void RegExpMacroAssemblerARM::CheckBitInTable( + Handle<ByteArray> table, + Label* on_bit_set) { + __ mov(r0, Operand(table)); + if (mode_ != ASCII || kTableMask != String::kMaxAsciiCharCode) { + __ and_(r1, current_character(), Operand(kTableSize - 1)); + __ add(r1, r1, Operand(ByteArray::kHeaderSize - kHeapObjectTag)); + } else { + __ add(r1, + current_character(), + Operand(ByteArray::kHeaderSize - kHeapObjectTag)); + } + __ ldrb(r0, MemOperand(r0, r1)); + __ cmp(r0, Operand(0)); + BranchOrBacktrack(ne, on_bit_set); +} + + bool RegExpMacroAssemblerARM::CheckSpecialCharacterClass(uc16 type, Label* on_no_match) { // Range checks (c in min..max) are generally implemented by an unsigned diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.h b/deps/v8/src/arm/regexp-macro-assembler-arm.h index 5c8ed0693f..14f984f567 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.h +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.h @@ -79,6 +79,14 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { uc16 minus, uc16 mask, Label* on_not_equal); + virtual void CheckCharacterInRange(uc16 from, + uc16 to, + Label* on_in_range); + virtual void CheckCharacterNotInRange(uc16 from, + uc16 to, + Label* on_not_in_range); + virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set); + // Checks whether the given offset from the current position is before // the end of the string. virtual void CheckPosition(int cp_offset, Label* on_outside_input); diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 06f8385af9..49c0982301 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -443,8 +443,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, Label exit; // Check that the map of the object hasn't changed. + CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS + : REQUIRE_EXACT_MAP; __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label, - DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); + DO_SMI_CHECK, mode); // Perform global security token check if needed. if (object->IsJSGlobalProxy()) { @@ -580,6 +582,8 @@ static void PushInterceptorArguments(MacroAssembler* masm, __ push(holder); __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset)); __ push(scratch); + __ mov(scratch, Operand(ExternalReference::isolate_address())); + __ push(scratch); } @@ -594,7 +598,7 @@ static void CompileCallLoadPropertyWithInterceptor( ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), masm->isolate()); - __ mov(r0, Operand(5)); + __ mov(r0, Operand(6)); __ mov(r1, Operand(ref)); CEntryStub stub(1); @@ -602,9 +606,9 @@ static void CompileCallLoadPropertyWithInterceptor( } -static const int kFastApiCallArguments = 3; +static const int kFastApiCallArguments = 4; -// Reserves space for the extra arguments to FastHandleApiCall in the +// Reserves space for the extra arguments to API function in the // caller's frame. // // These arguments are set by CheckPrototypes and GenerateFastApiDirectCall. @@ -630,7 +634,8 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, // -- sp[0] : holder (set by CheckPrototypes) // -- sp[4] : callee JS function // -- sp[8] : call data - // -- sp[12] : last JS argument + // -- sp[12] : isolate + // -- sp[16] : last JS argument // -- ... // -- sp[(argc + 3) * 4] : first JS argument // -- sp[(argc + 4) * 4] : receiver @@ -640,7 +645,7 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, __ LoadHeapObject(r5, function); __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset)); - // Pass the additional arguments FastHandleApiCall expects. + // Pass the additional arguments. Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); Handle<Object> call_data(api_call_info->data()); if (masm->isolate()->heap()->InNewSpace(*call_data)) { @@ -649,13 +654,15 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, } else { __ Move(r6, call_data); } - // Store JS function and call data. - __ stm(ib, sp, r5.bit() | r6.bit()); + __ mov(r7, Operand(ExternalReference::isolate_address())); + // Store JS function, call data and isolate. + __ stm(ib, sp, r5.bit() | r6.bit() | r7.bit()); - // r2 points to call data as expected by Arguments - // (refer to layout above). - __ add(r2, sp, Operand(2 * kPointerSize)); + // Prepare arguments. + __ add(r2, sp, Operand(3 * kPointerSize)); + // Allocate the v8::Arguments structure in the arguments' space since + // it's not controlled by GC. const int kApiStackSpace = 4; FrameScope frame_scope(masm, StackFrame::MANUAL); @@ -664,9 +671,9 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, // r0 = v8::Arguments& // Arguments is after the return address. __ add(r0, sp, Operand(1 * kPointerSize)); - // v8::Arguments::implicit_args = data + // v8::Arguments::implicit_args_ __ str(r2, MemOperand(r0, 0 * kPointerSize)); - // v8::Arguments::values = last argument + // v8::Arguments::values_ __ add(ip, r2, Operand(argc * kPointerSize)); __ str(ip, MemOperand(r0, 1 * kPointerSize)); // v8::Arguments::length_ = argc @@ -843,7 +850,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { __ CallExternalReference( ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), masm->isolate()), - 5); + 6); // Restore the name_ register. __ pop(name_); // Leave the internal frame. @@ -1202,7 +1209,9 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, } else { __ Move(scratch3, Handle<Object>(callback->data())); } - __ Push(reg, scratch3, name_reg); + __ Push(reg, scratch3); + __ mov(scratch3, Operand(ExternalReference::isolate_address())); + __ Push(scratch3, name_reg); __ mov(r0, sp); // r0 = Handle<String> const int kApiStackSpace = 1; @@ -1214,7 +1223,7 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, __ str(scratch2, MemOperand(sp, 1 * kPointerSize)); __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo& - const int kStackUnwindSpace = 4; + const int kStackUnwindSpace = 5; Address getter_address = v8::ToCData<Address>(callback->getter()); ApiFunction fun(getter_address); ExternalReference ref = @@ -1264,12 +1273,19 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, name, miss); ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); + // Preserve the receiver register explicitly whenever it is different from + // the holder and it is needed should the interceptor return without any + // result. The CALLBACKS case needs the receiver to be passed into C++ code, + // the FIELD case might cause a miss during the prototype check. + bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); + bool must_preserve_receiver_reg = !receiver.is(holder_reg) && + (lookup->type() == CALLBACKS || must_perfrom_prototype_check); + // Save necessary data before invoking an interceptor. // Requires a frame to make GC aware of pushed pointers. { FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { - // CALLBACKS case needs a receiver to be passed into C++ callback. + if (must_preserve_receiver_reg) { __ Push(receiver, holder_reg, name_reg); } else { __ Push(holder_reg, name_reg); @@ -1294,14 +1310,14 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, __ bind(&interceptor_failed); __ pop(name_reg); __ pop(holder_reg); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { + if (must_preserve_receiver_reg) { __ pop(receiver); } // Leave the internal frame. } // Check that the maps from interceptor's holder to lookup's holder // haven't changed. And load lookup's holder into |holder| register. - if (*interceptor_holder != lookup->holder()) { + if (must_perfrom_prototype_check) { holder_reg = CheckPrototypes(interceptor_holder, holder_reg, Handle<JSObject>(lookup->holder()), @@ -1335,20 +1351,19 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, if (!receiver.is(holder_reg)) { ASSERT(scratch1.is(holder_reg)); __ Push(receiver, holder_reg); - __ ldr(scratch3, - FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); - __ Push(scratch3, scratch2, name_reg); } else { __ push(receiver); - __ ldr(scratch3, - FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); - __ Push(holder_reg, scratch3, scratch2, name_reg); + __ push(holder_reg); } + __ ldr(scratch3, + FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); + __ mov(scratch1, Operand(ExternalReference::isolate_address())); + __ Push(scratch3, scratch1, scratch2, name_reg); ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadCallbackProperty), masm()->isolate()); - __ TailCallExternalReference(ref, 5, 1); + __ TailCallExternalReference(ref, 6, 1); } } else { // !compile_followup_inline // Call the runtime system to load the interceptor. @@ -1362,7 +1377,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate()); - __ TailCallExternalReference(ref, 5, 1); + __ TailCallExternalReference(ref, 6, 1); } } @@ -1730,7 +1745,7 @@ Handle<Code> CallStubCompiler::CompileArrayPopCall( // We can't address the last element in one operation. Compute the more // expensive shift first, and use an offset later on. __ add(elements, elements, Operand(r4, LSL, kPointerSizeLog2 - kSmiTagSize)); - __ ldr(r0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag)); + __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize)); __ cmp(r0, r6); __ b(eq, &call_builtin); @@ -1738,7 +1753,7 @@ Handle<Code> CallStubCompiler::CompileArrayPopCall( __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); // Fill with the hole. - __ str(r6, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag)); + __ str(r6, FieldMemOperand(elements, FixedArray::kHeaderSize)); __ Drop(argc + 1); __ Ret(); @@ -3368,6 +3383,44 @@ static bool IsElementTypeSigned(ElementsKind elements_kind) { } +static void GenerateSmiKeyCheck(MacroAssembler* masm, + Register key, + Register scratch0, + Register scratch1, + DwVfpRegister double_scratch0, + Label* fail) { + if (CpuFeatures::IsSupported(VFP3)) { + CpuFeatures::Scope scope(VFP3); + Label key_ok; + // Check for smi or a smi inside a heap number. We convert the heap + // number and check if the conversion is exact and fits into the smi + // range. + __ JumpIfSmi(key, &key_ok); + __ CheckMap(key, + scratch0, + Heap::kHeapNumberMapRootIndex, + fail, + DONT_DO_SMI_CHECK); + __ sub(ip, key, Operand(kHeapObjectTag)); + __ vldr(double_scratch0, ip, HeapNumber::kValueOffset); + __ EmitVFPTruncate(kRoundToZero, + double_scratch0.low(), + double_scratch0, + scratch0, + scratch1, + kCheckForInexactConversion); + __ b(ne, fail); + __ vmov(scratch0, double_scratch0.low()); + __ TrySmiTag(scratch0, fail, scratch1); + __ mov(key, scratch0); + __ bind(&key_ok); + } else { + // Check that the key is a smi. + __ JumpIfNotSmi(key, fail); + } +} + + void KeyedLoadStubCompiler::GenerateLoadExternalArray( MacroAssembler* masm, ElementsKind elements_kind) { @@ -3384,8 +3437,8 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(key, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key, r4, r5, d1, &miss_force_generic); __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); // r3: elements array @@ -3715,8 +3768,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(key, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key, r4, r5, d1, &miss_force_generic); __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); @@ -4041,8 +4094,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(r0, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, r0, r4, r5, d1, &miss_force_generic); // Get the elements array. __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset)); @@ -4093,8 +4146,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(key_reg, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, &miss_force_generic); // Get the elements array. __ ldr(elements_reg, @@ -4169,8 +4222,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(key_reg, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, &miss_force_generic); if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { __ JumpIfNotSmi(value_reg, &transition_elements_kind); @@ -4336,7 +4389,9 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - __ JumpIfNotSmi(key_reg, &miss_force_generic); + + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, &miss_force_generic); __ ldr(elements_reg, FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); @@ -4427,6 +4482,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // Increment the length of the array. __ mov(length_reg, Operand(Smi::FromInt(1))); __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); + __ ldr(elements_reg, + FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); __ jmp(&finish_store); __ bind(&check_capacity); diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index daa75d5753..9f2c8de3b1 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -465,15 +465,19 @@ function ArrayPush() { } +// Returns an array containing the array elements of the object followed +// by the array elements of each argument in order. See ECMA-262, +// section 15.4.4.7. function ArrayConcat(arg1) { // length == 1 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { throw MakeTypeError("called_on_null_or_undefined", ["Array.prototype.concat"]); } + var array = ToObject(this); var arg_count = %_ArgumentsLength(); var arrays = new InternalArray(1 + arg_count); - arrays[0] = this; + arrays[0] = array; for (var i = 0; i < arg_count; i++) { arrays[i + 1] = %_Arguments(i); } @@ -1023,13 +1027,28 @@ function ArrayFilter(f, receiver) { var result = new $Array(); var accumulator = new InternalArray(); var accumulator_length = 0; - for (var i = 0; i < length; i++) { - if (i in array) { - var element = array[i]; - if (%_CallFunction(receiver, element, i, array, f)) { - accumulator[accumulator_length++] = element; + if (%DebugCallbackSupportsStepping(f)) { + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + // Prepare break slots for debugger step in. + %DebugPrepareStepInIfStepping(f); + if (%_CallFunction(receiver, element, i, array, f)) { + accumulator[accumulator_length++] = element; + } + } + } + } else { + // This is a duplicate of the previous loop sans debug stepping. + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + if (%_CallFunction(receiver, element, i, array, f)) { + accumulator[accumulator_length++] = element; + } } } + // End of duplicate. } %MoveArrayContents(accumulator, result); return result; @@ -1055,12 +1074,24 @@ function ArrayForEach(f, receiver) { } else if (!IS_SPEC_OBJECT(receiver)) { receiver = ToObject(receiver); } - - for (var i = 0; i < length; i++) { - if (i in array) { - var element = array[i]; - %_CallFunction(receiver, element, i, array, f); + if (%DebugCallbackSupportsStepping(f)) { + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + // Prepare break slots for debugger step in. + %DebugPrepareStepInIfStepping(f); + %_CallFunction(receiver, element, i, array, f); + } } + } else { + // This is a duplicate of the previous loop sans debug stepping. + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + %_CallFunction(receiver, element, i, array, f); + } + } + // End of duplicate. } } @@ -1087,11 +1118,24 @@ function ArraySome(f, receiver) { receiver = ToObject(receiver); } - for (var i = 0; i < length; i++) { - if (i in array) { - var element = array[i]; - if (%_CallFunction(receiver, element, i, array, f)) return true; + if (%DebugCallbackSupportsStepping(f)) { + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + // Prepare break slots for debugger step in. + %DebugPrepareStepInIfStepping(f); + if (%_CallFunction(receiver, element, i, array, f)) return true; + } + } + } else { + // This is a duplicate of the previous loop sans debug stepping. + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + if (%_CallFunction(receiver, element, i, array, f)) return true; + } } + // End of duplicate. } return false; } @@ -1117,11 +1161,24 @@ function ArrayEvery(f, receiver) { receiver = ToObject(receiver); } - for (var i = 0; i < length; i++) { - if (i in array) { - var element = array[i]; - if (!%_CallFunction(receiver, element, i, array, f)) return false; + if (%DebugCallbackSupportsStepping(f)) { + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + // Prepare break slots for debugger step in. + %DebugPrepareStepInIfStepping(f); + if (!%_CallFunction(receiver, element, i, array, f)) return false; + } + } + } else { + // This is a duplicate of the previous loop sans debug stepping. + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + if (!%_CallFunction(receiver, element, i, array, f)) return false; + } } + // End of duplicate. } return true; } @@ -1148,11 +1205,24 @@ function ArrayMap(f, receiver) { var result = new $Array(); var accumulator = new InternalArray(length); - for (var i = 0; i < length; i++) { - if (i in array) { - var element = array[i]; - accumulator[i] = %_CallFunction(receiver, element, i, array, f); + if (%DebugCallbackSupportsStepping(f)) { + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + // Prepare break slots for debugger step in. + %DebugPrepareStepInIfStepping(f); + accumulator[i] = %_CallFunction(receiver, element, i, array, f); + } } + } else { + // This is a duplicate of the previous loop sans debug stepping. + for (var i = 0; i < length; i++) { + if (i in array) { + var element = array[i]; + accumulator[i] = %_CallFunction(receiver, element, i, array, f); + } + } + // End of duplicate. } %MoveArrayContents(accumulator, result); return result; @@ -1307,11 +1377,27 @@ function ArrayReduce(callback, current) { } var receiver = %GetDefaultReceiver(callback); - for (; i < length; i++) { - if (i in array) { - var element = array[i]; - current = %_CallFunction(receiver, current, element, i, array, callback); + + if (%DebugCallbackSupportsStepping(callback)) { + for (; i < length; i++) { + if (i in array) { + var element = array[i]; + // Prepare break slots for debugger step in. + %DebugPrepareStepInIfStepping(callback); + current = + %_CallFunction(receiver, current, element, i, array, callback); + } + } + } else { + // This is a duplicate of the previous loop sans debug stepping. + for (; i < length; i++) { + if (i in array) { + var element = array[i]; + current = + %_CallFunction(receiver, current, element, i, array, callback); + } } + // End of duplicate. } return current; } @@ -1344,11 +1430,27 @@ function ArrayReduceRight(callback, current) { } var receiver = %GetDefaultReceiver(callback); - for (; i >= 0; i--) { - if (i in array) { - var element = array[i]; - current = %_CallFunction(receiver, current, element, i, array, callback); + + if (%DebugCallbackSupportsStepping(callback)) { + for (; i >= 0; i--) { + if (i in array) { + var element = array[i]; + // Prepare break slots for debugger step in. + %DebugPrepareStepInIfStepping(callback); + current = + %_CallFunction(receiver, current, element, i, array, callback); + } + } + } else { + // This is a duplicate of the previous loop sans debug stepping. + for (; i >= 0; i--) { + if (i in array) { + var element = array[i]; + current = + %_CallFunction(receiver, current, element, i, array, callback); + } } + // End of duplicate. } return current; } diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index 4944202f07..be2564960d 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -99,21 +99,7 @@ struct DoubleConstant BASE_EMBEDDED { double the_hole_nan; }; -struct InitializeDoubleConstants { - static void Construct(DoubleConstant* double_constants) { - double_constants->min_int = kMinInt; - double_constants->one_half = 0.5; - double_constants->minus_zero = -0.0; - double_constants->uint8_max_value = 255; - double_constants->zero = 0.0; - double_constants->canonical_non_hole_nan = OS::nan_value(); - double_constants->the_hole_nan = BitCast<double>(kHoleNanInt64); - double_constants->negative_infinity = -V8_INFINITY; - } -}; - -static LazyInstance<DoubleConstant, InitializeDoubleConstants>::type - double_constants = LAZY_INSTANCE_INITIALIZER; +static DoubleConstant double_constants; const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING"; @@ -726,6 +712,18 @@ void RelocInfo::Verify() { // ----------------------------------------------------------------------------- // Implementation of ExternalReference +void ExternalReference::SetUp() { + double_constants.min_int = kMinInt; + double_constants.one_half = 0.5; + double_constants.minus_zero = -0.0; + double_constants.uint8_max_value = 255; + double_constants.zero = 0.0; + double_constants.canonical_non_hole_nan = OS::nan_value(); + double_constants.the_hole_nan = BitCast<double>(kHoleNanInt64); + double_constants.negative_infinity = -V8_INFINITY; +} + + ExternalReference::ExternalReference(Builtins::CFunctionId id, Isolate* isolate) : address_(Redirect(isolate, Builtins::c_function_address(id))) {} @@ -958,50 +956,47 @@ ExternalReference ExternalReference::scheduled_exception_address( ExternalReference ExternalReference::address_of_min_int() { - return ExternalReference(reinterpret_cast<void*>( - &double_constants.Pointer()->min_int)); + return ExternalReference(reinterpret_cast<void*>(&double_constants.min_int)); } ExternalReference ExternalReference::address_of_one_half() { - return ExternalReference(reinterpret_cast<void*>( - &double_constants.Pointer()->one_half)); + return ExternalReference(reinterpret_cast<void*>(&double_constants.one_half)); } ExternalReference ExternalReference::address_of_minus_zero() { - return ExternalReference(reinterpret_cast<void*>( - &double_constants.Pointer()->minus_zero)); + return ExternalReference( + reinterpret_cast<void*>(&double_constants.minus_zero)); } ExternalReference ExternalReference::address_of_zero() { - return ExternalReference(reinterpret_cast<void*>( - &double_constants.Pointer()->zero)); + return ExternalReference(reinterpret_cast<void*>(&double_constants.zero)); } ExternalReference ExternalReference::address_of_uint8_max_value() { - return ExternalReference(reinterpret_cast<void*>( - &double_constants.Pointer()->uint8_max_value)); + return ExternalReference( + reinterpret_cast<void*>(&double_constants.uint8_max_value)); } ExternalReference ExternalReference::address_of_negative_infinity() { - return ExternalReference(reinterpret_cast<void*>( - &double_constants.Pointer()->negative_infinity)); + return ExternalReference( + reinterpret_cast<void*>(&double_constants.negative_infinity)); } ExternalReference ExternalReference::address_of_canonical_non_hole_nan() { - return ExternalReference(reinterpret_cast<void*>( - &double_constants.Pointer()->canonical_non_hole_nan)); + return ExternalReference( + reinterpret_cast<void*>(&double_constants.canonical_non_hole_nan)); } ExternalReference ExternalReference::address_of_the_hole_nan() { - return ExternalReference(reinterpret_cast<void*>( - &double_constants.Pointer()->the_hole_nan)); + return ExternalReference( + reinterpret_cast<void*>(&double_constants.the_hole_nan)); } @@ -1158,6 +1153,20 @@ double power_double_int(double x, int y) { double power_double_double(double x, double y) { +#ifdef __MINGW64_VERSION_MAJOR + // MinGW64 has a custom implementation for pow. This handles certain + // special cases that are different. + if ((x == 0.0 || isinf(x)) && isfinite(y)) { + double f; + if (modf(y, &f) != 0.0) return ((x == 0.0) ^ (y > 0)) ? V8_INFINITY : 0; + } + + if (x == 2.0) { + int y_int = static_cast<int>(y); + if (y == y_int) return ldexp(1.0, y_int); + } +#endif + // The checks for special cases can be dropped in ia32 because it has already // been done in generated code before bailing out here. if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) return OS::nan_value(); diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 918a2a679b..05fe320ad0 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -62,6 +62,10 @@ class AssemblerBase: public Malloced { Isolate* isolate() const { return isolate_; } int jit_cookie() { return jit_cookie_; } + // Overwrite a host NaN with a quiet target NaN. Used by mksnapshot for + // cross-snapshotting. + static void QuietNaN(HeapObject* nan) { } + private: Isolate* isolate_; int jit_cookie_; @@ -535,6 +539,8 @@ class ExternalReference BASE_EMBEDDED { DIRECT_GETTER_CALL }; + static void SetUp(); + typedef void* ExternalReferenceRedirector(void* original, Type type); ExternalReference(Builtins::CFunctionId id, Isolate* isolate); diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 4b6ae680a4..6f9fd7afb2 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -962,6 +962,14 @@ RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives) } +static int IncreaseBy(int previous, int increase) { + if (RegExpTree::kInfinity - previous < increase) { + return RegExpTree::kInfinity; + } else { + return previous + increase; + } +} + RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes) : nodes_(nodes) { ASSERT(nodes->length() > 1); @@ -969,13 +977,10 @@ RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes) max_match_ = 0; for (int i = 0; i < nodes->length(); i++) { RegExpTree* node = nodes->at(i); - min_match_ += node->min_match(); + int node_min_match = node->min_match(); + min_match_ = IncreaseBy(min_match_, node_min_match); int node_max_match = node->max_match(); - if (kInfinity - max_match_ < node_max_match) { - max_match_ = kInfinity; - } else { - max_match_ += node->max_match(); - } + max_match_ = IncreaseBy(max_match_, node_max_match); } } @@ -993,138 +998,78 @@ CaseClause::CaseClause(Isolate* isolate, } -#define INCREASE_NODE_COUNT(NodeType) \ +#define REGULAR_NODE(NodeType) \ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ increase_node_count(); \ } +#define DONT_OPTIMIZE_NODE(NodeType) \ + void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ + increase_node_count(); \ + add_flag(kDontOptimize); \ + add_flag(kDontInline); \ + add_flag(kDontSelfOptimize); \ + } +#define DONT_INLINE_NODE(NodeType) \ + void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ + increase_node_count(); \ + add_flag(kDontInline); \ + } +#define DONT_SELFOPTIMIZE_NODE(NodeType) \ + void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ + increase_node_count(); \ + add_flag(kDontSelfOptimize); \ + } -INCREASE_NODE_COUNT(VariableDeclaration) -INCREASE_NODE_COUNT(FunctionDeclaration) -INCREASE_NODE_COUNT(ModuleDeclaration) -INCREASE_NODE_COUNT(ImportDeclaration) -INCREASE_NODE_COUNT(ExportDeclaration) -INCREASE_NODE_COUNT(ModuleLiteral) -INCREASE_NODE_COUNT(ModuleVariable) -INCREASE_NODE_COUNT(ModulePath) -INCREASE_NODE_COUNT(ModuleUrl) -INCREASE_NODE_COUNT(Block) -INCREASE_NODE_COUNT(ExpressionStatement) -INCREASE_NODE_COUNT(EmptyStatement) -INCREASE_NODE_COUNT(IfStatement) -INCREASE_NODE_COUNT(ContinueStatement) -INCREASE_NODE_COUNT(BreakStatement) -INCREASE_NODE_COUNT(ReturnStatement) -INCREASE_NODE_COUNT(Conditional) -INCREASE_NODE_COUNT(Literal) -INCREASE_NODE_COUNT(ObjectLiteral) -INCREASE_NODE_COUNT(Assignment) -INCREASE_NODE_COUNT(Throw) -INCREASE_NODE_COUNT(Property) -INCREASE_NODE_COUNT(UnaryOperation) -INCREASE_NODE_COUNT(CountOperation) -INCREASE_NODE_COUNT(BinaryOperation) -INCREASE_NODE_COUNT(CompareOperation) -INCREASE_NODE_COUNT(ThisFunction) -INCREASE_NODE_COUNT(Call) -INCREASE_NODE_COUNT(CallNew) - -#undef INCREASE_NODE_COUNT - - -void AstConstructionVisitor::VisitWithStatement(WithStatement* node) { - increase_node_count(); - add_flag(kDontOptimize); - add_flag(kDontInline); -} - - -void AstConstructionVisitor::VisitSwitchStatement(SwitchStatement* node) { - increase_node_count(); - add_flag(kDontInline); -} - - -void AstConstructionVisitor::VisitDoWhileStatement(DoWhileStatement* node) { - increase_node_count(); - add_flag(kDontSelfOptimize); -} - - -void AstConstructionVisitor::VisitWhileStatement(WhileStatement* node) { - increase_node_count(); - add_flag(kDontSelfOptimize); -} - - -void AstConstructionVisitor::VisitForStatement(ForStatement* node) { - increase_node_count(); - add_flag(kDontSelfOptimize); -} - - -void AstConstructionVisitor::VisitForInStatement(ForInStatement* node) { - increase_node_count(); - add_flag(kDontSelfOptimize); -} - - -void AstConstructionVisitor::VisitTryCatchStatement(TryCatchStatement* node) { - increase_node_count(); - add_flag(kDontOptimize); - add_flag(kDontInline); -} - - -void AstConstructionVisitor::VisitTryFinallyStatement( - TryFinallyStatement* node) { - increase_node_count(); - add_flag(kDontOptimize); - add_flag(kDontInline); -} - - -void AstConstructionVisitor::VisitDebuggerStatement(DebuggerStatement* node) { - increase_node_count(); - add_flag(kDontOptimize); - add_flag(kDontInline); -} - - -void AstConstructionVisitor::VisitFunctionLiteral(FunctionLiteral* node) { - increase_node_count(); - add_flag(kDontInline); -} - - -void AstConstructionVisitor::VisitSharedFunctionInfoLiteral( - SharedFunctionInfoLiteral* node) { - increase_node_count(); - add_flag(kDontOptimize); - add_flag(kDontInline); -} - - -void AstConstructionVisitor::VisitVariableProxy(VariableProxy* node) { - increase_node_count(); - // In theory, we'd have to add: - // if(node->var()->IsLookupSlot()) { add_flag(kDontInline); } - // However, node->var() is usually not bound yet at VariableProxy creation - // time, and LOOKUP variables only result from constructs that cannot - // be inlined anyway. -} - - -void AstConstructionVisitor::VisitRegExpLiteral(RegExpLiteral* node) { - increase_node_count(); - add_flag(kDontInline); // TODO(1322): Allow materialized literals. -} - - -void AstConstructionVisitor::VisitArrayLiteral(ArrayLiteral* node) { - increase_node_count(); - add_flag(kDontInline); // TODO(1322): Allow materialized literals. -} - +REGULAR_NODE(VariableDeclaration) +REGULAR_NODE(FunctionDeclaration) +REGULAR_NODE(Block) +REGULAR_NODE(ExpressionStatement) +REGULAR_NODE(EmptyStatement) +REGULAR_NODE(IfStatement) +REGULAR_NODE(ContinueStatement) +REGULAR_NODE(BreakStatement) +REGULAR_NODE(ReturnStatement) +REGULAR_NODE(SwitchStatement) +REGULAR_NODE(Conditional) +REGULAR_NODE(Literal) +REGULAR_NODE(ObjectLiteral) +REGULAR_NODE(Assignment) +REGULAR_NODE(Throw) +REGULAR_NODE(Property) +REGULAR_NODE(UnaryOperation) +REGULAR_NODE(CountOperation) +REGULAR_NODE(BinaryOperation) +REGULAR_NODE(CompareOperation) +REGULAR_NODE(ThisFunction) +REGULAR_NODE(Call) +REGULAR_NODE(CallNew) +// In theory, for VariableProxy we'd have to add: +// if (node->var()->IsLookupSlot()) add_flag(kDontInline); +// But node->var() is usually not bound yet at VariableProxy creation time, and +// LOOKUP variables only result from constructs that cannot be inlined anyway. +REGULAR_NODE(VariableProxy) + +DONT_OPTIMIZE_NODE(ModuleDeclaration) +DONT_OPTIMIZE_NODE(ImportDeclaration) +DONT_OPTIMIZE_NODE(ExportDeclaration) +DONT_OPTIMIZE_NODE(ModuleLiteral) +DONT_OPTIMIZE_NODE(ModuleVariable) +DONT_OPTIMIZE_NODE(ModulePath) +DONT_OPTIMIZE_NODE(ModuleUrl) +DONT_OPTIMIZE_NODE(WithStatement) +DONT_OPTIMIZE_NODE(TryCatchStatement) +DONT_OPTIMIZE_NODE(TryFinallyStatement) +DONT_OPTIMIZE_NODE(DebuggerStatement) +DONT_OPTIMIZE_NODE(SharedFunctionInfoLiteral) + +DONT_INLINE_NODE(FunctionLiteral) +DONT_INLINE_NODE(RegExpLiteral) // TODO(1322): Allow materialized literals. +DONT_INLINE_NODE(ArrayLiteral) // TODO(1322): Allow materialized literals. + +DONT_SELFOPTIMIZE_NODE(DoWhileStatement) +DONT_SELFOPTIMIZE_NODE(WhileStatement) +DONT_SELFOPTIMIZE_NODE(ForStatement) +DONT_SELFOPTIMIZE_NODE(ForInStatement) void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) { increase_node_count(); @@ -1142,6 +1087,11 @@ void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) { } } +#undef REGULAR_NODE +#undef DONT_OPTIMIZE_NODE +#undef DONT_INLINE_NODE +#undef DONT_SELFOPTIMIZE_NODE + Handle<String> Literal::ToString() { if (handle_->IsString()) return Handle<String>::cast(handle_); diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index b827302ebd..dad80576bd 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -270,6 +270,7 @@ class SmallMapList { void Reserve(int capacity) { list_.Reserve(capacity); } void Clear() { list_.Clear(); } + void Sort() { list_.Sort(); } bool is_empty() const { return list_.is_empty(); } int length() const { return list_.length(); } @@ -420,8 +421,8 @@ class Block: public BreakableStatement { ZoneList<Statement*>* statements() { return &statements_; } bool is_initializer_block() const { return is_initializer_block_; } - Scope* block_scope() const { return block_scope_; } - void set_block_scope(Scope* block_scope) { block_scope_ = block_scope; } + Scope* scope() const { return scope_; } + void set_scope(Scope* scope) { scope_ = scope; } protected: template<class> friend class AstNodeFactory; @@ -433,13 +434,13 @@ class Block: public BreakableStatement { : BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY), statements_(capacity), is_initializer_block_(is_initializer_block), - block_scope_(NULL) { + scope_(NULL) { } private: ZoneList<Statement*> statements_; bool is_initializer_block_; - Scope* block_scope_; + Scope* scope_; }; @@ -607,6 +608,7 @@ class ModuleLiteral: public Module { DECLARE_NODE_TYPE(ModuleLiteral) Block* body() const { return body_; } + Handle<Context> context() const { return context_; } protected: template<class> friend class AstNodeFactory; @@ -618,6 +620,7 @@ class ModuleLiteral: public Module { private: Block* body_; + Handle<Context> context_; }; diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 0e95b4b839..c65c68c2d7 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -1011,7 +1011,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, proto_map->set_prototype(global_context()->initial_object_prototype()); Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map); proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, - heap->empty_string()); + heap->query_colon_symbol()); proto->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, heap->false_value()); proto->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, @@ -2159,7 +2159,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from, Handle<DescriptorArray> descs = Handle<DescriptorArray>(from->map()->instance_descriptors()); for (int i = 0; i < descs->number_of_descriptors(); i++) { - PropertyDetails details = PropertyDetails(descs->GetDetails(i)); + PropertyDetails details = descs->GetDetails(i); switch (details.type()) { case FIELD: { HandleScope inner; diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 0f493e6e57..6d1c6a9785 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -412,12 +412,19 @@ static inline MaybeObject* EnsureJSArrayWithWritableFastElements( HeapObject* elms = array->elements(); Map* map = elms->map(); if (map == heap->fixed_array_map()) { - if (args == NULL || !array->HasFastSmiOnlyElements()) { + if (array->HasFastElements()) return elms; + if (args == NULL) { + if (array->HasFastDoubleElements()) { + ASSERT(elms == heap->empty_fixed_array()); + MaybeObject* maybe_transition = + array->TransitionElementsKind(FAST_ELEMENTS); + if (maybe_transition->IsFailure()) return maybe_transition; + } return elms; } } else if (map == heap->fixed_cow_array_map()) { MaybeObject* maybe_writable_result = array->EnsureWritableFastElements(); - if (args == NULL || !array->HasFastSmiOnlyElements() || + if (args == NULL || array->HasFastElements() || maybe_writable_result->IsFailure()) { return maybe_writable_result; } @@ -1098,7 +1105,7 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper( CustomArguments custom(isolate); v8::ImplementationUtilities::PrepareArgumentsData(custom.end(), - data_obj, *function, raw_holder); + isolate, data_obj, *function, raw_holder); v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( custom.end(), @@ -1138,68 +1145,6 @@ BUILTIN(HandleApiCallConstruct) { } -#ifdef DEBUG - -static void VerifyTypeCheck(Handle<JSObject> object, - Handle<JSFunction> function) { - ASSERT(function->shared()->IsApiFunction()); - FunctionTemplateInfo* info = function->shared()->get_api_func_data(); - if (info->signature()->IsUndefined()) return; - SignatureInfo* signature = SignatureInfo::cast(info->signature()); - Object* receiver_type = signature->receiver(); - if (receiver_type->IsUndefined()) return; - FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type); - ASSERT(object->IsInstanceOf(type)); -} - -#endif - - -BUILTIN(FastHandleApiCall) { - ASSERT(!CalledAsConstructor(isolate)); - Heap* heap = isolate->heap(); - const bool is_construct = false; - - // We expect four more arguments: callback, function, call data, and holder. - const int args_length = args.length() - 4; - ASSERT(args_length >= 0); - - Object* callback_obj = args[args_length]; - - v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( - &args[args_length + 1], - &args[0] - 1, - args_length - 1, - is_construct); - -#ifdef DEBUG - VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()), - Utils::OpenHandle(*new_args.Callee())); -#endif - HandleScope scope(isolate); - Object* result; - v8::Handle<v8::Value> value; - { - // Leaving JavaScript. - VMState state(isolate, EXTERNAL); - ExternalCallbackScope call_scope(isolate, - v8::ToCData<Address>(callback_obj)); - v8::InvocationCallback callback = - v8::ToCData<v8::InvocationCallback>(callback_obj); - - value = callback(new_args); - } - if (value.IsEmpty()) { - result = heap->undefined_value(); - } else { - result = *reinterpret_cast<Object**>(*value); - } - - RETURN_IF_SCHEDULED_EXCEPTION(isolate); - return result; -} - - // Helper function to handle calls to non-function objects created through the // API. The object can be called as either a constructor (using new) or just as // a function (without new). @@ -1238,7 +1183,7 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor( CustomArguments custom(isolate); v8::ImplementationUtilities::PrepareArgumentsData(custom.end(), - call_data->data(), constructor, obj); + isolate, call_data->data(), constructor, obj); v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( custom.end(), &args[0] - 1, diff --git a/deps/v8/src/builtins.h b/deps/v8/src/builtins.h index f079139d45..3ea33938eb 100644 --- a/deps/v8/src/builtins.h +++ b/deps/v8/src/builtins.h @@ -56,7 +56,6 @@ enum BuiltinExtraArguments { V(ArrayConcat, NO_EXTRA_ARGUMENTS) \ \ V(HandleApiCall, NEEDS_CALLED_FUNCTION) \ - V(FastHandleApiCall, NO_EXTRA_ARGUMENTS) \ V(HandleApiCallConstruct, NEEDS_CALLED_FUNCTION) \ V(HandleApiCallAsFunction, NO_EXTRA_ARGUMENTS) \ V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS) \ diff --git a/deps/v8/src/bytecodes-irregexp.h b/deps/v8/src/bytecodes-irregexp.h index b13efb36f8..c7cc66e527 100644 --- a/deps/v8/src/bytecodes-irregexp.h +++ b/deps/v8/src/bytecodes-irregexp.h @@ -72,24 +72,23 @@ V(AND_CHECK_4_CHARS, 27, 16) /* bc8 pad24 uint32 uint32 addr32 */ \ V(AND_CHECK_CHAR, 28, 12) /* bc8 pad8 uint16 uint32 addr32 */ \ V(AND_CHECK_NOT_4_CHARS, 29, 16) /* bc8 pad24 uint32 uint32 addr32 */ \ V(AND_CHECK_NOT_CHAR, 30, 12) /* bc8 pad8 uint16 uint32 addr32 */ \ -V(MINUS_AND_CHECK_NOT_CHAR, 31, 12) /* bc8 pad8 uc16 uc16 addr32 */ \ -V(CHECK_LT, 32, 8) /* bc8 pad8 uc16 addr32 */ \ -V(CHECK_GT, 33, 8) /* bc8 pad8 uc16 addr32 */ \ -V(CHECK_NOT_BACK_REF, 34, 8) /* bc8 reg_idx24 addr32 */ \ -V(CHECK_NOT_BACK_REF_NO_CASE, 35, 8) /* bc8 reg_idx24 addr32 */ \ -V(CHECK_NOT_REGS_EQUAL, 36, 12) /* bc8 regidx24 reg_idx32 addr32 */ \ -V(LOOKUP_MAP1, 37, 12) /* bc8 pad8 start16 bit_map_addr32 addr32 */ \ -V(LOOKUP_MAP2, 38, 96) /* bc8 pad8 start16 half_nibble_map_addr32* */ \ -V(LOOKUP_MAP8, 39, 96) /* bc8 pad8 start16 byte_map addr32* */ \ -V(LOOKUP_HI_MAP8, 40, 96) /* bc8 start24 byte_map_addr32 addr32* */ \ -V(CHECK_REGISTER_LT, 41, 12) /* bc8 reg_idx24 value32 addr32 */ \ -V(CHECK_REGISTER_GE, 42, 12) /* bc8 reg_idx24 value32 addr32 */ \ -V(CHECK_REGISTER_EQ_POS, 43, 8) /* bc8 reg_idx24 addr32 */ \ -V(CHECK_AT_START, 44, 8) /* bc8 pad24 addr32 */ \ -V(CHECK_NOT_AT_START, 45, 8) /* bc8 pad24 addr32 */ \ -V(CHECK_GREEDY, 46, 8) /* bc8 pad24 addr32 */ \ -V(ADVANCE_CP_AND_GOTO, 47, 8) /* bc8 offset24 addr32 */ \ -V(SET_CURRENT_POSITION_FROM_END, 48, 4) /* bc8 idx24 */ +V(MINUS_AND_CHECK_NOT_CHAR, 31, 12) /* bc8 pad8 uc16 uc16 uc16 addr32 */ \ +V(CHECK_CHAR_IN_RANGE, 32, 12) /* bc8 pad24 uc16 uc16 addr32 */ \ +V(CHECK_CHAR_NOT_IN_RANGE, 33, 12) /* bc8 pad24 uc16 uc16 addr32 */ \ +V(CHECK_BIT_IN_TABLE, 34, 24) /* bc8 pad24 addr32 bits128 */ \ +V(CHECK_LT, 35, 8) /* bc8 pad8 uc16 addr32 */ \ +V(CHECK_GT, 36, 8) /* bc8 pad8 uc16 addr32 */ \ +V(CHECK_NOT_BACK_REF, 37, 8) /* bc8 reg_idx24 addr32 */ \ +V(CHECK_NOT_BACK_REF_NO_CASE, 38, 8) /* bc8 reg_idx24 addr32 */ \ +V(CHECK_NOT_REGS_EQUAL, 39, 12) /* bc8 regidx24 reg_idx32 addr32 */ \ +V(CHECK_REGISTER_LT, 40, 12) /* bc8 reg_idx24 value32 addr32 */ \ +V(CHECK_REGISTER_GE, 41, 12) /* bc8 reg_idx24 value32 addr32 */ \ +V(CHECK_REGISTER_EQ_POS, 42, 8) /* bc8 reg_idx24 addr32 */ \ +V(CHECK_AT_START, 43, 8) /* bc8 pad24 addr32 */ \ +V(CHECK_NOT_AT_START, 44, 8) /* bc8 pad24 addr32 */ \ +V(CHECK_GREEDY, 45, 8) /* bc8 pad24 addr32 */ \ +V(ADVANCE_CP_AND_GOTO, 46, 8) /* bc8 offset24 addr32 */ \ +V(SET_CURRENT_POSITION_FROM_END, 47, 4) /* bc8 idx24 */ #define DECLARE_BYTECODES(name, code, length) \ static const int BC_##name = code; diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index 11016c8238..814e358721 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -73,21 +73,12 @@ SmartArrayPointer<const char> CodeStub::GetName() { void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) { - code->set_major_key(MajorKey()); - Isolate* isolate = masm->isolate(); SmartArrayPointer<const char> name = GetName(); PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name)); GDBJIT(AddCode(GDBJITInterface::STUB, *name, code)); Counters* counters = isolate->counters(); counters->total_stubs_code_size()->Increment(code->instruction_size()); - -#ifdef ENABLE_DISASSEMBLER - if (FLAG_print_code_stubs) { - code->Disassemble(*name); - PrintF("\n"); - } -#endif } @@ -125,8 +116,16 @@ Handle<Code> CodeStub::GetCode() { GetICState()); Handle<Code> new_object = factory->NewCode( desc, flags, masm.CodeObject(), NeedsImmovableCode()); - RecordCodeGeneration(*new_object, &masm); + new_object->set_major_key(MajorKey()); FinishCode(new_object); + RecordCodeGeneration(*new_object, &masm); + +#ifdef ENABLE_DISASSEMBLER + if (FLAG_print_code_stubs) { + new_object->Disassemble(*GetName()); + PrintF("\n"); + } +#endif if (UseSpecialCache()) { AddToSpecialCache(new_object); diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index b67e961ac7..5c8717838f 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -498,6 +498,7 @@ class ICCompareStub: public CodeStub { virtual void FinishCode(Handle<Code> code) { code->set_compare_state(state_); + code->set_compare_operation(op_); } virtual CodeStub::Major MajorKey() { return CompareIC; } diff --git a/deps/v8/src/compiler-intrinsics.h b/deps/v8/src/compiler-intrinsics.h index 3b9c59ea53..b73e8ac750 100644 --- a/deps/v8/src/compiler-intrinsics.h +++ b/deps/v8/src/compiler-intrinsics.h @@ -40,6 +40,9 @@ class CompilerIntrinsics { // Returns number of zero bits following most significant 1 bit. // Undefined for zero value. INLINE(static int CountLeadingZeros(uint32_t value)); + + // Returns the number of bits set. + INLINE(static int CountSetBits(uint32_t value)); }; #ifdef __GNUC__ @@ -51,6 +54,10 @@ int CompilerIntrinsics::CountLeadingZeros(uint32_t value) { return __builtin_clz(value); } +int CompilerIntrinsics::CountSetBits(uint32_t value) { + return __builtin_popcount(value); +} + #elif defined(_MSC_VER) #pragma intrinsic(_BitScanForward) @@ -68,6 +75,16 @@ int CompilerIntrinsics::CountLeadingZeros(uint32_t value) { return 31 - static_cast<int>(result); } +int CompilerIntrinsics::CountSetBits(uint32_t value) { + // Manually count set bits. + value = ((value >> 1) & 0x55555555) + (value & 0x55555555); + value = ((value >> 2) & 0x33333333) + (value & 0x33333333); + value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f); + value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff); + value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff); + return value; +} + #else #error Unsupported compiler #endif diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 2272337739..c9c2480fa2 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -531,6 +531,10 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, if (extension == NULL && !result.is_null()) { compilation_cache->PutScript(source, result); } + } else { + if (result->ic_age() != HEAP->global_ic_age()) { + result->ResetForNewContext(HEAP->global_ic_age()); + } } if (result.is_null()) isolate->ReportPendingMessages(); @@ -586,6 +590,10 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, compilation_cache->PutEval( source, context, is_global, result, scope_position); } + } else { + if (result->ic_age() != HEAP->global_ic_age()) { + result->ResetForNewContext(HEAP->global_ic_age()); + } } return result; diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h index af5cb036c6..647c15c153 100644 --- a/deps/v8/src/contexts.h +++ b/deps/v8/src/contexts.h @@ -397,7 +397,7 @@ class Context: public FixedArray { GLOBAL_CONTEXT_FIELDS(GLOBAL_CONTEXT_FIELD_ACCESSORS) #undef GLOBAL_CONTEXT_FIELD_ACCESSORS - // Lookup the the slot called name, starting with the current context. + // Lookup the slot called name, starting with the current context. // There are three possibilities: // // 1) result->IsContext(): diff --git a/deps/v8/src/conversions-inl.h b/deps/v8/src/conversions-inl.h index b098a1c29c..77b260f036 100644 --- a/deps/v8/src/conversions-inl.h +++ b/deps/v8/src/conversions-inl.h @@ -228,9 +228,7 @@ double InternalStringToIntDouble(UnicodeCache* unicode_cache, } ASSERT(number != 0); - // The double could be constructed faster from number (mantissa), exponent - // and sign. Assuming it's a rare case more simple code is used. - return static_cast<double>(negative ? -number : number) * pow(2.0, exponent); + return ldexp(static_cast<double>(negative ? -number : number), exponent); } diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index 45781cf0d4..adbe550136 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -315,9 +315,10 @@ static size_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { } -const char kArrayBufferReferencePropName[] = "_is_array_buffer_"; -const char kArrayBufferMarkerPropName[] = "_array_buffer_ref_"; +const char kArrayBufferMarkerPropName[] = "_is_array_buffer_"; +const char kArrayBufferReferencePropName[] = "_array_buffer_ref_"; +static const int kExternalArrayAllocationHeaderSize = 2; Handle<Value> Shell::CreateExternalArray(const Arguments& args, ExternalArrayType type, @@ -352,10 +353,11 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, Local<Value> length_value = (args.Length() < 3) ? (first_arg_is_array_buffer - ? args[0]->ToObject()->Get(String::New("length")) + ? args[0]->ToObject()->Get(String::New("byteLength")) : args[0]) : args[2]; - size_t length = convertToUint(length_value, &try_catch); + size_t byteLength = convertToUint(length_value, &try_catch); + size_t length = byteLength; if (try_catch.HasCaught()) return try_catch.Exception(); void* data = NULL; @@ -367,7 +369,7 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, data = derived_from->GetIndexedPropertiesExternalArrayData(); size_t array_buffer_length = convertToUint( - derived_from->Get(String::New("length")), + derived_from->Get(String::New("byteLength")), &try_catch); if (try_catch.HasCaught()) return try_catch.Exception(); @@ -426,22 +428,44 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, } Persistent<Object> persistent_array = Persistent<Object>::New(array); - persistent_array.MakeWeak(data, ExternalArrayWeakCallback); - persistent_array.MarkIndependent(); if (data == NULL && length != 0) { - data = calloc(length, element_size); + // Make sure the total size fits into a (signed) int. + static const int kMaxSize = 0x7fffffff; + if (length > (kMaxSize - sizeof(size_t)) / element_size) { + return ThrowException(String::New("Array exceeds maximum size (2G)")); + } + // Prepend the size of the allocated chunk to the data itself. + int total_size = length * element_size + + kExternalArrayAllocationHeaderSize * sizeof(size_t); + data = malloc(total_size); if (data == NULL) { return ThrowException(String::New("Memory allocation failed.")); } + *reinterpret_cast<size_t*>(data) = total_size; + data = reinterpret_cast<size_t*>(data) + kExternalArrayAllocationHeaderSize; + memset(data, 0, length * element_size); + V8::AdjustAmountOfExternalAllocatedMemory(total_size); } + persistent_array.MakeWeak(data, ExternalArrayWeakCallback); + persistent_array.MarkIndependent(); array->SetIndexedPropertiesToExternalArrayData( reinterpret_cast<uint8_t*>(data) + offset, type, static_cast<int>(length)); - array->Set(String::New("length"), - Int32::New(static_cast<int32_t>(length)), ReadOnly); - array->Set(String::New("BYTES_PER_ELEMENT"), - Int32::New(static_cast<int32_t>(element_size))); + array->Set(String::New("byteLength"), + Int32::New(static_cast<int32_t>(byteLength)), ReadOnly); + if (!is_array_buffer_construct) { + array->Set(String::New("length"), + Int32::New(static_cast<int32_t>(length)), ReadOnly); + array->Set(String::New("byteOffset"), + Int32::New(static_cast<int32_t>(offset)), ReadOnly); + array->Set(String::New("BYTES_PER_ELEMENT"), + Int32::New(static_cast<int32_t>(element_size))); + // We currently support 'buffer' property only if constructed from a buffer. + if (first_arg_is_array_buffer) { + array->Set(String::New("buffer"), args[0], ReadOnly); + } + } return array; } @@ -452,6 +476,9 @@ void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { Handle<Object> converted_object = object->ToObject(); Local<Value> prop_value = converted_object->Get(prop_name); if (data != NULL && !prop_value->IsObject()) { + data = reinterpret_cast<size_t*>(data) - kExternalArrayAllocationHeaderSize; + V8::AdjustAmountOfExternalAllocatedMemory( + -static_cast<int>(*reinterpret_cast<size_t*>(data))); free(data); } object.Dispose(); @@ -808,6 +835,8 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { global_template->Set(String::New("read"), FunctionTemplate::New(Read)); global_template->Set(String::New("readbinary"), FunctionTemplate::New(ReadBinary)); + global_template->Set(String::New("readbuffer"), + FunctionTemplate::New(ReadBuffer)); global_template->Set(String::New("readline"), FunctionTemplate::New(ReadLine)); global_template->Set(String::New("load"), FunctionTemplate::New(Load)); @@ -977,8 +1006,8 @@ void Shell::OnExit() { printf("+--------------------------------------------+-------------+\n"); delete [] counters; } - if (counters_file_ != NULL) - delete counters_file_; + delete counters_file_; + delete counter_map_; } #endif // V8_SHARED @@ -1043,6 +1072,32 @@ Handle<Value> Shell::ReadBinary(const Arguments& args) { } +Handle<Value> Shell::ReadBuffer(const Arguments& args) { + String::Utf8Value filename(args[0]); + int length; + if (*filename == NULL) { + return ThrowException(String::New("Error loading file")); + } + char* data = ReadChars(*filename, &length); + if (data == NULL) { + return ThrowException(String::New("Error reading file")); + } + + Handle<Object> buffer = Object::New(); + buffer->Set(String::New(kArrayBufferMarkerPropName), True(), ReadOnly); + + Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer); + persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback); + persistent_buffer.MarkIndependent(); + + buffer->SetIndexedPropertiesToExternalArrayData( + reinterpret_cast<uint8_t*>(data), kExternalUnsignedByteArray, length); + buffer->Set(String::New("byteLength"), + Int32::New(static_cast<int32_t>(length)), ReadOnly); + return buffer; +} + + #ifndef V8_SHARED static char* ReadToken(char* data, char token) { char* next = i::OS::StrChr(data, token); diff --git a/deps/v8/src/d8.h b/deps/v8/src/d8.h index c872f90958..23fdebcaf4 100644 --- a/deps/v8/src/d8.h +++ b/deps/v8/src/d8.h @@ -308,6 +308,7 @@ class Shell : public i::AllStatic { static Handle<Value> DisableProfiler(const Arguments& args); static Handle<Value> Read(const Arguments& args); static Handle<Value> ReadBinary(const Arguments& args); + static Handle<Value> ReadBuffer(const Arguments& args); static Handle<String> ReadFromStdin(); static Handle<Value> ReadLine(const Arguments& args) { return ReadFromStdin(); diff --git a/deps/v8/src/d8.js b/deps/v8/src/d8.js index bf269230b8..819135add4 100644 --- a/deps/v8/src/d8.js +++ b/deps/v8/src/d8.js @@ -2174,7 +2174,7 @@ function DebugResponseDetails(response) { } var current_line = from_line + num; - spacer = maxdigits - (1 + Math.floor(log10(current_line))); + var spacer = maxdigits - (1 + Math.floor(log10(current_line))); if (current_line == Debug.State.currentSourceLine + 1) { for (var i = 0; i < maxdigits; i++) { result += '>'; diff --git a/deps/v8/src/date.js b/deps/v8/src/date.js index 75edf6d32d..d0e24abc50 100644 --- a/deps/v8/src/date.js +++ b/deps/v8/src/date.js @@ -516,8 +516,7 @@ function DateSetMilliseconds(ms) { var t = LOCAL_DATE_VALUE(this); ms = ToNumber(ms); var time = MakeTime(LOCAL_HOUR(this), LOCAL_MIN(this), LOCAL_SEC(this), ms); - SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time)); - return this; + return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time)); } diff --git a/deps/v8/src/debug-agent.cc b/deps/v8/src/debug-agent.cc index bdc7a578ac..511663d8ee 100644 --- a/deps/v8/src/debug-agent.cc +++ b/deps/v8/src/debug-agent.cc @@ -323,41 +323,41 @@ bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn, const char* embedding_host) { static const int kBufferSize = 80; char buffer[kBufferSize]; // Sending buffer. + bool ok; int len; - int r; // Send the header. len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "Type: connect\r\n"); - r = conn->Send(buffer, len); - if (r != len) return false; + ok = conn->Send(buffer, len); + if (!ok) return false; len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "V8-Version: %s\r\n", v8::V8::GetVersion()); - r = conn->Send(buffer, len); - if (r != len) return false; + ok = conn->Send(buffer, len); + if (!ok) return false; len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "Protocol-Version: 1\r\n"); - r = conn->Send(buffer, len); - if (r != len) return false; + ok = conn->Send(buffer, len); + if (!ok) return false; if (embedding_host != NULL) { len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "Embedding-Host: %s\r\n", embedding_host); - r = conn->Send(buffer, len); - if (r != len) return false; + ok = conn->Send(buffer, len); + if (!ok) return false; } len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "%s: 0\r\n", kContentLength); - r = conn->Send(buffer, len); - if (r != len) return false; + ok = conn->Send(buffer, len); + if (!ok) return false; // Terminate header with empty line. len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n"); - r = conn->Send(buffer, len); - if (r != len) return false; + ok = conn->Send(buffer, len); + if (!ok) return false; // No body for connect message. diff --git a/deps/v8/src/debug-debugger.js b/deps/v8/src/debug-debugger.js index 802f6224c4..91838e8ad0 100644 --- a/deps/v8/src/debug-debugger.js +++ b/deps/v8/src/debug-debugger.js @@ -1957,7 +1957,7 @@ DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) { if (request.arguments && !IS_UNDEFINED(request.arguments.frameNumber)) { frame_index = request.arguments.frameNumber; if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) { - return response.failed('Invalid frame number'); + throw new Error('Invalid frame number'); } return this.exec_state_.frame(frame_index); } else { @@ -1966,20 +1966,44 @@ DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) { }; -DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) { - // No frames no scopes. - if (this.exec_state_.frameCount() == 0) { - return response.failed('No scopes'); +// Gets scope host object from request. It is either a function +// ('functionHandle' argument must be specified) or a stack frame +// ('frameNumber' may be specified and the current frame is taken by default). +DebugCommandProcessor.prototype.scopeHolderForScopeRequest_ = + function(request) { + if (request.arguments && "functionHandle" in request.arguments) { + if (!IS_NUMBER(request.arguments.functionHandle)) { + throw new Error('Function handle must be a number'); + } + var function_mirror = LookupMirror(request.arguments.functionHandle); + if (!function_mirror) { + throw new Error('Failed to find function object by handle'); + } + if (!function_mirror.isFunction()) { + throw new Error('Value of non-function type is found by handle'); + } + return function_mirror; + } else { + // No frames no scopes. + if (this.exec_state_.frameCount() == 0) { + throw new Error('No scopes'); + } + + // Get the frame for which the scopes are requested. + var frame = this.frameForScopeRequest_(request); + return frame; } +} - // Get the frame for which the scopes are requested. - var frame = this.frameForScopeRequest_(request); - // Fill all scopes for this frame. - var total_scopes = frame.scopeCount(); +DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) { + var scope_holder = this.scopeHolderForScopeRequest_(request); + + // Fill all scopes for this frame or function. + var total_scopes = scope_holder.scopeCount(); var scopes = []; for (var i = 0; i < total_scopes; i++) { - scopes.push(frame.scope(i)); + scopes.push(scope_holder.scope(i)); } response.body = { fromScope: 0, @@ -1991,24 +2015,19 @@ DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) { DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) { - // No frames no scopes. - if (this.exec_state_.frameCount() == 0) { - return response.failed('No scopes'); - } - - // Get the frame for which the scope is requested. - var frame = this.frameForScopeRequest_(request); + // Get the frame or function for which the scope is requested. + var scope_holder = this.scopeHolderForScopeRequest_(request); // With no scope argument just return top scope. var scope_index = 0; if (request.arguments && !IS_UNDEFINED(request.arguments.number)) { scope_index = %ToNumber(request.arguments.number); - if (scope_index < 0 || frame.scopeCount() <= scope_index) { + if (scope_index < 0 || scope_holder.scopeCount() <= scope_index) { return response.failed('Invalid scope number'); } } - response.body = frame.scope(scope_index); + response.body = scope_holder.scope(scope_index); }; diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index f8a1ecf4f9..9efb5c37aa 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -892,6 +892,16 @@ void Debug::Iterate(ObjectVisitor* v) { } +void Debug::PutValuesOnStackAndDie(int start, + Address c_entry_fp, + Address last_fp, + Address larger_fp, + int count, + int end) { + OS::Abort(); +} + + Object* Debug::Break(Arguments args) { Heap* heap = isolate_->heap(); HandleScope scope(isolate_); @@ -984,11 +994,34 @@ Object* Debug::Break(Arguments args) { // Count frames until target frame int count = 0; JavaScriptFrameIterator it(isolate_); - while (!it.done() && it.frame()->fp() != thread_local_.last_fp_) { + while (!it.done() && it.frame()->fp() < thread_local_.last_fp_) { count++; it.Advance(); } + // Catch the cases that would lead to crashes and capture + // - C entry FP at which to start stack crawl. + // - FP of the frame at which we plan to stop stepping out (last FP). + // - current FP that's larger than last FP. + // - Counter for the number of steps to step out. + if (it.done()) { + // We crawled the entire stack, never reaching last_fp_. + PutValuesOnStackAndDie(0xBEEEEEEE, + frame->fp(), + thread_local_.last_fp_, + NULL, + count, + 0xFEEEEEEE); + } else if (it.frame()->fp() != thread_local_.last_fp_) { + // We crawled over last_fp_, without getting a match. + PutValuesOnStackAndDie(0xBEEEEEEE, + frame->fp(), + thread_local_.last_fp_, + it.frame()->fp(), + count, + 0xFEEEEEEE); + } + // If we found original frame if (it.frame()->fp() == thread_local_.last_fp_) { if (step_count > 1) { @@ -1857,13 +1890,6 @@ static void RedirectActivationsToRecompiledCodeOnThread( // break slots. debug_break_slot_count++; } - if (frame_code->has_self_optimization_header() && - !new_code->has_self_optimization_header()) { - delta -= FullCodeGenerator::self_optimization_header_size(); - } else { - ASSERT(frame_code->has_self_optimization_header() == - new_code->has_self_optimization_header()); - } int debug_break_slot_bytes = debug_break_slot_count * Assembler::kDebugBreakSlotLength; if (FLAG_trace_deopt) { @@ -2234,6 +2260,13 @@ void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, } +const int Debug::FramePaddingLayout::kInitialSize = 1; + + +// Any even value bigger than kInitialSize as needed for stack scanning. +const int Debug::FramePaddingLayout::kPaddingValue = kInitialSize + 1; + + bool Debug::IsDebugGlobal(GlobalObject* global) { return IsLoaded() && global == debug_context()->global(); } diff --git a/deps/v8/src/debug.h b/deps/v8/src/debug.h index 474b90bd21..d9c966c37f 100644 --- a/deps/v8/src/debug.h +++ b/deps/v8/src/debug.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -232,6 +232,12 @@ class Debug { void PreemptionWhileInDebugger(); void Iterate(ObjectVisitor* v); + NO_INLINE(void PutValuesOnStackAndDie(int start, + Address c_entry_fp, + Address last_fp, + Address larger_fp, + int count, + int end)); Object* Break(Arguments args); void SetBreakPoint(Handle<SharedFunctionInfo> shared, Handle<Object> break_point_object, @@ -245,6 +251,8 @@ class Debug { bool IsBreakOnException(ExceptionBreakType type); void PrepareStep(StepAction step_action, int step_count); void ClearStepping(); + void ClearStepOut(); + bool IsStepping() { return thread_local_.step_count_ > 0; } bool StepNextContinue(BreakLocationIterator* break_location_iterator, JavaScriptFrame* frame); static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared); @@ -455,6 +463,50 @@ class Debug { // Architecture-specific constant. static const bool kFrameDropperSupported; + /** + * Defines layout of a stack frame that supports padding. This is a regular + * internal frame that has a flexible stack structure. LiveEdit can shift + * its lower part up the stack, taking up the 'padding' space when additional + * stack memory is required. + * Such frame is expected immediately above the topmost JavaScript frame. + * + * Stack Layout: + * --- Top + * LiveEdit routine frames + * --- + * C frames of debug handler + * --- + * ... + * --- + * An internal frame that has n padding words: + * - any number of words as needed by code -- upper part of frame + * - padding size: a Smi storing n -- current size of padding + * - padding: n words filled with kPaddingValue in form of Smi + * - 3 context/type words of a regular InternalFrame + * - fp + * --- + * Topmost JavaScript frame + * --- + * ... + * --- Bottom + */ + class FramePaddingLayout : public AllStatic { + public: + // Architecture-specific constant. + static const bool kIsSupported; + + // A size of frame base including fp. Padding words starts right above + // the base. + static const int kFrameBaseSize = 4; + + // A number of words that should be reserved on stack for the LiveEdit use. + // Normally equals 1. Stored on stack in form of Smi. + static const int kInitialSize; + // A value that padding words are filled with (in form of Smi). Going + // bottom-top, the first word not having this value is a counter word. + static const int kPaddingValue; + }; + private: explicit Debug(Isolate* isolate); ~Debug(); @@ -464,7 +516,6 @@ class Debug { void ActivateStepIn(StackFrame* frame); void ClearStepIn(); void ActivateStepOut(StackFrame* frame); - void ClearStepOut(); void ClearStepNext(); // Returns whether the compile succeeded. void RemoveDebugInfo(Handle<DebugInfo> debug_info); diff --git a/deps/v8/src/double.h b/deps/v8/src/double.h index 16a3245e9a..fcf6906af7 100644 --- a/deps/v8/src/double.h +++ b/deps/v8/src/double.h @@ -130,12 +130,6 @@ class Double { return (d64 & kExponentMask) == kExponentMask; } - bool IsNan() const { - uint64_t d64 = AsUint64(); - return ((d64 & kExponentMask) == kExponentMask) && - ((d64 & kSignificandMask) != 0); - } - bool IsInfinite() const { uint64_t d64 = AsUint64(); return ((d64 & kExponentMask) == kExponentMask) && diff --git a/deps/v8/src/elements.cc b/deps/v8/src/elements.cc index 1d043a153e..d367af85ce 100644 --- a/deps/v8/src/elements.cc +++ b/deps/v8/src/elements.cc @@ -199,10 +199,13 @@ static void CopyDictionaryToObjectElements(SeededNumberDictionary* from, } #endif } - ASSERT((copy_size + static_cast<int>(to_start)) <= to->length()); ASSERT(to != from); ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS); if (copy_size == 0) return; + uint32_t to_length = to->length(); + if (to_start + copy_size > to_length) { + copy_size = to_length - to_start; + } for (int i = 0; i < copy_size; i++) { int entry = from->FindEntry(i + from_start); if (entry != SeededNumberDictionary::kNotFound) { @@ -356,8 +359,11 @@ static void CopyDictionaryToDoubleElements(SeededNumberDictionary* from, } } } - ASSERT(copy_size + static_cast<int>(to_start) <= to->length()); if (copy_size == 0) return; + uint32_t to_length = to->length(); + if (to_start + copy_size > to_length) { + copy_size = to_length - to_start; + } for (int i = 0; i < copy_size; i++) { int entry = from->FindEntry(i + from_start); if (entry != SeededNumberDictionary::kNotFound) { @@ -418,10 +424,10 @@ class ElementsAccessorBase : public ElementsAccessor { receiver, holder, key, BackingStore::cast(backing_store)); } - virtual MaybeObject* Get(Object* receiver, - JSObject* holder, - uint32_t key, - FixedArrayBase* backing_store) { + MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver, + JSObject* holder, + uint32_t key, + FixedArrayBase* backing_store) { if (backing_store == NULL) { backing_store = holder->elements(); } @@ -429,62 +435,64 @@ class ElementsAccessorBase : public ElementsAccessor { receiver, holder, key, BackingStore::cast(backing_store)); } - static MaybeObject* GetImpl(Object* receiver, - JSObject* obj, - uint32_t key, - BackingStore* backing_store) { + MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver, + JSObject* obj, + uint32_t key, + BackingStore* backing_store) { return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store)) ? backing_store->get(key) : backing_store->GetHeap()->the_hole_value(); } - virtual MaybeObject* SetLength(JSArray* array, - Object* length) { + MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array, + Object* length) { return ElementsAccessorSubclass::SetLengthImpl( array, length, BackingStore::cast(array->elements())); } - static MaybeObject* SetLengthImpl(JSObject* obj, - Object* length, - BackingStore* backing_store); + MUST_USE_RESULT static MaybeObject* SetLengthImpl( + JSObject* obj, + Object* length, + BackingStore* backing_store); - virtual MaybeObject* SetCapacityAndLength(JSArray* array, - int capacity, - int length) { + MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(JSArray* array, + int capacity, + int length) { return ElementsAccessorSubclass::SetFastElementsCapacityAndLength( array, capacity, length); } - static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj, - int capacity, - int length) { + MUST_USE_RESULT static MaybeObject* SetFastElementsCapacityAndLength( + JSObject* obj, + int capacity, + int length) { UNIMPLEMENTED(); return obj; } - virtual MaybeObject* Delete(JSObject* obj, - uint32_t key, - JSReceiver::DeleteMode mode) = 0; + MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj, + uint32_t key, + JSReceiver::DeleteMode mode) = 0; - static MaybeObject* CopyElementsImpl(FixedArrayBase* from, - uint32_t from_start, - FixedArrayBase* to, - ElementsKind to_kind, - uint32_t to_start, - int copy_size) { + MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from, + uint32_t from_start, + FixedArrayBase* to, + ElementsKind to_kind, + uint32_t to_start, + int copy_size) { UNREACHABLE(); return NULL; } - virtual MaybeObject* CopyElements(JSObject* from_holder, - uint32_t from_start, - FixedArrayBase* to, - ElementsKind to_kind, - uint32_t to_start, - int copy_size, - FixedArrayBase* from) { + MUST_USE_RESULT virtual MaybeObject* CopyElements(JSObject* from_holder, + uint32_t from_start, + FixedArrayBase* to, + ElementsKind to_kind, + uint32_t to_start, + int copy_size, + FixedArrayBase* from) { if (from == NULL) { from = from_holder->elements(); } @@ -495,10 +503,11 @@ class ElementsAccessorBase : public ElementsAccessor { from, from_start, to, to_kind, to_start, copy_size); } - virtual MaybeObject* AddElementsToFixedArray(Object* receiver, - JSObject* holder, - FixedArray* to, - FixedArrayBase* from) { + MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray( + Object* receiver, + JSObject* holder, + FixedArray* to, + FixedArrayBase* from) { int len0 = to->length(); #ifdef DEBUG if (FLAG_enable_slow_asserts) { @@ -860,27 +869,28 @@ class ExternalElementsAccessor friend class ElementsAccessorBase<ExternalElementsAccessorSubclass, ElementsKindTraits<Kind> >; - static MaybeObject* GetImpl(Object* receiver, - JSObject* obj, - uint32_t key, - BackingStore* backing_store) { + MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver, + JSObject* obj, + uint32_t key, + BackingStore* backing_store) { return key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) ? backing_store->get(key) : backing_store->GetHeap()->undefined_value(); } - static MaybeObject* SetLengthImpl(JSObject* obj, - Object* length, - BackingStore* backing_store) { + MUST_USE_RESULT static MaybeObject* SetLengthImpl( + JSObject* obj, + Object* length, + BackingStore* backing_store) { // External arrays do not support changing their length. UNREACHABLE(); return obj; } - virtual MaybeObject* Delete(JSObject* obj, - uint32_t key, - JSReceiver::DeleteMode mode) { + MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj, + uint32_t key, + JSReceiver::DeleteMode mode) { // External arrays always ignore deletes. return obj->GetHeap()->true_value(); } @@ -996,10 +1006,11 @@ class DictionaryElementsAccessor // Adjusts the length of the dictionary backing store and returns the new // length according to ES5 section 15.4.5.2 behavior. - static MaybeObject* SetLengthWithoutNormalize(SeededNumberDictionary* dict, - JSArray* array, - Object* length_object, - uint32_t length) { + MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize( + SeededNumberDictionary* dict, + JSArray* array, + Object* length_object, + uint32_t length) { if (length == 0) { // If the length of a slow array is reset to zero, we clear // the array and flush backing storage. This has the added @@ -1051,9 +1062,10 @@ class DictionaryElementsAccessor return length_object; } - static MaybeObject* DeleteCommon(JSObject* obj, - uint32_t key, - JSReceiver::DeleteMode mode) { + MUST_USE_RESULT static MaybeObject* DeleteCommon( + JSObject* obj, + uint32_t key, + JSReceiver::DeleteMode mode) { Isolate* isolate = obj->GetIsolate(); Heap* heap = isolate->heap(); FixedArray* backing_store = FixedArray::cast(obj->elements()); @@ -1096,12 +1108,12 @@ class DictionaryElementsAccessor return heap->true_value(); } - static MaybeObject* CopyElementsImpl(FixedArrayBase* from, - uint32_t from_start, - FixedArrayBase* to, - ElementsKind to_kind, - uint32_t to_start, - int copy_size) { + MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from, + uint32_t from_start, + FixedArrayBase* to, + ElementsKind to_kind, + uint32_t to_start, + int copy_size) { switch (to_kind) { case FAST_SMI_ONLY_ELEMENTS: case FAST_ELEMENTS: @@ -1125,16 +1137,17 @@ class DictionaryElementsAccessor friend class ElementsAccessorBase<DictionaryElementsAccessor, ElementsKindTraits<DICTIONARY_ELEMENTS> >; - virtual MaybeObject* Delete(JSObject* obj, - uint32_t key, - JSReceiver::DeleteMode mode) { + MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj, + uint32_t key, + JSReceiver::DeleteMode mode) { return DeleteCommon(obj, key, mode); } - static MaybeObject* GetImpl(Object* receiver, - JSObject* obj, - uint32_t key, - SeededNumberDictionary* backing_store) { + MUST_USE_RESULT static MaybeObject* GetImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + SeededNumberDictionary* backing_store) { int entry = backing_store->FindEntry(key); if (entry != SeededNumberDictionary::kNotFound) { Object* element = backing_store->ValueAt(entry); @@ -1180,10 +1193,10 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< NonStrictArgumentsElementsAccessor, ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >; - static MaybeObject* GetImpl(Object* receiver, - JSObject* obj, - uint32_t key, - FixedArray* parameter_map) { + MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver, + JSObject* obj, + uint32_t key, + FixedArray* parameter_map) { Object* probe = GetParameterMapArg(obj, parameter_map, key); if (!probe->IsTheHole()) { Context* context = Context::cast(parameter_map->get(0)); @@ -1210,18 +1223,19 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< } } - static MaybeObject* SetLengthImpl(JSObject* obj, - Object* length, - FixedArray* parameter_map) { + MUST_USE_RESULT static MaybeObject* SetLengthImpl( + JSObject* obj, + Object* length, + FixedArray* parameter_map) { // TODO(mstarzinger): This was never implemented but will be used once we // correctly implement [[DefineOwnProperty]] on arrays. UNIMPLEMENTED(); return obj; } - virtual MaybeObject* Delete(JSObject* obj, - uint32_t key, - JSReceiver::DeleteMode mode) { + MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj, + uint32_t key, + JSReceiver::DeleteMode mode) { FixedArray* parameter_map = FixedArray::cast(obj->elements()); Object* probe = GetParameterMapArg(obj, parameter_map, key); if (!probe->IsTheHole()) { @@ -1240,12 +1254,12 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< return obj->GetHeap()->true_value(); } - static MaybeObject* CopyElementsImpl(FixedArrayBase* from, - uint32_t from_start, - FixedArrayBase* to, - ElementsKind to_kind, - uint32_t to_start, - int copy_size) { + MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from, + uint32_t from_start, + FixedArrayBase* to, + ElementsKind to_kind, + uint32_t to_start, + int copy_size) { FixedArray* parameter_map = FixedArray::cast(from); FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments); @@ -1326,18 +1340,8 @@ ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) { void ElementsAccessor::InitializeOncePerProcess() { - static struct ConcreteElementsAccessors { -#define ACCESSOR_STRUCT(Class, Kind, Store) Class* Kind##_handler; - ELEMENTS_LIST(ACCESSOR_STRUCT) -#undef ACCESSOR_STRUCT - } element_accessors = { -#define ACCESSOR_INIT(Class, Kind, Store) new Class(#Kind), - ELEMENTS_LIST(ACCESSOR_INIT) -#undef ACCESSOR_INIT - }; - static ElementsAccessor* accessor_array[] = { -#define ACCESSOR_ARRAY(Class, Kind, Store) element_accessors.Kind##_handler, +#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind), ELEMENTS_LIST(ACCESSOR_ARRAY) #undef ACCESSOR_ARRAY }; @@ -1349,9 +1353,17 @@ void ElementsAccessor::InitializeOncePerProcess() { } +void ElementsAccessor::TearDown() { +#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; + ELEMENTS_LIST(ACCESSOR_DELETE) +#undef ACCESSOR_DELETE + elements_accessors_ = NULL; +} + + template <typename ElementsAccessorSubclass, typename ElementsKindTraits> -MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, - ElementsKindTraits>:: +MUST_USE_RESULT MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, + ElementsKindTraits>:: SetLengthImpl(JSObject* obj, Object* length, typename ElementsKindTraits::BackingStore* backing_store) { diff --git a/deps/v8/src/elements.h b/deps/v8/src/elements.h index ff97c08324..55d6fa56f0 100644 --- a/deps/v8/src/elements.h +++ b/deps/v8/src/elements.h @@ -60,18 +60,19 @@ class ElementsAccessor { // can optionally pass in the backing store to use for the check, which must // be compatible with the ElementsKind of the ElementsAccessor. If // backing_store is NULL, the holder->elements() is used as the backing store. - virtual MaybeObject* Get(Object* receiver, - JSObject* holder, - uint32_t key, - FixedArrayBase* backing_store = NULL) = 0; + MUST_USE_RESULT virtual MaybeObject* Get( + Object* receiver, + JSObject* holder, + uint32_t key, + FixedArrayBase* backing_store = NULL) = 0; // Modifies the length data property as specified for JSArrays and resizes the // underlying backing store accordingly. The method honors the semantics of // changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e. array that // have non-deletable elements can only be shrunk to the size of highest // element that is non-deletable. - virtual MaybeObject* SetLength(JSArray* holder, - Object* new_length) = 0; + MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* holder, + Object* new_length) = 0; // Modifies both the length and capacity of a JSArray, resizing the underlying // backing store as necessary. This method does NOT honor the semantics of @@ -79,14 +80,14 @@ class ElementsAccessor { // elements. This method should only be called for array expansion OR by // runtime JavaScript code that use InternalArrays and don't care about // EcmaScript 5.1 semantics. - virtual MaybeObject* SetCapacityAndLength(JSArray* array, - int capacity, - int length) = 0; + MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(JSArray* array, + int capacity, + int length) = 0; // Deletes an element in an object, returning a new elements backing store. - virtual MaybeObject* Delete(JSObject* holder, - uint32_t key, - JSReceiver::DeleteMode mode) = 0; + MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* holder, + uint32_t key, + JSReceiver::DeleteMode mode) = 0; // If kCopyToEnd is specified as the copy_size to CopyElements, it copies all // of elements from source after source_start to the destination array. @@ -101,26 +102,28 @@ class ElementsAccessor { // the source JSObject or JSArray in source_holder. If the holder's backing // store is available, it can be passed in source and source_holder is // ignored. - virtual MaybeObject* CopyElements(JSObject* source_holder, - uint32_t source_start, - FixedArrayBase* destination, - ElementsKind destination_kind, - uint32_t destination_start, - int copy_size, - FixedArrayBase* source = NULL) = 0; - - MaybeObject* CopyElements(JSObject* from_holder, - FixedArrayBase* to, - ElementsKind to_kind, - FixedArrayBase* from = NULL) { + MUST_USE_RESULT virtual MaybeObject* CopyElements( + JSObject* source_holder, + uint32_t source_start, + FixedArrayBase* destination, + ElementsKind destination_kind, + uint32_t destination_start, + int copy_size, + FixedArrayBase* source = NULL) = 0; + + MUST_USE_RESULT MaybeObject* CopyElements(JSObject* from_holder, + FixedArrayBase* to, + ElementsKind to_kind, + FixedArrayBase* from = NULL) { return CopyElements(from_holder, 0, to, to_kind, 0, kCopyToEndAndInitializeToHole, from); } - virtual MaybeObject* AddElementsToFixedArray(Object* receiver, - JSObject* holder, - FixedArray* to, - FixedArrayBase* from = NULL) = 0; + MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray( + Object* receiver, + JSObject* holder, + FixedArray* to, + FixedArrayBase* from = NULL) = 0; // Returns a shared ElementsAccessor for the specified ElementsKind. static ElementsAccessor* ForKind(ElementsKind elements_kind) { @@ -131,6 +134,7 @@ class ElementsAccessor { static ElementsAccessor* ForArray(FixedArrayBase* array); static void InitializeOncePerProcess(); + static void TearDown(); protected: friend class NonStrictArgumentsElementsAccessor; diff --git a/deps/v8/src/extensions/externalize-string-extension.cc b/deps/v8/src/extensions/externalize-string-extension.cc index 9fbf329818..50d876136f 100644 --- a/deps/v8/src/extensions/externalize-string-extension.cc +++ b/deps/v8/src/extensions/externalize-string-extension.cc @@ -133,11 +133,8 @@ v8::Handle<v8::Value> ExternalizeStringExtension::IsAscii( void ExternalizeStringExtension::Register() { - static ExternalizeStringExtension* externalize_extension = NULL; - if (externalize_extension == NULL) - externalize_extension = new ExternalizeStringExtension; - static v8::DeclareExtension externalize_extension_declaration( - externalize_extension); + static ExternalizeStringExtension externalize_extension; + static v8::DeclareExtension declaration(&externalize_extension); } } } // namespace v8::internal diff --git a/deps/v8/src/extensions/gc-extension.cc b/deps/v8/src/extensions/gc-extension.cc index 573797e174..f921552aaa 100644 --- a/deps/v8/src/extensions/gc-extension.cc +++ b/deps/v8/src/extensions/gc-extension.cc @@ -46,9 +46,8 @@ v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) { void GCExtension::Register() { - static GCExtension* gc_extension = NULL; - if (gc_extension == NULL) gc_extension = new GCExtension(); - static v8::DeclareExtension gc_extension_declaration(gc_extension); + static GCExtension gc_extension; + static v8::DeclareExtension declaration(&gc_extension); } } } // namespace v8::internal diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index 143099cfb8..6bb7893746 100644 --- a/deps/v8/src/factory.cc +++ b/deps/v8/src/factory.cc @@ -291,6 +291,15 @@ Handle<Context> Factory::NewGlobalContext() { } +Handle<Context> Factory::NewModuleContext(Handle<Context> previous, + Handle<ScopeInfo> scope_info) { + CALL_HEAP_FUNCTION( + isolate(), + isolate()->heap()->AllocateModuleContext(*previous, *scope_info), + Context); +} + + Handle<Context> Factory::NewFunctionContext(int length, Handle<JSFunction> function) { CALL_HEAP_FUNCTION( @@ -324,10 +333,9 @@ Handle<Context> Factory::NewWithContext(Handle<JSFunction> function, } -Handle<Context> Factory::NewBlockContext( - Handle<JSFunction> function, - Handle<Context> previous, - Handle<ScopeInfo> scope_info) { +Handle<Context> Factory::NewBlockContext(Handle<JSFunction> function, + Handle<Context> previous, + Handle<ScopeInfo> scope_info) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateBlockContext(*function, @@ -537,6 +545,10 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo( : isolate()->strict_mode_function_map(), pretenure); + if (function_info->ic_age() != isolate()->heap()->global_ic_age()) { + function_info->ResetForNewContext(isolate()->heap()->global_ic_age()); + } + result->set_context(*context); if (!function_info->bound()) { int number_of_literals = function_info->num_literals(); @@ -924,6 +936,13 @@ Handle<JSObject> Factory::NewJSObject(Handle<JSFunction> constructor, } +Handle<JSModule> Factory::NewJSModule() { + CALL_HEAP_FUNCTION( + isolate(), + isolate()->heap()->AllocateJSModule(), JSModule); +} + + Handle<GlobalObject> Factory::NewGlobalObject( Handle<JSFunction> constructor) { CALL_HEAP_FUNCTION(isolate(), diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index 786d4a983a..06aad1bef6 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -162,9 +162,12 @@ class Factory { // Create a global (but otherwise uninitialized) context. Handle<Context> NewGlobalContext(); + // Create a module context. + Handle<Context> NewModuleContext(Handle<Context> previous, + Handle<ScopeInfo> scope_info); + // Create a function context. - Handle<Context> NewFunctionContext(int length, - Handle<JSFunction> function); + Handle<Context> NewFunctionContext(int length, Handle<JSFunction> function); // Create a catch context. Handle<Context> NewCatchContext(Handle<JSFunction> function, @@ -177,7 +180,7 @@ class Factory { Handle<Context> previous, Handle<JSObject> extension); - // Create a 'block' context. + // Create a block context. Handle<Context> NewBlockContext(Handle<JSFunction> function, Handle<Context> previous, Handle<ScopeInfo> scope_info); @@ -262,6 +265,9 @@ class Factory { // runtime. Handle<JSObject> NewJSObjectFromMap(Handle<Map> map); + // JS modules are pretenured. + Handle<JSModule> NewJSModule(); + // JS arrays are pretenured when allocated by the parser. Handle<JSArray> NewJSArray(int capacity, ElementsKind elements_kind = FAST_ELEMENTS, diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index 75697a8906..62a9782859 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -132,6 +132,8 @@ public: // Flags for language modes and experimental language features. DEFINE_bool(use_strict, false, "enforce strict mode") +DEFINE_bool(es52_globals, false, + "activate new semantics for global var declarations") DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof") DEFINE_bool(harmony_scoping, false, "enable harmony block scoping") @@ -165,7 +167,12 @@ DEFINE_bool(eliminate_dead_phis, true, "eliminate dead phis") DEFINE_bool(use_gvn, true, "use hydrogen global value numbering") DEFINE_bool(use_canonicalizing, true, "use hydrogen instruction canonicalizing") DEFINE_bool(use_inlining, true, "use function inlining") -DEFINE_bool(limit_inlining, true, "limit code size growth from inlining") +DEFINE_int(max_inlined_source_size, 600, + "maximum source size in bytes considered for a single inlining") +DEFINE_int(max_inlined_nodes, 196, + "maximum number of AST nodes considered for a single inlining") +DEFINE_int(max_inlined_nodes_cumulative, 196, + "maximum cumulative number of AST nodes considered for inlining") DEFINE_bool(loop_invariant_code_motion, true, "loop invariant code motion") DEFINE_bool(collect_megamorphic_maps_from_stub_cache, true, @@ -188,6 +195,8 @@ DEFINE_bool(trap_on_deopt, false, "put a break point before deoptimizing") DEFINE_bool(deoptimize_uncommon_cases, true, "deoptimize uncommon cases") DEFINE_bool(polymorphic_inlining, true, "polymorphic inlining") DEFINE_bool(use_osr, true, "use on-stack replacement") +DEFINE_bool(array_bounds_checks_elimination, true, + "perform array bounds checks elimination") DEFINE_bool(trace_osr, false, "trace on-stack replacement") DEFINE_int(stress_runs, 0, "number of stress runs") diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index 0571a813f5..e265341b1a 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -1359,34 +1359,28 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* // ------------------------------------------------------------------------- int NumRegs(RegList reglist) { - int n = 0; - while (reglist != 0) { - n++; - reglist &= reglist - 1; // clear one bit - } - return n; + return CompilerIntrinsics::CountSetBits(reglist); } struct JSCallerSavedCodeData { - JSCallerSavedCodeData() { - int i = 0; - for (int r = 0; r < kNumRegs; r++) - if ((kJSCallerSaved & (1 << r)) != 0) - reg_code[i++] = r; - - ASSERT(i == kNumJSCallerSaved); - } int reg_code[kNumJSCallerSaved]; }; +JSCallerSavedCodeData caller_saved_code_data; -static LazyInstance<JSCallerSavedCodeData>::type caller_saved_code_data = - LAZY_INSTANCE_INITIALIZER; +void SetUpJSCallerSavedCodeData() { + int i = 0; + for (int r = 0; r < kNumRegs; r++) + if ((kJSCallerSaved & (1 << r)) != 0) + caller_saved_code_data.reg_code[i++] = r; + + ASSERT(i == kNumJSCallerSaved); +} int JSCallerSavedCode(int n) { ASSERT(0 <= n && n < kNumJSCallerSaved); - return caller_saved_code_data.Get().reg_code[n]; + return caller_saved_code_data.reg_code[n]; } diff --git a/deps/v8/src/frames.h b/deps/v8/src/frames.h index 9071555197..78cdd0cedb 100644 --- a/deps/v8/src/frames.h +++ b/deps/v8/src/frames.h @@ -40,6 +40,8 @@ typedef uint32_t RegList; // Get the number of registers in a given register list. int NumRegs(RegList list); +void SetUpJSCallerSavedCodeData(); + // Return the code of the n-th saved register available to JavaScript. int JSCallerSavedCode(int n); @@ -209,6 +211,9 @@ class StackFrame BASE_EMBEDDED { virtual void SetCallerFp(Address caller_fp) = 0; + // Manually changes value of fp in this object. + void UpdateFp(Address fp) { state_.fp = fp; } + Address* pc_address() const { return state_.pc_address; } // Get the id of this stack frame. diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index d963979ad8..b8794c0b8b 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -315,7 +315,6 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) { Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info); code->set_optimizable(info->IsOptimizable() && !info->function()->flags()->Contains(kDontOptimize)); - code->set_self_optimization_header(cgen.has_self_optimization_header_); cgen.PopulateDeoptimizationData(code); cgen.PopulateTypeFeedbackInfo(code); cgen.PopulateTypeFeedbackCells(code); @@ -327,12 +326,10 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) { code->set_compiled_optimizable(info->IsOptimizable()); #endif // ENABLE_DEBUGGER_SUPPORT code->set_allow_osr_at_loop_nesting_level(0); + code->set_profiler_ticks(0); code->set_stack_check_table_offset(table_offset); CodeGenerator::PrintCode(code, info); info->SetCode(code); // May be an empty handle. - if (!code.is_null()) { - isolate->runtime_profiler()->NotifyCodeGenerated(code->instruction_size()); - } #ifdef ENABLE_GDB_JIT_INTERFACE if (FLAG_gdbjit && !code.is_null()) { GDBJITLineInfo* lineinfo = @@ -571,88 +568,91 @@ void FullCodeGenerator::DoTest(const TestContext* context) { void FullCodeGenerator::VisitDeclarations( ZoneList<Declaration*>* declarations) { - int save_global_count = global_count_; - global_count_ = 0; + ZoneList<Handle<Object> >* saved_globals = globals_; + ZoneList<Handle<Object> > inner_globals(10); + globals_ = &inner_globals; AstVisitor::VisitDeclarations(declarations); - - // Batch declare global functions and variables. - if (global_count_ > 0) { - Handle<FixedArray> array = - isolate()->factory()->NewFixedArray(2 * global_count_, TENURED); - int length = declarations->length(); - for (int j = 0, i = 0; i < length; i++) { - Declaration* decl = declarations->at(i); - Variable* var = decl->proxy()->var(); - - if (var->IsUnallocated()) { - array->set(j++, *(var->name())); - FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration(); - if (fun_decl == NULL) { - if (var->binding_needs_init()) { - // In case this binding needs initialization use the hole. - array->set_the_hole(j++); - } else { - array->set_undefined(j++); - } - } else { - Handle<SharedFunctionInfo> function = - Compiler::BuildFunctionInfo(fun_decl->fun(), script()); - // Check for stack-overflow exception. - if (function.is_null()) { - SetStackOverflow(); - return; - } - array->set(j++, *function); - } - } - } + if (!globals_->is_empty()) { // Invoke the platform-dependent code generator to do the actual // declaration the global functions and variables. + Handle<FixedArray> array = + isolate()->factory()->NewFixedArray(globals_->length(), TENURED); + for (int i = 0; i < globals_->length(); ++i) + array->set(i, *globals_->at(i)); DeclareGlobals(array); } - global_count_ = save_global_count; -} - - -void FullCodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { - EmitDeclaration(decl->proxy(), decl->mode(), NULL); + globals_ = saved_globals; } -void FullCodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { - EmitDeclaration(decl->proxy(), decl->mode(), decl->fun()); -} - - -void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* decl) { - EmitDeclaration(decl->proxy(), decl->mode(), NULL); -} - - -void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) { - EmitDeclaration(decl->proxy(), decl->mode(), NULL); -} +void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) { + Handle<JSModule> instance = module->interface()->Instance(); + ASSERT(!instance.is_null()); + // Allocate a module context statically. + Block* block = module->body(); + Scope* saved_scope = scope(); + scope_ = block->scope(); + Handle<ScopeInfo> scope_info = scope_->GetScopeInfo(); + + // Generate code for module creation and linking. + Comment cmnt(masm_, "[ ModuleLiteral"); + SetStatementPosition(block); + + if (scope_info->HasContext()) { + // Set up module context. + __ Push(scope_info); + __ Push(instance); + __ CallRuntime(Runtime::kPushModuleContext, 2); + StoreToFrameField( + StandardFrameConstants::kContextOffset, context_register()); + } -void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) { - // TODO(rossberg) -} + { + Comment cmnt(masm_, "[ Declarations"); + VisitDeclarations(scope_->declarations()); + } + scope_ = saved_scope; + if (scope_info->HasContext()) { + // Pop module context. + LoadContextField(context_register(), Context::PREVIOUS_INDEX); + // Update local stack frame context field. + StoreToFrameField( + StandardFrameConstants::kContextOffset, context_register()); + } -void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) { - // TODO(rossberg) + // Populate module instance object. + const PropertyAttributes attr = + static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE | DONT_ENUM); + for (Interface::Iterator it = module->interface()->iterator(); + !it.done(); it.Advance()) { + if (it.interface()->IsModule()) { + Handle<Object> value = it.interface()->Instance(); + ASSERT(!value.is_null()); + JSReceiver::SetProperty(instance, it.name(), value, attr, kStrictMode); + } else { + // TODO(rossberg): set proper getters instead of undefined... + // instance->DefineAccessor(*it.name(), ACCESSOR_GETTER, *getter, attr); + Handle<Object> value(isolate()->heap()->undefined_value()); + JSReceiver::SetProperty(instance, it.name(), value, attr, kStrictMode); + } + } + USE(instance->PreventExtensions()); } void FullCodeGenerator::VisitModuleVariable(ModuleVariable* module) { - // TODO(rossberg) + // Noting to do. + // The instance object is resolved statically through the module's interface. } void FullCodeGenerator::VisitModulePath(ModulePath* module) { - // TODO(rossberg) + // Noting to do. + // The instance object is resolved statically through the module's interface. } @@ -914,9 +914,9 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { Scope* saved_scope = scope(); // Push a block context when entering a block with block scoped variables. - if (stmt->block_scope() != NULL) { + if (stmt->scope() != NULL) { { Comment cmnt(masm_, "[ Extend block context"); - scope_ = stmt->block_scope(); + scope_ = stmt->scope(); Handle<ScopeInfo> scope_info = scope_->GetScopeInfo(); int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS; __ Push(scope_info); @@ -943,7 +943,7 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); // Pop block context if necessary. - if (stmt->block_scope() != NULL) { + if (stmt->scope() != NULL) { LoadContextField(context_register(), Context::PREVIOUS_INDEX); // Update local stack frame context field. StoreToFrameField(StandardFrameConstants::kContextOffset, diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index 58d59862a5..0e0ffe924b 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -83,22 +83,17 @@ class FullCodeGenerator: public AstVisitor { scope_(info->scope()), nesting_stack_(NULL), loop_depth_(0), - global_count_(0), + globals_(NULL), context_(NULL), bailout_entries_(info->HasDeoptimizationSupport() ? info->function()->ast_node_count() : 0), stack_checks_(2), // There's always at least one. type_feedback_cells_(info->HasDeoptimizationSupport() ? info->function()->ast_node_count() : 0), - ic_total_count_(0), - has_self_optimization_header_(false) { } + ic_total_count_(0) { } static bool MakeCode(CompilationInfo* info); - // Returns the platform-specific size in bytes of the self-optimization - // header. - static int self_optimization_header_size(); - // Encode state and pc-offset as a BitField<type, start, size>. // Only use 30 bits because we encode the result as a smi. class StateField : public BitField<State, 0, 1> { }; @@ -207,7 +202,7 @@ class FullCodeGenerator: public AstVisitor { virtual ~NestedBlock() {} virtual NestedStatement* Exit(int* stack_depth, int* context_length) { - if (statement()->AsBlock()->block_scope() != NULL) { + if (statement()->AsBlock()->scope() != NULL) { ++(*context_length); } return previous_; @@ -418,12 +413,9 @@ class FullCodeGenerator: public AstVisitor { Label* if_true, Label* if_false); - // Platform-specific code for a variable, constant, or function - // declaration. Functions have an initial value. - // Increments global_count_ for unallocated variables. - void EmitDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function); + // If enabled, emit debug code for checking that the current context is + // neither a with nor a catch context. + void EmitDebugCheckDeclarationContext(Variable* variable); // Platform-specific code for checking the stack limit at the back edge of // a loop. @@ -553,12 +545,8 @@ class FullCodeGenerator: public AstVisitor { Handle<Script> script() { return info_->script(); } bool is_eval() { return info_->is_eval(); } bool is_native() { return info_->is_native(); } - bool is_classic_mode() { - return language_mode() == CLASSIC_MODE; - } - LanguageMode language_mode() { - return function()->language_mode(); - } + bool is_classic_mode() { return language_mode() == CLASSIC_MODE; } + LanguageMode language_mode() { return function()->language_mode(); } FunctionLiteral* function() { return info_->function(); } Scope* scope() { return scope_; } @@ -790,13 +778,12 @@ class FullCodeGenerator: public AstVisitor { Label return_label_; NestedStatement* nesting_stack_; int loop_depth_; - int global_count_; + ZoneList<Handle<Object> >* globals_; const ExpressionContext* context_; ZoneList<BailoutEntry> bailout_entries_; ZoneList<BailoutEntry> stack_checks_; ZoneList<TypeFeedbackCellEntry> type_feedback_cells_; int ic_total_count_; - bool has_self_optimization_header_; Handle<FixedArray> handler_table_; Handle<JSGlobalPropertyCell> profiling_counter_; diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc index 416ecbd211..def1604ac7 100644 --- a/deps/v8/src/handles.cc +++ b/deps/v8/src/handles.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -729,9 +729,9 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); for (int i = 0; i < descs->number_of_descriptors(); i++) { - if (descs->IsProperty(i) && !descs->IsDontEnum(i)) { + if (descs->IsProperty(i) && !descs->GetDetails(i).IsDontEnum()) { storage->set(index, descs->GetKey(i)); - PropertyDetails details(descs->GetDetails(i)); + PropertyDetails details = descs->GetDetails(i); sort_array->set(index, Smi::FromInt(details.index())); if (!indices.is_null()) { if (details.type() != FIELD) { diff --git a/deps/v8/src/hashmap.h b/deps/v8/src/hashmap.h index 5aeb8951ed..91843b81b8 100644 --- a/deps/v8/src/hashmap.h +++ b/deps/v8/src/hashmap.h @@ -63,7 +63,9 @@ class TemplateHashMapImpl { Entry* Lookup(void* key, uint32_t hash, bool insert); // Removes the entry with matching key. - void Remove(void* key, uint32_t hash); + // It returns the value of the deleted entry + // or null if there is no value for such key. + void* Remove(void* key, uint32_t hash); // Empties the hash map (occupancy() == 0). void Clear(); @@ -146,14 +148,15 @@ typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Lookup( template<class P> -void TemplateHashMapImpl<P>::Remove(void* key, uint32_t hash) { +void* TemplateHashMapImpl<P>::Remove(void* key, uint32_t hash) { // Lookup the entry for the key to remove. Entry* p = Probe(key, hash); if (p->key == NULL) { // Key not found nothing to remove. - return; + return NULL; } + void* value = p->value; // To remove an entry we need to ensure that it does not create an empty // entry that will cause the search for another entry to stop too soon. If all // the entries between the entry to remove and the next empty slot have their @@ -202,6 +205,7 @@ void TemplateHashMapImpl<P>::Remove(void* key, uint32_t hash) { // Clear the entry which is allowed to en emptied. p->key = NULL; occupancy_--; + return value; } diff --git a/deps/v8/src/heap-inl.h b/deps/v8/src/heap-inl.h index 706d2886b9..e12895a283 100644 --- a/deps/v8/src/heap-inl.h +++ b/deps/v8/src/heap-inl.h @@ -460,15 +460,16 @@ MaybeObject* Heap::PrepareForCompare(String* str) { } -int Heap::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) { +intptr_t Heap::AdjustAmountOfExternalAllocatedMemory( + intptr_t change_in_bytes) { ASSERT(HasBeenSetUp()); - int amount = amount_of_external_allocated_memory_ + change_in_bytes; + intptr_t amount = amount_of_external_allocated_memory_ + change_in_bytes; if (change_in_bytes >= 0) { // Avoid overflow. if (amount > amount_of_external_allocated_memory_) { amount_of_external_allocated_memory_ = amount; } - int amount_since_last_global_gc = + intptr_t amount_since_last_global_gc = amount_of_external_allocated_memory_ - amount_of_external_allocated_memory_at_last_global_gc_; if (amount_since_last_global_gc > external_allocation_limit_) { diff --git a/deps/v8/src/heap-profiler.cc b/deps/v8/src/heap-profiler.cc index 8be6f27685..2e971a51b4 100644 --- a/deps/v8/src/heap-profiler.cc +++ b/deps/v8/src/heap-profiler.cc @@ -33,7 +33,6 @@ namespace v8 { namespace internal { - HeapProfiler::HeapProfiler() : snapshots_(new HeapSnapshotsCollection()), next_snapshot_uid_(1) { @@ -86,6 +85,24 @@ HeapSnapshot* HeapProfiler::TakeSnapshot(String* name, } +void HeapProfiler::StartHeapObjectsTracking() { + ASSERT(Isolate::Current()->heap_profiler() != NULL); + Isolate::Current()->heap_profiler()->StartHeapObjectsTrackingImpl(); +} + + +void HeapProfiler::StopHeapObjectsTracking() { + ASSERT(Isolate::Current()->heap_profiler() != NULL); + Isolate::Current()->heap_profiler()->StopHeapObjectsTrackingImpl(); +} + + +void HeapProfiler::PushHeapObjectsStats(v8::OutputStream* stream) { + ASSERT(Isolate::Current()->heap_profiler() != NULL); + return Isolate::Current()->heap_profiler()->PushHeapObjectsStatsImpl(stream); +} + + void HeapProfiler::DefineWrapperClass( uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) { ASSERT(class_id != v8::HeapProfiler::kPersistentHandleNoClassId); @@ -136,6 +153,20 @@ HeapSnapshot* HeapProfiler::TakeSnapshotImpl(String* name, return TakeSnapshotImpl(snapshots_->names()->GetName(name), type, control); } +void HeapProfiler::StartHeapObjectsTrackingImpl() { + snapshots_->StartHeapObjectsTracking(); +} + + +void HeapProfiler::PushHeapObjectsStatsImpl(OutputStream* stream) { + snapshots_->PushHeapObjectsStats(stream); +} + + +void HeapProfiler::StopHeapObjectsTrackingImpl() { + snapshots_->StopHeapObjectsTracking(); +} + int HeapProfiler::GetSnapshotsCount() { HeapProfiler* profiler = Isolate::Current()->heap_profiler(); @@ -158,6 +189,15 @@ HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) { } +SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) { + if (!obj->IsHeapObject()) + return v8::HeapProfiler::kUnknownObjectId; + HeapProfiler* profiler = Isolate::Current()->heap_profiler(); + ASSERT(profiler != NULL); + return profiler->snapshots_->FindObjectId(HeapObject::cast(*obj)->address()); +} + + void HeapProfiler::DeleteAllSnapshots() { HeapProfiler* profiler = Isolate::Current()->heap_profiler(); ASSERT(profiler != NULL); diff --git a/deps/v8/src/heap-profiler.h b/deps/v8/src/heap-profiler.h index ef5c4f4b4a..96b042d3cb 100644 --- a/deps/v8/src/heap-profiler.h +++ b/deps/v8/src/heap-profiler.h @@ -44,8 +44,6 @@ class HeapSnapshotsCollection; } \ } while (false) -// The HeapProfiler writes data to the log files, which can be postprocessed -// to generate .hp files for use by the GHC/Valgrind tool hp2ps. class HeapProfiler { public: static void SetUp(); @@ -57,9 +55,14 @@ class HeapProfiler { static HeapSnapshot* TakeSnapshot(String* name, int type, v8::ActivityControl* control); + + static void StartHeapObjectsTracking(); + static void StopHeapObjectsTracking(); + static void PushHeapObjectsStats(OutputStream* stream); static int GetSnapshotsCount(); static HeapSnapshot* GetSnapshot(int index); static HeapSnapshot* FindSnapshot(unsigned uid); + static SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj); static void DeleteAllSnapshots(); void ObjectMoveEvent(Address from, Address to); @@ -84,6 +87,10 @@ class HeapProfiler { v8::ActivityControl* control); void ResetSnapshots(); + void StartHeapObjectsTrackingImpl(); + void StopHeapObjectsTrackingImpl(); + void PushHeapObjectsStatsImpl(OutputStream* stream); + HeapSnapshotsCollection* snapshots_; unsigned next_snapshot_uid_; List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_; diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index a1cccf6f22..d3c7f0a9b0 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -42,6 +42,7 @@ #include "natives.h" #include "objects-visiting.h" #include "objects-visiting-inl.h" +#include "once.h" #include "runtime-profiler.h" #include "scopeinfo.h" #include "snapshot.h" @@ -60,8 +61,6 @@ namespace v8 { namespace internal { -static LazyMutex gc_initializer_mutex = LAZY_MUTEX_INITIALIZER; - Heap::Heap() : isolate_(NULL), @@ -145,7 +144,6 @@ Heap::Heap() number_idle_notifications_(0), last_idle_notification_gc_count_(0), last_idle_notification_gc_count_init_(false), - idle_notification_will_schedule_next_gc_(false), mark_sweeps_since_idle_round_started_(0), ms_count_at_last_idle_notification_(0), gc_count_at_last_idle_gc_(0), @@ -173,6 +171,9 @@ Heap::Heap() global_contexts_list_ = NULL; mark_compact_collector_.heap_ = this; external_string_table_.heap_ = this; + // Put a dummy entry in the remembered pages so we can find the list the + // minidump even if there are no real unmapped pages. + RememberUnmappedPage(NULL, false); } @@ -240,12 +241,17 @@ int Heap::GcSafeSizeOfOldObject(HeapObject* object) { GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space, const char** reason) { // Is global GC requested? - if (space != NEW_SPACE || FLAG_gc_global) { + if (space != NEW_SPACE) { isolate_->counters()->gc_compactor_caused_by_request()->Increment(); *reason = "GC in old space requested"; return MARK_COMPACTOR; } + if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) { + *reason = "GC in old space forced by flags"; + return MARK_COMPACTOR; + } + // Is enough data promoted to justify a global GC? if (OldGenerationPromotionLimitReached()) { isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); @@ -504,11 +510,17 @@ bool Heap::CollectGarbage(AllocationSpace space, !incremental_marking()->IsStopped() && !incremental_marking()->should_hurry() && FLAG_incremental_marking_steps) { - if (FLAG_trace_incremental_marking) { - PrintF("[IncrementalMarking] Delaying MarkSweep.\n"); + // Make progress in incremental marking. + const intptr_t kStepSizeWhenDelayedByScavenge = 1 * MB; + incremental_marking()->Step(kStepSizeWhenDelayedByScavenge, + IncrementalMarking::NO_GC_VIA_STACK_GUARD); + if (!incremental_marking()->IsComplete()) { + if (FLAG_trace_incremental_marking) { + PrintF("[IncrementalMarking] Delaying MarkSweep.\n"); + } + collector = SCAVENGER; + collector_reason = "incremental marking delaying mark-sweep"; } - collector = SCAVENGER; - collector_reason = "incremental marking delaying mark-sweep"; } bool next_gc_likely_to_collect_more = false; @@ -796,7 +808,7 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector, UpdateSurvivalRateTrend(start_new_space_size); - size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSize(); + size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects(); if (high_survival_rate_during_scavenges && IsStableOrIncreasingSurvivalTrend()) { @@ -1120,6 +1132,27 @@ void PromotionQueue::RelocateQueueHead() { } +class ScavengeWeakObjectRetainer : public WeakObjectRetainer { + public: + explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { } + + virtual Object* RetainAs(Object* object) { + if (!heap_->InFromSpace(object)) { + return object; + } + + MapWord map_word = HeapObject::cast(object)->map_word(); + if (map_word.IsForwardingAddress()) { + return map_word.ToForwardingAddress(); + } + return NULL; + } + + private: + Heap* heap_; +}; + + void Heap::Scavenge() { #ifdef DEBUG if (FLAG_verify_heap) VerifyNonPointerSpacePointers(); @@ -1218,6 +1251,9 @@ void Heap::Scavenge() { } incremental_marking()->UpdateMarkingDequeAfterScavenge(); + ScavengeWeakObjectRetainer weak_object_retainer(this); + ProcessWeakReferences(&weak_object_retainer); + ASSERT(new_space_front == new_space_.top()); // Set age mark. @@ -1304,7 +1340,8 @@ void Heap::UpdateReferencesInExternalStringTable( static Object* ProcessFunctionWeakReferences(Heap* heap, Object* function, - WeakObjectRetainer* retainer) { + WeakObjectRetainer* retainer, + bool record_slots) { Object* undefined = heap->undefined_value(); Object* head = undefined; JSFunction* tail = NULL; @@ -1321,6 +1358,12 @@ static Object* ProcessFunctionWeakReferences(Heap* heap, // Subsequent elements in the list. ASSERT(tail != NULL); tail->set_next_function_link(retain); + if (record_slots) { + Object** next_function = + HeapObject::RawField(tail, JSFunction::kNextFunctionLinkOffset); + heap->mark_compact_collector()->RecordSlot( + next_function, next_function, retain); + } } // Retained function is new tail. candidate_function = reinterpret_cast<JSFunction*>(retain); @@ -1349,6 +1392,15 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { Object* head = undefined; Context* tail = NULL; Object* candidate = global_contexts_list_; + + // We don't record weak slots during marking or scavenges. + // Instead we do it once when we complete mark-compact cycle. + // Note that write barrier has no effect if we are already in the middle of + // compacting mark-sweep cycle and we have to record slots manually. + bool record_slots = + gc_state() == MARK_COMPACT && + mark_compact_collector()->is_compacting(); + while (candidate != undefined) { // Check whether to keep the candidate in the list. Context* candidate_context = reinterpret_cast<Context*>(candidate); @@ -1364,6 +1416,14 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { Context::NEXT_CONTEXT_LINK, retain, UPDATE_WRITE_BARRIER); + + if (record_slots) { + Object** next_context = + HeapObject::RawField( + tail, FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK)); + mark_compact_collector()->RecordSlot( + next_context, next_context, retain); + } } // Retained context is new tail. candidate_context = reinterpret_cast<Context*>(retain); @@ -1376,11 +1436,19 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { ProcessFunctionWeakReferences( this, candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST), - retainer); + retainer, + record_slots); candidate_context->set_unchecked(this, Context::OPTIMIZED_FUNCTIONS_LIST, function_list_head, UPDATE_WRITE_BARRIER); + if (record_slots) { + Object** optimized_functions = + HeapObject::RawField( + tail, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST)); + mark_compact_collector()->RecordSlot( + optimized_functions, optimized_functions, function_list_head); + } } // Move to next element in the list. @@ -1480,6 +1548,27 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, } +STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0); + + +INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap, + HeapObject* object, + int size)); + +static HeapObject* EnsureDoubleAligned(Heap* heap, + HeapObject* object, + int size) { + if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) { + heap->CreateFillerObjectAt(object->address(), kPointerSize); + return HeapObject::FromAddress(object->address() + kPointerSize); + } else { + heap->CreateFillerObjectAt(object->address() + size - kPointerSize, + kPointerSize); + return object; + } +} + + enum LoggingAndProfiling { LOGGING_AND_PROFILING_ENABLED, LOGGING_AND_PROFILING_DISABLED @@ -1603,7 +1692,10 @@ class ScavengingVisitor : public StaticVisitorBase { } } - template<ObjectContents object_contents, SizeRestriction size_restriction> + + template<ObjectContents object_contents, + SizeRestriction size_restriction, + int alignment> static inline void EvacuateObject(Map* map, HeapObject** slot, HeapObject* object, @@ -1612,19 +1704,26 @@ class ScavengingVisitor : public StaticVisitorBase { (object_size <= Page::kMaxNonCodeHeapObjectSize)); SLOW_ASSERT(object->Size() == object_size); + int allocation_size = object_size; + if (alignment != kObjectAlignment) { + ASSERT(alignment == kDoubleAlignment); + allocation_size += kPointerSize; + } + Heap* heap = map->GetHeap(); if (heap->ShouldBePromoted(object->address(), object_size)) { MaybeObject* maybe_result; if ((size_restriction != SMALL) && - (object_size > Page::kMaxNonCodeHeapObjectSize)) { - maybe_result = heap->lo_space()->AllocateRaw(object_size, + (allocation_size > Page::kMaxNonCodeHeapObjectSize)) { + maybe_result = heap->lo_space()->AllocateRaw(allocation_size, NOT_EXECUTABLE); } else { if (object_contents == DATA_OBJECT) { - maybe_result = heap->old_data_space()->AllocateRaw(object_size); + maybe_result = heap->old_data_space()->AllocateRaw(allocation_size); } else { - maybe_result = heap->old_pointer_space()->AllocateRaw(object_size); + maybe_result = + heap->old_pointer_space()->AllocateRaw(allocation_size); } } @@ -1632,6 +1731,10 @@ class ScavengingVisitor : public StaticVisitorBase { if (maybe_result->ToObject(&result)) { HeapObject* target = HeapObject::cast(result); + if (alignment != kObjectAlignment) { + target = EnsureDoubleAligned(heap, target, allocation_size); + } + // Order is important: slot might be inside of the target if target // was allocated over a dead object and slot comes from the store // buffer. @@ -1639,18 +1742,27 @@ class ScavengingVisitor : public StaticVisitorBase { MigrateObject(heap, object, target, object_size); if (object_contents == POINTER_OBJECT) { - heap->promotion_queue()->insert(target, object_size); + if (map->instance_type() == JS_FUNCTION_TYPE) { + heap->promotion_queue()->insert( + target, JSFunction::kNonWeakFieldsEndOffset); + } else { + heap->promotion_queue()->insert(target, object_size); + } } heap->tracer()->increment_promoted_objects_size(object_size); return; } } - MaybeObject* allocation = heap->new_space()->AllocateRaw(object_size); + MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size); heap->promotion_queue()->SetNewLimit(heap->new_space()->top()); Object* result = allocation->ToObjectUnchecked(); HeapObject* target = HeapObject::cast(result); + if (alignment != kObjectAlignment) { + target = EnsureDoubleAligned(heap, target, allocation_size); + } + // Order is important: slot might be inside of the target if target // was allocated over a dead object and slot comes from the store // buffer. @@ -1686,7 +1798,7 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject** slot, HeapObject* object) { int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); - EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE>(map, + EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map, slot, object, object_size); @@ -1698,10 +1810,11 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject* object) { int length = reinterpret_cast<FixedDoubleArray*>(object)->length(); int object_size = FixedDoubleArray::SizeFor(length); - EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, - slot, - object, - object_size); + EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>( + map, + slot, + object, + object_size); } @@ -1709,7 +1822,8 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject** slot, HeapObject* object) { int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize(); - EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); + EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>( + map, slot, object, object_size); } @@ -1718,7 +1832,8 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject* object) { int object_size = SeqAsciiString::cast(object)-> SeqAsciiStringSize(map->instance_type()); - EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); + EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>( + map, slot, object, object_size); } @@ -1727,7 +1842,8 @@ class ScavengingVisitor : public StaticVisitorBase { HeapObject* object) { int object_size = SeqTwoByteString::cast(object)-> SeqTwoByteStringSize(map->instance_type()); - EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); + EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>( + map, slot, object, object_size); } @@ -1770,7 +1886,8 @@ class ScavengingVisitor : public StaticVisitorBase { } int object_size = ConsString::kSize; - EvacuateObject<POINTER_OBJECT, SMALL>(map, slot, object, object_size); + EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>( + map, slot, object, object_size); } template<ObjectContents object_contents> @@ -1780,14 +1897,16 @@ class ScavengingVisitor : public StaticVisitorBase { static inline void VisitSpecialized(Map* map, HeapObject** slot, HeapObject* object) { - EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); + EvacuateObject<object_contents, SMALL, kObjectAlignment>( + map, slot, object, object_size); } static inline void Visit(Map* map, HeapObject** slot, HeapObject* object) { int object_size = map->instance_size(); - EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); + EvacuateObject<object_contents, SMALL, kObjectAlignment>( + map, slot, object, object_size); } }; @@ -1904,7 +2023,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, map->set_pre_allocated_property_fields(0); map->init_instance_descriptors(); map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER); - map->set_prototype_transitions(empty_fixed_array(), SKIP_WRITE_BARRIER); + map->init_prototype_transitions(undefined_value()); map->set_unused_property_fields(0); map->set_bit_field(0); map->set_bit_field2(1 << Map::kIsExtensible); @@ -1953,7 +2072,7 @@ MaybeObject* Heap::AllocateTypeFeedbackInfo() { if (!maybe_info->To(&info)) return maybe_info; } info->set_ic_total_count(0); - info->set_ic_with_typeinfo_count(0); + info->set_ic_with_type_info_count(0); info->set_type_feedback_cells(TypeFeedbackCells::cast(empty_fixed_array()), SKIP_WRITE_BARRIER); return info; @@ -2043,15 +2162,15 @@ bool Heap::CreateInitialMaps() { // Fix the instance_descriptors for the existing maps. meta_map()->init_instance_descriptors(); meta_map()->set_code_cache(empty_fixed_array()); - meta_map()->set_prototype_transitions(empty_fixed_array()); + meta_map()->init_prototype_transitions(undefined_value()); fixed_array_map()->init_instance_descriptors(); fixed_array_map()->set_code_cache(empty_fixed_array()); - fixed_array_map()->set_prototype_transitions(empty_fixed_array()); + fixed_array_map()->init_prototype_transitions(undefined_value()); oddball_map()->init_instance_descriptors(); oddball_map()->set_code_cache(empty_fixed_array()); - oddball_map()->set_prototype_transitions(empty_fixed_array()); + oddball_map()->init_prototype_transitions(undefined_value()); // Fix prototype object for existing maps. meta_map()->set_prototype(null_value()); @@ -2897,9 +3016,9 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER); share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER); share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER); - share->set_deopt_counter(FLAG_deopt_every_n_times); - share->set_profiler_ticks(0); share->set_ast_node_count(0); + share->set_deopt_counter(FLAG_deopt_every_n_times); + share->set_ic_age(0); // Set integer fields (smi or int, depending on the architecture). share->set_length(0); @@ -3823,6 +3942,16 @@ MaybeObject* Heap::AllocateJSObject(JSFunction* constructor, } +MaybeObject* Heap::AllocateJSModule() { + // Allocate a fresh map. Modules do not have a prototype. + Map* map; + MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize); + if (!maybe_map->To(&map)) return maybe_map; + // Allocate the object based on the map. + return AllocateJSObjectFromMap(map, TENURED); +} + + MaybeObject* Heap::AllocateJSArrayAndStorage( ElementsKind elements_kind, int length, @@ -3959,7 +4088,7 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) { // Fill these accessors into the dictionary. DescriptorArray* descs = map->instance_descriptors(); for (int i = 0; i < descs->number_of_descriptors(); i++) { - PropertyDetails details(descs->GetDetails(i)); + PropertyDetails details = descs->GetDetails(i); ASSERT(details.type() == CALLBACKS); // Only accessors are expected. PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, details.index()); @@ -4652,6 +4781,11 @@ MaybeObject* Heap::AllocateRawFixedDoubleArray(int length, AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; int size = FixedDoubleArray::SizeFor(length); + +#ifndef V8_HOST_ARCH_64_BIT + size += kPointerSize; +#endif + if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) { // Too big for new space. space = LO_SPACE; @@ -4664,7 +4798,12 @@ MaybeObject* Heap::AllocateRawFixedDoubleArray(int length, AllocationSpace retry_space = (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE; - return AllocateRaw(size, space, retry_space); + HeapObject* object; + { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space); + if (!maybe_object->To<HeapObject>(&object)) return maybe_object; + } + + return EnsureDoubleAligned(this, object, size); } @@ -4697,6 +4836,22 @@ MaybeObject* Heap::AllocateGlobalContext() { } +MaybeObject* Heap::AllocateModuleContext(Context* previous, + ScopeInfo* scope_info) { + Object* result; + { MaybeObject* maybe_result = + AllocateFixedArrayWithHoles(scope_info->ContextLength(), TENURED); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + Context* context = reinterpret_cast<Context*>(result); + context->set_map_no_write_barrier(module_context_map()); + context->set_previous(previous); + context->set_extension(scope_info); + context->set_global(previous->global()); + return context; +} + + MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) { ASSERT(length >= Context::MIN_CONTEXT_SLOTS); Object* result; @@ -4817,10 +4972,8 @@ void Heap::EnsureHeapIsIterable() { void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) { - // This flag prevents incremental marking from requesting GC via stack guard - idle_notification_will_schedule_next_gc_ = true; - incremental_marking()->Step(step_size); - idle_notification_will_schedule_next_gc_ = false; + incremental_marking()->Step(step_size, + IncrementalMarking::NO_GC_VIA_STACK_GUARD); if (incremental_marking()->IsComplete()) { bool uncommit = false; @@ -4841,8 +4994,10 @@ void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) { bool Heap::IdleNotification(int hint) { const int kMaxHint = 1000; - intptr_t size_factor = Min(Max(hint, 30), kMaxHint) / 10; - // The size factor is in range [3..100]. + intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4; + // The size factor is in range [5..250]. The numbers here are chosen from + // experiments. If you changes them, make sure to test with + // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.* intptr_t step_size = size_factor * IncrementalMarking::kAllocatedThreshold; if (contexts_disposed_ > 0) { @@ -4866,11 +5021,14 @@ bool Heap::IdleNotification(int hint) { // Take into account that we might have decided to delay full collection // because incremental marking is in progress. ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped()); + // After context disposal there is likely a lot of garbage remaining, reset + // the idle notification counters in order to trigger more incremental GCs + // on subsequent idle notifications. + StartIdleRound(); return false; } - if (hint >= kMaxHint || !FLAG_incremental_marking || - FLAG_expose_gc || Serializer::enabled()) { + if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) { return IdleGlobalGC(); } @@ -4909,10 +5067,6 @@ bool Heap::IdleNotification(int hint) { } if (incremental_marking()->IsStopped()) { - if (!WorthStartingGCWhenIdle()) { - FinishIdleRound(); - return true; - } incremental_marking()->Start(); } @@ -5550,6 +5704,11 @@ bool Heap::ConfigureHeap(int max_semispace_size, intptr_t max_executable_size) { if (HasBeenSetUp()) return false; + if (FLAG_stress_compaction) { + // This will cause more frequent GCs when stressing. + max_semispace_size_ = Page::kPageSize; + } + if (max_semispace_size > 0) { if (max_semispace_size < Page::kPageSize) { max_semispace_size = Page::kPageSize; @@ -5654,16 +5813,6 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { } -intptr_t Heap::PromotedSpaceSize() { - return old_pointer_space_->Size() - + old_data_space_->Size() - + code_space_->Size() - + map_space_->Size() - + cell_space_->Size() - + lo_space_->Size(); -} - - intptr_t Heap::PromotedSpaceSizeOfObjects() { return old_pointer_space_->SizeOfObjects() + old_data_space_->SizeOfObjects() @@ -5674,7 +5823,7 @@ intptr_t Heap::PromotedSpaceSizeOfObjects() { } -int Heap::PromotedExternalMemorySize() { +intptr_t Heap::PromotedExternalMemorySize() { if (amount_of_external_allocated_memory_ <= amount_of_external_allocated_memory_at_last_global_gc_) return 0; return amount_of_external_allocated_memory_ @@ -5847,6 +5996,15 @@ class HeapDebugUtils { #endif + +V8_DECLARE_ONCE(initialize_gc_once); + +static void InitializeGCOnce() { + InitializeScavengingVisitorsTables(); + NewSpaceScavenger::Initialize(); + MarkCompactCollector::Initialize(); +} + bool Heap::SetUp(bool create_heap_objects) { #ifdef DEBUG allocation_timeout_ = FLAG_gc_interval; @@ -5865,15 +6023,7 @@ bool Heap::SetUp(bool create_heap_objects) { if (!ConfigureHeapDefault()) return false; } - gc_initializer_mutex.Pointer()->Lock(); - static bool initialized_gc = false; - if (!initialized_gc) { - initialized_gc = true; - InitializeScavengingVisitorsTables(); - NewSpaceScavenger::Initialize(); - MarkCompactCollector::Initialize(); - } - gc_initializer_mutex.Pointer()->Unlock(); + CallOnce(&initialize_gc_once, &InitializeGCOnce); MarkMapPointersAsEncoded(false); @@ -5985,6 +6135,11 @@ void Heap::SetStackLimits() { void Heap::TearDown() { +#ifdef DEBUG + if (FLAG_verify_heap) { + Verify(); + } +#endif if (FLAG_print_cumulative_gc_stat) { PrintF("\n\n"); PrintF("gc_count=%d ", gc_count_); diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index 2bd037f15b..beb1bc511e 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -243,7 +243,8 @@ namespace internal { V(compare_ic_symbol, ".compare_ic") \ V(infinity_symbol, "Infinity") \ V(minus_infinity_symbol, "-Infinity") \ - V(hidden_stack_trace_symbol, "v8::hidden_stack_trace") + V(hidden_stack_trace_symbol, "v8::hidden_stack_trace") \ + V(query_colon_symbol, "(?:)") // Forward declarations. class GCTracer; @@ -529,6 +530,8 @@ class Heap { MUST_USE_RESULT MaybeObject* AllocateJSObject( JSFunction* constructor, PretenureFlag pretenure = NOT_TENURED); + MUST_USE_RESULT MaybeObject* AllocateJSModule(); + // Allocate a JSArray with no elements MUST_USE_RESULT MaybeObject* AllocateEmptyJSArray( ElementsKind elements_kind, @@ -820,6 +823,10 @@ class Heap { // Allocate a global (but otherwise uninitialized) context. MUST_USE_RESULT MaybeObject* AllocateGlobalContext(); + // Allocate a module context. + MUST_USE_RESULT MaybeObject* AllocateModuleContext(Context* previous, + ScopeInfo* scope_info); + // Allocate a function context. MUST_USE_RESULT MaybeObject* AllocateFunctionContext(int length, JSFunction* function); @@ -1326,7 +1333,8 @@ class Heap { // Adjusts the amount of registered external memory. // Returns the adjusted value. - inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes); + inline intptr_t AdjustAmountOfExternalAllocatedMemory( + intptr_t change_in_bytes); // Allocate uninitialized fixed array. MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int length); @@ -1334,7 +1342,7 @@ class Heap { PretenureFlag pretenure); inline intptr_t PromotedTotalSize() { - return PromotedSpaceSize() + PromotedExternalMemorySize(); + return PromotedSpaceSizeOfObjects() + PromotedExternalMemorySize(); } // True if we have reached the allocation limit in the old generation that @@ -1355,19 +1363,6 @@ class Heap { static const intptr_t kMinimumAllocationLimit = 8 * (Page::kPageSize > MB ? Page::kPageSize : MB); - // When we sweep lazily we initially guess that there is no garbage on the - // heap and set the limits for the next GC accordingly. As we sweep we find - // out that some of the pages contained garbage and we have to adjust - // downwards the size of the heap. This means the limits that control the - // timing of the next GC also need to be adjusted downwards. - void LowerOldGenLimits(intptr_t adjustment) { - size_of_old_gen_at_last_old_space_gc_ -= adjustment; - old_gen_promotion_limit_ = - OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_); - old_gen_allocation_limit_ = - OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_); - } - intptr_t OldGenPromotionLimit(intptr_t old_gen_size) { const int divisor = FLAG_stress_compaction ? 10 : 3; intptr_t limit = @@ -1411,6 +1406,12 @@ class Heap { kRootListLength }; + STATIC_CHECK(kUndefinedValueRootIndex == Internals::kUndefinedValueRootIndex); + STATIC_CHECK(kNullValueRootIndex == Internals::kNullValueRootIndex); + STATIC_CHECK(kTrueValueRootIndex == Internals::kTrueValueRootIndex); + STATIC_CHECK(kFalseValueRootIndex == Internals::kFalseValueRootIndex); + STATIC_CHECK(kempty_symbolRootIndex == Internals::kEmptySymbolRootIndex); + MUST_USE_RESULT MaybeObject* NumberToString( Object* number, bool check_number_string_cache = true); MUST_USE_RESULT MaybeObject* Uint32ToString( @@ -1442,6 +1443,8 @@ class Heap { inline bool NextGCIsLikelyToBeFull() { if (FLAG_gc_global) return true; + if (FLAG_stress_compaction && (gc_count_ & 1) != 0) return true; + intptr_t total_promoted = PromotedTotalSize(); intptr_t adjusted_promotion_limit = @@ -1452,7 +1455,7 @@ class Heap { intptr_t adjusted_allocation_limit = old_gen_allocation_limit_ - new_space_.Capacity() / 5; - if (PromotedSpaceSize() >= adjusted_allocation_limit) return true; + if (PromotedSpaceSizeOfObjects() >= adjusted_allocation_limit) return true; return false; } @@ -1490,7 +1493,6 @@ class Heap { GCTracer* tracer() { return tracer_; } // Returns the size of objects residing in non new spaces. - intptr_t PromotedSpaceSize(); intptr_t PromotedSpaceSizeOfObjects(); double total_regexp_code_generated() { return total_regexp_code_generated_; } @@ -1569,10 +1571,6 @@ class Heap { // The roots that have an index less than this are always in old space. static const int kOldSpaceRoots = 0x20; - bool idle_notification_will_schedule_next_gc() { - return idle_notification_will_schedule_next_gc_; - } - uint32_t HashSeed() { uint32_t seed = static_cast<uint32_t>(hash_seed()->value()); ASSERT(FLAG_randomize_hashes || seed == 0); @@ -1609,6 +1607,8 @@ class Heap { // more expedient to get at the isolate directly from within Heap methods. Isolate* isolate_; + Object* roots_[kRootListLength]; + intptr_t code_range_size_; int reserved_semispace_size_; int max_semispace_size_; @@ -1650,7 +1650,7 @@ class Heap { int gc_post_processing_depth_; // Returns the amount of external memory registered since last global gc. - int PromotedExternalMemorySize(); + intptr_t PromotedExternalMemorySize(); int ms_count_; // how many mark-sweep collections happened unsigned int gc_count_; // how many gc happened @@ -1715,17 +1715,15 @@ class Heap { // The amount of external memory registered through the API kept alive // by global handles - int amount_of_external_allocated_memory_; + intptr_t amount_of_external_allocated_memory_; // Caches the amount of external memory registered at the last global gc. - int amount_of_external_allocated_memory_at_last_global_gc_; + intptr_t amount_of_external_allocated_memory_at_last_global_gc_; // Indicates that an allocation has failed in the old generation since the // last GC. int old_gen_exhausted_; - Object* roots_[kRootListLength]; - Object* global_contexts_list_; StoreBufferRebuilder store_buffer_rebuilder_; @@ -1978,13 +1976,6 @@ class Heap { return (scavenges_since_last_idle_round_ >= kIdleScavengeThreshold); } - bool WorthStartingGCWhenIdle() { - if (contexts_disposed_ > 0) { - return true; - } - return incremental_marking()->WorthActivating(); - } - // Estimates how many milliseconds a Mark-Sweep would take to complete. // In idle notification handler we assume that this function will return: // - a number less than 10 for small heaps, which are less than 8Mb. @@ -2033,7 +2024,6 @@ class Heap { unsigned int last_idle_notification_gc_count_; bool last_idle_notification_gc_count_init_; - bool idle_notification_will_schedule_next_gc_; int mark_sweeps_since_idle_round_started_; int ms_count_at_last_idle_notification_; unsigned int gc_count_at_last_idle_gc_; diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index f698da46d4..c66a7a137d 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/deps/v8/src/hydrogen-instructions.cc @@ -416,6 +416,7 @@ void HValue::Kill() { SetFlag(kIsDead); for (int i = 0; i < OperandCount(); ++i) { HValue* operand = OperandAt(i); + if (operand == NULL) continue; HUseListNode* first = operand->use_list_; if (first != NULL && first->value() == this && first->index() == i) { operand->use_list_ = first->tail(); @@ -462,7 +463,8 @@ void HValue::PrintChangesTo(StringStream* stream) { add_comma = true; \ stream->Add(#type); \ } - GVN_FLAG_LIST(PRINT_DO); + GVN_TRACKED_FLAG_LIST(PRINT_DO); + GVN_UNTRACKED_FLAG_LIST(PRINT_DO); #undef PRINT_DO } stream->Add("]"); @@ -599,6 +601,9 @@ void HInstruction::InsertAfter(HInstruction* previous) { SetBlock(block); previous->next_ = this; if (next != NULL) next->previous_ = this; + if (block->last() == previous) { + block->set_last(this); + } } @@ -608,6 +613,7 @@ void HInstruction::Verify() { HBasicBlock* cur_block = block(); for (int i = 0; i < OperandCount(); ++i) { HValue* other_operand = OperandAt(i); + if (other_operand == NULL) continue; HBasicBlock* other_block = other_operand->block(); if (cur_block == other_block) { if (!other_operand->IsPhi()) { @@ -866,6 +872,17 @@ HValue* HBitwise::Canonicalize() { } +HValue* HBitNot::Canonicalize() { + // Optimize ~~x, a common pattern used for ToInt32(x). + if (value()->IsBitNot()) { + HValue* result = HBitNot::cast(value())->value(); + ASSERT(result->representation().IsInteger32()); + return result; + } + return this; +} + + HValue* HAdd::Canonicalize() { if (!representation().IsInteger32()) return this; if (CheckUsesForFlag(kTruncatingToInt32)) ClearFlag(kCanOverflow); @@ -916,6 +933,62 @@ void HJSArrayLength::PrintDataTo(StringStream* stream) { } +HValue* HUnaryMathOperation::Canonicalize() { + if (op() == kMathFloor) { + // If the input is integer32 then we replace the floor instruction + // with its input. This happens before the representation changes are + // introduced. + if (value()->representation().IsInteger32()) return value(); + +#ifdef V8_TARGET_ARCH_ARM + if (value()->IsDiv() && (value()->UseCount() == 1)) { + // TODO(2038): Implement this optimization for non ARM architectures. + HDiv* hdiv = HDiv::cast(value()); + HValue* left = hdiv->left(); + HValue* right = hdiv->right(); + // Try to simplify left and right values of the division. + HValue* new_left = + LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(left); + HValue* new_right = + LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(right); + + // Return if left or right are not optimizable. + if ((new_left == NULL) || (new_right == NULL)) return this; + + // Insert the new values in the graph. + if (new_left->IsInstruction() && + !HInstruction::cast(new_left)->IsLinked()) { + HInstruction::cast(new_left)->InsertBefore(this); + } + if (new_right->IsInstruction() && + !HInstruction::cast(new_right)->IsLinked()) { + HInstruction::cast(new_right)->InsertBefore(this); + } + HMathFloorOfDiv* instr = new HMathFloorOfDiv(context(), + new_left, + new_right); + // Replace this HMathFloor instruction by the new HMathFloorOfDiv. + instr->InsertBefore(this); + ReplaceAllUsesWith(instr); + Kill(); + // We know the division had no other uses than this HMathFloor. Delete it. + // Also delete the arguments of the division if they are not used any + // more. + hdiv->DeleteAndReplaceWith(NULL); + ASSERT(left->IsChange() || left->IsConstant()); + ASSERT(right->IsChange() || right->IsConstant()); + if (left->HasNoUses()) left->DeleteAndReplaceWith(NULL); + if (right->HasNoUses()) right->DeleteAndReplaceWith(NULL); + + // Return NULL to remove this instruction from the graph. + return NULL; + } +#endif // V8_TARGET_ARCH_ARM + } + return this; +} + + HValue* HCheckInstanceType::Canonicalize() { if (check_ == IS_STRING && !value()->type().IsUninitialized() && @@ -965,16 +1038,13 @@ void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) { } -void HCheckMap::PrintDataTo(StringStream* stream) { +void HCheckMaps::PrintDataTo(StringStream* stream) { value()->PrintNameTo(stream); - stream->Add(" %p", *map()); - if (mode() == REQUIRE_EXACT_MAP) { - stream->Add(" [EXACT]"); - } else if (!has_element_transitions_) { - stream->Add(" [EXACT*]"); - } else { - stream->Add(" [MATCH ELEMENTS]"); + stream->Add(" [%p", *map_set()->first()); + for (int i = 1; i < map_set()->length(); ++i) { + stream->Add(",%p", *map_set()->at(i)); } + stream->Add("]"); } @@ -1533,6 +1603,7 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, SetOperandAt(1, object); set_representation(Representation::Tagged()); SetGVNFlag(kDependsOnMaps); + int map_transitions = 0; for (int i = 0; i < types->length() && types_.length() < kMaxLoadPolymorphism; ++i) { @@ -1554,13 +1625,20 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, case CONSTANT_FUNCTION: types_.Add(types->at(i)); break; + case MAP_TRANSITION: + // We should just ignore these since they are not relevant to a load + // operation. This means we will deopt if we actually see this map + // from optimized code. + map_transitions++; + break; default: break; } } } - if (types_.length() == types->length() && FLAG_deoptimize_uncommon_cases) { + if (types_.length() + map_transitions == types->length() && + FLAG_deoptimize_uncommon_cases) { SetFlag(kUseGVN); } else { SetAllSideEffects(); @@ -1736,6 +1814,9 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) { stream->Add(" = "); value()->PrintNameTo(stream); stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : ""); + if (NeedsWriteBarrier()) { + stream->Add(" (write-barrier)"); + } if (!transition().is_null()) { stream->Add(" (transition map %p)", *transition()); } @@ -1879,7 +1960,7 @@ HType HValue::CalculateInferredType() { } -HType HCheckMap::CalculateInferredType() { +HType HCheckMaps::CalculateInferredType() { return value()->type(); } @@ -2089,6 +2170,17 @@ HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) { } +bool HStoreKeyedFastDoubleElement::NeedsCanonicalization() { + // If value was loaded from unboxed double backing store or + // converted from an integer then we don't have to canonicalize it. + if (value()->IsLoadKeyedFastDoubleElement() || + (value()->IsChange() && HChange::cast(value())->from().IsInteger32())) { + return false; + } + return true; +} + + #define H_CONSTANT_INT32(val) \ new(zone) HConstant(FACTORY->NewNumberFromInt(val, TENURED), \ Representation::Integer32()) @@ -2257,6 +2349,13 @@ void HIn::PrintDataTo(StringStream* stream) { } +void HBitwise::PrintDataTo(StringStream* stream) { + stream->Add(Token::Name(op_)); + stream->Add(" "); + HBitwiseBinaryOperation::PrintDataTo(stream); +} + + Representation HPhi::InferredRepresentation() { bool double_occurred = false; bool int32_occurred = false; diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index fb5879fd90..9d262fc811 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -85,7 +85,7 @@ class LChunkBuilder; V(Change) \ V(CheckFunction) \ V(CheckInstanceType) \ - V(CheckMap) \ + V(CheckMaps) \ V(CheckNonSmi) \ V(CheckPrototypeMaps) \ V(CheckSmi) \ @@ -140,6 +140,7 @@ class LChunkBuilder; V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ + V(MathFloorOfDiv) \ V(Mod) \ V(Mul) \ V(ObjectLiteral) \ @@ -188,7 +189,10 @@ class LChunkBuilder; V(DateField) \ V(WrapReceiver) -#define GVN_FLAG_LIST(V) \ +#define GVN_TRACKED_FLAG_LIST(V) \ + V(NewSpacePromotion) + +#define GVN_UNTRACKED_FLAG_LIST(V) \ V(Calls) \ V(InobjectFields) \ V(BackingStoreFields) \ @@ -506,14 +510,18 @@ class HUseIterator BASE_EMBEDDED { // There must be one corresponding kDepends flag for every kChanges flag and // the order of the kChanges flags must be exactly the same as of the kDepends -// flags. +// flags. All tracked flags should appear before untracked ones. enum GVNFlag { // Declare global value numbering flags. #define DECLARE_FLAG(type) kChanges##type, kDependsOn##type, - GVN_FLAG_LIST(DECLARE_FLAG) + GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) + GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) #undef DECLARE_FLAG kAfterLastFlag, - kLastFlag = kAfterLastFlag - 1 + kLastFlag = kAfterLastFlag - 1, +#define COUNT_FLAG(type) + 1 + kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG) +#undef COUNT_FLAG }; typedef EnumSet<GVNFlag> GVNFlagSet; @@ -530,6 +538,10 @@ class HValue: public ZoneObject { // implement DataEquals(), which will be used to determine if other // occurrences of the instruction are indeed the same. kUseGVN, + // Track instructions that are dominating side effects. If an instruction + // sets this flag, it must implement SetSideEffectDominator() and should + // indicate which side effects to track by setting GVN flags. + kTrackSideEffectDominators, kCanOverflow, kBailoutOnMinusZero, kCanBeDivByZero, @@ -544,6 +556,12 @@ class HValue: public ZoneObject { static const int kChangesToDependsFlagsLeftShift = 1; + static GVNFlag ChangesFlagFromInt(int x) { + return static_cast<GVNFlag>(x * 2); + } + static GVNFlag DependsOnFlagFromInt(int x) { + return static_cast<GVNFlag>(x * 2 + 1); + } static GVNFlagSet ConvertChangesToDependsFlags(GVNFlagSet flags) { return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift); } @@ -726,6 +744,13 @@ class HValue: public ZoneObject { virtual HType CalculateInferredType(); + // This function must be overridden for instructions which have the + // kTrackSideEffectDominators flag set, to track instructions that are + // dominating side effects. + virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) { + UNREACHABLE(); + } + #ifdef DEBUG virtual void Verify() = 0; #endif @@ -756,7 +781,8 @@ class HValue: public ZoneObject { GVNFlagSet result; // Create changes mask. #define ADD_FLAG(type) result.Add(kDependsOn##type); - GVN_FLAG_LIST(ADD_FLAG) + GVN_TRACKED_FLAG_LIST(ADD_FLAG) + GVN_UNTRACKED_FLAG_LIST(ADD_FLAG) #undef ADD_FLAG return result; } @@ -765,7 +791,8 @@ class HValue: public ZoneObject { GVNFlagSet result; // Create changes mask. #define ADD_FLAG(type) result.Add(kChanges##type); - GVN_FLAG_LIST(ADD_FLAG) + GVN_TRACKED_FLAG_LIST(ADD_FLAG) + GVN_UNTRACKED_FLAG_LIST(ADD_FLAG) #undef ADD_FLAG return result; } @@ -781,6 +808,7 @@ class HValue: public ZoneObject { // an executing program (i.e. are not safe to repeat, move or remove); static GVNFlagSet AllObservableSideEffectsFlagSet() { GVNFlagSet result = AllChangesFlagSet(); + result.Remove(kChangesNewSpacePromotion); result.Remove(kChangesElementsKind); result.Remove(kChangesElementsPointer); result.Remove(kChangesMaps); @@ -1196,6 +1224,7 @@ class HChange: public HUnaryOperation { SetFlag(kUseGVN); if (deoptimize_on_undefined) SetFlag(kDeoptimizeOnUndefined); if (is_truncating) SetFlag(kTruncatingToInt32); + if (to.IsTagged()) SetGVNFlag(kChangesNewSpacePromotion); } virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); @@ -1321,6 +1350,7 @@ class HStackCheck: public HTemplateInstruction<1> { HStackCheck(HValue* context, Type type) : type_(type) { SetOperandAt(0, context); + SetGVNFlag(kChangesNewSpacePromotion); } HValue* context() { return OperandAt(0); } @@ -1353,12 +1383,16 @@ class HEnterInlined: public HTemplateInstruction<0> { int arguments_count, FunctionLiteral* function, CallKind call_kind, - bool is_construct) + bool is_construct, + Variable* arguments_var, + ZoneList<HValue*>* arguments_values) : closure_(closure), arguments_count_(arguments_count), function_(function), call_kind_(call_kind), - is_construct_(is_construct) { + is_construct_(is_construct), + arguments_var_(arguments_var), + arguments_values_(arguments_values) { } virtual void PrintDataTo(StringStream* stream); @@ -1373,6 +1407,9 @@ class HEnterInlined: public HTemplateInstruction<0> { return Representation::None(); } + Variable* arguments_var() { return arguments_var_; } + ZoneList<HValue*>* arguments_values() { return arguments_values_; } + DECLARE_CONCRETE_INSTRUCTION(EnterInlined) private: @@ -1381,18 +1418,28 @@ class HEnterInlined: public HTemplateInstruction<0> { FunctionLiteral* function_; CallKind call_kind_; bool is_construct_; + Variable* arguments_var_; + ZoneList<HValue*>* arguments_values_; }; class HLeaveInlined: public HTemplateInstruction<0> { public: - HLeaveInlined() {} + explicit HLeaveInlined(bool arguments_pushed) + : arguments_pushed_(arguments_pushed) { } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); } + bool arguments_pushed() { + return arguments_pushed_; + } + DECLARE_CONCRETE_INSTRUCTION(LeaveInlined) + + private: + bool arguments_pushed_; }; @@ -1600,14 +1647,26 @@ class HInvokeFunction: public HBinaryCall { : HBinaryCall(context, function, argument_count) { } + HInvokeFunction(HValue* context, + HValue* function, + Handle<JSFunction> known_function, + int argument_count) + : HBinaryCall(context, function, argument_count), + known_function_(known_function) { + } + virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); } HValue* context() { return first(); } HValue* function() { return second(); } + Handle<JSFunction> known_function() { return known_function_; } DECLARE_CONCRETE_INSTRUCTION(InvokeFunction) + + private: + Handle<JSFunction> known_function_; }; @@ -1860,6 +1919,8 @@ class HBitNot: public HUnaryOperation { } virtual HType CalculateInferredType(); + virtual HValue* Canonicalize(); + DECLARE_CONCRETE_INSTRUCTION(BitNot) protected: @@ -1882,6 +1943,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { case kMathAbs: set_representation(Representation::Tagged()); SetFlag(kFlexibleRepresentation); + SetGVNFlag(kChangesNewSpacePromotion); break; case kMathSqrt: case kMathPowHalf: @@ -1890,6 +1952,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { case kMathCos: case kMathTan: set_representation(Representation::Double()); + SetGVNFlag(kChangesNewSpacePromotion); break; default: UNREACHABLE(); @@ -1930,15 +1993,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { } } - virtual HValue* Canonicalize() { - // If the input is integer32 then we replace the floor instruction - // with its inputs. This happens before the representation changes are - // introduced. - if (op() == kMathFloor) { - if (value()->representation().IsInteger32()) return value(); - } - return this; - } + virtual HValue* Canonicalize(); BuiltinFunctionId op() const { return op_; } const char* OpName() const; @@ -1998,14 +2053,9 @@ class HLoadExternalArrayPointer: public HUnaryOperation { }; -class HCheckMap: public HTemplateInstruction<2> { +class HCheckMaps: public HTemplateInstruction<2> { public: - HCheckMap(HValue* value, - Handle<Map> map, - HValue* typecheck = NULL, - CompareMapMode mode = REQUIRE_EXACT_MAP) - : map_(map), - mode_(mode) { + HCheckMaps(HValue* value, Handle<Map> map, HValue* typecheck = NULL) { SetOperandAt(0, value); // If callers don't depend on a typecheck, they can pass in NULL. In that // case we use a copy of the |value| argument as a dummy value. @@ -2013,14 +2063,49 @@ class HCheckMap: public HTemplateInstruction<2> { set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetGVNFlag(kDependsOnMaps); - // If the map to check doesn't have the untransitioned elements, it must not - // be hoisted above TransitionElements instructions. - if (mode == REQUIRE_EXACT_MAP || !map->has_fast_smi_only_elements()) { - SetGVNFlag(kDependsOnElementsKind); + SetGVNFlag(kDependsOnElementsKind); + map_set()->Add(map); + } + HCheckMaps(HValue* value, SmallMapList* maps) { + SetOperandAt(0, value); + SetOperandAt(1, value); + set_representation(Representation::Tagged()); + SetFlag(kUseGVN); + SetGVNFlag(kDependsOnMaps); + SetGVNFlag(kDependsOnElementsKind); + for (int i = 0; i < maps->length(); i++) { + map_set()->Add(maps->at(i)); + } + map_set()->Sort(); + } + + static HCheckMaps* NewWithTransitions(HValue* object, Handle<Map> map) { + HCheckMaps* check_map = new HCheckMaps(object, map); + SmallMapList* map_set = check_map->map_set(); + + // If the map to check has the untransitioned elements, it can be hoisted + // above TransitionElements instructions. + if (map->has_fast_smi_only_elements()) { + check_map->ClearGVNFlag(kDependsOnElementsKind); + } + + Map* transitioned_fast_element_map = + map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL); + ASSERT(transitioned_fast_element_map == NULL || + map->elements_kind() != FAST_ELEMENTS); + if (transitioned_fast_element_map != NULL) { + map_set->Add(Handle<Map>(transitioned_fast_element_map)); + } + Map* transitioned_double_map = + map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL); + ASSERT(transitioned_double_map == NULL || + map->elements_kind() == FAST_SMI_ONLY_ELEMENTS); + if (transitioned_double_map != NULL) { + map_set->Add(Handle<Map>(transitioned_double_map)); } - has_element_transitions_ = - map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL) != NULL || - map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL) != NULL; + map_set->Sort(); + + return check_map; } virtual Representation RequiredInputRepresentation(int index) { @@ -2030,25 +2115,23 @@ class HCheckMap: public HTemplateInstruction<2> { virtual HType CalculateInferredType(); HValue* value() { return OperandAt(0); } - Handle<Map> map() const { return map_; } - CompareMapMode mode() const { return mode_; } + SmallMapList* map_set() { return &map_set_; } - DECLARE_CONCRETE_INSTRUCTION(CheckMap) + DECLARE_CONCRETE_INSTRUCTION(CheckMaps) protected: virtual bool DataEquals(HValue* other) { - HCheckMap* b = HCheckMap::cast(other); - // Two CheckMaps instructions are DataEqual if their maps are identical and - // they have the same mode. The mode comparison can be ignored if the map - // has no elements transitions. - return map_.is_identical_to(b->map()) && - (b->mode() == mode() || !has_element_transitions_); + HCheckMaps* b = HCheckMaps::cast(other); + // Relies on the fact that map_set has been sorted before. + if (map_set()->length() != b->map_set()->length()) return false; + for (int i = 0; i < map_set()->length(); i++) { + if (!map_set()->at(i).is_identical_to(b->map_set()->at(i))) return false; + } + return true; } private: - bool has_element_transitions_; - Handle<Map> map_; - CompareMapMode mode_; + SmallMapList map_set_; }; @@ -2544,7 +2627,7 @@ class HApplyArguments: public HTemplateInstruction<4> { class HArgumentsElements: public HTemplateInstruction<0> { public: - HArgumentsElements() { + explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) { // The value produced by this instruction is a pointer into the stack // that looks as if it was a smi because of alignment. set_representation(Representation::Tagged()); @@ -2557,8 +2640,12 @@ class HArgumentsElements: public HTemplateInstruction<0> { return Representation::None(); } + bool from_inlined() const { return from_inlined_; } + protected: virtual bool DataEquals(HValue* other) { return true; } + + bool from_inlined_; }; @@ -2664,6 +2751,25 @@ class HBitwiseBinaryOperation: public HBinaryOperation { }; +class HMathFloorOfDiv: public HBinaryOperation { + public: + HMathFloorOfDiv(HValue* context, HValue* left, HValue* right) + : HBinaryOperation(context, left, right) { + set_representation(Representation::Integer32()); + SetFlag(kUseGVN); + } + + virtual Representation RequiredInputRepresentation(int index) { + return Representation::Integer32(); + } + + DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv) + + protected: + virtual bool DataEquals(HValue* other) { return true; } +}; + + class HArithmeticBinaryOperation: public HBinaryOperation { public: HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right) @@ -3078,6 +3184,7 @@ class HPower: public HTemplateInstruction<2> { SetOperandAt(1, right); set_representation(Representation::Double()); SetFlag(kUseGVN); + SetGVNFlag(kChangesNewSpacePromotion); } HValue* left() { return OperandAt(0); } @@ -3277,6 +3384,8 @@ class HBitwise: public HBitwiseBinaryOperation { HValue* left, HValue* right); + virtual void PrintDataTo(StringStream* stream); + DECLARE_CONCRETE_INSTRUCTION(Bitwise) protected: @@ -3524,6 +3633,12 @@ inline bool StoringValueNeedsWriteBarrier(HValue* value) { } +inline bool ReceiverObjectNeedsWriteBarrier(HValue* object, + HValue* new_space_dominator) { + return !object->IsAllocateObject() || (object != new_space_dominator); +} + + class HStoreGlobalCell: public HUnaryOperation { public: HStoreGlobalCell(HValue* value, @@ -3990,9 +4105,12 @@ class HStoreNamedField: public HTemplateInstruction<2> { int offset) : name_(name), is_in_object_(in_object), - offset_(offset) { + offset_(offset), + new_space_dominator_(NULL) { SetOperandAt(0, obj); SetOperandAt(1, val); + SetFlag(kTrackSideEffectDominators); + SetGVNFlag(kDependsOnNewSpacePromotion); if (is_in_object_) { SetGVNFlag(kChangesInobjectFields); } else { @@ -4005,6 +4123,10 @@ class HStoreNamedField: public HTemplateInstruction<2> { virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); } + virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) { + ASSERT(side_effect == kChangesNewSpacePromotion); + new_space_dominator_ = dominator; + } virtual void PrintDataTo(StringStream* stream); HValue* object() { return OperandAt(0); } @@ -4015,9 +4137,11 @@ class HStoreNamedField: public HTemplateInstruction<2> { int offset() const { return offset_; } Handle<Map> transition() const { return transition_; } void set_transition(Handle<Map> map) { transition_ = map; } + HValue* new_space_dominator() const { return new_space_dominator_; } bool NeedsWriteBarrier() { - return StoringValueNeedsWriteBarrier(value()); + return StoringValueNeedsWriteBarrier(value()) && + ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); } private: @@ -4025,6 +4149,7 @@ class HStoreNamedField: public HTemplateInstruction<2> { bool is_in_object_; int offset_; Handle<Map> transition_; + HValue* new_space_dominator_; }; @@ -4134,6 +4259,8 @@ class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> { return StoringValueNeedsWriteBarrier(value()); } + bool NeedsCanonicalization(); + virtual void PrintDataTo(StringStream* stream); DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement) @@ -4227,6 +4354,7 @@ class HTransitionElementsKind: public HTemplateInstruction<1> { SetFlag(kUseGVN); SetGVNFlag(kChangesElementsKind); SetGVNFlag(kChangesElementsPointer); + SetGVNFlag(kChangesNewSpacePromotion); set_representation(Representation::Tagged()); } @@ -4288,6 +4416,7 @@ class HStringCharCodeAt: public HTemplateInstruction<3> { set_representation(Representation::Integer32()); SetFlag(kUseGVN); SetGVNFlag(kDependsOnMaps); + SetGVNFlag(kChangesNewSpacePromotion); } virtual Representation RequiredInputRepresentation(int index) { @@ -4319,6 +4448,7 @@ class HStringCharFromCode: public HTemplateInstruction<2> { SetOperandAt(1, char_code); set_representation(Representation::Tagged()); SetFlag(kUseGVN); + SetGVNFlag(kChangesNewSpacePromotion); } virtual Representation RequiredInputRepresentation(int index) { @@ -4371,8 +4501,12 @@ class HAllocateObject: public HTemplateInstruction<1> { : constructor_(constructor) { SetOperandAt(0, context); set_representation(Representation::Tagged()); + SetGVNFlag(kChangesNewSpacePromotion); } + // Maximum instance size for which allocations will be inlined. + static const int kMaxSize = 64 * kPointerSize; + HValue* context() { return OperandAt(0); } Handle<JSFunction> constructor() { return constructor_; } @@ -4416,6 +4550,7 @@ class HFastLiteral: public HMaterializedLiteral<1> { boilerplate_(boilerplate), total_size_(total_size) { SetOperandAt(0, context); + SetGVNFlag(kChangesNewSpacePromotion); } // Maximum depth and total number of elements and properties for literal @@ -4451,6 +4586,7 @@ class HArrayLiteral: public HMaterializedLiteral<1> { length_(length), boilerplate_object_(boilerplate_object) { SetOperandAt(0, context); + SetGVNFlag(kChangesNewSpacePromotion); } HValue* context() { return OperandAt(0); } @@ -4491,6 +4627,7 @@ class HObjectLiteral: public HMaterializedLiteral<1> { fast_elements_(fast_elements), has_function_(has_function) { SetOperandAt(0, context); + SetGVNFlag(kChangesNewSpacePromotion); } HValue* context() { return OperandAt(0); } @@ -4552,6 +4689,7 @@ class HFunctionLiteral: public HTemplateInstruction<1> { : shared_info_(shared), pretenure_(pretenure) { SetOperandAt(0, context); set_representation(Representation::Tagged()); + SetGVNFlag(kChangesNewSpacePromotion); } HValue* context() { return OperandAt(0); } diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 34fd1bc10a..3be001e42b 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -113,7 +113,6 @@ void HBasicBlock::AddInstruction(HInstruction* instr) { first_ = last_ = entry; } instr->InsertAfter(last_); - last_ = instr; } @@ -165,11 +164,15 @@ void HBasicBlock::Finish(HControlInstruction* end) { } -void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { +void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) { + bool drop_extra = state != NULL && state->drop_extra(); + bool arguments_pushed = state != NULL && state->arguments_pushed(); + if (block->IsInlineReturnTarget()) { - AddInstruction(new(zone()) HLeaveInlined); + AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); last_environment_ = last_environment()->DiscardInlined(drop_extra); } + AddSimulate(AstNode::kNoNumber); HGoto* instr = new(zone()) HGoto(block); Finish(instr); @@ -178,10 +181,13 @@ void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target, - bool drop_extra) { + FunctionState* state) { + bool drop_extra = state != NULL && state->drop_extra(); + bool arguments_pushed = state != NULL && state->arguments_pushed(); + ASSERT(target->IsInlineReturnTarget()); ASSERT(return_value != NULL); - AddInstruction(new(zone()) HLeaveInlined); + AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); last_environment_ = last_environment()->DiscardInlined(drop_extra); last_environment()->Push(return_value); AddSimulate(AstNode::kNoNumber); @@ -606,6 +612,7 @@ HGraphBuilder::HGraphBuilder(CompilationInfo* info, graph_(NULL), current_block_(NULL), inlined_count_(0), + globals_(10), zone_(info->isolate()->zone()), inline_bailout_(false) { // This is not initialized in the initializer list because the @@ -1143,14 +1150,39 @@ void HRangeAnalysis::AddRange(HValue* value, Range* range) { void TraceGVN(const char* msg, ...) { - if (FLAG_trace_gvn) { - va_list arguments; - va_start(arguments, msg); - OS::VPrint(msg, arguments); - va_end(arguments); - } + va_list arguments; + va_start(arguments, msg); + OS::VPrint(msg, arguments); + va_end(arguments); } +// Wrap TraceGVN in macros to avoid the expense of evaluating its arguments when +// --trace-gvn is off. +#define TRACE_GVN_1(msg, a1) \ + if (FLAG_trace_gvn) { \ + TraceGVN(msg, a1); \ + } + +#define TRACE_GVN_2(msg, a1, a2) \ + if (FLAG_trace_gvn) { \ + TraceGVN(msg, a1, a2); \ + } + +#define TRACE_GVN_3(msg, a1, a2, a3) \ + if (FLAG_trace_gvn) { \ + TraceGVN(msg, a1, a2, a3); \ + } + +#define TRACE_GVN_4(msg, a1, a2, a3, a4) \ + if (FLAG_trace_gvn) { \ + TraceGVN(msg, a1, a2, a3, a4); \ + } + +#define TRACE_GVN_5(msg, a1, a2, a3, a4, a5) \ + if (FLAG_trace_gvn) { \ + TraceGVN(msg, a1, a2, a3, a4, a5); \ + } + HValueMap::HValueMap(Zone* zone, const HValueMap* other) : array_size_(other->array_size_), @@ -1321,6 +1353,38 @@ void HValueMap::Insert(HValue* value) { } +HSideEffectMap::HSideEffectMap() : count_(0) { + memset(data_, 0, kNumberOfTrackedSideEffects * kPointerSize); +} + + +HSideEffectMap::HSideEffectMap(HSideEffectMap* other) : count_(other->count_) { + memcpy(data_, other->data_, kNumberOfTrackedSideEffects * kPointerSize); +} + + +void HSideEffectMap::Kill(GVNFlagSet flags) { + for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { + GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); + if (flags.Contains(changes_flag)) { + if (data_[i] != NULL) count_--; + data_[i] = NULL; + } + } +} + + +void HSideEffectMap::Store(GVNFlagSet flags, HInstruction* instr) { + for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { + GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); + if (flags.Contains(changes_flag)) { + if (data_[i] == NULL) count_++; + data_[i] = instr; + } + } +} + + class HStackCheckEliminator BASE_EMBEDDED { public: explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { } @@ -1427,7 +1491,9 @@ class HGlobalValueNumberer BASE_EMBEDDED { GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock( HBasicBlock* dominator, HBasicBlock* dominated); - void AnalyzeBlock(HBasicBlock* block, HValueMap* map); + void AnalyzeBlock(HBasicBlock* block, + HValueMap* map, + HSideEffectMap* dominators); void ComputeBlockSideEffects(); void LoopInvariantCodeMotion(); void ProcessLoopBlock(HBasicBlock* block, @@ -1465,7 +1531,8 @@ bool HGlobalValueNumberer::Analyze() { LoopInvariantCodeMotion(); } HValueMap* map = new(zone()) HValueMap(); - AnalyzeBlock(graph_->entry_block(), map); + HSideEffectMap side_effect_dominators; + AnalyzeBlock(graph_->entry_block(), map, &side_effect_dominators); return removed_side_effects_; } @@ -1510,14 +1577,100 @@ void HGlobalValueNumberer::ComputeBlockSideEffects() { } +SmartArrayPointer<char> GetGVNFlagsString(GVNFlagSet flags) { + char underlying_buffer[kLastFlag * 128]; + Vector<char> buffer(underlying_buffer, sizeof(underlying_buffer)); +#if DEBUG + int offset = 0; + const char* separator = ""; + const char* comma = ", "; + buffer[0] = 0; + uint32_t set_depends_on = 0; + uint32_t set_changes = 0; + for (int bit = 0; bit < kLastFlag; ++bit) { + if ((flags.ToIntegral() & (1 << bit)) != 0) { + if (bit % 2 == 0) { + set_changes++; + } else { + set_depends_on++; + } + } + } + bool positive_changes = set_changes < (kLastFlag / 2); + bool positive_depends_on = set_depends_on < (kLastFlag / 2); + if (set_changes > 0) { + if (positive_changes) { + offset += OS::SNPrintF(buffer + offset, "changes ["); + } else { + offset += OS::SNPrintF(buffer + offset, "changes all except ["); + } + for (int bit = 0; bit < kLastFlag; ++bit) { + if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_changes) { + switch (static_cast<GVNFlag>(bit)) { +#define DECLARE_FLAG(type) \ + case kChanges##type: \ + offset += OS::SNPrintF(buffer + offset, separator); \ + offset += OS::SNPrintF(buffer + offset, #type); \ + separator = comma; \ + break; +GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) +GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) +#undef DECLARE_FLAG + default: + break; + } + } + } + offset += OS::SNPrintF(buffer + offset, "]"); + } + if (set_depends_on > 0) { + separator = ""; + if (set_changes > 0) { + offset += OS::SNPrintF(buffer + offset, ", "); + } + if (positive_depends_on) { + offset += OS::SNPrintF(buffer + offset, "depends on ["); + } else { + offset += OS::SNPrintF(buffer + offset, "depends on all except ["); + } + for (int bit = 0; bit < kLastFlag; ++bit) { + if (((flags.ToIntegral() & (1 << bit)) != 0) == positive_depends_on) { + switch (static_cast<GVNFlag>(bit)) { +#define DECLARE_FLAG(type) \ + case kDependsOn##type: \ + offset += OS::SNPrintF(buffer + offset, separator); \ + offset += OS::SNPrintF(buffer + offset, #type); \ + separator = comma; \ + break; +GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) +GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) +#undef DECLARE_FLAG + default: + break; + } + } + } + offset += OS::SNPrintF(buffer + offset, "]"); + } +#else + OS::SNPrintF(buffer, "0x%08X", flags.ToIntegral()); +#endif + size_t string_len = strlen(underlying_buffer) + 1; + ASSERT(string_len <= sizeof(underlying_buffer)); + char* result = new char[strlen(underlying_buffer) + 1]; + memcpy(result, underlying_buffer, string_len); + return SmartArrayPointer<char>(result); +} + + void HGlobalValueNumberer::LoopInvariantCodeMotion() { for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { HBasicBlock* block = graph_->blocks()->at(i); if (block->IsLoopHeader()) { GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; - TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n", - block->block_id(), - side_effects.ToIntegral()); + TRACE_GVN_2("Try loop invariant motion for block B%d %s\n", + block->block_id(), + *GetGVNFlagsString(side_effects)); GVNFlagSet accumulated_first_time_depends; GVNFlagSet accumulated_first_time_changes; @@ -1540,20 +1693,19 @@ void HGlobalValueNumberer::ProcessLoopBlock( GVNFlagSet* first_time_changes) { HBasicBlock* pre_header = loop_header->predecessors()->at(0); GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); - TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n", - block->block_id(), - depends_flags.ToIntegral()); + TRACE_GVN_2("Loop invariant motion for B%d %s\n", + block->block_id(), + *GetGVNFlagsString(depends_flags)); HInstruction* instr = block->first(); while (instr != NULL) { HInstruction* next = instr->next(); bool hoisted = false; if (instr->CheckFlag(HValue::kUseGVN)) { - TraceGVN("Checking instruction %d (%s) instruction GVN flags 0x%X, " - "loop kills 0x%X\n", - instr->id(), - instr->Mnemonic(), - instr->gvn_flags().ToIntegral(), - depends_flags.ToIntegral()); + TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", + instr->id(), + instr->Mnemonic(), + *GetGVNFlagsString(instr->gvn_flags()), + *GetGVNFlagsString(loop_kills)); bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); if (instr->IsTransitionElementsKind()) { // It's possible to hoist transitions out of a loop as long as the @@ -1576,15 +1728,19 @@ void HGlobalValueNumberer::ProcessLoopBlock( if (trans->transitioned_map()->has_fast_double_elements()) { hoist_change_blockers.Add(kChangesArrayElements); } - TraceGVN("Checking dependencies on HTransitionElementsKind %d (%s) " - "hoist depends blockers 0x%X, hoist change blockers 0x%X, " - "accumulated depends 0x%X, accumulated changes 0x%X\n", - instr->id(), - instr->Mnemonic(), - hoist_depends_blockers.ToIntegral(), - hoist_change_blockers.ToIntegral(), - first_time_depends->ToIntegral(), - first_time_changes->ToIntegral()); + if (FLAG_trace_gvn) { + GVNFlagSet hoist_blockers = hoist_depends_blockers; + hoist_blockers.Add(hoist_change_blockers); + GVNFlagSet first_time = *first_time_changes; + first_time.Add(*first_time_depends); + TRACE_GVN_4("Checking dependencies on HTransitionElementsKind " + "%d (%s) hoist blockers: %s; " + "first-time accumulated: %s\n", + instr->id(), + instr->Mnemonic(), + *GetGVNFlagsString(hoist_blockers), + *GetGVNFlagsString(first_time)); + } // It's possible to hoist transition from the current loop loop only if // they dominate all of the successor blocks in the same loop and there // are not any instructions that have Changes/DependsOn that intervene @@ -1607,7 +1763,7 @@ void HGlobalValueNumberer::ProcessLoopBlock( } if (inputs_loop_invariant && ShouldMove(instr, loop_header)) { - TraceGVN("Hoisting loop invariant instruction %d\n", instr->id()); + TRACE_GVN_1("Hoisting loop invariant instruction %d\n", instr->id()); // Move the instruction out of the loop. instr->Unlink(); instr->InsertBefore(pre_header->end()); @@ -1619,8 +1775,18 @@ void HGlobalValueNumberer::ProcessLoopBlock( if (!hoisted) { // If an instruction is not hoisted, we have to account for its side // effects when hoisting later HTransitionElementsKind instructions. + GVNFlagSet previous_depends = *first_time_depends; + GVNFlagSet previous_changes = *first_time_changes; first_time_depends->Add(instr->DependsOnFlags()); first_time_changes->Add(instr->ChangesFlags()); + if (!(previous_depends == *first_time_depends)) { + TRACE_GVN_1("Updated first-time accumulated %s\n", + *GetGVNFlagsString(*first_time_depends)); + } + if (!(previous_changes == *first_time_changes)) { + TRACE_GVN_1("Updated first-time accumulated %s\n", + *GetGVNFlagsString(*first_time_changes)); + } } instr = next; } @@ -1660,10 +1826,12 @@ GVNFlagSet HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( } -void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { - TraceGVN("Analyzing block B%d%s\n", - block->block_id(), - block->IsLoopHeader() ? " (loop header)" : ""); +void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, + HValueMap* map, + HSideEffectMap* dominators) { + TRACE_GVN_2("Analyzing block B%d%s\n", + block->block_id(), + block->IsLoopHeader() ? " (loop header)" : ""); // If this is a loop header kill everything killed by the loop. if (block->IsLoopHeader()) { @@ -1677,25 +1845,45 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { GVNFlagSet flags = instr->ChangesFlags(); if (!flags.IsEmpty()) { // Clear all instructions in the map that are affected by side effects. + // Store instruction as the dominating one for tracked side effects. map->Kill(flags); - TraceGVN("Instruction %d kills\n", instr->id()); + dominators->Store(flags, instr); + TRACE_GVN_2("Instruction %d %s\n", instr->id(), + *GetGVNFlagsString(flags)); } if (instr->CheckFlag(HValue::kUseGVN)) { ASSERT(!instr->HasObservableSideEffects()); HValue* other = map->Lookup(instr); if (other != NULL) { ASSERT(instr->Equals(other) && other->Equals(instr)); - TraceGVN("Replacing value %d (%s) with value %d (%s)\n", - instr->id(), - instr->Mnemonic(), - other->id(), - other->Mnemonic()); + TRACE_GVN_4("Replacing value %d (%s) with value %d (%s)\n", + instr->id(), + instr->Mnemonic(), + other->id(), + other->Mnemonic()); if (instr->HasSideEffects()) removed_side_effects_ = true; instr->DeleteAndReplaceWith(other); } else { map->Add(instr); } } + if (instr->CheckFlag(HValue::kTrackSideEffectDominators)) { + for (int i = 0; i < kNumberOfTrackedSideEffects; i++) { + HValue* other = dominators->at(i); + GVNFlag changes_flag = HValue::ChangesFlagFromInt(i); + GVNFlag depends_on_flag = HValue::DependsOnFlagFromInt(i); + if (instr->DependsOnFlags().Contains(depends_on_flag) && + (other != NULL)) { + TRACE_GVN_5("Side-effect #%d in %d (%s) is dominated by %d (%s)\n", + i, + instr->id(), + instr->Mnemonic(), + other->id(), + other->Mnemonic()); + instr->SetSideEffectDominator(changes_flag, other); + } + } + } instr = next; } @@ -1705,20 +1893,22 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { HBasicBlock* dominated = block->dominated_blocks()->at(i); // No need to copy the map for the last child in the dominator tree. HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone()); + HSideEffectMap successor_dominators(dominators); // Kill everything killed on any path between this block and the - // dominated block. - // We don't have to traverse these paths if the value map is - // already empty. - // If the range of block ids (block_id, dominated_id) is empty - // there are no such paths. - if (!successor_map->IsEmpty() && + // dominated block. We don't have to traverse these paths if the + // value map and the dominators list is already empty. If the range + // of block ids (block_id, dominated_id) is empty there are no such + // paths. + if ((!successor_map->IsEmpty() || !successor_dominators.IsEmpty()) && block->block_id() + 1 < dominated->block_id()) { visited_on_paths_.Clear(); - successor_map->Kill(CollectSideEffectsOnPathsToDominatedBlock(block, - dominated)); + GVNFlagSet side_effects_on_all_paths = + CollectSideEffectsOnPathsToDominatedBlock(block, dominated); + successor_map->Kill(side_effects_on_all_paths); + successor_dominators.Kill(side_effects_on_all_paths); } - AnalyzeBlock(dominated, successor_map); + AnalyzeBlock(dominated, successor_map, &successor_dominators); } } @@ -2178,6 +2368,8 @@ FunctionState::FunctionState(HGraphBuilder* owner, return_handling_(return_handling), function_return_(NULL), test_context_(NULL), + entry_(NULL), + arguments_elements_(NULL), outer_(owner->function_state()) { if (outer_ != NULL) { // State for an inline function. @@ -2337,8 +2529,8 @@ void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { instr->SetSuccessorAt(0, empty_true); instr->SetSuccessorAt(1, empty_false); owner()->current_block()->Finish(instr); - empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); - empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); + empty_true->Goto(if_true(), owner()->function_state()); + empty_false->Goto(if_false(), owner()->function_state()); owner()->set_current_block(NULL); } @@ -2359,8 +2551,8 @@ void TestContext::BuildBranch(HValue* value) { HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); builder->current_block()->Finish(test); - empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); - empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); + empty_true->Goto(if_true(), owner()->function_state()); + empty_false->Goto(if_false(), owner()->function_state()); builder->set_current_block(NULL); } @@ -2484,7 +2676,7 @@ HGraph* HGraphBuilder::CreateGraph() { // Handle implicit declaration of the function name in named function // expressions before other declarations. if (scope->is_function_scope() && scope->function() != NULL) { - HandleDeclaration(scope->function(), CONST, NULL, NULL); + VisitVariableDeclaration(scope->function()); } VisitDeclarations(scope->declarations()); AddSimulate(AstNode::kDeclarationsId); @@ -2565,29 +2757,328 @@ HGraph* HGraphBuilder::CreateGraph() { HStackCheckEliminator sce(graph()); sce.Process(); - // Replace the results of check instructions with the original value, if the - // result is used. This is safe now, since we don't do code motion after this - // point. It enables better register allocation since the value produced by - // check instructions is really a copy of the original value. - graph()->ReplaceCheckedValues(); + graph()->EliminateRedundantBoundsChecks(); return graph(); } -void HGraph::ReplaceCheckedValues() { - HPhase phase("H_Replace checked values", this); - for (int i = 0; i < blocks()->length(); ++i) { - HInstruction* instr = blocks()->at(i)->first(); - while (instr != NULL) { - if (instr->IsBoundsCheck()) { - // Replace all uses of the checked value with the original input. - ASSERT(instr->UseCount() > 0); - instr->ReplaceAllUsesWith(HBoundsCheck::cast(instr)->index()); +// We try to "factor up" HBoundsCheck instructions towards the root of the +// dominator tree. +// For now we handle checks where the index is like "exp + int32value". +// If in the dominator tree we check "exp + v1" and later (dominated) +// "exp + v2", if v2 <= v1 we can safely remove the second check, and if +// v2 > v1 we can use v2 in the 1st check and again remove the second. +// To do so we keep a dictionary of all checks where the key if the pair +// "exp, length". +// The class BoundsCheckKey represents this key. +class BoundsCheckKey : public ZoneObject { + public: + HValue* IndexBase() const { return index_base_; } + HValue* Length() const { return length_; } + + uint32_t Hash() { + return static_cast<uint32_t>(index_base_->Hashcode() ^ length_->Hashcode()); + } + + static BoundsCheckKey* Create(Zone* zone, + HBoundsCheck* check, + int32_t* offset) { + HValue* index_base = NULL; + HConstant* constant = NULL; + bool is_sub = false; + + if (check->index()->IsAdd()) { + HAdd* index = HAdd::cast(check->index()); + if (index->left()->IsConstant()) { + constant = HConstant::cast(index->left()); + index_base = index->right(); + } else if (index->right()->IsConstant()) { + constant = HConstant::cast(index->right()); + index_base = index->left(); } - instr = instr->next(); + } else if (check->index()->IsSub()) { + HSub* index = HSub::cast(check->index()); + is_sub = true; + if (index->left()->IsConstant()) { + constant = HConstant::cast(index->left()); + index_base = index->right(); + } else if (index->right()->IsConstant()) { + constant = HConstant::cast(index->right()); + index_base = index->left(); + } + } + + if (constant != NULL && constant->HasInteger32Value()) { + *offset = is_sub ? - constant->Integer32Value() + : constant->Integer32Value(); + } else { + *offset = 0; + index_base = check->index(); } + + return new(zone) BoundsCheckKey(index_base, check->length()); } + + private: + BoundsCheckKey(HValue* index_base, HValue* length) + : index_base_(index_base), + length_(length) { } + + HValue* index_base_; + HValue* length_; +}; + + +// Data about each HBoundsCheck that can be eliminated or moved. +// It is the "value" in the dictionary indexed by "base-index, length" +// (the key is BoundsCheckKey). +// We scan the code with a dominator tree traversal. +// Traversing the dominator tree we keep a stack (implemented as a singly +// linked list) of "data" for each basic block that contains a relevant check +// with the same key (the dictionary holds the head of the list). +// We also keep all the "data" created for a given basic block in a list, and +// use it to "clean up" the dictionary when backtracking in the dominator tree +// traversal. +// Doing this each dictionary entry always directly points to the check that +// is dominating the code being examined now. +// We also track the current "offset" of the index expression and use it to +// decide if any check is already "covered" (so it can be removed) or not. +class BoundsCheckBbData: public ZoneObject { + public: + BoundsCheckKey* Key() const { return key_; } + int32_t LowerOffset() const { return lower_offset_; } + int32_t UpperOffset() const { return upper_offset_; } + HBasicBlock* BasicBlock() const { return basic_block_; } + HBoundsCheck* Check() const { return check_; } + BoundsCheckBbData* NextInBasicBlock() const { return next_in_bb_; } + BoundsCheckBbData* FatherInDominatorTree() const { return father_in_dt_; } + + bool OffsetIsCovered(int32_t offset) const { + return offset >= LowerOffset() && offset <= UpperOffset(); + } + + // This method removes new_check and modifies the current check so that it + // also "covers" what new_check covered. + // The obvious precondition is that new_check follows Check() in the + // same basic block, and that new_offset is not covered (otherwise we + // could simply remove new_check). + // As a consequence LowerOffset() or UpperOffset() change (the covered + // range grows). + // + // In the general case the check covering the current range should be like + // these two checks: + // 0 <= Key()->IndexBase() + LowerOffset() + // Key()->IndexBase() + UpperOffset() < Key()->Length() + // + // We can transform the second check like this: + // Key()->IndexBase() + LowerOffset() < + // Key()->Length() + (LowerOffset() - UpperOffset()) + // so we can handle both checks with a single unsigned comparison. + // + // The bulk of this method changes Check()->index() and Check()->length() + // replacing them with new HAdd instructions to perform the transformation + // described above. + void CoverCheck(HBoundsCheck* new_check, + int32_t new_offset) { + ASSERT(new_check->index()->representation().IsInteger32()); + + if (new_offset > upper_offset_) { + upper_offset_ = new_offset; + } else if (new_offset < lower_offset_) { + lower_offset_ = new_offset; + } else { + ASSERT(false); + } + + BuildOffsetAdd(&added_index_, + &added_index_offset_, + Key()->IndexBase(), + new_check->index()->representation(), + lower_offset_); + Check()->SetOperandAt(0, added_index_); + BuildOffsetAdd(&added_length_, + &added_length_offset_, + Key()->Length(), + new_check->length()->representation(), + lower_offset_ - upper_offset_); + Check()->SetOperandAt(1, added_length_); + + new_check->DeleteAndReplaceWith(NULL); + } + + void RemoveZeroOperations() { + RemoveZeroAdd(&added_index_, &added_index_offset_); + RemoveZeroAdd(&added_length_, &added_length_offset_); + } + + BoundsCheckBbData(BoundsCheckKey* key, + int32_t lower_offset, + int32_t upper_offset, + HBasicBlock* bb, + HBoundsCheck* check, + BoundsCheckBbData* next_in_bb, + BoundsCheckBbData* father_in_dt) + : key_(key), + lower_offset_(lower_offset), + upper_offset_(upper_offset), + basic_block_(bb), + check_(check), + added_index_offset_(NULL), + added_index_(NULL), + added_length_offset_(NULL), + added_length_(NULL), + next_in_bb_(next_in_bb), + father_in_dt_(father_in_dt) { } + + private: + BoundsCheckKey* key_; + int32_t lower_offset_; + int32_t upper_offset_; + HBasicBlock* basic_block_; + HBoundsCheck* check_; + HConstant* added_index_offset_; + HAdd* added_index_; + HConstant* added_length_offset_; + HAdd* added_length_; + BoundsCheckBbData* next_in_bb_; + BoundsCheckBbData* father_in_dt_; + + void BuildOffsetAdd(HAdd** add, + HConstant** constant, + HValue* original_value, + Representation representation, + int32_t new_offset) { + HConstant* new_constant = new(BasicBlock()->zone()) + HConstant(Handle<Object>(Smi::FromInt(new_offset)), + Representation::Integer32()); + if (*add == NULL) { + new_constant->InsertBefore(Check()); + *add = new(BasicBlock()->zone()) HAdd(NULL, + original_value, + new_constant); + (*add)->AssumeRepresentation(representation); + (*add)->InsertBefore(Check()); + } else { + new_constant->InsertBefore(*add); + (*constant)->DeleteAndReplaceWith(new_constant); + } + *constant = new_constant; + } + + void RemoveZeroAdd(HAdd** add, HConstant** constant) { + if (*add != NULL && (*constant)->Integer32Value() == 0) { + (*add)->DeleteAndReplaceWith((*add)->left()); + (*constant)->DeleteAndReplaceWith(NULL); + } + } +}; + + +static bool BoundsCheckKeyMatch(void* key1, void* key2) { + BoundsCheckKey* k1 = static_cast<BoundsCheckKey*>(key1); + BoundsCheckKey* k2 = static_cast<BoundsCheckKey*>(key2); + return k1->IndexBase() == k2->IndexBase() && k1->Length() == k2->Length(); +} + + +class BoundsCheckTable : private ZoneHashMap { + public: + BoundsCheckBbData** LookupOrInsert(BoundsCheckKey* key) { + return reinterpret_cast<BoundsCheckBbData**>( + &(Lookup(key, key->Hash(), true)->value)); + } + + void Insert(BoundsCheckKey* key, BoundsCheckBbData* data) { + Lookup(key, key->Hash(), true)->value = data; + } + + void Delete(BoundsCheckKey* key) { + Remove(key, key->Hash()); + } + + BoundsCheckTable() : ZoneHashMap(BoundsCheckKeyMatch) { } +}; + + +// Eliminates checks in bb and recursively in the dominated blocks. +// Also replace the results of check instructions with the original value, if +// the result is used. This is safe now, since we don't do code motion after +// this point. It enables better register allocation since the value produced +// by check instructions is really a copy of the original value. +void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb, + BoundsCheckTable* table) { + BoundsCheckBbData* bb_data_list = NULL; + + for (HInstruction* i = bb->first(); i != NULL; i = i->next()) { + if (!i->IsBoundsCheck()) continue; + + HBoundsCheck* check = HBoundsCheck::cast(i); + check->ReplaceAllUsesWith(check->index()); + + isolate()->counters()->array_bounds_checks_seen()->Increment(); + if (!FLAG_array_bounds_checks_elimination) continue; + + int32_t offset; + BoundsCheckKey* key = + BoundsCheckKey::Create(bb->zone(), check, &offset); + BoundsCheckBbData** data_p = table->LookupOrInsert(key); + BoundsCheckBbData* data = *data_p; + if (data == NULL) { + bb_data_list = new(zone()) BoundsCheckBbData(key, + offset, + offset, + bb, + check, + bb_data_list, + NULL); + *data_p = bb_data_list; + } else if (data->OffsetIsCovered(offset)) { + check->DeleteAndReplaceWith(NULL); + isolate()->counters()->array_bounds_checks_removed()->Increment(); + } else if (data->BasicBlock() == bb) { + data->CoverCheck(check, offset); + isolate()->counters()->array_bounds_checks_removed()->Increment(); + } else { + int32_t new_lower_offset = offset < data->LowerOffset() + ? offset + : data->LowerOffset(); + int32_t new_upper_offset = offset > data->UpperOffset() + ? offset + : data->UpperOffset(); + bb_data_list = new(bb->zone()) BoundsCheckBbData(key, + new_lower_offset, + new_upper_offset, + bb, + check, + bb_data_list, + data); + table->Insert(key, bb_data_list); + } + } + + for (int i = 0; i < bb->dominated_blocks()->length(); ++i) { + EliminateRedundantBoundsChecks(bb->dominated_blocks()->at(i), table); + } + + for (BoundsCheckBbData* data = bb_data_list; + data != NULL; + data = data->NextInBasicBlock()) { + data->RemoveZeroOperations(); + if (data->FatherInDominatorTree()) { + table->Insert(data->Key(), data->FatherInDominatorTree()); + } else { + table->Delete(data->Key()); + } + } +} + + +void HGraph::EliminateRedundantBoundsChecks() { + HPhase phase("H_Eliminate bounds checks", this); + AssertNoAllocation no_gc; + BoundsCheckTable checks_table; + EliminateRedundantBoundsChecks(entry_block(), &checks_table); } @@ -2701,7 +3192,7 @@ void HGraphBuilder::VisitBlock(Block* stmt) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); - if (stmt->block_scope() != NULL) { + if (stmt->scope() != NULL) { return Bailout("ScopedBlock"); } BreakAndContinueInfo break_info(stmt); @@ -2855,10 +3346,10 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { if (context->IsTest()) { TestContext* test = TestContext::cast(context); CHECK_ALIVE(VisitForEffect(stmt->expression())); - current_block()->Goto(test->if_true(), function_state()->drop_extra()); + current_block()->Goto(test->if_true(), function_state()); } else if (context->IsEffect()) { CHECK_ALIVE(VisitForEffect(stmt->expression())); - current_block()->Goto(function_return(), function_state()->drop_extra()); + current_block()->Goto(function_return(), function_state()); } else { ASSERT(context->IsValue()); CHECK_ALIVE(VisitForValue(stmt->expression())); @@ -2875,10 +3366,10 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { current_block()->Finish(typecheck); if_spec_object->AddLeaveInlined(return_value, function_return(), - function_state()->drop_extra()); + function_state()); not_spec_object->AddLeaveInlined(receiver, function_return(), - function_state()->drop_extra()); + function_state()); } } else { // Return from an inlined function, visit the subexpression in the @@ -2890,14 +3381,14 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { test->if_false()); } else if (context->IsEffect()) { CHECK_ALIVE(VisitForEffect(stmt->expression())); - current_block()->Goto(function_return(), function_state()->drop_extra()); + current_block()->Goto(function_return(), function_state()); } else { ASSERT(context->IsValue()); CHECK_ALIVE(VisitForValue(stmt->expression())); HValue* return_value = Pop(); current_block()->AddLeaveInlined(return_value, function_return(), - function_state()->drop_extra()); + function_state()); } } set_current_block(NULL); @@ -3682,10 +4173,11 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate, if (boilerplate->HasFastDoubleElements()) { *total_size += FixedDoubleArray::SizeFor(elements->length()); } else if (boilerplate->HasFastElements()) { + Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); int length = elements->length(); for (int i = 0; i < length; i++) { if ((*max_properties)-- == 0) return false; - Handle<Object> value = JSObject::GetElement(boilerplate, i); + Handle<Object> value(fast_elements->get(i)); if (value->IsJSObject()) { Handle<JSObject> value_object = Handle<JSObject>::cast(value); if (!IsFastLiteral(value_object, @@ -3914,21 +4406,22 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { } -// Sets the lookup result and returns true if the store can be inlined. -static bool ComputeStoredField(Handle<Map> type, - Handle<String> name, - LookupResult* lookup) { +// Sets the lookup result and returns true if the load/store can be inlined. +static bool ComputeLoadStoreField(Handle<Map> type, + Handle<String> name, + LookupResult* lookup, + bool is_store) { type->LookupInDescriptors(NULL, *name, lookup); if (!lookup->IsFound()) return false; if (lookup->type() == FIELD) return true; - return (lookup->type() == MAP_TRANSITION) && + return is_store && (lookup->type() == MAP_TRANSITION) && (type->unused_property_fields() > 0); } -static int ComputeStoredFieldIndex(Handle<Map> type, - Handle<String> name, - LookupResult* lookup) { +static int ComputeLoadStoreFieldIndex(Handle<Map> type, + Handle<String> name, + LookupResult* lookup) { ASSERT(lookup->type() == FIELD || lookup->type() == MAP_TRANSITION); if (lookup->type() == FIELD) { return lookup->GetLocalFieldIndexFromMap(*type); @@ -3947,11 +4440,10 @@ HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object, bool smi_and_map_check) { if (smi_and_map_check) { AddInstruction(new(zone()) HCheckNonSmi(object)); - AddInstruction(new(zone()) HCheckMap(object, type, NULL, - ALLOW_ELEMENT_TRANSITION_MAPS)); + AddInstruction(HCheckMaps::NewWithTransitions(object, type)); } - int index = ComputeStoredFieldIndex(type, name, lookup); + int index = ComputeLoadStoreFieldIndex(type, name, lookup); bool is_in_object = index < 0; int offset = index * kPointerSize; if (index < 0) { @@ -3997,7 +4489,7 @@ HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, LookupResult lookup(isolate()); Handle<Map> type = prop->GetReceiverType(); bool is_monomorphic = prop->IsMonomorphic() && - ComputeStoredField(type, name, &lookup); + ComputeLoadStoreField(type, name, &lookup, true); return is_monomorphic ? BuildStoreNamedField(object, name, value, type, &lookup, @@ -4019,7 +4511,7 @@ HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, LookupResult lookup(isolate()); SmallMapList* types = expr->GetReceiverTypes(); bool is_monomorphic = expr->IsMonomorphic() && - ComputeStoredField(types->first(), name, &lookup); + ComputeLoadStoreField(types->first(), name, &lookup, true); return is_monomorphic ? BuildStoreNamedField(object, name, value, types->first(), &lookup, @@ -4028,6 +4520,59 @@ HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, } +void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, + HValue* object, + SmallMapList* types, + Handle<String> name) { + int count = 0; + int previous_field_offset = 0; + bool previous_field_is_in_object = false; + bool is_monomorphic_field = true; + Handle<Map> map; + LookupResult lookup(isolate()); + for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { + map = types->at(i); + if (ComputeLoadStoreField(map, name, &lookup, false)) { + int index = ComputeLoadStoreFieldIndex(map, name, &lookup); + bool is_in_object = index < 0; + int offset = index * kPointerSize; + if (index < 0) { + // Negative property indices are in-object properties, indexed + // from the end of the fixed part of the object. + offset += map->instance_size(); + } else { + offset += FixedArray::kHeaderSize; + } + if (count == 0) { + previous_field_offset = offset; + previous_field_is_in_object = is_in_object; + } else if (is_monomorphic_field) { + is_monomorphic_field = (offset == previous_field_offset) && + (is_in_object == previous_field_is_in_object); + } + ++count; + } + } + + // Use monomorphic load if property lookup results in the same field index + // for all maps. Requires special map check on the set of all handled maps. + HInstruction* instr; + if (count == types->length() && is_monomorphic_field) { + AddInstruction(new(zone()) HCheckMaps(object, types)); + instr = BuildLoadNamedField(object, expr, map, &lookup, false); + } else { + HValue* context = environment()->LookupContext(); + instr = new(zone()) HLoadNamedFieldPolymorphic(context, + object, + types, + name); + } + + instr->set_position(expr->position()); + return ast_context()->ReturnInstruction(instr, expr->id()); +} + + void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, HValue* object, HValue* value, @@ -4041,7 +4586,7 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { Handle<Map> map = types->at(i); LookupResult lookup(isolate()); - if (ComputeStoredField(map, name, &lookup)) { + if (ComputeLoadStoreField(map, name, &lookup, true)) { if (count == 0) { AddInstruction(new(zone()) HCheckNonSmi(object)); // Only needed once. join = graph()->CreateBasicBlock(); @@ -4512,8 +5057,7 @@ HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, bool smi_and_map_check) { if (smi_and_map_check) { AddInstruction(new(zone()) HCheckNonSmi(object)); - AddInstruction(new(zone()) HCheckMap(object, type, NULL, - ALLOW_ELEMENT_TRANSITION_MAPS)); + AddInstruction(HCheckMaps::NewWithTransitions(object, type)); } int index = lookup->GetLocalFieldIndexFromMap(*type); @@ -4557,8 +5101,7 @@ HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, true); } else if (lookup.IsFound() && lookup.type() == CONSTANT_FUNCTION) { AddInstruction(new(zone()) HCheckNonSmi(obj)); - AddInstruction(new(zone()) HCheckMap(obj, map, NULL, - ALLOW_ELEMENT_TRANSITION_MAPS)); + AddInstruction(HCheckMaps::NewWithTransitions(obj, map)); Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); return new(zone()) HConstant(function, Representation::Tagged()); } else { @@ -4660,12 +5203,12 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, HValue* val, Handle<Map> map, bool is_store) { - HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); + HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMaps(object, map)); bool fast_smi_only_elements = map->has_fast_smi_only_elements(); bool fast_elements = map->has_fast_elements(); HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); if (is_store && (fast_elements || fast_smi_only_elements)) { - AddInstruction(new(zone()) HCheckMap( + AddInstruction(new(zone()) HCheckMaps( elements, isolate()->factory()->fixed_array_map())); } HInstruction* length = NULL; @@ -4815,7 +5358,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, elements_kind == FAST_ELEMENTS || elements_kind == FAST_DOUBLE_ELEMENTS) { if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) { - AddInstruction(new(zone()) HCheckMap( + AddInstruction(new(zone()) HCheckMaps( elements, isolate()->factory()->fixed_array_map(), elements_kind_branch)); } @@ -4933,6 +5476,34 @@ HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, function_strict_mode_flag()); } + +void HGraphBuilder::EnsureArgumentsArePushedForAccess() { + // Outermost function already has arguments on the stack. + if (function_state()->outer() == NULL) return; + + if (function_state()->arguments_pushed()) return; + + // Push arguments when entering inlined function. + HEnterInlined* entry = function_state()->entry(); + + ZoneList<HValue*>* arguments_values = entry->arguments_values(); + + HInstruction* insert_after = entry; + for (int i = 0; i < arguments_values->length(); i++) { + HValue* argument = arguments_values->at(i); + HInstruction* push_argument = new(zone()) HPushArgument(argument); + push_argument->InsertAfter(insert_after); + insert_after = push_argument; + } + + HArgumentsElements* arguments_elements = + new(zone()) HArgumentsElements(true); + arguments_elements->ClearFlag(HValue::kUseGVN); + arguments_elements->InsertAfter(insert_after); + function_state()->set_arguments_elements(arguments_elements); +} + + bool HGraphBuilder::TryArgumentsAccess(Property* expr) { VariableProxy* proxy = expr->obj()->AsVariableProxy(); if (proxy == NULL) return false; @@ -4941,31 +5512,51 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) { return false; } - // Our implementation of arguments (based on this stack frame or an - // adapter below it) does not work for inlined functions. - if (function_state()->outer() != NULL) { - Bailout("arguments access in inlined function"); - return true; - } - HInstruction* result = NULL; if (expr->key()->IsPropertyName()) { Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); if (!name->IsEqualTo(CStrVector("length"))) return false; - HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); - result = new(zone()) HArgumentsLength(elements); + + if (function_state()->outer() == NULL) { + HInstruction* elements = AddInstruction( + new(zone()) HArgumentsElements(false)); + result = new(zone()) HArgumentsLength(elements); + } else { + // Number of arguments without receiver. + int argument_count = environment()-> + arguments_environment()->parameter_count() - 1; + result = new(zone()) HConstant( + Handle<Object>(Smi::FromInt(argument_count)), + Representation::Integer32()); + } } else { Push(graph()->GetArgumentsObject()); VisitForValue(expr->key()); if (HasStackOverflow() || current_block() == NULL) return true; HValue* key = Pop(); Drop(1); // Arguments object. - HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); - HInstruction* length = AddInstruction( - new(zone()) HArgumentsLength(elements)); - HInstruction* checked_key = - AddInstruction(new(zone()) HBoundsCheck(key, length)); - result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); + if (function_state()->outer() == NULL) { + HInstruction* elements = AddInstruction( + new(zone()) HArgumentsElements(false)); + HInstruction* length = AddInstruction( + new(zone()) HArgumentsLength(elements)); + HInstruction* checked_key = + AddInstruction(new(zone()) HBoundsCheck(key, length)); + result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); + } else { + EnsureArgumentsArePushedForAccess(); + + // Number of arguments without receiver. + HInstruction* elements = function_state()->arguments_elements(); + int argument_count = environment()-> + arguments_environment()->parameter_count() - 1; + HInstruction* length = AddInstruction(new(zone()) HConstant( + Handle<Object>(Smi::FromInt(argument_count)), + Representation::Integer32())); + HInstruction* checked_key = + AddInstruction(new(zone()) HBoundsCheck(key, length)); + result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); + } } ast_context()->ReturnInstruction(result, expr->id()); return true; @@ -5019,8 +5610,8 @@ void HGraphBuilder::VisitProperty(Property* expr) { instr = BuildLoadNamed(obj, expr, types->first(), name); } else if (types != NULL && types->length() > 1) { AddInstruction(new(zone()) HCheckNonSmi(obj)); - HValue* context = environment()->LookupContext(); - instr = new(zone()) HLoadNamedFieldPolymorphic(context, obj, types, name); + HandlePolymorphicLoadNamedField(expr, obj, types, name); + return; } else { instr = BuildLoadNamedGeneric(obj, expr); } @@ -5061,8 +5652,7 @@ void HGraphBuilder::AddCheckConstantFunction(Call* expr, // its prototypes. if (smi_and_map_check) { AddInstruction(new(zone()) HCheckNonSmi(receiver)); - AddInstruction(new(zone()) HCheckMap(receiver, receiver_map, NULL, - ALLOW_ELEMENT_TRANSITION_MAPS)); + AddInstruction(HCheckMaps::NewWithTransitions(receiver, receiver_map)); } if (!expr->holder().is_null()) { AddInstruction(new(zone()) HCheckPrototypeMaps( @@ -5072,6 +5662,39 @@ void HGraphBuilder::AddCheckConstantFunction(Call* expr, } +class FunctionSorter { + public: + FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } + FunctionSorter(int index, int ticks, int ast_length, int src_length) + : index_(index), + ticks_(ticks), + ast_length_(ast_length), + src_length_(src_length) { } + + int index() const { return index_; } + int ticks() const { return ticks_; } + int ast_length() const { return ast_length_; } + int src_length() const { return src_length_; } + + private: + int index_; + int ticks_; + int ast_length_; + int src_length_; +}; + + +static int CompareHotness(void const* a, void const* b) { + FunctionSorter const* function1 = reinterpret_cast<FunctionSorter const*>(a); + FunctionSorter const* function2 = reinterpret_cast<FunctionSorter const*>(b); + int diff = function1->ticks() - function2->ticks(); + if (diff != 0) return -diff; + diff = function1->ast_length() - function2->ast_length(); + if (diff != 0) return diff; + return function1->src_length() - function2->src_length(); +} + + void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, HValue* receiver, SmallMapList* types, @@ -5080,51 +5703,73 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, // maps are identical. In that case we can avoid repeatedly generating the // same prototype map checks. int argument_count = expr->arguments()->length() + 1; // Includes receiver. - int count = 0; HBasicBlock* join = NULL; - for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) { + FunctionSorter order[kMaxCallPolymorphism]; + int ordered_functions = 0; + for (int i = 0; + i < types->length() && ordered_functions < kMaxCallPolymorphism; + ++i) { Handle<Map> map = types->at(i); if (expr->ComputeTarget(map, name)) { - if (count == 0) { - // Only needed once. - AddInstruction(new(zone()) HCheckNonSmi(receiver)); - join = graph()->CreateBasicBlock(); - } - ++count; - HBasicBlock* if_true = graph()->CreateBasicBlock(); - HBasicBlock* if_false = graph()->CreateBasicBlock(); - HCompareMap* compare = - new(zone()) HCompareMap(receiver, map, if_true, if_false); - current_block()->Finish(compare); + order[ordered_functions++] = + FunctionSorter(i, + expr->target()->shared()->profiler_ticks(), + InliningAstSize(expr->target()), + expr->target()->shared()->SourceSize()); + } + } - set_current_block(if_true); - AddCheckConstantFunction(expr, receiver, map, false); - if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { - PrintF("Trying to inline the polymorphic call to %s\n", - *name->ToCString()); - } - if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { - // Trying to inline will signal that we should bailout from the - // entire compilation by setting stack overflow on the visitor. - if (HasStackOverflow()) return; - } else { - HCallConstantFunction* call = - new(zone()) HCallConstantFunction(expr->target(), argument_count); - call->set_position(expr->position()); - PreProcessCall(call); - AddInstruction(call); - if (!ast_context()->IsEffect()) Push(call); - } + qsort(reinterpret_cast<void*>(&order[0]), + ordered_functions, + sizeof(order[0]), + &CompareHotness); - if (current_block() != NULL) current_block()->Goto(join); - set_current_block(if_false); + for (int fn = 0; fn < ordered_functions; ++fn) { + int i = order[fn].index(); + Handle<Map> map = types->at(i); + if (fn == 0) { + // Only needed once. + AddInstruction(new(zone()) HCheckNonSmi(receiver)); + join = graph()->CreateBasicBlock(); + } + HBasicBlock* if_true = graph()->CreateBasicBlock(); + HBasicBlock* if_false = graph()->CreateBasicBlock(); + HCompareMap* compare = + new(zone()) HCompareMap(receiver, map, if_true, if_false); + current_block()->Finish(compare); + + set_current_block(if_true); + expr->ComputeTarget(map, name); + AddCheckConstantFunction(expr, receiver, map, false); + if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { + Handle<JSFunction> caller = info()->closure(); + SmartArrayPointer<char> caller_name = + caller->shared()->DebugName()->ToCString(); + PrintF("Trying to inline the polymorphic call to %s from %s\n", + *name->ToCString(), + *caller_name); + } + if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { + // Trying to inline will signal that we should bailout from the + // entire compilation by setting stack overflow on the visitor. + if (HasStackOverflow()) return; + } else { + HCallConstantFunction* call = + new(zone()) HCallConstantFunction(expr->target(), argument_count); + call->set_position(expr->position()); + PreProcessCall(call); + AddInstruction(call); + if (!ast_context()->IsEffect()) Push(call); } + + if (current_block() != NULL) current_block()->Goto(join); + set_current_block(if_false); } // Finish up. Unconditionally deoptimize if we've handled all the maps we // know about and do not want to handle ones we've never seen. Otherwise // use a generic IC. - if (count == types->length() && FLAG_deoptimize_uncommon_cases) { + if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); } else { HValue* context = environment()->LookupContext(); @@ -5173,14 +5818,11 @@ void HGraphBuilder::TraceInline(Handle<JSFunction> target, } -bool HGraphBuilder::TryInline(CallKind call_kind, - Handle<JSFunction> target, - ZoneList<Expression*>* arguments, - HValue* receiver, - int ast_id, - int return_id, - ReturnHandlingFlag return_handling) { - if (!FLAG_use_inlining) return false; +static const int kNotInlinable = 1000000000; + + +int HGraphBuilder::InliningAstSize(Handle<JSFunction> target) { + if (!FLAG_use_inlining) return kNotInlinable; // Precondition: call is monomorphic and we have found a target with the // appropriate arity. @@ -5189,29 +5831,46 @@ bool HGraphBuilder::TryInline(CallKind call_kind, // Do a quick check on source code length to avoid parsing large // inlining candidates. - if ((FLAG_limit_inlining && target_shared->SourceSize() > kMaxSourceSize) - || target_shared->SourceSize() > kUnlimitedMaxSourceSize) { + if (target_shared->SourceSize() > + Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { TraceInline(target, caller, "target text too big"); - return false; + return kNotInlinable; } // Target must be inlineable. if (!target->IsInlineable()) { TraceInline(target, caller, "target not inlineable"); - return false; + return kNotInlinable; } if (target_shared->dont_inline() || target_shared->dont_optimize()) { TraceInline(target, caller, "target contains unsupported syntax [early]"); - return false; + return kNotInlinable; } int nodes_added = target_shared->ast_node_count(); - if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) || - nodes_added > kUnlimitedMaxInlinedSize) { + return nodes_added; +} + + +bool HGraphBuilder::TryInline(CallKind call_kind, + Handle<JSFunction> target, + ZoneList<Expression*>* arguments, + HValue* receiver, + int ast_id, + int return_id, + ReturnHandlingFlag return_handling) { + int nodes_added = InliningAstSize(target); + if (nodes_added == kNotInlinable) return false; + + Handle<JSFunction> caller = info()->closure(); + + if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { TraceInline(target, caller, "target AST is too large [early]"); return false; } + Handle<SharedFunctionInfo> target_shared(target->shared()); + #if !defined(V8_TARGET_ARCH_IA32) // Target must be able to use caller's context. CompilationInfo* outer_info = info(); @@ -5249,8 +5908,8 @@ bool HGraphBuilder::TryInline(CallKind call_kind, } // We don't want to add more than a certain number of nodes from inlining. - if ((FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) || - inlined_count_ > kUnlimitedMaxInlinedNodes) { + if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative, + kUnlimitedMaxInlinedNodesCumulative)) { TraceInline(target, caller, "cumulative AST node limit reached"); return false; } @@ -5277,8 +5936,7 @@ bool HGraphBuilder::TryInline(CallKind call_kind, // The following conditions must be checked again after re-parsing, because // earlier the information might not have been complete due to lazy parsing. nodes_added = function->ast_node_count(); - if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) || - nodes_added > kUnlimitedMaxInlinedSize) { + if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { TraceInline(target, caller, "target AST is too large [late]"); return false; } @@ -5373,19 +6031,42 @@ bool HGraphBuilder::TryInline(CallKind call_kind, AddInstruction(context); inner_env->BindContext(context); #endif + AddSimulate(return_id); current_block()->UpdateEnvironment(inner_env); - AddInstruction(new(zone()) HEnterInlined(target, - arguments->length(), - function, - call_kind, - function_state()->is_construct())); + + ZoneList<HValue*>* arguments_values = NULL; + + // If the function uses arguments copy current arguments values + // to use them for materialization. + if (function->scope()->arguments() != NULL) { + HEnvironment* arguments_env = inner_env->arguments_environment(); + int arguments_count = arguments_env->parameter_count(); + arguments_values = new(zone()) ZoneList<HValue*>(arguments_count); + for (int i = 0; i < arguments_count; i++) { + arguments_values->Add(arguments_env->Lookup(i)); + } + } + + HEnterInlined* enter_inlined = + new(zone()) HEnterInlined(target, + arguments->length(), + function, + call_kind, + function_state()->is_construct(), + function->scope()->arguments(), + arguments_values); + function_state()->set_entry(enter_inlined); + AddInstruction(enter_inlined); + // If the function uses arguments object create and bind one. if (function->scope()->arguments() != NULL) { ASSERT(function->scope()->arguments()->IsStackAllocated()); - environment()->Bind(function->scope()->arguments(), - graph()->GetArgumentsObject()); + inner_env->Bind(function->scope()->arguments(), + graph()->GetArgumentsObject()); } + + VisitDeclarations(target_info.scope()->declarations()); VisitStatements(function->body()); if (HasStackOverflow()) { @@ -5414,17 +6095,17 @@ bool HGraphBuilder::TryInline(CallKind call_kind, : undefined; current_block()->AddLeaveInlined(return_value, function_return(), - function_state()->drop_extra()); + function_state()); } else if (call_context()->IsEffect()) { ASSERT(function_return() != NULL); - current_block()->Goto(function_return(), function_state()->drop_extra()); + current_block()->Goto(function_return(), function_state()); } else { ASSERT(call_context()->IsTest()); ASSERT(inlined_test_context() != NULL); HBasicBlock* target = function_state()->is_construct() ? inlined_test_context()->if_true() : inlined_test_context()->if_false(); - current_block()->Goto(target, function_state()->drop_extra()); + current_block()->Goto(target, function_state()); } } @@ -5442,12 +6123,12 @@ bool HGraphBuilder::TryInline(CallKind call_kind, if (if_true->HasPredecessor()) { if_true->SetJoinId(ast_id); HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); - if_true->Goto(true_target, function_state()->drop_extra()); + if_true->Goto(true_target, function_state()); } if (if_false->HasPredecessor()) { if_false->SetJoinId(ast_id); HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); - if_false->Goto(false_target, function_state()->drop_extra()); + if_false->Goto(false_target, function_state()); } set_current_block(NULL); return true; @@ -5683,7 +6364,27 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, set_current_block(return_left); Push(left); set_current_block(return_right); - Push(right); + // The branch above always returns the right operand if either of + // them is NaN, but the spec requires that max/min(NaN, X) = NaN. + // We add another branch that checks if the left operand is NaN or not. + if (left_operand->representation().IsDouble()) { + // If left_operand != left_operand then it is NaN. + HCompareIDAndBranch* compare_nan = new(zone()) HCompareIDAndBranch( + left_operand, left_operand, Token::EQ); + compare_nan->SetInputRepresentation(left_operand->representation()); + HBasicBlock* left_is_number = graph()->CreateBasicBlock(); + HBasicBlock* left_is_nan = graph()->CreateBasicBlock(); + compare_nan->SetSuccessorAt(0, left_is_number); + compare_nan->SetSuccessorAt(1, left_is_nan); + current_block()->Finish(compare_nan); + set_current_block(left_is_nan); + Push(left); + set_current_block(left_is_number); + Push(right); + return_right = CreateJoin(left_is_number, left_is_nan, expr->id()); + } else { + Push(right); + } HBasicBlock* join = CreateJoin(return_left, return_right, expr->id()); set_current_block(join); @@ -5736,7 +6437,8 @@ bool HGraphBuilder::TryCallApply(Call* expr) { HValue* receiver = Pop(); if (function_state()->outer() == NULL) { - HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); + HInstruction* elements = AddInstruction( + new(zone()) HArgumentsElements(false)); HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); HValue* wrapped_receiver = @@ -5955,9 +6657,11 @@ void HGraphBuilder::VisitCall(Call* expr) { if (TryInlineCall(expr, true)) { // Drop function from environment. return; } else { - call = PreProcessCall(new(zone()) HInvokeFunction(context, - function, - argument_count)); + call = PreProcessCall( + new(zone()) HInvokeFunction(context, + function, + expr->target(), + argument_count)); Drop(1); // The function. } @@ -5985,7 +6689,8 @@ void HGraphBuilder::VisitCall(Call* expr) { // Checks whether allocation using the given constructor can be inlined. static bool IsAllocationInlineable(Handle<JSFunction> constructor) { return constructor->has_initial_map() && - constructor->initial_map()->instance_type() == JS_OBJECT_TYPE; + constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && + constructor->initial_map()->instance_size() < HAllocateObject::kMaxSize; } @@ -6877,11 +7582,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { Handle<Map> map = oracle()->GetCompareMap(expr); if (!map.is_null()) { AddInstruction(new(zone()) HCheckNonSmi(left)); - AddInstruction(new(zone()) HCheckMap(left, map, NULL, - ALLOW_ELEMENT_TRANSITION_MAPS)); + AddInstruction(HCheckMaps::NewWithTransitions(left, map)); AddInstruction(new(zone()) HCheckNonSmi(right)); - AddInstruction(new(zone()) HCheckMap(right, map, NULL, - ALLOW_ELEMENT_TRANSITION_MAPS)); + AddInstruction(HCheckMaps::NewWithTransitions(right, map)); HCompareObjectEqAndBranch* result = new(zone()) HCompareObjectEqAndBranch(left, right); result->set_position(expr->position()); @@ -6953,90 +7656,50 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { void HGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) { - int length = declarations->length(); - int global_count = 0; - for (int i = 0; i < declarations->length(); i++) { - Declaration* decl = declarations->at(i); - FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration(); - HandleDeclaration(decl->proxy(), - decl->mode(), - fun_decl != NULL ? fun_decl->fun() : NULL, - &global_count); - } - - // Batch declare global functions and variables. - if (global_count > 0) { + ASSERT(globals_.is_empty()); + AstVisitor::VisitDeclarations(declarations); + if (!globals_.is_empty()) { Handle<FixedArray> array = - isolate()->factory()->NewFixedArray(2 * global_count, TENURED); - for (int j = 0, i = 0; i < length; i++) { - Declaration* decl = declarations->at(i); - Variable* var = decl->proxy()->var(); - - if (var->IsUnallocated()) { - array->set(j++, *(var->name())); - FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration(); - if (fun_decl == NULL) { - if (var->binding_needs_init()) { - // In case this binding needs initialization use the hole. - array->set_the_hole(j++); - } else { - array->set_undefined(j++); - } - } else { - Handle<SharedFunctionInfo> function = - Compiler::BuildFunctionInfo(fun_decl->fun(), info()->script()); - // Check for stack-overflow exception. - if (function.is_null()) { - SetStackOverflow(); - return; - } - array->set(j++, *function); - } - } - } + isolate()->factory()->NewFixedArray(globals_.length(), TENURED); + for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i)); int flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) | DeclareGlobalsNativeFlag::encode(info()->is_native()) | DeclareGlobalsLanguageMode::encode(info()->language_mode()); - HInstruction* result = - new(zone()) HDeclareGlobals(environment()->LookupContext(), - array, - flags); + HInstruction* result = new(zone()) HDeclareGlobals( + environment()->LookupContext(), array, flags); AddInstruction(result); + globals_.Clear(); } } -void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function, - int* global_count) { - Variable* var = proxy->var(); - bool binding_needs_init = - (mode == CONST || mode == CONST_HARMONY || mode == LET); - switch (var->location()) { +void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + VariableMode mode = declaration->mode(); + Variable* variable = proxy->var(); + bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; + switch (variable->location()) { case Variable::UNALLOCATED: - ++(*global_count); + globals_.Add(variable->name()); + globals_.Add(variable->binding_needs_init() + ? isolate()->factory()->the_hole_value() + : isolate()->factory()->undefined_value()); return; case Variable::PARAMETER: case Variable::LOCAL: + if (hole_init) { + HValue* value = graph()->GetConstantHole(); + environment()->Bind(variable, value); + } + break; case Variable::CONTEXT: - if (binding_needs_init || function != NULL) { - HValue* value = NULL; - if (function != NULL) { - CHECK_ALIVE(VisitForValue(function)); - value = Pop(); - } else { - value = graph()->GetConstantHole(); - } - if (var->IsContextSlot()) { - HValue* context = environment()->LookupContext(); - HStoreContextSlot* store = new HStoreContextSlot( - context, var->index(), HStoreContextSlot::kNoCheck, value); - AddInstruction(store); - if (store->HasObservableSideEffects()) AddSimulate(proxy->id()); - } else { - environment()->Bind(var, value); - } + if (hole_init) { + HValue* value = graph()->GetConstantHole(); + HValue* context = environment()->LookupContext(); + HStoreContextSlot* store = new HStoreContextSlot( + context, variable->index(), HStoreContextSlot::kNoCheck, value); + AddInstruction(store); + if (store->HasObservableSideEffects()) AddSimulate(proxy->id()); } break; case Variable::LOOKUP: @@ -7045,48 +7708,74 @@ void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, } -void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { - UNREACHABLE(); -} - - -void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) { - UNREACHABLE(); +void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: { + globals_.Add(variable->name()); + Handle<SharedFunctionInfo> function = + Compiler::BuildFunctionInfo(declaration->fun(), info()->script()); + // Check for stack-overflow exception. + if (function.is_null()) return SetStackOverflow(); + globals_.Add(function); + return; + } + case Variable::PARAMETER: + case Variable::LOCAL: { + CHECK_ALIVE(VisitForValue(declaration->fun())); + HValue* value = Pop(); + environment()->Bind(variable, value); + break; + } + case Variable::CONTEXT: { + CHECK_ALIVE(VisitForValue(declaration->fun())); + HValue* value = Pop(); + HValue* context = environment()->LookupContext(); + HStoreContextSlot* store = new HStoreContextSlot( + context, variable->index(), HStoreContextSlot::kNoCheck, value); + AddInstruction(store); + if (store->HasObservableSideEffects()) AddSimulate(proxy->id()); + break; + } + case Variable::LOOKUP: + return Bailout("unsupported lookup slot in declaration"); + } } -void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) { +void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* declaration) { UNREACHABLE(); } -void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) { +void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* declaration) { UNREACHABLE(); } -void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) { +void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* declaration) { UNREACHABLE(); } void HGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) { - // TODO(rossberg) + UNREACHABLE(); } void HGraphBuilder::VisitModuleVariable(ModuleVariable* module) { - // TODO(rossberg) + UNREACHABLE(); } void HGraphBuilder::VisitModulePath(ModulePath* module) { - // TODO(rossberg) + UNREACHABLE(); } void HGraphBuilder::VisitModuleUrl(ModuleUrl* module) { - // TODO(rossberg) + UNREACHABLE(); } @@ -7207,7 +7896,8 @@ void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { // function is blacklisted by AstNode::IsInlineable. ASSERT(function_state()->outer() == NULL); ASSERT(call->arguments()->length() == 0); - HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); + HInstruction* elements = AddInstruction( + new(zone()) HArgumentsElements(false)); HArgumentsLength* result = new(zone()) HArgumentsLength(elements); return ast_context()->ReturnInstruction(result, call->id()); } @@ -7221,7 +7911,8 @@ void HGraphBuilder::GenerateArguments(CallRuntime* call) { ASSERT(call->arguments()->length() == 1); CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); HValue* index = Pop(); - HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); + HInstruction* elements = AddInstruction( + new(zone()) HArgumentsElements(false)); HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); HAccessArgumentsAt* result = new(zone()) HAccessArgumentsAt(elements, length, index); diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index e2779bb226..909d07b80e 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -42,6 +42,7 @@ namespace internal { // Forward declarations. class BitVector; +class FunctionState; class HEnvironment; class HGraph; class HLoopInformation; @@ -121,7 +122,7 @@ class HBasicBlock: public ZoneObject { void Finish(HControlInstruction* last); void FinishExit(HControlInstruction* instruction); - void Goto(HBasicBlock* block, bool drop_extra = false); + void Goto(HBasicBlock* block, FunctionState* state = NULL); int PredecessorIndexOf(HBasicBlock* predecessor) const; void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); } @@ -136,7 +137,7 @@ class HBasicBlock: public ZoneObject { // instruction and updating the bailout environment. void AddLeaveInlined(HValue* return_value, HBasicBlock* target, - bool drop_extra = false); + FunctionState* state = NULL); // If a target block is tagged as an inline function return, all // predecessors should contain the inlined exit sequence: @@ -240,7 +241,7 @@ class HLoopInformation: public ZoneObject { HStackCheck* stack_check_; }; - +class BoundsCheckTable; class HGraph: public ZoneObject { public: explicit HGraph(CompilationInfo* info); @@ -265,6 +266,7 @@ class HGraph: public ZoneObject { void OrderBlocks(); void AssignDominators(); void ReplaceCheckedValues(); + void EliminateRedundantBoundsChecks(); void PropagateDeoptimizingMark(); // Returns false if there are phi-uses of the arguments-object @@ -357,6 +359,7 @@ class HGraph: public ZoneObject { void InferTypes(ZoneList<HValue*>* worklist); void InitializeInferredTypes(int from_inclusive, int to_inclusive); void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor); + void EliminateRedundantBoundsChecks(HBasicBlock* bb, BoundsCheckTable* table); Isolate* isolate_; int next_block_id_; @@ -715,6 +718,16 @@ class FunctionState { FunctionState* outer() { return outer_; } + HEnterInlined* entry() { return entry_; } + void set_entry(HEnterInlined* entry) { entry_ = entry; } + + HArgumentsElements* arguments_elements() { return arguments_elements_; } + void set_arguments_elements(HArgumentsElements* arguments_elements) { + arguments_elements_ = arguments_elements; + } + + bool arguments_pushed() { return arguments_elements() != NULL; } + private: HGraphBuilder* owner_; @@ -741,6 +754,12 @@ class FunctionState { // return blocks. NULL in all other cases. TestContext* test_context_; + // When inlining HEnterInlined instruction corresponding to the function + // entry. + HEnterInlined* entry_; + + HArgumentsElements* arguments_elements_; + FunctionState* outer_; }; @@ -851,15 +870,11 @@ class HGraphBuilder: public AstVisitor { static const int kMaxLoadPolymorphism = 4; static const int kMaxStorePolymorphism = 4; - static const int kMaxInlinedNodes = 196; - static const int kMaxInlinedSize = 196; - static const int kMaxSourceSize = 600; - // Even in the 'unlimited' case we have to have some limit in order not to // overflow the stack. - static const int kUnlimitedMaxInlinedNodes = 1000; - static const int kUnlimitedMaxInlinedSize = 1000; - static const int kUnlimitedMaxSourceSize = 600; + static const int kUnlimitedMaxInlinedSourceSize = 100000; + static const int kUnlimitedMaxInlinedNodes = 10000; + static const int kUnlimitedMaxInlinedNodesCumulative = 10000; // Simple accessors. void set_function_state(FunctionState* state) { function_state_ = state; } @@ -896,11 +911,6 @@ class HGraphBuilder: public AstVisitor { INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) #undef INLINE_FUNCTION_GENERATOR_DECLARATION - void HandleDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function, - int* global_count); - void VisitDelete(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr); void VisitTypeof(UnaryOperation* expr); @@ -994,11 +1004,13 @@ class HGraphBuilder: public AstVisitor { LookupResult* lookup, bool is_store); + void EnsureArgumentsArePushedForAccess(); bool TryArgumentsAccess(Property* expr); // Try to optimize fun.apply(receiver, arguments) pattern. bool TryCallApply(Call* expr); + int InliningAstSize(Handle<JSFunction> target); bool TryInline(CallKind call_kind, Handle<JSFunction> target, ZoneList<Expression*>* arguments, @@ -1029,6 +1041,10 @@ class HGraphBuilder: public AstVisitor { void HandlePropertyAssignment(Assignment* expr); void HandleCompoundAssignment(Assignment* expr); + void HandlePolymorphicLoadNamedField(Property* expr, + HValue* object, + SmallMapList* types, + Handle<String> name); void HandlePolymorphicStoreNamedField(Assignment* expr, HValue* object, HValue* value, @@ -1145,6 +1161,7 @@ class HGraphBuilder: public AstVisitor { HBasicBlock* current_block_; int inlined_count_; + ZoneList<Handle<Object> > globals_; Zone* zone_; @@ -1219,6 +1236,30 @@ class HValueMap: public ZoneObject { }; +class HSideEffectMap BASE_EMBEDDED { + public: + HSideEffectMap(); + explicit HSideEffectMap(HSideEffectMap* other); + + void Kill(GVNFlagSet flags); + + void Store(GVNFlagSet flags, HInstruction* instr); + + bool IsEmpty() const { return count_ == 0; } + + inline HInstruction* operator[](int i) const { + ASSERT(0 <= i); + ASSERT(i < kNumberOfTrackedSideEffects); + return data_[i]; + } + inline HInstruction* at(int i) const { return operator[](i); } + + private: + int count_; + HInstruction* data_[kNumberOfTrackedSideEffects]; +}; + + class HStatistics: public Malloced { public: void Initialize(CompilationInfo* info); diff --git a/deps/v8/src/ia32/assembler-ia32.h b/deps/v8/src/ia32/assembler-ia32.h index 929b485ebf..4ead80b0ec 100644 --- a/deps/v8/src/ia32/assembler-ia32.h +++ b/deps/v8/src/ia32/assembler-ia32.h @@ -640,6 +640,9 @@ class Assembler : public AssemblerBase { static const byte kJccShortPrefix = 0x70; static const byte kJncShortOpcode = kJccShortPrefix | not_carry; static const byte kJcShortOpcode = kJccShortPrefix | carry; + static const byte kJnzShortOpcode = kJccShortPrefix | not_zero; + static const byte kJzShortOpcode = kJccShortPrefix | zero; + // --------------------------------------------------------------------------- // Code generation diff --git a/deps/v8/src/ia32/builtins-ia32.cc b/deps/v8/src/ia32/builtins-ia32.cc index a5d42cfbe4..a36763db20 100644 --- a/deps/v8/src/ia32/builtins-ia32.cc +++ b/deps/v8/src/ia32/builtins-ia32.cc @@ -831,7 +831,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { // Copy all arguments from the array to the stack. Label entry, loop; - __ mov(eax, Operand(ebp, kIndexOffset)); + __ mov(ecx, Operand(ebp, kIndexOffset)); __ jmp(&entry); __ bind(&loop); __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments @@ -848,16 +848,17 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { __ push(eax); // Update the index on the stack and in register eax. - __ mov(eax, Operand(ebp, kIndexOffset)); - __ add(eax, Immediate(1 << kSmiTagSize)); - __ mov(Operand(ebp, kIndexOffset), eax); + __ mov(ecx, Operand(ebp, kIndexOffset)); + __ add(ecx, Immediate(1 << kSmiTagSize)); + __ mov(Operand(ebp, kIndexOffset), ecx); __ bind(&entry); - __ cmp(eax, Operand(ebp, kLimitOffset)); + __ cmp(ecx, Operand(ebp, kLimitOffset)); __ j(not_equal, &loop); // Invoke the function. Label call_proxy; + __ mov(eax, ecx); ParameterCount actual(eax); __ SmiUntag(eax); __ mov(edi, Operand(ebp, kFunctionOffset)); diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index 4faa6a4b24..a1c6edd0fa 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -1681,6 +1681,11 @@ void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { } +// Input: +// edx: left operand (tagged) +// eax: right operand (tagged) +// Output: +// eax: result (tagged) void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Label call_runtime; ASSERT(operands_type_ == BinaryOpIC::INT32); @@ -1690,31 +1695,37 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { case Token::ADD: case Token::SUB: case Token::MUL: - case Token::DIV: { + case Token::DIV: + case Token::MOD: { Label not_floats; Label not_int32; if (CpuFeatures::IsSupported(SSE2)) { CpuFeatures::Scope use_sse2(SSE2); FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); - switch (op_) { - case Token::ADD: __ addsd(xmm0, xmm1); break; - case Token::SUB: __ subsd(xmm0, xmm1); break; - case Token::MUL: __ mulsd(xmm0, xmm1); break; - case Token::DIV: __ divsd(xmm0, xmm1); break; - default: UNREACHABLE(); - } - // Check result type if it is currently Int32. - if (result_type_ <= BinaryOpIC::INT32) { - __ cvttsd2si(ecx, Operand(xmm0)); - __ cvtsi2sd(xmm2, ecx); - __ ucomisd(xmm0, xmm2); - __ j(not_zero, ¬_int32); - __ j(carry, ¬_int32); + if (op_ == Token::MOD) { + GenerateRegisterArgsPush(masm); + __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); + } else { + switch (op_) { + case Token::ADD: __ addsd(xmm0, xmm1); break; + case Token::SUB: __ subsd(xmm0, xmm1); break; + case Token::MUL: __ mulsd(xmm0, xmm1); break; + case Token::DIV: __ divsd(xmm0, xmm1); break; + default: UNREACHABLE(); + } + // Check result type if it is currently Int32. + if (result_type_ <= BinaryOpIC::INT32) { + __ cvttsd2si(ecx, Operand(xmm0)); + __ cvtsi2sd(xmm2, ecx); + __ ucomisd(xmm0, xmm2); + __ j(not_zero, ¬_int32); + __ j(carry, ¬_int32); + } + GenerateHeapResultAllocation(masm, &call_runtime); + __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); + __ ret(0); } - GenerateHeapResultAllocation(masm, &call_runtime); - __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); - __ ret(0); } else { // SSE2 not available, use FPU. FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); FloatingPointHelper::LoadFloatOperands( @@ -1722,20 +1733,28 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { ecx, FloatingPointHelper::ARGS_IN_REGISTERS); FloatingPointHelper::CheckFloatOperandsAreInt32(masm, ¬_int32); - switch (op_) { - case Token::ADD: __ faddp(1); break; - case Token::SUB: __ fsubp(1); break; - case Token::MUL: __ fmulp(1); break; - case Token::DIV: __ fdivp(1); break; - default: UNREACHABLE(); + if (op_ == Token::MOD) { + // The operands are now on the FPU stack, but we don't need them. + __ fstp(0); + __ fstp(0); + GenerateRegisterArgsPush(masm); + __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); + } else { + switch (op_) { + case Token::ADD: __ faddp(1); break; + case Token::SUB: __ fsubp(1); break; + case Token::MUL: __ fmulp(1); break; + case Token::DIV: __ fdivp(1); break; + default: UNREACHABLE(); + } + Label after_alloc_failure; + GenerateHeapResultAllocation(masm, &after_alloc_failure); + __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); + __ ret(0); + __ bind(&after_alloc_failure); + __ fstp(0); // Pop FPU stack before calling runtime. + __ jmp(&call_runtime); } - Label after_alloc_failure; - GenerateHeapResultAllocation(masm, &after_alloc_failure); - __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); - __ ret(0); - __ bind(&after_alloc_failure); - __ ffree(); - __ jmp(&call_runtime); } __ bind(¬_floats); @@ -1744,10 +1763,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { break; } - case Token::MOD: { - // For MOD we go directly to runtime in the non-smi case. - break; - } case Token::BIT_OR: case Token::BIT_AND: case Token::BIT_XOR: @@ -1758,11 +1773,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Label not_floats; Label not_int32; Label non_smi_result; - /* { - CpuFeatures::Scope use_sse2(SSE2); - FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); - FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); - }*/ FloatingPointHelper::LoadUnknownsAsIntegers(masm, use_sse3_, ¬_floats); @@ -1833,8 +1843,8 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { default: UNREACHABLE(); break; } - // If an allocation fails, or SHR or MOD hit a hard case, - // use the runtime system to get the correct result. + // If an allocation fails, or SHR hits a hard case, use the runtime system to + // get the correct result. __ bind(&call_runtime); switch (op_) { @@ -1855,8 +1865,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); break; case Token::MOD: - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); break; case Token::BIT_OR: __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); @@ -1957,7 +1965,7 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ ret(0); __ bind(&after_alloc_failure); - __ ffree(); + __ fstp(0); // Pop FPU stack before calling runtime. __ jmp(&call_runtime); } @@ -2161,8 +2169,8 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ ret(0); __ bind(&after_alloc_failure); - __ ffree(); - __ jmp(&call_runtime); + __ fstp(0); // Pop FPU stack before calling runtime. + __ jmp(&call_runtime); } __ bind(¬_floats); break; @@ -5006,11 +5014,9 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { __ j(not_equal, ¬_outermost_js, Label::kNear); __ mov(Operand::StaticVariable(js_entry_sp), ebp); __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); - Label cont; - __ jmp(&cont, Label::kNear); + __ jmp(&invoke, Label::kNear); __ bind(¬_outermost_js); __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); - __ bind(&cont); // Jump to a faked try block that does the invoke, with a faked catch // block that sets the pending exception. @@ -6162,7 +6168,11 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ sub(ecx, edx); __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); Label not_original_string; - __ j(not_equal, ¬_original_string, Label::kNear); + // Shorter than original string's length: an actual substring. + __ j(below, ¬_original_string, Label::kNear); + // Longer than original string's length or negative: unsafe arguments. + __ j(above, &runtime); + // Return original string. Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->sub_string_native(), 1); __ ret(3 * kPointerSize); diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index ea61910322..cff6454ff1 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -397,9 +397,25 @@ void ElementsTransitionGenerator::GenerateSmiOnlyToDouble( // Allocate new FixedDoubleArray. // edx: receiver // edi: length of source FixedArray (smi-tagged) - __ lea(esi, Operand(edi, times_4, FixedDoubleArray::kHeaderSize)); + __ lea(esi, Operand(edi, + times_4, + FixedDoubleArray::kHeaderSize + kPointerSize)); __ AllocateInNewSpace(esi, eax, ebx, no_reg, &gc_required, TAG_OBJECT); + Label aligned, aligned_done; + __ test(eax, Immediate(kDoubleAlignmentMask - kHeapObjectTag)); + __ j(zero, &aligned, Label::kNear); + __ mov(FieldOperand(eax, 0), + Immediate(masm->isolate()->factory()->one_pointer_filler_map())); + __ add(eax, Immediate(kPointerSize)); + __ jmp(&aligned_done); + + __ bind(&aligned); + __ mov(Operand(eax, esi, times_1, -kPointerSize-1), + Immediate(masm->isolate()->factory()->one_pointer_filler_map())); + + __ bind(&aligned_done); + // eax: destination FixedDoubleArray // edi: number of elements // edx: receiver diff --git a/deps/v8/src/ia32/debug-ia32.cc b/deps/v8/src/ia32/debug-ia32.cc index d13fa759ca..901e38bfe3 100644 --- a/deps/v8/src/ia32/debug-ia32.cc +++ b/deps/v8/src/ia32/debug-ia32.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -91,9 +91,11 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() { rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength); } +// All debug break stubs support padding for LiveEdit. +const bool Debug::FramePaddingLayout::kIsSupported = true; -#define __ ACCESS_MASM(masm) +#define __ ACCESS_MASM(masm) static void Generate_DebugBreakCallHelper(MacroAssembler* masm, RegList object_regs, @@ -103,6 +105,13 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, { FrameScope scope(masm, StackFrame::INTERNAL); + // Load padding words on stack. + for (int i = 0; i < Debug::FramePaddingLayout::kInitialSize; i++) { + __ push(Immediate(Smi::FromInt( + Debug::FramePaddingLayout::kPaddingValue))); + } + __ push(Immediate(Smi::FromInt(Debug::FramePaddingLayout::kInitialSize))); + // Store the registers containing live values on the expression stack to // make sure that these are correctly updated during GC. Non object values // are stored as a smi causing it to be untouched by GC. @@ -134,6 +143,10 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, CEntryStub ceb(1); __ CallStub(&ceb); + // Automatically find register that could be used after register restore. + // We need one register for padding skip instructions. + Register unused_reg = { -1 }; + // Restore the register values containing object pointers from the // expression stack. for (int i = kNumJSCallerSaved; --i >= 0;) { @@ -142,15 +155,29 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, if (FLAG_debug_code) { __ Set(reg, Immediate(kDebugZapValue)); } + bool taken = reg.code() == esi.code(); if ((object_regs & (1 << r)) != 0) { __ pop(reg); + taken = true; } if ((non_object_regs & (1 << r)) != 0) { __ pop(reg); __ SmiUntag(reg); + taken = true; + } + if (!taken) { + unused_reg = reg; } } + ASSERT(unused_reg.code() != -1); + + // Read current padding counter and skip corresponding number of words. + __ pop(unused_reg); + // We divide stored value by 2 (untagging) and multiply it by word's size. + STATIC_ASSERT(kSmiTagSize == 1); + __ lea(esp, Operand(esp, unused_reg, times_half_pointer_size, 0)); + // Get rid of the internal frame. } @@ -172,10 +199,10 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) { // Register state for IC load call (from ic-ia32.cc). // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // ----------------------------------- - Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), 0, false); + Generate_DebugBreakCallHelper(masm, ecx.bit() | edx.bit(), 0, false); } @@ -194,10 +221,10 @@ void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) { void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) { // Register state for keyed IC load call (from ic-ia32.cc). // ----------- S t a t e ------------- + // -- ecx : key // -- edx : receiver - // -- eax : key // ----------------------------------- - Generate_DebugBreakCallHelper(masm, eax.bit() | edx.bit(), 0, false); + Generate_DebugBreakCallHelper(masm, ecx.bit() | edx.bit(), 0, false); } diff --git a/deps/v8/src/ia32/deoptimizer-ia32.cc b/deps/v8/src/ia32/deoptimizer-ia32.cc index 92d7cc1c2c..73961e1416 100644 --- a/deps/v8/src/ia32/deoptimizer-ia32.cc +++ b/deps/v8/src/ia32/deoptimizer-ia32.cc @@ -239,13 +239,13 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, // ok: if (FLAG_count_based_interrupts) { - ASSERT_EQ(*(call_target_address - 3), kJnsInstruction); - ASSERT_EQ(*(call_target_address - 2), kJnsOffset); + ASSERT_EQ(kJnsInstruction, *(call_target_address - 3)); + ASSERT_EQ(kJnsOffset, *(call_target_address - 2)); } else { - ASSERT_EQ(*(call_target_address - 3), kJaeInstruction); - ASSERT_EQ(*(call_target_address - 2), kJaeOffset); + ASSERT_EQ(kJaeInstruction, *(call_target_address - 3)); + ASSERT_EQ(kJaeOffset, *(call_target_address - 2)); } - ASSERT_EQ(*(call_target_address - 1), kCallInstruction); + ASSERT_EQ(kCallInstruction, *(call_target_address - 1)); *(call_target_address - 3) = kNopByteOne; *(call_target_address - 2) = kNopByteTwo; Assembler::set_target_address_at(call_target_address, @@ -266,9 +266,9 @@ void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code, // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to // restore the conditional branch. - ASSERT_EQ(*(call_target_address - 3), kNopByteOne); - ASSERT_EQ(*(call_target_address - 2), kNopByteTwo); - ASSERT_EQ(*(call_target_address - 1), kCallInstruction); + ASSERT_EQ(kNopByteOne, *(call_target_address - 3)); + ASSERT_EQ(kNopByteTwo, *(call_target_address - 2)); + ASSERT_EQ(kCallInstruction, *(call_target_address - 1)); if (FLAG_count_based_interrupts) { *(call_target_address - 3) = kJnsInstruction; *(call_target_address - 2) = kJnsOffset; @@ -548,6 +548,8 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator, void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, int frame_index) { + Builtins* builtins = isolate_->builtins(); + Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); unsigned height = iterator->Next(); unsigned height_in_bytes = height * kPointerSize; @@ -555,7 +557,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, PrintF(" translating construct stub => height=%d\n", height_in_bytes); } - unsigned fixed_frame_size = 6 * kPointerSize; + unsigned fixed_frame_size = 7 * kPointerSize; unsigned output_frame_size = height_in_bytes + fixed_frame_size; // Allocate and store the output frame description. @@ -620,6 +622,15 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, top_address + output_offset, output_offset, value); } + // The output frame reflects a JSConstructStubGeneric frame. + output_offset -= kPointerSize; + value = reinterpret_cast<intptr_t>(construct_stub); + output_frame->SetFrameSlot(output_offset, value); + if (FLAG_trace_deopt) { + PrintF(" 0x%08x: [top + %d] <- 0x%08x ; code object\n", + top_address + output_offset, output_offset, value); + } + // Number of incoming arguments. output_offset -= kPointerSize; value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1)); @@ -641,8 +652,6 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, ASSERT(0 == output_offset); - Builtins* builtins = isolate_->builtins(); - Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); uint32_t pc = reinterpret_cast<uint32_t>( construct_stub->instruction_start() + isolate_->heap()->construct_stub_deopt_pc_offset()->value()); diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index 62a2c2af33..10fe77b354 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -101,13 +101,6 @@ class JumpPatchSite BASE_EMBEDDED { }; -// TODO(jkummerow): Obsolete as soon as x64 is updated. Remove. -int FullCodeGenerator::self_optimization_header_size() { - UNREACHABLE(); - return 13; -} - - // Generate code for a JS function. On entry to the function the receiver // and arguments have been pushed on the stack left to right, with the // return address on top of them. The actual argument count matches the @@ -269,11 +262,11 @@ void FullCodeGenerator::Generate() { // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - VariableProxy* proxy = scope()->function(); - ASSERT(proxy->var()->mode() == CONST || - proxy->var()->mode() == CONST_HARMONY); - ASSERT(proxy->var()->location() != Variable::UNALLOCATED); - EmitDeclaration(proxy, proxy->var()->mode(), NULL); + VariableDeclaration* function = scope()->function(); + ASSERT(function->proxy()->var()->mode() == CONST || + function->proxy()->var()->mode() == CONST_HARMONY); + ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); + VisitVariableDeclaration(function); } VisitDeclarations(scope()->declarations()); } @@ -763,60 +756,51 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, } -void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function) { +void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { + // The variable in the declaration always resides in the current function + // context. + ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); + if (FLAG_debug_code) { + // Check that we're not inside a with or catch context. + __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); + __ cmp(ebx, isolate()->factory()->with_context_map()); + __ Check(not_equal, "Declaration in with context."); + __ cmp(ebx, isolate()->factory()->catch_context_map()); + __ Check(not_equal, "Declaration in catch context."); + } +} + + +void FullCodeGenerator::VisitVariableDeclaration( + VariableDeclaration* declaration) { // If it was not possible to allocate the variable at compile time, we // need to "declare" it at runtime to make sure it actually exists in the // local context. + VariableProxy* proxy = declaration->proxy(); + VariableMode mode = declaration->mode(); Variable* variable = proxy->var(); - bool binding_needs_init = (function == NULL) && - (mode == CONST || mode == CONST_HARMONY || mode == LET); + bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; switch (variable->location()) { case Variable::UNALLOCATED: - ++global_count_; + globals_->Add(variable->name()); + globals_->Add(variable->binding_needs_init() + ? isolate()->factory()->the_hole_value() + : isolate()->factory()->undefined_value()); break; case Variable::PARAMETER: case Variable::LOCAL: - if (function != NULL) { - Comment cmnt(masm_, "[ Declaration"); - VisitForAccumulatorValue(function); - __ mov(StackOperand(variable), result_register()); - } else if (binding_needs_init) { - Comment cmnt(masm_, "[ Declaration"); + if (hole_init) { + Comment cmnt(masm_, "[ VariableDeclaration"); __ mov(StackOperand(variable), Immediate(isolate()->factory()->the_hole_value())); } break; case Variable::CONTEXT: - // The variable in the decl always resides in the current function - // context. - ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); - if (FLAG_debug_code) { - // Check that we're not inside a with or catch context. - __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); - __ cmp(ebx, isolate()->factory()->with_context_map()); - __ Check(not_equal, "Declaration in with context."); - __ cmp(ebx, isolate()->factory()->catch_context_map()); - __ Check(not_equal, "Declaration in catch context."); - } - if (function != NULL) { - Comment cmnt(masm_, "[ Declaration"); - VisitForAccumulatorValue(function); - __ mov(ContextOperand(esi, variable->index()), result_register()); - // We know that we have written a function, which is not a smi. - __ RecordWriteContextSlot(esi, - Context::SlotOffset(variable->index()), - result_register(), - ecx, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - PrepareForBailoutForId(proxy->id(), NO_REGISTERS); - } else if (binding_needs_init) { - Comment cmnt(masm_, "[ Declaration"); + if (hole_init) { + Comment cmnt(masm_, "[ VariableDeclaration"); + EmitDebugCheckDeclarationContext(variable); __ mov(ContextOperand(esi, variable->index()), Immediate(isolate()->factory()->the_hole_value())); // No write barrier since the hole value is in old space. @@ -825,14 +809,12 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, break; case Variable::LOOKUP: { - Comment cmnt(masm_, "[ Declaration"); + Comment cmnt(masm_, "[ VariableDeclaration"); __ push(esi); __ push(Immediate(variable->name())); - // Declaration nodes are always introduced in one of four modes. - ASSERT(mode == VAR || - mode == CONST || - mode == CONST_HARMONY || - mode == LET); + // VariableDeclaration nodes are always introduced in one of four modes. + ASSERT(mode == VAR || mode == LET || + mode == CONST || mode == CONST_HARMONY); PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; __ push(Immediate(Smi::FromInt(attr))); @@ -840,9 +822,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, // Note: For variables we must not push an initial value (such as // 'undefined') because we may have a (legal) redeclaration and we // must not destroy the current value. - if (function != NULL) { - VisitForStackValue(function); - } else if (binding_needs_init) { + if (hole_init) { __ push(Immediate(isolate()->factory()->the_hole_value())); } else { __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. @@ -854,6 +834,118 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, } +void FullCodeGenerator::VisitFunctionDeclaration( + FunctionDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: { + globals_->Add(variable->name()); + Handle<SharedFunctionInfo> function = + Compiler::BuildFunctionInfo(declaration->fun(), script()); + // Check for stack-overflow exception. + if (function.is_null()) return SetStackOverflow(); + globals_->Add(function); + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + VisitForAccumulatorValue(declaration->fun()); + __ mov(StackOperand(variable), result_register()); + break; + } + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + EmitDebugCheckDeclarationContext(variable); + VisitForAccumulatorValue(declaration->fun()); + __ mov(ContextOperand(esi, variable->index()), result_register()); + // We know that we have written a function, which is not a smi. + __ RecordWriteContextSlot(esi, + Context::SlotOffset(variable->index()), + result_register(), + ecx, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); + break; + } + + case Variable::LOOKUP: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + __ push(esi); + __ push(Immediate(variable->name())); + __ push(Immediate(Smi::FromInt(NONE))); + VisitForStackValue(declaration->fun()); + __ CallRuntime(Runtime::kDeclareContextSlot, 4); + break; + } + } +} + + +void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + Handle<JSModule> instance = declaration->module()->interface()->Instance(); + ASSERT(!instance.is_null()); + + switch (variable->location()) { + case Variable::UNALLOCATED: { + Comment cmnt(masm_, "[ ModuleDeclaration"); + globals_->Add(variable->name()); + globals_->Add(instance); + Visit(declaration->module()); + break; + } + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ ModuleDeclaration"); + EmitDebugCheckDeclarationContext(variable); + __ mov(ContextOperand(esi, variable->index()), Immediate(instance)); + Visit(declaration->module()); + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::LOOKUP: + UNREACHABLE(); + } +} + + +void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: + // TODO(rossberg) + break; + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ ImportDeclaration"); + EmitDebugCheckDeclarationContext(variable); + // TODO(rossberg) + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::LOOKUP: + UNREACHABLE(); + } +} + + +void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { + // TODO(rossberg) +} + + void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { // Call the runtime to declare the globals. __ push(esi); // The context is the first argument. @@ -1194,7 +1286,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, // All extension objects were empty and it is safe to use a global // load IC call. - __ mov(eax, GlobalObjectOperand()); + __ mov(edx, GlobalObjectOperand()); __ mov(ecx, var->name()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) @@ -1278,7 +1370,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Comment cmnt(masm_, "Global variable"); // Use inline caching. Variable name is passed in ecx and the global // object in eax. - __ mov(eax, GlobalObjectOperand()); + __ mov(edx, GlobalObjectOperand()); __ mov(ecx, var->name()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); @@ -1672,9 +1764,9 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { break; case NAMED_PROPERTY: if (expr->is_compound()) { - // We need the receiver both on the stack and in the accumulator. - VisitForAccumulatorValue(property->obj()); - __ push(result_register()); + // We need the receiver both on the stack and in edx. + VisitForStackValue(property->obj()); + __ mov(edx, Operand(esp, 0)); } else { VisitForStackValue(property->obj()); } @@ -1682,9 +1774,9 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { case KEYED_PROPERTY: { if (expr->is_compound()) { VisitForStackValue(property->obj()); - VisitForAccumulatorValue(property->key()); - __ mov(edx, Operand(esp, 0)); - __ push(eax); + VisitForStackValue(property->key()); + __ mov(edx, Operand(esp, kPointerSize)); // Object. + __ mov(ecx, Operand(esp, 0)); // Key. } else { VisitForStackValue(property->obj()); VisitForStackValue(property->key()); @@ -1927,7 +2019,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { VisitForStackValue(prop->obj()); VisitForAccumulatorValue(prop->key()); __ mov(ecx, eax); - __ pop(edx); + __ pop(edx); // Receiver. __ pop(eax); // Restore value. Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() @@ -2033,6 +2125,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { // Assignment to a property, using a named store IC. + // eax : value + // esp[0] : receiver + Property* prop = expr->target()->AsProperty(); ASSERT(prop != NULL); ASSERT(prop->key()->AsLiteral() != NULL); @@ -2075,6 +2170,9 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { // Assignment to a property, using a keyed store IC. + // eax : value + // esp[0] : key + // esp[kPointerSize] : receiver // If the assignment starts a block of assignments to the same object, // change to slow case to avoid the quadratic behavior of repeatedly @@ -2087,7 +2185,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { __ pop(result_register()); } - __ pop(ecx); + __ pop(ecx); // Key. if (expr->ends_initialization_block()) { __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. } else { @@ -2120,12 +2218,14 @@ void FullCodeGenerator::VisitProperty(Property* expr) { if (key->IsPropertyName()) { VisitForAccumulatorValue(expr->obj()); + __ mov(edx, result_register()); EmitNamedPropertyLoad(expr); context()->Plug(eax); } else { VisitForStackValue(expr->obj()); VisitForAccumulatorValue(expr->key()); - __ pop(edx); + __ pop(edx); // Object. + __ mov(ecx, result_register()); // Key. EmitKeyedPropertyLoad(expr); context()->Plug(eax); } @@ -4017,15 +4117,16 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ push(Immediate(Smi::FromInt(0))); } if (assign_type == NAMED_PROPERTY) { - // Put the object both on the stack and in the accumulator. + // Put the object both on the stack and in edx. VisitForAccumulatorValue(prop->obj()); __ push(eax); + __ mov(edx, eax); EmitNamedPropertyLoad(prop); } else { VisitForStackValue(prop->obj()); - VisitForAccumulatorValue(prop->key()); - __ mov(edx, Operand(esp, 0)); - __ push(eax); + VisitForStackValue(prop->key()); + __ mov(edx, Operand(esp, kPointerSize)); // Object. + __ mov(ecx, Operand(esp, 0)); // Key. EmitKeyedPropertyLoad(prop); } } @@ -4172,7 +4273,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { if (proxy != NULL && proxy->var()->IsUnallocated()) { Comment cmnt(masm_, "Global variable"); - __ mov(eax, GlobalObjectOperand()); + __ mov(edx, GlobalObjectOperand()); __ mov(ecx, Immediate(proxy->name())); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); // Use a regular load, not a contextual load, to avoid a reference @@ -4437,7 +4538,8 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) { void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { Scope* declaration_scope = scope()->DeclarationScope(); - if (declaration_scope->is_global_scope()) { + if (declaration_scope->is_global_scope() || + declaration_scope->is_module_scope()) { // Contexts nested in the global context have a canonical empty function // as their closure, not the anonymous closure containing the global // code. Pass a smi sentinel and let the runtime look up the empty diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc index 33f247a349..dc64a09d83 100644 --- a/deps/v8/src/ia32/ic-ia32.cc +++ b/deps/v8/src/ia32/ic-ia32.cc @@ -218,13 +218,13 @@ static void GenerateDictionaryStore(MacroAssembler* masm, void LoadIC::GenerateArrayLength(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; - StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss); + StubCompiler::GenerateLoadArrayLength(masm, edx, eax, &miss); __ bind(&miss); StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } @@ -233,13 +233,13 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) { void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; - StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss, + StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss, support_wrappers); __ bind(&miss); StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); @@ -248,13 +248,13 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm, void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; - StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss); + StubCompiler::GenerateLoadFunctionPrototype(masm, edx, eax, ebx, &miss); __ bind(&miss); StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } @@ -383,7 +383,7 @@ static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm, __ j(below, slow_case); // Check that the key is a positive smi. - __ test(key, Immediate(0x8000001)); + __ test(key, Immediate(0x80000001)); __ j(not_zero, slow_case); // Load the elements into scratch1 and check its map. @@ -396,7 +396,7 @@ static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm, __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset)); __ sub(scratch2, Immediate(Smi::FromInt(2))); __ cmp(key, scratch2); - __ j(greater_equal, unmapped_case); + __ j(above_equal, unmapped_case); // Load element index and check whether it is the hole. const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize; @@ -443,7 +443,7 @@ static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm, void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -451,39 +451,34 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { Label probe_dictionary, check_number_dictionary; // Check that the key is a smi. - __ JumpIfNotSmi(eax, &check_string); + __ JumpIfNotSmi(ecx, &check_string); __ bind(&index_smi); // Now the key is known to be a smi. This place is also jumped to from // where a numeric string is converted to a smi. GenerateKeyedLoadReceiverCheck( - masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); + masm, edx, eax, Map::kHasIndexedInterceptor, &slow); // Check the receiver's map to see if it has fast elements. - __ CheckFastElements(ecx, &check_number_dictionary); - - GenerateFastArrayLoad(masm, - edx, - eax, - ecx, - eax, - NULL, - &slow); + __ CheckFastElements(eax, &check_number_dictionary); + + GenerateFastArrayLoad(masm, edx, ecx, eax, eax, NULL, &slow); Isolate* isolate = masm->isolate(); Counters* counters = isolate->counters(); __ IncrementCounter(counters->keyed_load_generic_smi(), 1); __ ret(0); + __ bind(&check_number_dictionary); - __ mov(ebx, eax); + __ mov(ebx, ecx); __ SmiUntag(ebx); - __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); + __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); // Check whether the elements is a number dictionary. // edx: receiver // ebx: untagged index - // eax: key - // ecx: elements - __ CheckMap(ecx, + // ecx: key + // eax: elements + __ CheckMap(eax, isolate->factory()->hash_table_map(), &slow, DONT_DO_SMI_CHECK); @@ -491,13 +486,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // Push receiver on the stack to free up a register for the dictionary // probing. __ push(edx); - __ LoadFromNumberDictionary(&slow_pop_receiver, - ecx, - eax, - ebx, - edx, - edi, - eax); + __ LoadFromNumberDictionary(&slow_pop_receiver, eax, ecx, ebx, edx, edi, eax); // Pop receiver before returning. __ pop(edx); __ ret(0); @@ -509,15 +498,15 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ bind(&slow); // Slow case: jump to runtime. // edx: receiver - // eax: key + // ecx: key __ IncrementCounter(counters->keyed_load_generic_slow(), 1); GenerateRuntimeGetProperty(masm); __ bind(&check_string); - GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow); + GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow); GenerateKeyedLoadReceiverCheck( - masm, edx, ecx, Map::kHasNamedInterceptor, &slow); + masm, edx, eax, Map::kHasNamedInterceptor, &slow); // If the receiver is a fast-case object, check the keyed lookup // cache. Otherwise probe the dictionary. @@ -526,15 +515,18 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { Immediate(isolate->factory()->hash_table_map())); __ j(equal, &probe_dictionary); - // Load the map of the receiver, compute the keyed lookup cache hash + // The receiver's map is still in eax, compute the keyed lookup cache hash // based on 32 bits of the map pointer and the string hash. - __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); - __ mov(ecx, ebx); - __ shr(ecx, KeyedLookupCache::kMapHashShift); - __ mov(edi, FieldOperand(eax, String::kHashFieldOffset)); + if (FLAG_debug_code) { + __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset)); + __ Check(equal, "Map is no longer in eax."); + } + __ mov(ebx, eax); // Keep the map around for later. + __ shr(eax, KeyedLookupCache::kMapHashShift); + __ mov(edi, FieldOperand(ecx, String::kHashFieldOffset)); __ shr(edi, String::kHashShift); - __ xor_(ecx, edi); - __ and_(ecx, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); + __ xor_(eax, edi); + __ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); // Load the key (consisting of map and symbol) from the cache and // check for match. @@ -546,7 +538,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { for (int i = 0; i < kEntriesPerBucket - 1; i++) { Label try_next_entry; - __ mov(edi, ecx); + __ mov(edi, eax); __ shl(edi, kPointerSizeLog2 + 1); if (i != 0) { __ add(edi, Immediate(kPointerSize * i * 2)); @@ -554,25 +546,25 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); __ j(not_equal, &try_next_entry); __ add(edi, Immediate(kPointerSize)); - __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys)); + __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys)); __ j(equal, &hit_on_nth_entry[i]); __ bind(&try_next_entry); } - __ lea(edi, Operand(ecx, 1)); + __ lea(edi, Operand(eax, 1)); __ shl(edi, kPointerSizeLog2 + 1); __ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2)); __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys)); __ j(not_equal, &slow); __ add(edi, Immediate(kPointerSize)); - __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys)); + __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys)); __ j(not_equal, &slow); // Get field offset. // edx : receiver // ebx : receiver's map - // eax : key - // ecx : lookup cache index + // ecx : key + // eax : lookup cache index ExternalReference cache_field_offsets = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate()); @@ -580,12 +572,12 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { for (int i = kEntriesPerBucket - 1; i >= 0; i--) { __ bind(&hit_on_nth_entry[i]); if (i != 0) { - __ add(ecx, Immediate(i)); + __ add(eax, Immediate(i)); } __ mov(edi, - Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets)); - __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); - __ sub(edi, ecx); + Operand::StaticArray(eax, times_pointer_size, cache_field_offsets)); + __ movzx_b(eax, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); + __ sub(edi, eax); __ j(above_equal, &property_array_property); if (i != 0) { __ jmp(&load_in_object_property); @@ -594,9 +586,9 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // Load in-object property. __ bind(&load_in_object_property); - __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); - __ add(ecx, edi); - __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0)); + __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceSizeOffset)); + __ add(eax, edi); + __ mov(eax, FieldOperand(edx, eax, times_pointer_size, 0)); __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1); __ ret(0); @@ -612,16 +604,16 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // exists. __ bind(&probe_dictionary); - __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); - GenerateGlobalInstanceTypeCheck(masm, ecx, &slow); + __ mov(eax, FieldOperand(edx, JSObject::kMapOffset)); + __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); + GenerateGlobalInstanceTypeCheck(masm, eax, &slow); - GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax); + GenerateDictionaryLoad(masm, &slow, ebx, ecx, eax, edi, eax); __ IncrementCounter(counters->keyed_load_generic_symbol(), 1); __ ret(0); __ bind(&index_string); - __ IndexFromHash(ebx, eax); + __ IndexFromHash(ebx, ecx); // Now jump to the place where smi keys are handled. __ jmp(&index_smi); } @@ -629,15 +621,15 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { void KeyedLoadIC::GenerateString(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : key (index) + // -- ecx : key (index) // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; Register receiver = edx; - Register index = eax; - Register scratch = ecx; + Register index = ecx; + Register scratch = ebx; Register result = eax; StringCharAtGenerator char_at_generator(receiver, @@ -661,7 +653,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -671,24 +663,24 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { __ JumpIfSmi(edx, &slow); // Check that the key is an array index, that is Uint32. - __ test(eax, Immediate(kSmiTagMask | kSmiSignMask)); + __ test(ecx, Immediate(kSmiTagMask | kSmiSignMask)); __ j(not_zero, &slow); // Get the map of the receiver. - __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); + __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset)); // Check that it has indexed interceptor and access checks // are not enabled for this object. - __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); - __ and_(ecx, Immediate(kSlowCaseBitFieldMask)); - __ cmp(ecx, Immediate(1 << Map::kHasIndexedInterceptor)); + __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset)); + __ and_(eax, Immediate(kSlowCaseBitFieldMask)); + __ cmp(eax, Immediate(1 << Map::kHasIndexedInterceptor)); __ j(not_zero, &slow); // Everything is fine, call runtime. - __ pop(ecx); + __ pop(eax); __ push(edx); // receiver - __ push(eax); // key - __ push(ecx); // return address + __ push(ecx); // key + __ push(eax); // return address // Perform tail call to the entry. ExternalReference ref = @@ -703,20 +695,20 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label slow, notin; Factory* factory = masm->isolate()->factory(); Operand mapped_location = - GenerateMappedArgumentsLookup(masm, edx, eax, ebx, ecx, ¬in, &slow); + GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, ¬in, &slow); __ mov(eax, mapped_location); __ Ret(); __ bind(¬in); // The unmapped lookup expects that the parameter map is in ebx. Operand unmapped_location = - GenerateUnmappedArgumentsLookup(masm, eax, ebx, ecx, &slow); + GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow); __ cmp(unmapped_location, factory->the_hole_value()); __ j(equal, &slow); __ mov(eax, unmapped_location); @@ -1308,15 +1300,15 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- // Probe the stub cache. Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC); - Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, eax, ecx, ebx, - edx); + Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, + eax); // Cache miss: Jump to runtime. GenerateMiss(masm); @@ -1325,17 +1317,17 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { void LoadIC::GenerateNormal(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; - GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss); + GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss); - // edx: elements + // eax: elements // Search the dictionary placing the result in eax. - GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax); + GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax); __ ret(0); // Cache miss: Jump to runtime. @@ -1346,15 +1338,15 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { void LoadIC::GenerateMiss(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1); __ pop(ebx); - __ push(eax); // receiver + __ push(edx); // receiver __ push(ecx); // name __ push(ebx); // return address @@ -1367,7 +1359,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -1376,7 +1368,7 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) { __ pop(ebx); __ push(edx); // receiver - __ push(eax); // name + __ push(ecx); // name __ push(ebx); // return address // Perform tail call to the entry. @@ -1390,14 +1382,14 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) { void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- __ pop(ebx); __ push(edx); // receiver - __ push(eax); // name + __ push(ecx); // name __ push(ebx); // return address // Perform tail call to the entry. @@ -1735,12 +1727,12 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { // Activate inlined smi code. if (previous_state == UNINITIALIZED) { - PatchInlinedSmiCode(address()); + PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); } } -void PatchInlinedSmiCode(Address address) { +void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { // The address of the instruction following the call. Address test_instruction_address = address + Assembler::kCallTargetAddressOffset; @@ -1761,14 +1753,18 @@ void PatchInlinedSmiCode(Address address) { address, test_instruction_address, delta); } - // Patch with a short conditional jump. There must be a - // short jump-if-carry/not-carry at this position. + // Patch with a short conditional jump. Enabling means switching from a short + // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the + // reverse operation of that. Address jmp_address = test_instruction_address - delta; - ASSERT(*jmp_address == Assembler::kJncShortOpcode || - *jmp_address == Assembler::kJcShortOpcode); - Condition cc = *jmp_address == Assembler::kJncShortOpcode - ? not_zero - : zero; + ASSERT((check == ENABLE_INLINED_SMI_CHECK) + ? (*jmp_address == Assembler::kJncShortOpcode || + *jmp_address == Assembler::kJcShortOpcode) + : (*jmp_address == Assembler::kJnzShortOpcode || + *jmp_address == Assembler::kJzShortOpcode)); + Condition cc = (check == ENABLE_INLINED_SMI_CHECK) + ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) + : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 8fb4c79196..455c502150 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -2059,8 +2059,9 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, RelocInfo::CODE_TARGET, instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); - ASSERT(instr->HasDeoptimizationEnvironment()); - LEnvironment* env = instr->deoptimization_environment(); + // Get the deoptimization index of the LLazyBailout-environment that + // corresponds to this instruction. + LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment(); safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); // Put the result value into the eax slot and restore all registers. @@ -2114,7 +2115,7 @@ void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { ASSERT(ToRegister(instr->context()).is(esi)); - ASSERT(ToRegister(instr->global_object()).is(eax)); + ASSERT(ToRegister(instr->global_object()).is(edx)); ASSERT(ToRegister(instr->result()).is(eax)); __ mov(ecx, instr->name()); @@ -2273,46 +2274,41 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { Register result = ToRegister(instr->result()); int map_count = instr->hydrogen()->types()->length(); + bool need_generic = instr->hydrogen()->need_generic(); + + if (map_count == 0 && !need_generic) { + DeoptimizeIf(no_condition, instr->environment()); + return; + } Handle<String> name = instr->hydrogen()->name(); - if (map_count == 0) { - ASSERT(instr->hydrogen()->need_generic()); - __ mov(ecx, name); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); - } else { - Label done; - for (int i = 0; i < map_count - 1; ++i) { - Handle<Map> map = instr->hydrogen()->types()->at(i); + Label done; + for (int i = 0; i < map_count; ++i) { + bool last = (i == map_count - 1); + Handle<Map> map = instr->hydrogen()->types()->at(i); + __ cmp(FieldOperand(object, HeapObject::kMapOffset), map); + if (last && !need_generic) { + DeoptimizeIf(not_equal, instr->environment()); + EmitLoadFieldOrConstantFunction(result, object, map, name); + } else { Label next; - __ cmp(FieldOperand(object, HeapObject::kMapOffset), map); __ j(not_equal, &next, Label::kNear); EmitLoadFieldOrConstantFunction(result, object, map, name); __ jmp(&done, Label::kNear); __ bind(&next); } - Handle<Map> map = instr->hydrogen()->types()->last(); - __ cmp(FieldOperand(object, HeapObject::kMapOffset), map); - if (instr->hydrogen()->need_generic()) { - Label generic; - __ j(not_equal, &generic, Label::kNear); - EmitLoadFieldOrConstantFunction(result, object, map, name); - __ jmp(&done, Label::kNear); - __ bind(&generic); - __ mov(ecx, name); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); - } else { - DeoptimizeIf(not_equal, instr->environment()); - EmitLoadFieldOrConstantFunction(result, object, map, name); - } - __ bind(&done); } + if (need_generic) { + __ mov(ecx, name); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + CallCode(ic, RelocInfo::CODE_TARGET, instr); + } + __ bind(&done); } void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { ASSERT(ToRegister(instr->context()).is(esi)); - ASSERT(ToRegister(instr->object()).is(eax)); + ASSERT(ToRegister(instr->object()).is(edx)); ASSERT(ToRegister(instr->result()).is(eax)); __ mov(ecx, instr->name()); @@ -2533,7 +2529,7 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement( void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->object()).is(edx)); - ASSERT(ToRegister(instr->key()).is(eax)); + ASSERT(ToRegister(instr->key()).is(ecx)); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -2543,25 +2539,29 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { Register result = ToRegister(instr->result()); - // Check for arguments adapter frame. - Label done, adapted; - __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); - __ mov(result, Operand(result, StandardFrameConstants::kContextOffset)); - __ cmp(Operand(result), - Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); - __ j(equal, &adapted, Label::kNear); - - // No arguments adaptor frame. - __ mov(result, Operand(ebp)); - __ jmp(&done, Label::kNear); + if (instr->hydrogen()->from_inlined()) { + __ lea(result, Operand(esp, -2 * kPointerSize)); + } else { + // Check for arguments adapter frame. + Label done, adapted; + __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); + __ mov(result, Operand(result, StandardFrameConstants::kContextOffset)); + __ cmp(Operand(result), + Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); + __ j(equal, &adapted, Label::kNear); + + // No arguments adaptor frame. + __ mov(result, Operand(ebp)); + __ jmp(&done, Label::kNear); - // Arguments adaptor frame present. - __ bind(&adapted); - __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); + // Arguments adaptor frame present. + __ bind(&adapted); + __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); - // Result is the frame pointer for the frame if not adapted and for the real - // frame below the adaptor frame if adapted. - __ bind(&done); + // Result is the frame pointer for the frame if not adapted and for the real + // frame below the adaptor frame if adapted. + __ bind(&done); + } } @@ -2666,7 +2666,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { // Invoke the function. __ bind(&invoke); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator( @@ -2683,6 +2683,11 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) { } +void LCodeGen::DoDrop(LDrop* instr) { + __ Drop(instr->count()); +} + + void LCodeGen::DoThisFunction(LThisFunction* instr) { Register result = ToRegister(instr->result()); __ LoadHeapObject(result, instr->hydrogen()->closure()); @@ -2729,7 +2734,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { void LCodeGen::CallKnownFunction(Handle<JSFunction> function, int arity, LInstruction* instr, - CallKind call_kind) { + CallKind call_kind, + EDIState edi_state) { bool can_invoke_directly = !function->NeedsArgumentsAdaption() || function->shared()->formal_parameter_count() == arity; @@ -2737,7 +2743,9 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, RecordPosition(pointers->position()); if (can_invoke_directly) { - __ LoadHeapObject(edi, function); + if (edi_state == EDI_UNINITIALIZED) { + __ LoadHeapObject(edi, function); + } // Change context if needed. bool change_context = @@ -2780,7 +2788,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { CallKnownFunction(instr->function(), instr->arity(), instr, - CALL_AS_METHOD); + CALL_AS_METHOD, + EDI_UNINITIALIZED); } @@ -2911,11 +2920,13 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { __ cmp(output_reg, 0x80000000u); DeoptimizeIf(equal, instr->environment()); } else { + Label negative_sign; Label done; - // Deoptimize on negative numbers. + // Deoptimize on unordered. __ xorps(xmm_scratch, xmm_scratch); // Zero the register. __ ucomisd(input_reg, xmm_scratch); - DeoptimizeIf(below, instr->environment()); + DeoptimizeIf(parity_even, instr->environment()); + __ j(below, &negative_sign, Label::kNear); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { // Check for negative zero. @@ -2931,10 +2942,21 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { // Use truncating instruction (OK because input is positive). __ cvttsd2si(output_reg, Operand(input_reg)); - // Overflow is signalled with minint. __ cmp(output_reg, 0x80000000u); DeoptimizeIf(equal, instr->environment()); + __ jmp(&done, Label::kNear); + + // Non-zero negative reaches here + __ bind(&negative_sign); + // Truncate, then compare and compensate + __ cvttsd2si(output_reg, Operand(input_reg)); + __ cvtsi2sd(xmm_scratch, output_reg); + __ ucomisd(input_reg, xmm_scratch); + __ j(equal, &done, Label::kNear); + __ sub(output_reg, Immediate(1)); + DeoptimizeIf(overflow, instr->environment()); + __ bind(&done); } } @@ -3226,13 +3248,21 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->function()).is(edi)); ASSERT(instr->HasPointerMap()); - ASSERT(instr->HasDeoptimizationEnvironment()); - LPointerMap* pointers = instr->pointer_map(); - RecordPosition(pointers->position()); - SafepointGenerator generator( - this, pointers, Safepoint::kLazyDeopt); - ParameterCount count(instr->arity()); - __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); + + if (instr->known_function().is_null()) { + LPointerMap* pointers = instr->pointer_map(); + RecordPosition(pointers->position()); + SafepointGenerator generator( + this, pointers, Safepoint::kLazyDeopt); + ParameterCount count(instr->arity()); + __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); + } else { + CallKnownFunction(instr->known_function(), + instr->arity(), + instr, + CALL_AS_METHOD, + EDI_CONTAINS_TARGET); + } } @@ -3287,7 +3317,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { ASSERT(ToRegister(instr->result()).is(eax)); - CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); + CallKnownFunction(instr->target(), + instr->arity(), + instr, + CALL_AS_FUNCTION, + EDI_UNINITIALIZED); } @@ -3460,15 +3494,18 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { void LCodeGen::DoStoreKeyedFastDoubleElement( LStoreKeyedFastDoubleElement* instr) { XMMRegister value = ToDoubleRegister(instr->value()); - Label have_value; - __ ucomisd(value, value); - __ j(parity_odd, &have_value); // NaN. + if (instr->NeedsCanonicalization()) { + Label have_value; - ExternalReference canonical_nan_reference = - ExternalReference::address_of_canonical_non_hole_nan(); - __ movdbl(value, Operand::StaticVariable(canonical_nan_reference)); - __ bind(&have_value); + __ ucomisd(value, value); + __ j(parity_odd, &have_value); // NaN. + + ExternalReference canonical_nan_reference = + ExternalReference::address_of_canonical_non_hole_nan(); + __ movdbl(value, Operand::StaticVariable(canonical_nan_reference)); + __ bind(&have_value); + } Operand double_store_operand = BuildFastArrayOperand( instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS, @@ -4181,12 +4218,21 @@ void LCodeGen::DoCheckMapCommon(Register reg, } -void LCodeGen::DoCheckMap(LCheckMap* instr) { +void LCodeGen::DoCheckMaps(LCheckMaps* instr) { LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister()); Register reg = ToRegister(input); - Handle<Map> map = instr->hydrogen()->map(); - DoCheckMapCommon(reg, map, instr->hydrogen()->mode(), instr->environment()); + + Label success; + SmallMapList* map_set = instr->hydrogen()->map_set(); + for (int i = 0; i < map_set->length() - 1; i++) { + Handle<Map> map = map_set->at(i); + __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP); + __ j(equal, &success); + } + Handle<Map> map = map_set->last(); + DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment()); + __ bind(&success); } @@ -4297,6 +4343,14 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { deferred->entry(), TAG_OBJECT); + __ bind(deferred->exit()); + if (FLAG_debug_code) { + Label is_in_new_space; + __ JumpIfInNewSpace(result, scratch, &is_in_new_space); + __ Abort("Allocated object is not in new-space"); + __ bind(&is_in_new_space); + } + // Load the initial map. Register map = scratch; __ LoadHeapObject(scratch, constructor); @@ -4331,14 +4385,14 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { __ mov(FieldOperand(result, property_offset), scratch); } } - - __ bind(deferred->exit()); } void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { Register result = ToRegister(instr->result()); Handle<JSFunction> constructor = instr->hydrogen()->constructor(); + Handle<Map> initial_map(constructor->initial_map()); + int instance_size = initial_map->instance_size(); // TODO(3095996): Get rid of this. For now, we need to make the // result register contain a valid pointer because it is already @@ -4346,8 +4400,9 @@ void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { __ Set(result, Immediate(0)); PushSafepointRegistersScope scope(this); - __ PushHeapObject(constructor); - CallRuntimeFromDeferred(Runtime::kNewObject, 1, instr, instr->context()); + __ push(Immediate(Smi::FromInt(instance_size))); + CallRuntimeFromDeferred( + Runtime::kAllocateInNewSpace, 1, instr, instr->context()); __ StoreToSafepointRegisterSlot(result, eax); } @@ -4415,6 +4470,13 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, __ LoadHeapObject(ecx, object); __ cmp(source, ecx); __ Assert(equal, "Unexpected object literal boilerplate"); + __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset)); + __ cmp(ecx, Handle<Map>(object->map())); + __ Assert(equal, "Unexpected boilerplate map"); + __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); + __ and_(ecx, Map::kElementsKindMask); + __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift); + __ Assert(equal, "Unexpected boilerplate elements kind"); } // Only elements backing stores for non-COW arrays need to be copied. @@ -4484,9 +4546,10 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high)); } } else if (elements->IsFixedArray()) { + Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); for (int i = 0; i < elements_length; i++) { int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i); - Handle<Object> value = JSObject::GetElement(object, i); + Handle<Object> value(fast_elements->get(i)); if (value->IsJSObject()) { Handle<JSObject> value_object = Handle<JSObject>::cast(value); __ lea(ecx, Operand(result, *offset)); @@ -4510,6 +4573,23 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, void LCodeGen::DoFastLiteral(LFastLiteral* instr) { ASSERT(ToRegister(instr->context()).is(esi)); int size = instr->hydrogen()->total_size(); + ElementsKind boilerplate_elements_kind = + instr->hydrogen()->boilerplate()->GetElementsKind(); + + // Deopt if the literal boilerplate ElementsKind is of a type different than + // the expected one. The check isn't necessary if the boilerplate has already + // been converted to FAST_ELEMENTS. + if (boilerplate_elements_kind != FAST_ELEMENTS) { + __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate()); + __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); + // Load the map's "bit field 2". We only need the first byte, + // but the following masking takes care of that anyway. + __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); + // Retrieve elements_kind from bit field 2. + __ and_(ecx, Map::kElementsKindMask); + __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift); + DeoptimizeIf(not_equal, instr->environment()); + } // Allocate all objects that are part of the literal in one big // allocation. This avoids multiple limit checks. @@ -4794,7 +4874,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { LOperand* key = instr->key(); __ push(ToOperand(obj)); EmitPushTaggedOperand(key); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); // Create safepoint generator that will also ensure enough space in the @@ -4892,7 +4972,7 @@ void LCodeGen::DoIn(LIn* instr) { LOperand* key = instr->key(); EmitPushTaggedOperand(key); EmitPushTaggedOperand(obj); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator( diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index 52befc6974..a2810f05c3 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -206,12 +206,18 @@ class LCodeGen BASE_EMBEDDED { LInstruction* instr, LOperand* context); + enum EDIState { + EDI_UNINITIALIZED, + EDI_CONTAINS_TARGET + }; + // Generate a direct call to a known function. Expects the function // to be in edi. void CallKnownFunction(Handle<JSFunction> function, int arity, LInstruction* instr, - CallKind call_kind); + CallKind call_kind, + EDIState edi_state); void RecordSafepointWithLazyDeopt(LInstruction* instr, SafepointMode safepoint_mode); diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index 2bfbb67bce..5adaf431bd 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/deps/v8/src/ia32/lithium-ia32.cc @@ -729,22 +729,6 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { } -LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( - LInstruction* instr, int ast_id) { - ASSERT(instruction_pending_deoptimization_environment_ == NULL); - ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); - instruction_pending_deoptimization_environment_ = instr; - pending_deoptimization_ast_id_ = ast_id; - return instr; -} - - -void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { - instruction_pending_deoptimization_environment_ = NULL; - pending_deoptimization_ast_id_ = AstNode::kNoNumber; -} - - LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, HInstruction* hinstr, CanDeoptimize can_deoptimize) { @@ -757,8 +741,10 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, if (hinstr->HasObservableSideEffects()) { ASSERT(hinstr->next()->IsSimulate()); HSimulate* sim = HSimulate::cast(hinstr->next()); - instr = SetInstructionPendingDeoptimizationEnvironment( - instr, sim->ast_id()); + ASSERT(instruction_pending_deoptimization_environment_ == NULL); + ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); + instruction_pending_deoptimization_environment_ = instr; + pending_deoptimization_ast_id_ = sim->ast_id(); } // If instruction does not have side-effects lazy deoptimization @@ -776,12 +762,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, } -LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) { - instr->MarkAsSaveDoubles(); - return instr; -} - - LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) { ASSERT(!instr->HasPointerMap()); instr->set_pointer_map(new(zone()) LPointerMap(position_)); @@ -1330,6 +1310,7 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { ASSERT(instr->value()->representation().IsInteger32()); ASSERT(instr->representation().IsInteger32()); + if (instr->HasNoUses()) return NULL; LOperand* input = UseRegisterAtStart(instr->value()); LBitNotI* result = new(zone()) LBitNotI(input); return DefineSameAsFirst(result); @@ -1354,6 +1335,12 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { } +LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) { + UNIMPLEMENTED(); + return NULL; +} + + LInstruction* LChunkBuilder::DoMod(HMod* instr) { if (instr->representation().IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); @@ -1800,9 +1787,9 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { } -LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) { +LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LOperand* value = UseRegisterAtStart(instr->value()); - LCheckMap* result = new(zone()) LCheckMap(value); + LCheckMaps* result = new(zone()) LCheckMaps(value); return AssignEnvironment(result); } @@ -1862,7 +1849,7 @@ LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) { LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { LOperand* context = UseFixed(instr->context(), esi); - LOperand* global_object = UseFixed(instr->global_object(), eax); + LOperand* global_object = UseFixed(instr->global_object(), edx); LLoadGlobalGeneric* result = new(zone()) LLoadGlobalGeneric(context, global_object); return MarkAsCall(DefineFixed(result, eax), instr); @@ -1922,7 +1909,7 @@ LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic( ASSERT(instr->representation().IsTagged()); if (instr->need_generic()) { LOperand* context = UseFixed(instr->context(), esi); - LOperand* obj = UseFixed(instr->object(), eax); + LOperand* obj = UseFixed(instr->object(), edx); LLoadNamedFieldPolymorphic* result = new(zone()) LLoadNamedFieldPolymorphic(context, obj); return MarkAsCall(DefineFixed(result, eax), instr); @@ -1938,7 +1925,7 @@ LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic( LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* context = UseFixed(instr->context(), esi); - LOperand* object = UseFixed(instr->object(), eax); + LOperand* object = UseFixed(instr->object(), edx); LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(context, object); return MarkAsCall(DefineFixed(result, eax), instr); } @@ -2017,7 +2004,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LOperand* context = UseFixed(instr->context(), esi); LOperand* object = UseFixed(instr->object(), edx); - LOperand* key = UseFixed(instr->key(), eax); + LOperand* key = UseFixed(instr->key(), ecx); LLoadKeyedGeneric* result = new(zone()) LLoadKeyedGeneric(context, object, key); @@ -2348,9 +2335,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { ASSERT(pending_deoptimization_ast_id_ == instr->ast_id()); LLazyBailout* lazy_bailout = new(zone()) LLazyBailout; LInstruction* result = AssignEnvironment(lazy_bailout); + // Store the lazy deopt environment with the instruction if needed. Right + // now it is only used for LInstanceOfKnownGlobal. instruction_pending_deoptimization_environment_-> - set_deoptimization_environment(result->environment()); - ClearInstructionPendingDeoptimizationEnvironment(); + SetDeferredLazyDeoptimizationEnvironment(result->environment()); + instruction_pending_deoptimization_environment_ = NULL; + pending_deoptimization_ast_id_ = AstNode::kNoNumber; return result; } @@ -2380,6 +2370,9 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { undefined, instr->call_kind(), instr->is_construct()); + if (instr->arguments_var() != NULL) { + inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject()); + } current_block_->UpdateEnvironment(inner); chunk_->AddInlinedClosure(instr->closure()); return NULL; @@ -2387,10 +2380,20 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { + LInstruction* pop = NULL; + + HEnvironment* env = current_block_->last_environment(); + + if (instr->arguments_pushed()) { + int argument_count = env->arguments_environment()->parameter_count(); + pop = new(zone()) LDrop(argument_count); + argument_count_ -= argument_count; + } + HEnvironment* outer = current_block_->last_environment()-> DiscardInlined(false); current_block_->UpdateEnvironment(outer); - return NULL; + return pop; } diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h index 4ecce96d0f..09f0b0d729 100644 --- a/deps/v8/src/ia32/lithium-ia32.h +++ b/deps/v8/src/ia32/lithium-ia32.h @@ -65,7 +65,7 @@ class LCodeGen; V(CallStub) \ V(CheckFunction) \ V(CheckInstanceType) \ - V(CheckMap) \ + V(CheckMaps) \ V(CheckNonSmi) \ V(CheckPrototypeMaps) \ V(CheckSmi) \ @@ -174,7 +174,8 @@ class LCodeGen; V(CheckMapValue) \ V(LoadFieldByIndex) \ V(DateField) \ - V(WrapReceiver) + V(WrapReceiver) \ + V(Drop) #define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \ @@ -198,8 +199,7 @@ class LInstruction: public ZoneObject { LInstruction() : environment_(NULL), hydrogen_value_(NULL), - is_call_(false), - is_save_doubles_(false) { } + is_call_(false) { } virtual ~LInstruction() { } virtual void CompileToNative(LCodeGen* generator) = 0; @@ -242,22 +242,12 @@ class LInstruction: public ZoneObject { void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; } HValue* hydrogen_value() const { return hydrogen_value_; } - void set_deoptimization_environment(LEnvironment* env) { - deoptimization_environment_.set(env); - } - LEnvironment* deoptimization_environment() const { - return deoptimization_environment_.get(); - } - bool HasDeoptimizationEnvironment() const { - return deoptimization_environment_.is_set(); - } + virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { } void MarkAsCall() { is_call_ = true; } - void MarkAsSaveDoubles() { is_save_doubles_ = true; } // Interface to the register allocator and iterators. bool IsMarkedAsCall() const { return is_call_; } - bool IsMarkedAsSaveDoubles() const { return is_save_doubles_; } virtual bool HasResult() const = 0; virtual LOperand* result() = 0; @@ -278,9 +268,7 @@ class LInstruction: public ZoneObject { LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; - SetOncePointer<LEnvironment> deoptimization_environment_; bool is_call_; - bool is_save_doubles_; }; @@ -525,9 +513,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { class LArgumentsElements: public LTemplateInstruction<1, 0, 0> { public: - LArgumentsElements() { } - DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements") + DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements) }; @@ -844,6 +831,15 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 2, 1> { DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) Handle<JSFunction> function() const { return hydrogen()->function(); } + LEnvironment* GetDeferredLazyDeoptimizationEnvironment() { + return lazy_deopt_env_; + } + virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { + lazy_deopt_env_ = env; + } + + private: + LEnvironment* lazy_deopt_env_; }; @@ -1401,6 +1397,19 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { }; +class LDrop: public LTemplateInstruction<0, 0, 0> { + public: + explicit LDrop(int count) : count_(count) { } + + int count() const { return count_; } + + DECLARE_CONCRETE_INSTRUCTION(Drop, "drop") + + private: + int count_; +}; + + class LThisFunction: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function") @@ -1489,6 +1498,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 2, 0> { virtual void PrintDataTo(StringStream* stream); int arity() const { return hydrogen()->argument_count() - 1; } + Handle<JSFunction> known_function() { return hydrogen()->known_function(); } }; @@ -1787,6 +1797,8 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } + + bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } }; @@ -1949,14 +1961,14 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 1> { }; -class LCheckMap: public LTemplateInstruction<0, 1, 0> { +class LCheckMaps: public LTemplateInstruction<0, 1, 0> { public: - explicit LCheckMap(LOperand* value) { + explicit LCheckMaps(LOperand* value) { inputs_[0] = value; } - DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map") - DECLARE_HYDROGEN_ACCESSOR(CheckMap) + DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps") + DECLARE_HYDROGEN_ACCESSOR(CheckMaps) }; @@ -2471,11 +2483,6 @@ class LChunkBuilder BASE_EMBEDDED { LInstruction* instr, HInstruction* hinstr, CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); - LInstruction* MarkAsSaveDoubles(LInstruction* instr); - - LInstruction* SetInstructionPendingDeoptimizationEnvironment( - LInstruction* instr, int ast_id); - void ClearInstructionPendingDeoptimizationEnvironment(); LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, int* argument_index_accumulator); diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 60e38a6c13..c31b0c24be 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -2566,7 +2566,7 @@ bool AreAliased(Register r1, Register r2, Register r3, Register r4) { CodePatcher::CodePatcher(byte* address, int size) : address_(address), size_(size), - masm_(Isolate::Current(), address, size + Assembler::kGap) { + masm_(NULL, address, size + Assembler::kGap) { // Create a new macro assembler pointing to the address of the code to patch. // The size is adjusted with kGap on order for the assembler to generate size // bytes of instructions without failing with buffer size constraints. diff --git a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc index 04d6b62c80..0029f33b1a 100644 --- a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc @@ -501,9 +501,13 @@ void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c, void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c, uint32_t mask, Label* on_equal) { - __ mov(eax, current_character()); - __ and_(eax, mask); - __ cmp(eax, c); + if (c == 0) { + __ test(current_character(), Immediate(mask)); + } else { + __ mov(eax, mask); + __ and_(eax, current_character()); + __ cmp(eax, c); + } BranchOrBacktrack(equal, on_equal); } @@ -511,9 +515,13 @@ void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c, void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c, uint32_t mask, Label* on_not_equal) { - __ mov(eax, current_character()); - __ and_(eax, mask); - __ cmp(eax, c); + if (c == 0) { + __ test(current_character(), Immediate(mask)); + } else { + __ mov(eax, mask); + __ and_(eax, current_character()); + __ cmp(eax, c); + } BranchOrBacktrack(not_equal, on_not_equal); } @@ -525,12 +533,51 @@ void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd( Label* on_not_equal) { ASSERT(minus < String::kMaxUtf16CodeUnit); __ lea(eax, Operand(current_character(), -minus)); - __ and_(eax, mask); - __ cmp(eax, c); + if (c == 0) { + __ test(eax, Immediate(mask)); + } else { + __ and_(eax, mask); + __ cmp(eax, c); + } BranchOrBacktrack(not_equal, on_not_equal); } +void RegExpMacroAssemblerIA32::CheckCharacterInRange( + uc16 from, + uc16 to, + Label* on_in_range) { + __ lea(eax, Operand(current_character(), -from)); + __ cmp(eax, to - from); + BranchOrBacktrack(below_equal, on_in_range); +} + + +void RegExpMacroAssemblerIA32::CheckCharacterNotInRange( + uc16 from, + uc16 to, + Label* on_not_in_range) { + __ lea(eax, Operand(current_character(), -from)); + __ cmp(eax, to - from); + BranchOrBacktrack(above, on_not_in_range); +} + + +void RegExpMacroAssemblerIA32::CheckBitInTable( + Handle<ByteArray> table, + Label* on_bit_set) { + __ mov(eax, Immediate(table)); + Register index = current_character(); + if (mode_ != ASCII || kTableMask != String::kMaxAsciiCharCode) { + __ mov(ebx, kTableSize - 1); + __ and_(ebx, current_character()); + index = ebx; + } + __ cmpb(FieldOperand(eax, index, times_1, ByteArray::kHeaderSize), 0); + BranchOrBacktrack(not_equal, on_bit_set); +} + + bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, Label* on_no_match) { // Range checks (c in min..max) are generally implemented by an unsigned diff --git a/deps/v8/src/ia32/regexp-macro-assembler-ia32.h b/deps/v8/src/ia32/regexp-macro-assembler-ia32.h index d504470280..78cd06958c 100644 --- a/deps/v8/src/ia32/regexp-macro-assembler-ia32.h +++ b/deps/v8/src/ia32/regexp-macro-assembler-ia32.h @@ -78,6 +78,14 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler { uc16 minus, uc16 mask, Label* on_not_equal); + virtual void CheckCharacterInRange(uc16 from, + uc16 to, + Label* on_in_range); + virtual void CheckCharacterNotInRange(uc16 from, + uc16 to, + Label* on_not_in_range); + virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set); + // Checks whether the given offset from the current position is before // the end of the string. virtual void CheckPosition(int cp_offset, Label* on_outside_input); diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index fd267798cf..e148e2f525 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -406,6 +406,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, __ push(receiver); __ push(holder); __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset)); + __ push(Immediate(reinterpret_cast<int>(masm->isolate()))); } @@ -419,12 +420,12 @@ static void CompileCallLoadPropertyWithInterceptor( __ CallExternalReference( ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), masm->isolate()), - 5); + 6); } // Number of pointers to be reserved on stack for fast API call. -static const int kFastApiCallArguments = 3; +static const int kFastApiCallArguments = 4; // Reserves space for the extra arguments to API function in the @@ -472,10 +473,11 @@ static void GenerateFastApiCall(MacroAssembler* masm, // -- esp[8] : api function // (first fast api call extra argument) // -- esp[12] : api call data - // -- esp[16] : last argument + // -- esp[16] : isolate + // -- esp[20] : last argument // -- ... - // -- esp[(argc + 3) * 4] : first argument - // -- esp[(argc + 4) * 4] : receiver + // -- esp[(argc + 4) * 4] : first argument + // -- esp[(argc + 5) * 4] : receiver // ----------------------------------- // Get the function and setup the context. Handle<JSFunction> function = optimization.constant_function(); @@ -493,9 +495,11 @@ static void GenerateFastApiCall(MacroAssembler* masm, } else { __ mov(Operand(esp, 3 * kPointerSize), Immediate(call_data)); } + __ mov(Operand(esp, 4 * kPointerSize), + Immediate(reinterpret_cast<int>(masm->isolate()))); // Prepare arguments. - __ lea(eax, Operand(esp, 3 * kPointerSize)); + __ lea(eax, Operand(esp, 4 * kPointerSize)); const int kApiArgc = 1; // API function gets reference to the v8::Arguments. @@ -679,7 +683,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { __ CallExternalReference( ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), masm->isolate()), - 5); + 6); // Restore the name_ register. __ pop(name_); @@ -746,8 +750,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, Register scratch, Label* miss_label) { // Check that the map of the object hasn't changed. + CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS + : REQUIRE_EXACT_MAP; __ CheckMap(receiver_reg, Handle<Map>(object->map()), - miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); + miss_label, DO_SMI_CHECK, mode); // Perform global security token check if needed. if (object->IsJSGlobalProxy()) { @@ -1032,6 +1038,7 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, } else { __ push(Immediate(Handle<Object>(callback->data()))); } + __ push(Immediate(reinterpret_cast<int>(isolate()))); // Save a pointer to where we pushed the arguments pointer. // This will be passed as the const AccessorInfo& to the C++ callback. @@ -1042,9 +1049,9 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, __ push(scratch3); // Restore return address. - // 3 elements array for v8::Arguments::values_, handler for name and pointer + // 4 elements array for v8::Arguments::values_, handler for name and pointer // to the values (it considered as smi in GC). - const int kStackSpace = 5; + const int kStackSpace = 6; const int kApiArgc = 2; __ PrepareCallApiFunction(kApiArgc); @@ -1122,13 +1129,20 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, name, miss); ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); + // Preserve the receiver register explicitly whenever it is different from + // the holder and it is needed should the interceptor return without any + // result. The CALLBACKS case needs the receiver to be passed into C++ code, + // the FIELD case might cause a miss during the prototype check. + bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); + bool must_preserve_receiver_reg = !receiver.is(holder_reg) && + (lookup->type() == CALLBACKS || must_perfrom_prototype_check); + // Save necessary data before invoking an interceptor. // Requires a frame to make GC aware of pushed pointers. { FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { - // CALLBACKS case needs a receiver to be passed into C++ callback. + if (must_preserve_receiver_reg) { __ push(receiver); } __ push(holder_reg); @@ -1151,10 +1165,17 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, frame_scope.GenerateLeaveFrame(); __ ret(0); + // Clobber registers when generating debug-code to provoke errors. __ bind(&interceptor_failed); + if (FLAG_debug_code) { + __ mov(receiver, Immediate(BitCast<int32_t>(kZapValue))); + __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue))); + __ mov(name_reg, Immediate(BitCast<int32_t>(kZapValue))); + } + __ pop(name_reg); __ pop(holder_reg); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { + if (must_preserve_receiver_reg) { __ pop(receiver); } @@ -1163,7 +1184,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, // Check that the maps from interceptor's holder to lookup's holder // haven't changed. And load lookup's holder into holder_reg. - if (*interceptor_holder != lookup->holder()) { + if (must_perfrom_prototype_check) { holder_reg = CheckPrototypes(interceptor_holder, holder_reg, Handle<JSObject>(lookup->holder()), @@ -1197,6 +1218,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, __ push(holder_reg); __ mov(holder_reg, Immediate(callback)); __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); + __ push(Immediate(reinterpret_cast<int>(isolate()))); __ push(holder_reg); __ push(name_reg); __ push(scratch2); // restore return address @@ -1204,7 +1226,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadCallbackProperty), masm()->isolate()); - __ TailCallExternalReference(ref, 5, 1); + __ TailCallExternalReference(ref, 6, 1); } } else { // !compile_followup_inline // Call the runtime system to load the interceptor. @@ -1220,7 +1242,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); - __ TailCallExternalReference(ref, 5, 1); + __ TailCallExternalReference(ref, 6, 1); } } @@ -2158,7 +2180,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall( name, depth, &miss); // Move the return address on top of the stack. - __ mov(eax, Operand(esp, 3 * kPointerSize)); + __ mov(eax, Operand(esp, 4 * kPointerSize)); __ mov(Operand(esp, 0 * kPointerSize), eax); // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains @@ -2687,27 +2709,27 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name, Handle<JSObject> object, Handle<JSObject> last) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; // Check that the receiver isn't a smi. - __ JumpIfSmi(eax, &miss); + __ JumpIfSmi(edx, &miss); ASSERT(last->IsGlobalObject() || last->HasFastProperties()); // Check the maps of the full prototype chain. Also check that // global property cells up to (but not including) the last object // in the prototype chain are empty. - CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss); + CheckPrototypes(object, edx, last, ebx, eax, edi, name, &miss); // If the last object in the prototype chain is a global object, // check that the global property cell is empty. if (last->IsGlobalObject()) { GenerateCheckPropertyCell( - masm(), Handle<GlobalObject>::cast(last), name, edx, &miss); + masm(), Handle<GlobalObject>::cast(last), name, eax, &miss); } // Return undefined if maps of the full prototype chain are still the @@ -2728,13 +2750,13 @@ Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object, int index, Handle<String> name) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; - GenerateLoadField(object, holder, eax, ebx, edx, edi, index, name, &miss); + GenerateLoadField(object, holder, edx, ebx, eax, edi, index, name, &miss); __ bind(&miss); GenerateLoadMiss(masm(), Code::LOAD_IC); @@ -2749,13 +2771,13 @@ Handle<Code> LoadStubCompiler::CompileLoadCallback( Handle<JSObject> holder, Handle<AccessorInfo> callback) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; - GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, edi, callback, + GenerateLoadCallback(object, holder, edx, ecx, ebx, eax, edi, callback, name, &miss); __ bind(&miss); GenerateLoadMiss(masm(), Code::LOAD_IC); @@ -2770,13 +2792,13 @@ Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object, Handle<JSFunction> value, Handle<String> name) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; - GenerateLoadConstant(object, holder, eax, ebx, edx, edi, value, name, &miss); + GenerateLoadConstant(object, holder, edx, ebx, eax, edi, value, name, &miss); __ bind(&miss); GenerateLoadMiss(masm(), Code::LOAD_IC); @@ -2789,8 +2811,8 @@ Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver, Handle<JSObject> holder, Handle<String> name) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; @@ -2800,7 +2822,7 @@ Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> receiver, // TODO(368): Compile in the whole chain: all the interceptors in // prototypes and ultimate answer. - GenerateLoadInterceptor(receiver, holder, &lookup, eax, ecx, edx, ebx, edi, + GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi, name, &miss); __ bind(&miss); @@ -2818,15 +2840,15 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal( Handle<String> name, bool is_dont_delete) { // ----------- S t a t e ------------- - // -- eax : receiver // -- ecx : name + // -- edx : receiver // -- esp[0] : return address // ----------------------------------- Label miss; // Check that the maps haven't changed. - __ JumpIfSmi(eax, &miss); - CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss); + __ JumpIfSmi(edx, &miss); + CheckPrototypes(object, edx, holder, ebx, eax, edi, name, &miss); // Get the value from the cell. if (Serializer::enabled()) { @@ -2864,7 +2886,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name, Handle<JSObject> holder, int index) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -2874,10 +2896,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name, __ IncrementCounter(counters->keyed_load_field(), 1); // Check that the name has not changed. - __ cmp(eax, Immediate(name)); + __ cmp(ecx, Immediate(name)); __ j(not_equal, &miss); - GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss); + GenerateLoadField(receiver, holder, edx, ebx, eax, edi, index, name, &miss); __ bind(&miss); __ DecrementCounter(counters->keyed_load_field(), 1); @@ -2894,7 +2916,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback( Handle<JSObject> holder, Handle<AccessorInfo> callback) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -2904,10 +2926,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback( __ IncrementCounter(counters->keyed_load_callback(), 1); // Check that the name has not changed. - __ cmp(eax, Immediate(name)); + __ cmp(ecx, Immediate(name)); __ j(not_equal, &miss); - GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, edi, callback, + GenerateLoadCallback(receiver, holder, edx, ecx, ebx, eax, edi, callback, name, &miss); __ bind(&miss); @@ -2925,7 +2947,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant( Handle<JSObject> holder, Handle<JSFunction> value) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -2935,11 +2957,11 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant( __ IncrementCounter(counters->keyed_load_constant_function(), 1); // Check that the name has not changed. - __ cmp(eax, Immediate(name)); + __ cmp(ecx, Immediate(name)); __ j(not_equal, &miss); GenerateLoadConstant( - receiver, holder, edx, ebx, ecx, edi, value, name, &miss); + receiver, holder, edx, ebx, eax, edi, value, name, &miss); __ bind(&miss); __ DecrementCounter(counters->keyed_load_constant_function(), 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); @@ -2954,7 +2976,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor( Handle<JSObject> holder, Handle<String> name) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -2964,12 +2986,12 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor( __ IncrementCounter(counters->keyed_load_interceptor(), 1); // Check that the name has not changed. - __ cmp(eax, Immediate(name)); + __ cmp(ecx, Immediate(name)); __ j(not_equal, &miss); LookupResult lookup(isolate()); LookupPostInterceptor(holder, name, &lookup); - GenerateLoadInterceptor(receiver, holder, &lookup, edx, eax, ecx, ebx, edi, + GenerateLoadInterceptor(receiver, holder, &lookup, edx, ecx, eax, ebx, edi, name, &miss); __ bind(&miss); __ DecrementCounter(counters->keyed_load_interceptor(), 1); @@ -2983,7 +3005,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor( Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength( Handle<String> name) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -2993,10 +3015,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength( __ IncrementCounter(counters->keyed_load_array_length(), 1); // Check that the name has not changed. - __ cmp(eax, Immediate(name)); + __ cmp(ecx, Immediate(name)); __ j(not_equal, &miss); - GenerateLoadArrayLength(masm(), edx, ecx, &miss); + GenerateLoadArrayLength(masm(), edx, eax, &miss); __ bind(&miss); __ DecrementCounter(counters->keyed_load_array_length(), 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); @@ -3009,7 +3031,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadArrayLength( Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength( Handle<String> name) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3019,10 +3041,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength( __ IncrementCounter(counters->keyed_load_string_length(), 1); // Check that the name has not changed. - __ cmp(eax, Immediate(name)); + __ cmp(ecx, Immediate(name)); __ j(not_equal, &miss); - GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); + GenerateLoadStringLength(masm(), edx, eax, ebx, &miss, true); __ bind(&miss); __ DecrementCounter(counters->keyed_load_string_length(), 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); @@ -3035,7 +3057,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadStringLength( Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype( Handle<String> name) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3045,10 +3067,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype( __ IncrementCounter(counters->keyed_load_function_prototype(), 1); // Check that the name has not changed. - __ cmp(eax, Immediate(name)); + __ cmp(ecx, Immediate(name)); __ j(not_equal, &miss); - GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); + GenerateLoadFunctionPrototype(masm(), edx, eax, ebx, &miss); __ bind(&miss); __ DecrementCounter(counters->keyed_load_function_prototype(), 1); GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); @@ -3061,7 +3083,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadFunctionPrototype( Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( Handle<Map> receiver_map) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3082,7 +3104,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic( MapHandleList* receiver_maps, CodeHandleList* handler_ics) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3246,7 +3268,7 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3254,21 +3276,15 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - __ JumpIfNotSmi(eax, &miss_force_generic); - __ mov(ebx, eax); + __ JumpIfNotSmi(ecx, &miss_force_generic); + __ mov(ebx, ecx); __ SmiUntag(ebx); - __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); + __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); // Push receiver on the stack to free up a register for the dictionary // probing. __ push(edx); - __ LoadFromNumberDictionary(&slow, - ecx, - eax, - ebx, - edx, - edi, - eax); + __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax); // Pop receiver before returning. __ pop(edx); __ ret(0); @@ -3277,7 +3293,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( __ pop(edx); // ----------- S t a t e ------------- - // -- eax : value // -- ecx : key // -- edx : receiver // -- esp[0] : return address @@ -3289,7 +3304,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( __ bind(&miss_force_generic); // ----------- S t a t e ------------- - // -- eax : value // -- ecx : key // -- edx : receiver // -- esp[0] : return address @@ -3301,11 +3315,44 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( } +static void GenerateSmiKeyCheck(MacroAssembler* masm, + Register key, + Register scratch, + XMMRegister xmm_scratch0, + XMMRegister xmm_scratch1, + Label* fail) { + // Check that key is a smi and if SSE2 is available a heap number + // containing a smi and branch if the check fails. + if (CpuFeatures::IsSupported(SSE2)) { + CpuFeatures::Scope use_sse2(SSE2); + Label key_ok; + __ JumpIfSmi(key, &key_ok); + __ cmp(FieldOperand(key, HeapObject::kMapOffset), + Immediate(Handle<Map>(masm->isolate()->heap()->heap_number_map()))); + __ j(not_equal, fail); + __ movdbl(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset)); + __ cvttsd2si(scratch, Operand(xmm_scratch0)); + __ cvtsi2sd(xmm_scratch1, scratch); + __ ucomisd(xmm_scratch1, xmm_scratch0); + __ j(not_equal, fail); + __ j(parity_even, fail); // NaN. + // Check if the key fits in the smi range. + __ cmp(scratch, 0xc0000000); + __ j(sign, fail); + __ SmiTag(scratch); + __ mov(key, scratch); + __ bind(&key_ok); + } else { + __ JumpIfNotSmi(key, fail); + } +} + + void KeyedLoadStubCompiler::GenerateLoadExternalArray( MacroAssembler* masm, ElementsKind elements_kind) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3314,41 +3361,41 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(eax, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic); // Check that the index is in range. __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); - __ cmp(eax, FieldOperand(ebx, ExternalArray::kLengthOffset)); + __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); // Unsigned comparison catches both negative and too-large values. __ j(above_equal, &miss_force_generic); __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); // ebx: base pointer of external storage switch (elements_kind) { case EXTERNAL_BYTE_ELEMENTS: - __ SmiUntag(eax); // Untag the index. - __ movsx_b(eax, Operand(ebx, eax, times_1, 0)); + __ SmiUntag(ecx); // Untag the index. + __ movsx_b(eax, Operand(ebx, ecx, times_1, 0)); break; case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case EXTERNAL_PIXEL_ELEMENTS: - __ SmiUntag(eax); // Untag the index. - __ movzx_b(eax, Operand(ebx, eax, times_1, 0)); + __ SmiUntag(ecx); // Untag the index. + __ movzx_b(eax, Operand(ebx, ecx, times_1, 0)); break; case EXTERNAL_SHORT_ELEMENTS: - __ movsx_w(eax, Operand(ebx, eax, times_1, 0)); + __ movsx_w(eax, Operand(ebx, ecx, times_1, 0)); break; case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ movzx_w(eax, Operand(ebx, eax, times_1, 0)); + __ movzx_w(eax, Operand(ebx, ecx, times_1, 0)); break; case EXTERNAL_UNSIGNED_INT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: - __ mov(ecx, Operand(ebx, eax, times_2, 0)); + __ mov(eax, Operand(ebx, ecx, times_2, 0)); break; case EXTERNAL_FLOAT_ELEMENTS: - __ fld_s(Operand(ebx, eax, times_2, 0)); + __ fld_s(Operand(ebx, ecx, times_2, 0)); break; case EXTERNAL_DOUBLE_ELEMENTS: - __ fld_d(Operand(ebx, eax, times_4, 0)); + __ fld_d(Operand(ebx, ecx, times_4, 0)); break; default: UNREACHABLE(); @@ -3356,7 +3403,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( } // For integer array types: - // ecx: value + // eax: value // For floating-point array type: // FP(0): value @@ -3367,18 +3414,17 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // it to a HeapNumber. Label box_int; if (elements_kind == EXTERNAL_INT_ELEMENTS) { - __ cmp(ecx, 0xC0000000); + __ cmp(eax, 0xc0000000); __ j(sign, &box_int); } else { ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind); // The test is different for unsigned int values. Since we need // the value to be in the range of a positive smi, we can't // handle either of the top two bits being set in the value. - __ test(ecx, Immediate(0xC0000000)); + __ test(eax, Immediate(0xc0000000)); __ j(not_zero, &box_int); } - __ mov(eax, ecx); __ SmiTag(eax); __ ret(0); @@ -3387,33 +3433,31 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // Allocate a HeapNumber for the int and perform int-to-double // conversion. if (elements_kind == EXTERNAL_INT_ELEMENTS) { - __ push(ecx); + __ push(eax); __ fild_s(Operand(esp, 0)); - __ pop(ecx); + __ pop(eax); } else { ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind); // Need to zero-extend the value. // There's no fild variant for unsigned values, so zero-extend // to a 64-bit int manually. __ push(Immediate(0)); - __ push(ecx); + __ push(eax); __ fild_d(Operand(esp, 0)); - __ pop(ecx); - __ pop(ecx); + __ pop(eax); + __ pop(eax); } // FP(0): value - __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); + __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation); // Set the value. - __ mov(eax, ecx); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ ret(0); } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { // For the floating-point array type, we need to always allocate a // HeapNumber. - __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); + __ AllocateHeapNumber(eax, ebx, edi, &failed_allocation); // Set the value. - __ mov(eax, ecx); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ ret(0); } else { @@ -3433,7 +3477,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ IncrementCounter(counters->keyed_load_external_array_slow(), 1); // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3442,7 +3486,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ jmp(ic, RelocInfo::CODE_TARGET); // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3459,7 +3503,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( MacroAssembler* masm, ElementsKind elements_kind) { // ----------- S t a t e ------------- - // -- eax : key + // -- eax : value + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3468,8 +3513,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(ecx, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic); // Check that the index is in range. __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); @@ -3564,12 +3609,39 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // (code-stubs-ia32.cc) is roughly what is needed here though the // conversion failure case does not need to be handled. if (CpuFeatures::IsSupported(SSE2)) { - if (elements_kind != EXTERNAL_INT_ELEMENTS && - elements_kind != EXTERNAL_UNSIGNED_INT_ELEMENTS) { + if ((elements_kind == EXTERNAL_INT_ELEMENTS || + elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) && + CpuFeatures::IsSupported(SSE3)) { + CpuFeatures::Scope scope(SSE3); + // fisttp stores values as signed integers. To represent the + // entire range of int and unsigned int arrays, store as a + // 64-bit int and discard the high 32 bits. + __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); + __ sub(esp, Immediate(2 * kPointerSize)); + __ fisttp_d(Operand(esp, 0)); + + // If conversion failed (NaN, infinity, or a number outside + // signed int64 range), the result is 0x8000000000000000, and + // we must handle this case in the runtime. + Label ok; + __ cmp(Operand(esp, kPointerSize), Immediate(0x80000000u)); + __ j(not_equal, &ok); + __ cmp(Operand(esp, 0), Immediate(0)); + __ j(not_equal, &ok); + __ add(esp, Immediate(2 * kPointerSize)); // Restore the stack. + __ jmp(&slow); + + __ bind(&ok); + __ pop(ebx); + __ add(esp, Immediate(kPointerSize)); + __ mov(Operand(edi, ecx, times_2, 0), ebx); + } else { ASSERT(CpuFeatures::IsSupported(SSE2)); CpuFeatures::Scope scope(SSE2); __ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset)); - // ecx: untagged integer value + __ cmp(ebx, 0x80000000u); + __ j(equal, &slow); + // ebx: untagged integer value switch (elements_kind) { case EXTERNAL_PIXEL_ELEMENTS: __ ClampUint8(ebx); @@ -3583,41 +3655,14 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: __ mov_w(Operand(edi, ecx, times_1, 0), ebx); break; + case EXTERNAL_INT_ELEMENTS: + case EXTERNAL_UNSIGNED_INT_ELEMENTS: + __ mov(Operand(edi, ecx, times_2, 0), ebx); + break; default: UNREACHABLE(); break; } - } else { - if (CpuFeatures::IsSupported(SSE3)) { - CpuFeatures::Scope scope(SSE3); - // fisttp stores values as signed integers. To represent the - // entire range of int and unsigned int arrays, store as a - // 64-bit int and discard the high 32 bits. - // If the value is NaN or +/-infinity, the result is 0x80000000, - // which is automatically zero when taken mod 2^n, n < 32. - __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); - __ sub(esp, Immediate(2 * kPointerSize)); - __ fisttp_d(Operand(esp, 0)); - __ pop(ebx); - __ add(esp, Immediate(kPointerSize)); - } else { - ASSERT(CpuFeatures::IsSupported(SSE2)); - CpuFeatures::Scope scope(SSE2); - // We can easily implement the correct rounding behavior for the - // range [0, 2^31-1]. For the time being, to keep this code simple, - // make the slow runtime call for values outside this range. - // Note: we could do better for signed int arrays. - __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); - // We will need the key if we have to make the slow runtime call. - __ push(ebx); - __ LoadPowerOf2(xmm1, ebx, 31); - __ pop(ebx); - __ ucomisd(xmm1, xmm0); - __ j(above_equal, &slow); - __ cvttsd2si(ebx, Operand(xmm0)); - } - // ebx: untagged integer value - __ mov(Operand(edi, ecx, times_2, 0), ebx); } __ ret(0); // Return original value. } @@ -3655,7 +3700,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3664,19 +3709,19 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(eax, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic); // Get the elements array. - __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); - __ AssertFastElements(ecx); + __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); + __ AssertFastElements(eax); // Check that the key is within bounds. - __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); + __ cmp(ecx, FieldOperand(eax, FixedArray::kLengthOffset)); __ j(above_equal, &miss_force_generic); // Load the result and make sure it's not the hole. - __ mov(ebx, Operand(ecx, eax, times_2, + __ mov(ebx, Operand(eax, ecx, times_2, FixedArray::kHeaderSize - kHeapObjectTag)); __ cmp(ebx, masm->isolate()->factory()->the_hole_value()); __ j(equal, &miss_force_generic); @@ -3693,7 +3738,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( MacroAssembler* masm) { // ----------- S t a t e ------------- - // -- eax : key + // -- ecx : key // -- edx : receiver // -- esp[0] : return address // ----------------------------------- @@ -3702,39 +3747,38 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(eax, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, ecx, eax, xmm0, xmm1, &miss_force_generic); // Get the elements array. - __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); - __ AssertFastElements(ecx); + __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); + __ AssertFastElements(eax); // Check that the key is within bounds. - __ cmp(eax, FieldOperand(ecx, FixedDoubleArray::kLengthOffset)); + __ cmp(ecx, FieldOperand(eax, FixedDoubleArray::kLengthOffset)); __ j(above_equal, &miss_force_generic); // Check for the hole uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); - __ cmp(FieldOperand(ecx, eax, times_4, offset), Immediate(kHoleNanUpper32)); + __ cmp(FieldOperand(eax, ecx, times_4, offset), Immediate(kHoleNanUpper32)); __ j(equal, &miss_force_generic); // Always allocate a heap number for the result. if (CpuFeatures::IsSupported(SSE2)) { CpuFeatures::Scope use_sse2(SSE2); - __ movdbl(xmm0, FieldOperand(ecx, eax, times_4, + __ movdbl(xmm0, FieldOperand(eax, ecx, times_4, FixedDoubleArray::kHeaderSize)); } else { - __ fld_d(FieldOperand(ecx, eax, times_4, FixedDoubleArray::kHeaderSize)); + __ fld_d(FieldOperand(eax, ecx, times_4, FixedDoubleArray::kHeaderSize)); } - __ AllocateHeapNumber(ecx, ebx, edi, &slow_allocate_heapnumber); + __ AllocateHeapNumber(eax, ebx, edi, &slow_allocate_heapnumber); // Set the value. if (CpuFeatures::IsSupported(SSE2)) { CpuFeatures::Scope use_sse2(SSE2); - __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); + __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); } else { - __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset)); + __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); } - __ mov(eax, ecx); __ ret(0); __ bind(&slow_allocate_heapnumber); @@ -3771,8 +3815,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(ecx, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic); if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { __ JumpIfNotSmi(eax, &transition_elements_kind); @@ -3926,8 +3970,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(ecx, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, ecx, ebx, xmm0, xmm1, &miss_force_generic); // Get the elements array. __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); @@ -3988,6 +4032,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements); __ AllocateInNewSpace(size, edi, ebx, ecx, &prepare_slow, TAG_OBJECT); + // Restore the key, which is known to be the array length. __ mov(ecx, Immediate(0)); diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index c7621277db..9772b94a98 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -296,58 +296,44 @@ Failure* IC::ReferenceError(const char* type, Handle<String> name) { } +static int ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state) { + bool was_uninitialized = + old_state == UNINITIALIZED || old_state == PREMONOMORPHIC; + bool is_uninitialized = + new_state == UNINITIALIZED || new_state == PREMONOMORPHIC; + return (was_uninitialized && !is_uninitialized) ? 1 : + (!was_uninitialized && is_uninitialized) ? -1 : 0; +} + + void IC::PostPatching(Address address, Code* target, Code* old_target) { - if (FLAG_type_info_threshold > 0) { - if (old_target->is_inline_cache_stub() && - target->is_inline_cache_stub()) { - State old_state = old_target->ic_state(); - State new_state = target->ic_state(); - bool was_uninitialized = - old_state == UNINITIALIZED || old_state == PREMONOMORPHIC; - bool is_uninitialized = - new_state == UNINITIALIZED || new_state == PREMONOMORPHIC; - int delta = 0; - if (was_uninitialized && !is_uninitialized) { - delta = 1; - } else if (!was_uninitialized && is_uninitialized) { - delta = -1; - } - if (delta != 0) { - Code* host = target->GetHeap()->isolate()-> - inner_pointer_to_code_cache()->GetCacheEntry(address)->code; - // Not all Code objects have TypeFeedbackInfo. - if (host->type_feedback_info()->IsTypeFeedbackInfo()) { - TypeFeedbackInfo* info = - TypeFeedbackInfo::cast(host->type_feedback_info()); - info->set_ic_with_typeinfo_count( - info->ic_with_typeinfo_count() + delta); - } - } + if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) { + return; + } + Code* host = target->GetHeap()->isolate()-> + inner_pointer_to_code_cache()->GetCacheEntry(address)->code; + if (host->kind() != Code::FUNCTION) return; + + if (FLAG_type_info_threshold > 0 && + old_target->is_inline_cache_stub() && + target->is_inline_cache_stub()) { + int delta = ComputeTypeInfoCountDelta(old_target->ic_state(), + target->ic_state()); + // Not all Code objects have TypeFeedbackInfo. + if (delta != 0 && host->type_feedback_info()->IsTypeFeedbackInfo()) { + TypeFeedbackInfo* info = + TypeFeedbackInfo::cast(host->type_feedback_info()); + info->set_ic_with_type_info_count( + info->ic_with_type_info_count() + delta); } } if (FLAG_watch_ic_patching) { + host->set_profiler_ticks(0); Isolate::Current()->runtime_profiler()->NotifyICChanged(); - // We do not want to optimize until the ICs have settled down, - // so when they are patched, we postpone optimization for the - // current function and the functions above it on the stack that - // might want to inline this one. - StackFrameIterator it; - if (it.done()) return; - it.Advance(); - static const int kStackFramesToMark = Compiler::kMaxInliningLevels - 1; - for (int i = 0; i < kStackFramesToMark; ++i) { - if (it.done()) return; - StackFrame* raw_frame = it.frame(); - if (raw_frame->is_java_script()) { - JSFunction* function = - JSFunction::cast(JavaScriptFrame::cast(raw_frame)->function()); - if (function->IsOptimized()) continue; - SharedFunctionInfo* shared = function->shared(); - shared->set_profiler_ticks(0); - } - it.Advance(); - } } + // TODO(2029): When an optimized function is patched, it would + // be nice to propagate the corresponding type information to its + // unoptimized version for the benefit of later inlining. } @@ -366,9 +352,9 @@ void IC::Clear(Address address) { return KeyedStoreIC::Clear(address, target); case Code::CALL_IC: return CallIC::Clear(address, target); case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); + case Code::COMPARE_IC: return CompareIC::Clear(address, target); case Code::UNARY_OP_IC: case Code::BINARY_OP_IC: - case Code::COMPARE_IC: case Code::TO_BOOLEAN_IC: // Clearing these is tricky and does not // make any performance difference. @@ -379,9 +365,8 @@ void IC::Clear(Address address) { void CallICBase::Clear(Address address, Code* target) { + if (target->ic_state() == UNINITIALIZED) return; bool contextual = CallICBase::Contextual::decode(target->extra_ic_state()); - State state = target->ic_state(); - if (state == UNINITIALIZED) return; Code* code = Isolate::Current()->stub_cache()->FindCallInitialize( target->arguments_count(), @@ -424,6 +409,17 @@ void KeyedStoreIC::Clear(Address address, Code* target) { } +void CompareIC::Clear(Address address, Code* target) { + // Only clear ICCompareStubs, we currently cannot clear generic CompareStubs. + if (target->major_key() != CodeStub::CompareIC) return; + // Only clear CompareICs that can retain objects. + if (target->compare_state() != KNOWN_OBJECTS) return; + Token::Value op = CompareIC::ComputeOperation(target); + SetTargetAtAddress(address, GetRawUninitialized(op)); + PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); +} + + static bool HasInterceptorGetter(JSObject* object) { return !object->GetNamedInterceptor()->getter()->IsUndefined(); } @@ -1067,18 +1063,33 @@ Handle<Code> KeyedLoadIC::ComputePolymorphicStub( } +static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { + // This helper implements a few common fast cases for converting + // non-smi keys of keyed loads/stores to a smi or a string. + if (key->IsHeapNumber()) { + double value = Handle<HeapNumber>::cast(key)->value(); + if (isnan(value)) { + key = isolate->factory()->nan_symbol(); + } else { + int int_value = FastD2I(value); + if (value == int_value && Smi::IsValid(int_value)) { + key = Handle<Smi>(Smi::FromInt(int_value)); + } + } + } else if (key->IsUndefined()) { + key = isolate->factory()->undefined_symbol(); + } + return key; +} + + MaybeObject* KeyedLoadIC::Load(State state, Handle<Object> object, Handle<Object> key, bool force_generic_stub) { - // Check for values that can be converted into a symbol. - // TODO(1295): Remove this code. - if (key->IsHeapNumber() && - isnan(Handle<HeapNumber>::cast(key)->value())) { - key = isolate()->factory()->nan_symbol(); - } else if (key->IsUndefined()) { - key = isolate()->factory()->undefined_symbol(); - } + // Check for values that can be converted into a symbol directly or + // is representable as a smi. + key = TryConvertKey(key, isolate()); if (key->IsSymbol()) { Handle<String> name = Handle<String>::cast(key); @@ -1775,6 +1786,10 @@ MaybeObject* KeyedStoreIC::Store(State state, Handle<Object> key, Handle<Object> value, bool force_generic) { + // Check for values that can be converted into a symbol directly or + // is representable as a smi. + key = TryConvertKey(key, isolate()); + if (key->IsSymbol()) { Handle<String> name = Handle<String>::cast(key); @@ -2391,7 +2406,7 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { // Activate inlined smi code. if (previous_type == BinaryOpIC::UNINITIALIZED) { - PatchInlinedSmiCode(ic.address()); + PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); } } @@ -2452,6 +2467,14 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { } +Code* CompareIC::GetRawUninitialized(Token::Value op) { + ICCompareStub stub(op, UNINITIALIZED); + Code* code = NULL; + CHECK(stub.FindCodeInCache(&code)); + return code; +} + + Handle<Code> CompareIC::GetUninitialized(Token::Value op) { ICCompareStub stub(op, UNINITIALIZED); return stub.GetCode(); @@ -2466,6 +2489,12 @@ CompareIC::State CompareIC::ComputeState(Code* target) { } +Token::Value CompareIC::ComputeOperation(Code* target) { + ASSERT(target->major_key() == CodeStub::CompareIC); + return static_cast<Token::Value>(target->compare_operation()); +} + + const char* CompareIC::GetStateName(State state) { switch (state) { case UNINITIALIZED: return "UNINITIALIZED"; diff --git a/deps/v8/src/ic.h b/deps/v8/src/ic.h index 56625525d4..3b44abf4de 100644 --- a/deps/v8/src/ic.h +++ b/deps/v8/src/ic.h @@ -794,6 +794,9 @@ class CompareIC: public IC { // Helper function for determining the state of a compare IC. static State ComputeState(Code* target); + // Helper function for determining the operation a compare IC is for. + static Token::Value ComputeOperation(Code* target); + static const char* GetStateName(State state); private: @@ -804,7 +807,13 @@ class CompareIC: public IC { Condition GetCondition() const { return ComputeCondition(op_); } State GetState() { return ComputeState(target()); } + static Code* GetRawUninitialized(Token::Value op); + + static void Clear(Address address, Code* target); + Token::Value op_; + + friend class IC; }; @@ -817,7 +826,8 @@ class ToBooleanIC: public IC { // Helper for BinaryOpIC and CompareIC. -void PatchInlinedSmiCode(Address address); +enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK }; +void PatchInlinedSmiCode(Address address, InlinedSmiCheck check); } } // namespace v8::internal diff --git a/deps/v8/src/incremental-marking-inl.h b/deps/v8/src/incremental-marking-inl.h index 3e3d6c43fd..5ce003f31d 100644 --- a/deps/v8/src/incremental-marking-inl.h +++ b/deps/v8/src/incremental-marking-inl.h @@ -100,7 +100,7 @@ void IncrementalMarking::BlackToGreyAndUnshift(HeapObject* obj, int64_t old_bytes_rescanned = bytes_rescanned_; bytes_rescanned_ = old_bytes_rescanned + obj_size; if ((bytes_rescanned_ >> 20) != (old_bytes_rescanned >> 20)) { - if (bytes_rescanned_ > 2 * heap_->PromotedSpaceSize()) { + if (bytes_rescanned_ > 2 * heap_->PromotedSpaceSizeOfObjects()) { // If we have queued twice the heap size for rescanning then we are // going around in circles, scanning the same objects again and again // as the program mutates the heap faster than we can incrementally diff --git a/deps/v8/src/incremental-marking.cc b/deps/v8/src/incremental-marking.cc index 8fe89b4a98..5b58c9d787 100644 --- a/deps/v8/src/incremental-marking.cc +++ b/deps/v8/src/incremental-marking.cc @@ -205,6 +205,12 @@ class IncrementalMarkingMarkingVisitor : public ObjectVisitor { MarkObject(target); } + void VisitSharedFunctionInfo(SharedFunctionInfo* shared) { + if (shared->ic_age() != heap_->global_ic_age()) { + shared->ResetForNewContext(heap_->global_ic_age()); + } + } + void VisitPointer(Object** p) { Object* obj = *p; if (obj->NonFailureIsHeapObject()) { @@ -743,7 +749,7 @@ void IncrementalMarking::Finalize() { } -void IncrementalMarking::MarkingComplete() { +void IncrementalMarking::MarkingComplete(CompletionAction action) { state_ = COMPLETE; // We will set the stack guard to request a GC now. This will mean the rest // of the GC gets performed as soon as possible (we can't do a GC here in a @@ -754,13 +760,14 @@ void IncrementalMarking::MarkingComplete() { if (FLAG_trace_incremental_marking) { PrintF("[IncrementalMarking] Complete (normal).\n"); } - if (!heap_->idle_notification_will_schedule_next_gc()) { + if (action == GC_VIA_STACK_GUARD) { heap_->isolate()->stack_guard()->RequestGC(); } } -void IncrementalMarking::Step(intptr_t allocated_bytes) { +void IncrementalMarking::Step(intptr_t allocated_bytes, + CompletionAction action) { if (heap_->gc_state() != Heap::NOT_IN_GC || !FLAG_incremental_marking || !FLAG_incremental_marking_steps || @@ -823,6 +830,19 @@ void IncrementalMarking::Step(intptr_t allocated_bytes) { MarkObjectGreyDoNotEnqueue(ctx->normalized_map_cache()); VisitGlobalContext(ctx, &marking_visitor); + } else if (map->instance_type() == JS_FUNCTION_TYPE) { + marking_visitor.VisitPointers( + HeapObject::RawField(obj, JSFunction::kPropertiesOffset), + HeapObject::RawField(obj, JSFunction::kCodeEntryOffset)); + + marking_visitor.VisitCodeEntry( + obj->address() + JSFunction::kCodeEntryOffset); + + marking_visitor.VisitPointers( + HeapObject::RawField(obj, + JSFunction::kCodeEntryOffset + kPointerSize), + HeapObject::RawField(obj, + JSFunction::kNonWeakFieldsEndOffset)); } else { obj->IterateBody(map->instance_type(), size, &marking_visitor); } @@ -833,7 +853,7 @@ void IncrementalMarking::Step(intptr_t allocated_bytes) { Marking::MarkBlack(obj_mark_bit); MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size); } - if (marking_deque_.IsEmpty()) MarkingComplete(); + if (marking_deque_.IsEmpty()) MarkingComplete(action); } allocated_ = 0; @@ -931,7 +951,7 @@ void IncrementalMarking::ResetStepCounters() { int64_t IncrementalMarking::SpaceLeftInOldSpace() { - return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSize(); + return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSizeOfObjects(); } } } // namespace v8::internal diff --git a/deps/v8/src/incremental-marking.h b/deps/v8/src/incremental-marking.h index 4f8fa6b127..8cbe6c18e7 100644 --- a/deps/v8/src/incremental-marking.h +++ b/deps/v8/src/incremental-marking.h @@ -46,6 +46,11 @@ class IncrementalMarking { COMPLETE }; + enum CompletionAction { + GC_VIA_STACK_GUARD, + NO_GC_VIA_STACK_GUARD + }; + explicit IncrementalMarking(Heap* heap); void TearDown(); @@ -82,7 +87,7 @@ class IncrementalMarking { void Abort(); - void MarkingComplete(); + void MarkingComplete(CompletionAction action); // It's hard to know how much work the incremental marker should do to make // progress in the face of the mutator creating new work for it. We start @@ -102,10 +107,11 @@ class IncrementalMarking { static const intptr_t kMaxAllocationMarkingFactor = 1000; void OldSpaceStep(intptr_t allocated) { - Step(allocated * kFastMarking / kInitialAllocationMarkingFactor); + Step(allocated * kFastMarking / kInitialAllocationMarkingFactor, + GC_VIA_STACK_GUARD); } - void Step(intptr_t allocated); + void Step(intptr_t allocated, CompletionAction action); inline void RestartIfNotMarking() { if (state_ == COMPLETE) { diff --git a/deps/v8/src/interface.cc b/deps/v8/src/interface.cc index e344b86150..7836110e5f 100644 --- a/deps/v8/src/interface.cc +++ b/deps/v8/src/interface.cc @@ -79,7 +79,7 @@ void Interface::DoAdd( PrintF("%*sthis = ", Nesting::current(), ""); this->Print(Nesting::current()); PrintF("%*s%s : ", Nesting::current(), "", - (*reinterpret_cast<String**>(name))->ToAsciiArray()); + (*static_cast<String**>(name))->ToAsciiArray()); interface->Print(Nesting::current()); } #endif @@ -97,7 +97,7 @@ void Interface::DoAdd( #ifdef DEBUG Nesting nested; #endif - reinterpret_cast<Interface*>(p->value)->Unify(interface, ok); + static_cast<Interface*>(p->value)->Unify(interface, ok); } #ifdef DEBUG @@ -180,6 +180,15 @@ void Interface::DoUnify(Interface* that, bool* ok) { return; } + // Merge instance. + if (!that->instance_.is_null()) { + if (!this->instance_.is_null() && *this->instance_ != *that->instance_) { + *ok = false; + return; + } + this->instance_ = that->instance_; + } + // Merge interfaces. this->flags_ |= that->flags_; that->forward_ = this; diff --git a/deps/v8/src/interface.h b/deps/v8/src/interface.h index c2991cbd63..580f082b46 100644 --- a/deps/v8/src/interface.h +++ b/deps/v8/src/interface.h @@ -86,6 +86,12 @@ class Interface : public ZoneObject { if (*ok) Chase()->flags_ |= MODULE; } + // Set associated instance object. + void MakeSingleton(Handle<JSModule> instance, bool* ok) { + *ok = IsModule() && Chase()->instance_.is_null(); + if (*ok) Chase()->instance_ = instance; + } + // Do not allow any further refinements, directly or through unification. void Freeze(bool* ok) { *ok = IsValue() || IsModule(); @@ -95,9 +101,6 @@ class Interface : public ZoneObject { // --------------------------------------------------------------------------- // Accessors. - // Look up an exported name. Returns NULL if not (yet) defined. - Interface* Lookup(Handle<String> name); - // Check whether this is still a fully undetermined type. bool IsUnknown() { return Chase()->flags_ == NONE; } @@ -110,6 +113,42 @@ class Interface : public ZoneObject { // Check whether this is closed (i.e. fully determined). bool IsFrozen() { return Chase()->flags_ & FROZEN; } + Handle<JSModule> Instance() { return Chase()->instance_; } + + // Look up an exported name. Returns NULL if not (yet) defined. + Interface* Lookup(Handle<String> name); + + // --------------------------------------------------------------------------- + // Iterators. + + // Use like: + // for (auto it = interface->iterator(); !it.done(); it.Advance()) { + // ... it.name() ... it.interface() ... + // } + class Iterator { + public: + bool done() const { return entry_ == NULL; } + Handle<String> name() const { + ASSERT(!done()); + return Handle<String>(*static_cast<String**>(entry_->key)); + } + Interface* interface() const { + ASSERT(!done()); + return static_cast<Interface*>(entry_->value); + } + void Advance() { entry_ = exports_->Next(entry_); } + + private: + friend class Interface; + explicit Iterator(const ZoneHashMap* exports) + : exports_(exports), entry_(exports ? exports->Start() : NULL) {} + + const ZoneHashMap* exports_; + ZoneHashMap::Entry* entry_; + }; + + Iterator iterator() const { return Iterator(this->exports_); } + // --------------------------------------------------------------------------- // Debugging. #ifdef DEBUG @@ -129,6 +168,7 @@ class Interface : public ZoneObject { int flags_; Interface* forward_; // Unification link ZoneHashMap* exports_; // Module exports and their types (allocated lazily) + Handle<JSModule> instance_; explicit Interface(int flags) : flags_(flags), diff --git a/deps/v8/src/interpreter-irregexp.cc b/deps/v8/src/interpreter-irregexp.cc index b337e88452..3a92b84554 100644 --- a/deps/v8/src/interpreter-irregexp.cc +++ b/deps/v8/src/interpreter-irregexp.cc @@ -33,8 +33,9 @@ #include "utils.h" #include "ast.h" #include "bytecodes-irregexp.h" -#include "jsregexp.h" #include "interpreter-irregexp.h" +#include "jsregexp.h" +#include "regexp-macro-assembler.h" namespace v8 { namespace internal { @@ -449,6 +450,37 @@ static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate, } break; } + BYTECODE(CHECK_CHAR_IN_RANGE) { + uint32_t from = Load16Aligned(pc + 4); + uint32_t to = Load16Aligned(pc + 6); + if (from <= current_char && current_char <= to) { + pc = code_base + Load32Aligned(pc + 8); + } else { + pc += BC_CHECK_CHAR_IN_RANGE_LENGTH; + } + break; + } + BYTECODE(CHECK_CHAR_NOT_IN_RANGE) { + uint32_t from = Load16Aligned(pc + 4); + uint32_t to = Load16Aligned(pc + 6); + if (from > current_char || current_char > to) { + pc = code_base + Load32Aligned(pc + 8); + } else { + pc += BC_CHECK_CHAR_NOT_IN_RANGE_LENGTH; + } + break; + } + BYTECODE(CHECK_BIT_IN_TABLE) { + int mask = RegExpMacroAssembler::kTableMask; + byte b = pc[8 + ((current_char & mask) >> kBitsPerByteLog2)]; + int bit = (current_char & (kBitsPerByte - 1)); + if ((b & (1 << bit)) != 0) { + pc = code_base + Load32Aligned(pc + 4); + } else { + pc += BC_CHECK_BIT_IN_TABLE_LENGTH; + } + break; + } BYTECODE(CHECK_LT) { uint32_t limit = (insn >> BYTECODE_SHIFT); if (current_char < limit) { @@ -488,59 +520,6 @@ static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate, pc += BC_CHECK_REGISTER_EQ_POS_LENGTH; } break; - BYTECODE(LOOKUP_MAP1) { - // Look up character in a bitmap. If we find a 0, then jump to the - // location at pc + 8. Otherwise fall through! - int index = current_char - (insn >> BYTECODE_SHIFT); - byte map = code_base[Load32Aligned(pc + 4) + (index >> 3)]; - map = ((map >> (index & 7)) & 1); - if (map == 0) { - pc = code_base + Load32Aligned(pc + 8); - } else { - pc += BC_LOOKUP_MAP1_LENGTH; - } - break; - } - BYTECODE(LOOKUP_MAP2) { - // Look up character in a half-nibble map. If we find 00, then jump to - // the location at pc + 8. If we find 01 then jump to location at - // pc + 11, etc. - int index = (current_char - (insn >> BYTECODE_SHIFT)) << 1; - byte map = code_base[Load32Aligned(pc + 3) + (index >> 3)]; - map = ((map >> (index & 7)) & 3); - if (map < 2) { - if (map == 0) { - pc = code_base + Load32Aligned(pc + 8); - } else { - pc = code_base + Load32Aligned(pc + 12); - } - } else { - if (map == 2) { - pc = code_base + Load32Aligned(pc + 16); - } else { - pc = code_base + Load32Aligned(pc + 20); - } - } - break; - } - BYTECODE(LOOKUP_MAP8) { - // Look up character in a byte map. Use the byte as an index into a - // table that follows this instruction immediately. - int index = current_char - (insn >> BYTECODE_SHIFT); - byte map = code_base[Load32Aligned(pc + 4) + index]; - const byte* new_pc = code_base + Load32Aligned(pc + 8) + (map << 2); - pc = code_base + Load32Aligned(new_pc); - break; - } - BYTECODE(LOOKUP_HI_MAP8) { - // Look up high byte of this character in a byte map. Use the byte as - // an index into a table that follows this instruction immediately. - int index = (current_char >> 8) - (insn >> BYTECODE_SHIFT); - byte map = code_base[Load32Aligned(pc + 4) + index]; - const byte* new_pc = code_base + Load32Aligned(pc + 8) + (map << 2); - pc = code_base + Load32Aligned(new_pc); - break; - } BYTECODE(CHECK_NOT_REGS_EQUAL) if (registers[insn >> BYTECODE_SHIFT] == registers[Load32Aligned(pc + 4)]) { diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 625cc56727..0c97abd89e 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -38,7 +38,6 @@ #include "heap-profiler.h" #include "hydrogen.h" #include "isolate.h" -#include "lazy-instance.h" #include "lithium-allocator.h" #include "log.h" #include "messages.h" @@ -57,31 +56,6 @@ namespace v8 { namespace internal { -struct GlobalState { - Thread::LocalStorageKey per_isolate_thread_data_key; - Thread::LocalStorageKey isolate_key; - Thread::LocalStorageKey thread_id_key; - Isolate* default_isolate; - Isolate::ThreadDataTable* thread_data_table; - Mutex* mutex; -}; - -struct InitializeGlobalState { - static void Construct(GlobalState* state) { - state->isolate_key = Thread::CreateThreadLocalKey(); - state->thread_id_key = Thread::CreateThreadLocalKey(); - state->per_isolate_thread_data_key = Thread::CreateThreadLocalKey(); - state->thread_data_table = new Isolate::ThreadDataTable(); - state->default_isolate = new Isolate(); - state->mutex = OS::CreateMutex(); - // Can't use SetIsolateThreadLocals(default_isolate_, NULL) here - // because a non-null thread data may be already set. - Thread::SetThreadLocal(state->isolate_key, state->default_isolate); - } -}; - -static LazyInstance<GlobalState, InitializeGlobalState>::type global_state; - Atomic32 ThreadId::highest_thread_id_ = 0; int ThreadId::AllocateThreadId() { @@ -91,11 +65,10 @@ int ThreadId::AllocateThreadId() { int ThreadId::GetCurrentThreadId() { - const GlobalState& global = global_state.Get(); - int thread_id = Thread::GetThreadLocalInt(global.thread_id_key); + int thread_id = Thread::GetThreadLocalInt(Isolate::thread_id_key_); if (thread_id == 0) { thread_id = AllocateThreadId(); - Thread::SetThreadLocalInt(global.thread_id_key, thread_id); + Thread::SetThreadLocalInt(Isolate::thread_id_key_, thread_id); } return thread_id; } @@ -339,16 +312,23 @@ void Isolate::PreallocatedStorageDelete(void* p) { storage->LinkTo(&free_list_); } +Isolate* Isolate::default_isolate_ = NULL; +Thread::LocalStorageKey Isolate::isolate_key_; +Thread::LocalStorageKey Isolate::thread_id_key_; +Thread::LocalStorageKey Isolate::per_isolate_thread_data_key_; +Mutex* Isolate::process_wide_mutex_ = OS::CreateMutex(); +Isolate::ThreadDataTable* Isolate::thread_data_table_ = NULL; + + Isolate::PerIsolateThreadData* Isolate::AllocatePerIsolateThreadData( ThreadId thread_id) { ASSERT(!thread_id.Equals(ThreadId::Invalid())); PerIsolateThreadData* per_thread = new PerIsolateThreadData(this, thread_id); { - GlobalState* const global = global_state.Pointer(); - ScopedLock lock(global->mutex); - ASSERT(global->thread_data_table->Lookup(this, thread_id) == NULL); - global->thread_data_table->Insert(per_thread); - ASSERT(global->thread_data_table->Lookup(this, thread_id) == per_thread); + ScopedLock lock(process_wide_mutex_); + ASSERT(thread_data_table_->Lookup(this, thread_id) == NULL); + thread_data_table_->Insert(per_thread); + ASSERT(thread_data_table_->Lookup(this, thread_id) == per_thread); } return per_thread; } @@ -359,9 +339,8 @@ Isolate::PerIsolateThreadData* ThreadId thread_id = ThreadId::Current(); PerIsolateThreadData* per_thread = NULL; { - GlobalState* const global = global_state.Pointer(); - ScopedLock lock(global->mutex); - per_thread = global->thread_data_table->Lookup(this, thread_id); + ScopedLock lock(process_wide_mutex_); + per_thread = thread_data_table_->Lookup(this, thread_id); if (per_thread == NULL) { per_thread = AllocatePerIsolateThreadData(thread_id); } @@ -374,74 +353,64 @@ Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThisThread() { ThreadId thread_id = ThreadId::Current(); PerIsolateThreadData* per_thread = NULL; { - GlobalState* const global = global_state.Pointer(); - ScopedLock lock(global->mutex); - per_thread = global->thread_data_table->Lookup(this, thread_id); + ScopedLock lock(process_wide_mutex_); + per_thread = thread_data_table_->Lookup(this, thread_id); } return per_thread; } -bool Isolate::IsDefaultIsolate() const { - return this == global_state.Get().default_isolate; -} - - void Isolate::EnsureDefaultIsolate() { - GlobalState* const global = global_state.Pointer(); + ScopedLock lock(process_wide_mutex_); + if (default_isolate_ == NULL) { + isolate_key_ = Thread::CreateThreadLocalKey(); + thread_id_key_ = Thread::CreateThreadLocalKey(); + per_isolate_thread_data_key_ = Thread::CreateThreadLocalKey(); + thread_data_table_ = new Isolate::ThreadDataTable(); + default_isolate_ = new Isolate(); + } // Can't use SetIsolateThreadLocals(default_isolate_, NULL) here // because a non-null thread data may be already set. - if (Thread::GetThreadLocal(global->isolate_key) == NULL) { - Thread::SetThreadLocal(global->isolate_key, global->default_isolate); + if (Thread::GetThreadLocal(isolate_key_) == NULL) { + Thread::SetThreadLocal(isolate_key_, default_isolate_); } } +struct StaticInitializer { + StaticInitializer() { + Isolate::EnsureDefaultIsolate(); + } +} static_initializer; #ifdef ENABLE_DEBUGGER_SUPPORT Debugger* Isolate::GetDefaultIsolateDebugger() { EnsureDefaultIsolate(); - return global_state.Pointer()->default_isolate->debugger(); + return default_isolate_->debugger(); } #endif StackGuard* Isolate::GetDefaultIsolateStackGuard() { EnsureDefaultIsolate(); - return global_state.Pointer()->default_isolate->stack_guard(); -} - - -Thread::LocalStorageKey Isolate::isolate_key() { - return global_state.Get().isolate_key; -} - - -Thread::LocalStorageKey Isolate::thread_id_key() { - return global_state.Get().thread_id_key; -} - - -Thread::LocalStorageKey Isolate::per_isolate_thread_data_key() { - return global_state.Get().per_isolate_thread_data_key; + return default_isolate_->stack_guard(); } void Isolate::EnterDefaultIsolate() { EnsureDefaultIsolate(); - Isolate* const default_isolate = global_state.Pointer()->default_isolate; - ASSERT(default_isolate != NULL); + ASSERT(default_isolate_ != NULL); PerIsolateThreadData* data = CurrentPerIsolateThreadData(); // If not yet in default isolate - enter it. - if (data == NULL || data->isolate() != default_isolate) { - default_isolate->Enter(); + if (data == NULL || data->isolate() != default_isolate_) { + default_isolate_->Enter(); } } Isolate* Isolate::GetDefaultIsolateForLocking() { EnsureDefaultIsolate(); - return global_state.Pointer()->default_isolate; + return default_isolate_; } @@ -1461,6 +1430,7 @@ void Isolate::ThreadDataTable::RemoveAllThreads(Isolate* isolate) { Isolate::Isolate() : state_(UNINITIALIZED), + embedder_data_(NULL), entry_stack_(NULL), stack_trace_nesting_level_(0), incomplete_message_(NULL), @@ -1503,7 +1473,6 @@ Isolate::Isolate() string_tracker_(NULL), regexp_stack_(NULL), date_cache_(NULL), - embedder_data_(NULL), context_exit_happened_(false) { TRACE_ISOLATE(constructor); @@ -1564,8 +1533,8 @@ void Isolate::TearDown() { Deinit(); - { ScopedLock lock(global_state.Pointer()->mutex); - global_state.Pointer()->thread_data_table->RemoveAllThreads(this); + { ScopedLock lock(process_wide_mutex_); + thread_data_table_->RemoveAllThreads(this); } if (!IsDefaultIsolate()) { @@ -1618,9 +1587,8 @@ void Isolate::Deinit() { void Isolate::SetIsolateThreadLocals(Isolate* isolate, PerIsolateThreadData* data) { - const GlobalState& global = global_state.Get(); - Thread::SetThreadLocal(global.isolate_key, isolate); - Thread::SetThreadLocal(global.per_isolate_thread_data_key, data); + Thread::SetThreadLocal(isolate_key_, isolate); + Thread::SetThreadLocal(per_isolate_thread_data_key_, data); } @@ -1874,6 +1842,9 @@ bool Isolate::Init(Deserializer* des) { // stack guard. heap_.SetStackLimits(); + // Quiet the heap NaN if needed on target platform. + if (des != NULL) Assembler::QuietNaN(heap_.nan_value()); + deoptimizer_data_ = new DeoptimizerData; runtime_profiler_ = new RuntimeProfiler(this); runtime_profiler_->SetUp(); @@ -1886,6 +1857,13 @@ bool Isolate::Init(Deserializer* des) { LOG(this, LogCompiledFunctions()); } + CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, state_)), + Internals::kIsolateStateOffset); + CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, embedder_data_)), + Internals::kIsolateEmbedderDataOffset); + CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, heap_.roots_)), + Internals::kIsolateRootsOffset); + state_ = INITIALIZED; time_millis_at_init_ = OS::TimeCurrentMillis(); return true; diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h index 0c5a54c598..f1c9b3ccfa 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -422,7 +422,7 @@ class Isolate { enum AddressId { #define DECLARE_ENUM(CamelName, hacker_name) k##CamelName##Address, FOR_EACH_ISOLATE_ADDRESS_NAME(DECLARE_ENUM) -#undef C +#undef DECLARE_ENUM kIsolateAddressCount }; @@ -430,25 +430,19 @@ class Isolate { // not currently set). static PerIsolateThreadData* CurrentPerIsolateThreadData() { return reinterpret_cast<PerIsolateThreadData*>( - Thread::GetThreadLocal(per_isolate_thread_data_key())); + Thread::GetThreadLocal(per_isolate_thread_data_key_)); } // Returns the isolate inside which the current thread is running. INLINE(static Isolate* Current()) { - const Thread::LocalStorageKey key = isolate_key(); Isolate* isolate = reinterpret_cast<Isolate*>( - Thread::GetExistingThreadLocal(key)); - if (!isolate) { - EnsureDefaultIsolate(); - isolate = reinterpret_cast<Isolate*>( - Thread::GetExistingThreadLocal(key)); - } + Thread::GetExistingThreadLocal(isolate_key_)); ASSERT(isolate != NULL); return isolate; } INLINE(static Isolate* UncheckedCurrent()) { - return reinterpret_cast<Isolate*>(Thread::GetThreadLocal(isolate_key())); + return reinterpret_cast<Isolate*>(Thread::GetThreadLocal(isolate_key_)); } // Usually called by Init(), but can be called early e.g. to allow @@ -470,7 +464,7 @@ class Isolate { // for legacy API reasons. void TearDown(); - bool IsDefaultIsolate() const; + bool IsDefaultIsolate() const { return this == default_isolate_; } // Ensures that process-wide resources and the default isolate have been // allocated. It is only necessary to call this method in rare cases, for @@ -495,10 +489,14 @@ class Isolate { // Returns the key used to store the pointer to the current isolate. // Used internally for V8 threads that do not execute JavaScript but still // are part of the domain of an isolate (like the context switcher). - static Thread::LocalStorageKey isolate_key(); + static Thread::LocalStorageKey isolate_key() { + return isolate_key_; + } // Returns the key used to store process-wide thread IDs. - static Thread::LocalStorageKey thread_id_key(); + static Thread::LocalStorageKey thread_id_key() { + return thread_id_key_; + } static Thread::LocalStorageKey per_isolate_thread_data_key(); @@ -1040,6 +1038,18 @@ class Isolate { friend struct GlobalState; friend struct InitializeGlobalState; + enum State { + UNINITIALIZED, // Some components may not have been allocated. + INITIALIZED // All components are fully initialized. + }; + + // These fields are accessed through the API, offsets must be kept in sync + // with v8::internal::Internals (in include/v8.h) constants. This is also + // verified in Isolate::Init() using runtime checks. + State state_; // Will be padded to kApiPointerSize. + void* embedder_data_; + Heap heap_; + // The per-process lock should be acquired before the ThreadDataTable is // modified. class ThreadDataTable { @@ -1082,19 +1092,21 @@ class Isolate { DISALLOW_COPY_AND_ASSIGN(EntryStackItem); }; + // This mutex protects highest_thread_id_, thread_data_table_ and + // default_isolate_. + static Mutex* process_wide_mutex_; + + static Thread::LocalStorageKey per_isolate_thread_data_key_; + static Thread::LocalStorageKey isolate_key_; + static Thread::LocalStorageKey thread_id_key_; + static Isolate* default_isolate_; + static ThreadDataTable* thread_data_table_; + void Deinit(); static void SetIsolateThreadLocals(Isolate* isolate, PerIsolateThreadData* data); - enum State { - UNINITIALIZED, // Some components may not have been allocated. - INITIALIZED // All components are fully initialized. - }; - - State state_; - EntryStackItem* entry_stack_; - // Allocate and insert PerIsolateThreadData into the ThreadDataTable // (regardless of whether such data already exists). PerIsolateThreadData* AllocatePerIsolateThreadData(ThreadId thread_id); @@ -1138,13 +1150,13 @@ class Isolate { // the Error object. bool IsErrorObject(Handle<Object> obj); + EntryStackItem* entry_stack_; int stack_trace_nesting_level_; StringStream* incomplete_message_; // The preallocated memory thread singleton. PreallocatedMemoryThread* preallocated_memory_thread_; Address isolate_addresses_[kIsolateAddressCount + 1]; // NOLINT NoAllocationStringAllocator* preallocated_message_space_; - Bootstrapper* bootstrapper_; RuntimeProfiler* runtime_profiler_; CompilationCache* compilation_cache_; @@ -1153,7 +1165,6 @@ class Isolate { Mutex* break_access_; Atomic32 debugger_initialized_; Mutex* debugger_access_; - Heap heap_; Logger* logger_; StackGuard stack_guard_; StatsTable* stats_table_; @@ -1194,11 +1205,8 @@ class Isolate { unibrow::Mapping<unibrow::Ecma262Canonicalize> regexp_macro_assembler_canonicalize_; RegExpStack* regexp_stack_; - DateCache* date_cache_; - unibrow::Mapping<unibrow::Ecma262Canonicalize> interp_canonicalize_mapping_; - void* embedder_data_; // The garbage collector should be a little more aggressive when it knows // that a context was recently exited. diff --git a/deps/v8/src/jsregexp.cc b/deps/v8/src/jsregexp.cc index 8ccbae49ce..3455abce23 100644 --- a/deps/v8/src/jsregexp.cc +++ b/deps/v8/src/jsregexp.cc @@ -108,6 +108,60 @@ static inline void ThrowRegExpException(Handle<JSRegExp> re, } +ContainedInLattice AddRange(ContainedInLattice containment, + const int* ranges, + int ranges_length, + Interval new_range) { + ASSERT((ranges_length & 1) == 1); + ASSERT(ranges[ranges_length - 1] == String::kMaxUtf16CodeUnit + 1); + if (containment == kLatticeUnknown) return containment; + bool inside = false; + int last = 0; + for (int i = 0; i < ranges_length; inside = !inside, last = ranges[i], i++) { + // Consider the range from last to ranges[i]. + // We haven't got to the new range yet. + if (ranges[i] <= new_range.from()) continue; + // New range is wholly inside last-ranges[i]. Note that new_range.to() is + // inclusive, but the values in ranges are not. + if (last <= new_range.from() && new_range.to() < ranges[i]) { + return Combine(containment, inside ? kLatticeIn : kLatticeOut); + } + return kLatticeUnknown; + } + return containment; +} + + +// More makes code generation slower, less makes V8 benchmark score lower. +const int kMaxLookaheadForBoyerMoore = 8; +// In a 3-character pattern you can maximally step forwards 3 characters +// at a time, which is not always enough to pay for the extra logic. +const int kPatternTooShortForBoyerMoore = 2; + + +// Identifies the sort of regexps where the regexp engine is faster +// than the code used for atom matches. +static bool HasFewDifferentCharacters(Handle<String> pattern) { + int length = Min(kMaxLookaheadForBoyerMoore, pattern->length()); + if (length <= kPatternTooShortForBoyerMoore) return false; + const int kMod = 128; + bool character_found[kMod]; + int different = 0; + memset(&character_found[0], 0, sizeof(character_found)); + for (int i = 0; i < length; i++) { + int ch = (pattern->Get(i) & (kMod - 1)); + if (!character_found[ch]) { + character_found[ch] = true; + different++; + // We declare a regexp low-alphabet if it has at least 3 times as many + // characters as it has different characters. + if (different * 3 > length) return false; + } + } + return true; +} + + // Generic RegExp methods. Dispatches to implementation specific methods. @@ -141,9 +195,14 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re, return Handle<Object>::null(); } - if (parse_result.simple && !flags.is_ignore_case()) { + bool has_been_compiled = false; + + if (parse_result.simple && + !flags.is_ignore_case() && + !HasFewDifferentCharacters(pattern)) { // Parse-tree is a single atom that is equal to the pattern. AtomCompile(re, pattern, flags, pattern); + has_been_compiled = true; } else if (parse_result.tree->IsAtom() && !flags.is_ignore_case() && parse_result.capture_count == 0) { @@ -151,8 +210,12 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re, Vector<const uc16> atom_pattern = atom->data(); Handle<String> atom_string = isolate->factory()->NewStringFromTwoByte(atom_pattern); - AtomCompile(re, pattern, flags, atom_string); - } else { + if (!HasFewDifferentCharacters(atom_string)) { + AtomCompile(re, pattern, flags, atom_string); + has_been_compiled = true; + } + } + if (!has_been_compiled) { IrregexpInitialize(re, pattern, flags, parse_result.capture_count); } ASSERT(re->data()->IsFixedArray()); @@ -280,7 +343,8 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re, // from the source pattern. // If compilation fails, an exception is thrown and this function // returns false. -bool RegExpImpl::EnsureCompiledIrregexp(Handle<JSRegExp> re, bool is_ascii) { +bool RegExpImpl::EnsureCompiledIrregexp( + Handle<JSRegExp> re, Handle<String> sample_subject, bool is_ascii) { Object* compiled_code = re->DataAt(JSRegExp::code_index(is_ascii)); #ifdef V8_INTERPRETED_REGEXP if (compiled_code->IsByteArray()) return true; @@ -296,7 +360,7 @@ bool RegExpImpl::EnsureCompiledIrregexp(Handle<JSRegExp> re, bool is_ascii) { ASSERT(compiled_code->IsSmi()); return true; } - return CompileIrregexp(re, is_ascii); + return CompileIrregexp(re, sample_subject, is_ascii); } @@ -316,7 +380,9 @@ static bool CreateRegExpErrorObjectAndThrow(Handle<JSRegExp> re, } -bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) { +bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, + Handle<String> sample_subject, + bool is_ascii) { // Compile the RegExp. Isolate* isolate = re->GetIsolate(); ZoneScope zone_scope(isolate, DELETE_ON_EXIT); @@ -365,6 +431,7 @@ bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) { flags.is_ignore_case(), flags.is_multiline(), pattern, + sample_subject, is_ascii); if (result.error_message != NULL) { // Unable to compile regexp. @@ -435,7 +502,7 @@ int RegExpImpl::IrregexpPrepare(Handle<JSRegExp> regexp, // Check the asciiness of the underlying storage. bool is_ascii = subject->IsAsciiRepresentationUnderneath(); - if (!EnsureCompiledIrregexp(regexp, is_ascii)) return -1; + if (!EnsureCompiledIrregexp(regexp, subject, is_ascii)) return -1; #ifdef V8_INTERPRETED_REGEXP // Byte-code regexp needs space allocated for all its registers. @@ -466,7 +533,7 @@ RegExpImpl::IrregexpResult RegExpImpl::IrregexpExecOnce( #ifndef V8_INTERPRETED_REGEXP ASSERT(output.length() >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2); do { - EnsureCompiledIrregexp(regexp, is_ascii); + EnsureCompiledIrregexp(regexp, subject, is_ascii); Handle<Code> code(IrregexpNativeCode(*irregexp, is_ascii), isolate); NativeRegExpMacroAssembler::Result res = NativeRegExpMacroAssembler::Match(code, @@ -784,6 +851,53 @@ DispatchTable* ChoiceNode::GetTable(bool ignore_case) { } +class FrequencyCollator { + public: + FrequencyCollator() : total_samples_(0) { + for (int i = 0; i < RegExpMacroAssembler::kTableSize; i++) { + frequencies_[i] = CharacterFrequency(i); + } + } + + void CountCharacter(int character) { + int index = (character & RegExpMacroAssembler::kTableMask); + frequencies_[index].Increment(); + total_samples_++; + } + + // Does not measure in percent, but rather per-128 (the table size from the + // regexp macro assembler). + int Frequency(int in_character) { + ASSERT((in_character & RegExpMacroAssembler::kTableMask) == in_character); + if (total_samples_ < 1) return 1; // Division by zero. + int freq_in_per128 = + (frequencies_[in_character].counter() * 128) / total_samples_; + return freq_in_per128; + } + + private: + class CharacterFrequency { + public: + CharacterFrequency() : counter_(0), character_(-1) { } + explicit CharacterFrequency(int character) + : counter_(0), character_(character) { } + + void Increment() { counter_++; } + int counter() { return counter_; } + int character() { return character_; } + + private: + int counter_; + int character_; + }; + + + private: + CharacterFrequency frequencies_[RegExpMacroAssembler::kTableSize]; + int total_samples_; +}; + + class RegExpCompiler { public: RegExpCompiler(int capture_count, bool ignore_case, bool is_ascii); @@ -819,6 +933,7 @@ class RegExpCompiler { inline bool ignore_case() { return ignore_case_; } inline bool ascii() { return ascii_; } + FrequencyCollator* frequency_collator() { return &frequency_collator_; } int current_expansion_factor() { return current_expansion_factor_; } void set_current_expansion_factor(int value) { @@ -837,6 +952,7 @@ class RegExpCompiler { bool ascii_; bool reg_exp_too_big_; int current_expansion_factor_; + FrequencyCollator frequency_collator_; }; @@ -865,7 +981,8 @@ RegExpCompiler::RegExpCompiler(int capture_count, bool ignore_case, bool ascii) ignore_case_(ignore_case), ascii_(ascii), reg_exp_too_big_(false), - current_expansion_factor_(1) { + current_expansion_factor_(1), + frequency_collator_() { accept_ = new EndNode(EndNode::ACCEPT); ASSERT(next_register_ - 1 <= RegExpMacroAssembler::kMaxRegister); } @@ -1534,6 +1651,357 @@ static inline bool EmitAtomLetter(Isolate* isolate, } +static void EmitBoundaryTest(RegExpMacroAssembler* masm, + int border, + Label* fall_through, + Label* above_or_equal, + Label* below) { + if (below != fall_through) { + masm->CheckCharacterLT(border, below); + if (above_or_equal != fall_through) masm->GoTo(above_or_equal); + } else { + masm->CheckCharacterGT(border - 1, above_or_equal); + } +} + + +static void EmitDoubleBoundaryTest(RegExpMacroAssembler* masm, + int first, + int last, + Label* fall_through, + Label* in_range, + Label* out_of_range) { + if (in_range == fall_through) { + if (first == last) { + masm->CheckNotCharacter(first, out_of_range); + } else { + masm->CheckCharacterNotInRange(first, last, out_of_range); + } + } else { + if (first == last) { + masm->CheckCharacter(first, in_range); + } else { + masm->CheckCharacterInRange(first, last, in_range); + } + if (out_of_range != fall_through) masm->GoTo(out_of_range); + } +} + + +// even_label is for ranges[i] to ranges[i + 1] where i - start_index is even. +// odd_label is for ranges[i] to ranges[i + 1] where i - start_index is odd. +static void EmitUseLookupTable( + RegExpMacroAssembler* masm, + ZoneList<int>* ranges, + int start_index, + int end_index, + int min_char, + Label* fall_through, + Label* even_label, + Label* odd_label) { + static const int kSize = RegExpMacroAssembler::kTableSize; + static const int kMask = RegExpMacroAssembler::kTableMask; + + int base = (min_char & ~kMask); + USE(base); + + // Assert that everything is on one kTableSize page. + for (int i = start_index; i <= end_index; i++) { + ASSERT_EQ(ranges->at(i) & ~kMask, base); + } + ASSERT(start_index == 0 || (ranges->at(start_index - 1) & ~kMask) <= base); + + char templ[kSize]; + Label* on_bit_set; + Label* on_bit_clear; + int bit; + if (even_label == fall_through) { + on_bit_set = odd_label; + on_bit_clear = even_label; + bit = 1; + } else { + on_bit_set = even_label; + on_bit_clear = odd_label; + bit = 0; + } + for (int i = 0; i < (ranges->at(start_index) & kMask) && i < kSize; i++) { + templ[i] = bit; + } + int j = 0; + bit ^= 1; + for (int i = start_index; i < end_index; i++) { + for (j = (ranges->at(i) & kMask); j < (ranges->at(i + 1) & kMask); j++) { + templ[j] = bit; + } + bit ^= 1; + } + for (int i = j; i < kSize; i++) { + templ[i] = bit; + } + // TODO(erikcorry): Cache these. + Handle<ByteArray> ba = FACTORY->NewByteArray(kSize, TENURED); + for (int i = 0; i < kSize; i++) { + ba->set(i, templ[i]); + } + masm->CheckBitInTable(ba, on_bit_set); + if (on_bit_clear != fall_through) masm->GoTo(on_bit_clear); +} + + +static void CutOutRange(RegExpMacroAssembler* masm, + ZoneList<int>* ranges, + int start_index, + int end_index, + int cut_index, + Label* even_label, + Label* odd_label) { + bool odd = (((cut_index - start_index) & 1) == 1); + Label* in_range_label = odd ? odd_label : even_label; + Label dummy; + EmitDoubleBoundaryTest(masm, + ranges->at(cut_index), + ranges->at(cut_index + 1) - 1, + &dummy, + in_range_label, + &dummy); + ASSERT(!dummy.is_linked()); + // Cut out the single range by rewriting the array. This creates a new + // range that is a merger of the two ranges on either side of the one we + // are cutting out. The oddity of the labels is preserved. + for (int j = cut_index; j > start_index; j--) { + ranges->at(j) = ranges->at(j - 1); + } + for (int j = cut_index + 1; j < end_index; j++) { + ranges->at(j) = ranges->at(j + 1); + } +} + + +// Unicode case. Split the search space into kSize spaces that are handled +// with recursion. +static void SplitSearchSpace(ZoneList<int>* ranges, + int start_index, + int end_index, + int* new_start_index, + int* new_end_index, + int* border) { + static const int kSize = RegExpMacroAssembler::kTableSize; + static const int kMask = RegExpMacroAssembler::kTableMask; + + int first = ranges->at(start_index); + int last = ranges->at(end_index) - 1; + + *new_start_index = start_index; + *border = (ranges->at(start_index) & ~kMask) + kSize; + while (*new_start_index < end_index) { + if (ranges->at(*new_start_index) > *border) break; + (*new_start_index)++; + } + // new_start_index is the index of the first edge that is beyond the + // current kSize space. + + // For very large search spaces we do a binary chop search of the non-ASCII + // space instead of just going to the end of the current kSize space. The + // heuristics are complicated a little by the fact that any 128-character + // encoding space can be quickly tested with a table lookup, so we don't + // wish to do binary chop search at a smaller granularity than that. A + // 128-character space can take up a lot of space in the ranges array if, + // for example, we only want to match every second character (eg. the lower + // case characters on some Unicode pages). + int binary_chop_index = (end_index + start_index) / 2; + // The first test ensures that we get to the code that handles the ASCII + // range with a single not-taken branch, speeding up this important + // character range (even non-ASCII charset-based text has spaces and + // punctuation). + if (*border - 1 > String::kMaxAsciiCharCode && // ASCII case. + end_index - start_index > (*new_start_index - start_index) * 2 && + last - first > kSize * 2 && + binary_chop_index > *new_start_index && + ranges->at(binary_chop_index) >= first + 2 * kSize) { + int scan_forward_for_section_border = binary_chop_index;; + int new_border = (ranges->at(binary_chop_index) | kMask) + 1; + + while (scan_forward_for_section_border < end_index) { + if (ranges->at(scan_forward_for_section_border) > new_border) { + *new_start_index = scan_forward_for_section_border; + *border = new_border; + break; + } + scan_forward_for_section_border++; + } + } + + ASSERT(*new_start_index > start_index); + *new_end_index = *new_start_index - 1; + if (ranges->at(*new_end_index) == *border) { + (*new_end_index)--; + } + if (*border >= ranges->at(end_index)) { + *border = ranges->at(end_index); + *new_start_index = end_index; // Won't be used. + *new_end_index = end_index - 1; + } +} + + +// Gets a series of segment boundaries representing a character class. If the +// character is in the range between an even and an odd boundary (counting from +// start_index) then go to even_label, otherwise go to odd_label. We already +// know that the character is in the range of min_char to max_char inclusive. +// Either label can be NULL indicating backtracking. Either label can also be +// equal to the fall_through label. +static void GenerateBranches(RegExpMacroAssembler* masm, + ZoneList<int>* ranges, + int start_index, + int end_index, + uc16 min_char, + uc16 max_char, + Label* fall_through, + Label* even_label, + Label* odd_label) { + int first = ranges->at(start_index); + int last = ranges->at(end_index) - 1; + + ASSERT_LT(min_char, first); + + // Just need to test if the character is before or on-or-after + // a particular character. + if (start_index == end_index) { + EmitBoundaryTest(masm, first, fall_through, even_label, odd_label); + return; + } + + // Another almost trivial case: There is one interval in the middle that is + // different from the end intervals. + if (start_index + 1 == end_index) { + EmitDoubleBoundaryTest( + masm, first, last, fall_through, even_label, odd_label); + return; + } + + // It's not worth using table lookup if there are very few intervals in the + // character class. + if (end_index - start_index <= 6) { + // It is faster to test for individual characters, so we look for those + // first, then try arbitrary ranges in the second round. + static int kNoCutIndex = -1; + int cut = kNoCutIndex; + for (int i = start_index; i < end_index; i++) { + if (ranges->at(i) == ranges->at(i + 1) - 1) { + cut = i; + break; + } + } + if (cut == kNoCutIndex) cut = start_index; + CutOutRange( + masm, ranges, start_index, end_index, cut, even_label, odd_label); + ASSERT_GE(end_index - start_index, 2); + GenerateBranches(masm, + ranges, + start_index + 1, + end_index - 1, + min_char, + max_char, + fall_through, + even_label, + odd_label); + return; + } + + // If there are a lot of intervals in the regexp, then we will use tables to + // determine whether the character is inside or outside the character class. + static const int kBits = RegExpMacroAssembler::kTableSizeBits; + + if ((max_char >> kBits) == (min_char >> kBits)) { + EmitUseLookupTable(masm, + ranges, + start_index, + end_index, + min_char, + fall_through, + even_label, + odd_label); + return; + } + + if ((min_char >> kBits) != (first >> kBits)) { + masm->CheckCharacterLT(first, odd_label); + GenerateBranches(masm, + ranges, + start_index + 1, + end_index, + first, + max_char, + fall_through, + odd_label, + even_label); + return; + } + + int new_start_index = 0; + int new_end_index = 0; + int border = 0; + + SplitSearchSpace(ranges, + start_index, + end_index, + &new_start_index, + &new_end_index, + &border); + + Label handle_rest; + Label* above = &handle_rest; + if (border == last + 1) { + // We didn't find any section that started after the limit, so everything + // above the border is one of the terminal labels. + above = (end_index & 1) != (start_index & 1) ? odd_label : even_label; + ASSERT(new_end_index == end_index - 1); + } + + ASSERT_LE(start_index, new_end_index); + ASSERT_LE(new_start_index, end_index); + ASSERT_LT(start_index, new_start_index); + ASSERT_LT(new_end_index, end_index); + ASSERT(new_end_index + 1 == new_start_index || + (new_end_index + 2 == new_start_index && + border == ranges->at(new_end_index + 1))); + ASSERT_LT(min_char, border - 1); + ASSERT_LT(border, max_char); + ASSERT_LT(ranges->at(new_end_index), border); + ASSERT(border < ranges->at(new_start_index) || + (border == ranges->at(new_start_index) && + new_start_index == end_index && + new_end_index == end_index - 1 && + border == last + 1)); + ASSERT(new_start_index == 0 || border >= ranges->at(new_start_index - 1)); + + masm->CheckCharacterGT(border - 1, above); + Label dummy; + GenerateBranches(masm, + ranges, + start_index, + new_end_index, + min_char, + border - 1, + &dummy, + even_label, + odd_label); + if (handle_rest.is_linked()) { + masm->Bind(&handle_rest); + bool flip = (new_start_index & 1) != (start_index & 1); + GenerateBranches(masm, + ranges, + new_start_index, + end_index, + border, + max_char, + &dummy, + flip ? odd_label : even_label, + flip ? even_label : odd_label); + } +} + + static void EmitCharClass(RegExpMacroAssembler* macro_assembler, RegExpCharacterClass* cc, bool ascii, @@ -1542,6 +2010,10 @@ static void EmitCharClass(RegExpMacroAssembler* macro_assembler, bool check_offset, bool preloaded) { ZoneList<CharacterRange>* ranges = cc->ranges(); + if (!CharacterRange::IsCanonical(ranges)) { + CharacterRange::Canonicalize(ranges); + } + int max_char; if (ascii) { max_char = String::kMaxAsciiCharCode; @@ -1549,11 +2021,6 @@ static void EmitCharClass(RegExpMacroAssembler* macro_assembler, max_char = String::kMaxUtf16CodeUnit; } - Label success; - - Label* char_is_in_class = - cc->is_negated() ? on_failure : &success; - int range_count = ranges->length(); int last_valid_range = range_count - 1; @@ -1567,8 +2034,6 @@ static void EmitCharClass(RegExpMacroAssembler* macro_assembler, if (last_valid_range < 0) { if (!cc->is_negated()) { - // TODO(plesner): We can remove this when the node level does our - // ASCII optimizations for us. macro_assembler->GoTo(on_failure); } if (check_offset) { @@ -1578,6 +2043,18 @@ static void EmitCharClass(RegExpMacroAssembler* macro_assembler, } if (last_valid_range == 0 && + ranges->at(0).IsEverything(max_char)) { + if (cc->is_negated()) { + macro_assembler->GoTo(on_failure); + } else { + // This is a common case hit by non-anchored expressions. + if (check_offset) { + macro_assembler->CheckPosition(cp_offset, on_failure); + } + } + return; + } + if (last_valid_range == 0 && !cc->is_negated() && ranges->at(0).IsEverything(max_char)) { // This is a common case hit by non-anchored expressions. @@ -1597,64 +2074,43 @@ static void EmitCharClass(RegExpMacroAssembler* macro_assembler, return; } - for (int i = 0; i < last_valid_range; i++) { - CharacterRange& range = ranges->at(i); - Label next_range; - uc16 from = range.from(); - uc16 to = range.to(); - if (from > max_char) { - continue; - } - if (to > max_char) to = max_char; - if (to == from) { - macro_assembler->CheckCharacter(to, char_is_in_class); - } else { - if (from != 0) { - macro_assembler->CheckCharacterLT(from, &next_range); - } - if (to != max_char) { - macro_assembler->CheckCharacterLT(to + 1, char_is_in_class); - } else { - macro_assembler->GoTo(char_is_in_class); - } - } - macro_assembler->Bind(&next_range); - } - CharacterRange& range = ranges->at(last_valid_range); - uc16 from = range.from(); - uc16 to = range.to(); + // A new list with ascending entries. Each entry is a code unit + // where there is a boundary between code units that are part of + // the class and code units that are not. Normally we insert an + // entry at zero which goes to the failure label, but if there + // was already one there we fall through for success on that entry. + // Subsequent entries have alternating meaning (success/failure). + ZoneList<int>* range_boundaries = new ZoneList<int>(last_valid_range); - if (to > max_char) to = max_char; - ASSERT(to >= from); + bool zeroth_entry_is_failure = !cc->is_negated(); - if (to == from) { - if (cc->is_negated()) { - macro_assembler->CheckCharacter(to, on_failure); - } else { - macro_assembler->CheckNotCharacter(to, on_failure); - } - } else { - if (from != 0) { - if (cc->is_negated()) { - macro_assembler->CheckCharacterLT(from, &success); - } else { - macro_assembler->CheckCharacterLT(from, on_failure); - } - } - if (to != String::kMaxUtf16CodeUnit) { - if (cc->is_negated()) { - macro_assembler->CheckCharacterLT(to + 1, on_failure); - } else { - macro_assembler->CheckCharacterGT(to, on_failure); - } + for (int i = 0; i <= last_valid_range; i++) { + CharacterRange& range = ranges->at(i); + if (range.from() == 0) { + ASSERT_EQ(i, 0); + zeroth_entry_is_failure = !zeroth_entry_is_failure; } else { - if (cc->is_negated()) { - macro_assembler->GoTo(on_failure); - } + range_boundaries->Add(range.from()); } + range_boundaries->Add(range.to() + 1); } - macro_assembler->Bind(&success); + int end_index = range_boundaries->length() - 1; + if (range_boundaries->at(end_index) > max_char) { + end_index--; + } + + Label fall_through; + GenerateBranches(macro_assembler, + range_boundaries, + 0, // start_index. + end_index, + 0, // min_char. + max_char, + &fall_through, + zeroth_entry_is_failure ? &fall_through : on_failure, + zeroth_entry_is_failure ? on_failure : &fall_through); + macro_assembler->Bind(&fall_through); } @@ -1717,6 +2173,18 @@ int ActionNode::EatsAtLeast(int still_to_find, } +void ActionNode::FillInBMInfo(int offset, + BoyerMooreLookahead* bm, + bool not_at_start) { + if (type_ == BEGIN_SUBMATCH) { + bm->SetRest(offset); + } else if (type_ != POSITIVE_SUBMATCH_SUCCESS) { + on_success()->FillInBMInfo(offset, bm, not_at_start); + } + SaveBMInfo(bm, not_at_start, offset); +} + + int AssertionNode::EatsAtLeast(int still_to_find, int recursion_depth, bool not_at_start) { @@ -1733,6 +2201,15 @@ int AssertionNode::EatsAtLeast(int still_to_find, } +void AssertionNode::FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start) { + // Match the behaviour of EatsAtLeast on this node. + if (type() == AT_START && not_at_start) return; + on_success()->FillInBMInfo(offset, bm, not_at_start); + SaveBMInfo(bm, not_at_start, offset); +} + + int BackReferenceNode::EatsAtLeast(int still_to_find, int recursion_depth, bool not_at_start) { @@ -2071,10 +2548,12 @@ void TextNode::GetQuickCheckDetails(QuickCheckDetails* details, } } ASSERT(characters_filled_in != details->characters()); - on_success()-> GetQuickCheckDetails(details, - compiler, - characters_filled_in, - true); + if (!details->cannot_match()) { + on_success()-> GetQuickCheckDetails(details, + compiler, + characters_filled_in, + true); + } } @@ -2152,6 +2631,148 @@ class VisitMarker { }; +RegExpNode* SeqRegExpNode::FilterASCII(int depth) { + if (info()->replacement_calculated) return replacement(); + if (depth < 0) return this; + ASSERT(!info()->visited); + VisitMarker marker(info()); + return FilterSuccessor(depth - 1); +} + + +RegExpNode* SeqRegExpNode::FilterSuccessor(int depth) { + RegExpNode* next = on_success_->FilterASCII(depth - 1); + if (next == NULL) return set_replacement(NULL); + on_success_ = next; + return set_replacement(this); +} + + +RegExpNode* TextNode::FilterASCII(int depth) { + if (info()->replacement_calculated) return replacement(); + if (depth < 0) return this; + ASSERT(!info()->visited); + VisitMarker marker(info()); + int element_count = elms_->length(); + for (int i = 0; i < element_count; i++) { + TextElement elm = elms_->at(i); + if (elm.type == TextElement::ATOM) { + Vector<const uc16> quarks = elm.data.u_atom->data(); + for (int j = 0; j < quarks.length(); j++) { + // We don't need special handling for case independence + // because of the rule that case independence cannot make + // a non-ASCII character match an ASCII character. + if (quarks[j] > String::kMaxAsciiCharCode) { + return set_replacement(NULL); + } + } + } else { + ASSERT(elm.type == TextElement::CHAR_CLASS); + RegExpCharacterClass* cc = elm.data.u_char_class; + ZoneList<CharacterRange>* ranges = cc->ranges(); + if (!CharacterRange::IsCanonical(ranges)) { + CharacterRange::Canonicalize(ranges); + } + // Now they are in order so we only need to look at the first. + int range_count = ranges->length(); + if (cc->is_negated()) { + if (range_count != 0 && + ranges->at(0).from() == 0 && + ranges->at(0).to() >= String::kMaxAsciiCharCode) { + return set_replacement(NULL); + } + } else { + if (range_count == 0 || + ranges->at(0).from() > String::kMaxAsciiCharCode) { + return set_replacement(NULL); + } + } + } + } + return FilterSuccessor(depth - 1); +} + + +RegExpNode* LoopChoiceNode::FilterASCII(int depth) { + if (info()->replacement_calculated) return replacement(); + if (depth < 0) return this; + if (info()->visited) return this; + { + VisitMarker marker(info()); + + RegExpNode* continue_replacement = continue_node_->FilterASCII(depth - 1); + // If we can't continue after the loop then there is no sense in doing the + // loop. + if (continue_replacement == NULL) return set_replacement(NULL); + } + + return ChoiceNode::FilterASCII(depth - 1); +} + + +RegExpNode* ChoiceNode::FilterASCII(int depth) { + if (info()->replacement_calculated) return replacement(); + if (depth < 0) return this; + if (info()->visited) return this; + VisitMarker marker(info()); + int choice_count = alternatives_->length(); + int surviving = 0; + RegExpNode* survivor = NULL; + for (int i = 0; i < choice_count; i++) { + GuardedAlternative alternative = alternatives_->at(i); + RegExpNode* replacement = alternative.node()->FilterASCII(depth - 1); + ASSERT(replacement != this); // No missing EMPTY_MATCH_CHECK. + if (replacement != NULL) { + alternatives_->at(i).set_node(replacement); + surviving++; + survivor = replacement; + } + } + if (surviving < 2) return set_replacement(survivor); + + set_replacement(this); + if (surviving == choice_count) { + return this; + } + // Only some of the nodes survived the filtering. We need to rebuild the + // alternatives list. + ZoneList<GuardedAlternative>* new_alternatives = + new ZoneList<GuardedAlternative>(surviving); + for (int i = 0; i < choice_count; i++) { + RegExpNode* replacement = + alternatives_->at(i).node()->FilterASCII(depth - 1); + if (replacement != NULL) { + alternatives_->at(i).set_node(replacement); + new_alternatives->Add(alternatives_->at(i)); + } + } + alternatives_ = new_alternatives; + return this; +} + + +RegExpNode* NegativeLookaheadChoiceNode::FilterASCII(int depth) { + if (info()->replacement_calculated) return replacement(); + if (depth < 0) return this; + if (info()->visited) return this; + VisitMarker marker(info()); + // Alternative 0 is the negative lookahead, alternative 1 is what comes + // afterwards. + RegExpNode* node = alternatives_->at(1).node(); + RegExpNode* replacement = node->FilterASCII(depth - 1); + if (replacement == NULL) return set_replacement(NULL); + alternatives_->at(1).set_node(replacement); + + RegExpNode* neg_node = alternatives_->at(0).node(); + RegExpNode* neg_replacement = neg_node->FilterASCII(depth - 1); + // If the negative lookahead is always going to fail then + // we don't need to check it. + if (neg_replacement == NULL) return set_replacement(replacement); + alternatives_->at(0).set_node(neg_replacement); + return set_replacement(this); +} + + void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, RegExpCompiler* compiler, int characters_filled_in, @@ -2165,6 +2786,18 @@ void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, } +void LoopChoiceNode::FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start) { + if (body_can_be_zero_length_) { + bm->SetRest(offset); + SaveBMInfo(bm, not_at_start, offset); + return; + } + ChoiceNode::FillInBMInfo(offset, bm, not_at_start); + SaveBMInfo(bm, not_at_start, offset); +} + + void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, RegExpCompiler* compiler, int characters_filled_in, @@ -2249,110 +2882,83 @@ static void EmitHat(RegExpCompiler* compiler, } -// Emit the code to handle \b and \B (word-boundary or non-word-boundary) -// when we know whether the next character must be a word character or not. -static void EmitHalfBoundaryCheck(AssertionNode::AssertionNodeType type, - RegExpCompiler* compiler, - RegExpNode* on_success, - Trace* trace) { +// Emit the code to handle \b and \B (word-boundary or non-word-boundary). +void AssertionNode::EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace) { RegExpMacroAssembler* assembler = compiler->macro_assembler(); - Label done; - - Trace new_trace(*trace); - - bool expect_word_character = (type == AssertionNode::AFTER_WORD_CHARACTER); - Label* on_word = expect_word_character ? &done : new_trace.backtrack(); - Label* on_non_word = expect_word_character ? new_trace.backtrack() : &done; - - // Check whether previous character was a word character. - switch (trace->at_start()) { - case Trace::TRUE: - if (expect_word_character) { - assembler->GoTo(on_non_word); - } - break; - case Trace::UNKNOWN: - ASSERT_EQ(0, trace->cp_offset()); - assembler->CheckAtStart(on_non_word); - // Fall through. - case Trace::FALSE: - int prev_char_offset = trace->cp_offset() - 1; - assembler->LoadCurrentCharacter(prev_char_offset, NULL, false, 1); - EmitWordCheck(assembler, on_word, on_non_word, expect_word_character); - // We may or may not have loaded the previous character. - new_trace.InvalidateCurrentCharacter(); + Trace::TriBool next_is_word_character = Trace::UNKNOWN; + bool not_at_start = (trace->at_start() == Trace::FALSE); + BoyerMooreLookahead* lookahead = bm_info(not_at_start); + if (lookahead == NULL) { + int eats_at_least = + Min(kMaxLookaheadForBoyerMoore, + EatsAtLeast(kMaxLookaheadForBoyerMoore, 0, not_at_start)); + if (eats_at_least >= 1) { + BoyerMooreLookahead* bm = + new BoyerMooreLookahead(eats_at_least, compiler); + FillInBMInfo(0, bm, not_at_start); + if (bm->at(0)->is_non_word()) next_is_word_character = Trace::FALSE; + if (bm->at(0)->is_word()) next_is_word_character = Trace::TRUE; + } + } else { + if (lookahead->at(0)->is_non_word()) next_is_word_character = Trace::FALSE; + if (lookahead->at(0)->is_word()) next_is_word_character = Trace::TRUE; + } + bool at_boundary = (type_ == AssertionNode::AT_BOUNDARY); + if (next_is_word_character == Trace::UNKNOWN) { + Label before_non_word; + Label before_word; + if (trace->characters_preloaded() != 1) { + assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word); + } + // Fall through on non-word. + EmitWordCheck(assembler, &before_word, &before_non_word, false); + // Next character is not a word character. + assembler->Bind(&before_non_word); + Label ok; + BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord); + assembler->GoTo(&ok); + + assembler->Bind(&before_word); + BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord); + assembler->Bind(&ok); + } else if (next_is_word_character == Trace::TRUE) { + BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord); + } else { + ASSERT(next_is_word_character == Trace::FALSE); + BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord); } - - assembler->Bind(&done); - - on_success->Emit(compiler, &new_trace); } -// Emit the code to handle \b and \B (word-boundary or non-word-boundary). -static void EmitBoundaryCheck(AssertionNode::AssertionNodeType type, - RegExpCompiler* compiler, - RegExpNode* on_success, - Trace* trace) { +void AssertionNode::BacktrackIfPrevious( + RegExpCompiler* compiler, + Trace* trace, + AssertionNode::IfPrevious backtrack_if_previous) { RegExpMacroAssembler* assembler = compiler->macro_assembler(); - Label before_non_word; - Label before_word; - if (trace->characters_preloaded() != 1) { - assembler->LoadCurrentCharacter(trace->cp_offset(), &before_non_word); - } - // Fall through on non-word. - EmitWordCheck(assembler, &before_word, &before_non_word, false); - - // We will be loading the previous character into the current character - // register. Trace new_trace(*trace); new_trace.InvalidateCurrentCharacter(); - Label ok; - Label* boundary; - Label* not_boundary; - if (type == AssertionNode::AT_BOUNDARY) { - boundary = &ok; - not_boundary = new_trace.backtrack(); - } else { - not_boundary = &ok; - boundary = new_trace.backtrack(); - } + Label fall_through, dummy; - // Next character is not a word character. - assembler->Bind(&before_non_word); - if (new_trace.cp_offset() == 0) { - // The start of input counts as a non-word character, so the question is - // decided if we are at the start. - assembler->CheckAtStart(not_boundary); - } - // We already checked that we are not at the start of input so it must be - // OK to load the previous character. - assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, - &ok, // Unused dummy label in this call. - false); - // Fall through on non-word. - EmitWordCheck(assembler, boundary, not_boundary, false); - assembler->GoTo(not_boundary); + Label* non_word = backtrack_if_previous == kIsNonWord ? + new_trace.backtrack() : + &fall_through; + Label* word = backtrack_if_previous == kIsNonWord ? + &fall_through : + new_trace.backtrack(); - // Next character is a word character. - assembler->Bind(&before_word); if (new_trace.cp_offset() == 0) { // The start of input counts as a non-word character, so the question is // decided if we are at the start. - assembler->CheckAtStart(boundary); + assembler->CheckAtStart(non_word); } // We already checked that we are not at the start of input so it must be // OK to load the previous character. - assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, - &ok, // Unused dummy label in this call. - false); - bool fall_through_on_word = (type == AssertionNode::AT_NON_BOUNDARY); - EmitWordCheck(assembler, not_boundary, boundary, fall_through_on_word); + assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, &dummy, false); + EmitWordCheck(assembler, word, non_word, backtrack_if_previous == kIsNonWord); - assembler->Bind(&ok); - - on_success->Emit(compiler, &new_trace); + assembler->Bind(&fall_through); + on_success()->Emit(compiler, &new_trace); } @@ -2400,13 +3006,9 @@ void AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) { return; case AT_BOUNDARY: case AT_NON_BOUNDARY: { - EmitBoundaryCheck(type_, compiler, on_success(), trace); + EmitBoundaryCheck(compiler, trace); return; } - case AFTER_WORD_CHARACTER: - case AFTER_NONWORD_CHARACTER: { - EmitHalfBoundaryCheck(type_, compiler, on_success(), trace); - } } on_success()->Emit(compiler, trace); } @@ -2661,6 +3263,30 @@ int TextNode::GreedyLoopTextLength() { } +RegExpNode* TextNode::GetSuccessorOfOmnivorousTextNode( + RegExpCompiler* compiler) { + if (elms_->length() != 1) return NULL; + TextElement elm = elms_->at(0); + if (elm.type != TextElement::CHAR_CLASS) return NULL; + RegExpCharacterClass* node = elm.data.u_char_class; + ZoneList<CharacterRange>* ranges = node->ranges(); + if (!CharacterRange::IsCanonical(ranges)) { + CharacterRange::Canonicalize(ranges); + } + if (node->is_negated()) { + return ranges->length() == 0 ? on_success() : NULL; + } + if (ranges->length() != 1) return NULL; + uint32_t max_char; + if (compiler->ascii()) { + max_char = String::kMaxAsciiCharCode; + } else { + max_char = String::kMaxUtf16CodeUnit; + } + return ranges->at(0).IsEverything(max_char) ? on_success() : NULL; +} + + // Finds the fixed match length of a sequence of nodes that goes from // this alternative and back to this choice node. If there are variable // length nodes or other complications in the way then return a sentinel @@ -2725,8 +3351,8 @@ void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler, - bool not_at_start) { - int preload_characters = EatsAtLeast(4, 0, not_at_start); + int eats_at_least) { + int preload_characters = Min(4, eats_at_least); if (compiler->macro_assembler()->CanReadUnaligned()) { bool ascii = compiler->ascii(); if (ascii) { @@ -2792,6 +3418,250 @@ class AlternativeGenerationList { }; +// The '2' variant is has inclusive from and exclusive to. +static const int kSpaceRanges[] = { '\t', '\r' + 1, ' ', ' ' + 1, 0x00A0, + 0x00A1, 0x1680, 0x1681, 0x180E, 0x180F, 0x2000, 0x200B, 0x2028, 0x202A, + 0x202F, 0x2030, 0x205F, 0x2060, 0x3000, 0x3001, 0xFEFF, 0xFF00, 0x10000 }; +static const int kSpaceRangeCount = ARRAY_SIZE(kSpaceRanges); + +static const int kWordRanges[] = { + '0', '9' + 1, 'A', 'Z' + 1, '_', '_' + 1, 'a', 'z' + 1, 0x10000 }; +static const int kWordRangeCount = ARRAY_SIZE(kWordRanges); +static const int kDigitRanges[] = { '0', '9' + 1, 0x10000 }; +static const int kDigitRangeCount = ARRAY_SIZE(kDigitRanges); +static const int kSurrogateRanges[] = { 0xd800, 0xe000, 0x10000 }; +static const int kSurrogateRangeCount = ARRAY_SIZE(kSurrogateRanges); +static const int kLineTerminatorRanges[] = { 0x000A, 0x000B, 0x000D, 0x000E, + 0x2028, 0x202A, 0x10000 }; +static const int kLineTerminatorRangeCount = ARRAY_SIZE(kLineTerminatorRanges); + + +void BoyerMoorePositionInfo::Set(int character) { + SetInterval(Interval(character, character)); +} + + +void BoyerMoorePositionInfo::SetInterval(const Interval& interval) { + s_ = AddRange(s_, kSpaceRanges, kSpaceRangeCount, interval); + w_ = AddRange(w_, kWordRanges, kWordRangeCount, interval); + d_ = AddRange(d_, kDigitRanges, kDigitRangeCount, interval); + surrogate_ = + AddRange(surrogate_, kSurrogateRanges, kSurrogateRangeCount, interval); + if (interval.to() - interval.from() >= kMapSize - 1) { + if (map_count_ != kMapSize) { + map_count_ = kMapSize; + for (int i = 0; i < kMapSize; i++) map_->at(i) = true; + } + return; + } + for (int i = interval.from(); i <= interval.to(); i++) { + int mod_character = (i & kMask); + if (!map_->at(mod_character)) { + map_count_++; + map_->at(mod_character) = true; + } + if (map_count_ == kMapSize) return; + } +} + + +void BoyerMoorePositionInfo::SetAll() { + s_ = w_ = d_ = kLatticeUnknown; + if (map_count_ != kMapSize) { + map_count_ = kMapSize; + for (int i = 0; i < kMapSize; i++) map_->at(i) = true; + } +} + + +BoyerMooreLookahead::BoyerMooreLookahead( + int length, RegExpCompiler* compiler) + : length_(length), + compiler_(compiler) { + if (compiler->ascii()) { + max_char_ = String::kMaxAsciiCharCode; + } else { + max_char_ = String::kMaxUtf16CodeUnit; + } + bitmaps_ = new ZoneList<BoyerMoorePositionInfo*>(length); + for (int i = 0; i < length; i++) { + bitmaps_->Add(new BoyerMoorePositionInfo()); + } +} + + +// Find the longest range of lookahead that has the fewest number of different +// characters that can occur at a given position. Since we are optimizing two +// different parameters at once this is a tradeoff. +bool BoyerMooreLookahead::FindWorthwhileInterval(int* from, int* to) { + int biggest_points = 0; + // If more than 32 characters out of 128 can occur it is unlikely that we can + // be lucky enough to step forwards much of the time. + const int kMaxMax = 32; + for (int max_number_of_chars = 4; + max_number_of_chars < kMaxMax; + max_number_of_chars *= 2) { + biggest_points = + FindBestInterval(max_number_of_chars, biggest_points, from, to); + } + if (biggest_points == 0) return false; + return true; +} + + +// Find the highest-points range between 0 and length_ where the character +// information is not too vague. 'Too vague' means that there are more than +// max_number_of_chars that can occur at this position. Calculates the number +// of points as the product of width-of-the-range and +// probability-of-finding-one-of-the-characters, where the probability is +// calculated using the frequency distribution of the sample subject string. +int BoyerMooreLookahead::FindBestInterval( + int max_number_of_chars, int old_biggest_points, int* from, int* to) { + int biggest_points = old_biggest_points; + static const int kSize = RegExpMacroAssembler::kTableSize; + for (int i = 0; i < length_; ) { + while (i < length_ && Count(i) > max_number_of_chars) i++; + if (i == length_) break; + int remembered_from = i; + bool union_map[kSize]; + for (int j = 0; j < kSize; j++) union_map[j] = false; + while (i < length_ && Count(i) <= max_number_of_chars) { + BoyerMoorePositionInfo* map = bitmaps_->at(i); + for (int j = 0; j < kSize; j++) union_map[j] |= map->at(j); + i++; + } + int frequency = 0; + for (int j = 0; j < kSize; j++) { + if (union_map[j]) { + // Add 1 to the frequency to give a small per-character boost for + // the cases where our sampling is not good enough and many + // characters have a frequency of zero. This means the frequency + // can theoretically be up to 2*kSize though we treat it mostly as + // a fraction of kSize. + frequency += compiler_->frequency_collator()->Frequency(j) + 1; + } + } + // We use the probability of skipping times the distance we are skipping to + // judge the effectiveness of this. Actually we have a cut-off: By + // dividing by 2 we switch off the skipping if the probability of skipping + // is less than 50%. This is because the multibyte mask-and-compare + // skipping in quickcheck is more likely to do well on this case. + bool in_quickcheck_range = ((i - remembered_from < 4) || + (compiler_->ascii() ? remembered_from <= 4 : remembered_from <= 2)); + // Called 'probability' but it is only a rough estimate and can actually + // be outside the 0-kSize range. + int probability = (in_quickcheck_range ? kSize / 2 : kSize) - frequency; + int points = (i - remembered_from) * probability; + if (points > biggest_points) { + *from = remembered_from; + *to = i - 1; + biggest_points = points; + } + } + return biggest_points; +} + + +// Take all the characters that will not prevent a successful match if they +// occur in the subject string in the range between min_lookahead and +// max_lookahead (inclusive) measured from the current position. If the +// character at max_lookahead offset is not one of these characters, then we +// can safely skip forwards by the number of characters in the range. +int BoyerMooreLookahead::GetSkipTable(int min_lookahead, + int max_lookahead, + Handle<ByteArray> boolean_skip_table) { + const int kSize = RegExpMacroAssembler::kTableSize; + + const int kSkipArrayEntry = 0; + const int kDontSkipArrayEntry = 1; + + for (int i = 0; i < kSize; i++) { + boolean_skip_table->set(i, kSkipArrayEntry); + } + int skip = max_lookahead + 1 - min_lookahead; + + for (int i = max_lookahead; i >= min_lookahead; i--) { + BoyerMoorePositionInfo* map = bitmaps_->at(i); + for (int j = 0; j < kSize; j++) { + if (map->at(j)) { + boolean_skip_table->set(j, kDontSkipArrayEntry); + } + } + } + + return skip; +} + + +// See comment above on the implementation of GetSkipTable. +bool BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) { + const int kSize = RegExpMacroAssembler::kTableSize; + + int min_lookahead = 0; + int max_lookahead = 0; + + if (!FindWorthwhileInterval(&min_lookahead, &max_lookahead)) return false; + + bool found_single_character = false; + int single_character = 0; + for (int i = max_lookahead; i >= min_lookahead; i--) { + BoyerMoorePositionInfo* map = bitmaps_->at(i); + if (map->map_count() > 1 || + (found_single_character && map->map_count() != 0)) { + found_single_character = false; + break; + } + for (int j = 0; j < kSize; j++) { + if (map->at(j)) { + found_single_character = true; + single_character = j; + break; + } + } + } + + int lookahead_width = max_lookahead + 1 - min_lookahead; + + if (found_single_character && lookahead_width == 1 && max_lookahead < 3) { + // The mask-compare can probably handle this better. + return false; + } + + if (found_single_character) { + Label cont, again; + masm->Bind(&again); + masm->LoadCurrentCharacter(max_lookahead, &cont, true); + if (max_char_ > kSize) { + masm->CheckCharacterAfterAnd(single_character, + RegExpMacroAssembler::kTableMask, + &cont); + } else { + masm->CheckCharacter(single_character, &cont); + } + masm->AdvanceCurrentPosition(lookahead_width); + masm->GoTo(&again); + masm->Bind(&cont); + return true; + } + + Handle<ByteArray> boolean_skip_table = + FACTORY->NewByteArray(kSize, TENURED); + int skip_distance = GetSkipTable( + min_lookahead, max_lookahead, boolean_skip_table); + ASSERT(skip_distance != 0); + + Label cont, again; + masm->Bind(&again); + masm->LoadCurrentCharacter(max_lookahead, &cont, true); + masm->CheckBitInTable(boolean_skip_table, &cont); + masm->AdvanceCurrentPosition(skip_distance); + masm->GoTo(&again); + masm->Bind(&cont); + + return true; +} + + /* Code generation for choice nodes. * * We generate quick checks that do a mask and compare to eliminate a @@ -2870,7 +3740,6 @@ class AlternativeGenerationList { * \______________/ */ - void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); int choice_count = alternatives_->length(); @@ -2935,10 +3804,52 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { int first_normal_choice = greedy_loop ? 1 : 0; - int preload_characters = - CalculatePreloadCharacters(compiler, - current_trace->at_start() == Trace::FALSE); - bool preload_is_current = + bool not_at_start = current_trace->at_start() == Trace::FALSE; + const int kEatsAtLeastNotYetInitialized = -1; + int eats_at_least = kEatsAtLeastNotYetInitialized; + + bool skip_was_emitted = false; + + if (!greedy_loop && choice_count == 2) { + GuardedAlternative alt1 = alternatives_->at(1); + if (alt1.guards() == NULL || alt1.guards()->length() == 0) { + RegExpNode* eats_anything_node = alt1.node(); + if (eats_anything_node->GetSuccessorOfOmnivorousTextNode(compiler) == + this) { + // At this point we know that we are at a non-greedy loop that will eat + // any character one at a time. Any non-anchored regexp has such a + // loop prepended to it in order to find where it starts. We look for + // a pattern of the form ...abc... where we can look 6 characters ahead + // and step forwards 3 if the character is not one of abc. Abc need + // not be atoms, they can be any reasonably limited character class or + // small alternation. + ASSERT(trace->is_trivial()); // This is the case on LoopChoiceNodes. + BoyerMooreLookahead* lookahead = bm_info(not_at_start); + if (lookahead == NULL) { + eats_at_least = + Min(kMaxLookaheadForBoyerMoore, + EatsAtLeast(kMaxLookaheadForBoyerMoore, 0, not_at_start)); + if (eats_at_least >= 1) { + BoyerMooreLookahead* bm = + new BoyerMooreLookahead(eats_at_least, compiler); + GuardedAlternative alt0 = alternatives_->at(0); + alt0.node()->FillInBMInfo(0, bm, not_at_start); + skip_was_emitted = bm->EmitSkipInstructions(macro_assembler); + } + } else { + skip_was_emitted = lookahead->EmitSkipInstructions(macro_assembler); + } + } + } + } + + if (eats_at_least == kEatsAtLeastNotYetInitialized) { + // Save some time by looking at most one machine word ahead. + eats_at_least = EatsAtLeast(compiler->ascii() ? 4 : 2, 0, not_at_start); + } + int preload_characters = CalculatePreloadCharacters(compiler, eats_at_least); + + bool preload_is_current = !skip_was_emitted && (current_trace->characters_preloaded() == preload_characters); bool preload_has_checked_bounds = preload_is_current; @@ -3489,12 +4400,6 @@ void DotPrinter::VisitAssertion(AssertionNode* that) { case AssertionNode::AFTER_NEWLINE: stream()->Add("label=\"(?<=\\n)\", shape=septagon"); break; - case AssertionNode::AFTER_WORD_CHARACTER: - stream()->Add("label=\"(?<=\\w)\", shape=septagon"); - break; - case AssertionNode::AFTER_NONWORD_CHARACTER: - stream()->Add("label=\"(?<=\\W)\", shape=septagon"); - break; } stream()->Add("];\n"); PrintAttributes(that); @@ -3599,21 +4504,6 @@ void RegExpEngine::DotPrint(const char* label, // ------------------------------------------------------------------- // Tree to graph conversion -static const uc16 kSpaceRanges[] = { 0x0009, 0x000D, 0x0020, 0x0020, 0x00A0, - 0x00A0, 0x1680, 0x1680, 0x180E, 0x180E, 0x2000, 0x200A, 0x2028, 0x2029, - 0x202F, 0x202F, 0x205F, 0x205F, 0x3000, 0x3000, 0xFEFF, 0xFEFF }; -static const int kSpaceRangeCount = ARRAY_SIZE(kSpaceRanges); - -static const uc16 kWordRanges[] = { '0', '9', 'A', 'Z', '_', '_', 'a', 'z' }; -static const int kWordRangeCount = ARRAY_SIZE(kWordRanges); - -static const uc16 kDigitRanges[] = { '0', '9' }; -static const int kDigitRangeCount = ARRAY_SIZE(kDigitRanges); - -static const uc16 kLineTerminatorRanges[] = { 0x000A, 0x000A, 0x000D, 0x000D, - 0x2028, 0x2029 }; -static const int kLineTerminatorRangeCount = ARRAY_SIZE(kLineTerminatorRanges); - RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler, RegExpNode* on_success) { ZoneList<TextElement>* elms = new ZoneList<TextElement>(1); @@ -3627,9 +4517,12 @@ RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler, return new TextNode(elements(), on_success); } + static bool CompareInverseRanges(ZoneList<CharacterRange>* ranges, - const uc16* special_class, + const int* special_class, int length) { + length--; // Remove final 0x10000. + ASSERT(special_class[length] == 0x10000); ASSERT(ranges->length() != 0); ASSERT(length != 0); ASSERT(special_class[0] != 0); @@ -3645,7 +4538,7 @@ static bool CompareInverseRanges(ZoneList<CharacterRange>* ranges, return false; } range = ranges->at((i >> 1) + 1); - if (special_class[i+1] != range.from() - 1) { + if (special_class[i+1] != range.from()) { return false; } } @@ -3657,14 +4550,17 @@ static bool CompareInverseRanges(ZoneList<CharacterRange>* ranges, static bool CompareRanges(ZoneList<CharacterRange>* ranges, - const uc16* special_class, + const int* special_class, int length) { + length--; // Remove final 0x10000. + ASSERT(special_class[length] == 0x10000); if (ranges->length() * 2 != length) { return false; } for (int i = 0; i < length; i += 2) { CharacterRange range = ranges->at(i >> 1); - if (range.from() != special_class[i] || range.to() != special_class[i+1]) { + if (range.from() != special_class[i] || + range.to() != special_class[i + 1] - 1) { return false; } } @@ -4065,27 +4961,31 @@ RegExpNode* RegExpAlternative::ToNode(RegExpCompiler* compiler, } -static void AddClass(const uc16* elmv, +static void AddClass(const int* elmv, int elmc, ZoneList<CharacterRange>* ranges) { + elmc--; + ASSERT(elmv[elmc] == 0x10000); for (int i = 0; i < elmc; i += 2) { - ASSERT(elmv[i] <= elmv[i + 1]); - ranges->Add(CharacterRange(elmv[i], elmv[i + 1])); + ASSERT(elmv[i] < elmv[i + 1]); + ranges->Add(CharacterRange(elmv[i], elmv[i + 1] - 1)); } } -static void AddClassNegated(const uc16 *elmv, +static void AddClassNegated(const int *elmv, int elmc, ZoneList<CharacterRange>* ranges) { + elmc--; + ASSERT(elmv[elmc] == 0x10000); ASSERT(elmv[0] != 0x0000); ASSERT(elmv[elmc-1] != String::kMaxUtf16CodeUnit); uc16 last = 0x0000; for (int i = 0; i < elmc; i += 2) { ASSERT(last <= elmv[i] - 1); - ASSERT(elmv[i] <= elmv[i + 1]); + ASSERT(elmv[i] < elmv[i + 1]); ranges->Add(CharacterRange(last, elmv[i] - 1)); - last = elmv[i + 1] + 1; + last = elmv[i + 1]; } ranges->Add(CharacterRange(last, String::kMaxUtf16CodeUnit)); } @@ -4136,8 +5036,8 @@ void CharacterRange::AddClassEscape(uc16 type, } -Vector<const uc16> CharacterRange::GetWordBounds() { - return Vector<const uc16>(kWordRanges, kWordRangeCount); +Vector<const int> CharacterRange::GetWordBounds() { + return Vector<const int>(kWordRanges, kWordRangeCount - 1); } @@ -4169,7 +5069,7 @@ void CharacterRangeSplitter::Call(uc16 from, DispatchTable::Entry entry) { void CharacterRange::Split(ZoneList<CharacterRange>* base, - Vector<const uc16> overlay, + Vector<const int> overlay, ZoneList<CharacterRange>** included, ZoneList<CharacterRange>** excluded) { ASSERT_EQ(NULL, *included); @@ -4178,7 +5078,7 @@ void CharacterRange::Split(ZoneList<CharacterRange>* base, for (int i = 0; i < base->length(); i++) table.AddRange(base->at(i), CharacterRangeSplitter::kInBase); for (int i = 0; i < overlay.length(); i += 2) { - table.AddRange(CharacterRange(overlay[i], overlay[i+1]), + table.AddRange(CharacterRange(overlay[i], overlay[i + 1] - 1), CharacterRangeSplitter::kInOverlay); } CharacterRangeSplitter callback(included, excluded); @@ -4226,7 +5126,7 @@ void CharacterRange::AddCaseEquivalents(ZoneList<CharacterRange>* ranges, // as a "singleton block"). unibrow::uchar range[unibrow::Ecma262UnCanonicalize::kMaxWidth]; int pos = bottom; - while (pos < top) { + while (pos <= top) { int length = isolate->jsregexp_canonrange()->get(pos, '\0', range); uc16 block_end; if (length == 0) { @@ -4264,87 +5164,6 @@ bool CharacterRange::IsCanonical(ZoneList<CharacterRange>* ranges) { return true; } -SetRelation CharacterRange::WordCharacterRelation( - ZoneList<CharacterRange>* range) { - ASSERT(IsCanonical(range)); - int i = 0; // Word character range index. - int j = 0; // Argument range index. - ASSERT_NE(0, kWordRangeCount); - SetRelation result; - if (range->length() == 0) { - result.SetElementsInSecondSet(); - return result; - } - CharacterRange argument_range = range->at(0); - CharacterRange word_range = CharacterRange(kWordRanges[0], kWordRanges[1]); - while (i < kWordRangeCount && j < range->length()) { - // Check the two ranges for the five cases: - // - no overlap. - // - partial overlap (there are elements in both ranges that isn't - // in the other, and there are also elements that are in both). - // - argument range entirely inside word range. - // - word range entirely inside argument range. - // - ranges are completely equal. - - // First check for no overlap. The earlier range is not in the other set. - if (argument_range.from() > word_range.to()) { - // Ranges are disjoint. The earlier word range contains elements that - // cannot be in the argument set. - result.SetElementsInSecondSet(); - } else if (word_range.from() > argument_range.to()) { - // Ranges are disjoint. The earlier argument range contains elements that - // cannot be in the word set. - result.SetElementsInFirstSet(); - } else if (word_range.from() <= argument_range.from() && - word_range.to() >= argument_range.from()) { - result.SetElementsInBothSets(); - // argument range completely inside word range. - if (word_range.from() < argument_range.from() || - word_range.to() > argument_range.from()) { - result.SetElementsInSecondSet(); - } - } else if (word_range.from() >= argument_range.from() && - word_range.to() <= argument_range.from()) { - result.SetElementsInBothSets(); - result.SetElementsInFirstSet(); - } else { - // There is overlap, and neither is a subrange of the other - result.SetElementsInFirstSet(); - result.SetElementsInSecondSet(); - result.SetElementsInBothSets(); - } - if (result.NonTrivialIntersection()) { - // The result is as (im)precise as we can possibly make it. - return result; - } - // Progress the range(s) with minimal to-character. - uc16 word_to = word_range.to(); - uc16 argument_to = argument_range.to(); - if (argument_to <= word_to) { - j++; - if (j < range->length()) { - argument_range = range->at(j); - } - } - if (word_to <= argument_to) { - i += 2; - if (i < kWordRangeCount) { - word_range = CharacterRange(kWordRanges[i], kWordRanges[i + 1]); - } - } - } - // Check if anything wasn't compared in the loop. - if (i < kWordRangeCount) { - // word range contains something not in argument range. - result.SetElementsInSecondSet(); - } else if (j < range->length()) { - // Argument range contains something not in word range. - result.SetElementsInFirstSet(); - } - - return result; -} - ZoneList<CharacterRange>* CharacterSet::ranges() { if (ranges_ == NULL) { @@ -4477,145 +5296,6 @@ void CharacterRange::Canonicalize(ZoneList<CharacterRange>* character_ranges) { } -// Utility function for CharacterRange::Merge. Adds a range at the end of -// a canonicalized range list, if necessary merging the range with the last -// range of the list. -static void AddRangeToSet(ZoneList<CharacterRange>* set, CharacterRange range) { - if (set == NULL) return; - ASSERT(set->length() == 0 || set->at(set->length() - 1).to() < range.from()); - int n = set->length(); - if (n > 0) { - CharacterRange lastRange = set->at(n - 1); - if (lastRange.to() == range.from() - 1) { - set->at(n - 1) = CharacterRange(lastRange.from(), range.to()); - return; - } - } - set->Add(range); -} - - -static void AddRangeToSelectedSet(int selector, - ZoneList<CharacterRange>* first_set, - ZoneList<CharacterRange>* second_set, - ZoneList<CharacterRange>* intersection_set, - CharacterRange range) { - switch (selector) { - case kInsideFirst: - AddRangeToSet(first_set, range); - break; - case kInsideSecond: - AddRangeToSet(second_set, range); - break; - case kInsideBoth: - AddRangeToSet(intersection_set, range); - break; - } -} - - - -void CharacterRange::Merge(ZoneList<CharacterRange>* first_set, - ZoneList<CharacterRange>* second_set, - ZoneList<CharacterRange>* first_set_only_out, - ZoneList<CharacterRange>* second_set_only_out, - ZoneList<CharacterRange>* both_sets_out) { - // Inputs are canonicalized. - ASSERT(CharacterRange::IsCanonical(first_set)); - ASSERT(CharacterRange::IsCanonical(second_set)); - // Outputs are empty, if applicable. - ASSERT(first_set_only_out == NULL || first_set_only_out->length() == 0); - ASSERT(second_set_only_out == NULL || second_set_only_out->length() == 0); - ASSERT(both_sets_out == NULL || both_sets_out->length() == 0); - - // Merge sets by iterating through the lists in order of lowest "from" value, - // and putting intervals into one of three sets. - - if (first_set->length() == 0) { - second_set_only_out->AddAll(*second_set); - return; - } - if (second_set->length() == 0) { - first_set_only_out->AddAll(*first_set); - return; - } - // Indices into input lists. - int i1 = 0; - int i2 = 0; - // Cache length of input lists. - int n1 = first_set->length(); - int n2 = second_set->length(); - // Current range. May be invalid if state is kInsideNone. - int from = 0; - int to = -1; - // Where current range comes from. - int state = kInsideNone; - - while (i1 < n1 || i2 < n2) { - CharacterRange next_range; - int range_source; - if (i2 == n2 || - (i1 < n1 && first_set->at(i1).from() < second_set->at(i2).from())) { - // Next smallest element is in first set. - next_range = first_set->at(i1++); - range_source = kInsideFirst; - } else { - // Next smallest element is in second set. - next_range = second_set->at(i2++); - range_source = kInsideSecond; - } - if (to < next_range.from()) { - // Ranges disjoint: |current| |next| - AddRangeToSelectedSet(state, - first_set_only_out, - second_set_only_out, - both_sets_out, - CharacterRange(from, to)); - from = next_range.from(); - to = next_range.to(); - state = range_source; - } else { - if (from < next_range.from()) { - AddRangeToSelectedSet(state, - first_set_only_out, - second_set_only_out, - both_sets_out, - CharacterRange(from, next_range.from()-1)); - } - if (to < next_range.to()) { - // Ranges overlap: |current| - // |next| - AddRangeToSelectedSet(state | range_source, - first_set_only_out, - second_set_only_out, - both_sets_out, - CharacterRange(next_range.from(), to)); - from = to + 1; - to = next_range.to(); - state = range_source; - } else { - // Range included: |current| , possibly ending at same character. - // |next| - AddRangeToSelectedSet( - state | range_source, - first_set_only_out, - second_set_only_out, - both_sets_out, - CharacterRange(next_range.from(), next_range.to())); - from = next_range.to() + 1; - // If ranges end at same character, both ranges are consumed completely. - if (next_range.to() == to) state = kInsideNone; - } - } - } - AddRangeToSelectedSet(state, - first_set_only_out, - second_set_only_out, - both_sets_out, - CharacterRange(from, to)); -} - - void CharacterRange::Negate(ZoneList<CharacterRange>* ranges, ZoneList<CharacterRange>* negated_ranges) { ASSERT(CharacterRange::IsCanonical(ranges)); @@ -4639,45 +5319,6 @@ void CharacterRange::Negate(ZoneList<CharacterRange>* ranges, } - -// ------------------------------------------------------------------- -// Interest propagation - - -RegExpNode* RegExpNode::TryGetSibling(NodeInfo* info) { - for (int i = 0; i < siblings_.length(); i++) { - RegExpNode* sibling = siblings_.Get(i); - if (sibling->info()->Matches(info)) - return sibling; - } - return NULL; -} - - -RegExpNode* RegExpNode::EnsureSibling(NodeInfo* info, bool* cloned) { - ASSERT_EQ(false, *cloned); - siblings_.Ensure(this); - RegExpNode* result = TryGetSibling(info); - if (result != NULL) return result; - result = this->Clone(); - NodeInfo* new_info = result->info(); - new_info->ResetCompilationState(); - new_info->AddFromPreceding(info); - AddSibling(result); - *cloned = true; - return result; -} - - -template <class C> -static RegExpNode* PropagateToEndpoint(C* node, NodeInfo* info) { - NodeInfo full_info(*node->info()); - full_info.AddFromPreceding(info); - bool cloned = false; - return RegExpNode::EnsureSibling(node, &full_info, &cloned); -} - - // ------------------------------------------------------------------- // Splay tree @@ -4928,213 +5569,99 @@ void Analysis::VisitBackReference(BackReferenceNode* that) { void Analysis::VisitAssertion(AssertionNode* that) { EnsureAnalyzed(that->on_success()); - AssertionNode::AssertionNodeType type = that->type(); - if (type == AssertionNode::AT_BOUNDARY || - type == AssertionNode::AT_NON_BOUNDARY) { - // Check if the following character is known to be a word character - // or known to not be a word character. - ZoneList<CharacterRange>* following_chars = that->FirstCharacterSet(); - - CharacterRange::Canonicalize(following_chars); - - SetRelation word_relation = - CharacterRange::WordCharacterRelation(following_chars); - if (word_relation.Disjoint()) { - // Includes the case where following_chars is empty (e.g., end-of-input). - // Following character is definitely *not* a word character. - type = (type == AssertionNode::AT_BOUNDARY) ? - AssertionNode::AFTER_WORD_CHARACTER : - AssertionNode::AFTER_NONWORD_CHARACTER; - that->set_type(type); - } else if (word_relation.ContainedIn()) { - // Following character is definitely a word character. - type = (type == AssertionNode::AT_BOUNDARY) ? - AssertionNode::AFTER_NONWORD_CHARACTER : - AssertionNode::AFTER_WORD_CHARACTER; - that->set_type(type); - } - } -} - - -ZoneList<CharacterRange>* RegExpNode::FirstCharacterSet() { - if (first_character_set_ == NULL) { - if (ComputeFirstCharacterSet(kFirstCharBudget) < 0) { - // If we can't find an exact solution within the budget, we - // set the value to the set of every character, i.e., all characters - // are possible. - ZoneList<CharacterRange>* all_set = new ZoneList<CharacterRange>(1); - all_set->Add(CharacterRange::Everything()); - first_character_set_ = all_set; - } - } - return first_character_set_; } -int RegExpNode::ComputeFirstCharacterSet(int budget) { - // Default behavior is to not be able to determine the first character. - return kComputeFirstCharacterSetFail; +void BackReferenceNode::FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start) { + // Working out the set of characters that a backreference can match is too + // hard, so we just say that any character can match. + bm->SetRest(offset); + SaveBMInfo(bm, not_at_start, offset); } -int LoopChoiceNode::ComputeFirstCharacterSet(int budget) { - budget--; - if (budget >= 0) { - // Find loop min-iteration. It's the value of the guarded choice node - // with a GEQ guard, if any. - int min_repetition = 0; +STATIC_ASSERT(BoyerMoorePositionInfo::kMapSize == + RegExpMacroAssembler::kTableSize); - for (int i = 0; i <= 1; i++) { - GuardedAlternative alternative = alternatives()->at(i); - ZoneList<Guard*>* guards = alternative.guards(); - if (guards != NULL && guards->length() > 0) { - Guard* guard = guards->at(0); - if (guard->op() == Guard::GEQ) { - min_repetition = guard->value(); - break; - } - } - } - - budget = loop_node()->ComputeFirstCharacterSet(budget); - if (budget >= 0) { - ZoneList<CharacterRange>* character_set = - loop_node()->first_character_set(); - if (body_can_be_zero_length() || min_repetition == 0) { - budget = continue_node()->ComputeFirstCharacterSet(budget); - if (budget < 0) return budget; - ZoneList<CharacterRange>* body_set = - continue_node()->first_character_set(); - ZoneList<CharacterRange>* union_set = - new ZoneList<CharacterRange>(Max(character_set->length(), - body_set->length())); - CharacterRange::Merge(character_set, - body_set, - union_set, - union_set, - union_set); - character_set = union_set; - } - set_first_character_set(character_set); - } - } - return budget; -} - -int NegativeLookaheadChoiceNode::ComputeFirstCharacterSet(int budget) { - budget--; - if (budget >= 0) { - GuardedAlternative successor = this->alternatives()->at(1); - RegExpNode* successor_node = successor.node(); - budget = successor_node->ComputeFirstCharacterSet(budget); - if (budget >= 0) { - set_first_character_set(successor_node->first_character_set()); - } - } - return budget; -} - - -// The first character set of an EndNode is unknowable. Just use the -// default implementation that fails and returns all characters as possible. - - -int AssertionNode::ComputeFirstCharacterSet(int budget) { - budget -= 1; - if (budget >= 0) { - switch (type_) { - case AT_END: { - set_first_character_set(new ZoneList<CharacterRange>(0)); - break; - } - case AT_START: - case AT_BOUNDARY: - case AT_NON_BOUNDARY: - case AFTER_NEWLINE: - case AFTER_NONWORD_CHARACTER: - case AFTER_WORD_CHARACTER: { - ASSERT_NOT_NULL(on_success()); - budget = on_success()->ComputeFirstCharacterSet(budget); - if (budget >= 0) { - set_first_character_set(on_success()->first_character_set()); - } - break; - } +void ChoiceNode::FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start) { + ZoneList<GuardedAlternative>* alts = alternatives(); + for (int i = 0; i < alts->length(); i++) { + GuardedAlternative& alt = alts->at(i); + if (alt.guards() != NULL && alt.guards()->length() != 0) { + bm->SetRest(offset); // Give up trying to fill in info. + SaveBMInfo(bm, not_at_start, offset); + return; } + alt.node()->FillInBMInfo(offset, bm, not_at_start); } - return budget; + SaveBMInfo(bm, not_at_start, offset); } -int ActionNode::ComputeFirstCharacterSet(int budget) { - if (type_ == POSITIVE_SUBMATCH_SUCCESS) return kComputeFirstCharacterSetFail; - budget--; - if (budget >= 0) { - ASSERT_NOT_NULL(on_success()); - budget = on_success()->ComputeFirstCharacterSet(budget); - if (budget >= 0) { - set_first_character_set(on_success()->first_character_set()); +void TextNode::FillInBMInfo( + int initial_offset, BoyerMooreLookahead* bm, bool not_at_start) { + if (initial_offset >= bm->length()) return; + int offset = initial_offset; + int max_char = bm->max_char(); + for (int i = 0; i < elements()->length(); i++) { + if (offset >= bm->length()) { + if (initial_offset == 0) set_bm_info(not_at_start, bm); + return; } - } - return budget; -} - - -int BackReferenceNode::ComputeFirstCharacterSet(int budget) { - // We don't know anything about the first character of a backreference - // at this point. - // The potential first characters are the first characters of the capture, - // and the first characters of the on_success node, depending on whether the - // capture can be empty and whether it is known to be participating or known - // not to be. - return kComputeFirstCharacterSetFail; -} - - -int TextNode::ComputeFirstCharacterSet(int budget) { - budget--; - if (budget >= 0) { - ASSERT_NE(0, elements()->length()); - TextElement text = elements()->at(0); + TextElement text = elements()->at(i); if (text.type == TextElement::ATOM) { RegExpAtom* atom = text.data.u_atom; - ASSERT_NE(0, atom->length()); - uc16 first_char = atom->data()[0]; - ZoneList<CharacterRange>* range = new ZoneList<CharacterRange>(1); - range->Add(CharacterRange(first_char, first_char)); - set_first_character_set(range); + for (int j = 0; j < atom->length(); j++, offset++) { + if (offset >= bm->length()) { + if (initial_offset == 0) set_bm_info(not_at_start, bm); + return; + } + uc16 character = atom->data()[j]; + if (bm->compiler()->ignore_case()) { + unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; + int length = GetCaseIndependentLetters( + ISOLATE, + character, + bm->max_char() == String::kMaxAsciiCharCode, + chars); + for (int j = 0; j < length; j++) { + bm->Set(offset, chars[j]); + } + } else { + if (character <= max_char) bm->Set(offset, character); + } + } } else { ASSERT(text.type == TextElement::CHAR_CLASS); RegExpCharacterClass* char_class = text.data.u_char_class; ZoneList<CharacterRange>* ranges = char_class->ranges(); - // TODO(lrn): Canonicalize ranges when they are created - // instead of waiting until now. - CharacterRange::Canonicalize(ranges); if (char_class->is_negated()) { - int length = ranges->length(); - int new_length = length + 1; - if (length > 0) { - if (ranges->at(0).from() == 0) new_length--; - if (ranges->at(length - 1).to() == String::kMaxUtf16CodeUnit) { - new_length--; - } - } - ZoneList<CharacterRange>* negated_ranges = - new ZoneList<CharacterRange>(new_length); - CharacterRange::Negate(ranges, negated_ranges); - set_first_character_set(negated_ranges); + bm->SetAll(offset); } else { - set_first_character_set(ranges); + for (int k = 0; k < ranges->length(); k++) { + CharacterRange& range = ranges->at(k); + if (range.from() > max_char) continue; + int to = Min(max_char, static_cast<int>(range.to())); + bm->SetInterval(offset, Interval(range.from(), to)); + } } + offset++; } } - return budget; + if (offset >= bm->length()) { + if (initial_offset == 0) set_bm_info(not_at_start, bm); + return; + } + on_success()->FillInBMInfo(offset, + bm, + true); // Not at start after a text node. + if (initial_offset == 0) set_bm_info(not_at_start, bm); } - // ------------------------------------------------------------------- // Dispatch table construction @@ -5250,15 +5777,30 @@ void DispatchTableConstructor::VisitAction(ActionNode* that) { } -RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data, - bool ignore_case, - bool is_multiline, - Handle<String> pattern, - bool is_ascii) { +RegExpEngine::CompilationResult RegExpEngine::Compile( + RegExpCompileData* data, + bool ignore_case, + bool is_multiline, + Handle<String> pattern, + Handle<String> sample_subject, + bool is_ascii) { if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) { return IrregexpRegExpTooBig(); } RegExpCompiler compiler(data->capture_count, ignore_case, is_ascii); + + // Sample some characters from the middle of the string. + static const int kSampleSize = 128; + + FlattenString(sample_subject); + int chars_sampled = 0; + int half_way = (sample_subject->length() - kSampleSize) / 2; + for (int i = Max(0, half_way); + i < sample_subject->length() && chars_sampled < kSampleSize; + i++, chars_sampled++) { + compiler.frequency_collator()->CountCharacter(sample_subject->Get(i)); + } + // Wrap the body of the regexp in capture #0. RegExpNode* captured_body = RegExpCapture::ToNode(data->tree, 0, @@ -5292,6 +5834,14 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data, node = loop_node; } } + if (is_ascii) { + node = node->FilterASCII(RegExpCompiler::kMaxRecursion); + // Do it again to propagate the new nodes to places where they were not + // put because they had not been calculated yet. + if (node != NULL) node = node->FilterASCII(RegExpCompiler::kMaxRecursion); + } + + if (node == NULL) node = new EndNode(EndNode::BACKTRACK); data->node = node; Analysis analysis(ignore_case, is_ascii); analysis.EnsureAnalyzed(node); diff --git a/deps/v8/src/jsregexp.h b/deps/v8/src/jsregexp.h index 8875de9eb2..20313ca559 100644 --- a/deps/v8/src/jsregexp.h +++ b/deps/v8/src/jsregexp.h @@ -40,6 +40,7 @@ class RegExpCompiler; class RegExpMacroAssembler; class RegExpNode; class RegExpTree; +class BoyerMooreLookahead; class RegExpImpl { public: @@ -190,8 +191,10 @@ class RegExpImpl { static String* last_ascii_string_; static String* two_byte_cached_string_; - static bool CompileIrregexp(Handle<JSRegExp> re, bool is_ascii); - static inline bool EnsureCompiledIrregexp(Handle<JSRegExp> re, bool is_ascii); + static bool CompileIrregexp( + Handle<JSRegExp> re, Handle<String> sample_subject, bool is_ascii); + static inline bool EnsureCompiledIrregexp( + Handle<JSRegExp> re, Handle<String> sample_subject, bool is_ascii); // Set the subject cache. The previous string buffer is not deleted, so the @@ -222,48 +225,8 @@ enum ElementInSetsRelation { }; -// Represents the relation of two sets. -// Sets can be either disjoint, partially or fully overlapping, or equal. -class SetRelation BASE_EMBEDDED { - public: - // Relation is represented by a bit saying whether there are elements in - // one set that is not in the other, and a bit saying that there are elements - // that are in both sets. - - // Location of an element. Corresponds to the internal areas of - // a Venn diagram. - enum { - kInFirst = 1 << kInsideFirst, - kInSecond = 1 << kInsideSecond, - kInBoth = 1 << kInsideBoth - }; - SetRelation() : bits_(0) {} - ~SetRelation() {} - // Add the existence of objects in a particular - void SetElementsInFirstSet() { bits_ |= kInFirst; } - void SetElementsInSecondSet() { bits_ |= kInSecond; } - void SetElementsInBothSets() { bits_ |= kInBoth; } - // Check the currently known relation of the sets (common functions only, - // for other combinations, use value() to get the bits and check them - // manually). - // Sets are completely disjoint. - bool Disjoint() { return (bits_ & kInBoth) == 0; } - // Sets are equal. - bool Equals() { return (bits_ & (kInFirst | kInSecond)) == 0; } - // First set contains second. - bool Contains() { return (bits_ & kInSecond) == 0; } - // Second set contains first. - bool ContainedIn() { return (bits_ & kInFirst) == 0; } - bool NonTrivialIntersection() { - return (bits_ == (kInFirst | kInSecond | kInBoth)); - } - int value() { return bits_; } - - private: - int bits_; -}; - - +// Represents code units in the range from from_ to to_, both ends are +// inclusive. class CharacterRange { public: CharacterRange() : from_(0), to_(0) { } @@ -271,7 +234,7 @@ class CharacterRange { CharacterRange(void* null) { ASSERT_EQ(NULL, null); } //NOLINT CharacterRange(uc16 from, uc16 to) : from_(from), to_(to) { } static void AddClassEscape(uc16 type, ZoneList<CharacterRange>* ranges); - static Vector<const uc16> GetWordBounds(); + static Vector<const int> GetWordBounds(); static inline CharacterRange Singleton(uc16 value) { return CharacterRange(value, value); } @@ -292,7 +255,7 @@ class CharacterRange { bool IsSingleton() { return (from_ == to_); } void AddCaseEquivalents(ZoneList<CharacterRange>* ranges, bool is_ascii); static void Split(ZoneList<CharacterRange>* base, - Vector<const uc16> overlay, + Vector<const int> overlay, ZoneList<CharacterRange>** included, ZoneList<CharacterRange>** excluded); // Whether a range list is in canonical form: Ranges ordered by from value, @@ -303,28 +266,6 @@ class CharacterRange { // adjacent ranges are merged. The resulting list may be shorter than the // original, but cannot be longer. static void Canonicalize(ZoneList<CharacterRange>* ranges); - // Check how the set of characters defined by a CharacterRange list relates - // to the set of word characters. List must be in canonical form. - static SetRelation WordCharacterRelation(ZoneList<CharacterRange>* ranges); - // Takes two character range lists (representing character sets) in canonical - // form and merges them. - // The characters that are only covered by the first set are added to - // first_set_only_out. the characters that are only in the second set are - // added to second_set_only_out, and the characters that are in both are - // added to both_sets_out. - // The pointers to first_set_only_out, second_set_only_out and both_sets_out - // should be to empty lists, but they need not be distinct, and may be NULL. - // If NULL, the characters are dropped, and if two arguments are the same - // pointer, the result is the union of the two sets that would be created - // if the pointers had been distinct. - // This way, the Merge function can compute all the usual set operations: - // union (all three out-sets are equal), intersection (only both_sets_out is - // non-NULL), and set difference (only first_set is non-NULL). - static void Merge(ZoneList<CharacterRange>* first_set, - ZoneList<CharacterRange>* second_set, - ZoneList<CharacterRange>* first_set_only_out, - ZoneList<CharacterRange>* second_set_only_out, - ZoneList<CharacterRange>* both_sets_out); // Negate the contents of a character range in canonical form. static void Negate(ZoneList<CharacterRange>* src, ZoneList<CharacterRange>* dst); @@ -475,7 +416,8 @@ struct NodeInfo { follows_newline_interest(false), follows_start_interest(false), at_end(false), - visited(false) { } + visited(false), + replacement_calculated(false) { } // Returns true if the interests and assumptions of this node // matches the given one. @@ -525,25 +467,7 @@ struct NodeInfo { bool at_end: 1; bool visited: 1; -}; - - -class SiblingList { - public: - SiblingList() : list_(NULL) { } - int length() { - return list_ == NULL ? 0 : list_->length(); - } - void Ensure(RegExpNode* parent) { - if (list_ == NULL) { - list_ = new ZoneList<RegExpNode*>(2); - list_->Add(parent); - } - } - void Add(RegExpNode* node) { list_->Add(node); } - RegExpNode* Get(int index) { return list_->at(index); } - private: - ZoneList<RegExpNode*>* list_; + bool replacement_calculated: 1; }; @@ -599,9 +523,14 @@ class QuickCheckDetails { }; +extern int kUninitializedRegExpNodePlaceHolder; + + class RegExpNode: public ZoneObject { public: - RegExpNode() : first_character_set_(NULL), trace_count_(0) { } + RegExpNode() : replacement_(NULL), trace_count_(0) { + bm_info_[0] = bm_info_[1] = NULL; + } virtual ~RegExpNode(); virtual void Accept(NodeVisitor* visitor) = 0; // Generates a goto to this node or actually generates the code at this point. @@ -635,6 +564,45 @@ class RegExpNode: public ZoneObject { bool not_at_start) = 0; static const int kNodeIsTooComplexForGreedyLoops = -1; virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } + // Only returns the successor for a text node of length 1 that matches any + // character and that has no guards on it. + virtual RegExpNode* GetSuccessorOfOmnivorousTextNode( + RegExpCompiler* compiler) { + return NULL; + } + + // Collects information on the possible code units (mod 128) that can match if + // we look forward. This is used for a Boyer-Moore-like string searching + // implementation. TODO(erikcorry): This should share more code with + // EatsAtLeast, GetQuickCheckDetails. + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start) { + UNREACHABLE(); + } + + // If we know that the input is ASCII then there are some nodes that can + // never match. This method returns a node that can be substituted for + // itself, or NULL if the node can never match. + virtual RegExpNode* FilterASCII(int depth) { return this; } + // Helper for FilterASCII. + RegExpNode* replacement() { + ASSERT(info()->replacement_calculated); + return replacement_; + } + RegExpNode* set_replacement(RegExpNode* replacement) { + info()->replacement_calculated = true; + replacement_ = replacement; + return replacement; // For convenience. + } + + // We want to avoid recalculating the lookahead info, so we store it on the + // node. Only info that is for this node is stored. We can tell that the + // info is for this node when offset == 0, so the information is calculated + // relative to this node. + void SaveBMInfo(BoyerMooreLookahead* bm, bool not_at_start, int offset) { + if (offset == 0) set_bm_info(not_at_start, bm); + } + Label* label() { return &label_; } // If non-generic code is generated for a node (i.e. the node is not at the // start of the trace) then it cannot be reused. This variable sets a limit @@ -645,72 +613,31 @@ class RegExpNode: public ZoneObject { NodeInfo* info() { return &info_; } - void AddSibling(RegExpNode* node) { siblings_.Add(node); } - - // Static version of EnsureSibling that expresses the fact that the - // result has the same type as the input. - template <class C> - static C* EnsureSibling(C* node, NodeInfo* info, bool* cloned) { - return static_cast<C*>(node->EnsureSibling(info, cloned)); - } - - SiblingList* siblings() { return &siblings_; } - void set_siblings(SiblingList* other) { siblings_ = *other; } - - // Return the set of possible next characters recognized by the regexp - // (or a safe subset, potentially the set of all characters). - ZoneList<CharacterRange>* FirstCharacterSet(); - - // Compute (if possible within the budget of traversed nodes) the - // possible first characters of the input matched by this node and - // its continuation. Returns the remaining budget after the computation. - // If the budget is spent, the result is negative, and the cached - // first_character_set_ value isn't set. - virtual int ComputeFirstCharacterSet(int budget); - - // Get and set the cached first character set value. - ZoneList<CharacterRange>* first_character_set() { - return first_character_set_; - } - void set_first_character_set(ZoneList<CharacterRange>* character_set) { - first_character_set_ = character_set; + BoyerMooreLookahead* bm_info(bool not_at_start) { + return bm_info_[not_at_start ? 1 : 0]; } protected: enum LimitResult { DONE, CONTINUE }; - static const int kComputeFirstCharacterSetFail = -1; + RegExpNode* replacement_; LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace); - // Returns a sibling of this node whose interests and assumptions - // match the ones in the given node info. If no sibling exists NULL - // is returned. - RegExpNode* TryGetSibling(NodeInfo* info); - - // Returns a sibling of this node whose interests match the ones in - // the given node info. The info must not contain any assertions. - // If no node exists a new one will be created by cloning the current - // node. The result will always be an instance of the same concrete - // class as this node. - RegExpNode* EnsureSibling(NodeInfo* info, bool* cloned); - - // Returns a clone of this node initialized using the copy constructor - // of its concrete class. Note that the node may have to be pre- - // processed before it is on a usable state. - virtual RegExpNode* Clone() = 0; + void set_bm_info(bool not_at_start, BoyerMooreLookahead* bm) { + bm_info_[not_at_start ? 1 : 0] = bm; + } private: static const int kFirstCharBudget = 10; Label label_; NodeInfo info_; - SiblingList siblings_; - ZoneList<CharacterRange>* first_character_set_; // This variable keeps track of how many times code has been generated for // this node (in different traces). We don't keep track of where the // generated code is located unless the code is generated at the start of // a trace, in which case it is generic and can be reused by flushing the // deferred operations in the current trace and generating a goto. int trace_count_; + BoyerMooreLookahead* bm_info_[2]; }; @@ -731,8 +658,8 @@ class Interval { return (from_ <= value) && (value <= to_); } bool is_empty() { return from_ == kNone; } - int from() { return from_; } - int to() { return to_; } + int from() const { return from_; } + int to() const { return to_; } static Interval Empty() { return Interval(); } static const int kNone = -1; private: @@ -747,6 +674,16 @@ class SeqRegExpNode: public RegExpNode { : on_success_(on_success) { } RegExpNode* on_success() { return on_success_; } void set_on_success(RegExpNode* node) { on_success_ = node; } + virtual RegExpNode* FilterASCII(int depth); + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start) { + on_success_->FillInBMInfo(offset, bm, not_at_start); + if (offset == 0) set_bm_info(not_at_start, bm); + } + + protected: + RegExpNode* FilterSuccessor(int depth); + private: RegExpNode* on_success_; }; @@ -793,11 +730,11 @@ class ActionNode: public SeqRegExpNode { return on_success()->GetQuickCheckDetails( details, compiler, filled_in, not_at_start); } + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start); Type type() { return type_; } // TODO(erikcorry): We should allow some action nodes in greedy loops. virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } - virtual ActionNode* Clone() { return new ActionNode(*this); } - virtual int ComputeFirstCharacterSet(int budget); private: union { @@ -860,13 +797,12 @@ class TextNode: public SeqRegExpNode { ZoneList<TextElement>* elements() { return elms_; } void MakeCaseIndependent(bool is_ascii); virtual int GreedyLoopTextLength(); - virtual TextNode* Clone() { - TextNode* result = new TextNode(*this); - result->CalculateOffsets(); - return result; - } + virtual RegExpNode* GetSuccessorOfOmnivorousTextNode( + RegExpCompiler* compiler); + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start); void CalculateOffsets(); - virtual int ComputeFirstCharacterSet(int budget); + virtual RegExpNode* FilterASCII(int depth); private: enum TextEmitPassType { @@ -897,12 +833,7 @@ class AssertionNode: public SeqRegExpNode { AT_START, AT_BOUNDARY, AT_NON_BOUNDARY, - AFTER_NEWLINE, - // Types not directly expressible in regexp syntax. - // Used for modifying a boundary node if its following character is - // known to be word and/or non-word. - AFTER_NONWORD_CHARACTER, - AFTER_WORD_CHARACTER + AFTER_NEWLINE }; static AssertionNode* AtEnd(RegExpNode* on_success) { return new AssertionNode(AT_END, on_success); @@ -928,12 +859,17 @@ class AssertionNode: public SeqRegExpNode { RegExpCompiler* compiler, int filled_in, bool not_at_start); - virtual int ComputeFirstCharacterSet(int budget); - virtual AssertionNode* Clone() { return new AssertionNode(*this); } + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start); AssertionNodeType type() { return type_; } void set_type(AssertionNodeType type) { type_ = type; } private: + void EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace); + enum IfPrevious { kIsNonWord, kIsWord }; + void BacktrackIfPrevious(RegExpCompiler* compiler, + Trace* trace, + IfPrevious backtrack_if_previous); AssertionNode(AssertionNodeType t, RegExpNode* on_success) : SeqRegExpNode(on_success), type_(t) { } AssertionNodeType type_; @@ -961,8 +897,8 @@ class BackReferenceNode: public SeqRegExpNode { bool not_at_start) { return; } - virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); } - virtual int ComputeFirstCharacterSet(int budget); + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start); private: int start_reg_; @@ -986,7 +922,12 @@ class EndNode: public RegExpNode { // Returning 0 from EatsAtLeast should ensure we never get here. UNREACHABLE(); } - virtual EndNode* Clone() { return new EndNode(*this); } + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start) { + // Returning 0 from EatsAtLeast should ensure we never get here. + UNREACHABLE(); + } + private: Action action_; }; @@ -1071,13 +1012,15 @@ class ChoiceNode: public RegExpNode { RegExpCompiler* compiler, int characters_filled_in, bool not_at_start); - virtual ChoiceNode* Clone() { return new ChoiceNode(*this); } + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start); bool being_calculated() { return being_calculated_; } bool not_at_start() { return not_at_start_; } void set_not_at_start() { not_at_start_ = true; } void set_being_calculated(bool b) { being_calculated_ = b; } virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; } + virtual RegExpNode* FilterASCII(int depth); protected: int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative); @@ -1089,7 +1032,7 @@ class ChoiceNode: public RegExpNode { void GenerateGuard(RegExpMacroAssembler* macro_assembler, Guard* guard, Trace* trace); - int CalculatePreloadCharacters(RegExpCompiler* compiler, bool not_at_start); + int CalculatePreloadCharacters(RegExpCompiler* compiler, int eats_at_least); void EmitOutOfLineContinuation(RegExpCompiler* compiler, Trace* trace, GuardedAlternative alternative, @@ -1119,13 +1062,18 @@ class NegativeLookaheadChoiceNode: public ChoiceNode { RegExpCompiler* compiler, int characters_filled_in, bool not_at_start); + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start) { + alternatives_->at(1).node()->FillInBMInfo(offset, bm, not_at_start); + if (offset == 0) set_bm_info(not_at_start, bm); + } // For a negative lookahead we don't emit the quick check for the // alternative that is expected to fail. This is because quick check code // starts by loading enough characters for the alternative that takes fewest // characters, but on a negative lookahead the negative branch did not take // part in that calculation (EatsAtLeast) so the assumptions don't hold. virtual bool try_to_emit_quick_check_for_alternative(int i) { return i != 0; } - virtual int ComputeFirstCharacterSet(int budget); + virtual RegExpNode* FilterASCII(int depth); }; @@ -1146,12 +1094,13 @@ class LoopChoiceNode: public ChoiceNode { RegExpCompiler* compiler, int characters_filled_in, bool not_at_start); - virtual int ComputeFirstCharacterSet(int budget); - virtual LoopChoiceNode* Clone() { return new LoopChoiceNode(*this); } + virtual void FillInBMInfo( + int offset, BoyerMooreLookahead* bm, bool not_at_start); RegExpNode* loop_node() { return loop_node_; } RegExpNode* continue_node() { return continue_node_; } bool body_can_be_zero_length() { return body_can_be_zero_length_; } virtual void Accept(NodeVisitor* visitor); + virtual RegExpNode* FilterASCII(int depth); private: // AddAlternative is made private for loop nodes because alternatives @@ -1167,6 +1116,146 @@ class LoopChoiceNode: public ChoiceNode { }; +// Improve the speed that we scan for an initial point where a non-anchored +// regexp can match by using a Boyer-Moore-like table. This is done by +// identifying non-greedy non-capturing loops in the nodes that eat any +// character one at a time. For example in the middle of the regexp +// /foo[\s\S]*?bar/ we find such a loop. There is also such a loop implicitly +// inserted at the start of any non-anchored regexp. +// +// When we have found such a loop we look ahead in the nodes to find the set of +// characters that can come at given distances. For example for the regexp +// /.?foo/ we know that there are at least 3 characters ahead of us, and the +// sets of characters that can occur are [any, [f, o], [o]]. We find a range in +// the lookahead info where the set of characters is reasonably constrained. In +// our example this is from index 1 to 2 (0 is not constrained). We can now +// look 3 characters ahead and if we don't find one of [f, o] (the union of +// [f, o] and [o]) then we can skip forwards by the range size (in this case 2). +// +// For Unicode input strings we do the same, but modulo 128. +// +// We also look at the first string fed to the regexp and use that to get a hint +// of the character frequencies in the inputs. This affects the assessment of +// whether the set of characters is 'reasonably constrained'. +// +// We also have another lookahead mechanism (called quick check in the code), +// which uses a wide load of multiple characters followed by a mask and compare +// to determine whether a match is possible at this point. +enum ContainedInLattice { + kNotYet = 0, + kLatticeIn = 1, + kLatticeOut = 2, + kLatticeUnknown = 3 // Can also mean both in and out. +}; + + +inline ContainedInLattice Combine(ContainedInLattice a, ContainedInLattice b) { + return static_cast<ContainedInLattice>(a | b); +} + + +ContainedInLattice AddRange(ContainedInLattice a, + const int* ranges, + int ranges_size, + Interval new_range); + + +class BoyerMoorePositionInfo : public ZoneObject { + public: + BoyerMoorePositionInfo() + : map_(new ZoneList<bool>(kMapSize)), + map_count_(0), + w_(kNotYet), + s_(kNotYet), + d_(kNotYet), + surrogate_(kNotYet) { + for (int i = 0; i < kMapSize; i++) { + map_->Add(false); + } + } + + bool& at(int i) { return map_->at(i); } + + static const int kMapSize = 128; + static const int kMask = kMapSize - 1; + + int map_count() const { return map_count_; } + + void Set(int character); + void SetInterval(const Interval& interval); + void SetAll(); + bool is_non_word() { return w_ == kLatticeOut; } + bool is_word() { return w_ == kLatticeIn; } + + private: + ZoneList<bool>* map_; + int map_count_; // Number of set bits in the map. + ContainedInLattice w_; // The \w character class. + ContainedInLattice s_; // The \s character class. + ContainedInLattice d_; // The \d character class. + ContainedInLattice surrogate_; // Surrogate UTF-16 code units. +}; + + +class BoyerMooreLookahead : public ZoneObject { + public: + BoyerMooreLookahead(int length, RegExpCompiler* compiler); + + int length() { return length_; } + int max_char() { return max_char_; } + RegExpCompiler* compiler() { return compiler_; } + + int Count(int map_number) { + return bitmaps_->at(map_number)->map_count(); + } + + BoyerMoorePositionInfo* at(int i) { return bitmaps_->at(i); } + + void Set(int map_number, int character) { + if (character > max_char_) return; + BoyerMoorePositionInfo* info = bitmaps_->at(map_number); + info->Set(character); + } + + void SetInterval(int map_number, const Interval& interval) { + if (interval.from() > max_char_) return; + BoyerMoorePositionInfo* info = bitmaps_->at(map_number); + if (interval.to() > max_char_) { + info->SetInterval(Interval(interval.from(), max_char_)); + } else { + info->SetInterval(interval); + } + } + + void SetAll(int map_number) { + bitmaps_->at(map_number)->SetAll(); + } + + void SetRest(int from_map) { + for (int i = from_map; i < length_; i++) SetAll(i); + } + bool EmitSkipInstructions(RegExpMacroAssembler* masm); + + private: + // This is the value obtained by EatsAtLeast. If we do not have at least this + // many characters left in the sample string then the match is bound to fail. + // Therefore it is OK to read a character this far ahead of the current match + // point. + int length_; + RegExpCompiler* compiler_; + // 0x7f for ASCII, 0xffff for UTF-16. + int max_char_; + ZoneList<BoyerMoorePositionInfo*>* bitmaps_; + + int GetSkipTable(int min_lookahead, + int max_lookahead, + Handle<ByteArray> boolean_skip_table); + bool FindWorthwhileInterval(int* from, int* to); + int FindBestInterval( + int max_number_of_chars, int old_biggest_points, int* from, int* to); +}; + + // There are many ways to generate code for a node. This class encapsulates // the current way we should be generating. In other words it encapsulates // the current state of the code generator. The effect of this is that we @@ -1458,6 +1547,7 @@ class RegExpEngine: public AllStatic { bool ignore_case, bool multiline, Handle<String> pattern, + Handle<String> sample_subject, bool is_ascii); static void DotPrint(const char* label, RegExpNode* node, bool ignore_case); diff --git a/deps/v8/src/lazy-instance.h b/deps/v8/src/lazy-instance.h index 09dfe2154d..9d68b8cacc 100644 --- a/deps/v8/src/lazy-instance.h +++ b/deps/v8/src/lazy-instance.h @@ -65,6 +65,13 @@ // static LazyInstance<MyClass, MyCreateTrait>::type my_instance = // LAZY_INSTANCE_INITIALIZER; // +// WARNINGS: +// - This implementation of LazyInstance is NOT THREAD-SAFE by default. See +// ThreadSafeInitOnceTrait declared below for that. +// - Lazy initialization comes with a cost. Make sure that you don't use it on +// critical path. Consider adding your initialization code to a function +// which is explicitly called once. +// // Notes for advanced users: // LazyInstance can actually be used in two different ways: // @@ -104,9 +111,17 @@ struct LeakyInstanceTrait { // Traits that define how an instance is allocated and accessed. +// TODO(kalmard): __alignof__ is only defined for GCC > 4.2. Fix alignment issue +// on MIPS with other compilers. +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) +#define LAZY_ALIGN(x) __attribute__((aligned(__alignof__(x)))) +#else +#define LAZY_ALIGN(x) +#endif + template <typename T> struct StaticallyAllocatedInstanceTrait { - typedef char StorageType[sizeof(T)]; + typedef char StorageType[sizeof(T)] LAZY_ALIGN(T); static T* MutableInstance(StorageType* storage) { return reinterpret_cast<T*>(storage); @@ -118,6 +133,8 @@ struct StaticallyAllocatedInstanceTrait { } }; +#undef LAZY_ALIGN + template <typename T> struct DynamicallyAllocatedInstanceTrait { @@ -151,9 +168,29 @@ struct DefaultCreateTrait { }; +struct ThreadSafeInitOnceTrait { + template <typename Function, typename Storage> + static void Init(OnceType* once, Function function, Storage storage) { + CallOnce(once, function, storage); + } +}; + + +// Initialization trait for users who don't care about thread-safety. +struct SingleThreadInitOnceTrait { + template <typename Function, typename Storage> + static void Init(OnceType* once, Function function, Storage storage) { + if (*once == ONCE_STATE_UNINITIALIZED) { + function(storage); + *once = ONCE_STATE_DONE; + } + } +}; + + // TODO(pliard): Handle instances destruction (using global destructors). template <typename T, typename AllocationTrait, typename CreateTrait, - typename DestroyTrait /* not used yet. */ > + typename InitOnceTrait, typename DestroyTrait /* not used yet. */> struct LazyInstanceImpl { public: typedef typename AllocationTrait::StorageType StorageType; @@ -164,7 +201,12 @@ struct LazyInstanceImpl { } void Init() const { - CallOnce(&once_, &InitInstance, &storage_); + InitOnceTrait::Init( + &once_, + // Casts to void* are needed here to avoid breaking strict aliasing + // rules. + reinterpret_cast<void(*)(void*)>(&InitInstance), // NOLINT + reinterpret_cast<void*>(&storage_)); } public: @@ -180,35 +222,40 @@ struct LazyInstanceImpl { mutable OnceType once_; // Note that the previous field, OnceType, is an AtomicWord which guarantees - // the correct alignment of the storage field below. + // 4-byte alignment of the storage field below. If compiling with GCC (>4.2), + // the LAZY_ALIGN macro above will guarantee correctness for any alignment. mutable StorageType storage_; }; template <typename T, typename CreateTrait = DefaultConstructTrait<T>, + typename InitOnceTrait = SingleThreadInitOnceTrait, typename DestroyTrait = LeakyInstanceTrait<T> > struct LazyStaticInstance { - typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, CreateTrait, - DestroyTrait> type; + typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, + CreateTrait, InitOnceTrait, DestroyTrait> type; }; template <typename T, typename CreateTrait = DefaultConstructTrait<T>, + typename InitOnceTrait = SingleThreadInitOnceTrait, typename DestroyTrait = LeakyInstanceTrait<T> > struct LazyInstance { // A LazyInstance is a LazyStaticInstance. - typedef typename LazyStaticInstance<T, CreateTrait, DestroyTrait>::type type; + typedef typename LazyStaticInstance<T, CreateTrait, InitOnceTrait, + DestroyTrait>::type type; }; template <typename T, - typename CreateTrait = DefaultConstructTrait<T>, + typename CreateTrait = DefaultCreateTrait<T>, + typename InitOnceTrait = SingleThreadInitOnceTrait, typename DestroyTrait = LeakyInstanceTrait<T> > struct LazyDynamicInstance { - typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, CreateTrait, - DestroyTrait> type; + typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, + CreateTrait, InitOnceTrait, DestroyTrait> type; }; } } // namespace v8::internal diff --git a/deps/v8/src/list-inl.h b/deps/v8/src/list-inl.h index 7c2c83f0f7..6cf3badc62 100644 --- a/deps/v8/src/list-inl.h +++ b/deps/v8/src/list-inl.h @@ -137,6 +137,14 @@ bool List<T, P>::RemoveElement(const T& elm) { template<typename T, class P> +void List<T, P>::Allocate(int length) { + DeleteData(data_); + Initialize(length); + length_ = length; +} + + +template<typename T, class P> void List<T, P>::Clear() { DeleteData(data_); Initialize(0); @@ -207,20 +215,19 @@ void List<T, P>::Initialize(int capacity) { } -template <typename T> -int SortedListBSearch( - const List<T>& list, T elem, int (*cmp)(const T* x, const T* y)) { +template <typename T, typename P> +int SortedListBSearch(const List<T>& list, P cmp) { int low = 0; int high = list.length() - 1; while (low <= high) { int mid = (low + high) / 2; T mid_elem = list[mid]; - if (cmp(&mid_elem, &elem) > 0) { + if (cmp(&mid_elem) > 0) { high = mid - 1; continue; } - if (cmp(&mid_elem, &elem) < 0) { + if (cmp(&mid_elem) < 0) { low = mid + 1; continue; } @@ -231,9 +238,21 @@ int SortedListBSearch( } +template<typename T> +class ElementCmp { + public: + explicit ElementCmp(T e) : elem_(e) {} + int operator()(const T* other) { + return PointerValueCompare(other, &elem_); + } + private: + T elem_; +}; + + template <typename T> int SortedListBSearch(const List<T>& list, T elem) { - return SortedListBSearch<T>(list, elem, PointerValueCompare<T>); + return SortedListBSearch<T, ElementCmp<T> > (list, ElementCmp<T>(elem)); } diff --git a/deps/v8/src/list.h b/deps/v8/src/list.h index adddea41f0..7350c0d44e 100644 --- a/deps/v8/src/list.h +++ b/deps/v8/src/list.h @@ -117,6 +117,9 @@ class List { // pointer type. Returns the removed element. INLINE(T RemoveLast()) { return Remove(length_ - 1); } + // Deletes current list contents and allocates space for 'length' elements. + INLINE(void Allocate(int length)); + // Clears the list by setting the length to zero. Even if T is a // pointer type, clearing the list doesn't delete the entries. INLINE(void Clear()); @@ -173,9 +176,11 @@ typedef List<Handle<Code> > CodeHandleList; // Perform binary search for an element in an already sorted // list. Returns the index of the element of -1 if it was not found. -template <typename T> -int SortedListBSearch( - const List<T>& list, T elem, int (*cmp)(const T* x, const T* y)); +// |cmp| is a predicate that takes a pointer to an element of the List +// and returns +1 if it is greater, -1 if it is less than the element +// being searched. +template <typename T, class P> +int SortedListBSearch(const List<T>& list, P cmp); template <typename T> int SortedListBSearch(const List<T>& list, T elem); diff --git a/deps/v8/src/lithium-allocator.cc b/deps/v8/src/lithium-allocator.cc index 4396c7354c..9534f9e05a 100644 --- a/deps/v8/src/lithium-allocator.cc +++ b/deps/v8/src/lithium-allocator.cc @@ -958,7 +958,7 @@ void LAllocator::ProcessInstructions(HBasicBlock* block, BitVector* live) { } } - if (instr->IsMarkedAsCall() || instr->IsMarkedAsSaveDoubles()) { + if (instr->IsMarkedAsCall()) { for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) { if (output == NULL || !output->IsDoubleRegister() || output->index() != i) { diff --git a/deps/v8/src/lithium.cc b/deps/v8/src/lithium.cc index aefd8b6492..c41cce8d9d 100644 --- a/deps/v8/src/lithium.cc +++ b/deps/v8/src/lithium.cc @@ -95,31 +95,37 @@ void LOperand::PrintTo(StringStream* stream) { } #define DEFINE_OPERAND_CACHE(name, type) \ - name* name::cache = NULL; \ - void name::SetUpCache() { \ + L##name* L##name::cache = NULL; \ + \ + void L##name::SetUpCache() { \ if (cache) return; \ - cache = new name[kNumCachedOperands]; \ + cache = new L##name[kNumCachedOperands]; \ for (int i = 0; i < kNumCachedOperands; i++) { \ cache[i].ConvertTo(type, i); \ } \ } \ + \ + void L##name::TearDownCache() { \ + delete[] cache; \ + } -DEFINE_OPERAND_CACHE(LConstantOperand, CONSTANT_OPERAND) -DEFINE_OPERAND_CACHE(LStackSlot, STACK_SLOT) -DEFINE_OPERAND_CACHE(LDoubleStackSlot, DOUBLE_STACK_SLOT) -DEFINE_OPERAND_CACHE(LRegister, REGISTER) -DEFINE_OPERAND_CACHE(LDoubleRegister, DOUBLE_REGISTER) - +LITHIUM_OPERAND_LIST(DEFINE_OPERAND_CACHE) #undef DEFINE_OPERAND_CACHE void LOperand::SetUpCaches() { - LConstantOperand::SetUpCache(); - LStackSlot::SetUpCache(); - LDoubleStackSlot::SetUpCache(); - LRegister::SetUpCache(); - LDoubleRegister::SetUpCache(); +#define LITHIUM_OPERAND_SETUP(name, type) L##name::SetUpCache(); + LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_SETUP) +#undef LITHIUM_OPERAND_SETUP +} + + +void LOperand::TearDownCaches() { +#define LITHIUM_OPERAND_TEARDOWN(name, type) L##name::TearDownCache(); + LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_TEARDOWN) +#undef LITHIUM_OPERAND_TEARDOWN } + bool LParallelMove::IsRedundant() const { for (int i = 0; i < move_operands_.length(); ++i) { if (!move_operands_[i].IsRedundant()) return false; diff --git a/deps/v8/src/lithium.h b/deps/v8/src/lithium.h index d1e2e3cdef..2ccbf56c50 100644 --- a/deps/v8/src/lithium.h +++ b/deps/v8/src/lithium.h @@ -35,6 +35,14 @@ namespace v8 { namespace internal { +#define LITHIUM_OPERAND_LIST(V) \ + V(ConstantOperand, CONSTANT_OPERAND) \ + V(StackSlot, STACK_SLOT) \ + V(DoubleStackSlot, DOUBLE_STACK_SLOT) \ + V(Register, REGISTER) \ + V(DoubleRegister, DOUBLE_REGISTER) + + class LOperand: public ZoneObject { public: enum Kind { @@ -52,14 +60,13 @@ class LOperand: public ZoneObject { Kind kind() const { return KindField::decode(value_); } int index() const { return static_cast<int>(value_) >> kKindFieldWidth; } - bool IsConstantOperand() const { return kind() == CONSTANT_OPERAND; } - bool IsStackSlot() const { return kind() == STACK_SLOT; } - bool IsDoubleStackSlot() const { return kind() == DOUBLE_STACK_SLOT; } - bool IsRegister() const { return kind() == REGISTER; } - bool IsDoubleRegister() const { return kind() == DOUBLE_REGISTER; } - bool IsArgument() const { return kind() == ARGUMENT; } - bool IsUnallocated() const { return kind() == UNALLOCATED; } - bool IsIgnored() const { return kind() == INVALID; } +#define LITHIUM_OPERAND_PREDICATE(name, type) \ + bool Is##name() const { return kind() == type; } + LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_PREDICATE) + LITHIUM_OPERAND_PREDICATE(Argument, ARGUMENT) + LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED) + LITHIUM_OPERAND_PREDICATE(Ignored, INVALID) +#undef LITHIUM_OPERAND_PREDICATE bool Equals(LOperand* other) const { return value_ == other->value_; } void PrintTo(StringStream* stream); @@ -69,9 +76,9 @@ class LOperand: public ZoneObject { ASSERT(this->index() == index); } - // Calls SetUpCache() for each subclass. Don't forget to update this method - // if you add a new LOperand subclass. + // Calls SetUpCache()/TearDownCache() for each subclass. static void SetUpCaches(); + static void TearDownCaches(); protected: static const int kKindFieldWidth = 3; @@ -265,6 +272,7 @@ class LConstantOperand: public LOperand { } static void SetUpCache(); + static void TearDownCache(); private: static const int kNumCachedOperands = 128; @@ -300,6 +308,7 @@ class LStackSlot: public LOperand { } static void SetUpCache(); + static void TearDownCache(); private: static const int kNumCachedOperands = 128; @@ -324,6 +333,7 @@ class LDoubleStackSlot: public LOperand { } static void SetUpCache(); + static void TearDownCache(); private: static const int kNumCachedOperands = 128; @@ -348,6 +358,7 @@ class LRegister: public LOperand { } static void SetUpCache(); + static void TearDownCache(); private: static const int kNumCachedOperands = 16; @@ -372,6 +383,7 @@ class LDoubleRegister: public LOperand { } static void SetUpCache(); + static void TearDownCache(); private: static const int kNumCachedOperands = 16; diff --git a/deps/v8/src/liveedit-debugger.js b/deps/v8/src/liveedit-debugger.js index abfb0f69c6..4463c93e2a 100644 --- a/deps/v8/src/liveedit-debugger.js +++ b/deps/v8/src/liveedit-debugger.js @@ -159,6 +159,11 @@ Debug.LiveEdit = new function() { preview_description.stack_modified = dropped_functions_number != 0; + // Our current implementation requires client to manually issue "step in" + // command for correct stack state. + preview_description.stack_update_needs_step_in = + preview_description.stack_modified; + // Start with breakpoints. Convert their line/column positions and // temporary remove. var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log); diff --git a/deps/v8/src/liveedit.cc b/deps/v8/src/liveedit.cc index 9c5294a26d..22b82501e9 100644 --- a/deps/v8/src/liveedit.cc +++ b/deps/v8/src/liveedit.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -30,6 +30,7 @@ #include "liveedit.h" +#include "code-stubs.h" #include "compilation-cache.h" #include "compiler.h" #include "debug.h" @@ -1475,26 +1476,36 @@ static const char* DropFrames(Vector<StackFrame*> frames, // Check the nature of the top frame. Isolate* isolate = Isolate::Current(); Code* pre_top_frame_code = pre_top_frame->LookupCode(); + bool frame_has_padding; if (pre_top_frame_code->is_inline_cache_stub() && pre_top_frame_code->ic_state() == DEBUG_BREAK) { // OK, we can drop inline cache calls. *mode = Debug::FRAME_DROPPED_IN_IC_CALL; + frame_has_padding = Debug::FramePaddingLayout::kIsSupported; } else if (pre_top_frame_code == isolate->debug()->debug_break_slot()) { // OK, we can drop debug break slot. *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL; + frame_has_padding = Debug::FramePaddingLayout::kIsSupported; } else if (pre_top_frame_code == isolate->builtins()->builtin( Builtins::kFrameDropper_LiveEdit)) { // OK, we can drop our own code. *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL; + frame_has_padding = false; } else if (pre_top_frame_code == isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) { *mode = Debug::FRAME_DROPPED_IN_RETURN_CALL; + frame_has_padding = Debug::FramePaddingLayout::kIsSupported; } else if (pre_top_frame_code->kind() == Code::STUB && - pre_top_frame_code->major_key()) { - // Entry from our unit tests, it's fine, we support this case. + pre_top_frame_code->major_key() == CodeStub::CEntry) { + // Entry from our unit tests on 'debugger' statement. + // It's fine, we support this case. *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL; + // We don't have a padding from 'debugger' statement call. + // Here the stub is CEntry, it's not debug-only and can't be padded. + // If anyone would complain, a proxy padded stub could be added. + frame_has_padding = false; } else { return "Unknown structure of stack above changing function"; } @@ -1504,8 +1515,49 @@ static const char* DropFrames(Vector<StackFrame*> frames, - Debug::kFrameDropperFrameSize * kPointerSize // Size of the new frame. + kPointerSize; // Bigger address end is exclusive. + Address* top_frame_pc_address = top_frame->pc_address(); + + // top_frame may be damaged below this point. Do not used it. + ASSERT(!(top_frame = NULL)); + if (unused_stack_top > unused_stack_bottom) { - return "Not enough space for frame dropper frame"; + if (frame_has_padding) { + int shortage_bytes = + static_cast<int>(unused_stack_top - unused_stack_bottom); + + Address padding_start = pre_top_frame->fp() - + Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize; + + Address padding_pointer = padding_start; + Smi* padding_object = + Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue); + while (Memory::Object_at(padding_pointer) == padding_object) { + padding_pointer -= kPointerSize; + } + int padding_counter = + Smi::cast(Memory::Object_at(padding_pointer))->value(); + if (padding_counter * kPointerSize < shortage_bytes) { + return "Not enough space for frame dropper frame " + "(even with padding frame)"; + } + Memory::Object_at(padding_pointer) = + Smi::FromInt(padding_counter - shortage_bytes / kPointerSize); + + StackFrame* pre_pre_frame = frames[top_frame_index - 2]; + + memmove(padding_start + kPointerSize - shortage_bytes, + padding_start + kPointerSize, + Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize); + + pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes); + pre_pre_frame->SetCallerFp(pre_top_frame->fp()); + unused_stack_top -= shortage_bytes; + + STATIC_ASSERT(sizeof(Address) == kPointerSize); + top_frame_pc_address -= shortage_bytes / kPointerSize; + } else { + return "Not enough space for frame dropper frame"; + } } // Committing now. After this point we should return only NULL value. @@ -1515,7 +1567,7 @@ static const char* DropFrames(Vector<StackFrame*> frames, ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame)); Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit(); - top_frame->set_pc(code->entry()); + *top_frame_pc_address = code->entry(); pre_top_frame->SetCallerFp(bottom_js_frame->fp()); *restarter_frame_function_pointer = diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc index 21d64df21c..d93a9d82b1 100644 --- a/deps/v8/src/log.cc +++ b/deps/v8/src/log.cc @@ -1730,13 +1730,20 @@ void Logger::EnableSlidingStateWindow() { } // Protects the state below. -static LazyMutex active_samplers_mutex = LAZY_MUTEX_INITIALIZER; +static Mutex* active_samplers_mutex = NULL; List<Sampler*>* SamplerRegistry::active_samplers_ = NULL; +void SamplerRegistry::SetUp() { + if (!active_samplers_mutex) { + active_samplers_mutex = OS::CreateMutex(); + } +} + + bool SamplerRegistry::IterateActiveSamplers(VisitSampler func, void* param) { - ScopedLock lock(active_samplers_mutex.Pointer()); + ScopedLock lock(active_samplers_mutex); for (int i = 0; ActiveSamplersExist() && i < active_samplers_->length(); ++i) { @@ -1763,7 +1770,7 @@ SamplerRegistry::State SamplerRegistry::GetState() { void SamplerRegistry::AddActiveSampler(Sampler* sampler) { ASSERT(sampler->IsActive()); - ScopedLock lock(active_samplers_mutex.Pointer()); + ScopedLock lock(active_samplers_mutex); if (active_samplers_ == NULL) { active_samplers_ = new List<Sampler*>; } else { @@ -1775,7 +1782,7 @@ void SamplerRegistry::AddActiveSampler(Sampler* sampler) { void SamplerRegistry::RemoveActiveSampler(Sampler* sampler) { ASSERT(sampler->IsActive()); - ScopedLock lock(active_samplers_mutex.Pointer()); + ScopedLock lock(active_samplers_mutex); ASSERT(active_samplers_ != NULL); bool removed = active_samplers_->RemoveElement(sampler); ASSERT(removed); diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h index 129738757e..03c7b3b670 100644 --- a/deps/v8/src/log.h +++ b/deps/v8/src/log.h @@ -437,6 +437,8 @@ class SamplerRegistry : public AllStatic { HAS_CPU_PROFILING_SAMPLERS }; + static void SetUp(); + typedef void (*VisitSampler)(Sampler*, void*); static State GetState(); diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py index 93287ae3d4..08fa82e686 100644 --- a/deps/v8/src/macros.py +++ b/deps/v8/src/macros.py @@ -196,6 +196,7 @@ macro SET_UTC_DATE_VALUE(arg, value) = (%DateSetValue(arg, value, 1)); macro SET_LOCAL_DATE_VALUE(arg, value) = (%DateSetValue(arg, value, 0)); # Last input and last subject of regexp matches. +const LAST_SUBJECT_INDEX = 1; macro LAST_SUBJECT(array) = ((array)[1]); macro LAST_INPUT(array) = ((array)[2]); @@ -204,6 +205,15 @@ macro CAPTURE(index) = (3 + (index)); const CAPTURE0 = 3; const CAPTURE1 = 4; +# For the regexp capture override array. This has the same +# format as the arguments to a function called from +# String.prototype.replace. +macro OVERRIDE_MATCH(override) = ((override)[0]); +macro OVERRIDE_POS(override) = ((override)[(override).length - 2]); +macro OVERRIDE_SUBJECT(override) = ((override)[(override).length - 1]); +# 1-based so index of 1 returns the first capture +macro OVERRIDE_CAPTURE(override, index) = ((override)[(index)]); + # PropertyDescriptor return value indices - must match # PropertyDescriptorIndices in runtime.cc. const IS_ACCESSOR_INDEX = 0; diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc index dde172d2f0..0aa119219a 100644 --- a/deps/v8/src/mark-compact.cc +++ b/deps/v8/src/mark-compact.cc @@ -296,8 +296,6 @@ void MarkCompactCollector::CollectGarbage() { if (!collect_maps_) ReattachInitialMaps(); - heap_->isolate()->inner_pointer_to_code_cache()->Flush(); - Finish(); tracer_ = NULL; @@ -337,6 +335,7 @@ void MarkCompactCollector::VerifyMarkbitsAreClean() { for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { MarkBit mark_bit = Marking::MarkBitFrom(obj); ASSERT(Marking::IsWhite(mark_bit)); + ASSERT_EQ(0, Page::FromAddress(obj->address())->LiveBytes()); } } #endif @@ -373,6 +372,7 @@ void MarkCompactCollector::ClearMarkbits() { MarkBit mark_bit = Marking::MarkBitFrom(obj); mark_bit.Clear(); mark_bit.Next().Clear(); + Page::FromAddress(obj->address())->ResetLiveBytes(); } } @@ -680,7 +680,6 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) { ASSERT(!FLAG_never_compact || !FLAG_always_compact); - if (collect_maps_) CreateBackPointers(); #ifdef ENABLE_GDB_JIT_INTERFACE if (FLAG_gdbjit) { // If GDBJIT interface is active disable compaction. @@ -1150,9 +1149,10 @@ class StaticMarkingVisitor : public StaticVisitorBase { JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(object); // Enqueue weak map in linked list of encountered weak maps. - ASSERT(weak_map->next() == Smi::FromInt(0)); - weak_map->set_next(collector->encountered_weak_maps()); - collector->set_encountered_weak_maps(weak_map); + if (weak_map->next() == Smi::FromInt(0)) { + weak_map->set_next(collector->encountered_weak_maps()); + collector->set_encountered_weak_maps(weak_map); + } // Skip visiting the backing hash table containing the mappings. int object_size = JSWeakMap::BodyDescriptor::SizeOf(map, object); @@ -1168,9 +1168,15 @@ class StaticMarkingVisitor : public StaticVisitorBase { object_size); // Mark the backing hash table without pushing it on the marking stack. - ObjectHashTable* table = ObjectHashTable::cast(weak_map->table()); - ASSERT(!MarkCompactCollector::IsMarked(table)); - collector->SetMark(table, Marking::MarkBitFrom(table)); + Object* table_object = weak_map->table(); + if (!table_object->IsHashTable()) return; + ObjectHashTable* table = ObjectHashTable::cast(table_object); + Object** table_slot = + HeapObject::RawField(weak_map, JSWeakMap::kTableOffset); + MarkBit table_mark = Marking::MarkBitFrom(table); + collector->RecordSlot(table_slot, table_slot, table); + if (!table_mark.Get()) collector->SetMark(table, table_mark); + // Recording the map slot can be skipped, because maps are not compacted. collector->MarkObject(table->map(), Marking::MarkBitFrom(table->map())); ASSERT(MarkCompactCollector::IsMarked(table->map())); } @@ -1179,16 +1185,7 @@ class StaticMarkingVisitor : public StaticVisitorBase { Heap* heap = map->GetHeap(); Code* code = reinterpret_cast<Code*>(object); if (FLAG_cleanup_code_caches_at_gc) { - Object* raw_info = code->type_feedback_info(); - if (raw_info->IsTypeFeedbackInfo()) { - TypeFeedbackCells* type_feedback_cells = - TypeFeedbackInfo::cast(raw_info)->type_feedback_cells(); - for (int i = 0; i < type_feedback_cells->CellCount(); i++) { - ASSERT(type_feedback_cells->AstId(i)->IsSmi()); - JSGlobalPropertyCell* cell = type_feedback_cells->Cell(i); - cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap)); - } - } + code->ClearTypeFeedbackCells(heap); } code->CodeIterateBody<StaticMarkingVisitor>(heap); } @@ -1390,6 +1387,12 @@ class StaticMarkingVisitor : public StaticVisitorBase { static void VisitSharedFunctionInfoAndFlushCode(Map* map, HeapObject* object) { + Heap* heap = map->GetHeap(); + SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); + if (shared->ic_age() != heap->global_ic_age()) { + shared->ResetForNewContext(heap->global_ic_age()); + } + MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector(); if (!collector->is_code_flushing_enabled()) { VisitSharedFunctionInfoGeneric(map, object); @@ -1519,12 +1522,6 @@ class StaticMarkingVisitor : public StaticVisitorBase { JSFunction::kCodeEntryOffset + kPointerSize), HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset)); - - // Don't visit the next function list field as it is a weak reference. - Object** next_function = - HeapObject::RawField(object, JSFunction::kNextFunctionLinkOffset); - heap->mark_compact_collector()->RecordSlot( - next_function, next_function, *next_function); } static inline void VisitJSRegExpFields(Map* map, @@ -1818,13 +1815,19 @@ void MarkCompactCollector::ProcessNewlyMarkedObject(HeapObject* object) { void MarkCompactCollector::MarkMapContents(Map* map) { // Mark prototype transitions array but don't push it into marking stack. // This will make references from it weak. We will clean dead prototype - // transitions in ClearNonLiveTransitions. - FixedArray* prototype_transitions = map->prototype_transitions(); - MarkBit mark = Marking::MarkBitFrom(prototype_transitions); - if (!mark.Get()) { - mark.Set(); - MemoryChunk::IncrementLiveBytesFromGC(prototype_transitions->address(), - prototype_transitions->Size()); + // transitions in ClearNonLiveTransitions. But make sure that back pointers + // stored inside prototype transitions arrays are marked. + Object* raw_proto_transitions = map->unchecked_prototype_transitions(); + if (raw_proto_transitions->IsFixedArray()) { + FixedArray* prototype_transitions = FixedArray::cast(raw_proto_transitions); + MarkBit mark = Marking::MarkBitFrom(prototype_transitions); + if (!mark.Get()) { + mark.Set(); + MemoryChunk::IncrementLiveBytesFromGC(prototype_transitions->address(), + prototype_transitions->Size()); + MarkObjectAndPush(HeapObject::cast( + prototype_transitions->get(Map::kProtoTransitionBackPointerOffset))); + } } Object** raw_descriptor_array_slot = @@ -1923,23 +1926,6 @@ void MarkCompactCollector::MarkDescriptorArray( } -void MarkCompactCollector::CreateBackPointers() { - HeapObjectIterator iterator(heap()->map_space()); - for (HeapObject* next_object = iterator.Next(); - next_object != NULL; next_object = iterator.Next()) { - if (next_object->IsMap()) { // Could also be FreeSpace object on free list. - Map* map = Map::cast(next_object); - STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); - if (map->instance_type() >= FIRST_JS_RECEIVER_TYPE) { - map->CreateBackPointers(); - } else { - ASSERT(map->instance_descriptors() == heap()->empty_descriptor_array()); - } - } - } -} - - // Fill the marking stack with overflowed objects returned by the given // iterator. Stop when the marking stack is filled or the end of the space // is reached, whichever comes first. @@ -1970,6 +1956,7 @@ static inline int MarkWordToObjectStarts(uint32_t mark_bits, int* starts); static void DiscoverGreyObjectsOnPage(MarkingDeque* marking_deque, Page* p) { + ASSERT(!marking_deque->IsFull()); ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0); ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0); @@ -2462,15 +2449,8 @@ void MarkCompactCollector::ReattachInitialMaps() { void MarkCompactCollector::ClearNonLiveTransitions() { HeapObjectIterator map_iterator(heap()->map_space()); // Iterate over the map space, setting map transitions that go from - // a marked map to an unmarked map to null transitions. At the same time, - // set all the prototype fields of maps back to their original value, - // dropping the back pointers temporarily stored in the prototype field. - // Setting the prototype field requires following the linked list of - // back pointers, reversing them all at once. This allows us to find - // those maps with map transitions that need to be nulled, and only - // scan the descriptor arrays of those maps, not all maps. - // All of these actions are carried out only on maps of JSObjects - // and related subtypes. + // a marked map to an unmarked map to null transitions. This action + // is carried out only on maps of JSObjects and related subtypes. for (HeapObject* obj = map_iterator.Next(); obj != NULL; obj = map_iterator.Next()) { Map* map = reinterpret_cast<Map*>(obj); @@ -2546,36 +2526,16 @@ void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map, MarkBit map_mark) { - // Follow the chain of back pointers to find the prototype. - Object* real_prototype = map; - while (real_prototype->IsMap()) { - real_prototype = Map::cast(real_prototype)->prototype(); - ASSERT(real_prototype->IsHeapObject()); - } + Object* potential_parent = map->GetBackPointer(); + if (!potential_parent->IsMap()) return; + Map* parent = Map::cast(potential_parent); - // Follow back pointers, setting them to prototype, clearing map transitions - // when necessary. - Map* current = map; + // Follow back pointer, check whether we are dealing with a map transition + // from a live map to a dead path and in case clear transitions of parent. bool current_is_alive = map_mark.Get(); - bool on_dead_path = !current_is_alive; - while (current->IsMap()) { - Object* next = current->prototype(); - // There should never be a dead map above a live map. - ASSERT(on_dead_path || current_is_alive); - - // A live map above a dead map indicates a dead transition. This test will - // always be false on the first iteration. - if (on_dead_path && current_is_alive) { - on_dead_path = false; - current->ClearNonLiveTransitions(heap(), real_prototype); - } - - Object** slot = HeapObject::RawField(current, Map::kPrototypeOffset); - *slot = real_prototype; - if (current_is_alive) RecordSlot(slot, slot, real_prototype); - - current = reinterpret_cast<Map*>(next); - current_is_alive = Marking::MarkBitFrom(current).Get(); + bool parent_is_alive = Marking::MarkBitFrom(parent).Get(); + if (!current_is_alive && parent_is_alive) { + parent->ClearNonLiveTransitions(heap()); } } @@ -2586,14 +2546,17 @@ void MarkCompactCollector::ProcessWeakMaps() { ASSERT(MarkCompactCollector::IsMarked(HeapObject::cast(weak_map_obj))); JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(weak_map_obj); ObjectHashTable* table = ObjectHashTable::cast(weak_map->table()); + Object** anchor = reinterpret_cast<Object**>(table->address()); for (int i = 0; i < table->Capacity(); i++) { if (MarkCompactCollector::IsMarked(HeapObject::cast(table->KeyAt(i)))) { - Object* value = table->get(table->EntryToValueIndex(i)); - StaticMarkingVisitor::VisitPointer(heap(), &value); - table->set_unchecked(heap(), - table->EntryToValueIndex(i), - value, - UPDATE_WRITE_BARRIER); + Object** key_slot = + HeapObject::RawField(table, FixedArray::OffsetOfElementAt( + ObjectHashTable::EntryToIndex(i))); + RecordSlot(anchor, key_slot, *key_slot); + Object** value_slot = + HeapObject::RawField(table, FixedArray::OffsetOfElementAt( + ObjectHashTable::EntryToValueIndex(i))); + StaticMarkingVisitor::MarkObjectByPointer(this, anchor, value_slot); } } weak_map_obj = weak_map->next(); @@ -3413,6 +3376,8 @@ void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { // under it. ProcessInvalidatedCode(&updating_visitor); + heap_->isolate()->inner_pointer_to_code_cache()->Flush(); + #ifdef DEBUG if (FLAG_verify_heap) { VerifyEvacuation(heap_); @@ -3825,7 +3790,7 @@ void MarkCompactCollector::SweepSpace(PagedSpace* space, SweeperType sweeper) { bool lazy_sweeping_active = false; bool unused_page_present = false; - intptr_t old_space_size = heap()->PromotedSpaceSize(); + intptr_t old_space_size = heap()->PromotedSpaceSizeOfObjects(); intptr_t space_left = Min(heap()->OldGenPromotionLimit(old_space_size), heap()->OldGenAllocationLimit(old_space_size)) - old_space_size; diff --git a/deps/v8/src/mark-compact.h b/deps/v8/src/mark-compact.h index 66ffd19535..6420a21fe3 100644 --- a/deps/v8/src/mark-compact.h +++ b/deps/v8/src/mark-compact.h @@ -544,6 +544,8 @@ class MarkCompactCollector { void ClearMarkbits(); + bool is_compacting() const { return compacting_; } + private: MarkCompactCollector(); ~MarkCompactCollector(); @@ -640,13 +642,6 @@ class MarkCompactCollector { void ProcessNewlyMarkedObject(HeapObject* obj); - // Creates back pointers for all map transitions, stores them in - // the prototype field. The original prototype pointers are restored - // in ClearNonLiveTransitions(). All JSObject maps - // connected by map transitions have the same prototype object, which - // is why we can use this field temporarily for back pointers. - void CreateBackPointers(); - // Mark a Map and its DescriptorArray together, skipping transitions. void MarkMapContents(Map* map); void MarkAccessorPairSlot(HeapObject* accessors, int offset); diff --git a/deps/v8/src/math.js b/deps/v8/src/math.js index 8e735c4a68..aee56af4f9 100644 --- a/deps/v8/src/math.js +++ b/deps/v8/src/math.js @@ -30,7 +30,6 @@ // has the added benefit that the code in this file is isolated from // changes to these properties. var $floor = MathFloor; -var $random = MathRandom; var $abs = MathAbs; // Instance class name can only be set on functions. That is the only diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index a3adcf8634..f8b57666de 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -1125,13 +1125,7 @@ function SetUpError() { } %FunctionSetInstanceClassName(f, 'Error'); %SetProperty(f.prototype, 'constructor', f, DONT_ENUM); - // The name property on the prototype of error objects is not - // specified as being read-one and dont-delete. However, allowing - // overwriting allows leaks of error objects between script blocks - // in the same context in a browser setting. Therefore we fix the - // name. - %SetProperty(f.prototype, "name", name, - DONT_ENUM | DONT_DELETE | READ_ONLY) ; + %SetProperty(f.prototype, "name", name, DONT_ENUM); %SetCode(f, function(m) { if (%_IsConstructCall()) { // Define all the expected properties directly on the error @@ -1147,10 +1141,8 @@ function SetUpError() { return FormatMessage(%NewMessageObject(obj.type, obj.arguments)); }); } else if (!IS_UNDEFINED(m)) { - %IgnoreAttributesAndSetProperty(this, - 'message', - ToString(m), - DONT_ENUM); + %IgnoreAttributesAndSetProperty( + this, 'message', ToString(m), DONT_ENUM); } captureStackTrace(this, f); } else { @@ -1180,16 +1172,41 @@ $Error.captureStackTrace = captureStackTrace; var visited_errors = new InternalArray(); var cyclic_error_marker = new $Object(); +function GetPropertyWithoutInvokingMonkeyGetters(error, name) { + // Climb the prototype chain until we find the holder. + while (error && !%HasLocalProperty(error, name)) { + error = error.__proto__; + } + if (error === null) return void 0; + if (!IS_OBJECT(error)) return error[name]; + // If the property is an accessor on one of the predefined errors that can be + // generated statically by the compiler, don't touch it. This is to address + // http://code.google.com/p/chromium/issues/detail?id=69187 + var desc = %GetOwnProperty(error, name); + if (desc && desc[IS_ACCESSOR_INDEX]) { + var isName = name === "name"; + if (error === $ReferenceError.prototype) + return isName ? "ReferenceError" : void 0; + if (error === $SyntaxError.prototype) + return isName ? "SyntaxError" : void 0; + if (error === $TypeError.prototype) + return isName ? "TypeError" : void 0; + } + // Otherwise, read normally. + return error[name]; +} + function ErrorToStringDetectCycle(error) { if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker; try { - var type = error.type; - var name = error.name; + var type = GetPropertyWithoutInvokingMonkeyGetters(error, "type"); + var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name"); name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name); - var message = error.message; + var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message"); var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty); if (type && !hasMessage) { - message = FormatMessage(%NewMessageObject(type, error.arguments)); + var args = GetPropertyWithoutInvokingMonkeyGetters(error, "arguments"); + message = FormatMessage(%NewMessageObject(type, args)); } message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message); if (name === "") return message; diff --git a/deps/v8/src/mips/assembler-mips.cc b/deps/v8/src/mips/assembler-mips.cc index 0d7f9218b4..f347fdc576 100644 --- a/deps/v8/src/mips/assembler-mips.cc +++ b/deps/v8/src/mips/assembler-mips.cc @@ -143,7 +143,7 @@ int ToNumber(Register reg) { 27, // k1 28, // gp 29, // sp - 30, // s8_fp + 30, // fp 31, // ra }; return kNumbers[reg.code()]; @@ -163,7 +163,7 @@ Register ToRegister(int num) { k0, k1, gp, sp, - s8_fp, + fp, ra }; return kRegisters[num]; @@ -237,28 +237,28 @@ MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) { static const int kNegOffset = 0x00008000; // addiu(sp, sp, 4) aka Pop() operation or part of Pop(r) // operations as post-increment of sp. -const Instr kPopInstruction = ADDIU | (sp.code() << kRsShift) - | (sp.code() << kRtShift) | (kPointerSize & kImm16Mask); +const Instr kPopInstruction = ADDIU | (kRegister_sp_Code << kRsShift) + | (kRegister_sp_Code << kRtShift) | (kPointerSize & kImm16Mask); // addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp. -const Instr kPushInstruction = ADDIU | (sp.code() << kRsShift) - | (sp.code() << kRtShift) | (-kPointerSize & kImm16Mask); +const Instr kPushInstruction = ADDIU | (kRegister_sp_Code << kRsShift) + | (kRegister_sp_Code << kRtShift) | (-kPointerSize & kImm16Mask); // sw(r, MemOperand(sp, 0)) -const Instr kPushRegPattern = SW | (sp.code() << kRsShift) +const Instr kPushRegPattern = SW | (kRegister_sp_Code << kRsShift) | (0 & kImm16Mask); // lw(r, MemOperand(sp, 0)) -const Instr kPopRegPattern = LW | (sp.code() << kRsShift) +const Instr kPopRegPattern = LW | (kRegister_sp_Code << kRsShift) | (0 & kImm16Mask); -const Instr kLwRegFpOffsetPattern = LW | (s8_fp.code() << kRsShift) +const Instr kLwRegFpOffsetPattern = LW | (kRegister_fp_Code << kRsShift) | (0 & kImm16Mask); -const Instr kSwRegFpOffsetPattern = SW | (s8_fp.code() << kRsShift) +const Instr kSwRegFpOffsetPattern = SW | (kRegister_fp_Code << kRsShift) | (0 & kImm16Mask); -const Instr kLwRegFpNegOffsetPattern = LW | (s8_fp.code() << kRsShift) +const Instr kLwRegFpNegOffsetPattern = LW | (kRegister_fp_Code << kRsShift) | (kNegOffset & kImm16Mask); -const Instr kSwRegFpNegOffsetPattern = SW | (s8_fp.code() << kRsShift) +const Instr kSwRegFpNegOffsetPattern = SW | (kRegister_fp_Code << kRsShift) | (kNegOffset & kImm16Mask); // A mask for the Rt register for push, pop, lw, sw instructions. const Instr kRtMask = kRtFieldMask; @@ -2137,6 +2137,15 @@ Address Assembler::target_address_at(Address pc) { } +// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32 +// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap +// snapshot generated on ia32, the resulting MIPS sNaN must be quieted. +// OS::nan_value() returns a qNaN. +void Assembler::QuietNaN(HeapObject* object) { + HeapNumber::cast(object)->set_value(OS::nan_value()); +} + + // On Mips, a target address is stored in a lui/ori instruction pair, each // of which load 16 bits of the 32-bit address to a register. // Patching the address must replace both instr, and flush the i-cache. diff --git a/deps/v8/src/mips/assembler-mips.h b/deps/v8/src/mips/assembler-mips.h index 8b877f653b..84714e507e 100644 --- a/deps/v8/src/mips/assembler-mips.h +++ b/deps/v8/src/mips/assembler-mips.h @@ -125,40 +125,59 @@ struct Register { int code_; }; -const Register no_reg = { -1 }; - -const Register zero_reg = { 0 }; // Always zero. -const Register at = { 1 }; // at: Reserved for synthetic instructions. -const Register v0 = { 2 }; // v0, v1: Used when returning multiple values -const Register v1 = { 3 }; // from subroutines. -const Register a0 = { 4 }; // a0 - a4: Used to pass non-FP parameters. -const Register a1 = { 5 }; -const Register a2 = { 6 }; -const Register a3 = { 7 }; -const Register t0 = { 8 }; // t0 - t9: Can be used without reservation, act -const Register t1 = { 9 }; // as temporary registers and are allowed to -const Register t2 = { 10 }; // be destroyed by subroutines. -const Register t3 = { 11 }; -const Register t4 = { 12 }; -const Register t5 = { 13 }; -const Register t6 = { 14 }; -const Register t7 = { 15 }; -const Register s0 = { 16 }; // s0 - s7: Subroutine register variables. -const Register s1 = { 17 }; // Subroutines that write to these registers -const Register s2 = { 18 }; // must restore their values before exiting so -const Register s3 = { 19 }; // that the caller can expect the values to be -const Register s4 = { 20 }; // preserved. -const Register s5 = { 21 }; -const Register s6 = { 22 }; -const Register s7 = { 23 }; -const Register t8 = { 24 }; -const Register t9 = { 25 }; -const Register k0 = { 26 }; // k0, k1: Reserved for system calls and -const Register k1 = { 27 }; // interrupt handlers. -const Register gp = { 28 }; // gp: Reserved. -const Register sp = { 29 }; // sp: Stack pointer. -const Register s8_fp = { 30 }; // fp: Frame pointer. -const Register ra = { 31 }; // ra: Return address pointer. +#define REGISTER(N, C) \ + const int kRegister_ ## N ## _Code = C; \ + const Register N = { C } + +REGISTER(no_reg, -1); +// Always zero. +REGISTER(zero_reg, 0); +// at: Reserved for synthetic instructions. +REGISTER(at, 1); +// v0, v1: Used when returning multiple values from subroutines. +REGISTER(v0, 2); +REGISTER(v1, 3); +// a0 - a4: Used to pass non-FP parameters. +REGISTER(a0, 4); +REGISTER(a1, 5); +REGISTER(a2, 6); +REGISTER(a3, 7); +// t0 - t9: Can be used without reservation, act as temporary registers and are +// allowed to be destroyed by subroutines. +REGISTER(t0, 8); +REGISTER(t1, 9); +REGISTER(t2, 10); +REGISTER(t3, 11); +REGISTER(t4, 12); +REGISTER(t5, 13); +REGISTER(t6, 14); +REGISTER(t7, 15); +// s0 - s7: Subroutine register variables. Subroutines that write to these +// registers must restore their values before exiting so that the caller can +// expect the values to be preserved. +REGISTER(s0, 16); +REGISTER(s1, 17); +REGISTER(s2, 18); +REGISTER(s3, 19); +REGISTER(s4, 20); +REGISTER(s5, 21); +REGISTER(s6, 22); +REGISTER(s7, 23); +REGISTER(t8, 24); +REGISTER(t9, 25); +// k0, k1: Reserved for system calls and interrupt handlers. +REGISTER(k0, 26); +REGISTER(k1, 27); +// gp: Reserved. +REGISTER(gp, 28); +// sp: Stack pointer. +REGISTER(sp, 29); +// fp: Frame pointer. +REGISTER(fp, 30); +// ra: Return address pointer. +REGISTER(ra, 31); + +#undef REGISTER int ToNumber(Register reg); @@ -303,7 +322,6 @@ static const Register& kLithiumScratchReg = s3; // Scratch register. static const Register& kLithiumScratchReg2 = s4; // Scratch register. static const Register& kRootRegister = s6; // Roots array pointer. static const Register& cp = s7; // JavaScript context pointer. -static const Register& fp = s8_fp; // Alias for fp. static const DoubleRegister& kLithiumScratchDouble = f30; static const FPURegister& kDoubleRegZero = f28; @@ -552,6 +570,8 @@ class Assembler : public AssemblerBase { static void JumpLabelToJumpRegister(Address pc); + static void QuietNaN(HeapObject* nan); + // This sets the branch destination (which gets loaded at the call address). // This is for calls and branches within generated code. The serializer // has already deserialized the lui/ori instructions etc. diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc index 1b3242cf09..f3dd95b851 100644 --- a/deps/v8/src/mips/code-stubs-mips.cc +++ b/deps/v8/src/mips/code-stubs-mips.cc @@ -481,7 +481,7 @@ void ConvertToDoubleStub::Generate(MacroAssembler* masm) { __ Branch(¬_special, gt, source_, Operand(1)); // For 1 or -1 we need to or in the 0 exponent (biased to 1023). - static const uint32_t exponent_word_for_1 = + const uint32_t exponent_word_for_1 = HeapNumber::kExponentBias << HeapNumber::kExponentShift; // Safe to use 'at' as dest reg here. __ Or(at, exponent, Operand(exponent_word_for_1)); @@ -2754,7 +2754,6 @@ void BinaryOpStub::GenerateSmiCode( Register left = a1; Register right = a0; Register scratch1 = t3; - Register scratch2 = t5; // Perform combined smi check on both operands. __ Or(scratch1, left, Operand(right)); @@ -3459,7 +3458,6 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { Label no_update; Label skip_cache; - const Register heap_number_map = t2; // Call C function to calculate the result and update the cache. // Register a0 holds precalculated cache entry address; preserve @@ -4421,7 +4419,7 @@ Register InstanceofStub::right() { return a1; } void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { // The displacement is the offset of the last parameter (if any) // relative to the frame pointer. - static const int kDisplacement = + const int kDisplacement = StandardFrameConstants::kCallerSPOffset - kPointerSize; // Check that the key is a smiGenerateReadElement. @@ -4833,10 +4831,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // sp[8]: subject string // sp[12]: JSRegExp object - static const int kLastMatchInfoOffset = 0 * kPointerSize; - static const int kPreviousIndexOffset = 1 * kPointerSize; - static const int kSubjectOffset = 2 * kPointerSize; - static const int kJSRegExpOffset = 3 * kPointerSize; + const int kLastMatchInfoOffset = 0 * kPointerSize; + const int kPreviousIndexOffset = 1 * kPointerSize; + const int kSubjectOffset = 2 * kPointerSize; + const int kJSRegExpOffset = 3 * kPointerSize; Isolate* isolate = masm->isolate(); @@ -5045,8 +5043,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { 1, a0, a2); // Isolates: note we add an additional parameter here (isolate pointer). - static const int kRegExpExecuteArguments = 8; - static const int kParameterRegisters = 4; + const int kRegExpExecuteArguments = 8; + const int kParameterRegisters = 4; __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); // Stack pointer now points to cell where return address is to be written. @@ -5402,9 +5400,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ LoadRoot(at, Heap::kTheHoleValueRootIndex); __ Branch(&call, ne, t0, Operand(at)); // Patch the receiver on the stack with the global receiver object. - __ lw(a2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); - __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset)); - __ sw(a2, MemOperand(sp, argc_ * kPointerSize)); + __ lw(a3, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ lw(a3, FieldMemOperand(a3, GlobalObject::kGlobalReceiverOffset)); + __ sw(a3, MemOperand(sp, argc_ * kPointerSize)); __ bind(&call); } @@ -5412,8 +5410,12 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { // a1: pushed function (to be verified) __ JumpIfSmi(a1, &non_function); // Get the map of the function object. - __ GetObjectType(a1, a2, a2); - __ Branch(&slow, ne, a2, Operand(JS_FUNCTION_TYPE)); + __ GetObjectType(a1, a3, a3); + __ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE)); + + if (RecordCallTarget()) { + GenerateRecordCallTarget(masm); + } // Fast-case: Invoke the function now. // a1: pushed function @@ -5438,8 +5440,17 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { // Slow-case: Non-function called. __ bind(&slow); + if (RecordCallTarget()) { + // If there is a call target cache, mark it megamorphic in the + // non-function case. MegamorphicSentinel is an immortal immovable + // object (undefined) so no write barrier is needed. + ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), + masm->isolate()->heap()->undefined_value()); + __ LoadRoot(at, Heap::kUndefinedValueRootIndex); + __ sw(at, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset)); + } // Check for function proxy. - __ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE)); + __ Branch(&non_function, ne, a3, Operand(JS_FUNCTION_PROXY_TYPE)); __ push(a1); // Put proxy as additional argument. __ li(a0, Operand(argc_ + 1, RelocInfo::NONE)); __ li(a2, Operand(0, RelocInfo::NONE)); @@ -5931,7 +5942,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, // scratch: - // Perform a number of probes in the symbol table. - static const int kProbes = 4; + const int kProbes = 4; Label found_in_symbol_table; Label next_probe[kProbes]; Register candidate = scratch5; // Scratch register contains candidate. @@ -6059,9 +6070,9 @@ void SubStringStub::Generate(MacroAssembler* masm) { // 0 <= from <= to <= string.length. // If any of these assumptions fail, we call the runtime system. - static const int kToOffset = 0 * kPointerSize; - static const int kFromOffset = 1 * kPointerSize; - static const int kStringOffset = 2 * kPointerSize; + const int kToOffset = 0 * kPointerSize; + const int kFromOffset = 1 * kPointerSize; + const int kStringOffset = 2 * kPointerSize; __ lw(a2, MemOperand(sp, kToOffset)); __ lw(a3, MemOperand(sp, kFromOffset)); @@ -6095,37 +6106,11 @@ void SubStringStub::Generate(MacroAssembler* masm) { // a2: result string length __ lw(t0, FieldMemOperand(v0, String::kLengthOffset)); __ sra(t0, t0, 1); + // Return original string. __ Branch(&return_v0, eq, a2, Operand(t0)); - - - Label result_longer_than_two; - // Check for special case of two character ASCII string, in which case - // we do a lookup in the symbol table first. - __ li(t0, 2); - __ Branch(&result_longer_than_two, gt, a2, Operand(t0)); - __ Branch(&runtime, lt, a2, Operand(t0)); - - __ JumpIfInstanceTypeIsNotSequentialAscii(a1, a1, &runtime); - - // Get the two characters forming the sub string. - __ Addu(v0, v0, Operand(a3)); - __ lbu(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); - __ lbu(t0, FieldMemOperand(v0, SeqAsciiString::kHeaderSize + 1)); - - // Try to lookup two character string in symbol table. - Label make_two_character_string; - StringHelper::GenerateTwoCharacterSymbolTableProbe( - masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string); - __ jmp(&return_v0); - - // a2: result string length. - // a3: two characters combined into halfword in little endian byte order. - __ bind(&make_two_character_string); - __ AllocateAsciiString(v0, a2, t0, t1, t4, &runtime); - __ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); - __ jmp(&return_v0); - - __ bind(&result_longer_than_two); + // Longer than original string's length or negative: unsafe arguments. + __ Branch(&runtime, hi, a2, Operand(t0)); + // Shorter than original string's length: an actual substring. // Deal with different string types: update the index if necessary // and put the underlying string into t1. @@ -7356,43 +7341,46 @@ struct AheadOfTimeWriteBarrierStubList { RememberedSetAction action; }; +#define REG(Name) { kRegister_ ## Name ## _Code } -struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { +static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { // Used in RegExpExecStub. - { s2, s0, t3, EMIT_REMEMBERED_SET }, - { s2, a2, t3, EMIT_REMEMBERED_SET }, + { REG(s2), REG(s0), REG(t3), EMIT_REMEMBERED_SET }, + { REG(s2), REG(a2), REG(t3), EMIT_REMEMBERED_SET }, // Used in CompileArrayPushCall. // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore. // Also used in KeyedStoreIC::GenerateGeneric. - { a3, t0, t1, EMIT_REMEMBERED_SET }, + { REG(a3), REG(t0), REG(t1), EMIT_REMEMBERED_SET }, // Used in CompileStoreGlobal. - { t0, a1, a2, OMIT_REMEMBERED_SET }, + { REG(t0), REG(a1), REG(a2), OMIT_REMEMBERED_SET }, // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField. - { a1, a2, a3, EMIT_REMEMBERED_SET }, - { a3, a2, a1, EMIT_REMEMBERED_SET }, + { REG(a1), REG(a2), REG(a3), EMIT_REMEMBERED_SET }, + { REG(a3), REG(a2), REG(a1), EMIT_REMEMBERED_SET }, // Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. - { a2, a1, a3, EMIT_REMEMBERED_SET }, - { a3, a1, a2, EMIT_REMEMBERED_SET }, + { REG(a2), REG(a1), REG(a3), EMIT_REMEMBERED_SET }, + { REG(a3), REG(a1), REG(a2), EMIT_REMEMBERED_SET }, // KeyedStoreStubCompiler::GenerateStoreFastElement. - { a3, a2, t0, EMIT_REMEMBERED_SET }, - { a2, a3, t0, EMIT_REMEMBERED_SET }, + { REG(a3), REG(a2), REG(t0), EMIT_REMEMBERED_SET }, + { REG(a2), REG(a3), REG(t0), EMIT_REMEMBERED_SET }, // ElementsTransitionGenerator::GenerateSmiOnlyToObject // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble // and ElementsTransitionGenerator::GenerateDoubleToObject - { a2, a3, t5, EMIT_REMEMBERED_SET }, - { a2, a3, t5, OMIT_REMEMBERED_SET }, + { REG(a2), REG(a3), REG(t5), EMIT_REMEMBERED_SET }, + { REG(a2), REG(a3), REG(t5), OMIT_REMEMBERED_SET }, // ElementsTransitionGenerator::GenerateDoubleToObject - { t2, a2, a0, EMIT_REMEMBERED_SET }, - { a2, t2, t5, EMIT_REMEMBERED_SET }, + { REG(t2), REG(a2), REG(a0), EMIT_REMEMBERED_SET }, + { REG(a2), REG(t2), REG(t5), EMIT_REMEMBERED_SET }, // StoreArrayLiteralElementStub::Generate - { t1, a0, t2, EMIT_REMEMBERED_SET }, + { REG(t1), REG(a0), REG(t2), EMIT_REMEMBERED_SET }, // Null termination. - { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET} + { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET} }; +#undef REG + bool RecordWriteStub::IsPregenerated() { - for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; + for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; !entry->object.is(no_reg); entry++) { if (object_.is(entry->object) && @@ -7419,7 +7407,7 @@ void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() { void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { - for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; + for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; !entry->object.is(no_reg); entry++) { RecordWriteStub stub(entry->object, diff --git a/deps/v8/src/mips/constants-mips.h b/deps/v8/src/mips/constants-mips.h index fd04722792..3d585717cb 100644 --- a/deps/v8/src/mips/constants-mips.h +++ b/deps/v8/src/mips/constants-mips.h @@ -788,11 +788,6 @@ const int kBArgsSlotsSize = 0 * Instruction::kInstrSize; const int kBranchReturnOffset = 2 * Instruction::kInstrSize; -const int kDoubleAlignmentBits = 3; -const int kDoubleAlignment = (1 << kDoubleAlignmentBits); -const int kDoubleAlignmentMask = kDoubleAlignment - 1; - - } } // namespace v8::internal #endif // #ifndef V8_MIPS_CONSTANTS_H_ diff --git a/deps/v8/src/mips/debug-mips.cc b/deps/v8/src/mips/debug-mips.cc index 83f5f50172..3be1e4d8b2 100644 --- a/deps/v8/src/mips/debug-mips.cc +++ b/deps/v8/src/mips/debug-mips.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -116,6 +116,8 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() { Assembler::kDebugBreakSlotInstructions); } +const bool Debug::FramePaddingLayout::kIsSupported = false; + #define __ ACCESS_MASM(masm) diff --git a/deps/v8/src/mips/deoptimizer-mips.cc b/deps/v8/src/mips/deoptimizer-mips.cc index 51c2e46778..62f3155eb3 100644 --- a/deps/v8/src/mips/deoptimizer-mips.cc +++ b/deps/v8/src/mips/deoptimizer-mips.cc @@ -447,6 +447,8 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator, void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, int frame_index) { + Builtins* builtins = isolate_->builtins(); + Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); unsigned height = iterator->Next(); unsigned height_in_bytes = height * kPointerSize; @@ -454,7 +456,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, PrintF(" translating construct stub => height=%d\n", height_in_bytes); } - unsigned fixed_frame_size = 7 * kPointerSize; + unsigned fixed_frame_size = 8 * kPointerSize; unsigned output_frame_size = height_in_bytes + fixed_frame_size; // Allocate and store the output frame description. @@ -519,6 +521,15 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, top_address + output_offset, output_offset, value); } + // The output frame reflects a JSConstructStubGeneric frame. + output_offset -= kPointerSize; + value = reinterpret_cast<intptr_t>(construct_stub); + output_frame->SetFrameSlot(output_offset, value); + if (FLAG_trace_deopt) { + PrintF(" 0x%08x: [top + %d] <- 0x%08x ; code object\n", + top_address + output_offset, output_offset, value); + } + // Number of incoming arguments. output_offset -= kPointerSize; value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1)); @@ -549,8 +560,6 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, ASSERT(0 == output_offset); - Builtins* builtins = isolate_->builtins(); - Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); uint32_t pc = reinterpret_cast<uint32_t>( construct_stub->instruction_start() + isolate_->heap()->construct_stub_deopt_pc_offset()->value()); diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc index 657bee8657..4ffd0ea011 100644 --- a/deps/v8/src/mips/full-codegen-mips.cc +++ b/deps/v8/src/mips/full-codegen-mips.cc @@ -120,13 +120,6 @@ class JumpPatchSite BASE_EMBEDDED { }; -// TODO(jkummerow): Obsolete as soon as x64 is updated. Remove. -int FullCodeGenerator::self_optimization_header_size() { - UNREACHABLE(); - return 10 * Instruction::kInstrSize; -} - - // Generate code for a JS function. On entry to the function the receiver // and arguments have been pushed on the stack left to right. The actual // argument count matches the formal parameter count expected by the @@ -282,11 +275,11 @@ void FullCodeGenerator::Generate() { // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - VariableProxy* proxy = scope()->function(); - ASSERT(proxy->var()->mode() == CONST || - proxy->var()->mode() == CONST_HARMONY); - ASSERT(proxy->var()->location() != Variable::UNALLOCATED); - EmitDeclaration(proxy, proxy->var()->mode(), NULL); + VariableDeclaration* function = scope()->function(); + ASSERT(function->proxy()->var()->mode() == CONST || + function->proxy()->var()->mode() == CONST_HARMONY); + ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); + VisitVariableDeclaration(function); } VisitDeclarations(scope()->declarations()); } @@ -796,64 +789,53 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, } -void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function) { +void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { + // The variable in the declaration always resides in the current function + // context. + ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); + if (FLAG_debug_code) { + // Check that we're not inside a with or catch context. + __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset)); + __ LoadRoot(t0, Heap::kWithContextMapRootIndex); + __ Check(ne, "Declaration in with context.", + a1, Operand(t0)); + __ LoadRoot(t0, Heap::kCatchContextMapRootIndex); + __ Check(ne, "Declaration in catch context.", + a1, Operand(t0)); + } +} + + +void FullCodeGenerator::VisitVariableDeclaration( + VariableDeclaration* declaration) { // If it was not possible to allocate the variable at compile time, we // need to "declare" it at runtime to make sure it actually exists in the // local context. + VariableProxy* proxy = declaration->proxy(); + VariableMode mode = declaration->mode(); Variable* variable = proxy->var(); - bool binding_needs_init = (function == NULL) && - (mode == CONST || mode == CONST_HARMONY || mode == LET); + bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; switch (variable->location()) { case Variable::UNALLOCATED: - ++global_count_; + globals_->Add(variable->name()); + globals_->Add(variable->binding_needs_init() + ? isolate()->factory()->the_hole_value() + : isolate()->factory()->undefined_value()); break; case Variable::PARAMETER: case Variable::LOCAL: - if (function != NULL) { - Comment cmnt(masm_, "[ Declaration"); - VisitForAccumulatorValue(function); - __ sw(result_register(), StackOperand(variable)); - } else if (binding_needs_init) { - Comment cmnt(masm_, "[ Declaration"); - __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); - __ sw(t0, StackOperand(variable)); + if (hole_init) { + Comment cmnt(masm_, "[ VariableDeclaration"); + __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); + __ sw(t0, StackOperand(variable)); } break; case Variable::CONTEXT: - // The variable in the decl always resides in the current function - // context. - ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); - if (FLAG_debug_code) { - // Check that we're not inside a with or catch context. - __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset)); - __ LoadRoot(t0, Heap::kWithContextMapRootIndex); - __ Check(ne, "Declaration in with context.", - a1, Operand(t0)); - __ LoadRoot(t0, Heap::kCatchContextMapRootIndex); - __ Check(ne, "Declaration in catch context.", - a1, Operand(t0)); - } - if (function != NULL) { - Comment cmnt(masm_, "[ Declaration"); - VisitForAccumulatorValue(function); - __ sw(result_register(), ContextOperand(cp, variable->index())); - int offset = Context::SlotOffset(variable->index()); - // We know that we have written a function, which is not a smi. - __ RecordWriteContextSlot(cp, - offset, - result_register(), - a2, - kRAHasBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - PrepareForBailoutForId(proxy->id(), NO_REGISTERS); - } else if (binding_needs_init) { - Comment cmnt(masm_, "[ Declaration"); + if (hole_init) { + Comment cmnt(masm_, "[ VariableDeclaration"); + EmitDebugCheckDeclarationContext(variable); __ LoadRoot(at, Heap::kTheHoleValueRootIndex); __ sw(at, ContextOperand(cp, variable->index())); // No write barrier since the_hole_value is in old space. @@ -862,13 +844,11 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, break; case Variable::LOOKUP: { - Comment cmnt(masm_, "[ Declaration"); + Comment cmnt(masm_, "[ VariableDeclaration"); __ li(a2, Operand(variable->name())); // Declaration nodes are always introduced in one of four modes. - ASSERT(mode == VAR || - mode == CONST || - mode == CONST_HARMONY || - mode == LET); + ASSERT(mode == VAR || mode == LET || + mode == CONST || mode == CONST_HARMONY); PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; __ li(a1, Operand(Smi::FromInt(attr))); @@ -876,13 +856,9 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, // Note: For variables we must not push an initial value (such as // 'undefined') because we may have a (legal) redeclaration and we // must not destroy the current value. - if (function != NULL) { - __ Push(cp, a2, a1); - // Push initial value for function declaration. - VisitForStackValue(function); - } else if (binding_needs_init) { - __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); - __ Push(cp, a2, a1, a0); + if (hole_init) { + __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); + __ Push(cp, a2, a1, a0); } else { ASSERT(Smi::FromInt(0) == 0); __ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value. @@ -895,6 +871,122 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, } +void FullCodeGenerator::VisitFunctionDeclaration( + FunctionDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: { + globals_->Add(variable->name()); + Handle<SharedFunctionInfo> function = + Compiler::BuildFunctionInfo(declaration->fun(), script()); + // Check for stack-overflow exception. + if (function.is_null()) return SetStackOverflow(); + globals_->Add(function); + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + VisitForAccumulatorValue(declaration->fun()); + __ sw(result_register(), StackOperand(variable)); + break; + } + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + EmitDebugCheckDeclarationContext(variable); + VisitForAccumulatorValue(declaration->fun()); + __ sw(result_register(), ContextOperand(cp, variable->index())); + int offset = Context::SlotOffset(variable->index()); + // We know that we have written a function, which is not a smi. + __ RecordWriteContextSlot(cp, + offset, + result_register(), + a2, + kRAHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); + break; + } + + case Variable::LOOKUP: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + __ li(a2, Operand(variable->name())); + __ li(a1, Operand(Smi::FromInt(NONE))); + __ Push(cp, a2, a1); + // Push initial value for function declaration. + VisitForStackValue(declaration->fun()); + __ CallRuntime(Runtime::kDeclareContextSlot, 4); + break; + } + } +} + + +void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + Handle<JSModule> instance = declaration->module()->interface()->Instance(); + ASSERT(!instance.is_null()); + + switch (variable->location()) { + case Variable::UNALLOCATED: { + Comment cmnt(masm_, "[ ModuleDeclaration"); + globals_->Add(variable->name()); + globals_->Add(instance); + Visit(declaration->module()); + break; + } + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ ModuleDeclaration"); + EmitDebugCheckDeclarationContext(variable); + __ li(a1, Operand(instance)); + __ sw(a1, ContextOperand(cp, variable->index())); + Visit(declaration->module()); + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::LOOKUP: + UNREACHABLE(); + } +} + + +void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: + // TODO(rossberg) + break; + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ ImportDeclaration"); + EmitDebugCheckDeclarationContext(variable); + // TODO(rossberg) + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::LOOKUP: + UNREACHABLE(); + } +} + + +void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { + // TODO(rossberg) +} + + void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { // Call the runtime to declare the globals. // The context is the first argument. @@ -2296,6 +2388,18 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { } // Record source position for debugger. SetSourcePosition(expr->position()); + + // Record call targets in unoptimized code, but not in the snapshot. + if (!Serializer::enabled()) { + flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); + Handle<Object> uninitialized = + TypeFeedbackCells::UninitializedSentinel(isolate()); + Handle<JSGlobalPropertyCell> cell = + isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); + RecordTypeFeedbackCell(expr->id(), cell); + __ li(a2, Operand(cell)); + } + CallFunctionStub stub(arg_count, flags); __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ CallStub(&stub); @@ -2984,7 +3088,7 @@ void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) { __ Move(f14, zero_reg, a1); // Subtract and store the result in the heap number. __ sub_d(f0, f12, f14); - __ sdc1(f0, MemOperand(s0, HeapNumber::kValueOffset - kHeapObjectTag)); + __ sdc1(f0, FieldMemOperand(s0, HeapNumber::kValueOffset)); __ mov(v0, s0); } else { __ PrepareCallCFunction(2, a0); @@ -3646,7 +3750,6 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { Register scratch1 = t3; Register scratch2 = t5; Register scratch3 = t4; - Register scratch4 = v1; // Separator operand is on the stack. __ pop(separator); @@ -4492,7 +4595,8 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) { void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { Scope* declaration_scope = scope()->DeclarationScope(); - if (declaration_scope->is_global_scope()) { + if (declaration_scope->is_global_scope() || + declaration_scope->is_module_scope()) { // Contexts nested in the global context have a canonical empty function // as their closure, not the anonymous closure containing the global // code. Pass a smi sentinel and let the runtime look up the empty diff --git a/deps/v8/src/mips/ic-mips.cc b/deps/v8/src/mips/ic-mips.cc index 2c4da1a886..964a7e2430 100644 --- a/deps/v8/src/mips/ic-mips.cc +++ b/deps/v8/src/mips/ic-mips.cc @@ -767,7 +767,7 @@ static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, __ Branch(slow_case, lt, scratch2, Operand(FIRST_JS_RECEIVER_TYPE)); // Check that the key is a positive smi. - __ And(scratch1, key, Operand(0x8000001)); + __ And(scratch1, key, Operand(0x80000001)); __ Branch(slow_case, ne, scratch1, Operand(zero_reg)); // Load the elements into scratch1 and check its map. @@ -1688,12 +1688,12 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { // Activate inlined smi code. if (previous_state == UNINITIALIZED) { - PatchInlinedSmiCode(address()); + PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); } } -void PatchInlinedSmiCode(Address address) { +void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { Address andi_instruction_address = address + Assembler::kCallTargetAddressOffset; @@ -1727,33 +1727,30 @@ void PatchInlinedSmiCode(Address address) { Instr instr_at_patch = Assembler::instr_at(patch_address); Instr branch_instr = Assembler::instr_at(patch_address + Instruction::kInstrSize); - ASSERT(Assembler::IsAndImmediate(instr_at_patch)); - ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch)); + // This is patching a conditional "jump if not smi/jump if smi" site. + // Enabling by changing from + // andi at, rx, 0 + // Branch <target>, eq, at, Operand(zero_reg) + // to: + // andi at, rx, #kSmiTagMask + // Branch <target>, ne, at, Operand(zero_reg) + // and vice-versa to be disabled again. + CodePatcher patcher(patch_address, 2); + Register reg = Register::from_code(Assembler::GetRs(instr_at_patch)); + if (check == ENABLE_INLINED_SMI_CHECK) { + ASSERT(Assembler::IsAndImmediate(instr_at_patch)); + ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch)); + patcher.masm()->andi(at, reg, kSmiTagMask); + } else { + ASSERT(check == DISABLE_INLINED_SMI_CHECK); + ASSERT(Assembler::IsAndImmediate(instr_at_patch)); + patcher.masm()->andi(at, reg, 0); + } ASSERT(Assembler::IsBranch(branch_instr)); if (Assembler::IsBeq(branch_instr)) { - // This is patching a "jump if not smi" site to be active. - // Changing: - // andi at, rx, 0 - // Branch <target>, eq, at, Operand(zero_reg) - // to: - // andi at, rx, #kSmiTagMask - // Branch <target>, ne, at, Operand(zero_reg) - CodePatcher patcher(patch_address, 2); - Register reg = Register::from_code(Assembler::GetRs(instr_at_patch)); - patcher.masm()->andi(at, reg, kSmiTagMask); patcher.ChangeBranchCondition(ne); } else { ASSERT(Assembler::IsBne(branch_instr)); - // This is patching a "jump if smi" site to be active. - // Changing: - // andi at, rx, 0 - // Branch <target>, ne, at, Operand(zero_reg) - // to: - // andi at, rx, #kSmiTagMask - // Branch <target>, eq, at, Operand(zero_reg) - CodePatcher patcher(patch_address, 2); - Register reg = Register::from_code(Assembler::GetRs(instr_at_patch)); - patcher.masm()->andi(at, reg, kSmiTagMask); patcher.ChangeBranchCondition(eq); } } diff --git a/deps/v8/src/mips/lithium-codegen-mips.cc b/deps/v8/src/mips/lithium-codegen-mips.cc index 6628d8e1ef..986921fef5 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.cc +++ b/deps/v8/src/mips/lithium-codegen-mips.cc @@ -2139,8 +2139,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, RelocInfo::CODE_TARGET, instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); - ASSERT(instr->HasDeoptimizationEnvironment()); - LEnvironment* env = instr->deoptimization_environment(); + LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment(); safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); // Put the result value into the result register slot and // restore all registers. @@ -2345,39 +2344,35 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { Register result = ToRegister(instr->result()); Register scratch = scratch0(); int map_count = instr->hydrogen()->types()->length(); + bool need_generic = instr->hydrogen()->need_generic(); + + if (map_count == 0 && !need_generic) { + DeoptimizeIf(al, instr->environment()); + return; + } Handle<String> name = instr->hydrogen()->name(); - if (map_count == 0) { - ASSERT(instr->hydrogen()->need_generic()); - __ li(a2, Operand(name)); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); - } else { - Label done; - __ lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); - for (int i = 0; i < map_count - 1; ++i) { - Handle<Map> map = instr->hydrogen()->types()->at(i); + Label done; + __ lw(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); + for (int i = 0; i < map_count; ++i) { + bool last = (i == map_count - 1); + Handle<Map> map = instr->hydrogen()->types()->at(i); + if (last && !need_generic) { + Handle<Map> map = instr->hydrogen()->types()->last(); + DeoptimizeIf(ne, instr->environment(), scratch, Operand(map)); + } else { Label next; __ Branch(&next, ne, scratch, Operand(map)); EmitLoadFieldOrConstantFunction(result, object, map, name); __ Branch(&done); __ bind(&next); } - Handle<Map> map = instr->hydrogen()->types()->last(); - if (instr->hydrogen()->need_generic()) { - Label generic; - __ Branch(&generic, ne, scratch, Operand(map)); - EmitLoadFieldOrConstantFunction(result, object, map, name); - __ Branch(&done); - __ bind(&generic); - __ li(a2, Operand(name)); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); - } else { - DeoptimizeIf(ne, instr->environment(), scratch, Operand(map)); - EmitLoadFieldOrConstantFunction(result, object, map, name); - } - __ bind(&done); } + if (need_generic) { + __ li(a2, Operand(name)); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + CallCode(ic, RelocInfo::CODE_TARGET, instr); + } + __ bind(&done); } @@ -2651,16 +2646,20 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { Register temp = scratch1(); Register result = ToRegister(instr->result()); - // Check if the calling frame is an arguments adaptor frame. - Label done, adapted; - __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); - __ lw(result, MemOperand(scratch, StandardFrameConstants::kContextOffset)); - __ Xor(temp, result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); - - // Result is the frame pointer for the frame if not adapted and for the real - // frame below the adaptor frame if adapted. - __ Movn(result, fp, temp); // Move only if temp is not equal to zero (ne). - __ Movz(result, scratch, temp); // Move only if temp is equal to zero (eq). + if (instr->hydrogen()->from_inlined()) { + __ Subu(result, sp, 2 * kPointerSize); + } else { + // Check if the calling frame is an arguments adaptor frame. + Label done, adapted; + __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); + __ lw(result, MemOperand(scratch, StandardFrameConstants::kContextOffset)); + __ Xor(temp, result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); + + // Result is the frame pointer for the frame if not adapted and for the real + // frame below the adaptor frame if adapted. + __ Movn(result, fp, temp); // Move only if temp is not equal to zero (ne). + __ Movz(result, scratch, temp); // Move only if temp is equal to zero (eq). + } } @@ -2768,7 +2767,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { __ sll(scratch, length, 2); __ bind(&invoke); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator( @@ -2793,6 +2792,11 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) { } +void LCodeGen::DoDrop(LDrop* instr) { + __ Drop(instr->count()); +} + + void LCodeGen::DoThisFunction(LThisFunction* instr) { Register result = ToRegister(instr->result()); __ LoadHeapObject(result, instr->hydrogen()->closure()); @@ -2823,7 +2827,6 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { void LCodeGen::DoGlobalObject(LGlobalObject* instr) { - Register context = ToRegister(instr->context()); Register result = ToRegister(instr->result()); __ lw(result, ContextOperand(cp, Context::GLOBAL_INDEX)); } @@ -2839,7 +2842,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { void LCodeGen::CallKnownFunction(Handle<JSFunction> function, int arity, LInstruction* instr, - CallKind call_kind) { + CallKind call_kind, + A1State a1_state) { bool can_invoke_directly = !function->NeedsArgumentsAdaption() || function->shared()->formal_parameter_count() == arity; @@ -2847,7 +2851,10 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, RecordPosition(pointers->position()); if (can_invoke_directly) { - __ LoadHeapObject(a1, function); + if (a1_state == A1_UNINITIALIZED) { + __ LoadHeapObject(a1, function); + } + // Change context if needed. bool change_context = (info()->closure()->context() != function->context()) || @@ -2884,7 +2891,11 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { ASSERT(ToRegister(instr->result()).is(v0)); __ mov(a0, v0); - CallKnownFunction(instr->function(), instr->arity(), instr, CALL_AS_METHOD); + CallKnownFunction(instr->function(), + instr->arity(), + instr, + CALL_AS_METHOD, + A1_UNINITIALIZED); } @@ -3210,7 +3221,7 @@ void LCodeGen::DoRandom(LRandom* instr) { // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16) __ And(a3, a1, Operand(0xFFFF)); __ li(t0, Operand(18273)); - __ mul(a3, a3, t0); + __ Mul(a3, a3, t0); __ srl(a1, a1, 16); __ Addu(a1, a3, a1); // Save state[0]. @@ -3219,7 +3230,7 @@ void LCodeGen::DoRandom(LRandom* instr) { // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16) __ And(a3, a0, Operand(0xFFFF)); __ li(t0, Operand(36969)); - __ mul(a3, a3, t0); + __ Mul(a3, a3, t0); __ srl(a0, a0, 16), __ Addu(a0, a3, a0); // Save state[1]. @@ -3320,13 +3331,21 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { ASSERT(ToRegister(instr->function()).is(a1)); ASSERT(instr->HasPointerMap()); - ASSERT(instr->HasDeoptimizationEnvironment()); - LPointerMap* pointers = instr->pointer_map(); - RecordPosition(pointers->position()); - SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); - ParameterCount count(instr->arity()); - __ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD); - __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + + if (instr->known_function().is_null()) { + LPointerMap* pointers = instr->pointer_map(); + RecordPosition(pointers->position()); + SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); + ParameterCount count(instr->arity()); + __ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD); + __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } else { + CallKnownFunction(instr->known_function(), + instr->arity(), + instr, + CALL_AS_METHOD, + A1_CONTAINS_TARGET); + } } @@ -3381,7 +3400,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { ASSERT(ToRegister(instr->result()).is(v0)); - CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); + CallKnownFunction(instr->target(), + instr->arity(), + instr, + CALL_AS_FUNCTION, + A1_UNINITIALIZED); } @@ -3537,14 +3560,16 @@ void LCodeGen::DoStoreKeyedFastDoubleElement( Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); } - Label is_nan; - // Check for NaN. All NaNs must be canonicalized. - __ BranchF(NULL, &is_nan, eq, value, value); - __ Branch(¬_nan); + if (instr->NeedsCanonicalization()) { + Label is_nan; + // Check for NaN. All NaNs must be canonicalized. + __ BranchF(NULL, &is_nan, eq, value, value); + __ Branch(¬_nan); - // Only load canonical NaN if the comparison above set the overflow. - __ bind(&is_nan); - __ Move(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double()); + // Only load canonical NaN if the comparison above set the overflow. + __ bind(&is_nan); + __ Move(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double()); + } __ bind(¬_nan); __ sdc1(value, MemOperand(scratch)); @@ -4124,7 +4149,6 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Register scratch1 = scratch0(); Register scratch2 = ToRegister(instr->TempAt(0)); DoubleRegister double_input = ToDoubleRegister(instr->InputAt(0)); - DoubleRegister double_scratch = double_scratch0(); FPURegister single_scratch = double_scratch0().low(); if (instr->truncating()) { @@ -4237,14 +4261,21 @@ void LCodeGen::DoCheckMapCommon(Register reg, } -void LCodeGen::DoCheckMap(LCheckMap* instr) { +void LCodeGen::DoCheckMaps(LCheckMaps* instr) { Register scratch = scratch0(); LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister()); Register reg = ToRegister(input); - Handle<Map> map = instr->hydrogen()->map(); - DoCheckMapCommon(reg, scratch, map, instr->hydrogen()->mode(), - instr->environment()); + Label success; + SmallMapList* map_set = instr->hydrogen()->map_set(); + for (int i = 0; i < map_set->length() - 1; i++) { + Handle<Map> map = map_set->at(i); + __ CompareMapAndBranch( + reg, scratch, map, &success, eq, &success, REQUIRE_EXACT_MAP); + } + Handle<Map> map = map_set->last(); + DoCheckMapCommon(reg, scratch, map, REQUIRE_EXACT_MAP, instr->environment()); + __ bind(&success); } @@ -4360,6 +4391,14 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { deferred->entry(), TAG_OBJECT); + __ bind(deferred->exit()); + if (FLAG_debug_code) { + Label is_in_new_space; + __ JumpIfInNewSpace(result, scratch, &is_in_new_space); + __ Abort("Allocated object is not in new-space"); + __ bind(&is_in_new_space); + } + // Load the initial map. Register map = scratch; __ LoadHeapObject(map, constructor); @@ -4378,14 +4417,14 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { __ sw(scratch, FieldMemOperand(result, property_offset)); } } - - __ bind(deferred->exit()); } void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { Register result = ToRegister(instr->result()); Handle<JSFunction> constructor = instr->hydrogen()->constructor(); + Handle<Map> initial_map(constructor->initial_map()); + int instance_size = initial_map->instance_size(); // TODO(3095996): Get rid of this. For now, we need to make the // result register contain a valid pointer because it is already @@ -4393,9 +4432,9 @@ void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { __ mov(result, zero_reg); PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); - __ LoadHeapObject(a0, constructor); + __ li(a0, Operand(Smi::FromInt(instance_size))); __ push(a0); - CallRuntimeFromDeferred(Runtime::kNewObject, 1, instr); + CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); __ StoreToSafepointRegisterSlot(v0, result); } @@ -4531,9 +4570,10 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, __ sw(a2, FieldMemOperand(result, total_offset + 4)); } } else if (elements->IsFixedArray()) { + Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); for (int i = 0; i < elements_length; i++) { int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i); - Handle<Object> value = JSObject::GetElement(object, i); + Handle<Object> value(fast_elements->get(i)); if (value->IsJSObject()) { Handle<JSObject> value_object = Handle<JSObject>::cast(value); __ Addu(a2, result, Operand(*offset)); @@ -4557,6 +4597,23 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, void LCodeGen::DoFastLiteral(LFastLiteral* instr) { int size = instr->hydrogen()->total_size(); + ElementsKind boilerplate_elements_kind = + instr->hydrogen()->boilerplate()->GetElementsKind(); + + // Deopt if the literal boilerplate ElementsKind is of a type different than + // the expected one. The check isn't necessary if the boilerplate has already + // been converted to FAST_ELEMENTS. + if (boilerplate_elements_kind != FAST_ELEMENTS) { + __ LoadHeapObject(a1, instr->hydrogen()->boilerplate()); + // Load map into a2. + __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset)); + // Load the map's "bit field 2". + __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset)); + // Retrieve elements_kind from bit field 2. + __ Ext(a2, a2, Map::kElementsKindShift, Map::kElementsKindBitCount); + DeoptimizeIf(ne, instr->environment(), a2, + Operand(boilerplate_elements_kind)); + } // Allocate all objects that are part of the literal in one big // allocation. This avoids multiple limit checks. @@ -4892,7 +4949,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { Register strict = scratch0(); __ li(strict, Operand(Smi::FromInt(strict_mode_flag()))); __ Push(object, key, strict); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator( @@ -4905,7 +4962,7 @@ void LCodeGen::DoIn(LIn* instr) { Register obj = ToRegister(instr->object()); Register key = ToRegister(instr->key()); __ Push(key, obj); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); diff --git a/deps/v8/src/mips/lithium-codegen-mips.h b/deps/v8/src/mips/lithium-codegen-mips.h index b5082561e0..94bb945b31 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.h +++ b/deps/v8/src/mips/lithium-codegen-mips.h @@ -212,12 +212,18 @@ class LCodeGen BASE_EMBEDDED { int argc, LInstruction* instr); + enum A1State { + A1_UNINITIALIZED, + A1_CONTAINS_TARGET + }; + // Generate a direct call to a known function. Expects the function // to be in a1. void CallKnownFunction(Handle<JSFunction> function, int arity, LInstruction* instr, - CallKind call_kind); + CallKind call_kind, + A1State a1_state); void LoadHeapObject(Register result, Handle<HeapObject> object); diff --git a/deps/v8/src/mips/lithium-gap-resolver-mips.cc b/deps/v8/src/mips/lithium-gap-resolver-mips.cc index 41b060debc..4a5fbe39c5 100644 --- a/deps/v8/src/mips/lithium-gap-resolver-mips.cc +++ b/deps/v8/src/mips/lithium-gap-resolver-mips.cc @@ -33,8 +33,6 @@ namespace v8 { namespace internal { -static const Register kSavedValueRegister = kLithiumScratchReg; - LGapResolver::LGapResolver(LCodeGen* owner) : cgen_(owner), moves_(32), @@ -170,9 +168,9 @@ void LGapResolver::BreakCycle(int index) { LOperand* source = moves_[index].source(); saved_destination_ = moves_[index].destination(); if (source->IsRegister()) { - __ mov(kSavedValueRegister, cgen_->ToRegister(source)); + __ mov(kLithiumScratchReg, cgen_->ToRegister(source)); } else if (source->IsStackSlot()) { - __ lw(kSavedValueRegister, cgen_->ToMemOperand(source)); + __ lw(kLithiumScratchReg, cgen_->ToMemOperand(source)); } else if (source->IsDoubleRegister()) { __ mov_d(kLithiumScratchDouble, cgen_->ToDoubleRegister(source)); } else if (source->IsDoubleStackSlot()) { @@ -189,11 +187,11 @@ void LGapResolver::RestoreValue() { ASSERT(in_cycle_); ASSERT(saved_destination_ != NULL); - // Spilled value is in kSavedValueRegister or kLithiumScratchDouble. + // Spilled value is in kLithiumScratchReg or kLithiumScratchDouble. if (saved_destination_->IsRegister()) { - __ mov(cgen_->ToRegister(saved_destination_), kSavedValueRegister); + __ mov(cgen_->ToRegister(saved_destination_), kLithiumScratchReg); } else if (saved_destination_->IsStackSlot()) { - __ sw(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_)); + __ sw(kLithiumScratchReg, cgen_->ToMemOperand(saved_destination_)); } else if (saved_destination_->IsDoubleRegister()) { __ mov_d(cgen_->ToDoubleRegister(saved_destination_), kLithiumScratchDouble); @@ -245,8 +243,8 @@ void LGapResolver::EmitMove(int index) { __ sw(at, destination_operand); } } else { - __ lw(kSavedValueRegister, source_operand); - __ sw(kSavedValueRegister, destination_operand); + __ lw(kLithiumScratchReg, source_operand); + __ sw(kLithiumScratchReg, destination_operand); } } @@ -263,13 +261,13 @@ void LGapResolver::EmitMove(int index) { ASSERT(destination->IsStackSlot()); ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone. if (cgen_->IsInteger32(constant_source)) { - __ li(kSavedValueRegister, + __ li(kLithiumScratchReg, Operand(cgen_->ToInteger32(constant_source))); } else { - __ LoadObject(kSavedValueRegister, + __ LoadObject(kLithiumScratchReg, cgen_->ToHandle(constant_source)); } - __ sw(kSavedValueRegister, cgen_->ToMemOperand(destination)); + __ sw(kLithiumScratchReg, cgen_->ToMemOperand(destination)); } } else if (source->IsDoubleRegister()) { @@ -291,15 +289,15 @@ void LGapResolver::EmitMove(int index) { MemOperand destination_operand = cgen_->ToMemOperand(destination); if (in_cycle_) { // kLithiumScratchDouble was used to break the cycle, - // but kSavedValueRegister is free. + // but kLithiumScratchReg is free. MemOperand source_high_operand = cgen_->ToHighMemOperand(source); MemOperand destination_high_operand = cgen_->ToHighMemOperand(destination); - __ lw(kSavedValueRegister, source_operand); - __ sw(kSavedValueRegister, destination_operand); - __ lw(kSavedValueRegister, source_high_operand); - __ sw(kSavedValueRegister, destination_high_operand); + __ lw(kLithiumScratchReg, source_operand); + __ sw(kLithiumScratchReg, destination_operand); + __ lw(kLithiumScratchReg, source_high_operand); + __ sw(kLithiumScratchReg, destination_high_operand); } else { __ ldc1(kLithiumScratchDouble, source_operand); __ sdc1(kLithiumScratchDouble, destination_operand); diff --git a/deps/v8/src/mips/lithium-mips.cc b/deps/v8/src/mips/lithium-mips.cc index 1e0c2160aa..1eb3ab7a0e 100644 --- a/deps/v8/src/mips/lithium-mips.cc +++ b/deps/v8/src/mips/lithium-mips.cc @@ -108,22 +108,17 @@ void LInstruction::PrintTo(StringStream* stream) { } -template<int R, int I, int T> -void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) { +void LInstruction::PrintDataTo(StringStream* stream) { stream->Add("= "); - for (int i = 0; i < inputs_.length(); i++) { + for (int i = 0; i < InputCount(); i++) { if (i > 0) stream->Add(" "); - inputs_[i]->PrintTo(stream); + InputAt(i)->PrintTo(stream); } } -template<int R, int I, int T> -void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) { - for (int i = 0; i < results_.length(); i++) { - if (i > 0) stream->Add(" "); - results_[i]->PrintTo(stream); - } +void LInstruction::PrintOutputOperandTo(StringStream* stream) { + if (HasResult()) result()->PrintTo(stream); } @@ -732,22 +727,6 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { } -LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( - LInstruction* instr, int ast_id) { - ASSERT(instruction_pending_deoptimization_environment_ == NULL); - ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); - instruction_pending_deoptimization_environment_ = instr; - pending_deoptimization_ast_id_ = ast_id; - return instr; -} - - -void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { - instruction_pending_deoptimization_environment_ = NULL; - pending_deoptimization_ast_id_ = AstNode::kNoNumber; -} - - LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, HInstruction* hinstr, CanDeoptimize can_deoptimize) { @@ -760,8 +739,10 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, if (hinstr->HasObservableSideEffects()) { ASSERT(hinstr->next()->IsSimulate()); HSimulate* sim = HSimulate::cast(hinstr->next()); - instr = SetInstructionPendingDeoptimizationEnvironment( - instr, sim->ast_id()); + ASSERT(instruction_pending_deoptimization_environment_ == NULL); + ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); + instruction_pending_deoptimization_environment_ = instr; + pending_deoptimization_ast_id_ = sim->ast_id(); } // If instruction does not have side-effects lazy deoptimization @@ -779,12 +760,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, } -LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) { - instr->MarkAsSaveDoubles(); - return instr; -} - - LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) { ASSERT(!instr->HasPointerMap()); instr->set_pointer_map(new(zone()) LPointerMap(position_)); @@ -1296,6 +1271,7 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { ASSERT(instr->value()->representation().IsInteger32()); ASSERT(instr->representation().IsInteger32()); + if (instr->HasNoUses()) return NULL; LOperand* value = UseRegisterAtStart(instr->value()); return DefineAsRegister(new(zone()) LBitNotI(value)); } @@ -1320,6 +1296,12 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { } +LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) { + UNIMPLEMENTED(); + return NULL; +} + + LInstruction* LChunkBuilder::DoMod(HMod* instr) { if (instr->representation().IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); @@ -1460,7 +1442,6 @@ LInstruction* LChunkBuilder::DoRandom(HRandom* instr) { LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) { - Representation r = instr->GetInputRepresentation(); ASSERT(instr->left()->representation().IsTagged()); ASSERT(instr->right()->representation().IsTagged()); LOperand* left = UseFixed(instr->left(), a1); @@ -1755,9 +1736,9 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { } -LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) { +LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LOperand* value = UseRegisterAtStart(instr->value()); - LInstruction* result = new(zone()) LCheckMap(value); + LInstruction* result = new(zone()) LCheckMaps(value); return AssignEnvironment(result); } @@ -2248,9 +2229,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { if (pending_deoptimization_ast_id_ == instr->ast_id()) { LInstruction* result = new(zone()) LLazyBailout; result = AssignEnvironment(result); + // Store the lazy deopt environment with the instruction if needed. Right + // now it is only used for LInstanceOfKnownGlobal. instruction_pending_deoptimization_environment_-> - set_deoptimization_environment(result->environment()); - ClearInstructionPendingDeoptimizationEnvironment(); + SetDeferredLazyDeoptimizationEnvironment(result->environment()); + instruction_pending_deoptimization_environment_ = NULL; + pending_deoptimization_ast_id_ = AstNode::kNoNumber; return result; } @@ -2277,6 +2261,9 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { undefined, instr->call_kind(), instr->is_construct()); + if (instr->arguments_var() != NULL) { + inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject()); + } current_block_->UpdateEnvironment(inner); chunk_->AddInlinedClosure(instr->closure()); return NULL; @@ -2284,10 +2271,21 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { + LInstruction* pop = NULL; + + HEnvironment* env = current_block_->last_environment(); + + if (instr->arguments_pushed()) { + int argument_count = env->arguments_environment()->parameter_count(); + pop = new(zone()) LDrop(argument_count); + argument_count_ -= argument_count; + } + HEnvironment* outer = current_block_->last_environment()-> DiscardInlined(false); current_block_->UpdateEnvironment(outer); - return NULL; + + return pop; } diff --git a/deps/v8/src/mips/lithium-mips.h b/deps/v8/src/mips/lithium-mips.h index 5a7bf4d941..a04b42961a 100644 --- a/deps/v8/src/mips/lithium-mips.h +++ b/deps/v8/src/mips/lithium-mips.h @@ -71,7 +71,7 @@ class LCodeGen; V(CallStub) \ V(CheckFunction) \ V(CheckInstanceType) \ - V(CheckMap) \ + V(CheckMaps) \ V(CheckNonSmi) \ V(CheckPrototypeMaps) \ V(CheckSmi) \ @@ -179,7 +179,8 @@ class LCodeGen; V(CheckMapValue) \ V(LoadFieldByIndex) \ V(DateField) \ - V(WrapReceiver) + V(WrapReceiver) \ + V(Drop) #define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \ virtual Opcode opcode() const { return LInstruction::k##type; } \ @@ -202,15 +203,14 @@ class LInstruction: public ZoneObject { LInstruction() : environment_(NULL), hydrogen_value_(NULL), - is_call_(false), - is_save_doubles_(false) { } + is_call_(false) { } virtual ~LInstruction() { } virtual void CompileToNative(LCodeGen* generator) = 0; virtual const char* Mnemonic() const = 0; virtual void PrintTo(StringStream* stream); - virtual void PrintDataTo(StringStream* stream) = 0; - virtual void PrintOutputOperandTo(StringStream* stream) = 0; + virtual void PrintDataTo(StringStream* stream); + virtual void PrintOutputOperandTo(StringStream* stream); enum Opcode { // Declare a unique enum value for each instruction. @@ -245,22 +245,12 @@ class LInstruction: public ZoneObject { void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; } HValue* hydrogen_value() const { return hydrogen_value_; } - void set_deoptimization_environment(LEnvironment* env) { - deoptimization_environment_.set(env); - } - LEnvironment* deoptimization_environment() const { - return deoptimization_environment_.get(); - } - bool HasDeoptimizationEnvironment() const { - return deoptimization_environment_.is_set(); - } + virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { } void MarkAsCall() { is_call_ = true; } - void MarkAsSaveDoubles() { is_save_doubles_ = true; } // Interface to the register allocator and iterators. bool IsMarkedAsCall() const { return is_call_; } - bool IsMarkedAsSaveDoubles() const { return is_save_doubles_; } virtual bool HasResult() const = 0; virtual LOperand* result() = 0; @@ -281,7 +271,6 @@ class LInstruction: public ZoneObject { LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; - SetOncePointer<LEnvironment> deoptimization_environment_; bool is_call_; bool is_save_doubles_; }; @@ -305,9 +294,6 @@ class LTemplateInstruction: public LInstruction { int TempCount() { return T; } LOperand* TempAt(int i) { return temps_[i]; } - virtual void PrintDataTo(StringStream* stream); - virtual void PrintOutputOperandTo(StringStream* stream); - protected: EmbeddedContainer<LOperand*, R> results_; EmbeddedContainer<LOperand*, I> inputs_; @@ -533,9 +519,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { class LArgumentsElements: public LTemplateInstruction<1, 0, 0> { public: - LArgumentsElements() { } - DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements") + DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements) }; @@ -833,6 +818,15 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) Handle<JSFunction> function() const { return hydrogen()->function(); } + LEnvironment* GetDeferredLazyDeoptimizationEnvironment() { + return lazy_deopt_env_; + } + virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { + lazy_deopt_env_ = env; + } + + private: + LEnvironment* lazy_deopt_env_; }; @@ -1358,6 +1352,19 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { }; +class LDrop: public LTemplateInstruction<0, 0, 0> { + public: + explicit LDrop(int count) : count_(count) { } + + int count() const { return count_; } + + DECLARE_CONCRETE_INSTRUCTION(Drop, "drop") + + private: + int count_; +}; + + class LThisFunction: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function") @@ -1440,6 +1447,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> { virtual void PrintDataTo(StringStream* stream); int arity() const { return hydrogen()->argument_count() - 1; } + Handle<JSFunction> known_function() { return hydrogen()->known_function(); } }; @@ -1719,6 +1727,8 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } + + bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } }; @@ -1869,14 +1879,14 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> { }; -class LCheckMap: public LTemplateInstruction<0, 1, 0> { +class LCheckMaps: public LTemplateInstruction<0, 1, 0> { public: - explicit LCheckMap(LOperand* value) { + explicit LCheckMaps(LOperand* value) { inputs_[0] = value; } - DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map") - DECLARE_HYDROGEN_ACCESSOR(CheckMap) + DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps") + DECLARE_HYDROGEN_ACCESSOR(CheckMaps) }; @@ -2349,11 +2359,6 @@ class LChunkBuilder BASE_EMBEDDED { LInstruction* instr, HInstruction* hinstr, CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); - LInstruction* MarkAsSaveDoubles(LInstruction* instr); - - LInstruction* SetInstructionPendingDeoptimizationEnvironment( - LInstruction* instr, int ast_id); - void ClearInstructionPendingDeoptimizationEnvironment(); LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, int* argument_index_accumulator); diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc index e93a4175b3..2c2445b4c7 100644 --- a/deps/v8/src/mips/macro-assembler-mips.cc +++ b/deps/v8/src/mips/macro-assembler-mips.cc @@ -5378,7 +5378,7 @@ CodePatcher::CodePatcher(byte* address, int instructions) : address_(address), instructions_(instructions), size_(instructions * Assembler::kInstrSize), - masm_(Isolate::Current(), address, size_ + Assembler::kGap) { + masm_(NULL, address, size_ + Assembler::kGap) { // Create a new macro assembler pointing to the address of the code to patch. // The size is adjusted with kGap on order for the assembler to generate size // bytes of instructions without failing with buffer size constraints. diff --git a/deps/v8/src/mips/regexp-macro-assembler-mips.cc b/deps/v8/src/mips/regexp-macro-assembler-mips.cc index ae4da936ce..c48bcc497e 100644 --- a/deps/v8/src/mips/regexp-macro-assembler-mips.cc +++ b/deps/v8/src/mips/regexp-macro-assembler-mips.cc @@ -158,7 +158,7 @@ int RegExpMacroAssemblerMIPS::stack_limit_slack() { void RegExpMacroAssemblerMIPS::AdvanceCurrentPosition(int by) { if (by != 0) { __ Addu(current_input_offset(), - current_input_offset(), Operand(by * char_size())); + current_input_offset(), Operand(by * char_size())); } } @@ -229,9 +229,9 @@ void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) { void RegExpMacroAssemblerMIPS::CheckCharacters(Vector<const uc16> str, - int cp_offset, - Label* on_failure, - bool check_end_of_string) { + int cp_offset, + Label* on_failure, + bool check_end_of_string) { if (on_failure == NULL) { // Instead of inlining a backtrack for each test, (re)use the global // backtrack target. @@ -452,24 +452,26 @@ void RegExpMacroAssemblerMIPS::CheckNotRegistersEqual(int reg1, void RegExpMacroAssemblerMIPS::CheckNotCharacter(uint32_t c, - Label* on_not_equal) { + Label* on_not_equal) { BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c)); } void RegExpMacroAssemblerMIPS::CheckCharacterAfterAnd(uint32_t c, - uint32_t mask, - Label* on_equal) { + uint32_t mask, + Label* on_equal) { __ And(a0, current_character(), Operand(mask)); - BranchOrBacktrack(on_equal, eq, a0, Operand(c)); + Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c); + BranchOrBacktrack(on_equal, eq, a0, rhs); } void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterAnd(uint32_t c, - uint32_t mask, - Label* on_not_equal) { + uint32_t mask, + Label* on_not_equal) { __ And(a0, current_character(), Operand(mask)); - BranchOrBacktrack(on_not_equal, ne, a0, Operand(c)); + Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c); + BranchOrBacktrack(on_not_equal, ne, a0, rhs); } @@ -478,12 +480,51 @@ void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterMinusAnd( uc16 minus, uc16 mask, Label* on_not_equal) { - UNIMPLEMENTED_MIPS(); + ASSERT(minus < String::kMaxUtf16CodeUnit); + __ Subu(a0, current_character(), Operand(minus)); + __ And(a0, a0, Operand(mask)); + BranchOrBacktrack(on_not_equal, ne, a0, Operand(c)); +} + + +void RegExpMacroAssemblerMIPS::CheckCharacterInRange( + uc16 from, + uc16 to, + Label* on_in_range) { + __ Subu(a0, current_character(), Operand(from)); + // Unsigned lower-or-same condition. + BranchOrBacktrack(on_in_range, ls, a0, Operand(to - from)); +} + + +void RegExpMacroAssemblerMIPS::CheckCharacterNotInRange( + uc16 from, + uc16 to, + Label* on_not_in_range) { + __ Subu(a0, current_character(), Operand(from)); + // Unsigned higher condition. + BranchOrBacktrack(on_not_in_range, hi, a0, Operand(to - from)); +} + + +void RegExpMacroAssemblerMIPS::CheckBitInTable( + Handle<ByteArray> table, + Label* on_bit_set) { + __ li(a0, Operand(table)); + if (mode_ != ASCII || kTableMask != String::kMaxAsciiCharCode) { + __ And(a1, current_character(), Operand(kTableSize - 1)); + __ Addu(a0, a0, a1); + } else { + __ Addu(a0, a0, current_character()); + } + + __ lbu(a0, FieldMemOperand(a0, ByteArray::kHeaderSize)); + BranchOrBacktrack(on_bit_set, ne, a0, Operand(zero_reg)); } bool RegExpMacroAssemblerMIPS::CheckSpecialCharacterClass(uc16 type, - Label* on_no_match) { + Label* on_no_match) { // Range checks (c in min..max) are generally implemented by an unsigned // (c - min) <= (max - min) check. switch (type) { @@ -848,23 +889,23 @@ void RegExpMacroAssemblerMIPS::GoTo(Label* to) { void RegExpMacroAssemblerMIPS::IfRegisterGE(int reg, - int comparand, - Label* if_ge) { + int comparand, + Label* if_ge) { __ lw(a0, register_location(reg)); BranchOrBacktrack(if_ge, ge, a0, Operand(comparand)); } void RegExpMacroAssemblerMIPS::IfRegisterLT(int reg, - int comparand, - Label* if_lt) { + int comparand, + Label* if_lt) { __ lw(a0, register_location(reg)); BranchOrBacktrack(if_lt, lt, a0, Operand(comparand)); } void RegExpMacroAssemblerMIPS::IfRegisterEqPos(int reg, - Label* if_eq) { + Label* if_eq) { __ lw(a0, register_location(reg)); BranchOrBacktrack(if_eq, eq, a0, Operand(current_input_offset())); } @@ -877,9 +918,9 @@ RegExpMacroAssembler::IrregexpImplementation void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset, - Label* on_end_of_input, - bool check_bounds, - int characters) { + Label* on_end_of_input, + bool check_bounds, + int characters) { ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works). if (check_bounds) { @@ -930,7 +971,7 @@ void RegExpMacroAssemblerMIPS::PushCurrentPosition() { void RegExpMacroAssemblerMIPS::PushRegister(int register_index, - StackCheckFlag check_stack_limit) { + StackCheckFlag check_stack_limit) { __ lw(a0, register_location(register_index)); Push(a0); if (check_stack_limit) CheckStackLimit(); @@ -977,7 +1018,7 @@ void RegExpMacroAssemblerMIPS::Succeed() { void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg, - int cp_offset) { + int cp_offset) { if (cp_offset == 0) { __ sw(current_input_offset(), register_location(reg)); } else { @@ -1134,7 +1175,7 @@ MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) { void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset, - Label* on_outside_input) { + Label* on_outside_input) { BranchOrBacktrack(on_outside_input, ge, current_input_offset(), @@ -1162,8 +1203,10 @@ void RegExpMacroAssemblerMIPS::BranchOrBacktrack(Label* to, } -void RegExpMacroAssemblerMIPS::SafeCall(Label* to, Condition cond, Register rs, - const Operand& rt) { +void RegExpMacroAssemblerMIPS::SafeCall(Label* to, + Condition cond, + Register rs, + const Operand& rt) { __ BranchAndLink(to, cond, rs, rt); } @@ -1234,7 +1277,7 @@ void RegExpMacroAssemblerMIPS::CallCFunctionUsingStub( void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset, - int characters) { + int characters) { Register offset = current_input_offset(); if (cp_offset != 0) { __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size())); diff --git a/deps/v8/src/mips/regexp-macro-assembler-mips.h b/deps/v8/src/mips/regexp-macro-assembler-mips.h index d42d4cf67e..d167f624b6 100644 --- a/deps/v8/src/mips/regexp-macro-assembler-mips.h +++ b/deps/v8/src/mips/regexp-macro-assembler-mips.h @@ -81,6 +81,14 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler { uc16 minus, uc16 mask, Label* on_not_equal); + virtual void CheckCharacterInRange(uc16 from, + uc16 to, + Label* on_in_range); + virtual void CheckCharacterNotInRange(uc16 from, + uc16 to, + Label* on_not_in_range); + virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set); + // Checks whether the given offset from the current position is before // the end of the string. virtual void CheckPosition(int cp_offset, Label* on_outside_input); diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc index 294bc0a074..18a5f5f7e1 100644 --- a/deps/v8/src/mips/stub-cache-mips.cc +++ b/deps/v8/src/mips/stub-cache-mips.cc @@ -429,8 +429,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, // a0 : value. Label exit; // Check that the map of the object hasn't changed. + CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS + : REQUIRE_EXACT_MAP; __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label, - DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); + DO_SMI_CHECK, mode); // Perform global security token check if needed. if (object->IsJSGlobalProxy()) { @@ -563,6 +565,8 @@ static void PushInterceptorArguments(MacroAssembler* masm, __ Push(scratch, receiver, holder); __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset)); __ push(scratch); + __ li(scratch, Operand(ExternalReference::isolate_address())); + __ push(scratch); } @@ -577,7 +581,7 @@ static void CompileCallLoadPropertyWithInterceptor( ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), masm->isolate()); - __ PrepareCEntryArgs(5); + __ PrepareCEntryArgs(6); __ PrepareCEntryFunction(ref); CEntryStub stub(1); @@ -585,10 +589,10 @@ static void CompileCallLoadPropertyWithInterceptor( } -static const int kFastApiCallArguments = 3; +static const int kFastApiCallArguments = 4; -// Reserves space for the extra arguments to FastHandleApiCall in the +// Reserves space for the extra arguments to API function in the // caller's frame. // // These arguments are set by CheckPrototypes and GenerateFastApiDirectCall. @@ -614,7 +618,8 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, // -- sp[0] : holder (set by CheckPrototypes) // -- sp[4] : callee JS function // -- sp[8] : call data - // -- sp[12] : last JS argument + // -- sp[12] : isolate + // -- sp[16] : last JS argument // -- ... // -- sp[(argc + 3) * 4] : first JS argument // -- sp[(argc + 4) * 4] : receiver @@ -624,7 +629,7 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, __ LoadHeapObject(t1, function); __ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset)); - // Pass the additional arguments FastHandleApiCall expects. + // Pass the additional arguments. Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); Handle<Object> call_data(api_call_info->data()); if (masm->isolate()->heap()->InNewSpace(*call_data)) { @@ -634,14 +639,17 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, __ li(t2, call_data); } - // Store JS function and call data. + __ li(t3, Operand(ExternalReference::isolate_address())); + // Store JS function, call data and isolate. __ sw(t1, MemOperand(sp, 1 * kPointerSize)); __ sw(t2, MemOperand(sp, 2 * kPointerSize)); + __ sw(t3, MemOperand(sp, 3 * kPointerSize)); - // a2 points to call data as expected by Arguments - // (refer to layout above). - __ Addu(a2, sp, Operand(2 * kPointerSize)); + // Prepare arguments. + __ Addu(a2, sp, Operand(3 * kPointerSize)); + // Allocate the v8::Arguments structure in the arguments' space since + // it's not controlled by GC. const int kApiStackSpace = 4; FrameScope frame_scope(masm, StackFrame::MANUAL); @@ -656,9 +664,9 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, // Arguments is built at sp + 1 (sp is a reserved spot for ra). __ Addu(a1, sp, kPointerSize); - // v8::Arguments::implicit_args = data + // v8::Arguments::implicit_args_ __ sw(a2, MemOperand(a1, 0 * kPointerSize)); - // v8::Arguments::values = last argument + // v8::Arguments::values_ __ Addu(t0, a2, Operand(argc * kPointerSize)); __ sw(t0, MemOperand(a1, 1 * kPointerSize)); // v8::Arguments::length_ = argc @@ -836,7 +844,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { ExternalReference( IC_Utility(IC::kLoadPropertyWithInterceptorForCall), masm->isolate()), - 5); + 6); // Restore the name_ register. __ pop(name_); // Leave the internal frame. @@ -1168,9 +1176,8 @@ void StubCompiler::GenerateLoadConstant(Handle<JSObject> object, __ JumpIfSmi(receiver, miss, scratch1); // Check that the maps haven't changed. - Register reg = - CheckPrototypes(object, receiver, holder, - scratch1, scratch2, scratch3, name, miss); + CheckPrototypes(object, receiver, holder, + scratch1, scratch2, scratch3, name, miss); // Return the constant value. __ LoadHeapObject(v0, value); @@ -1205,7 +1212,13 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, } else { __ li(scratch3, Handle<Object>(callback->data())); } - __ Push(reg, scratch3, name_reg); + __ Subu(sp, sp, 4 * kPointerSize); + __ sw(reg, MemOperand(sp, 3 * kPointerSize)); + __ sw(scratch3, MemOperand(sp, 2 * kPointerSize)); + __ li(scratch3, Operand(ExternalReference::isolate_address())); + __ sw(scratch3, MemOperand(sp, 1 * kPointerSize)); + __ sw(name_reg, MemOperand(sp, 0 * kPointerSize)); + __ mov(a2, scratch2); // Saved in case scratch2 == a1. __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String> @@ -1224,7 +1237,7 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, // a2 (second argument - see note above) = AccessorInfo& __ Addu(a2, sp, kPointerSize); - const int kStackUnwindSpace = 4; + const int kStackUnwindSpace = 5; Address getter_address = v8::ToCData<Address>(callback->getter()); ApiFunction fun(getter_address); ExternalReference ref = @@ -1274,12 +1287,19 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, name, miss); ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); + // Preserve the receiver register explicitly whenever it is different from + // the holder and it is needed should the interceptor return without any + // result. The CALLBACKS case needs the receiver to be passed into C++ code, + // the FIELD case might cause a miss during the prototype check. + bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); + bool must_preserve_receiver_reg = !receiver.is(holder_reg) && + (lookup->type() == CALLBACKS || must_perfrom_prototype_check); + // Save necessary data before invoking an interceptor. // Requires a frame to make GC aware of pushed pointers. { FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { - // CALLBACKS case needs a receiver to be passed into C++ callback. + if (must_preserve_receiver_reg) { __ Push(receiver, holder_reg, name_reg); } else { __ Push(holder_reg, name_reg); @@ -1303,14 +1323,14 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, __ bind(&interceptor_failed); __ pop(name_reg); __ pop(holder_reg); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { + if (must_preserve_receiver_reg) { __ pop(receiver); } // Leave the internal frame. } // Check that the maps from interceptor's holder to lookup's holder // haven't changed. And load lookup's holder into |holder| register. - if (*interceptor_holder != lookup->holder()) { + if (must_perfrom_prototype_check) { holder_reg = CheckPrototypes(interceptor_holder, holder_reg, Handle<JSObject>(lookup->holder()), @@ -1340,24 +1360,17 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, // Important invariant in CALLBACKS case: the code above must be // structured to never clobber |receiver| register. __ li(scratch2, callback); - // holder_reg is either receiver or scratch1. - if (!receiver.is(holder_reg)) { - ASSERT(scratch1.is(holder_reg)); - __ Push(receiver, holder_reg); - __ lw(scratch3, - FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); - __ Push(scratch3, scratch2, name_reg); - } else { - __ push(receiver); - __ lw(scratch3, - FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); - __ Push(holder_reg, scratch3, scratch2, name_reg); - } + + __ Push(receiver, holder_reg); + __ lw(scratch3, + FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); + __ li(scratch1, Operand(ExternalReference::isolate_address())); + __ Push(scratch3, scratch1, scratch2, name_reg); ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadCallbackProperty), masm()->isolate()); - __ TailCallExternalReference(ref, 5, 1); + __ TailCallExternalReference(ref, 6, 1); } } else { // !compile_followup_inline // Call the runtime system to load the interceptor. @@ -1370,7 +1383,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, ExternalReference ref = ExternalReference( IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate()); - __ TailCallExternalReference(ref, 5, 1); + __ TailCallExternalReference(ref, 6, 1); } } @@ -1737,14 +1750,14 @@ Handle<Code> CallStubCompiler::CompileArrayPopCall( // expensive shift first, and use an offset later on. __ sll(t1, t0, kPointerSizeLog2 - kSmiTagSize); __ Addu(elements, elements, t1); - __ lw(v0, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag)); + __ lw(v0, FieldMemOperand(elements, FixedArray::kHeaderSize)); __ Branch(&call_builtin, eq, v0, Operand(t2)); // Set the array's length. __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); // Fill with the hole. - __ sw(t2, MemOperand(elements, FixedArray::kHeaderSize - kHeapObjectTag)); + __ sw(t2, FieldMemOperand(elements, FixedArray::kHeaderSize)); __ Drop(argc + 1); __ Ret(); @@ -3371,6 +3384,45 @@ static bool IsElementTypeSigned(ElementsKind elements_kind) { } +static void GenerateSmiKeyCheck(MacroAssembler* masm, + Register key, + Register scratch0, + Register scratch1, + FPURegister double_scratch0, + Label* fail) { + if (CpuFeatures::IsSupported(FPU)) { + CpuFeatures::Scope scope(FPU); + Label key_ok; + // Check for smi or a smi inside a heap number. We convert the heap + // number and check if the conversion is exact and fits into the smi + // range. + __ JumpIfSmi(key, &key_ok); + __ CheckMap(key, + scratch0, + Heap::kHeapNumberMapRootIndex, + fail, + DONT_DO_SMI_CHECK); + __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset)); + __ EmitFPUTruncate(kRoundToZero, + double_scratch0, + double_scratch0, + scratch0, + scratch1, + kCheckForInexactConversion); + + __ Branch(fail, ne, scratch1, Operand(zero_reg)); + + __ mfc1(scratch0, double_scratch0); + __ SmiTagCheckOverflow(key, scratch0, scratch1); + __ BranchOnOverflow(fail, scratch1); + __ bind(&key_ok); + } else { + // Check that the key is a smi. + __ JumpIfNotSmi(key, fail); + } +} + + void KeyedLoadStubCompiler::GenerateLoadExternalArray( MacroAssembler* masm, ElementsKind elements_kind) { @@ -3387,8 +3439,8 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(key, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic); __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset)); // a3: elements array @@ -3496,7 +3548,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( CpuFeatures::Scope scope(FPU); __ mtc1(value, f0); __ cvt_d_w(f0, f0); - __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag)); + __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); __ Ret(); } else { Register dst1 = t2; @@ -3544,7 +3596,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ Cvt_d_uw(f0, value, f22); - __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag)); + __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); __ Ret(); } else { @@ -3598,7 +3650,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ AllocateHeapNumber(v0, t3, t5, t6, &slow); // The float (single) value is already in fpu reg f0 (if we use float). __ cvt_d_s(f0, f0); - __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag)); + __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); __ Ret(); } else { // Allocate a HeapNumber for the result. Don't use a0 and a1 as @@ -3726,8 +3778,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(key, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic); __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset)); @@ -4106,9 +4158,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(a0, &miss_force_generic, at, USE_DELAY_SLOT); - // The delay slot can be safely used here, a1 is an object pointer. + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic); // Get the elements array. __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset)); @@ -4158,8 +4209,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(key_reg, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic); // Get the elements array. __ lw(elements_reg, @@ -4228,13 +4279,12 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( Register elements_reg = a3; Register length_reg = t1; Register scratch2 = t2; - Register scratch3 = t3; // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(key_reg, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic); if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { __ JumpIfNotSmi(value_reg, &transition_elements_kind); @@ -4400,7 +4450,9 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - __ JumpIfNotSmi(key_reg, &miss_force_generic); + + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic); __ lw(elements_reg, FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); @@ -4492,6 +4544,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // Increment the length of the array. __ li(length_reg, Operand(Smi::FromInt(1))); __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); + __ lw(elements_reg, + FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); __ jmp(&finish_store); __ bind(&check_capacity); diff --git a/deps/v8/src/mirror-debugger.js b/deps/v8/src/mirror-debugger.js index c43dd228ec..c7f0dccb7b 100644 --- a/deps/v8/src/mirror-debugger.js +++ b/deps/v8/src/mirror-debugger.js @@ -596,6 +596,23 @@ ObjectMirror.prototype.protoObject = function() { }; +/** + * Return the primitive value if this is object of Boolean, Number or String + * type (but not Date). Otherwise return undefined. + */ +ObjectMirror.prototype.primitiveValue = function() { + if (!IS_STRING_WRAPPER(this.value_) && !IS_NUMBER_WRAPPER(this.value_) && + !IS_BOOLEAN_WRAPPER(this.value_)) { + return void 0; + } + var primitiveValue = %_ValueOf(this.value_); + if (IS_UNDEFINED(primitiveValue)) { + return void 0; + } + return MakeMirror(primitiveValue); +}; + + ObjectMirror.prototype.hasNamedInterceptor = function() { // Get information on interceptors for this object. var x = %GetInterceptorInfo(this.value_); @@ -896,6 +913,22 @@ FunctionMirror.prototype.constructedBy = function(opt_max_instances) { }; +FunctionMirror.prototype.scopeCount = function() { + if (this.resolved()) { + return %GetFunctionScopeCount(this.value()); + } else { + return 0; + } +}; + + +FunctionMirror.prototype.scope = function(index) { + if (this.resolved()) { + return new ScopeMirror(void 0, this, index); + } +}; + + FunctionMirror.prototype.toText = function() { return this.source(); }; @@ -1572,7 +1605,7 @@ FrameMirror.prototype.scopeCount = function() { FrameMirror.prototype.scope = function(index) { - return new ScopeMirror(this, index); + return new ScopeMirror(this, void 0, index); }; @@ -1735,39 +1768,54 @@ FrameMirror.prototype.toText = function(opt_locals) { var kScopeDetailsTypeIndex = 0; var kScopeDetailsObjectIndex = 1; -function ScopeDetails(frame, index) { - this.break_id_ = frame.break_id_; - this.details_ = %GetScopeDetails(frame.break_id_, - frame.details_.frameId(), - frame.details_.inlinedFrameIndex(), - index); +function ScopeDetails(frame, fun, index) { + if (frame) { + this.break_id_ = frame.break_id_; + this.details_ = %GetScopeDetails(frame.break_id_, + frame.details_.frameId(), + frame.details_.inlinedFrameIndex(), + index); + } else { + this.details_ = %GetFunctionScopeDetails(fun.value(), index); + this.break_id_ = undefined; + } } ScopeDetails.prototype.type = function() { - %CheckExecutionState(this.break_id_); + if (!IS_UNDEFINED(this.break_id_)) { + %CheckExecutionState(this.break_id_); + } return this.details_[kScopeDetailsTypeIndex]; }; ScopeDetails.prototype.object = function() { - %CheckExecutionState(this.break_id_); + if (!IS_UNDEFINED(this.break_id_)) { + %CheckExecutionState(this.break_id_); + } return this.details_[kScopeDetailsObjectIndex]; }; /** - * Mirror object for scope. + * Mirror object for scope of frame or function. Either frame or function must + * be specified. * @param {FrameMirror} frame The frame this scope is a part of + * @param {FunctionMirror} function The function this scope is a part of * @param {number} index The scope index in the frame * @constructor * @extends Mirror */ -function ScopeMirror(frame, index) { +function ScopeMirror(frame, function, index) { %_CallFunction(this, SCOPE_TYPE, Mirror); - this.frame_index_ = frame.index_; + if (frame) { + this.frame_index_ = frame.index_; + } else { + this.frame_index_ = undefined; + } this.scope_index_ = index; - this.details_ = new ScopeDetails(frame, index); + this.details_ = new ScopeDetails(frame, function, index); } inherits(ScopeMirror, Mirror); @@ -2234,6 +2282,11 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content, content.protoObject = this.serializeReference(mirror.protoObject()); content.prototypeObject = this.serializeReference(mirror.prototypeObject()); + var primitiveValue = mirror.primitiveValue(); + if (!IS_UNDEFINED(primitiveValue)) { + content.primitiveValue = this.serializeReference(primitiveValue); + } + // Add flags to indicate whether there are interceptors. if (mirror.hasNamedInterceptor()) { content.namedInterceptor = true; @@ -2259,6 +2312,15 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content, serializeLocationFields(mirror.sourceLocation(), content); } + + content.scopes = []; + for (var i = 0; i < mirror.scopeCount(); i++) { + var scope = mirror.scope(i); + content.scopes.push({ + type: scope.scopeType(), + index: i + }); + } } // Add date specific properties. diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index 8eefb23db2..3bfb74d6a4 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -135,6 +135,9 @@ void HeapObject::HeapObjectVerify() { case JS_CONTEXT_EXTENSION_OBJECT_TYPE: JSObject::cast(this)->JSObjectVerify(); break; + case JS_MODULE_TYPE: + JSModule::cast(this)->JSModuleVerify(); + break; case JS_VALUE_TYPE: JSValue::cast(this)->JSValueVerify(); break; @@ -300,6 +303,8 @@ void Map::MapVerify() { instance_size() < HEAP->Capacity())); VerifyHeapPointer(prototype()); VerifyHeapPointer(instance_descriptors()); + SLOW_ASSERT(instance_descriptors()->IsSortedNoDuplicates()); + SLOW_ASSERT(instance_descriptors()->IsConsistentWithBackPointers(this)); } @@ -366,6 +371,15 @@ void FixedDoubleArray::FixedDoubleArrayVerify() { } +void JSModule::JSModuleVerify() { + Object* v = context(); + if (v->IsHeapObject()) { + VerifyHeapPointer(v); + } + CHECK(v->IsUndefined() || v->IsModuleContext()); +} + + void JSValue::JSValueVerify() { Object* v = value(); if (v->IsHeapObject()) { @@ -882,6 +896,61 @@ bool DescriptorArray::IsSortedNoDuplicates() { } +static bool CheckOneBackPointer(Map* current_map, Object* target) { + return !target->IsMap() || Map::cast(target)->GetBackPointer() == current_map; +} + + +bool DescriptorArray::IsConsistentWithBackPointers(Map* current_map) { + for (int i = 0; i < number_of_descriptors(); ++i) { + switch (GetType(i)) { + case MAP_TRANSITION: + case CONSTANT_TRANSITION: + if (!CheckOneBackPointer(current_map, GetValue(i))) { + return false; + } + break; + case ELEMENTS_TRANSITION: { + Object* object = GetValue(i); + if (!CheckOneBackPointer(current_map, object)) { + return false; + } + if (object->IsFixedArray()) { + FixedArray* array = FixedArray::cast(object); + for (int i = 0; i < array->length(); ++i) { + if (!CheckOneBackPointer(current_map, array->get(i))) { + return false; + } + } + } + break; + } + case CALLBACKS: { + Object* object = GetValue(i); + if (object->IsAccessorPair()) { + AccessorPair* accessors = AccessorPair::cast(object); + if (!CheckOneBackPointer(current_map, accessors->getter())) { + return false; + } + if (!CheckOneBackPointer(current_map, accessors->setter())) { + return false; + } + } + break; + } + case NORMAL: + case FIELD: + case CONSTANT_FUNCTION: + case HANDLER: + case INTERCEPTOR: + case NULL_DESCRIPTOR: + break; + } + } + return true; +} + + void JSFunctionResultCache::JSFunctionResultCacheVerify() { JSFunction::cast(get(kFactoryIndex))->Verify(); diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 78578cc884..eb1586ad0c 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -581,7 +581,8 @@ bool Object::IsContext() { map == heap->catch_context_map() || map == heap->with_context_map() || map == heap->global_context_map() || - map == heap->block_context_map()); + map == heap->block_context_map() || + map == heap->module_context_map()); } return false; } @@ -594,6 +595,13 @@ bool Object::IsGlobalContext() { } +bool Object::IsModuleContext() { + return Object::IsHeapObject() && + HeapObject::cast(this)->map() == + HeapObject::cast(this)->GetHeap()->module_context_map(); +} + + bool Object::IsScopeInfo() { return Object::IsHeapObject() && HeapObject::cast(this)->map() == @@ -613,6 +621,7 @@ TYPE_CHECKER(Code, CODE_TYPE) TYPE_CHECKER(Oddball, ODDBALL_TYPE) TYPE_CHECKER(JSGlobalPropertyCell, JS_GLOBAL_PROPERTY_CELL_TYPE) TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE) +TYPE_CHECKER(JSModule, JS_MODULE_TYPE) TYPE_CHECKER(JSValue, JS_VALUE_TYPE) TYPE_CHECKER(JSDate, JS_DATE_TYPE) TYPE_CHECKER(JSMessageObject, JS_MESSAGE_OBJECT_TYPE) @@ -1383,7 +1392,9 @@ void JSObject::initialize_properties() { void JSObject::initialize_elements() { - ASSERT(map()->has_fast_elements() || map()->has_fast_smi_only_elements()); + ASSERT(map()->has_fast_elements() || + map()->has_fast_smi_only_elements() || + map()->has_fast_double_elements()); ASSERT(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array())); WRITE_FIELD(this, kElementsOffset, GetHeap()->empty_fixed_array()); } @@ -1436,6 +1447,8 @@ int JSObject::GetHeaderSize() { // field operations considerably on average. if (type == JS_OBJECT_TYPE) return JSObject::kHeaderSize; switch (type) { + case JS_MODULE_TYPE: + return JSModule::kSize; case JS_GLOBAL_PROXY_TYPE: return JSGlobalProxy::kSize; case JS_GLOBAL_OBJECT_TYPE: @@ -1922,15 +1935,15 @@ Object* DescriptorArray::GetValue(int descriptor_number) { } -Smi* DescriptorArray::GetDetails(int descriptor_number) { +PropertyDetails DescriptorArray::GetDetails(int descriptor_number) { ASSERT(descriptor_number < number_of_descriptors()); - return Smi::cast(GetContentArray()->get(ToDetailsIndex(descriptor_number))); + Object* details = GetContentArray()->get(ToDetailsIndex(descriptor_number)); + return PropertyDetails(Smi::cast(details)); } PropertyType DescriptorArray::GetType(int descriptor_number) { - ASSERT(descriptor_number < number_of_descriptors()); - return PropertyDetails(GetDetails(descriptor_number)).type(); + return GetDetails(descriptor_number).type(); } @@ -1993,15 +2006,10 @@ bool DescriptorArray::IsNullDescriptor(int descriptor_number) { } -bool DescriptorArray::IsDontEnum(int descriptor_number) { - return PropertyDetails(GetDetails(descriptor_number)).IsDontEnum(); -} - - void DescriptorArray::Get(int descriptor_number, Descriptor* desc) { desc->Init(GetKey(descriptor_number), GetValue(descriptor_number), - PropertyDetails(GetDetails(descriptor_number))); + GetDetails(descriptor_number)); } @@ -3004,26 +3012,26 @@ void Code::set_is_pregenerated(bool value) { bool Code::optimizable() { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); return READ_BYTE_FIELD(this, kOptimizableOffset) == 1; } void Code::set_optimizable(bool value) { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); WRITE_BYTE_FIELD(this, kOptimizableOffset, value ? 1 : 0); } bool Code::has_deoptimization_support() { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); return FullCodeFlagsHasDeoptimizationSupportField::decode(flags); } void Code::set_has_deoptimization_support(bool value) { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); flags = FullCodeFlagsHasDeoptimizationSupportField::update(flags, value); WRITE_BYTE_FIELD(this, kFullCodeFlags, flags); @@ -3031,14 +3039,14 @@ void Code::set_has_deoptimization_support(bool value) { bool Code::has_debug_break_slots() { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); return FullCodeFlagsHasDebugBreakSlotsField::decode(flags); } void Code::set_has_debug_break_slots(bool value) { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); flags = FullCodeFlagsHasDebugBreakSlotsField::update(flags, value); WRITE_BYTE_FIELD(this, kFullCodeFlags, flags); @@ -3046,45 +3054,43 @@ void Code::set_has_debug_break_slots(bool value) { bool Code::is_compiled_optimizable() { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); return FullCodeFlagsIsCompiledOptimizable::decode(flags); } void Code::set_compiled_optimizable(bool value) { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); flags = FullCodeFlagsIsCompiledOptimizable::update(flags, value); WRITE_BYTE_FIELD(this, kFullCodeFlags, flags); } -bool Code::has_self_optimization_header() { - ASSERT(kind() == FUNCTION); - byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); - return FullCodeFlagsHasSelfOptimizationHeader::decode(flags); +int Code::allow_osr_at_loop_nesting_level() { + ASSERT_EQ(FUNCTION, kind()); + return READ_BYTE_FIELD(this, kAllowOSRAtLoopNestingLevelOffset); } -void Code::set_self_optimization_header(bool value) { - ASSERT(kind() == FUNCTION); - byte flags = READ_BYTE_FIELD(this, kFullCodeFlags); - flags = FullCodeFlagsHasSelfOptimizationHeader::update(flags, value); - WRITE_BYTE_FIELD(this, kFullCodeFlags, flags); +void Code::set_allow_osr_at_loop_nesting_level(int level) { + ASSERT_EQ(FUNCTION, kind()); + ASSERT(level >= 0 && level <= kMaxLoopNestingMarker); + WRITE_BYTE_FIELD(this, kAllowOSRAtLoopNestingLevelOffset, level); } -int Code::allow_osr_at_loop_nesting_level() { - ASSERT(kind() == FUNCTION); - return READ_BYTE_FIELD(this, kAllowOSRAtLoopNestingLevelOffset); +int Code::profiler_ticks() { + ASSERT_EQ(FUNCTION, kind()); + return READ_BYTE_FIELD(this, kProfilerTicksOffset); } -void Code::set_allow_osr_at_loop_nesting_level(int level) { - ASSERT(kind() == FUNCTION); - ASSERT(level >= 0 && level <= kMaxLoopNestingMarker); - WRITE_BYTE_FIELD(this, kAllowOSRAtLoopNestingLevelOffset, level); +void Code::set_profiler_ticks(int ticks) { + ASSERT_EQ(FUNCTION, kind()); + ASSERT(ticks < 256); + WRITE_BYTE_FIELD(this, kProfilerTicksOffset, ticks); } @@ -3114,13 +3120,13 @@ void Code::set_safepoint_table_offset(unsigned offset) { unsigned Code::stack_check_table_offset() { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); return READ_UINT32_FIELD(this, kStackCheckTableOffsetOffset); } void Code::set_stack_check_table_offset(unsigned offset) { - ASSERT(kind() == FUNCTION); + ASSERT_EQ(FUNCTION, kind()); ASSERT(IsAligned(offset, static_cast<unsigned>(kIntSize))); WRITE_UINT32_FIELD(this, kStackCheckTableOffsetOffset, offset); } @@ -3187,6 +3193,18 @@ void Code::set_compare_state(byte value) { } +byte Code::compare_operation() { + ASSERT(is_compare_ic_stub()); + return READ_BYTE_FIELD(this, kCompareOperationOffset); +} + + +void Code::set_compare_operation(byte value) { + ASSERT(is_compare_ic_stub()); + WRITE_BYTE_FIELD(this, kCompareOperationOffset, value); +} + + byte Code::to_boolean_state() { ASSERT(is_to_boolean_ic_stub()); return READ_BYTE_FIELD(this, kToBooleanTypeOffset); @@ -3389,14 +3407,66 @@ void Map::set_bit_field3(int value) { } -FixedArray* Map::unchecked_prototype_transitions() { - return reinterpret_cast<FixedArray*>( - READ_FIELD(this, kPrototypeTransitionsOffset)); +Object* Map::GetBackPointer() { + Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset); + if (object->IsFixedArray()) { + return FixedArray::cast(object)->get(kProtoTransitionBackPointerOffset); + } else { + return object; + } +} + + +void Map::SetBackPointer(Object* value, WriteBarrierMode mode) { + Heap* heap = GetHeap(); + ASSERT(instance_type() >= FIRST_JS_RECEIVER_TYPE); + ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) || + (value->IsMap() && GetBackPointer()->IsUndefined())); + Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset); + if (object->IsFixedArray()) { + FixedArray::cast(object)->set( + kProtoTransitionBackPointerOffset, value, mode); + } else { + WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, value); + CONDITIONAL_WRITE_BARRIER( + heap, this, kPrototypeTransitionsOrBackPointerOffset, value, mode); + } +} + + +FixedArray* Map::prototype_transitions() { + Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset); + if (object->IsFixedArray()) { + return FixedArray::cast(object); + } else { + return GetHeap()->empty_fixed_array(); + } +} + + +void Map::set_prototype_transitions(FixedArray* value, WriteBarrierMode mode) { + Heap* heap = GetHeap(); + ASSERT(value != heap->empty_fixed_array()); + value->set(kProtoTransitionBackPointerOffset, GetBackPointer()); + WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, value); + CONDITIONAL_WRITE_BARRIER( + heap, this, kPrototypeTransitionsOrBackPointerOffset, value, mode); +} + + +void Map::init_prototype_transitions(Object* undefined) { + ASSERT(undefined->IsUndefined()); + WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, undefined); +} + + +HeapObject* Map::unchecked_prototype_transitions() { + Object* object = READ_FIELD(this, kPrototypeTransitionsOrBackPointerOffset); + return reinterpret_cast<HeapObject*>(object); } ACCESSORS(Map, code_cache, Object, kCodeCacheOffset) -ACCESSORS(Map, prototype_transitions, FixedArray, kPrototypeTransitionsOffset) ACCESSORS(Map, constructor, Object, kConstructorOffset) ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset) @@ -3507,8 +3577,8 @@ ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset) ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset) ACCESSORS(SharedFunctionInfo, this_property_assignments, Object, kThisPropertyAssignmentsOffset) +SMI_ACCESSORS(SharedFunctionInfo, ic_age, kICAgeOffset) -SMI_ACCESSORS(SharedFunctionInfo, profiler_ticks, kProfilerTicksOffset) BOOL_ACCESSORS(FunctionTemplateInfo, flag, hidden_prototype, kHiddenPrototypeBit) @@ -3654,6 +3724,12 @@ void SharedFunctionInfo::set_optimization_disabled(bool disable) { } +int SharedFunctionInfo::profiler_ticks() { + if (code()->kind() != Code::FUNCTION) return 0; + return code()->profiler_ticks(); +} + + LanguageMode SharedFunctionInfo::language_mode() { int hints = compiler_hints(); if (BooleanBit::get(hints, kExtendedModeFunction)) { @@ -4080,6 +4156,16 @@ void Foreign::set_foreign_address(Address value) { } +ACCESSORS(JSModule, context, Object, kContextOffset) + + +JSModule* JSModule::cast(Object* obj) { + ASSERT(obj->IsJSModule()); + ASSERT(HeapObject::cast(obj)->Size() == JSModule::kSize); + return reinterpret_cast<JSModule*>(obj); +} + + ACCESSORS(JSValue, value, Object, kValueOffset) @@ -4814,7 +4900,7 @@ Object* TypeFeedbackCells::RawUninitializedSentinel(Heap* heap) { SMI_ACCESSORS(TypeFeedbackInfo, ic_total_count, kIcTotalCountOffset) -SMI_ACCESSORS(TypeFeedbackInfo, ic_with_typeinfo_count, +SMI_ACCESSORS(TypeFeedbackInfo, ic_with_type_info_count, kIcWithTypeinfoCountOffset) ACCESSORS(TypeFeedbackInfo, type_feedback_cells, TypeFeedbackCells, kTypeFeedbackCellsOffset) diff --git a/deps/v8/src/objects-printer.cc b/deps/v8/src/objects-printer.cc index 38e61386b2..febdaabb12 100644 --- a/deps/v8/src/objects-printer.cc +++ b/deps/v8/src/objects-printer.cc @@ -135,6 +135,9 @@ void HeapObject::HeapObjectPrint(FILE* out) { case ODDBALL_TYPE: Oddball::cast(this)->to_string()->Print(out); break; + case JS_MODULE_TYPE: + JSModule::cast(this)->JSModulePrint(out); + break; case JS_FUNCTION_TYPE: JSFunction::cast(this)->JSFunctionPrint(out); break; @@ -152,7 +155,7 @@ void HeapObject::HeapObjectPrint(FILE* out) { JSValue::cast(this)->value()->Print(out); break; case JS_DATE_TYPE: - JSDate::cast(this)->value()->Print(out); + JSDate::cast(this)->JSDatePrint(out); break; case CODE_TYPE: Code::cast(this)->CodePrint(out); @@ -328,14 +331,16 @@ void JSObject::PrintElements(FILE* out) { } case FAST_DOUBLE_ELEMENTS: { // Print in array notation for non-sparse arrays. - FixedDoubleArray* p = FixedDoubleArray::cast(elements()); - for (int i = 0; i < p->length(); i++) { - if (p->is_the_hole(i)) { - PrintF(out, " %d: <the hole>", i); - } else { - PrintF(out, " %d: %g", i, p->get_scalar(i)); + if (elements()->length() > 0) { + FixedDoubleArray* p = FixedDoubleArray::cast(elements()); + for (int i = 0; i < p->length(); i++) { + if (p->is_the_hole(i)) { + PrintF(out, " %d: <the hole>", i); + } else { + PrintF(out, " %d: %g", i, p->get_scalar(i)); + } + PrintF(out, "\n"); } - PrintF(out, "\n"); } break; } @@ -437,6 +442,19 @@ void JSObject::JSObjectPrint(FILE* out) { } +void JSModule::JSModulePrint(FILE* out) { + HeapObject::PrintHeader(out, "JSModule"); + PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map())); + PrintF(out, " - context = "); + context()->Print(out); + PrintElementsKind(out, this->map()->elements_kind()); + PrintF(out, " {\n"); + PrintProperties(out); + PrintElements(out); + PrintF(out, " }\n"); +} + + static const char* TypeToString(InstanceType type) { switch (type) { case INVALID_TYPE: return "INVALID"; @@ -483,6 +501,7 @@ static const char* TypeToString(InstanceType type) { case ODDBALL_TYPE: return "ODDBALL"; case JS_GLOBAL_PROPERTY_CELL_TYPE: return "JS_GLOBAL_PROPERTY_CELL"; case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO"; + case JS_MODULE_TYPE: return "JS_MODULE"; case JS_FUNCTION_TYPE: return "JS_FUNCTION"; case CODE_TYPE: return "CODE"; case JS_ARRAY_TYPE: return "JS_ARRAY"; @@ -559,8 +578,8 @@ void PolymorphicCodeCache::PolymorphicCodeCachePrint(FILE* out) { void TypeFeedbackInfo::TypeFeedbackInfoPrint(FILE* out) { HeapObject::PrintHeader(out, "TypeFeedbackInfo"); - PrintF(out, "\n - ic_total_count: %d, ic_with_typeinfo_count: %d", - ic_total_count(), ic_with_typeinfo_count()); + PrintF(out, "\n - ic_total_count: %d, ic_with_type_info_count: %d", + ic_total_count(), ic_with_type_info_count()); PrintF(out, "\n - type_feedback_cells: "); type_feedback_cells()->FixedArrayPrint(out); } diff --git a/deps/v8/src/objects-visiting-inl.h b/deps/v8/src/objects-visiting-inl.h index 627d1bc2ef..8ba92f70c9 100644 --- a/deps/v8/src/objects-visiting-inl.h +++ b/deps/v8/src/objects-visiting-inl.h @@ -72,9 +72,7 @@ void StaticNewSpaceVisitor<StaticVisitor>::Initialize() { table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString); - table_.Register(kVisitJSFunction, - &JSObjectVisitor:: - template VisitSpecialized<JSFunction::kSize>); + table_.Register(kVisitJSFunction, &VisitJSFunction); table_.Register(kVisitFreeSpace, &VisitFreeSpace); diff --git a/deps/v8/src/objects-visiting.cc b/deps/v8/src/objects-visiting.cc index c7c8a87895..a2dc43e247 100644 --- a/deps/v8/src/objects-visiting.cc +++ b/deps/v8/src/objects-visiting.cc @@ -133,6 +133,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( case JS_OBJECT_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE: + case JS_MODULE_TYPE: case JS_VALUE_TYPE: case JS_DATE_TYPE: case JS_ARRAY_TYPE: diff --git a/deps/v8/src/objects-visiting.h b/deps/v8/src/objects-visiting.h index 26e79ae5ed..b476dfef2e 100644 --- a/deps/v8/src/objects-visiting.h +++ b/deps/v8/src/objects-visiting.h @@ -289,6 +289,23 @@ class StaticNewSpaceVisitor : public StaticVisitorBase { } private: + static inline int VisitJSFunction(Map* map, HeapObject* object) { + Heap* heap = map->GetHeap(); + VisitPointers(heap, + HeapObject::RawField(object, JSFunction::kPropertiesOffset), + HeapObject::RawField(object, JSFunction::kCodeEntryOffset)); + + // Don't visit code entry. We are using this visitor only during scavenges. + + VisitPointers( + heap, + HeapObject::RawField(object, + JSFunction::kCodeEntryOffset + kPointerSize), + HeapObject::RawField(object, + JSFunction::kNonWeakFieldsEndOffset)); + return JSFunction::kSize; + } + static inline int VisitByteArray(Map* map, HeapObject* object) { return reinterpret_cast<ByteArray*>(object)->ByteArraySize(); } diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 64d85a0685..7f75611bb4 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -1338,6 +1338,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size, break; case JS_OBJECT_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE: + case JS_MODULE_TYPE: case JS_VALUE_TYPE: case JS_DATE_TYPE: case JS_ARRAY_TYPE: @@ -1390,9 +1391,11 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case EXTERNAL_FLOAT_ARRAY_TYPE: case EXTERNAL_DOUBLE_ARRAY_TYPE: break; - case SHARED_FUNCTION_INFO_TYPE: - SharedFunctionInfo::BodyDescriptor::IterateBody(this, v); + case SHARED_FUNCTION_INFO_TYPE: { + SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this); + shared->SharedFunctionInfoIterateBody(v); break; + } #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: @@ -1601,6 +1604,7 @@ MaybeObject* JSObject::AddFastProperty(String* name, // We have now allocated all the necessary objects. // All the changes can be applied at once, so they are atomic. map()->set_instance_descriptors(old_descriptors); + new_map->SetBackPointer(map()); new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); set_map(new_map); return FastPropertyAtPut(index, value); @@ -1661,6 +1665,7 @@ MaybeObject* JSObject::AddConstantFunctionProperty( } } old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); + Map::cast(new_map)->SetBackPointer(old_map); return function; } @@ -1821,6 +1826,7 @@ MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition( } } old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); + map()->SetBackPointer(old_map); return result; } @@ -2319,7 +2325,7 @@ Object* Map::GetDescriptorContents(String* sentinel_name, } // If the transition already exists, return its descriptor. if (index != DescriptorArray::kNotFound) { - PropertyDetails details(descriptors->GetDetails(index)); + PropertyDetails details = descriptors->GetDetails(index); if (details.type() == ELEMENTS_TRANSITION) { return descriptors->GetValue(index); } else { @@ -2405,6 +2411,7 @@ MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind, return maybe_new_descriptors; } set_instance_descriptors(DescriptorArray::cast(new_descriptors)); + transitioned_map->SetBackPointer(this); return this; } @@ -3023,7 +3030,6 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( String* name, Object* value, PropertyAttributes attributes) { - // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc; @@ -3092,7 +3098,6 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); case HANDLER: UNREACHABLE(); - return value; } UNREACHABLE(); // keep the compiler happy return value; @@ -3343,7 +3348,7 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, DescriptorArray* descs = map_of_this->instance_descriptors(); for (int i = 0; i < descs->number_of_descriptors(); i++) { - PropertyDetails details(descs->GetDetails(i)); + PropertyDetails details = descs->GetDetails(i); switch (details.type()) { case CONSTANT_FUNCTION: { PropertyDetails d = @@ -3751,13 +3756,11 @@ MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) { MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize); StringDictionary* dictionary; if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc; - MaybeObject* store_result = - SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), - dictionary, - DONT_ENUM, - kNonStrictMode); - if (store_result->IsFailure()) return store_result; - return dictionary; + // Using AddProperty or SetPropertyPostInterceptor here could fail, because + // object might be non-extensible. + return HasFastProperties() + ? AddFastProperty(GetHeap()->hidden_symbol(), dictionary, DONT_ENUM) + : AddSlowProperty(GetHeap()->hidden_symbol(), dictionary, DONT_ENUM); } @@ -4207,7 +4210,7 @@ int Map::NumberOfDescribedProperties(PropertyAttributes filter) { int result = 0; DescriptorArray* descs = instance_descriptors(); for (int i = 0; i < descs->number_of_descriptors(); i++) { - PropertyDetails details(descs->GetDetails(i)); + PropertyDetails details = descs->GetDetails(i); if (descs->IsProperty(i) && (details.attributes() & filter) == 0) { result++; } @@ -4410,37 +4413,56 @@ MaybeObject* JSObject::DefineElementAccessor(uint32_t index, } +MaybeObject* JSObject::CreateAccessorPairFor(String* name) { + LookupResult result(GetHeap()->isolate()); + LocalLookupRealNamedProperty(name, &result); + if (result.IsProperty() && result.type() == CALLBACKS) { + // Note that the result can actually have IsDontDelete() == true when we + // e.g. have to fall back to the slow case while adding a setter after + // successfully reusing a map transition for a getter. Nevertheless, this is + // OK, because the assertion only holds for the whole addition of both + // accessors, not for the addition of each part. See first comment in + // DefinePropertyAccessor below. + Object* obj = result.GetCallbackObject(); + if (obj->IsAccessorPair()) { + return AccessorPair::cast(obj)->CopyWithoutTransitions(); + } + } + return GetHeap()->AllocateAccessorPair(); +} + + MaybeObject* JSObject::DefinePropertyAccessor(String* name, Object* getter, Object* setter, PropertyAttributes attributes) { - // Lookup the name. - LookupResult result(GetHeap()->isolate()); - LocalLookupRealNamedProperty(name, &result); - if (result.IsFound()) { - if (result.type() == CALLBACKS) { - ASSERT(!result.IsDontDelete()); - Object* obj = result.GetCallbackObject(); - // Need to preserve old getters/setters. - if (obj->IsAccessorPair()) { - AccessorPair* copy; - { MaybeObject* maybe_copy = - AccessorPair::cast(obj)->CopyWithoutTransitions(); - if (!maybe_copy->To(©)) return maybe_copy; - } - copy->SetComponents(getter, setter); - // Use set to update attributes. - return SetPropertyCallback(name, copy, attributes); - } + // We could assert that the property is configurable here, but we would need + // to do a lookup, which seems to be a bit of overkill. + Heap* heap = GetHeap(); + bool only_attribute_changes = getter->IsNull() && setter->IsNull(); + if (HasFastProperties() && !only_attribute_changes) { + MaybeObject* getterOk = heap->undefined_value(); + if (!getter->IsNull()) { + getterOk = DefineFastAccessor(name, ACCESSOR_GETTER, getter, attributes); + if (getterOk->IsFailure()) return getterOk; + } + + MaybeObject* setterOk = heap->undefined_value(); + if (getterOk != heap->null_value() && !setter->IsNull()) { + setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes); + if (setterOk->IsFailure()) return setterOk; + } + + if (getterOk != heap->null_value() && setterOk != heap->null_value()) { + return heap->undefined_value(); } } AccessorPair* accessors; - { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair(); + { MaybeObject* maybe_accessors = CreateAccessorPairFor(name); if (!maybe_accessors->To(&accessors)) return maybe_accessors; } accessors->SetComponents(getter, setter); - return SetPropertyCallback(name, accessors, attributes); } @@ -4585,6 +4607,159 @@ MaybeObject* JSObject::DefineAccessor(String* name, } +static MaybeObject* CreateFreshAccessor(JSObject* obj, + String* name, + AccessorComponent component, + Object* accessor, + PropertyAttributes attributes) { + // step 1: create a new getter/setter pair with only the accessor in it + Heap* heap = obj->GetHeap(); + AccessorPair* accessors2; + { MaybeObject* maybe_accessors2 = heap->AllocateAccessorPair(); + if (!maybe_accessors2->To(&accessors2)) return maybe_accessors2; + } + accessors2->set(component, accessor); + + // step 2: create a copy of the descriptors, incl. the new getter/setter pair + Map* map1 = obj->map(); + CallbacksDescriptor callbacks_descr2(name, accessors2, attributes); + DescriptorArray* descriptors2; + { MaybeObject* maybe_descriptors2 = + map1->instance_descriptors()->CopyInsert(&callbacks_descr2, + REMOVE_TRANSITIONS); + if (!maybe_descriptors2->To(&descriptors2)) return maybe_descriptors2; + } + + // step 3: create a new map with the new descriptors + Map* map2; + { MaybeObject* maybe_map2 = map1->CopyDropDescriptors(); + if (!maybe_map2->To(&map2)) return maybe_map2; + } + map2->set_instance_descriptors(descriptors2); + + // step 4: create a new getter/setter pair with a transition to the new map + AccessorPair* accessors1; + { MaybeObject* maybe_accessors1 = heap->AllocateAccessorPair(); + if (!maybe_accessors1->To(&accessors1)) return maybe_accessors1; + } + accessors1->set(component, map2); + + // step 5: create a copy of the descriptors, incl. the new getter/setter pair + // with the transition + CallbacksDescriptor callbacks_descr1(name, accessors1, attributes); + DescriptorArray* descriptors1; + { MaybeObject* maybe_descriptors1 = + map1->instance_descriptors()->CopyInsert(&callbacks_descr1, + KEEP_TRANSITIONS); + if (!maybe_descriptors1->To(&descriptors1)) return maybe_descriptors1; + } + + // step 6: everything went well so far, so we make our changes visible + obj->set_map(map2); + map1->set_instance_descriptors(descriptors1); + map2->SetBackPointer(map1); + return obj; +} + + +static bool TransitionToSameAccessor(Object* map, + String* name, + AccessorComponent component, + Object* accessor, + PropertyAttributes attributes ) { + DescriptorArray* descs = Map::cast(map)->instance_descriptors(); + int number = descs->SearchWithCache(name); + ASSERT(number != DescriptorArray::kNotFound); + Object* target_accessor = + AccessorPair::cast(descs->GetCallbacksObject(number))->get(component); + PropertyAttributes target_attributes = descs->GetDetails(number).attributes(); + return target_accessor == accessor && target_attributes == attributes; +} + + +static MaybeObject* NewCallbackTransition(JSObject* obj, + String* name, + AccessorComponent component, + Object* accessor, + PropertyAttributes attributes, + AccessorPair* accessors2) { + // step 1: copy the old getter/setter pair and set the new accessor + AccessorPair* accessors3; + { MaybeObject* maybe_accessors3 = accessors2->CopyWithoutTransitions(); + if (!maybe_accessors3->To(&accessors3)) return maybe_accessors3; + } + accessors3->set(component, accessor); + + // step 2: create a copy of the descriptors, incl. the new getter/setter pair + Map* map2 = obj->map(); + CallbacksDescriptor callbacks_descr3(name, accessors3, attributes); + DescriptorArray* descriptors3; + { MaybeObject* maybe_descriptors3 = + map2->instance_descriptors()->CopyInsert(&callbacks_descr3, + REMOVE_TRANSITIONS); + if (!maybe_descriptors3->To(&descriptors3)) return maybe_descriptors3; + } + + // step 3: create a new map with the new descriptors + Map* map3; + { MaybeObject* maybe_map3 = map2->CopyDropDescriptors(); + if (!maybe_map3->To(&map3)) return maybe_map3; + } + map3->set_instance_descriptors(descriptors3); + + // step 4: everything went well so far, so we make our changes visible + obj->set_map(map3); + accessors2->set(component, map3); + map3->SetBackPointer(map2); + return obj; +} + + +MaybeObject* JSObject::DefineFastAccessor(String* name, + AccessorComponent component, + Object* accessor, + PropertyAttributes attributes) { + ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined()); + LookupResult result(GetIsolate()); + LocalLookup(name, &result); + + // If we have a new property, create a fresh accessor plus a transition to it. + if (!result.IsFound()) { + return CreateFreshAccessor(this, name, component, accessor, attributes); + } + + // If the property is not a JavaScript accessor, fall back to the slow case. + if (result.type() != CALLBACKS) return GetHeap()->null_value(); + Object* callback_value = result.GetValue(); + if (!callback_value->IsAccessorPair()) return GetHeap()->null_value(); + AccessorPair* accessors = AccessorPair::cast(callback_value); + + // Follow a callback transition, if there is a fitting one. + Object* entry = accessors->get(component); + if (entry->IsMap() && + TransitionToSameAccessor(entry, name, component, accessor, attributes)) { + set_map(Map::cast(entry)); + return this; + } + + // When we re-add the same accessor again, there is nothing to do. + if (entry == accessor && result.GetAttributes() == attributes) return this; + + // Only the other accessor has been set so far, create a new transition. + if (entry->IsTheHole()) { + return NewCallbackTransition(this, + name, + component, + accessor, + attributes, + accessors); + } + + // Nothing from the above worked, so we have to fall back to the slow case. + return GetHeap()->null_value(); +} + + MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { Isolate* isolate = GetIsolate(); String* name = String::cast(info->name()); @@ -4968,7 +5143,7 @@ class IntrusiveMapTransitionIterator { // underlying array while it is running. class IntrusivePrototypeTransitionIterator { public: - explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans) + explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans) : proto_trans_(proto_trans) { } void Start() { @@ -4993,7 +5168,7 @@ class IntrusivePrototypeTransitionIterator { private: bool HasTransitions() { - return proto_trans_->length() >= Map::kProtoTransitionHeaderSize; + return proto_trans_->map()->IsSmi() || proto_trans_->IsFixedArray(); } Object** Header() { @@ -5001,12 +5176,16 @@ class IntrusivePrototypeTransitionIterator { } int NumberOfTransitions() { - Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset); + ASSERT(HasTransitions()); + FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_); + Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset); return Smi::cast(num)->value(); } Map* GetTransition(int transitionNumber) { - return Map::cast(proto_trans_->get(IndexFor(transitionNumber))); + ASSERT(HasTransitions()); + FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_); + return Map::cast(proto_trans->get(IndexFor(transitionNumber))); } int IndexFor(int transitionNumber) { @@ -5015,7 +5194,7 @@ class IntrusivePrototypeTransitionIterator { transitionNumber * Map::kProtoTransitionElementsPerEntry; } - FixedArray* proto_trans_; + HeapObject* proto_trans_; }; @@ -5696,7 +5875,7 @@ MaybeObject* DescriptorArray::CopyFrom(int dst_index, int src_index, const WhitenessWitness& witness) { Object* value = src->GetValue(src_index); - PropertyDetails details(src->GetDetails(src_index)); + PropertyDetails details = src->GetDetails(src_index); if (details.type() == CALLBACKS && value->IsAccessorPair()) { MaybeObject* maybe_copy = AccessorPair::cast(value)->CopyWithoutTransitions(); @@ -5739,7 +5918,7 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor, if (replacing) { // We are replacing an existing descriptor. We keep the enumeration // index of a visible property. - PropertyType t = PropertyDetails(GetDetails(index)).type(); + PropertyType t = GetDetails(index).type(); if (t == CONSTANT_FUNCTION || t == FIELD || t == CALLBACKS || @@ -5766,8 +5945,7 @@ MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor, int enumeration_index = NextEnumerationIndex(); if (!descriptor->ContainsTransition()) { if (keep_enumeration_index) { - descriptor->SetEnumerationIndex( - PropertyDetails(GetDetails(index)).index()); + descriptor->SetEnumerationIndex(GetDetails(index).index()); } else { descriptor->SetEnumerationIndex(enumeration_index); ++enumeration_index; @@ -5911,10 +6089,10 @@ int DescriptorArray::BinarySearch(String* name, int low, int high) { ASSERT(hash == mid_hash); // There might be more, so we find the first one and // check them all to see if we have a match. - if (name == mid_name && !is_null_descriptor(mid)) return mid; + if (name == mid_name && !IsNullDescriptor(mid)) return mid; while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--; for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) { - if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid; + if (GetKey(mid)->Equals(name) && !IsNullDescriptor(mid)) return mid; } break; } @@ -5928,7 +6106,7 @@ int DescriptorArray::LinearSearch(String* name, int len) { String* entry = GetKey(number); if ((entry->Hash() == hash) && name->Equals(entry) && - !is_null_descriptor(number)) { + !IsNullDescriptor(number)) { return number; } } @@ -5949,8 +6127,8 @@ MaybeObject* AccessorPair::CopyWithoutTransitions() { Object* AccessorPair::GetComponent(AccessorComponent component) { - Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter(); - return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor; + Object* accessor = get(component); + return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor; } @@ -7178,85 +7356,23 @@ void String::PrintOn(FILE* file) { } -void Map::CreateOneBackPointer(Object* transition_target) { - if (!transition_target->IsMap()) return; - Map* target = Map::cast(transition_target); -#ifdef DEBUG - // Verify target. - Object* source_prototype = prototype(); - Object* target_prototype = target->prototype(); - ASSERT(source_prototype->IsJSReceiver() || - source_prototype->IsMap() || - source_prototype->IsNull()); - ASSERT(target_prototype->IsJSReceiver() || - target_prototype->IsNull()); - ASSERT(source_prototype->IsMap() || - source_prototype == target_prototype); -#endif - // Point target back to source. set_prototype() will not let us set - // the prototype to a map, as we do here. - *RawField(target, kPrototypeOffset) = this; -} - - -void Map::CreateBackPointers() { - DescriptorArray* descriptors = instance_descriptors(); - for (int i = 0; i < descriptors->number_of_descriptors(); i++) { - switch (descriptors->GetType(i)) { - case MAP_TRANSITION: - case CONSTANT_TRANSITION: - CreateOneBackPointer(descriptors->GetValue(i)); - break; - case ELEMENTS_TRANSITION: { - Object* object = descriptors->GetValue(i); - if (object->IsMap()) { - CreateOneBackPointer(object); - } else { - FixedArray* array = FixedArray::cast(object); - for (int i = 0; i < array->length(); ++i) { - CreateOneBackPointer(array->get(i)); - } - } - break; - } - case CALLBACKS: { - Object* object = descriptors->GetValue(i); - if (object->IsAccessorPair()) { - AccessorPair* accessors = AccessorPair::cast(object); - CreateOneBackPointer(accessors->getter()); - CreateOneBackPointer(accessors->setter()); - } - break; - } - case NORMAL: - case FIELD: - case CONSTANT_FUNCTION: - case HANDLER: - case INTERCEPTOR: - case NULL_DESCRIPTOR: - break; - } - } -} - - -bool Map::RestoreOneBackPointer(Object* object, - Object* real_prototype, - bool* keep_entry) { - if (!object->IsMap()) return false; - Map* map = Map::cast(object); +// Clear a possible back pointer in case the transition leads to a dead map. +// Return true in case a back pointer has been cleared and false otherwise. +// Set *keep_entry to true when a live map transition has been found. +static bool ClearBackPointer(Heap* heap, Object* target, bool* keep_entry) { + if (!target->IsMap()) return false; + Map* map = Map::cast(target); if (Marking::MarkBitFrom(map).Get()) { *keep_entry = true; return false; + } else { + map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); + return true; } - ASSERT(map->prototype() == this || map->prototype() == real_prototype); - // Getter prototype() is read-only, set_prototype() has side effects. - *RawField(map, Map::kPrototypeOffset) = real_prototype; - return true; } -void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { +void Map::ClearNonLiveTransitions(Heap* heap) { DescriptorArray* d = DescriptorArray::cast( *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); if (d->IsEmpty()) return; @@ -7269,24 +7385,22 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { // If the pair (value, details) is a map transition, check if the target is // live. If not, null the descriptor. Also drop the back pointer for that // map transition, so that this map is not reached again by following a back - // pointer from a non-live object. + // pointer from that non-live map. bool keep_entry = false; PropertyDetails details(Smi::cast(contents->get(i + 1))); switch (details.type()) { case MAP_TRANSITION: case CONSTANT_TRANSITION: - RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry); + ClearBackPointer(heap, contents->get(i), &keep_entry); break; case ELEMENTS_TRANSITION: { Object* object = contents->get(i); if (object->IsMap()) { - RestoreOneBackPointer(object, real_prototype, &keep_entry); + ClearBackPointer(heap, object, &keep_entry); } else { FixedArray* array = FixedArray::cast(object); for (int j = 0; j < array->length(); ++j) { - if (RestoreOneBackPointer(array->get(j), - real_prototype, - &keep_entry)) { + if (ClearBackPointer(heap, array->get(j), &keep_entry)) { array->set_undefined(j); } } @@ -7297,14 +7411,10 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { Object* object = contents->get(i); if (object->IsAccessorPair()) { AccessorPair* accessors = AccessorPair::cast(object); - if (RestoreOneBackPointer(accessors->getter(), - real_prototype, - &keep_entry)) { + if (ClearBackPointer(heap, accessors->getter(), &keep_entry)) { accessors->set_getter(heap->the_hole_value()); } - if (RestoreOneBackPointer(accessors->setter(), - real_prototype, - &keep_entry)) { + if (ClearBackPointer(heap, accessors->setter(), &keep_entry)) { accessors->set_setter(heap->the_hole_value()); } } else { @@ -7869,6 +7979,22 @@ void SharedFunctionInfo::AttachInitialMap(Map* map) { } +void SharedFunctionInfo::ResetForNewContext(int new_ic_age) { + code()->ClearInlineCaches(); + set_ic_age(new_ic_age); + if (code()->kind() == Code::FUNCTION) { + code()->set_profiler_ticks(0); + if (optimization_disabled() && + opt_count() >= Compiler::kDefaultMaxOptCount) { + // Re-enable optimizations if they were disabled due to opt_count limit. + set_optimization_disabled(false); + code()->set_optimizable(true); + } + set_opt_count(0); + } +} + + static void GetMinInobjectSlack(Map* map, void* data) { int slack = map->unused_property_fields(); if (*reinterpret_cast<int*>(data) > slack) { @@ -7912,6 +8038,12 @@ void SharedFunctionInfo::CompleteInobjectSlackTracking() { } +void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) { + v->VisitSharedFunctionInfo(this); + SharedFunctionInfo::BodyDescriptor::IterateBody(this, v); +} + + #define DECLARE_TAG(ignore1, name, ignore2) name, const char* const VisitorSynchronization::kTags[ VisitorSynchronization::kNumberOfSyncTags] = { @@ -7969,7 +8101,6 @@ void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) { CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target. } - void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) { ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); VisitPointer(rinfo->target_object_address()); @@ -8116,6 +8247,35 @@ Map* Code::FindFirstMap() { } +void Code::ClearInlineCaches() { + int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | + RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) | + RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) | + RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT); + for (RelocIterator it(this, mask); !it.done(); it.next()) { + RelocInfo* info = it.rinfo(); + Code* target(Code::GetCodeFromTargetAddress(info->target_address())); + if (target->is_inline_cache_stub()) { + IC::Clear(info->pc()); + } + } +} + + +void Code::ClearTypeFeedbackCells(Heap* heap) { + Object* raw_info = type_feedback_info(); + if (raw_info->IsTypeFeedbackInfo()) { + TypeFeedbackCells* type_feedback_cells = + TypeFeedbackInfo::cast(raw_info)->type_feedback_cells(); + for (int i = 0; i < type_feedback_cells->CellCount(); i++) { + ASSERT(type_feedback_cells->AstId(i)->IsSmi()); + JSGlobalPropertyCell* cell = type_feedback_cells->Cell(i); + cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap)); + } + } +} + + #ifdef ENABLE_DISASSEMBLER void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { @@ -8348,6 +8508,14 @@ void Code::Disassemble(const char* name, FILE* out) { if (is_call_stub() || is_keyed_call_stub()) { PrintF(out, "argc = %d\n", arguments_count()); } + if (is_compare_ic_stub()) { + CompareIC::State state = CompareIC::ComputeState(this); + PrintF(out, "compare_state = %s\n", CompareIC::GetStateName(state)); + } + if (is_compare_ic_stub() && major_key() == CodeStub::CompareIC) { + Token::Value op = CompareIC::ComputeOperation(this); + PrintF(out, "compare_operation = %s\n", Token::Name(op)); + } } if ((name != NULL) && (name[0] != '\0')) { PrintF(out, "name = %s\n", name); @@ -8453,8 +8621,10 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength( ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS) ? FAST_SMI_ONLY_ELEMENTS : FAST_ELEMENTS; - // int copy_size = Min(old_elements_raw->length(), new_elements->length()); - accessor->CopyElements(this, new_elements, to_kind); + { MaybeObject* maybe_obj = + accessor->CopyElements(this, new_elements, to_kind); + if (maybe_obj->IsFailure()) return maybe_obj; + } if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) { set_map_and_elements(new_map, new_elements); } else { @@ -8483,7 +8653,7 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( // We should never end in here with a pixel or external array. ASSERT(!HasExternalArrayElements()); - FixedDoubleArray* elems; + FixedArrayBase* elems; { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedDoubleArray(capacity); if (!maybe_obj->To(&elems)) return maybe_obj; @@ -8498,7 +8668,10 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( FixedArrayBase* old_elements = elements(); ElementsKind elements_kind = GetElementsKind(); ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind); - accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS); + { MaybeObject* maybe_obj = + accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS); + if (maybe_obj->IsFailure()) return maybe_obj; + } if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) { set_map_and_elements(new_map, elems); } else { @@ -9634,9 +9807,10 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) { ElementsKind from_kind = map()->elements_kind(); Isolate* isolate = GetIsolate(); - if (from_kind == FAST_SMI_ONLY_ELEMENTS && - (to_kind == FAST_ELEMENTS || - elements() == isolate->heap()->empty_fixed_array())) { + if ((from_kind == FAST_SMI_ONLY_ELEMENTS || + elements() == isolate->heap()->empty_fixed_array()) && + to_kind == FAST_ELEMENTS) { + ASSERT(from_kind != FAST_ELEMENTS); MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind); Map* new_map; if (!maybe_new_map->To(&new_map)) return maybe_new_map; @@ -12814,7 +12988,7 @@ int BreakPointInfo::GetBreakPointCount() { #endif // ENABLE_DEBUGGER_SUPPORT -MaybeObject* JSDate::GetField(Object* object, Smi* index) { +Object* JSDate::GetField(Object* object, Smi* index) { return JSDate::cast(object)->DoGetField( static_cast<FieldIndex>(index->value())); } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index ced23a98cb..22993f2568 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -59,6 +59,7 @@ // - JSWeakMap // - JSRegExp // - JSFunction +// - JSModule // - GlobalObject // - JSGlobalObject // - JSBuiltinsObject @@ -306,6 +307,7 @@ const int kVariableSizeSentinel = 0; V(JS_DATE_TYPE) \ V(JS_OBJECT_TYPE) \ V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \ + V(JS_MODULE_TYPE) \ V(JS_GLOBAL_OBJECT_TYPE) \ V(JS_BUILTINS_OBJECT_TYPE) \ V(JS_GLOBAL_PROXY_TYPE) \ @@ -626,6 +628,7 @@ enum InstanceType { JS_DATE_TYPE, JS_OBJECT_TYPE, JS_CONTEXT_EXTENSION_OBJECT_TYPE, + JS_MODULE_TYPE, JS_GLOBAL_OBJECT_TYPE, JS_BUILTINS_OBJECT_TYPE, JS_GLOBAL_PROXY_TYPE, @@ -677,6 +680,7 @@ const int kExternalArrayTypeCount = STATIC_CHECK(JS_OBJECT_TYPE == Internals::kJSObjectType); STATIC_CHECK(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType); +STATIC_CHECK(ODDBALL_TYPE == Internals::kOddballType); STATIC_CHECK(FOREIGN_TYPE == Internals::kForeignType); @@ -700,12 +704,13 @@ enum CompareResult { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \ +class AccessorPair; class DictionaryElementsAccessor; class ElementsAccessor; +class Failure; class FixedArrayBase; class ObjectVisitor; class StringStream; -class Failure; struct ValueInfo : public Malloced { ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { } @@ -803,6 +808,7 @@ class MaybeObject BASE_EMBEDDED { V(JSReceiver) \ V(JSObject) \ V(JSContextExtensionObject) \ + V(JSModule) \ V(Map) \ V(DescriptorArray) \ V(DeoptimizationInputData) \ @@ -812,6 +818,7 @@ class MaybeObject BASE_EMBEDDED { V(FixedDoubleArray) \ V(Context) \ V(GlobalContext) \ + V(ModuleContext) \ V(ScopeInfo) \ V(JSFunction) \ V(Code) \ @@ -1636,6 +1643,14 @@ class JSObject: public JSReceiver { Object* getter, Object* setter, PropertyAttributes attributes); + // Try to define a single accessor paying attention to map transitions. + // Returns a JavaScript null if this was not possible and we have to use the + // slow case. Note that we can fail due to allocations, too. + MUST_USE_RESULT MaybeObject* DefineFastAccessor( + String* name, + AccessorComponent component, + Object* accessor, + PropertyAttributes attributes); Object* LookupAccessor(String* name, AccessorComponent component); MUST_USE_RESULT MaybeObject* DefineAccessor(AccessorInfo* info); @@ -2186,6 +2201,7 @@ class JSObject: public JSReceiver { Object* getter, Object* setter, PropertyAttributes attributes); + MUST_USE_RESULT MaybeObject* CreateAccessorPairFor(String* name); MUST_USE_RESULT MaybeObject* DefinePropertyAccessor( String* name, Object* getter, @@ -2467,7 +2483,7 @@ class DescriptorArray: public FixedArray { // Accessors for fetching instance descriptor at descriptor number. inline String* GetKey(int descriptor_number); inline Object* GetValue(int descriptor_number); - inline Smi* GetDetails(int descriptor_number); + inline PropertyDetails GetDetails(int descriptor_number); inline PropertyType GetType(int descriptor_number); inline int GetFieldIndex(int descriptor_number); inline JSFunction* GetConstantFunction(int descriptor_number); @@ -2476,7 +2492,6 @@ class DescriptorArray: public FixedArray { inline bool IsProperty(int descriptor_number); inline bool IsTransitionOnly(int descriptor_number); inline bool IsNullDescriptor(int descriptor_number); - inline bool IsDontEnum(int descriptor_number); class WhitenessWitness { public: @@ -2594,6 +2609,9 @@ class DescriptorArray: public FixedArray { // Is the descriptor array sorted and without duplicates? bool IsSortedNoDuplicates(); + // Is the descriptor array consistent with the back pointers in targets? + bool IsConsistentWithBackPointers(Map* current_map); + // Are two DescriptorArrays equal? bool IsEqualTo(DescriptorArray* other); #endif @@ -2630,10 +2648,6 @@ class DescriptorArray: public FixedArray { return descriptor_number << 1; } - bool is_null_descriptor(int descriptor_number) { - return PropertyDetails(GetDetails(descriptor_number)).type() == - NULL_DESCRIPTOR; - } // Swap operation on FixedArray without using write barriers. static inline void NoIncrementalWriteBarrierSwap( FixedArray* array, int first, int second); @@ -3413,8 +3427,8 @@ class ScopeInfo : public FixedArray { // otherwise returns a value < 0. The name must be a symbol (canonicalized). int ParameterIndex(String* name); - // Lookup support for serialized scope info. Returns the - // function context slot index if the function name is present (named + // Lookup support for serialized scope info. Returns the function context + // slot index if the function name is present and context-allocated (named // function expressions, only), otherwise returns a value < 0. The name // must be a symbol (canonicalized). int FunctionContextSlotIndex(String* name, VariableMode* mode); @@ -4243,11 +4257,6 @@ class Code: public HeapObject { inline bool is_compiled_optimizable(); inline void set_compiled_optimizable(bool value); - // [has_self_optimization_header]: For FUNCTION kind, tells if it has - // a self-optimization header. - inline bool has_self_optimization_header(); - inline void set_self_optimization_header(bool value); - // [allow_osr_at_loop_nesting_level]: For FUNCTION kind, tells for // how long the function has been marked for OSR and therefore which // level of loop nesting we are willing to do on-stack replacement @@ -4255,6 +4264,11 @@ class Code: public HeapObject { inline void set_allow_osr_at_loop_nesting_level(int level); inline int allow_osr_at_loop_nesting_level(); + // [profiler_ticks]: For FUNCTION kind, tells for how many profiler ticks + // the code object was seen on the stack with no IC patching going on. + inline int profiler_ticks(); + inline void set_profiler_ticks(int ticks); + // [stack_slots]: For kind OPTIMIZED_FUNCTION, the number of stack slots // reserved in the code prologue. inline unsigned stack_slots(); @@ -4289,6 +4303,11 @@ class Code: public HeapObject { inline byte compare_state(); inline void set_compare_state(byte value); + // [compare_operation]: For kind COMPARE_IC tells what compare operation the + // stub was generated for. + inline byte compare_operation(); + inline void set_compare_operation(byte value); + // [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in. inline byte to_boolean_state(); inline void set_to_boolean_state(byte value); @@ -4423,6 +4442,8 @@ class Code: public HeapObject { #ifdef DEBUG void CodeVerify(); #endif + void ClearInlineCaches(); + void ClearTypeFeedbackCells(Heap* heap); // Max loop nesting marker used to postpose OSR. We don't take loop // nesting that is deeper than 5 levels into account. @@ -4468,11 +4489,13 @@ class Code: public HeapObject { public BitField<bool, 0, 1> {}; // NOLINT class FullCodeFlagsHasDebugBreakSlotsField: public BitField<bool, 1, 1> {}; class FullCodeFlagsIsCompiledOptimizable: public BitField<bool, 2, 1> {}; - class FullCodeFlagsHasSelfOptimizationHeader: public BitField<bool, 3, 1> {}; static const int kBinaryOpReturnTypeOffset = kBinaryOpTypeOffset + 1; + static const int kCompareOperationOffset = kCompareStateOffset + 1; + static const int kAllowOSRAtLoopNestingLevelOffset = kFullCodeFlags + 1; + static const int kProfilerTicksOffset = kAllowOSRAtLoopNestingLevelOffset + 1; static const int kSafepointTableOffsetOffset = kStackSlotsOffset + kIntSize; static const int kStackCheckTableOffsetOffset = kStackSlotsOffset + kIntSize; @@ -4699,19 +4722,30 @@ class Map: public HeapObject { // [stub cache]: contains stubs compiled for this map. DECL_ACCESSORS(code_cache, Object) + // [back pointer]: points back to the parent map from which a transition + // leads to this map. The field overlaps with prototype transitions and the + // back pointer will be moved into the prototype transitions array if + // required. + inline Object* GetBackPointer(); + inline void SetBackPointer(Object* value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + // [prototype transitions]: cache of prototype transitions. // Prototype transition is a transition that happens // when we change object's prototype to a new one. // Cache format: // 0: finger - index of the first free cell in the cache - // 1 + 2 * i: prototype - // 2 + 2 * i: target map + // 1: back pointer that overlaps with prototype transitions field. + // 2 + 2 * i: prototype + // 3 + 2 * i: target map DECL_ACCESSORS(prototype_transitions, FixedArray) - inline FixedArray* unchecked_prototype_transitions(); + inline void init_prototype_transitions(Object* undefined); + inline HeapObject* unchecked_prototype_transitions(); - static const int kProtoTransitionHeaderSize = 1; + static const int kProtoTransitionHeaderSize = 2; static const int kProtoTransitionNumberOfEntriesOffset = 0; + static const int kProtoTransitionBackPointerOffset = 1; static const int kProtoTransitionElementsPerEntry = 2; static const int kProtoTransitionPrototypeOffset = 0; static const int kProtoTransitionMapOffset = 1; @@ -4783,25 +4817,10 @@ class Map: public HeapObject { // Removes a code object from the code cache at the given index. void RemoveFromCodeCache(String* name, Code* code, int index); - // For every transition in this map, makes the transition's - // target's prototype pointer point back to this map. - // This is undone in MarkCompactCollector::ClearNonLiveTransitions(). - void CreateBackPointers(); - - void CreateOneBackPointer(Object* transition_target); - - // Set all map transitions from this map to dead maps to null. - // Also, restore the original prototype on the targets of these - // transitions, so that we do not process this map again while - // following back pointers. - void ClearNonLiveTransitions(Heap* heap, Object* real_prototype); - - // Restore a possible back pointer in the prototype field of object. - // Return true in that case and false otherwise. Set *keep_entry to - // true when a live map transition has been found. - bool RestoreOneBackPointer(Object* object, - Object* real_prototype, - bool* keep_entry); + // Set all map transitions from this map to dead maps to null. Also clear + // back pointers in transition targets so that we do not process this map + // again while following back pointers. + void ClearNonLiveTransitions(Heap* heap); // Computes a hash value for this map, to be used in HashTables and such. int Hash(); @@ -4883,16 +4902,17 @@ class Map: public HeapObject { kConstructorOffset + kPointerSize; static const int kCodeCacheOffset = kInstanceDescriptorsOrBitField3Offset + kPointerSize; - static const int kPrototypeTransitionsOffset = + static const int kPrototypeTransitionsOrBackPointerOffset = kCodeCacheOffset + kPointerSize; - static const int kPadStart = kPrototypeTransitionsOffset + kPointerSize; + static const int kPadStart = + kPrototypeTransitionsOrBackPointerOffset + kPointerSize; static const int kSize = MAP_POINTER_ALIGN(kPadStart); // Layout of pointer fields. Heap iteration code relies on them // being continuously allocated. static const int kPointerFieldsBeginOffset = Map::kPrototypeOffset; static const int kPointerFieldsEndOffset = - Map::kPrototypeTransitionsOffset + kPointerSize; + kPrototypeTransitionsOrBackPointerOffset + kPointerSize; // Byte offsets within kInstanceSizesOffset. static const int kInstanceSizeOffset = kInstanceSizesOffset + 0; @@ -5323,16 +5343,20 @@ class SharedFunctionInfo: public HeapObject { inline int compiler_hints(); inline void set_compiler_hints(int value); + inline int ast_node_count(); + inline void set_ast_node_count(int count); + // A counter used to determine when to stress the deoptimizer with a // deopt. inline int deopt_counter(); inline void set_deopt_counter(int counter); inline int profiler_ticks(); - inline void set_profiler_ticks(int ticks); - inline int ast_node_count(); - inline void set_ast_node_count(int count); + // Inline cache age is used to infer whether the function survived a context + // disposal or not. In the former case we reset the opt_count. + inline int ic_age(); + inline void set_ic_age(int age); // Add information on assignments of the form this.x = ...; void SetThisPropertyAssignmentsInfo( @@ -5478,6 +5502,8 @@ class SharedFunctionInfo: public HeapObject { void SharedFunctionInfoVerify(); #endif + void ResetForNewContext(int new_ic_age); + // Helpers to compile the shared code. Returns true on success, false on // failure (e.g., stack overflow during compilation). static bool EnsureCompiled(Handle<SharedFunctionInfo> shared, @@ -5485,6 +5511,8 @@ class SharedFunctionInfo: public HeapObject { static bool CompileLazy(Handle<SharedFunctionInfo> shared, ClearExceptionFlag flag); + void SharedFunctionInfoIterateBody(ObjectVisitor* v); + // Casting. static inline SharedFunctionInfo* cast(Object* obj); @@ -5508,12 +5536,13 @@ class SharedFunctionInfo: public HeapObject { kInferredNameOffset + kPointerSize; static const int kThisPropertyAssignmentsOffset = kInitialMapOffset + kPointerSize; - static const int kProfilerTicksOffset = - kThisPropertyAssignmentsOffset + kPointerSize; + // ic_age is a Smi field. It could be grouped with another Smi field into a + // PSEUDO_SMI_ACCESSORS pair (on x64), if one becomes available. + static const int kICAgeOffset = kThisPropertyAssignmentsOffset + kPointerSize; #if V8_HOST_ARCH_32_BIT // Smi fields. static const int kLengthOffset = - kProfilerTicksOffset + kPointerSize; + kICAgeOffset + kPointerSize; static const int kFormalParameterCountOffset = kLengthOffset + kPointerSize; static const int kExpectedNofPropertiesOffset = kFormalParameterCountOffset + kPointerSize; @@ -5532,8 +5561,9 @@ class SharedFunctionInfo: public HeapObject { static const int kOptCountOffset = kThisPropertyAssignmentsCountOffset + kPointerSize; static const int kAstNodeCountOffset = kOptCountOffset + kPointerSize; - static const int kDeoptCounterOffset = - kAstNodeCountOffset + kPointerSize; + static const int kDeoptCounterOffset = kAstNodeCountOffset + kPointerSize; + + // Total size. static const int kSize = kDeoptCounterOffset + kPointerSize; #else @@ -5547,7 +5577,7 @@ class SharedFunctionInfo: public HeapObject { // word is not set and thus this word cannot be treated as pointer // to HeapObject during old space traversal. static const int kLengthOffset = - kProfilerTicksOffset + kPointerSize; + kICAgeOffset + kPointerSize; static const int kFormalParameterCountOffset = kLengthOffset + kIntSize; @@ -5681,6 +5711,35 @@ class SharedFunctionInfo: public HeapObject { }; +// Representation for module instance objects. +class JSModule: public JSObject { + public: + // [context]: the context holding the module's locals, or undefined if none. + DECL_ACCESSORS(context, Object) + + // Casting. + static inline JSModule* cast(Object* obj); + + // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void JSModulePrint() { + JSModulePrint(stdout); + } + void JSModulePrint(FILE* out); +#endif +#ifdef DEBUG + void JSModuleVerify(); +#endif + + // Layout description. + static const int kContextOffset = JSObject::kHeaderSize; + static const int kSize = kContextOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(JSModule); +}; + + // JSFunction describes JavaScript functions. class JSFunction: public JSObject { public: @@ -6080,7 +6139,7 @@ class JSDate: public JSObject { // Returns the date field with the specified index. // See FieldIndex for the list of date fields. - static MaybeObject* GetField(Object* date, Smi* index); + static Object* GetField(Object* date, Smi* index); void SetValue(Object* value, bool is_value_nan); @@ -6562,8 +6621,8 @@ class TypeFeedbackInfo: public Struct { inline int ic_total_count(); inline void set_ic_total_count(int count); - inline int ic_with_typeinfo_count(); - inline void set_ic_with_typeinfo_count(int count); + inline int ic_with_type_info_count(); + inline void set_ic_with_type_info_count(int count); DECL_ACCESSORS(type_feedback_cells, TypeFeedbackCells) @@ -7597,6 +7656,10 @@ class Oddball: public HeapObject { kToNumberOffset + kPointerSize, kSize> BodyDescriptor; + STATIC_CHECK(kKindOffset == Internals::kOddballKindOffset); + STATIC_CHECK(kNull == Internals::kNullOddballKind); + STATIC_CHECK(kUndefined == Internals::kUndefinedOddballKind); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(Oddball); }; @@ -8057,6 +8120,18 @@ class AccessorPair: public Struct { MUST_USE_RESULT MaybeObject* CopyWithoutTransitions(); + Object* get(AccessorComponent component) { + return component == ACCESSOR_GETTER ? getter() : setter(); + } + + void set(AccessorComponent component, Object* value) { + if (component == ACCESSOR_GETTER) { + set_getter(value); + } else { + set_setter(value); + } + } + // Note: Returns undefined instead in case of a hole. Object* GetComponent(AccessorComponent component); @@ -8531,6 +8606,8 @@ class ObjectVisitor BASE_EMBEDDED { // Visit pointer embedded into a code object. virtual void VisitEmbeddedPointer(RelocInfo* rinfo); + virtual void VisitSharedFunctionInfo(SharedFunctionInfo* shared) {} + // Visits a contiguous arrays of external references (references to the C++ // heap) in the half-open range [start, end). Any or all of the values // may be modified on return. diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index da680411a9..862051956b 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -1333,11 +1333,19 @@ Module* Parser::ParseModuleLiteral(bool* ok) { Expect(Token::RBRACE, CHECK_OK); scope->set_end_position(scanner().location().end_pos); - body->set_block_scope(scope); + body->set_scope(scope); - scope->interface()->Freeze(ok); + // Instance objects have to be created ahead of time (before code generation + // linking them) because of potentially cyclic references between them. + // We create them here, to avoid another pass over the AST. + Interface* interface = scope->interface(); + interface->MakeModule(ok); ASSERT(ok); - return factory()->NewModuleLiteral(body, scope->interface()); + interface->MakeSingleton(Isolate::Current()->factory()->NewJSModule(), ok); + ASSERT(ok); + interface->Freeze(ok); + ASSERT(ok); + return factory()->NewModuleLiteral(body, interface); } @@ -1403,7 +1411,14 @@ Module* Parser::ParseModuleUrl(bool* ok) { #ifdef DEBUG if (FLAG_print_interface_details) PrintF("# Url "); #endif - return factory()->NewModuleUrl(symbol); + + Module* result = factory()->NewModuleUrl(symbol); + Interface* interface = result->interface(); + interface->MakeSingleton(Isolate::Current()->factory()->NewJSModule(), ok); + ASSERT(ok); + interface->Freeze(ok); + ASSERT(ok); + return result; } @@ -2015,7 +2030,7 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { Expect(Token::RBRACE, CHECK_OK); block_scope->set_end_position(scanner().location().end_pos); block_scope = block_scope->FinalizeBlockScope(); - body->set_block_scope(block_scope); + body->set_scope(block_scope); return body; } @@ -2254,7 +2269,7 @@ Block* Parser::ParseVariableDeclarations( // Global variable declarations must be compiled in a specific // way. When the script containing the global variable declaration // is entered, the global variable must be declared, so that if it - // doesn't exist (not even in a prototype of the global object) it + // doesn't exist (on the global object itself, see ES5 errata) it // gets created with an initial undefined value. This is handled // by the declarations part of the function representing the // top-level global code; see Runtime::DeclareGlobalVariable. If @@ -2917,7 +2932,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { top_scope_ = saved_scope; for_scope->set_end_position(scanner().location().end_pos); for_scope = for_scope->FinalizeBlockScope(); - body_block->set_block_scope(for_scope); + body_block->set_scope(for_scope); // Parsed for-in loop w/ let declaration. return loop; @@ -2997,7 +3012,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Block* result = factory()->NewBlock(NULL, 2, false); result->AddStatement(init); result->AddStatement(loop); - result->set_block_scope(for_scope); + result->set_scope(for_scope); if (loop) loop->Initialize(NULL, cond, next, body); return result; } else { @@ -4460,15 +4475,15 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, Variable* fvar = NULL; Token::Value fvar_init_op = Token::INIT_CONST; if (type == FunctionLiteral::NAMED_EXPRESSION) { - VariableMode fvar_mode; - if (is_extended_mode()) { - fvar_mode = CONST_HARMONY; - fvar_init_op = Token::INIT_CONST_HARMONY; - } else { - fvar_mode = CONST; - } - fvar = - top_scope_->DeclareFunctionVar(function_name, fvar_mode, factory()); + if (is_extended_mode()) fvar_init_op = Token::INIT_CONST_HARMONY; + VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST; + fvar = new(zone()) Variable(top_scope_, + function_name, fvar_mode, true /* is valid LHS */, + Variable::NORMAL, kCreatedInitialized); + VariableProxy* proxy = factory()->NewVariableProxy(fvar); + VariableDeclaration* fvar_declaration = + factory()->NewVariableDeclaration(proxy, fvar_mode, top_scope_); + top_scope_->DeclareFunctionVar(fvar_declaration); } // Determine whether the function will be lazily compiled. diff --git a/deps/v8/src/platform-cygwin.cc b/deps/v8/src/platform-cygwin.cc index fa6fce024b..089ea38d9a 100644 --- a/deps/v8/src/platform-cygwin.cc +++ b/deps/v8/src/platform-cygwin.cc @@ -41,6 +41,7 @@ #include "v8.h" +#include "platform-posix.h" #include "platform.h" #include "v8threads.h" #include "vm-state-inl.h" @@ -61,18 +62,10 @@ double ceiling(double x) { static Mutex* limit_mutex = NULL; -void OS::SetUp() { - // Seed the random number generator. - // Convert the current time to a 64-bit integer first, before converting it - // to an unsigned. Going directly can cause an overflow and the seed to be - // set to all ones. The seed will be identical for different instances that - // call this setup code within the same millisecond. - uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); - srandom(static_cast<unsigned int>(seed)); - limit_mutex = CreateMutex(); +void OS::PostSetUp() { + POSIXPostSetUp(); } - uint64_t OS::CpuFeaturesImpliedByPlatform() { return 0; // Nothing special about Cygwin. } @@ -627,8 +620,11 @@ class SamplerThread : public Thread { : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), interval_(interval) {} + static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } + static void TearDown() { delete mutex_; } + static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::AddActiveSampler(sampler); if (instance_ == NULL) { instance_ = new SamplerThread(sampler->interval()); @@ -639,7 +635,7 @@ class SamplerThread : public Thread { } static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::RemoveActiveSampler(sampler); if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_); @@ -725,7 +721,7 @@ class SamplerThread : public Thread { RuntimeProfilerRateLimiter rate_limiter_; // Protects the process wide state below. - static LazyMutex mutex_; + static Mutex* mutex_; static SamplerThread* instance_; private: @@ -733,10 +729,29 @@ class SamplerThread : public Thread { }; -LazyMutex SamplerThread::mutex_ = LAZY_MUTEX_INITIALIZER; +Mutex* SamplerThread::mutex_ = NULL; SamplerThread* SamplerThread::instance_ = NULL; +void OS::SetUp() { + // Seed the random number generator. + // Convert the current time to a 64-bit integer first, before converting it + // to an unsigned. Going directly can cause an overflow and the seed to be + // set to all ones. The seed will be identical for different instances that + // call this setup code within the same millisecond. + uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); + srandom(static_cast<unsigned int>(seed)); + limit_mutex = CreateMutex(); + SamplerThread::SetUp(); +} + + +void OS::TearDown() { + SamplerThread::TearDown(); + delete limit_mutex; +} + + Sampler::Sampler(Isolate* isolate, int interval) : isolate_(isolate), interval_(interval), diff --git a/deps/v8/src/platform-freebsd.cc b/deps/v8/src/platform-freebsd.cc index 2a9e174e35..511759c485 100644 --- a/deps/v8/src/platform-freebsd.cc +++ b/deps/v8/src/platform-freebsd.cc @@ -54,6 +54,7 @@ #include "v8.h" #include "v8threads.h" +#include "platform-posix.h" #include "platform.h" #include "vm-state-inl.h" @@ -79,15 +80,8 @@ double ceiling(double x) { static Mutex* limit_mutex = NULL; -void OS::SetUp() { - // Seed the random number generator. - // Convert the current time to a 64-bit integer first, before converting it - // to an unsigned. Going directly can cause an overflow and the seed to be - // set to all ones. The seed will be identical for different instances that - // call this setup code within the same millisecond. - uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); - srandom(static_cast<unsigned int>(seed)); - limit_mutex = CreateMutex(); +void OS::PostSetUp() { + POSIXPostSetUp(); } @@ -560,6 +554,7 @@ class FreeBSDMutex : public Mutex { ASSERT(result == 0); result = pthread_mutex_init(&mutex_, &attrs); ASSERT(result == 0); + USE(result); } virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); } @@ -722,8 +717,11 @@ class SignalSender : public Thread { : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)), interval_(interval) {} + static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } + static void TearDown() { delete mutex_; } + static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::AddActiveSampler(sampler); if (instance_ == NULL) { // Install a signal handler. @@ -743,7 +741,7 @@ class SignalSender : public Thread { } static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::RemoveActiveSampler(sampler); if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_); @@ -836,7 +834,7 @@ class SignalSender : public Thread { RuntimeProfilerRateLimiter rate_limiter_; // Protects the process wide state below. - static LazyMutex mutex_; + static Mutex* mutex_; static SignalSender* instance_; static bool signal_handler_installed_; static struct sigaction old_signal_handler_; @@ -845,12 +843,31 @@ class SignalSender : public Thread { DISALLOW_COPY_AND_ASSIGN(SignalSender); }; -LazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER; +Mutex* SignalSender::mutex_ = NULL; SignalSender* SignalSender::instance_ = NULL; struct sigaction SignalSender::old_signal_handler_; bool SignalSender::signal_handler_installed_ = false; +void OS::SetUp() { + // Seed the random number generator. + // Convert the current time to a 64-bit integer first, before converting it + // to an unsigned. Going directly can cause an overflow and the seed to be + // set to all ones. The seed will be identical for different instances that + // call this setup code within the same millisecond. + uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); + srandom(static_cast<unsigned int>(seed)); + limit_mutex = CreateMutex(); + SignalSender::SetUp(); +} + + +void OS::TearDown() { + SignalSender::TearDown(); + delete limit_mutex; +} + + Sampler::Sampler(Isolate* isolate, int interval) : isolate_(isolate), interval_(interval), diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc index 08f4495b53..f6db423e42 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -46,9 +46,9 @@ #include <sys/stat.h> // open #include <fcntl.h> // open #include <unistd.h> // sysconf -#ifdef __GLIBC__ +#if defined(__GLIBC__) && !defined(__UCLIBC__) #include <execinfo.h> // backtrace, backtrace_symbols -#endif // def __GLIBC__ +#endif // defined(__GLIBC__) && !defined(__UCLIBC__) #include <strings.h> // index #include <errno.h> #include <stdarg.h> @@ -57,6 +57,7 @@ #include "v8.h" +#include "platform-posix.h" #include "platform.h" #include "v8threads.h" #include "vm-state-inl.h" @@ -78,30 +79,8 @@ double ceiling(double x) { static Mutex* limit_mutex = NULL; -void OS::SetUp() { - // Seed the random number generator. We preserve microsecond resolution. - uint64_t seed = Ticks() ^ (getpid() << 16); - srandom(static_cast<unsigned int>(seed)); - limit_mutex = CreateMutex(); - -#ifdef __arm__ - // When running on ARM hardware check that the EABI used by V8 and - // by the C code is the same. - bool hard_float = OS::ArmUsingHardFloat(); - if (hard_float) { -#if !USE_EABI_HARDFLOAT - PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without " - "-DUSE_EABI_HARDFLOAT\n"); - exit(1); -#endif - } else { -#if USE_EABI_HARDFLOAT - PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with " - "-DUSE_EABI_HARDFLOAT\n"); - exit(1); -#endif - } -#endif +void OS::PostSetUp() { + POSIXPostSetUp(); } @@ -556,7 +535,7 @@ void OS::SignalCodeMovingGC() { int OS::StackWalk(Vector<OS::StackFrame> frames) { // backtrace is a glibc extension. -#ifdef __GLIBC__ +#if defined(__GLIBC__) && !defined(__UCLIBC__) int frames_size = frames.length(); ScopedVector<void*> addresses(frames_size); @@ -581,9 +560,9 @@ int OS::StackWalk(Vector<OS::StackFrame> frames) { free(symbols); return frames_count; -#else // ndef __GLIBC__ +#else // defined(__GLIBC__) && !defined(__UCLIBC__) return 0; -#endif // ndef __GLIBC__ +#endif // defined(__GLIBC__) && !defined(__UCLIBC__) } @@ -985,6 +964,25 @@ typedef struct ucontext { __sigset_t uc_sigmask; } ucontext_t; +#elif !defined(__GLIBC__) && defined(__i386__) +// x86 version for Android. +struct sigcontext { + uint32_t gregs[19]; + void* fpregs; + uint32_t oldmask; + uint32_t cr2; +}; + +typedef uint32_t __sigset_t; +typedef struct sigcontext mcontext_t; +typedef struct ucontext { + uint32_t uc_flags; + struct ucontext* uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + __sigset_t uc_sigmask; +} ucontext_t; +enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 }; #endif @@ -1076,6 +1074,9 @@ class SignalSender : public Thread { vm_tgid_(getpid()), interval_(interval) {} + static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } + static void TearDown() { delete mutex_; } + static void InstallSignalHandler() { struct sigaction sa; sa.sa_sigaction = ProfilerSignalHandler; @@ -1093,7 +1094,7 @@ class SignalSender : public Thread { } static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::AddActiveSampler(sampler); if (instance_ == NULL) { // Start a thread that will send SIGPROF signal to VM threads, @@ -1106,7 +1107,7 @@ class SignalSender : public Thread { } static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::RemoveActiveSampler(sampler); if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_); @@ -1209,7 +1210,7 @@ class SignalSender : public Thread { RuntimeProfilerRateLimiter rate_limiter_; // Protects the process wide state below. - static LazyMutex mutex_; + static Mutex* mutex_; static SignalSender* instance_; static bool signal_handler_installed_; static struct sigaction old_signal_handler_; @@ -1219,12 +1220,46 @@ class SignalSender : public Thread { }; -LazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER; +Mutex* SignalSender::mutex_ = NULL; SignalSender* SignalSender::instance_ = NULL; struct sigaction SignalSender::old_signal_handler_; bool SignalSender::signal_handler_installed_ = false; +void OS::SetUp() { + // Seed the random number generator. We preserve microsecond resolution. + uint64_t seed = Ticks() ^ (getpid() << 16); + srandom(static_cast<unsigned int>(seed)); + limit_mutex = CreateMutex(); + +#ifdef __arm__ + // When running on ARM hardware check that the EABI used by V8 and + // by the C code is the same. + bool hard_float = OS::ArmUsingHardFloat(); + if (hard_float) { +#if !USE_EABI_HARDFLOAT + PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without " + "-DUSE_EABI_HARDFLOAT\n"); + exit(1); +#endif + } else { +#if USE_EABI_HARDFLOAT + PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with " + "-DUSE_EABI_HARDFLOAT\n"); + exit(1); +#endif + } +#endif + SignalSender::SetUp(); +} + + +void OS::TearDown() { + SignalSender::TearDown(); + delete limit_mutex; +} + + Sampler::Sampler(Isolate* isolate, int interval) : isolate_(isolate), interval_(interval), diff --git a/deps/v8/src/platform-macos.cc b/deps/v8/src/platform-macos.cc index bfcaab0b51..a937ed3a5c 100644 --- a/deps/v8/src/platform-macos.cc +++ b/deps/v8/src/platform-macos.cc @@ -58,6 +58,7 @@ #include "v8.h" +#include "platform-posix.h" #include "platform.h" #include "vm-state-inl.h" @@ -93,11 +94,8 @@ double ceiling(double x) { static Mutex* limit_mutex = NULL; -void OS::SetUp() { - // Seed the random number generator. We preserve microsecond resolution. - uint64_t seed = Ticks() ^ (getpid() << 16); - srandom(static_cast<unsigned int>(seed)); - limit_mutex = CreateMutex(); +void OS::PostSetUp() { + POSIXPostSetUp(); } @@ -745,8 +743,11 @@ class SamplerThread : public Thread { : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), interval_(interval) {} + static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } + static void TearDown() { delete mutex_; } + static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::AddActiveSampler(sampler); if (instance_ == NULL) { instance_ = new SamplerThread(sampler->interval()); @@ -757,7 +758,7 @@ class SamplerThread : public Thread { } static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::RemoveActiveSampler(sampler); if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_); @@ -854,7 +855,7 @@ class SamplerThread : public Thread { RuntimeProfilerRateLimiter rate_limiter_; // Protects the process wide state below. - static LazyMutex mutex_; + static Mutex* mutex_; static SamplerThread* instance_; private: @@ -864,10 +865,25 @@ class SamplerThread : public Thread { #undef REGISTER_FIELD -LazyMutex SamplerThread::mutex_ = LAZY_MUTEX_INITIALIZER; +Mutex* SamplerThread::mutex_ = NULL; SamplerThread* SamplerThread::instance_ = NULL; +void OS::SetUp() { + // Seed the random number generator. We preserve microsecond resolution. + uint64_t seed = Ticks() ^ (getpid() << 16); + srandom(static_cast<unsigned int>(seed)); + limit_mutex = CreateMutex(); + SamplerThread::SetUp(); +} + + +void OS::TearDown() { + SamplerThread::TearDown(); + delete limit_mutex; +} + + Sampler::Sampler(Isolate* isolate, int interval) : isolate_(isolate), interval_(interval), diff --git a/deps/v8/src/platform-nullos.cc b/deps/v8/src/platform-nullos.cc index e05345c80a..679ef8e89e 100644 --- a/deps/v8/src/platform-nullos.cc +++ b/deps/v8/src/platform-nullos.cc @@ -86,6 +86,16 @@ void OS::SetUp() { } +void OS::PostSetUp() { + UNIMPLEMENTED(); +} + + +void OS::TearDown() { + UNIMPLEMENTED(); +} + + // Returns the accumulated user time for thread. int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { UNIMPLEMENTED(); diff --git a/deps/v8/src/platform-openbsd.cc b/deps/v8/src/platform-openbsd.cc index b79cb71a50..ba33a8444e 100644 --- a/deps/v8/src/platform-openbsd.cc +++ b/deps/v8/src/platform-openbsd.cc @@ -51,6 +51,7 @@ #include "v8.h" +#include "platform-posix.h" #include "platform.h" #include "v8threads.h" #include "vm-state-inl.h" @@ -99,11 +100,8 @@ static void* GetRandomMmapAddr() { } -void OS::SetUp() { - // Seed the random number generator. We preserve microsecond resolution. - uint64_t seed = Ticks() ^ (getpid() << 16); - srandom(static_cast<unsigned int>(seed)); - limit_mutex = CreateMutex(); +void OS::PostSetUp() { + POSIXPostSetUp(); } @@ -795,6 +793,9 @@ class SignalSender : public Thread { vm_tgid_(getpid()), interval_(interval) {} + static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } + static void TearDown() { delete mutex_; } + static void InstallSignalHandler() { struct sigaction sa; sa.sa_sigaction = ProfilerSignalHandler; @@ -812,7 +813,7 @@ class SignalSender : public Thread { } static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::AddActiveSampler(sampler); if (instance_ == NULL) { // Start a thread that will send SIGPROF signal to VM threads, @@ -825,7 +826,7 @@ class SignalSender : public Thread { } static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::RemoveActiveSampler(sampler); if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_); @@ -919,7 +920,7 @@ class SignalSender : public Thread { RuntimeProfilerRateLimiter rate_limiter_; // Protects the process wide state below. - static LazyMutex mutex_; + static Mutex* mutex_; static SignalSender* instance_; static bool signal_handler_installed_; static struct sigaction old_signal_handler_; @@ -929,12 +930,27 @@ class SignalSender : public Thread { }; -LazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER; +Mutex* SignalSender::mutex_ = NULL; SignalSender* SignalSender::instance_ = NULL; struct sigaction SignalSender::old_signal_handler_; bool SignalSender::signal_handler_installed_ = false; +void OS::SetUp() { + // Seed the random number generator. We preserve microsecond resolution. + uint64_t seed = Ticks() ^ (getpid() << 16); + srandom(static_cast<unsigned int>(seed)); + limit_mutex = CreateMutex(); + SignalSender::SetUp(); +} + + +void OS::TearDown() { + SignalSender::TearDown(); + delete limit_mutex; +} + + Sampler::Sampler(Isolate* isolate, int interval) : isolate_(isolate), interval_(interval), diff --git a/deps/v8/src/platform-posix.cc b/deps/v8/src/platform-posix.cc index 1f87e70972..66316594c8 100644 --- a/deps/v8/src/platform-posix.cc +++ b/deps/v8/src/platform-posix.cc @@ -29,6 +29,8 @@ // own but contains the parts which are the same across POSIX platforms Linux, // Mac OS, FreeBSD and OpenBSD. +#include "platform-posix.h" + #include <unistd.h> #include <errno.h> #include <time.h> @@ -129,13 +131,10 @@ double modulo(double x, double y) { #define UNARY_MATH_FUNCTION(name, generator) \ static UnaryMathFunction fast_##name##_function = NULL; \ -V8_DECLARE_ONCE(fast_##name##_init_once); \ void init_fast_##name##_function() { \ fast_##name##_function = generator; \ } \ double fast_##name(double x) { \ - CallOnce(&fast_##name##_init_once, \ - &init_fast_##name##_function); \ return (*fast_##name##_function)(x); \ } @@ -305,20 +304,11 @@ int OS::VSNPrintF(Vector<char> str, #if defined(V8_TARGET_ARCH_IA32) static OS::MemCopyFunction memcopy_function = NULL; -static LazyMutex memcopy_function_mutex = LAZY_MUTEX_INITIALIZER; // Defined in codegen-ia32.cc. OS::MemCopyFunction CreateMemCopyFunction(); // Copy memory area to disjoint memory area. void OS::MemCopy(void* dest, const void* src, size_t size) { - if (memcopy_function == NULL) { - ScopedLock lock(memcopy_function_mutex.Pointer()); - if (memcopy_function == NULL) { - OS::MemCopyFunction temp = CreateMemCopyFunction(); - MemoryBarrier(); - memcopy_function = temp; - } - } // Note: here we rely on dependent reads being ordered. This is true // on all architectures we currently support. (*memcopy_function)(dest, src, size); @@ -328,6 +318,18 @@ void OS::MemCopy(void* dest, const void* src, size_t size) { } #endif // V8_TARGET_ARCH_IA32 + +void POSIXPostSetUp() { +#if defined(V8_TARGET_ARCH_IA32) + memcopy_function = CreateMemCopyFunction(); +#endif + init_fast_sin_function(); + init_fast_cos_function(); + init_fast_tan_function(); + init_fast_log_function(); + init_fast_sqrt_function(); +} + // ---------------------------------------------------------------------------- // POSIX string support. // @@ -419,11 +421,7 @@ Socket* POSIXSocket::Accept() const { return NULL; } - int socket; - do - socket = accept(socket_, NULL, NULL); - while (socket == -1 && errno == EINTR); - + int socket = accept(socket_, NULL, NULL); if (socket == -1) { return NULL; } else { @@ -450,10 +448,7 @@ bool POSIXSocket::Connect(const char* host, const char* port) { } // Connect. - do - status = connect(socket_, result->ai_addr, result->ai_addrlen); - while (status == -1 && errno == EINTR); - + status = connect(socket_, result->ai_addr, result->ai_addrlen); freeaddrinfo(result); return status == 0; } @@ -472,32 +467,13 @@ bool POSIXSocket::Shutdown() { int POSIXSocket::Send(const char* data, int len) const { - int written; - - for (written = 0; written < len; /* empty */) { - int status = send(socket_, data + written, len - written, 0); - if (status == 0) { - break; - } else if (status > 0) { - written += status; - } else if (errno == EINTR) { - /* interrupted by signal, retry */ - } else { - return -1; - } - } - - return written; + int status = send(socket_, data, len, 0); + return status; } int POSIXSocket::Receive(char* data, int len) const { - int status; - - do - status = recv(socket_, data, len, 0); - while (status == -1 && errno == EINTR); - + int status = recv(socket_, data, len, 0); return status; } diff --git a/deps/v8/src/platform-posix.h b/deps/v8/src/platform-posix.h new file mode 100644 index 0000000000..7a982ed2ef --- /dev/null +++ b/deps/v8/src/platform-posix.h @@ -0,0 +1,39 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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 V8_PLATFORM_POSIX_H_ +#define V8_PLATFORM_POSIX_H_ + +namespace v8 { +namespace internal { + +// Used by platform implementation files during OS::PostSetUp(). +void POSIXPostSetUp(); + +} } // namespace v8::internal + +#endif // V8_PLATFORM_POSIX_H_ diff --git a/deps/v8/src/platform-solaris.cc b/deps/v8/src/platform-solaris.cc index 50ad353392..4248ea214f 100644 --- a/deps/v8/src/platform-solaris.cc +++ b/deps/v8/src/platform-solaris.cc @@ -52,6 +52,7 @@ #include "v8.h" +#include "platform-posix.h" #include "platform.h" #include "v8threads.h" #include "vm-state-inl.h" @@ -90,15 +91,10 @@ double ceiling(double x) { static Mutex* limit_mutex = NULL; -void OS::SetUp() { - // Seed the random number generator. - // Convert the current time to a 64-bit integer first, before converting it - // to an unsigned. Going directly will cause an overflow and the seed to be - // set to all ones. The seed will be identical for different instances that - // call this setup code within the same millisecond. - uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); - srandom(static_cast<unsigned int>(seed)); - limit_mutex = CreateMutex(); + + +void OS::PostSetUp() { + POSIXPostSetUp(); } @@ -491,12 +487,10 @@ void Thread::set_name(const char* name) { void Thread::Start() { - pthread_attr_t* attr_ptr = NULL; pthread_attr_t attr; if (stack_size_ > 0) { pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_)); - attr_ptr = &attr; } pthread_create(&data_->thread_, NULL, ThreadEntry, this); ASSERT(data_->thread_ != kNoThread); @@ -716,6 +710,9 @@ class SignalSender : public Thread { : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)), interval_(interval) {} + static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } + static void TearDown() { delete mutex_; } + static void InstallSignalHandler() { struct sigaction sa; sa.sa_sigaction = ProfilerSignalHandler; @@ -733,7 +730,7 @@ class SignalSender : public Thread { } static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::AddActiveSampler(sampler); if (instance_ == NULL) { // Start a thread that will send SIGPROF signal to VM threads, @@ -746,7 +743,7 @@ class SignalSender : public Thread { } static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::RemoveActiveSampler(sampler); if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_); @@ -840,7 +837,7 @@ class SignalSender : public Thread { RuntimeProfilerRateLimiter rate_limiter_; // Protects the process wide state below. - static LazyMutex mutex_; + static Mutex* mutex_; static SignalSender* instance_; static bool signal_handler_installed_; static struct sigaction old_signal_handler_; @@ -849,12 +846,31 @@ class SignalSender : public Thread { DISALLOW_COPY_AND_ASSIGN(SignalSender); }; -LazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER; +Mutex* SignalSender::mutex_ = NULL; SignalSender* SignalSender::instance_ = NULL; struct sigaction SignalSender::old_signal_handler_; bool SignalSender::signal_handler_installed_ = false; +void OS::SetUp() { + // Seed the random number generator. + // Convert the current time to a 64-bit integer first, before converting it + // to an unsigned. Going directly will cause an overflow and the seed to be + // set to all ones. The seed will be identical for different instances that + // call this setup code within the same millisecond. + uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); + srandom(static_cast<unsigned int>(seed)); + limit_mutex = CreateMutex(); + SignalSender::SetUp(); +} + + +void OS::TearDown() { + SignalSender::TearDown(); + delete limit_mutex; +} + + Sampler::Sampler(Isolate* isolate, int interval) : isolate_(isolate), interval_(interval), diff --git a/deps/v8/src/platform-win32.cc b/deps/v8/src/platform-win32.cc index 2801b711bf..9e377a1977 100644 --- a/deps/v8/src/platform-win32.cc +++ b/deps/v8/src/platform-win32.cc @@ -51,6 +51,22 @@ int strncasecmp(const char* s1, const char* s2, int n) { // the Microsoft Visual Studio C++ CRT. #ifdef __MINGW32__ + +#ifndef __MINGW64_VERSION_MAJOR + +#define _TRUNCATE 0 +#define STRUNCATE 80 + +inline void MemoryBarrier() { + int barrier = 0; + __asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier)); +} + +#endif // __MINGW64_VERSION_MAJOR + + +#ifndef MINGW_HAS_SECURE_API + int localtime_s(tm* out_tm, const time_t* time) { tm* posix_local_time_struct = localtime(time); if (posix_local_time_struct == NULL) return 1; @@ -64,21 +80,6 @@ int fopen_s(FILE** pFile, const char* filename, const char* mode) { return *pFile != NULL ? 0 : 1; } - -#ifndef __MINGW64_VERSION_MAJOR - -// Not sure this the correct interpretation of _mkgmtime -time_t _mkgmtime(tm* timeptr) { - return mktime(timeptr); -} - - -#define _TRUNCATE 0 -#define STRUNCATE 80 - -#endif // __MINGW64_VERSION_MAJOR - - int _vsnprintf_s(char* buffer, size_t sizeOfBuffer, size_t count, const char* format, va_list argptr) { ASSERT(count == _TRUNCATE); @@ -112,16 +113,7 @@ int strncpy_s(char* dest, size_t dest_size, const char* source, size_t count) { return 0; } - -#ifndef __MINGW64_VERSION_MAJOR - -inline void MemoryBarrier() { - int barrier = 0; - __asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier)); -} - -#endif // __MINGW64_VERSION_MAJOR - +#endif // MINGW_HAS_SECURE_API #endif // __MINGW32__ @@ -149,20 +141,11 @@ static Mutex* limit_mutex = NULL; #if defined(V8_TARGET_ARCH_IA32) static OS::MemCopyFunction memcopy_function = NULL; -static LazyMutex memcopy_function_mutex = LAZY_MUTEX_INITIALIZER; // Defined in codegen-ia32.cc. OS::MemCopyFunction CreateMemCopyFunction(); // Copy memory area to disjoint memory area. void OS::MemCopy(void* dest, const void* src, size_t size) { - if (memcopy_function == NULL) { - ScopedLock lock(memcopy_function_mutex.Pointer()); - if (memcopy_function == NULL) { - OS::MemCopyFunction temp = CreateMemCopyFunction(); - MemoryBarrier(); - memcopy_function = temp; - } - } // Note: here we rely on dependent reads being ordered. This is true // on all architectures we currently support. (*memcopy_function)(dest, src, size); @@ -175,7 +158,6 @@ void OS::MemCopy(void* dest, const void* src, size_t size) { #ifdef _WIN64 typedef double (*ModuloFunction)(double, double); static ModuloFunction modulo_function = NULL; -V8_DECLARE_ONCE(modulo_function_init_once); // Defined in codegen-x64.cc. ModuloFunction CreateModuloFunction(); @@ -184,7 +166,6 @@ void init_modulo_function() { } double modulo(double x, double y) { - CallOnce(&modulo_function_init_once, &init_modulo_function); // Note: here we rely on dependent reads being ordered. This is true // on all architectures we currently support. return (*modulo_function)(x, y); @@ -207,13 +188,10 @@ double modulo(double x, double y) { #define UNARY_MATH_FUNCTION(name, generator) \ static UnaryMathFunction fast_##name##_function = NULL; \ -V8_DECLARE_ONCE(fast_##name##_init_once); \ void init_fast_##name##_function() { \ fast_##name##_function = generator; \ } \ double fast_##name(double x) { \ - CallOnce(&fast_##name##_init_once, \ - &init_fast_##name##_function); \ return (*fast_##name##_function)(x); \ } @@ -226,6 +204,18 @@ UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) #undef MATH_FUNCTION +void MathSetup() { +#ifdef _WIN64 + init_modulo_function(); +#endif + init_fast_sin_function(); + init_fast_cos_function(); + init_fast_tan_function(); + init_fast_log_function(); + init_fast_sqrt_function(); +} + + // ---------------------------------------------------------------------------- // The Time class represents time on win32. A timestamp is represented as // a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript @@ -470,6 +460,9 @@ void Time::SetToCurrentTime() { // Check if we need to resync due to elapsed time. needs_resync |= (time_now.t_ - init_time.t_) > kMaxClockElapsedTime; + // Check if we need to resync due to backwards time change. + needs_resync |= time_now.t_ < init_time.t_; + // Resync the clock if necessary. if (needs_resync) { GetSystemTimeAsFileTime(&init_time.ft_); @@ -511,11 +504,14 @@ int64_t Time::LocalOffset() { // Convert to local time, as struct with fields for day, hour, year, etc. tm posix_local_time_struct; if (localtime_s(&posix_local_time_struct, &posix_time)) return 0; - // Convert local time in struct to POSIX time as if it were a UTC time. - time_t local_posix_time = _mkgmtime(&posix_local_time_struct); - Time localtime(1000.0 * local_posix_time); - return localtime.Diff(&rounded_to_second); + if (posix_local_time_struct.tm_isdst > 0) { + return (tzinfo_.Bias + tzinfo_.DaylightBias) * -kMsPerMinute; + } else if (posix_local_time_struct.tm_isdst == 0) { + return (tzinfo_.Bias + tzinfo_.StandardBias) * -kMsPerMinute; + } else { + return tzinfo_.Bias * -kMsPerMinute; + } } @@ -558,15 +554,13 @@ char* Time::LocalTimezone() { } -void OS::SetUp() { - // Seed the random number generator. - // Convert the current time to a 64-bit integer first, before converting it - // to an unsigned. Going directly can cause an overflow and the seed to be - // set to all ones. The seed will be identical for different instances that - // call this setup code within the same millisecond. - uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); - srand(static_cast<unsigned int>(seed)); - limit_mutex = CreateMutex(); +void OS::PostSetUp() { + // Math functions depend on CPU features therefore they are initialized after + // CPU. + MathSetup(); +#if defined(V8_TARGET_ARCH_IA32) + memcopy_function = CreateMemCopyFunction(); +#endif } @@ -1955,8 +1949,11 @@ class SamplerThread : public Thread { : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), interval_(interval) {} + static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } + static void TearDown() { delete mutex_; } + static void AddActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::AddActiveSampler(sampler); if (instance_ == NULL) { instance_ = new SamplerThread(sampler->interval()); @@ -1967,7 +1964,7 @@ class SamplerThread : public Thread { } static void RemoveActiveSampler(Sampler* sampler) { - ScopedLock lock(mutex_.Pointer()); + ScopedLock lock(mutex_); SamplerRegistry::RemoveActiveSampler(sampler); if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_); @@ -2053,7 +2050,7 @@ class SamplerThread : public Thread { RuntimeProfilerRateLimiter rate_limiter_; // Protects the process wide state below. - static LazyMutex mutex_; + static Mutex* mutex_; static SamplerThread* instance_; private: @@ -2061,10 +2058,29 @@ class SamplerThread : public Thread { }; -LazyMutex SamplerThread::mutex_ = LAZY_MUTEX_INITIALIZER; +Mutex* SamplerThread::mutex_ = NULL; SamplerThread* SamplerThread::instance_ = NULL; +void OS::SetUp() { + // Seed the random number generator. + // Convert the current time to a 64-bit integer first, before converting it + // to an unsigned. Going directly can cause an overflow and the seed to be + // set to all ones. The seed will be identical for different instances that + // call this setup code within the same millisecond. + uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); + srand(static_cast<unsigned int>(seed)); + limit_mutex = CreateMutex(); + SamplerThread::SetUp(); +} + + +void OS::TearDown() { + SamplerThread::TearDown(); + delete limit_mutex; +} + + Sampler::Sampler(Isolate* isolate, int interval) : isolate_(isolate), interval_(interval), diff --git a/deps/v8/src/platform.h b/deps/v8/src/platform.h index 4ec6057c5d..168791a0a4 100644 --- a/deps/v8/src/platform.h +++ b/deps/v8/src/platform.h @@ -119,6 +119,13 @@ class OS { // Initializes the platform OS support. Called once at VM startup. static void SetUp(); + // Initializes the platform OS support that depend on CPU features. This is + // called after CPU initialization. + static void PostSetUp(); + + // Clean up platform-OS-related things. Called once at VM shutdown. + static void TearDown(); + // Returns the accumulated user time for thread. This routine // can be used for profiling. The implementation should // strive for high-precision timer resolution, preferable @@ -545,7 +552,8 @@ struct CreateMutexTrait { // // Do something. // } // -typedef LazyDynamicInstance<Mutex, CreateMutexTrait>::type LazyMutex; +typedef LazyDynamicInstance< + Mutex, CreateMutexTrait, ThreadSafeInitOnceTrait>::type LazyMutex; #define LAZY_MUTEX_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER @@ -616,7 +624,8 @@ struct CreateSemaphoreTrait { template <int InitialValue> struct LazySemaphore { typedef typename LazyDynamicInstance< - Semaphore, CreateSemaphoreTrait<InitialValue> >::type type; + Semaphore, CreateSemaphoreTrait<InitialValue>, + ThreadSafeInitOnceTrait>::type type; }; #define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER diff --git a/deps/v8/src/preparser.cc b/deps/v8/src/preparser.cc index 20d3b9c59c..0c17eecd6a 100644 --- a/deps/v8/src/preparser.cc +++ b/deps/v8/src/preparser.cc @@ -581,9 +581,8 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) { ParseExpression(true, CHECK_OK); Expect(i::Token::RPAREN, CHECK_OK); - scope_->EnterWith(); + Scope::InsideWith iw(scope_); ParseStatement(CHECK_OK); - scope_->LeaveWith(); return Statement::Default(); } @@ -749,10 +748,9 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) { return Statement::Default(); } Expect(i::Token::RPAREN, CHECK_OK); - scope_->EnterWith(); - ParseBlock(ok); - scope_->LeaveWith(); - if (!*ok) Statement::Default(); + { Scope::InsideWith iw(scope_); + ParseBlock(CHECK_OK); + } catch_or_finally_seen = true; } if (peek() == i::Token::FINALLY) { diff --git a/deps/v8/src/preparser.h b/deps/v8/src/preparser.h index f3a43475df..13261f7a5b 100644 --- a/deps/v8/src/preparser.h +++ b/deps/v8/src/preparser.h @@ -470,8 +470,19 @@ class PreParser { void set_language_mode(i::LanguageMode language_mode) { language_mode_ = language_mode; } - void EnterWith() { with_nesting_count_++; } - void LeaveWith() { with_nesting_count_--; } + + class InsideWith { + public: + explicit InsideWith(Scope* scope) : scope_(scope) { + scope->with_nesting_count_++; + } + + ~InsideWith() { scope_->with_nesting_count_--; } + + private: + Scope* scope_; + DISALLOW_COPY_AND_ASSIGN(InsideWith); + }; private: Scope** const variable_; diff --git a/deps/v8/src/profile-generator-inl.h b/deps/v8/src/profile-generator-inl.h index 65369befdf..9afc52fa08 100644 --- a/deps/v8/src/profile-generator-inl.h +++ b/deps/v8/src/profile-generator-inl.h @@ -95,6 +95,55 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { } +HeapEntry* HeapGraphEdge::from() const { + return &snapshot()->entries()[from_index_]; +} + + +HeapSnapshot* HeapGraphEdge::snapshot() const { + return to_entry_->snapshot(); +} + + +int HeapEntry::index() const { + return static_cast<int>(this - &snapshot_->entries().first()); +} + + +int HeapEntry::set_children_index(int index) { + children_index_ = index; + int next_index = index + children_count_; + children_count_ = 0; + return next_index; +} + + +int HeapEntry::set_retainers_index(int index) { + retainers_index_ = index; + int next_index = index + retainers_count_; + retainers_count_ = 0; + return next_index; +} + + +HeapGraphEdge** HeapEntry::children_arr() { + ASSERT(children_index_ >= 0); + return &snapshot_->children()[children_index_]; +} + + +HeapGraphEdge** HeapEntry::retainers_arr() { + ASSERT(retainers_index_ >= 0); + return &snapshot_->retainers()[retainers_index_]; +} + + +HeapEntry* HeapEntry::dominator() const { + ASSERT(dominator_ >= 0); + return &snapshot_->entries()[dominator_]; +} + + SnapshotObjectId HeapObjectsMap::GetNthGcSubrootId(int delta) { return kGcRootsFirstSubrootId + delta * kObjectIdStep; } diff --git a/deps/v8/src/profile-generator.cc b/deps/v8/src/profile-generator.cc index 2d0984ecbf..c03e526170 100644 --- a/deps/v8/src/profile-generator.cc +++ b/deps/v8/src/profile-generator.cc @@ -34,6 +34,7 @@ #include "scopeinfo.h" #include "unicode.h" #include "zone-inl.h" +#include "debug.h" namespace v8 { namespace internal { @@ -930,81 +931,71 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { } -void HeapGraphEdge::Init( - int child_index, Type type, const char* name, HeapEntry* to) { +HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to) + : type_(type), + from_index_(from), + to_index_(to), + name_(name) { ASSERT(type == kContextVariable - || type == kProperty - || type == kInternal - || type == kShortcut); - child_index_ = child_index; - type_ = type; - name_ = name; - to_ = to; + || type == kProperty + || type == kInternal + || type == kShortcut); } -void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) { +HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to) + : type_(type), + from_index_(from), + to_index_(to), + index_(index) { ASSERT(type == kElement || type == kHidden || type == kWeak); - child_index_ = child_index; - type_ = type; - index_ = index; - to_ = to; } -void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { - Init(child_index, kElement, index, to); +void HeapGraphEdge::ReplaceToIndexWithEntry(HeapSnapshot* snapshot) { + to_entry_ = &snapshot->entries()[to_index_]; } -HeapEntry* HeapGraphEdge::From() { - return reinterpret_cast<HeapEntry*>(this - child_index_) - 1; -} - +const int HeapEntry::kNoEntry = -1; -void HeapEntry::Init(HeapSnapshot* snapshot, +HeapEntry::HeapEntry(HeapSnapshot* snapshot, Type type, const char* name, SnapshotObjectId id, - int self_size, - int children_count, - int retainers_count) { - snapshot_ = snapshot; - type_ = type; - painted_ = false; - name_ = name; - self_size_ = self_size; - retained_size_ = 0; - children_count_ = children_count; - retainers_count_ = retainers_count; - dominator_ = NULL; - id_ = id; -} + int self_size) + : painted_(false), + user_reachable_(false), + dominator_(kNoEntry), + type_(type), + retainers_count_(0), + retainers_index_(-1), + children_count_(0), + children_index_(-1), + self_size_(self_size), + retained_size_(0), + id_(id), + snapshot_(snapshot), + name_(name) { } void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, - int child_index, const char* name, - HeapEntry* entry, - int retainer_index) { - children()[child_index].Init(child_index, type, name, entry); - entry->retainers()[retainer_index] = children_arr() + child_index; + HeapEntry* entry) { + HeapGraphEdge edge(type, name, this->index(), entry->index()); + snapshot_->edges().Add(edge); + ++children_count_; + ++entry->retainers_count_; } void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, - int child_index, int index, - HeapEntry* entry, - int retainer_index) { - children()[child_index].Init(child_index, type, index, entry); - entry->retainers()[retainer_index] = children_arr() + child_index; -} - - -void HeapEntry::SetUnidirElementReference( - int child_index, int index, HeapEntry* entry) { - children()[child_index].Init(child_index, index, entry); + HeapEntry* entry) { + HeapGraphEdge edge(type, index, this->index(), entry->index()); + snapshot_->edges().Add(edge); + ++children_count_; + ++entry->retainers_count_; } @@ -1015,7 +1006,8 @@ Handle<HeapObject> HeapEntry::GetHeapObject() { void HeapEntry::Print( const char* prefix, const char* edge_name, int max_depth, int indent) { - OS::Print("%6d %7d @%6llu %*c %s%s: ", + STATIC_CHECK(sizeof(unsigned) == sizeof(id())); + OS::Print("%6d %7d @%6u %*c %s%s: ", self_size(), retained_size(), id(), indent, ' ', prefix, edge_name); if (type() != kString) { @@ -1033,9 +1025,9 @@ void HeapEntry::Print( OS::Print("\"\n"); } if (--max_depth == 0) return; - Vector<HeapGraphEdge> ch = children(); + Vector<HeapGraphEdge*> ch = children(); for (int i = 0; i < ch.length(); ++i) { - HeapGraphEdge& edge = ch[i]; + HeapGraphEdge& edge = *ch[i]; const char* edge_prefix = ""; EmbeddedVector<char, 64> index; const char* edge_name = index.start(); @@ -1091,15 +1083,6 @@ const char* HeapEntry::TypeAsString() { } -size_t HeapEntry::EntriesSize(int entries_count, - int children_count, - int retainers_count) { - return sizeof(HeapEntry) * entries_count // NOLINT - + sizeof(HeapGraphEdge) * children_count // NOLINT - + sizeof(HeapGraphEdge*) * retainers_count; // NOLINT -} - - // It is very important to keep objects that form a heap snapshot // as small as possible. namespace { // Avoid littering the global namespace. @@ -1108,7 +1091,7 @@ template <size_t ptr_size> struct SnapshotSizeConstants; template <> struct SnapshotSizeConstants<4> { static const int kExpectedHeapGraphEdgeSize = 12; - static const int kExpectedHeapEntrySize = 32; + static const int kExpectedHeapEntrySize = 40; static const size_t kMaxSerializableSnapshotRawSize = 256 * MB; }; @@ -1129,11 +1112,10 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, type_(type), title_(title), uid_(uid), - root_entry_(NULL), - gc_roots_entry_(NULL), - natives_root_entry_(NULL), - raw_entries_(NULL), - entries_sorted_(false) { + root_index_(HeapEntry::kNoEntry), + gc_roots_index_(HeapEntry::kNoEntry), + natives_root_index_(HeapEntry::kNoEntry), + max_snapshot_js_object_id_(0) { STATIC_CHECK( sizeof(HeapGraphEdge) == SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize); @@ -1141,34 +1123,24 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, sizeof(HeapEntry) == SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize); for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) { - gc_subroot_entries_[i] = NULL; + gc_subroot_indexes_[i] = HeapEntry::kNoEntry; } } -HeapSnapshot::~HeapSnapshot() { - DeleteArray(raw_entries_); -} - - void HeapSnapshot::Delete() { collection_->RemoveSnapshot(this); delete this; } -void HeapSnapshot::AllocateEntries(int entries_count, - int children_count, - int retainers_count) { - ASSERT(raw_entries_ == NULL); - raw_entries_size_ = - HeapEntry::EntriesSize(entries_count, children_count, retainers_count); - raw_entries_ = NewArray<char>(raw_entries_size_); +void HeapSnapshot::RememberLastJSObjectId() { + max_snapshot_js_object_id_ = collection_->last_assigned_id(); } -static void HeapEntryClearPaint(HeapEntry** entry_ptr) { - (*entry_ptr)->clear_paint(); +static void HeapEntryClearPaint(HeapEntry* entry_ptr) { + entry_ptr->clear_paint(); } @@ -1177,96 +1149,102 @@ void HeapSnapshot::ClearPaint() { } -HeapEntry* HeapSnapshot::AddRootEntry(int children_count) { - ASSERT(root_entry_ == NULL); - return (root_entry_ = AddEntry(HeapEntry::kObject, - "", - HeapObjectsMap::kInternalRootObjectId, - 0, - children_count, - 0)); +HeapEntry* HeapSnapshot::AddRootEntry() { + ASSERT(root_index_ == HeapEntry::kNoEntry); + ASSERT(entries_.is_empty()); // Root entry must be the first one. + HeapEntry* entry = AddEntry(HeapEntry::kObject, + "", + HeapObjectsMap::kInternalRootObjectId, + 0); + root_index_ = entry->index(); + ASSERT(root_index_ == 0); + return entry; } -HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count, - int retainers_count) { - ASSERT(gc_roots_entry_ == NULL); - return (gc_roots_entry_ = AddEntry(HeapEntry::kObject, - "(GC roots)", - HeapObjectsMap::kGcRootsObjectId, - 0, - children_count, - retainers_count)); +HeapEntry* HeapSnapshot::AddGcRootsEntry() { + ASSERT(gc_roots_index_ == HeapEntry::kNoEntry); + HeapEntry* entry = AddEntry(HeapEntry::kObject, + "(GC roots)", + HeapObjectsMap::kGcRootsObjectId, + 0); + gc_roots_index_ = entry->index(); + return entry; } -HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag, - int children_count, - int retainers_count) { - ASSERT(gc_subroot_entries_[tag] == NULL); +HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) { + ASSERT(gc_subroot_indexes_[tag] == HeapEntry::kNoEntry); ASSERT(0 <= tag && tag < VisitorSynchronization::kNumberOfSyncTags); - return (gc_subroot_entries_[tag] = AddEntry( + HeapEntry* entry = AddEntry( HeapEntry::kObject, VisitorSynchronization::kTagNames[tag], HeapObjectsMap::GetNthGcSubrootId(tag), - 0, - children_count, - retainers_count)); + 0); + gc_subroot_indexes_[tag] = entry->index(); + return entry; } HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, const char* name, SnapshotObjectId id, - int size, - int children_count, - int retainers_count) { - HeapEntry* entry = GetNextEntryToInit(); - entry->Init(this, type, name, id, size, children_count, retainers_count); - return entry; + int size) { + HeapEntry entry(this, type, name, id, size); + entries_.Add(entry); + return &entries_.last(); +} + + +void HeapSnapshot::FillChildrenAndRetainers() { + ASSERT(children().is_empty()); + children().Allocate(edges().length()); + ASSERT(retainers().is_empty()); + retainers().Allocate(edges().length()); + int children_index = 0; + int retainers_index = 0; + for (int i = 0; i < entries().length(); ++i) { + HeapEntry* entry = &entries()[i]; + children_index = entry->set_children_index(children_index); + retainers_index = entry->set_retainers_index(retainers_index); + } + ASSERT(edges().length() == children_index); + ASSERT(edges().length() == retainers_index); + for (int i = 0; i < edges().length(); ++i) { + HeapGraphEdge* edge = &edges()[i]; + edge->ReplaceToIndexWithEntry(this); + edge->from()->add_child(edge); + edge->to()->add_retainer(edge); + } } void HeapSnapshot::SetDominatorsToSelf() { for (int i = 0; i < entries_.length(); ++i) { - HeapEntry* entry = entries_[i]; - if (entry->dominator() == NULL) entry->set_dominator(entry); + entries_[i].set_dominator(&entries_[i]); } } -HeapEntry* HeapSnapshot::GetNextEntryToInit() { - if (entries_.length() > 0) { - HeapEntry* last_entry = entries_.last(); - entries_.Add(reinterpret_cast<HeapEntry*>( - reinterpret_cast<char*>(last_entry) + last_entry->EntrySize())); - } else { - entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_)); +class FindEntryById { + public: + explicit FindEntryById(SnapshotObjectId id) : id_(id) { } + int operator()(HeapEntry* const* entry) { + if ((*entry)->id() == id_) return 0; + return (*entry)->id() < id_ ? -1 : 1; } - ASSERT(reinterpret_cast<char*>(entries_.last()) < - (raw_entries_ + raw_entries_size_)); - return entries_.last(); -} + private: + SnapshotObjectId id_; +}; HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) { List<HeapEntry*>* entries_by_id = GetSortedEntriesList(); - // Perform a binary search by id. - int low = 0; - int high = entries_by_id->length() - 1; - while (low <= high) { - int mid = - (static_cast<unsigned int>(low) + static_cast<unsigned int>(high)) >> 1; - SnapshotObjectId mid_id = entries_by_id->at(mid)->id(); - if (mid_id > id) - high = mid - 1; - else if (mid_id < id) - low = mid + 1; - else - return entries_by_id->at(mid); - } - return NULL; + int index = SortedListBSearch(*entries_by_id, FindEntryById(id)); + if (index == -1) + return NULL; + return entries_by_id->at(index); } @@ -1279,11 +1257,14 @@ static int SortByIds(const T* entry1_ptr, List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { - if (!entries_sorted_) { - entries_.Sort(SortByIds); - entries_sorted_ = true; + if (sorted_entries_.is_empty()) { + sorted_entries_.Allocate(entries_.length()); + for (int i = 0; i < entries_.length(); ++i) { + sorted_entries_[i] = &entries_[i]; + } + sorted_entries_.Sort(SortByIds); } - return &entries_; + return &sorted_entries_; } @@ -1292,6 +1273,22 @@ void HeapSnapshot::Print(int max_depth) { } +template<typename T, class P> +static size_t GetMemoryUsedByList(const List<T, P>& list) { + return list.capacity() * sizeof(T); +} + + +size_t HeapSnapshot::RawSnapshotSize() const { + return + GetMemoryUsedByList(entries_) + + GetMemoryUsedByList(edges_) + + GetMemoryUsedByList(children_) + + GetMemoryUsedByList(retainers_) + + GetMemoryUsedByList(sorted_entries_); +} + + // We split IDs on evens for embedder objects (see // HeapObjectsMap::GenerateId) and odds for native objects. const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1; @@ -1304,96 +1301,166 @@ const SnapshotObjectId HeapObjectsMap::kFirstAvailableObjectId = VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep; HeapObjectsMap::HeapObjectsMap() - : initial_fill_mode_(true), - next_id_(kFirstAvailableObjectId), - entries_map_(AddressesMatch), - entries_(new List<EntryInfo>()) { } - - -HeapObjectsMap::~HeapObjectsMap() { - delete entries_; + : next_id_(kFirstAvailableObjectId), + entries_map_(AddressesMatch) { + // This dummy element solves a problem with entries_map_. + // When we do lookup in HashMap we see no difference between two cases: + // it has an entry with NULL as the value or it has created + // a new entry on the fly with NULL as the default value. + // With such dummy element we have a guaranty that all entries_map_ entries + // will have the value field grater than 0. + // This fact is using in MoveObject method. + entries_.Add(EntryInfo(0, NULL, 0)); } void HeapObjectsMap::SnapshotGenerationFinished() { - initial_fill_mode_ = false; RemoveDeadEntries(); } -SnapshotObjectId HeapObjectsMap::FindObject(Address addr) { - if (!initial_fill_mode_) { - SnapshotObjectId existing = FindEntry(addr); - if (existing != 0) return existing; - } - SnapshotObjectId id = next_id_; - next_id_ += kObjectIdStep; - AddEntry(addr, id); - return id; -} - - void HeapObjectsMap::MoveObject(Address from, Address to) { + ASSERT(to != NULL); + ASSERT(from != NULL); if (from == to) return; - HashMap::Entry* entry = entries_map_.Lookup(from, AddressHash(from), false); - if (entry != NULL) { - void* value = entry->value; - entries_map_.Remove(from, AddressHash(from)); - if (to != NULL) { - entry = entries_map_.Lookup(to, AddressHash(to), true); - // We can have an entry at the new location, it is OK, as GC can overwrite - // dead objects with alive objects being moved. - entry->value = value; - } + void* from_value = entries_map_.Remove(from, AddressHash(from)); + if (from_value == NULL) return; + int from_entry_info_index = + static_cast<int>(reinterpret_cast<intptr_t>(from_value)); + entries_.at(from_entry_info_index).addr = to; + HashMap::Entry* to_entry = entries_map_.Lookup(to, AddressHash(to), true); + if (to_entry->value != NULL) { + int to_entry_info_index = + static_cast<int>(reinterpret_cast<intptr_t>(to_entry->value)); + // Without this operation we will have two EntryInfo's with the same + // value in addr field. It is bad because later at RemoveDeadEntries + // one of this entry will be removed with the corresponding entries_map_ + // entry. + entries_.at(to_entry_info_index).addr = NULL; } + to_entry->value = reinterpret_cast<void*>(from_entry_info_index); } -void HeapObjectsMap::AddEntry(Address addr, SnapshotObjectId id) { - HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true); - ASSERT(entry->value == NULL); - entry->value = reinterpret_cast<void*>(entries_->length()); - entries_->Add(EntryInfo(id)); +SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) { + HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false); + if (entry == NULL) return 0; + int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); + EntryInfo& entry_info = entries_.at(entry_index); + ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); + return entry_info.id; } -SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) { - HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false); - if (entry != NULL) { +SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr, + unsigned int size) { + ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); + HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true); + if (entry->value != NULL) { int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); - EntryInfo& entry_info = entries_->at(entry_index); + EntryInfo& entry_info = entries_.at(entry_index); entry_info.accessed = true; + entry_info.size = size; return entry_info.id; - } else { - return 0; } + entry->value = reinterpret_cast<void*>(entries_.length()); + SnapshotObjectId id = next_id_; + next_id_ += kObjectIdStep; + entries_.Add(EntryInfo(id, addr, size)); + ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); + return id; +} + + +void HeapObjectsMap::StopHeapObjectsTracking() { + time_intervals_.Clear(); +} + +void HeapObjectsMap::UpdateHeapObjectsMap() { + HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask, + "HeapSnapshotsCollection::UpdateHeapObjectsMap"); + HeapIterator iterator; + for (HeapObject* obj = iterator.next(); + obj != NULL; + obj = iterator.next()) { + FindOrAddEntry(obj->address(), obj->Size()); + } + RemoveDeadEntries(); +} + + +void HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) { + UpdateHeapObjectsMap(); + time_intervals_.Add(TimeInterval(next_id_)); + int prefered_chunk_size = stream->GetChunkSize(); + List<v8::HeapStatsUpdate> stats_buffer; + ASSERT(!entries_.is_empty()); + EntryInfo* entry_info = &entries_.first(); + EntryInfo* end_entry_info = &entries_.last() + 1; + for (int time_interval_index = 0; + time_interval_index < time_intervals_.length(); + ++time_interval_index) { + TimeInterval& time_interval = time_intervals_[time_interval_index]; + SnapshotObjectId time_interval_id = time_interval.id; + uint32_t entries_size = 0; + EntryInfo* start_entry_info = entry_info; + while (entry_info < end_entry_info && entry_info->id < time_interval_id) { + entries_size += entry_info->size; + ++entry_info; + } + uint32_t entries_count = + static_cast<uint32_t>(entry_info - start_entry_info); + if (time_interval.count != entries_count || + time_interval.size != entries_size) { + stats_buffer.Add(v8::HeapStatsUpdate( + time_interval_index, + time_interval.count = entries_count, + time_interval.size = entries_size)); + if (stats_buffer.length() >= prefered_chunk_size) { + OutputStream::WriteResult result = stream->WriteHeapStatsChunk( + &stats_buffer.first(), stats_buffer.length()); + if (result == OutputStream::kAbort) return; + stats_buffer.Clear(); + } + } + } + ASSERT(entry_info == end_entry_info); + if (!stats_buffer.is_empty()) { + OutputStream::WriteResult result = stream->WriteHeapStatsChunk( + &stats_buffer.first(), stats_buffer.length()); + if (result == OutputStream::kAbort) return; + } + stream->EndOfStream(); } void HeapObjectsMap::RemoveDeadEntries() { - List<EntryInfo>* new_entries = new List<EntryInfo>(); - List<void*> dead_entries; - for (HashMap::Entry* entry = entries_map_.Start(); - entry != NULL; - entry = entries_map_.Next(entry)) { - int entry_index = - static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); - EntryInfo& entry_info = entries_->at(entry_index); + ASSERT(entries_.length() > 0 && + entries_.at(0).id == 0 && + entries_.at(0).addr == NULL); + int first_free_entry = 1; + for (int i = 1; i < entries_.length(); ++i) { + EntryInfo& entry_info = entries_.at(i); if (entry_info.accessed) { - entry->value = reinterpret_cast<void*>(new_entries->length()); - new_entries->Add(EntryInfo(entry_info.id, false)); + if (first_free_entry != i) { + entries_.at(first_free_entry) = entry_info; + } + entries_.at(first_free_entry).accessed = false; + HashMap::Entry* entry = entries_map_.Lookup( + entry_info.addr, AddressHash(entry_info.addr), false); + ASSERT(entry); + entry->value = reinterpret_cast<void*>(first_free_entry); + ++first_free_entry; } else { - dead_entries.Add(entry->key); + if (entry_info.addr) { + entries_map_.Remove(entry_info.addr, AddressHash(entry_info.addr)); + } } } - for (int i = 0; i < dead_entries.length(); ++i) { - void* raw_entry = dead_entries[i]; - entries_map_.Remove( - raw_entry, AddressHash(reinterpret_cast<Address>(raw_entry))); - } - delete entries_; - entries_ = new_entries; + entries_.Rewind(first_free_entry); + ASSERT(static_cast<uint32_t>(entries_.length()) - 1 == + entries_map_.occupancy()); } @@ -1480,7 +1547,7 @@ Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById( for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { - if (ids_.FindObject(obj->address()) == id) { + if (ids_.FindEntry(obj->address()) == id) { ASSERT(object == NULL); object = obj; // Can't break -- kFilterUnreachable requires full heap traversal. @@ -1490,80 +1557,22 @@ Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById( } -HeapEntry* const HeapEntriesMap::kHeapEntryPlaceholder = - reinterpret_cast<HeapEntry*>(1); - HeapEntriesMap::HeapEntriesMap() - : entries_(HeapThingsMatch), - entries_count_(0), - total_children_count_(0), - total_retainers_count_(0) { + : entries_(HeapThingsMatch) { } -HeapEntriesMap::~HeapEntriesMap() { - for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) { - delete reinterpret_cast<EntryInfo*>(p->value); - } -} - - -void HeapEntriesMap::AllocateEntries() { - for (HashMap::Entry* p = entries_.Start(); - p != NULL; - p = entries_.Next(p)) { - EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value); - entry_info->entry = entry_info->allocator->AllocateEntry( - p->key, - entry_info->children_count, - entry_info->retainers_count); - ASSERT(entry_info->entry != NULL); - ASSERT(entry_info->entry != kHeapEntryPlaceholder); - entry_info->children_count = 0; - entry_info->retainers_count = 0; - } -} - - -HeapEntry* HeapEntriesMap::Map(HeapThing thing) { +int HeapEntriesMap::Map(HeapThing thing) { HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false); - if (cache_entry != NULL) { - EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value); - return entry_info->entry; - } else { - return NULL; - } + if (cache_entry == NULL) return HeapEntry::kNoEntry; + return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); } -void HeapEntriesMap::Pair( - HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry) { +void HeapEntriesMap::Pair(HeapThing thing, int entry) { HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true); ASSERT(cache_entry->value == NULL); - cache_entry->value = new EntryInfo(entry, allocator); - ++entries_count_; -} - - -void HeapEntriesMap::CountReference(HeapThing from, HeapThing to, - int* prev_children_count, - int* prev_retainers_count) { - HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), false); - HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false); - ASSERT(from_cache_entry != NULL); - ASSERT(to_cache_entry != NULL); - EntryInfo* from_entry_info = - reinterpret_cast<EntryInfo*>(from_cache_entry->value); - EntryInfo* to_entry_info = - reinterpret_cast<EntryInfo*>(to_cache_entry->value); - if (prev_children_count) - *prev_children_count = from_entry_info->children_count; - if (prev_retainers_count) - *prev_retainers_count = to_entry_info->retainers_count; - ++from_entry_info->children_count; - ++to_entry_info->retainers_count; - ++total_children_count_; - ++total_retainers_count_; + cache_entry->value = reinterpret_cast<void*>(static_cast<intptr_t>(entry)); } @@ -1580,20 +1589,14 @@ void HeapObjectsSet::Clear() { bool HeapObjectsSet::Contains(Object* obj) { if (!obj->IsHeapObject()) return false; HeapObject* object = HeapObject::cast(obj); - HashMap::Entry* cache_entry = - entries_.Lookup(object, HeapEntriesMap::Hash(object), false); - return cache_entry != NULL; + return entries_.Lookup(object, HeapEntriesMap::Hash(object), false) != NULL; } void HeapObjectsSet::Insert(Object* obj) { if (!obj->IsHeapObject()) return; HeapObject* object = HeapObject::cast(obj); - HashMap::Entry* cache_entry = - entries_.Lookup(object, HeapEntriesMap::Hash(object), true); - if (cache_entry->value == NULL) { - cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder; - } + entries_.Lookup(object, HeapEntriesMap::Hash(object), true); } @@ -1601,12 +1604,9 @@ const char* HeapObjectsSet::GetTag(Object* obj) { HeapObject* object = HeapObject::cast(obj); HashMap::Entry* cache_entry = entries_.Lookup(object, HeapEntriesMap::Hash(object), false); - if (cache_entry != NULL - && cache_entry->value != HeapEntriesMap::kHeapEntryPlaceholder) { - return reinterpret_cast<const char*>(cache_entry->value); - } else { - return NULL; - } + return cache_entry != NULL + ? reinterpret_cast<const char*>(cache_entry->value) + : NULL; } @@ -1648,126 +1648,83 @@ V8HeapExplorer::~V8HeapExplorer() { } -HeapEntry* V8HeapExplorer::AllocateEntry( - HeapThing ptr, int children_count, int retainers_count) { - return AddEntry( - reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count); +HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) { + return AddEntry(reinterpret_cast<HeapObject*>(ptr)); } -HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, - int children_count, - int retainers_count) { +HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { if (object == kInternalRootObject) { - ASSERT(retainers_count == 0); - return snapshot_->AddRootEntry(children_count); + snapshot_->AddRootEntry(); + return snapshot_->root(); } else if (object == kGcRootsObject) { - return snapshot_->AddGcRootsEntry(children_count, retainers_count); + HeapEntry* entry = snapshot_->AddGcRootsEntry(); + return entry; } else if (object >= kFirstGcSubrootObject && object < kLastGcSubrootObject) { - return snapshot_->AddGcSubrootEntry( - GetGcSubrootOrder(object), - children_count, - retainers_count); + HeapEntry* entry = snapshot_->AddGcSubrootEntry(GetGcSubrootOrder(object)); + return entry; } else if (object->IsJSFunction()) { JSFunction* func = JSFunction::cast(object); SharedFunctionInfo* shared = func->shared(); const char* name = shared->bound() ? "native_bind" : collection_->names()->GetName(String::cast(shared->name())); - return AddEntry(object, - HeapEntry::kClosure, - name, - children_count, - retainers_count); + return AddEntry(object, HeapEntry::kClosure, name); } else if (object->IsJSRegExp()) { JSRegExp* re = JSRegExp::cast(object); return AddEntry(object, HeapEntry::kRegExp, - collection_->names()->GetName(re->Pattern()), - children_count, - retainers_count); + collection_->names()->GetName(re->Pattern())); } else if (object->IsJSObject()) { - return AddEntry(object, - HeapEntry::kObject, - "", - children_count, - retainers_count); + const char* name = collection_->names()->GetName( + GetConstructorName(JSObject::cast(object))); + if (object->IsJSGlobalObject()) { + const char* tag = objects_tags_.GetTag(object); + if (tag != NULL) { + name = collection_->names()->GetFormatted("%s / %s", name, tag); + } + } + return AddEntry(object, HeapEntry::kObject, name); } else if (object->IsString()) { return AddEntry(object, HeapEntry::kString, - collection_->names()->GetName(String::cast(object)), - children_count, - retainers_count); + collection_->names()->GetName(String::cast(object))); } else if (object->IsCode()) { - return AddEntry(object, - HeapEntry::kCode, - "", - children_count, - retainers_count); + return AddEntry(object, HeapEntry::kCode, ""); } else if (object->IsSharedFunctionInfo()) { - SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); + String* name = String::cast(SharedFunctionInfo::cast(object)->name()); return AddEntry(object, HeapEntry::kCode, - collection_->names()->GetName(String::cast(shared->name())), - children_count, - retainers_count); + collection_->names()->GetName(name)); } else if (object->IsScript()) { - Script* script = Script::cast(object); + Object* name = Script::cast(object)->name(); return AddEntry(object, HeapEntry::kCode, - script->name()->IsString() ? - collection_->names()->GetName( - String::cast(script->name())) - : "", - children_count, - retainers_count); + name->IsString() + ? collection_->names()->GetName(String::cast(name)) + : ""); } else if (object->IsGlobalContext()) { - return AddEntry(object, - HeapEntry::kHidden, - "system / GlobalContext", - children_count, - retainers_count); + return AddEntry(object, HeapEntry::kHidden, "system / GlobalContext"); } else if (object->IsContext()) { - return AddEntry(object, - HeapEntry::kHidden, - "system / Context", - children_count, - retainers_count); + return AddEntry(object, HeapEntry::kHidden, "system / Context"); } else if (object->IsFixedArray() || object->IsFixedDoubleArray() || object->IsByteArray() || object->IsExternalArray()) { - const char* tag = objects_tags_.GetTag(object); - return AddEntry(object, - HeapEntry::kArray, - tag != NULL ? tag : "", - children_count, - retainers_count); + return AddEntry(object, HeapEntry::kArray, ""); } else if (object->IsHeapNumber()) { - return AddEntry(object, - HeapEntry::kHeapNumber, - "number", - children_count, - retainers_count); + return AddEntry(object, HeapEntry::kHeapNumber, "number"); } - return AddEntry(object, - HeapEntry::kHidden, - GetSystemEntryName(object), - children_count, - retainers_count); + return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object)); } HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, HeapEntry::Type type, - const char* name, - int children_count, - int retainers_count) { - return snapshot_->AddEntry(type, - name, - collection_->GetObjectId(object->address()), - object->Size(), - children_count, - retainers_count); + const char* name) { + int object_size = object->Size(); + SnapshotObjectId object_id = + collection_->GetObjectId(object->address(), object_size); + return snapshot_->AddEntry(type, name, object_id, object_size); } @@ -1836,10 +1793,10 @@ class IndexedReferencesExtractor : public ObjectVisitor { public: IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject* parent_obj, - HeapEntry* parent_entry) + int parent) : generator_(generator), parent_obj_(parent_obj), - parent_(parent_entry), + parent_(parent), next_index_(1) { } void VisitPointers(Object** start, Object** end) { @@ -1868,178 +1825,40 @@ class IndexedReferencesExtractor : public ObjectVisitor { } V8HeapExplorer* generator_; HeapObject* parent_obj_; - HeapEntry* parent_; + int parent_; int next_index_; }; void V8HeapExplorer::ExtractReferences(HeapObject* obj) { - HeapEntry* entry = GetEntry(obj); - if (entry == NULL) return; // No interest in this object. + HeapEntry* heap_entry = GetEntry(obj); + if (heap_entry == NULL) return; // No interest in this object. + int entry = heap_entry->index(); bool extract_indexed_refs = true; if (obj->IsJSGlobalProxy()) { - // We need to reference JS global objects from snapshot's root. - // We use JSGlobalProxy because this is what embedder (e.g. browser) - // uses for the global object. - JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); - SetRootShortcutReference(proxy->map()->prototype()); + ExtractJSGlobalProxyReferences(JSGlobalProxy::cast(obj)); } else if (obj->IsJSObject()) { - JSObject* js_obj = JSObject::cast(obj); - ExtractClosureReferences(js_obj, entry); - ExtractPropertyReferences(js_obj, entry); - ExtractElementReferences(js_obj, entry); - ExtractInternalReferences(js_obj, entry); - SetPropertyReference( - obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype()); - if (obj->IsJSFunction()) { - JSFunction* js_fun = JSFunction::cast(js_obj); - Object* proto_or_map = js_fun->prototype_or_initial_map(); - if (!proto_or_map->IsTheHole()) { - if (!proto_or_map->IsMap()) { - SetPropertyReference( - obj, entry, - heap_->prototype_symbol(), proto_or_map, - NULL, - JSFunction::kPrototypeOrInitialMapOffset); - } else { - SetPropertyReference( - obj, entry, - heap_->prototype_symbol(), js_fun->prototype()); - } - } - SharedFunctionInfo* shared_info = js_fun->shared(); - // JSFunction has either bindings or literals and never both. - bool bound = shared_info->bound(); - TagObject(js_fun->literals_or_bindings(), - bound ? "(function bindings)" : "(function literals)"); - SetInternalReference(js_fun, entry, - bound ? "bindings" : "literals", - js_fun->literals_or_bindings(), - JSFunction::kLiteralsOffset); - SetInternalReference(js_fun, entry, - "shared", shared_info, - JSFunction::kSharedFunctionInfoOffset); - TagObject(js_fun->unchecked_context(), "(context)"); - SetInternalReference(js_fun, entry, - "context", js_fun->unchecked_context(), - JSFunction::kContextOffset); - for (int i = JSFunction::kNonWeakFieldsEndOffset; - i < JSFunction::kSize; - i += kPointerSize) { - SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i); - } - } - TagObject(js_obj->properties(), "(object properties)"); - SetInternalReference(obj, entry, - "properties", js_obj->properties(), - JSObject::kPropertiesOffset); - TagObject(js_obj->elements(), "(object elements)"); - SetInternalReference(obj, entry, - "elements", js_obj->elements(), - JSObject::kElementsOffset); + ExtractJSObjectReferences(entry, JSObject::cast(obj)); } else if (obj->IsString()) { - if (obj->IsConsString()) { - ConsString* cs = ConsString::cast(obj); - SetInternalReference(obj, entry, 1, cs->first()); - SetInternalReference(obj, entry, 2, cs->second()); - } - if (obj->IsSlicedString()) { - SlicedString* ss = SlicedString::cast(obj); - SetInternalReference(obj, entry, "parent", ss->parent()); - } + ExtractStringReferences(entry, String::cast(obj)); extract_indexed_refs = false; - } else if (obj->IsGlobalContext()) { - Context* context = Context::cast(obj); - TagObject(context->jsfunction_result_caches(), - "(context func. result caches)"); - TagObject(context->normalized_map_cache(), "(context norm. map cache)"); - TagObject(context->runtime_context(), "(runtime context)"); - TagObject(context->data(), "(context data)"); - for (int i = Context::FIRST_WEAK_SLOT; - i < Context::GLOBAL_CONTEXT_SLOTS; - ++i) { - SetWeakReference(obj, entry, - i, context->get(i), - FixedArray::OffsetOfElementAt(i)); - } + } else if (obj->IsContext()) { + ExtractContextReferences(entry, Context::cast(obj)); } else if (obj->IsMap()) { - Map* map = Map::cast(obj); - SetInternalReference(obj, entry, - "prototype", map->prototype(), Map::kPrototypeOffset); - SetInternalReference(obj, entry, - "constructor", map->constructor(), - Map::kConstructorOffset); - if (!map->instance_descriptors()->IsEmpty()) { - TagObject(map->instance_descriptors(), "(map descriptors)"); - SetInternalReference(obj, entry, - "descriptors", map->instance_descriptors(), - Map::kInstanceDescriptorsOrBitField3Offset); - } - if (map->prototype_transitions() != heap_->empty_fixed_array()) { - TagObject(map->prototype_transitions(), "(prototype transitions)"); - SetInternalReference(obj, - entry, - "prototype_transitions", - map->prototype_transitions(), - Map::kPrototypeTransitionsOffset); - } - SetInternalReference(obj, entry, - "code_cache", map->code_cache(), - Map::kCodeCacheOffset); + ExtractMapReferences(entry, Map::cast(obj)); } else if (obj->IsSharedFunctionInfo()) { - SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); - SetInternalReference(obj, entry, - "name", shared->name(), - SharedFunctionInfo::kNameOffset); - SetInternalReference(obj, entry, - "code", shared->unchecked_code(), - SharedFunctionInfo::kCodeOffset); - TagObject(shared->scope_info(), "(function scope info)"); - SetInternalReference(obj, entry, - "scope_info", shared->scope_info(), - SharedFunctionInfo::kScopeInfoOffset); - SetInternalReference(obj, entry, - "instance_class_name", shared->instance_class_name(), - SharedFunctionInfo::kInstanceClassNameOffset); - SetInternalReference(obj, entry, - "script", shared->script(), - SharedFunctionInfo::kScriptOffset); - SetWeakReference(obj, entry, - 1, shared->initial_map(), - SharedFunctionInfo::kInitialMapOffset); + ExtractSharedFunctionInfoReferences(entry, SharedFunctionInfo::cast(obj)); } else if (obj->IsScript()) { - Script* script = Script::cast(obj); - SetInternalReference(obj, entry, - "source", script->source(), - Script::kSourceOffset); - SetInternalReference(obj, entry, - "name", script->name(), - Script::kNameOffset); - SetInternalReference(obj, entry, - "data", script->data(), - Script::kDataOffset); - SetInternalReference(obj, entry, - "context_data", script->context_data(), - Script::kContextOffset); - TagObject(script->line_ends(), "(script line ends)"); - SetInternalReference(obj, entry, - "line_ends", script->line_ends(), - Script::kLineEndsOffset); + ExtractScriptReferences(entry, Script::cast(obj)); } else if (obj->IsCodeCache()) { - CodeCache* code_cache = CodeCache::cast(obj); - TagObject(code_cache->default_cache(), "(default code cache)"); - SetInternalReference(obj, entry, - "default_cache", code_cache->default_cache(), - CodeCache::kDefaultCacheOffset); - TagObject(code_cache->normal_type_cache(), "(code type cache)"); - SetInternalReference(obj, entry, - "type_cache", code_cache->normal_type_cache(), - CodeCache::kNormalTypeCacheOffset); + ExtractCodeCacheReferences(entry, CodeCache::cast(obj)); } else if (obj->IsCode()) { - Code* code = Code::cast(obj); - TagObject(code->unchecked_relocation_info(), "(code relocation info)"); - TagObject(code->unchecked_deoptimization_data(), "(code deopt data)"); + ExtractCodeReferences(entry, Code::cast(obj)); + } else if (obj->IsJSGlobalPropertyCell()) { + ExtractJSGlobalPropertyCellReferences( + entry, JSGlobalPropertyCell::cast(obj)); + extract_indexed_refs = false; } if (extract_indexed_refs) { SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); @@ -2049,14 +1868,266 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { } -void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, - HeapEntry* entry) { +void V8HeapExplorer::ExtractJSGlobalProxyReferences(JSGlobalProxy* proxy) { + // We need to reference JS global objects from snapshot's root. + // We use JSGlobalProxy because this is what embedder (e.g. browser) + // uses for the global object. + Object* object = proxy->map()->prototype(); + bool is_debug_object = false; +#ifdef ENABLE_DEBUGGER_SUPPORT + is_debug_object = object->IsGlobalObject() && + Isolate::Current()->debug()->IsDebugGlobal(GlobalObject::cast(object)); +#endif + if (!is_debug_object) { + SetUserGlobalReference(object); + } +} + + +void V8HeapExplorer::ExtractJSObjectReferences( + int entry, JSObject* js_obj) { + HeapObject* obj = js_obj; + ExtractClosureReferences(js_obj, entry); + ExtractPropertyReferences(js_obj, entry); + ExtractElementReferences(js_obj, entry); + ExtractInternalReferences(js_obj, entry); + SetPropertyReference( + obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype()); + if (obj->IsJSFunction()) { + JSFunction* js_fun = JSFunction::cast(js_obj); + Object* proto_or_map = js_fun->prototype_or_initial_map(); + if (!proto_or_map->IsTheHole()) { + if (!proto_or_map->IsMap()) { + SetPropertyReference( + obj, entry, + heap_->prototype_symbol(), proto_or_map, + NULL, + JSFunction::kPrototypeOrInitialMapOffset); + } else { + SetPropertyReference( + obj, entry, + heap_->prototype_symbol(), js_fun->prototype()); + } + } + SharedFunctionInfo* shared_info = js_fun->shared(); + // JSFunction has either bindings or literals and never both. + bool bound = shared_info->bound(); + TagObject(js_fun->literals_or_bindings(), + bound ? "(function bindings)" : "(function literals)"); + SetInternalReference(js_fun, entry, + bound ? "bindings" : "literals", + js_fun->literals_or_bindings(), + JSFunction::kLiteralsOffset); + TagObject(shared_info, "(shared function info)"); + SetInternalReference(js_fun, entry, + "shared", shared_info, + JSFunction::kSharedFunctionInfoOffset); + TagObject(js_fun->unchecked_context(), "(context)"); + SetInternalReference(js_fun, entry, + "context", js_fun->unchecked_context(), + JSFunction::kContextOffset); + for (int i = JSFunction::kNonWeakFieldsEndOffset; + i < JSFunction::kSize; + i += kPointerSize) { + SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i); + } + } else if (obj->IsGlobalObject()) { + GlobalObject* global_obj = GlobalObject::cast(obj); + SetInternalReference(global_obj, entry, + "builtins", global_obj->builtins(), + GlobalObject::kBuiltinsOffset); + SetInternalReference(global_obj, entry, + "global_context", global_obj->global_context(), + GlobalObject::kGlobalContextOffset); + SetInternalReference(global_obj, entry, + "global_receiver", global_obj->global_receiver(), + GlobalObject::kGlobalReceiverOffset); + } + TagObject(js_obj->properties(), "(object properties)"); + SetInternalReference(obj, entry, + "properties", js_obj->properties(), + JSObject::kPropertiesOffset); + TagObject(js_obj->elements(), "(object elements)"); + SetInternalReference(obj, entry, + "elements", js_obj->elements(), + JSObject::kElementsOffset); +} + + +void V8HeapExplorer::ExtractStringReferences(int entry, String* string) { + if (string->IsConsString()) { + ConsString* cs = ConsString::cast(string); + SetInternalReference(cs, entry, "first", cs->first()); + SetInternalReference(cs, entry, "second", cs->second()); + } else if (string->IsSlicedString()) { + SlicedString* ss = SlicedString::cast(string); + SetInternalReference(ss, entry, "parent", ss->parent()); + } +} + + +void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { +#define EXTRACT_CONTEXT_FIELD(index, type, name) \ + SetInternalReference(context, entry, #name, context->get(Context::index), \ + FixedArray::OffsetOfElementAt(Context::index)); + EXTRACT_CONTEXT_FIELD(CLOSURE_INDEX, JSFunction, closure); + EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous); + EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension); + EXTRACT_CONTEXT_FIELD(GLOBAL_INDEX, GlobalObject, global); + if (context->IsGlobalContext()) { + TagObject(context->jsfunction_result_caches(), + "(context func. result caches)"); + TagObject(context->normalized_map_cache(), "(context norm. map cache)"); + TagObject(context->runtime_context(), "(runtime context)"); + TagObject(context->data(), "(context data)"); + GLOBAL_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD); +#undef EXTRACT_CONTEXT_FIELD + for (int i = Context::FIRST_WEAK_SLOT; + i < Context::GLOBAL_CONTEXT_SLOTS; + ++i) { + SetWeakReference(context, entry, i, context->get(i), + FixedArray::OffsetOfElementAt(i)); + } + } +} + + +void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { + SetInternalReference(map, entry, + "prototype", map->prototype(), Map::kPrototypeOffset); + SetInternalReference(map, entry, + "constructor", map->constructor(), + Map::kConstructorOffset); + if (!map->instance_descriptors()->IsEmpty()) { + TagObject(map->instance_descriptors(), "(map descriptors)"); + SetInternalReference(map, entry, + "descriptors", map->instance_descriptors(), + Map::kInstanceDescriptorsOrBitField3Offset); + } + if (map->unchecked_prototype_transitions()->IsFixedArray()) { + TagObject(map->prototype_transitions(), "(prototype transitions)"); + SetInternalReference(map, entry, + "prototype_transitions", map->prototype_transitions(), + Map::kPrototypeTransitionsOrBackPointerOffset); + } else { + SetInternalReference(map, entry, + "back_pointer", map->GetBackPointer(), + Map::kPrototypeTransitionsOrBackPointerOffset); + } + SetInternalReference(map, entry, + "code_cache", map->code_cache(), + Map::kCodeCacheOffset); +} + + +void V8HeapExplorer::ExtractSharedFunctionInfoReferences( + int entry, SharedFunctionInfo* shared) { + HeapObject* obj = shared; + SetInternalReference(obj, entry, + "name", shared->name(), + SharedFunctionInfo::kNameOffset); + TagObject(shared->code(), "(code)"); + SetInternalReference(obj, entry, + "code", shared->code(), + SharedFunctionInfo::kCodeOffset); + TagObject(shared->scope_info(), "(function scope info)"); + SetInternalReference(obj, entry, + "scope_info", shared->scope_info(), + SharedFunctionInfo::kScopeInfoOffset); + SetInternalReference(obj, entry, + "instance_class_name", shared->instance_class_name(), + SharedFunctionInfo::kInstanceClassNameOffset); + SetInternalReference(obj, entry, + "script", shared->script(), + SharedFunctionInfo::kScriptOffset); + TagObject(shared->construct_stub(), "(code)"); + SetInternalReference(obj, entry, + "construct_stub", shared->construct_stub(), + SharedFunctionInfo::kConstructStubOffset); + SetInternalReference(obj, entry, + "function_data", shared->function_data(), + SharedFunctionInfo::kFunctionDataOffset); + SetInternalReference(obj, entry, + "debug_info", shared->debug_info(), + SharedFunctionInfo::kDebugInfoOffset); + SetInternalReference(obj, entry, + "inferred_name", shared->inferred_name(), + SharedFunctionInfo::kInferredNameOffset); + SetInternalReference(obj, entry, + "this_property_assignments", + shared->this_property_assignments(), + SharedFunctionInfo::kThisPropertyAssignmentsOffset); + SetWeakReference(obj, entry, + 1, shared->initial_map(), + SharedFunctionInfo::kInitialMapOffset); +} + + +void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) { + HeapObject* obj = script; + SetInternalReference(obj, entry, + "source", script->source(), + Script::kSourceOffset); + SetInternalReference(obj, entry, + "name", script->name(), + Script::kNameOffset); + SetInternalReference(obj, entry, + "data", script->data(), + Script::kDataOffset); + SetInternalReference(obj, entry, + "context_data", script->context_data(), + Script::kContextOffset); + TagObject(script->line_ends(), "(script line ends)"); + SetInternalReference(obj, entry, + "line_ends", script->line_ends(), + Script::kLineEndsOffset); +} + + +void V8HeapExplorer::ExtractCodeCacheReferences( + int entry, CodeCache* code_cache) { + TagObject(code_cache->default_cache(), "(default code cache)"); + SetInternalReference(code_cache, entry, + "default_cache", code_cache->default_cache(), + CodeCache::kDefaultCacheOffset); + TagObject(code_cache->normal_type_cache(), "(code type cache)"); + SetInternalReference(code_cache, entry, + "type_cache", code_cache->normal_type_cache(), + CodeCache::kNormalTypeCacheOffset); +} + + +void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) { + TagObject(code->relocation_info(), "(code relocation info)"); + SetInternalReference(code, entry, + "relocation_info", code->relocation_info(), + Code::kRelocationInfoOffset); + SetInternalReference(code, entry, + "handler_table", code->handler_table(), + Code::kHandlerTableOffset); + TagObject(code->deoptimization_data(), "(code deopt data)"); + SetInternalReference(code, entry, + "deoptimization_data", code->deoptimization_data(), + Code::kDeoptimizationDataOffset); + SetInternalReference(code, entry, + "type_feedback_info", code->type_feedback_info(), + Code::kTypeFeedbackInfoOffset); + SetInternalReference(code, entry, + "gc_metadata", code->gc_metadata(), + Code::kGCMetadataOffset); +} + + +void V8HeapExplorer::ExtractJSGlobalPropertyCellReferences( + int entry, JSGlobalPropertyCell* cell) { + SetInternalReference(cell, entry, "value", cell->value()); +} + + +void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) { if (!js_obj->IsJSFunction()) return; JSFunction* func = JSFunction::cast(js_obj); - Context* context = func->context(); - ScopeInfo* scope_info = context->closure()->shared()->scope_info(); - if (func->shared()->bound()) { FixedArray* bindings = func->function_bindings(); SetNativeBindReference(js_obj, entry, "bound_this", @@ -2072,6 +2143,8 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, bindings->get(i)); } } else { + Context* context = func->context()->declaration_context(); + ScopeInfo* scope_info = context->closure()->shared()->scope_info(); // Add context allocated locals. int context_locals = scope_info->ContextLocalCount(); for (int i = 0; i < context_locals; ++i) { @@ -2083,19 +2156,17 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, // Add function variable. if (scope_info->HasFunctionName()) { String* name = scope_info->FunctionName(); - int idx = Context::MIN_CONTEXT_SLOTS + context_locals; -#ifdef DEBUG VariableMode mode; - ASSERT(idx == scope_info->FunctionContextSlotIndex(name, &mode)); -#endif - SetClosureReference(js_obj, entry, name, context->get(idx)); + int idx = scope_info->FunctionContextSlotIndex(name, &mode); + if (idx >= 0) { + SetClosureReference(js_obj, entry, name, context->get(idx)); + } } } } -void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, - HeapEntry* entry) { +void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { if (js_obj->HasFastProperties()) { DescriptorArray* descs = js_obj->map()->instance_descriptors(); for (int i = 0; i < descs->number_of_descriptors(); i++) { @@ -2152,15 +2223,15 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, Object* k = dictionary->KeyAt(i); if (dictionary->IsKey(k)) { Object* target = dictionary->ValueAt(i); - SetPropertyReference( - js_obj, entry, String::cast(k), target); // We assume that global objects can only have slow properties. - if (target->IsJSGlobalPropertyCell()) { - SetPropertyShortcutReference(js_obj, - entry, - String::cast(k), - JSGlobalPropertyCell::cast( - target)->value()); + Object* value = target->IsJSGlobalPropertyCell() + ? JSGlobalPropertyCell::cast(target)->value() + : target; + if (String::cast(k)->length() > 0) { + SetPropertyReference(js_obj, entry, String::cast(k), value); + } else { + TagObject(value, "(hidden properties)"); + SetInternalReference(js_obj, entry, "hidden_properties", value); } } } @@ -2168,8 +2239,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, } -void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, - HeapEntry* entry) { +void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) { if (js_obj->HasFastElements()) { FixedArray* elements = FixedArray::cast(js_obj->elements()); int length = js_obj->IsJSArray() ? @@ -2195,8 +2265,7 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, } -void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, - HeapEntry* entry) { +void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, int entry) { int length = js_obj->GetInternalFieldCount(); for (int i = 0; i < length; ++i) { Object* o = js_obj->GetInternalField(i); @@ -2322,6 +2391,7 @@ bool V8HeapExplorer::IterateAndExtractReferences( filler_ = NULL; return false; } + SetRootGcRootsReference(); RootsReferencesExtractor extractor; heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG); @@ -2329,148 +2399,127 @@ bool V8HeapExplorer::IterateAndExtractReferences( heap_->IterateRoots(&extractor, VISIT_ALL); extractor.FillReferences(this); filler_ = NULL; - return progress_->ProgressReport(false); -} - - -bool V8HeapExplorer::IterateAndSetObjectNames(SnapshotFillerInterface* filler) { - HeapIterator iterator(HeapIterator::kFilterUnreachable); - filler_ = filler; - for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { - SetObjectName(obj); - } - return true; + return progress_->ProgressReport(true); } -void V8HeapExplorer::SetObjectName(HeapObject* object) { - if (!object->IsJSObject() || object->IsJSRegExp() || object->IsJSFunction()) { - return; - } - const char* name = collection_->names()->GetName( - GetConstructorName(JSObject::cast(object))); - if (object->IsJSGlobalObject()) { - const char* tag = objects_tags_.GetTag(object); - if (tag != NULL) { - name = collection_->names()->GetFormatted("%s / %s", name, tag); - } - } - GetEntry(object)->set_name(name); +bool V8HeapExplorer::IsEssentialObject(Object* object) { + // We have to use raw_unchecked_* versions because checked versions + // would fail during iteration over object properties. + return object->IsHeapObject() + && !object->IsOddball() + && object != heap_->raw_unchecked_empty_byte_array() + && object != heap_->raw_unchecked_empty_fixed_array() + && object != heap_->raw_unchecked_empty_descriptor_array() + && object != heap_->raw_unchecked_fixed_array_map() + && object != heap_->raw_unchecked_global_property_cell_map() + && object != heap_->raw_unchecked_shared_function_info_map() + && object != heap_->raw_unchecked_free_space_map() + && object != heap_->raw_unchecked_one_pointer_filler_map() + && object != heap_->raw_unchecked_two_pointer_filler_map(); } void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent_entry, String* reference_name, Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry != NULL) { filler_->SetNamedReference(HeapGraphEdge::kContextVariable, - parent_obj, parent_entry, collection_->names()->GetName(reference_name), - child_obj, child_entry); } } void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent_entry, const char* reference_name, Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry != NULL) { filler_->SetNamedReference(HeapGraphEdge::kShortcut, - parent_obj, parent_entry, reference_name, - child_obj, child_entry); } } void V8HeapExplorer::SetElementReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent_entry, int index, Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry != NULL) { filler_->SetIndexedReference(HeapGraphEdge::kElement, - parent_obj, parent_entry, index, - child_obj, child_entry); } } void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent_entry, const char* reference_name, Object* child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); - if (child_entry != NULL) { + if (child_entry == NULL) return; + if (IsEssentialObject(child_obj)) { filler_->SetNamedReference(HeapGraphEdge::kInternal, - parent_obj, parent_entry, reference_name, - child_obj, child_entry); - IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); } + IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); } void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent_entry, int index, Object* child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); - if (child_entry != NULL) { + if (child_entry == NULL) return; + if (IsEssentialObject(child_obj)) { filler_->SetNamedReference(HeapGraphEdge::kInternal, - parent_obj, parent_entry, collection_->names()->GetName(index), - child_obj, child_entry); - IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); } + IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); } void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent_entry, int index, Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); - if (child_entry != NULL) { + if (child_entry != NULL && IsEssentialObject(child_obj)) { filler_->SetIndexedReference(HeapGraphEdge::kHidden, - parent_obj, parent_entry, index, - child_obj, child_entry); } } void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent_entry, int index, Object* child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry != NULL) { filler_->SetIndexedReference(HeapGraphEdge::kWeak, - parent_obj, parent_entry, index, - child_obj, child_entry); IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); } @@ -2478,7 +2527,7 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent_entry, String* reference_name, Object* child_obj, const char* name_format_string, @@ -2495,10 +2544,8 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, collection_->names()->GetName(reference_name); filler_->SetNamedReference(type, - parent_obj, parent_entry, name, - child_obj, child_entry); IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); } @@ -2506,16 +2553,14 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent_entry, String* reference_name, Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry != NULL) { filler_->SetNamedReference(HeapGraphEdge::kShortcut, - parent_obj, parent_entry, collection_->names()->GetName(reference_name), - child_obj, child_entry); } } @@ -2524,26 +2569,26 @@ void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj, void V8HeapExplorer::SetRootGcRootsReference() { filler_->SetIndexedAutoIndexReference( HeapGraphEdge::kElement, - kInternalRootObject, snapshot_->root(), - kGcRootsObject, snapshot_->gc_roots()); + snapshot_->root()->index(), + snapshot_->gc_roots()); } -void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) { +void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); ASSERT(child_entry != NULL); filler_->SetNamedAutoIndexReference( HeapGraphEdge::kShortcut, - kInternalRootObject, snapshot_->root(), - child_obj, child_entry); + snapshot_->root()->index(), + child_entry); } void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) { filler_->SetIndexedAutoIndexReference( HeapGraphEdge::kElement, - kGcRootsObject, snapshot_->gc_roots(), - GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag)); + snapshot_->gc_roots()->index(), + snapshot_->gc_subroot(tag)); } @@ -2551,21 +2596,48 @@ void V8HeapExplorer::SetGcSubrootReference( VisitorSynchronization::SyncTag tag, bool is_weak, Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry != NULL) { - filler_->SetIndexedAutoIndexReference( - is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement, - GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag), - child_obj, child_entry); + const char* name = GetStrongGcSubrootName(child_obj); + if (name != NULL) { + filler_->SetNamedReference( + HeapGraphEdge::kInternal, + snapshot_->gc_subroot(tag)->index(), + name, + child_entry); + } else { + filler_->SetIndexedAutoIndexReference( + is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement, + snapshot_->gc_subroot(tag)->index(), + child_entry); + } + } +} + + +const char* V8HeapExplorer::GetStrongGcSubrootName(Object* object) { + if (strong_gc_subroot_names_.is_empty()) { +#define NAME_ENTRY(name) strong_gc_subroot_names_.SetTag(heap_->name(), #name); +#define ROOT_NAME(type, name, camel_name) NAME_ENTRY(name) + STRONG_ROOT_LIST(ROOT_NAME) +#undef ROOT_NAME +#define STRUCT_MAP_NAME(NAME, Name, name) NAME_ENTRY(name##_map) + STRUCT_LIST(STRUCT_MAP_NAME) +#undef STRUCT_MAP_NAME +#define SYMBOL_NAME(name, str) NAME_ENTRY(name) + SYMBOL_LIST(SYMBOL_NAME) +#undef SYMBOL_NAME +#undef NAME_ENTRY + CHECK(!strong_gc_subroot_names_.is_empty()); } + return strong_gc_subroot_names_.GetTag(object); } void V8HeapExplorer::TagObject(Object* obj, const char* tag) { - if (obj->IsHeapObject() && - !obj->IsOddball() && - obj != heap_->raw_unchecked_empty_byte_array() && - obj != heap_->raw_unchecked_empty_fixed_array() && - obj != heap_->raw_unchecked_empty_descriptor_array()) { - objects_tags_.SetTag(obj, tag); + if (IsEssentialObject(obj)) { + HeapEntry* entry = GetEntry(obj); + if (entry->name()[0] == '\0') { + entry->set_name(tag); + } } } @@ -2611,7 +2683,7 @@ void V8HeapExplorer::TagGlobalObjects() { Handle<JSGlobalObject> global_obj = enumerator.at(i); Object* obj_document; if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && - obj_document->IsJSObject()) { + obj_document->IsJSObject()) { JSObject* document = JSObject::cast(obj_document); Object* obj_url; if (document->GetProperty(*url_string)->ToObject(&obj_url) && @@ -2655,8 +2727,7 @@ class BasicHeapEntriesAllocator : public HeapEntriesAllocator { collection_(snapshot_->collection()), entries_type_(entries_type) { } - virtual HeapEntry* AllocateEntry( - HeapThing ptr, int children_count, int retainers_count); + virtual HeapEntry* AllocateEntry(HeapThing ptr); private: HeapSnapshot* snapshot_; HeapSnapshotsCollection* collection_; @@ -2664,23 +2735,19 @@ class BasicHeapEntriesAllocator : public HeapEntriesAllocator { }; -HeapEntry* BasicHeapEntriesAllocator::AllocateEntry( - HeapThing ptr, int children_count, int retainers_count) { +HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(HeapThing ptr) { v8::RetainedObjectInfo* info = reinterpret_cast<v8::RetainedObjectInfo*>(ptr); intptr_t elements = info->GetElementCount(); intptr_t size = info->GetSizeInBytes(); + const char* name = elements != -1 + ? collection_->names()->GetFormatted( + "%s / %" V8_PTR_PREFIX "d entries", info->GetLabel(), elements) + : collection_->names()->GetCopy(info->GetLabel()); return snapshot_->AddEntry( entries_type_, - elements != -1 ? - collection_->names()->GetFormatted( - "%s / %" V8_PTR_PREFIX "d entries", - info->GetLabel(), - info->GetElementCount()) : - collection_->names()->GetCopy(info->GetLabel()), + name, HeapObjectsMap::GenerateId(info), - size != -1 ? static_cast<int>(size) : 0, - children_count, - retainers_count); + size != -1 ? static_cast<int>(size) : 0); } @@ -2761,9 +2828,9 @@ void NativeObjectsExplorer::FillImplicitReferences() { for (int i = 0; i < groups->length(); ++i) { ImplicitRefGroup* group = groups->at(i); HeapObject* parent = *group->parent_; - HeapEntry* parent_entry = - filler_->FindOrAddEntry(parent, native_entries_allocator_); - ASSERT(parent_entry != NULL); + int parent_entry = + filler_->FindOrAddEntry(parent, native_entries_allocator_)->index(); + ASSERT(parent_entry != HeapEntry::kNoEntry); Object*** children = group->children_; for (size_t j = 0; j < group->length_; ++j) { Object* child = *children[j]; @@ -2771,9 +2838,9 @@ void NativeObjectsExplorer::FillImplicitReferences() { filler_->FindOrAddEntry(child, native_entries_allocator_); filler_->SetNamedReference( HeapGraphEdge::kInternal, - parent, parent_entry, + parent_entry, "native", - child, child_entry); + child_entry); } } } @@ -2851,8 +2918,9 @@ NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo( HEAP->HashSeed()); HashMap::Entry* entry = native_groups_.Lookup(const_cast<char*>(label_copy), hash, true); - if (entry->value == NULL) + if (entry->value == NULL) { entry->value = new NativeGroupRetainedObjectInfo(label); + } return static_cast<NativeGroupRetainedObjectInfo*>(entry->value); } @@ -2868,8 +2936,8 @@ void NativeObjectsExplorer::SetNativeRootReference( filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_); filler_->SetNamedAutoIndexReference( HeapGraphEdge::kInternal, - group_info, group_entry, - info, child_entry); + group_entry->index(), + child_entry); } @@ -2881,12 +2949,12 @@ void NativeObjectsExplorer::SetWrapperNativeReferences( filler_->FindOrAddEntry(info, native_entries_allocator_); ASSERT(info_entry != NULL); filler_->SetNamedReference(HeapGraphEdge::kInternal, - wrapper, wrapper_entry, + wrapper_entry->index(), "native", - info, info_entry); + info_entry); filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, - info, info_entry, - wrapper, wrapper_entry); + info_entry->index(), + wrapper_entry); } @@ -2901,8 +2969,8 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() { ASSERT(group_entry != NULL); filler_->SetIndexedAutoIndexReference( HeapGraphEdge::kElement, - V8HeapExplorer::kInternalRootObject, snapshot_->root(), - group_info, group_entry); + snapshot_->root()->index(), + group_entry); } } @@ -2917,56 +2985,6 @@ void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) { } -class SnapshotCounter : public SnapshotFillerInterface { - public: - explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { } - HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { - entries_->Pair(ptr, allocator, HeapEntriesMap::kHeapEntryPlaceholder); - return HeapEntriesMap::kHeapEntryPlaceholder; - } - HeapEntry* FindEntry(HeapThing ptr) { - return entries_->Map(ptr); - } - HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { - HeapEntry* entry = FindEntry(ptr); - return entry != NULL ? entry : AddEntry(ptr, allocator); - } - void SetIndexedReference(HeapGraphEdge::Type, - HeapThing parent_ptr, - HeapEntry*, - int, - HeapThing child_ptr, - HeapEntry*) { - entries_->CountReference(parent_ptr, child_ptr); - } - void SetIndexedAutoIndexReference(HeapGraphEdge::Type, - HeapThing parent_ptr, - HeapEntry*, - HeapThing child_ptr, - HeapEntry*) { - entries_->CountReference(parent_ptr, child_ptr); - } - void SetNamedReference(HeapGraphEdge::Type, - HeapThing parent_ptr, - HeapEntry*, - const char*, - HeapThing child_ptr, - HeapEntry*) { - entries_->CountReference(parent_ptr, child_ptr); - } - void SetNamedAutoIndexReference(HeapGraphEdge::Type, - HeapThing parent_ptr, - HeapEntry*, - HeapThing child_ptr, - HeapEntry*) { - entries_->CountReference(parent_ptr, child_ptr); - } - - private: - HeapEntriesMap* entries_; -}; - - class SnapshotFiller : public SnapshotFillerInterface { public: explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) @@ -2974,64 +2992,48 @@ class SnapshotFiller : public SnapshotFillerInterface { collection_(snapshot->collection()), entries_(entries) { } HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { - UNREACHABLE(); - return NULL; + HeapEntry* entry = allocator->AllocateEntry(ptr); + entries_->Pair(ptr, entry->index()); + return entry; } HeapEntry* FindEntry(HeapThing ptr) { - return entries_->Map(ptr); + int index = entries_->Map(ptr); + return index != HeapEntry::kNoEntry ? &snapshot_->entries()[index] : NULL; } HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { HeapEntry* entry = FindEntry(ptr); return entry != NULL ? entry : AddEntry(ptr, allocator); } void SetIndexedReference(HeapGraphEdge::Type type, - HeapThing parent_ptr, - HeapEntry* parent_entry, + int parent, int index, - HeapThing child_ptr, HeapEntry* child_entry) { - int child_index, retainer_index; - entries_->CountReference( - parent_ptr, child_ptr, &child_index, &retainer_index); - parent_entry->SetIndexedReference( - type, child_index, index, child_entry, retainer_index); + HeapEntry* parent_entry = &snapshot_->entries()[parent]; + parent_entry->SetIndexedReference(type, index, child_entry); } void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, - HeapThing parent_ptr, - HeapEntry* parent_entry, - HeapThing child_ptr, + int parent, HeapEntry* child_entry) { - int child_index, retainer_index; - entries_->CountReference( - parent_ptr, child_ptr, &child_index, &retainer_index); - parent_entry->SetIndexedReference( - type, child_index, child_index + 1, child_entry, retainer_index); + HeapEntry* parent_entry = &snapshot_->entries()[parent]; + int index = parent_entry->children_count() + 1; + parent_entry->SetIndexedReference(type, index, child_entry); } void SetNamedReference(HeapGraphEdge::Type type, - HeapThing parent_ptr, - HeapEntry* parent_entry, + int parent, const char* reference_name, - HeapThing child_ptr, HeapEntry* child_entry) { - int child_index, retainer_index; - entries_->CountReference( - parent_ptr, child_ptr, &child_index, &retainer_index); - parent_entry->SetNamedReference( - type, child_index, reference_name, child_entry, retainer_index); + HeapEntry* parent_entry = &snapshot_->entries()[parent]; + parent_entry->SetNamedReference(type, reference_name, child_entry); } void SetNamedAutoIndexReference(HeapGraphEdge::Type type, - HeapThing parent_ptr, - HeapEntry* parent_entry, - HeapThing child_ptr, + int parent, HeapEntry* child_entry) { - int child_index, retainer_index; - entries_->CountReference( - parent_ptr, child_ptr, &child_index, &retainer_index); - parent_entry->SetNamedReference(type, - child_index, - collection_->names()->GetName(child_index + 1), - child_entry, - retainer_index); + HeapEntry* parent_entry = &snapshot_->entries()[parent]; + int index = parent_entry->children_count() + 1; + parent_entry->SetNamedReference( + type, + collection_->names()->GetName(index), + child_entry); } private: @@ -3081,30 +3083,17 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { debug_heap->Verify(); #endif - SetProgressTotal(2); // 2 passes. - -#ifdef DEBUG - debug_heap->Verify(); -#endif - - // Pass 1. Iterate heap contents to count entries and references. - if (!CountEntriesAndReferences()) return false; + SetProgressTotal(1); // 1 pass. #ifdef DEBUG debug_heap->Verify(); #endif - // Allocate memory for entries and references. - snapshot_->AllocateEntries(entries_.entries_count(), - entries_.total_children_count(), - entries_.total_retainers_count()); - - // Allocate heap objects to entries hash map. - entries_.AllocateEntries(); - - // Pass 2. Fill references. if (!FillReferences()) return false; + snapshot_->FillChildrenAndRetainers(); + snapshot_->RememberLastJSObjectId(); + if (!SetEntriesDominators()) return false; if (!CalculateRetainedSizes()) return false; @@ -3134,49 +3123,77 @@ bool HeapSnapshotGenerator::ProgressReport(bool force) { void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { if (control_ == NULL) return; HeapIterator iterator(HeapIterator::kFilterUnreachable); - progress_total_ = ( + progress_total_ = iterations_count * ( v8_heap_explorer_.EstimateObjectsCount(&iterator) + - dom_explorer_.EstimateObjectsCount()) * iterations_count; + dom_explorer_.EstimateObjectsCount()); progress_counter_ = 0; } -bool HeapSnapshotGenerator::CountEntriesAndReferences() { - SnapshotCounter counter(&entries_); - v8_heap_explorer_.AddRootEntries(&counter); - return v8_heap_explorer_.IterateAndExtractReferences(&counter) - && dom_explorer_.IterateAndExtractReferences(&counter); -} - - bool HeapSnapshotGenerator::FillReferences() { SnapshotFiller filler(snapshot_, &entries_); - // IterateAndExtractReferences cannot set object names because - // it makes call to JSObject::LocalLookupRealNamedProperty which - // in turn may relocate objects in property maps thus changing the heap - // layout and affecting retainer counts. This is not acceptable because - // number of retainers must not change between count and fill passes. - // To avoid this there's a separate postpass that set object names. + v8_heap_explorer_.AddRootEntries(&filler); return v8_heap_explorer_.IterateAndExtractReferences(&filler) - && dom_explorer_.IterateAndExtractReferences(&filler) - && v8_heap_explorer_.IterateAndSetObjectNames(&filler); + && dom_explorer_.IterateAndExtractReferences(&filler); } -void HeapSnapshotGenerator::FillReversePostorderIndexes( +bool HeapSnapshotGenerator::IsUserGlobalReference(const HeapGraphEdge* edge) { + ASSERT(edge->from() == snapshot_->root()); + return edge->type() == HeapGraphEdge::kShortcut; +} + + +void HeapSnapshotGenerator::MarkUserReachableObjects() { + List<HeapEntry*> worklist; + + Vector<HeapGraphEdge*> children = snapshot_->root()->children(); + for (int i = 0; i < children.length(); ++i) { + if (IsUserGlobalReference(children[i])) { + worklist.Add(children[i]->to()); + } + } + + while (!worklist.is_empty()) { + HeapEntry* entry = worklist.RemoveLast(); + if (entry->user_reachable()) continue; + entry->set_user_reachable(); + Vector<HeapGraphEdge*> children = entry->children(); + for (int i = 0; i < children.length(); ++i) { + HeapEntry* child = children[i]->to(); + if (!child->user_reachable()) { + worklist.Add(child); + } + } + } +} + + +static bool IsRetainingEdge(HeapGraphEdge* edge) { + if (edge->type() == HeapGraphEdge::kShortcut) return false; + // The edge is not retaining if it goes from system domain + // (i.e. an object not reachable from window) to the user domain + // (i.e. a reachable object). + return edge->from()->user_reachable() + || !edge->to()->user_reachable(); +} + + +void HeapSnapshotGenerator::FillPostorderIndexes( Vector<HeapEntry*>* entries) { snapshot_->ClearPaint(); int current_entry = 0; List<HeapEntry*> nodes_to_visit; - nodes_to_visit.Add(snapshot_->root()); + HeapEntry* root = snapshot_->root(); + nodes_to_visit.Add(root); snapshot_->root()->paint(); while (!nodes_to_visit.is_empty()) { HeapEntry* entry = nodes_to_visit.last(); - Vector<HeapGraphEdge> children = entry->children(); + Vector<HeapGraphEdge*> children = entry->children(); bool has_new_edges = false; for (int i = 0; i < children.length(); ++i) { - if (children[i].type() == HeapGraphEdge::kShortcut) continue; - HeapEntry* child = children[i].to(); + if (entry != root && !IsRetainingEdge(children[i])) continue; + HeapEntry* child = children[i]->to(); if (!child->painted()) { nodes_to_visit.Add(child); child->paint(); @@ -3184,7 +3201,7 @@ void HeapSnapshotGenerator::FillReversePostorderIndexes( } } if (!has_new_edges) { - entry->set_ordered_index(current_entry); + entry->set_postorder_index(current_entry); (*entries)[current_entry++] = entry; nodes_to_visit.RemoveLast(); } @@ -3210,9 +3227,9 @@ bool HeapSnapshotGenerator::BuildDominatorTree( const Vector<HeapEntry*>& entries, Vector<int>* dominators) { if (entries.length() == 0) return true; + HeapEntry* root = snapshot_->root(); const int entries_length = entries.length(), root_index = entries_length - 1; - static const int kNoDominator = -1; - for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; + for (int i = 0; i < root_index; ++i) (*dominators)[i] = HeapEntry::kNoEntry; (*dominators)[root_index] = root_index; // The affected array is used to mark entries which dominators @@ -3220,28 +3237,28 @@ bool HeapSnapshotGenerator::BuildDominatorTree( ScopedVector<bool> affected(entries_length); for (int i = 0; i < affected.length(); ++i) affected[i] = false; // Mark the root direct children as affected. - Vector<HeapGraphEdge> children = entries[root_index]->children(); + Vector<HeapGraphEdge*> children = entries[root_index]->children(); for (int i = 0; i < children.length(); ++i) { - affected[children[i].to()->ordered_index()] = true; + affected[children[i]->to()->postorder_index()] = true; } bool changed = true; while (changed) { changed = false; - if (!ProgressReport(true)) return false; + if (!ProgressReport(false)) return false; for (int i = root_index - 1; i >= 0; --i) { if (!affected[i]) continue; affected[i] = false; // If dominator of the entry has already been set to root, // then it can't propagate any further. if ((*dominators)[i] == root_index) continue; - int new_idom_index = kNoDominator; + int new_idom_index = HeapEntry::kNoEntry; Vector<HeapGraphEdge*> rets = entries[i]->retainers(); for (int j = 0; j < rets.length(); ++j) { - if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; - int ret_index = rets[j]->From()->ordered_index(); - if (dominators->at(ret_index) != kNoDominator) { - new_idom_index = new_idom_index == kNoDominator + if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue; + int ret_index = rets[j]->from()->postorder_index(); + if (dominators->at(ret_index) != HeapEntry::kNoEntry) { + new_idom_index = new_idom_index == HeapEntry::kNoEntry ? ret_index : Intersect(ret_index, new_idom_index, *dominators); // If idom has already reached the root, it doesn't make sense @@ -3249,13 +3266,13 @@ bool HeapSnapshotGenerator::BuildDominatorTree( if (new_idom_index == root_index) break; } } - if (new_idom_index != kNoDominator + if (new_idom_index != HeapEntry::kNoEntry && dominators->at(i) != new_idom_index) { (*dominators)[i] = new_idom_index; changed = true; - Vector<HeapGraphEdge> children = entries[i]->children(); + Vector<HeapGraphEdge*> children = entries[i]->children(); for (int j = 0; j < children.length(); ++j) { - affected[children[j].to()->ordered_index()] = true; + affected[children[j]->to()->postorder_index()] = true; } } } @@ -3265,13 +3282,14 @@ bool HeapSnapshotGenerator::BuildDominatorTree( bool HeapSnapshotGenerator::SetEntriesDominators() { - // This array is used for maintaining reverse postorder of nodes. - ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); - FillReversePostorderIndexes(&ordered_entries); + MarkUserReachableObjects(); + // This array is used for maintaining postorder of nodes. + ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries().length()); + FillPostorderIndexes(&ordered_entries); ScopedVector<int> dominators(ordered_entries.length()); if (!BuildDominatorTree(ordered_entries, &dominators)) return false; for (int i = 0; i < ordered_entries.length(); ++i) { - ASSERT(dominators[i] >= 0); + ASSERT(dominators[i] != HeapEntry::kNoEntry); ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); } return true; @@ -3282,17 +3300,18 @@ bool HeapSnapshotGenerator::CalculateRetainedSizes() { // As for the dominators tree we only know parent nodes, not // children, to sum up total sizes we "bubble" node's self size // adding it to all of its parents. - List<HeapEntry*>& entries = *snapshot_->entries(); + List<HeapEntry>& entries = snapshot_->entries(); for (int i = 0; i < entries.length(); ++i) { - HeapEntry* entry = entries[i]; + HeapEntry* entry = &entries[i]; entry->set_retained_size(entry->self_size()); } for (int i = 0; i < entries.length(); ++i) { - HeapEntry* entry = entries[i]; - int entry_size = entry->self_size(); - for (HeapEntry* dominator = entry->dominator(); - dominator != entry; - entry = dominator, dominator = entry->dominator()) { + int entry_size = entries[i].self_size(); + HeapEntry* current = &entries[i]; + for (HeapEntry* dominator = current->dominator(); + dominator != current; + current = dominator, dominator = current->dominator()) { + ASSERT(current->dominator() != NULL); dominator->add_retained_size(entry_size); } } @@ -3345,9 +3364,7 @@ class OutputStreamWriter { MaybeWriteChunk(); } } - void AddNumber(int n) { AddNumberImpl<int>(n, "%d"); } void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); } - void AddNumber(uint64_t n) { AddNumberImpl<uint64_t>(n, "%llu"); } void Finalize() { if (aborted_) return; ASSERT(chunk_pos_ < chunk_size_); @@ -3398,20 +3415,23 @@ class OutputStreamWriter { }; +// type, name|index, to_node. +const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3; +// type, name, id, self_size, retained_size, dominator, children_index. +const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 7; + void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { ASSERT(writer_ == NULL); writer_ = new OutputStreamWriter(stream); HeapSnapshot* original_snapshot = NULL; - if (snapshot_->raw_entries_size() >= + if (snapshot_->RawSnapshotSize() >= SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize) { // The snapshot is too big. Serialize a fake snapshot. original_snapshot = snapshot_; snapshot_ = CreateFakeSnapshot(); } - // Since nodes graph is cyclic, we need the first pass to enumerate - // them. Strings can be serialized in one pass. - EnumerateNodes(); + SerializeImpl(); delete writer_; @@ -3429,30 +3449,35 @@ HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() { HeapSnapshot::kFull, snapshot_->title(), snapshot_->uid()); - result->AllocateEntries(2, 1, 0); - HeapEntry* root = result->AddRootEntry(1); + result->AddRootEntry(); const char* text = snapshot_->collection()->names()->GetFormatted( "The snapshot is too big. " "Maximum snapshot size is %" V8_PTR_PREFIX "u MB. " "Actual snapshot size is %" V8_PTR_PREFIX "u MB.", SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize / MB, - (snapshot_->raw_entries_size() + MB - 1) / MB); - HeapEntry* message = result->AddEntry( - HeapEntry::kString, text, 0, 4, 0, 0); - root->SetUnidirElementReference(0, 1, message); + (snapshot_->RawSnapshotSize() + MB - 1) / MB); + HeapEntry* message = result->AddEntry(HeapEntry::kString, text, 0, 4); + result->root()->SetIndexedReference(HeapGraphEdge::kElement, 1, message); + result->FillChildrenAndRetainers(); result->SetDominatorsToSelf(); return result; } void HeapSnapshotJSONSerializer::SerializeImpl() { + List<HeapEntry>& nodes = snapshot_->entries(); + ASSERT(0 == snapshot_->root()->index()); writer_->AddCharacter('{'); writer_->AddString("\"snapshot\":{"); SerializeSnapshot(); if (writer_->aborted()) return; writer_->AddString("},\n"); writer_->AddString("\"nodes\":["); - SerializeNodes(); + SerializeNodes(nodes); + if (writer_->aborted()) return; + writer_->AddString("],\n"); + writer_->AddString("\"edges\":["); + SerializeEdges(nodes); if (writer_->aborted()) return; writer_->AddString("],\n"); writer_->AddString("\"strings\":["); @@ -3464,34 +3489,6 @@ void HeapSnapshotJSONSerializer::SerializeImpl() { } -class HeapSnapshotJSONSerializerEnumerator { - public: - explicit HeapSnapshotJSONSerializerEnumerator(HeapSnapshotJSONSerializer* s) - : s_(s) { - } - void Apply(HeapEntry** entry) { - s_->GetNodeId(*entry); - } - private: - HeapSnapshotJSONSerializer* s_; -}; - -void HeapSnapshotJSONSerializer::EnumerateNodes() { - GetNodeId(snapshot_->root()); // Make sure root gets the first id. - HeapSnapshotJSONSerializerEnumerator iter(this); - snapshot_->IterateEntries(&iter); -} - - -int HeapSnapshotJSONSerializer::GetNodeId(HeapEntry* entry) { - HashMap::Entry* cache_entry = nodes_.Lookup(entry, ObjectHash(entry), true); - if (cache_entry->value == NULL) { - cache_entry->value = reinterpret_cast<void*>(next_node_id_++); - } - return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); -} - - int HeapSnapshotJSONSerializer::GetStringId(const char* s) { HashMap::Entry* cache_entry = strings_.Lookup( const_cast<char*>(s), ObjectHash(s), true); @@ -3502,7 +3499,26 @@ int HeapSnapshotJSONSerializer::GetStringId(const char* s) { } -void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { +static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) { + int number_of_digits = 0; + unsigned t = value; + do { + ++number_of_digits; + } while (t /= 10); + + buffer_pos += number_of_digits; + int result = buffer_pos; + do { + int last_digit = value % 10; + buffer[--buffer_pos] = '0' + last_digit; + value /= 10; + } while (value); + return result; +} + + +void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, + bool first_edge) { // The buffer needs space for 3 ints, 3 commas and \0 static const int kBufferSize = MaxDecimalDigitsIn<sizeof(int)>::kSigned * 3 + 3 + 1; // NOLINT @@ -3511,125 +3527,71 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { || edge->type() == HeapGraphEdge::kHidden || edge->type() == HeapGraphEdge::kWeak ? edge->index() : GetStringId(edge->name()); - STATIC_CHECK(sizeof(int) == sizeof(edge->type())); // NOLINT - STATIC_CHECK(sizeof(int) == sizeof(edge_name_or_index)); // NOLINT - STATIC_CHECK(sizeof(int) == sizeof(GetNodeId(edge->to()))); // NOLINT - int result = OS::SNPrintF(buffer, ",%d,%d,%d", - edge->type(), edge_name_or_index, GetNodeId(edge->to())); - USE(result); - ASSERT(result != -1); + int buffer_pos = 0; + if (!first_edge) { + buffer[buffer_pos++] = ','; + } + buffer_pos = utoa(edge->type(), buffer, buffer_pos); + buffer[buffer_pos++] = ','; + buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos); + buffer[buffer_pos++] = ','; + buffer_pos = utoa(entry_index(edge->to()), buffer, buffer_pos); + buffer[buffer_pos++] = '\0'; writer_->AddString(buffer.start()); } -void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { +void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry>& nodes) { + bool first_edge = true; + for (int i = 0; i < nodes.length(); ++i) { + HeapEntry* entry = &nodes[i]; + Vector<HeapGraphEdge*> children = entry->children(); + for (int j = 0; j < children.length(); ++j) { + SerializeEdge(children[j], first_edge); + first_edge = false; + if (writer_->aborted()) return; + } + } +} + + +void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, + int edges_index) { // The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0 static const int kBufferSize = 6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT + MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT + 7 + 1 + 1; EmbeddedVector<char, kBufferSize> buffer; - Vector<HeapGraphEdge> children = entry->children(); - STATIC_CHECK(sizeof(int) == sizeof(entry->type())); // NOLINT - STATIC_CHECK(sizeof(int) == sizeof(GetStringId(entry->name()))); // NOLINT - STATIC_CHECK(sizeof(unsigned) == sizeof(entry->id())); // NOLINT - STATIC_CHECK(sizeof(int) == sizeof(entry->self_size())); // NOLINT - STATIC_CHECK(sizeof(int) == sizeof(entry->retained_size())); // NOLINT - STATIC_CHECK(sizeof(int) == sizeof(GetNodeId(entry->dominator()))); // NOLINT - STATIC_CHECK(sizeof(int) == sizeof(children.length())); // NOLINT - int result = OS::SNPrintF(buffer, "\n,%d,%d,%u,%d,%d,%d,%d", - entry->type(), - GetStringId(entry->name()), - entry->id(), - entry->self_size(), - entry->retained_size(), - GetNodeId(entry->dominator()), - children.length()); - USE(result); - ASSERT(result != -1); + int buffer_pos = 0; + if (entry_index(entry) != 0) { + buffer[buffer_pos++] = ','; + } + buffer_pos = utoa(entry->type(), buffer, buffer_pos); + buffer[buffer_pos++] = ','; + buffer_pos = utoa(GetStringId(entry->name()), buffer, buffer_pos); + buffer[buffer_pos++] = ','; + buffer_pos = utoa(entry->id(), buffer, buffer_pos); + buffer[buffer_pos++] = ','; + buffer_pos = utoa(entry->self_size(), buffer, buffer_pos); + buffer[buffer_pos++] = ','; + buffer_pos = utoa(entry->retained_size(), buffer, buffer_pos); + buffer[buffer_pos++] = ','; + buffer_pos = utoa(entry_index(entry->dominator()), buffer, buffer_pos); + buffer[buffer_pos++] = ','; + buffer_pos = utoa(edges_index, buffer, buffer_pos); + buffer[buffer_pos++] = '\n'; + buffer[buffer_pos++] = '\0'; writer_->AddString(buffer.start()); - for (int i = 0; i < children.length(); ++i) { - SerializeEdge(&children[i]); - if (writer_->aborted()) return; - } } -void HeapSnapshotJSONSerializer::SerializeNodes() { - // The first (zero) item of nodes array is an object describing node - // serialization layout. We use a set of macros to improve - // readability. -#define JSON_A(s) "["s"]" -#define JSON_O(s) "{"s"}" -#define JSON_S(s) "\""s"\"" - writer_->AddString(JSON_O( - JSON_S("fields") ":" JSON_A( - JSON_S("type") - "," JSON_S("name") - "," JSON_S("id") - "," JSON_S("self_size") - "," JSON_S("retained_size") - "," JSON_S("dominator") - "," JSON_S("children_count") - "," JSON_S("children")) - "," JSON_S("types") ":" JSON_A( - JSON_A( - JSON_S("hidden") - "," JSON_S("array") - "," JSON_S("string") - "," JSON_S("object") - "," JSON_S("code") - "," JSON_S("closure") - "," JSON_S("regexp") - "," JSON_S("number") - "," JSON_S("native") - "," JSON_S("synthetic")) - "," JSON_S("string") - "," JSON_S("number") - "," JSON_S("number") - "," JSON_S("number") - "," JSON_S("number") - "," JSON_S("number") - "," JSON_O( - JSON_S("fields") ":" JSON_A( - JSON_S("type") - "," JSON_S("name_or_index") - "," JSON_S("to_node")) - "," JSON_S("types") ":" JSON_A( - JSON_A( - JSON_S("context") - "," JSON_S("element") - "," JSON_S("property") - "," JSON_S("internal") - "," JSON_S("hidden") - "," JSON_S("shortcut") - "," JSON_S("weak")) - "," JSON_S("string_or_number") - "," JSON_S("node")))))); -#undef JSON_S -#undef JSON_O -#undef JSON_A - - const int node_fields_count = 7; - // type,name,id,self_size,retained_size,dominator,children_count. - const int edge_fields_count = 3; // type,name|index,to_node. - List<HashMap::Entry*> sorted_nodes; - SortHashMap(&nodes_, &sorted_nodes); - // Rewrite node ids, so they refer to actual array positions. - if (sorted_nodes.length() > 1) { - // Nodes start from array index 1. - int prev_value = 1; - sorted_nodes[0]->value = reinterpret_cast<void*>(prev_value); - for (int i = 1; i < sorted_nodes.length(); ++i) { - HeapEntry* prev_heap_entry = - reinterpret_cast<HeapEntry*>(sorted_nodes[i-1]->key); - prev_value += node_fields_count + - prev_heap_entry->children().length() * edge_fields_count; - sorted_nodes[i]->value = reinterpret_cast<void*>(prev_value); - } - } - for (int i = 0; i < sorted_nodes.length(); ++i) { - SerializeNode(reinterpret_cast<HeapEntry*>(sorted_nodes[i]->key)); +void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry>& nodes) { + int edges_index = 0; + for (int i = 0; i < nodes.length(); ++i) { + HeapEntry* entry = &nodes[i]; + SerializeNode(entry, edges_index); + edges_index += entry->children().length() * kEdgeFieldsCount; if (writer_->aborted()) return; } } @@ -3641,6 +3603,61 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { writer_->AddString("\""); writer_->AddString(",\"uid\":"); writer_->AddNumber(snapshot_->uid()); + writer_->AddString(",\"meta\":"); + // The object describing node serialization layout. + // We use a set of macros to improve readability. +#define JSON_A(s) "["s"]" +#define JSON_O(s) "{"s"}" +#define JSON_S(s) "\""s"\"" + writer_->AddString(JSON_O( + JSON_S("node_fields") ":" JSON_A( + JSON_S("type") "," + JSON_S("name") "," + JSON_S("id") "," + JSON_S("self_size") "," + JSON_S("retained_size") "," + JSON_S("dominator") "," + JSON_S("edges_index")) "," + JSON_S("node_types") ":" JSON_A( + JSON_A( + JSON_S("hidden") "," + JSON_S("array") "," + JSON_S("string") "," + JSON_S("object") "," + JSON_S("code") "," + JSON_S("closure") "," + JSON_S("regexp") "," + JSON_S("number") "," + JSON_S("native") "," + JSON_S("synthetic")) "," + JSON_S("string") "," + JSON_S("number") "," + JSON_S("number") "," + JSON_S("number") "," + JSON_S("number") "," + JSON_S("number")) "," + JSON_S("edge_fields") ":" JSON_A( + JSON_S("type") "," + JSON_S("name_or_index") "," + JSON_S("to_node")) "," + JSON_S("edge_types") ":" JSON_A( + JSON_A( + JSON_S("context") "," + JSON_S("element") "," + JSON_S("property") "," + JSON_S("internal") "," + JSON_S("hidden") "," + JSON_S("shortcut") "," + JSON_S("weak")) "," + JSON_S("string_or_number") "," + JSON_S("node")))); +#undef JSON_S +#undef JSON_O +#undef JSON_A + writer_->AddString(",\"node_count\":"); + writer_->AddNumber(snapshot_->entries().length()); + writer_->AddString(",\"edge_count\":"); + writer_->AddNumber(snapshot_->edges().length()); } diff --git a/deps/v8/src/profile-generator.h b/deps/v8/src/profile-generator.h index d9a1319b87..92896c29e9 100644 --- a/deps/v8/src/profile-generator.h +++ b/deps/v8/src/profile-generator.h @@ -35,8 +35,6 @@ namespace v8 { namespace internal { -typedef uint32_t SnapshotObjectId; - class TokenEnumerator { public: TokenEnumerator(); @@ -448,6 +446,7 @@ class ProfileGenerator { class HeapEntry; +class HeapSnapshot; class HeapGraphEdge BASE_EMBEDDED { public: @@ -462,60 +461,45 @@ class HeapGraphEdge BASE_EMBEDDED { }; HeapGraphEdge() { } - void Init(int child_index, Type type, const char* name, HeapEntry* to); - void Init(int child_index, Type type, int index, HeapEntry* to); - void Init(int child_index, int index, HeapEntry* to); + HeapGraphEdge(Type type, const char* name, int from, int to); + HeapGraphEdge(Type type, int index, int from, int to); + void ReplaceToIndexWithEntry(HeapSnapshot* snapshot); - Type type() { return static_cast<Type>(type_); } - int index() { + Type type() const { return static_cast<Type>(type_); } + int index() const { ASSERT(type_ == kElement || type_ == kHidden || type_ == kWeak); return index_; } - const char* name() { + const char* name() const { ASSERT(type_ == kContextVariable - || type_ == kProperty - || type_ == kInternal - || type_ == kShortcut); + || type_ == kProperty + || type_ == kInternal + || type_ == kShortcut); return name_; } - HeapEntry* to() { return to_; } - - HeapEntry* From(); + INLINE(HeapEntry* from() const); + HeapEntry* to() const { return to_entry_; } private: - int child_index_ : 29; + INLINE(HeapSnapshot* snapshot() const); + unsigned type_ : 3; + int from_index_ : 29; + union { + // During entries population |to_index_| is used for storing the index, + // afterwards it is replaced with a pointer to the entry. + int to_index_; + HeapEntry* to_entry_; + }; union { int index_; const char* name_; }; - HeapEntry* to_; - - DISALLOW_COPY_AND_ASSIGN(HeapGraphEdge); }; -class HeapSnapshot; - // HeapEntry instances represent an entity from the heap (or a special -// virtual node, e.g. root). To make heap snapshots more compact, -// HeapEntries has a special memory layout (no Vectors or Lists used): -// -// +-----------------+ -// HeapEntry -// +-----------------+ -// HeapGraphEdge | -// ... } children_count -// HeapGraphEdge | -// +-----------------+ -// HeapGraphEdge* | -// ... } retainers_count -// HeapGraphEdge* | -// +-----------------+ -// -// In a HeapSnapshot, all entries are hand-allocated in a continuous array -// of raw bytes. -// +// virtual node, e.g. root). class HeapEntry BASE_EMBEDDED { public: enum Type { @@ -530,15 +514,14 @@ class HeapEntry BASE_EMBEDDED { kNative = v8::HeapGraphNode::kNative, kSynthetic = v8::HeapGraphNode::kSynthetic }; + static const int kNoEntry; HeapEntry() { } - void Init(HeapSnapshot* snapshot, + HeapEntry(HeapSnapshot* snapshot, Type type, const char* name, SnapshotObjectId id, - int self_size, - int children_count, - int retainers_count); + int self_size); HeapSnapshot* snapshot() { return snapshot_; } Type type() { return static_cast<Type>(type_); } @@ -548,72 +531,65 @@ class HeapEntry BASE_EMBEDDED { int self_size() { return self_size_; } int retained_size() { return retained_size_; } void add_retained_size(int size) { retained_size_ += size; } - void set_retained_size(int value) { retained_size_ = value; } - int ordered_index() { return ordered_index_; } - void set_ordered_index(int value) { ordered_index_ = value; } - - Vector<HeapGraphEdge> children() { - return Vector<HeapGraphEdge>(children_arr(), children_count_); } + void set_retained_size(int size) { retained_size_ = size; } + INLINE(int index() const); + int postorder_index() { return postorder_index_; } + void set_postorder_index(int value) { postorder_index_ = value; } + int children_count() const { return children_count_; } + INLINE(int set_children_index(int index)); + INLINE(int set_retainers_index(int index)); + void add_child(HeapGraphEdge* edge) { + children_arr()[children_count_++] = edge; + } + void add_retainer(HeapGraphEdge* edge) { + retainers_arr()[retainers_count_++] = edge; + } + Vector<HeapGraphEdge*> children() { + return Vector<HeapGraphEdge*>(children_arr(), children_count_); } Vector<HeapGraphEdge*> retainers() { return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); } - HeapEntry* dominator() { return dominator_; } + INLINE(HeapEntry* dominator() const); void set_dominator(HeapEntry* entry) { ASSERT(entry != NULL); - dominator_ = entry; + dominator_ = entry->index(); } void clear_paint() { painted_ = false; } bool painted() { return painted_; } void paint() { painted_ = true; } + bool user_reachable() { return user_reachable_; } + void set_user_reachable() { user_reachable_ = true; } - void SetIndexedReference(HeapGraphEdge::Type type, - int child_index, - int index, - HeapEntry* entry, - int retainer_index); - void SetNamedReference(HeapGraphEdge::Type type, - int child_index, - const char* name, - HeapEntry* entry, - int retainer_index); - void SetUnidirElementReference(int child_index, int index, HeapEntry* entry); - - size_t EntrySize() { - return EntriesSize(1, children_count_, retainers_count_); - } + void SetIndexedReference( + HeapGraphEdge::Type type, int index, HeapEntry* entry); + void SetNamedReference( + HeapGraphEdge::Type type, const char* name, HeapEntry* entry); void Print( const char* prefix, const char* edge_name, int max_depth, int indent); Handle<HeapObject> GetHeapObject(); - static size_t EntriesSize(int entries_count, - int children_count, - int retainers_count); - private: - HeapGraphEdge* children_arr() { - return reinterpret_cast<HeapGraphEdge*>(this + 1); - } - HeapGraphEdge** retainers_arr() { - return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_); - } + INLINE(HeapGraphEdge** children_arr()); + INLINE(HeapGraphEdge** retainers_arr()); const char* TypeAsString(); unsigned painted_: 1; + unsigned user_reachable_: 1; + int dominator_: 30; unsigned type_: 4; - int children_count_: 27; - int retainers_count_; + int retainers_count_: 28; + int retainers_index_; + int children_count_; + int children_index_; int self_size_; union { - int ordered_index_; // Used during dominator tree building. - int retained_size_; // At that moment, there is no retained size yet. + int postorder_index_; // Used during dominator tree building. + int retained_size_; // At that moment, there is no retained size yet. }; SnapshotObjectId id_; - HeapEntry* dominator_; HeapSnapshot* snapshot_; const char* name_; - - DISALLOW_COPY_AND_ASSIGN(HeapEntry); }; @@ -634,59 +610,60 @@ class HeapSnapshot { Type type, const char* title, unsigned uid); - ~HeapSnapshot(); void Delete(); HeapSnapshotsCollection* collection() { return collection_; } Type type() { return type_; } const char* title() { return title_; } unsigned uid() { return uid_; } - HeapEntry* root() { return root_entry_; } - HeapEntry* gc_roots() { return gc_roots_entry_; } - HeapEntry* natives_root() { return natives_root_entry_; } - HeapEntry* gc_subroot(int index) { return gc_subroot_entries_[index]; } - List<HeapEntry*>* entries() { return &entries_; } - size_t raw_entries_size() { return raw_entries_size_; } - - void AllocateEntries( - int entries_count, int children_count, int retainers_count); + size_t RawSnapshotSize() const; + HeapEntry* root() { return &entries_[root_index_]; } + HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; } + HeapEntry* natives_root() { return &entries_[natives_root_index_]; } + HeapEntry* gc_subroot(int index) { + return &entries_[gc_subroot_indexes_[index]]; + } + List<HeapEntry>& entries() { return entries_; } + List<HeapGraphEdge>& edges() { return edges_; } + List<HeapGraphEdge*>& children() { return children_; } + List<HeapGraphEdge*>& retainers() { return retainers_; } + void RememberLastJSObjectId(); + SnapshotObjectId max_snapshot_js_object_id() const { + return max_snapshot_js_object_id_; + } + HeapEntry* AddEntry(HeapEntry::Type type, const char* name, SnapshotObjectId id, - int size, - int children_count, - int retainers_count); - HeapEntry* AddRootEntry(int children_count); - HeapEntry* AddGcRootsEntry(int children_count, int retainers_count); - HeapEntry* AddGcSubrootEntry(int tag, - int children_count, - int retainers_count); - HeapEntry* AddNativesRootEntry(int children_count, int retainers_count); + int size); + HeapEntry* AddRootEntry(); + HeapEntry* AddGcRootsEntry(); + HeapEntry* AddGcSubrootEntry(int tag); + HeapEntry* AddNativesRootEntry(); void ClearPaint(); HeapEntry* GetEntryById(SnapshotObjectId id); List<HeapEntry*>* GetSortedEntriesList(); - template<class Visitor> - void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); } void SetDominatorsToSelf(); + void FillChildrenAndRetainers(); void Print(int max_depth); void PrintEntriesSize(); private: - HeapEntry* GetNextEntryToInit(); - HeapSnapshotsCollection* collection_; Type type_; const char* title_; unsigned uid_; - HeapEntry* root_entry_; - HeapEntry* gc_roots_entry_; - HeapEntry* natives_root_entry_; - HeapEntry* gc_subroot_entries_[VisitorSynchronization::kNumberOfSyncTags]; - char* raw_entries_; - List<HeapEntry*> entries_; - bool entries_sorted_; - size_t raw_entries_size_; + int root_index_; + int gc_roots_index_; + int natives_root_index_; + int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags]; + List<HeapEntry> entries_; + List<HeapGraphEdge> edges_; + List<HeapGraphEdge*> children_; + List<HeapGraphEdge*> retainers_; + List<HeapEntry*> sorted_entries_; + SnapshotObjectId max_snapshot_js_object_id_; friend class HeapSnapshotTester; @@ -697,11 +674,17 @@ class HeapSnapshot { class HeapObjectsMap { public: HeapObjectsMap(); - ~HeapObjectsMap(); void SnapshotGenerationFinished(); - SnapshotObjectId FindObject(Address addr); + SnapshotObjectId FindEntry(Address addr); + SnapshotObjectId FindOrAddEntry(Address addr, unsigned int size); void MoveObject(Address from, Address to); + SnapshotObjectId last_assigned_id() const { + return next_id_ - kObjectIdStep; + } + + void StopHeapObjectsTracking(); + void PushHeapObjectsStats(OutputStream* stream); static SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info); static inline SnapshotObjectId GetNthGcSubrootId(int delta); @@ -715,16 +698,23 @@ class HeapObjectsMap { private: struct EntryInfo { - explicit EntryInfo(SnapshotObjectId id) : id(id), accessed(true) { } - EntryInfo(SnapshotObjectId id, bool accessed) - : id(id), - accessed(accessed) { } + EntryInfo(SnapshotObjectId id, Address addr, unsigned int size) + : id(id), addr(addr), size(size), accessed(true) { } + EntryInfo(SnapshotObjectId id, Address addr, unsigned int size, bool accessed) + : id(id), addr(addr), size(size), accessed(accessed) { } SnapshotObjectId id; + Address addr; + unsigned int size; bool accessed; }; + struct TimeInterval { + explicit TimeInterval(SnapshotObjectId id) : id(id), size(0), count(0) { } + SnapshotObjectId id; + uint32_t size; + uint32_t count; + }; - void AddEntry(Address addr, SnapshotObjectId id); - SnapshotObjectId FindEntry(Address addr); + void UpdateHeapObjectsMap(); void RemoveDeadEntries(); static bool AddressesMatch(void* key1, void* key2) { @@ -737,10 +727,10 @@ class HeapObjectsMap { v8::internal::kZeroHashSeed); } - bool initial_fill_mode_; SnapshotObjectId next_id_; HashMap entries_map_; - List<EntryInfo>* entries_; + List<EntryInfo> entries_; + List<TimeInterval> time_intervals_; DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap); }; @@ -752,6 +742,11 @@ class HeapSnapshotsCollection { ~HeapSnapshotsCollection(); bool is_tracking_objects() { return is_tracking_objects_; } + void PushHeapObjectsStats(OutputStream* stream) { + return ids_.PushHeapObjectsStats(stream); + } + void StartHeapObjectsTracking() { is_tracking_objects_ = true; } + void StopHeapObjectsTracking() { ids_.StopHeapObjectsTracking(); } HeapSnapshot* NewSnapshot( HeapSnapshot::Type type, const char* name, unsigned uid); @@ -763,9 +758,17 @@ class HeapSnapshotsCollection { StringsStorage* names() { return &names_; } TokenEnumerator* token_enumerator() { return token_enumerator_; } - SnapshotObjectId GetObjectId(Address addr) { return ids_.FindObject(addr); } + SnapshotObjectId FindObjectId(Address object_addr) { + return ids_.FindEntry(object_addr); + } + SnapshotObjectId GetObjectId(Address object_addr, int object_size) { + return ids_.FindOrAddEntry(object_addr, object_size); + } Handle<HeapObject> FindHeapObjectById(SnapshotObjectId id); void ObjectMoveEvent(Address from, Address to) { ids_.MoveObject(from, to); } + SnapshotObjectId last_assigned_id() const { + return ids_.last_assigned_id(); + } private: INLINE(static bool HeapSnapshotsMatch(void* key1, void* key2)) { @@ -794,8 +797,7 @@ typedef void* HeapThing; class HeapEntriesAllocator { public: virtual ~HeapEntriesAllocator() { } - virtual HeapEntry* AllocateEntry( - HeapThing ptr, int children_count, int retainers_count) = 0; + virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0; }; @@ -804,35 +806,11 @@ class HeapEntriesAllocator { class HeapEntriesMap { public: HeapEntriesMap(); - ~HeapEntriesMap(); - void AllocateEntries(); - HeapEntry* Map(HeapThing thing); - void Pair(HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry); - void CountReference(HeapThing from, HeapThing to, - int* prev_children_count = NULL, - int* prev_retainers_count = NULL); - - int entries_count() { return entries_count_; } - int total_children_count() { return total_children_count_; } - int total_retainers_count() { return total_retainers_count_; } - - static HeapEntry* const kHeapEntryPlaceholder; + int Map(HeapThing thing); + void Pair(HeapThing thing, int entry); private: - struct EntryInfo { - EntryInfo(HeapEntry* entry, HeapEntriesAllocator* allocator) - : entry(entry), - allocator(allocator), - children_count(0), - retainers_count(0) { - } - HeapEntry* entry; - HeapEntriesAllocator* allocator; - int children_count; - int retainers_count; - }; - static uint32_t Hash(HeapThing thing) { return ComputeIntegerHash( static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)), @@ -843,9 +821,6 @@ class HeapEntriesMap { } HashMap entries_; - int entries_count_; - int total_children_count_; - int total_retainers_count_; friend class HeapObjectsSet; @@ -861,6 +836,7 @@ class HeapObjectsSet { void Insert(Object* obj); const char* GetTag(Object* obj); void SetTag(Object* obj, const char* tag); + bool is_empty() const { return entries_.occupancy() == 0; } private: HashMap entries_; @@ -879,26 +855,18 @@ class SnapshotFillerInterface { virtual HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) = 0; virtual void SetIndexedReference(HeapGraphEdge::Type type, - HeapThing parent_ptr, - HeapEntry* parent_entry, + int parent_entry, int index, - HeapThing child_ptr, HeapEntry* child_entry) = 0; virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, - HeapThing parent_ptr, - HeapEntry* parent_entry, - HeapThing child_ptr, + int parent_entry, HeapEntry* child_entry) = 0; virtual void SetNamedReference(HeapGraphEdge::Type type, - HeapThing parent_ptr, - HeapEntry* parent_entry, + int parent_entry, const char* reference_name, - HeapThing child_ptr, HeapEntry* child_entry) = 0; virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type, - HeapThing parent_ptr, - HeapEntry* parent_entry, - HeapThing child_ptr, + int parent_entry, HeapEntry* child_entry) = 0; }; @@ -917,12 +885,10 @@ class V8HeapExplorer : public HeapEntriesAllocator { V8HeapExplorer(HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress); virtual ~V8HeapExplorer(); - virtual HeapEntry* AllocateEntry( - HeapThing ptr, int children_count, int retainers_count); + virtual HeapEntry* AllocateEntry(HeapThing ptr); void AddRootEntries(SnapshotFillerInterface* filler); int EstimateObjectsCount(HeapIterator* iterator); bool IterateAndExtractReferences(SnapshotFillerInterface* filler); - bool IterateAndSetObjectNames(SnapshotFillerInterface* filler); void TagGlobalObjects(); static String* GetConstructorName(JSObject* object); @@ -930,66 +896,77 @@ class V8HeapExplorer : public HeapEntriesAllocator { static HeapObject* const kInternalRootObject; private: - HeapEntry* AddEntry( - HeapObject* object, int children_count, int retainers_count); + HeapEntry* AddEntry(HeapObject* object); HeapEntry* AddEntry(HeapObject* object, HeapEntry::Type type, - const char* name, - int children_count, - int retainers_count); + const char* name); const char* GetSystemEntryName(HeapObject* object); + void ExtractReferences(HeapObject* obj); - void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry); - void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); - void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry); - void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry); + void ExtractJSGlobalProxyReferences(JSGlobalProxy* proxy); + void ExtractJSObjectReferences(int entry, JSObject* js_obj); + void ExtractStringReferences(int entry, String* obj); + void ExtractContextReferences(int entry, Context* context); + void ExtractMapReferences(int entry, Map* map); + void ExtractSharedFunctionInfoReferences(int entry, + SharedFunctionInfo* shared); + void ExtractScriptReferences(int entry, Script* script); + void ExtractCodeCacheReferences(int entry, CodeCache* code_cache); + void ExtractCodeReferences(int entry, Code* code); + void ExtractJSGlobalPropertyCellReferences(int entry, + JSGlobalPropertyCell* cell); + void ExtractClosureReferences(JSObject* js_obj, int entry); + void ExtractPropertyReferences(JSObject* js_obj, int entry); + void ExtractElementReferences(JSObject* js_obj, int entry); + void ExtractInternalReferences(JSObject* js_obj, int entry); + bool IsEssentialObject(Object* object); void SetClosureReference(HeapObject* parent_obj, - HeapEntry* parent, + int parent, String* reference_name, Object* child); void SetNativeBindReference(HeapObject* parent_obj, - HeapEntry* parent, + int parent, const char* reference_name, Object* child); void SetElementReference(HeapObject* parent_obj, - HeapEntry* parent, + int parent, int index, Object* child); void SetInternalReference(HeapObject* parent_obj, - HeapEntry* parent, + int parent, const char* reference_name, Object* child, int field_offset = -1); void SetInternalReference(HeapObject* parent_obj, - HeapEntry* parent, + int parent, int index, Object* child, int field_offset = -1); void SetHiddenReference(HeapObject* parent_obj, - HeapEntry* parent, + int parent, int index, Object* child); void SetWeakReference(HeapObject* parent_obj, - HeapEntry* parent_entry, + int parent, int index, Object* child_obj, int field_offset); void SetPropertyReference(HeapObject* parent_obj, - HeapEntry* parent, + int parent, String* reference_name, Object* child, const char* name_format_string = NULL, int field_offset = -1); void SetPropertyShortcutReference(HeapObject* parent_obj, - HeapEntry* parent, + int parent, String* reference_name, Object* child); - void SetRootShortcutReference(Object* child); + void SetUserGlobalReference(Object* user_global); void SetRootGcRootsReference(); void SetGcRootsReference(VisitorSynchronization::SyncTag tag); void SetGcSubrootReference( VisitorSynchronization::SyncTag tag, bool is_weak, Object* child); - void SetObjectName(HeapObject* object); + const char* GetStrongGcSubrootName(Object* object); void TagObject(Object* obj, const char* tag); HeapEntry* GetEntry(Object* obj); @@ -1003,6 +980,7 @@ class V8HeapExplorer : public HeapEntriesAllocator { SnapshottingProgressReportingInterface* progress_; SnapshotFillerInterface* filler_; HeapObjectsSet objects_tags_; + HeapObjectsSet strong_gc_subroot_names_; static HeapObject* const kGcRootsObject; static HeapObject* const kFirstGcSubrootObject; @@ -1086,9 +1064,10 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface { bool BuildDominatorTree(const Vector<HeapEntry*>& entries, Vector<int>* dominators); bool CalculateRetainedSizes(); - bool CountEntriesAndReferences(); bool FillReferences(); - void FillReversePostorderIndexes(Vector<HeapEntry*>* entries); + void FillPostorderIndexes(Vector<HeapEntry*>* entries); + bool IsUserGlobalReference(const HeapGraphEdge* edge); + void MarkUserReachableObjects(); void ProgressStep(); bool ProgressReport(bool force = false); bool SetEntriesDominators(); @@ -1113,7 +1092,6 @@ class HeapSnapshotJSONSerializer { public: explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot) : snapshot_(snapshot), - nodes_(ObjectsMatch), strings_(ObjectsMatch), next_node_id_(1), next_string_id_(1), @@ -1132,23 +1110,23 @@ class HeapSnapshotJSONSerializer { v8::internal::kZeroHashSeed); } - void EnumerateNodes(); HeapSnapshot* CreateFakeSnapshot(); - int GetNodeId(HeapEntry* entry); int GetStringId(const char* s); - void SerializeEdge(HeapGraphEdge* edge); + int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; } + void SerializeEdge(HeapGraphEdge* edge, bool first_edge); + void SerializeEdges(const List<HeapEntry>& nodes); void SerializeImpl(); - void SerializeNode(HeapEntry* entry); - void SerializeNodes(); + void SerializeNode(HeapEntry* entry, int edges_index); + void SerializeNodes(const List<HeapEntry>& nodes); void SerializeSnapshot(); void SerializeString(const unsigned char* s); void SerializeStrings(); void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries); - static const int kMaxSerializableSnapshotRawSize; + static const int kEdgeFieldsCount; + static const int kNodeFieldsCount; HeapSnapshot* snapshot_; - HashMap nodes_; HashMap strings_; int next_node_id_; int next_string_id_; diff --git a/deps/v8/src/property.h b/deps/v8/src/property.h index 04f78b22d4..ba5e3c8998 100644 --- a/deps/v8/src/property.h +++ b/deps/v8/src/property.h @@ -214,13 +214,6 @@ class LookupResult BASE_EMBEDDED { number_ = number; } - void DescriptorResult(JSObject* holder, Smi* details, int number) { - lookup_type_ = DESCRIPTOR_TYPE; - holder_ = holder; - details_ = PropertyDetails(details); - number_ = number; - } - void ConstantResult(JSObject* holder) { lookup_type_ = CONSTANT_TYPE; holder_ = holder; diff --git a/deps/v8/src/regexp-macro-assembler-irregexp-inl.h b/deps/v8/src/regexp-macro-assembler-irregexp-inl.h index f2a4e851f7..a767ec0089 100644 --- a/deps/v8/src/regexp-macro-assembler-irregexp-inl.h +++ b/deps/v8/src/regexp-macro-assembler-irregexp-inl.h @@ -62,6 +62,16 @@ void RegExpMacroAssemblerIrregexp::Emit16(uint32_t word) { } +void RegExpMacroAssemblerIrregexp::Emit8(uint32_t word) { + ASSERT(pc_ <= buffer_.length()); + if (pc_ == buffer_.length()) { + Expand(); + } + *reinterpret_cast<unsigned char*>(buffer_.start() + pc_) = word; + pc_ += 1; +} + + void RegExpMacroAssemblerIrregexp::Emit32(uint32_t word) { ASSERT(pc_ <= buffer_.length()); if (pc_ + 3 >= buffer_.length()) { diff --git a/deps/v8/src/regexp-macro-assembler-irregexp.cc b/deps/v8/src/regexp-macro-assembler-irregexp.cc index 322efa1365..aa67919c54 100644 --- a/deps/v8/src/regexp-macro-assembler-irregexp.cc +++ b/deps/v8/src/regexp-macro-assembler-irregexp.cc @@ -352,6 +352,42 @@ void RegExpMacroAssemblerIrregexp::CheckNotCharacterAfterMinusAnd( } +void RegExpMacroAssemblerIrregexp::CheckCharacterInRange( + uc16 from, + uc16 to, + Label* on_in_range) { + Emit(BC_CHECK_CHAR_IN_RANGE, 0); + Emit16(from); + Emit16(to); + EmitOrLink(on_in_range); +} + + +void RegExpMacroAssemblerIrregexp::CheckCharacterNotInRange( + uc16 from, + uc16 to, + Label* on_not_in_range) { + Emit(BC_CHECK_CHAR_NOT_IN_RANGE, 0); + Emit16(from); + Emit16(to); + EmitOrLink(on_not_in_range); +} + + +void RegExpMacroAssemblerIrregexp::CheckBitInTable( + Handle<ByteArray> table, Label* on_bit_set) { + Emit(BC_CHECK_BIT_IN_TABLE, 0); + EmitOrLink(on_bit_set); + for (int i = 0; i < kTableSize; i += kBitsPerByte) { + int byte = 0; + for (int j = 0; j < kBitsPerByte; j++) { + if (table->get(i + j) != 0) byte |= 1 << j; + } + Emit8(byte); + } +} + + void RegExpMacroAssemblerIrregexp::CheckNotBackReference(int start_reg, Label* on_not_equal) { ASSERT(start_reg >= 0); diff --git a/deps/v8/src/regexp-macro-assembler-irregexp.h b/deps/v8/src/regexp-macro-assembler-irregexp.h index 262ead297c..25cb68de0b 100644 --- a/deps/v8/src/regexp-macro-assembler-irregexp.h +++ b/deps/v8/src/regexp-macro-assembler-irregexp.h @@ -93,6 +93,13 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler { uc16 minus, uc16 mask, Label* on_not_equal); + virtual void CheckCharacterInRange(uc16 from, + uc16 to, + Label* on_in_range); + virtual void CheckCharacterNotInRange(uc16 from, + uc16 to, + Label* on_not_in_range); + virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set); virtual void CheckNotBackReference(int start_reg, Label* on_no_match); virtual void CheckNotBackReferenceIgnoreCase(int start_reg, Label* on_no_match); @@ -114,6 +121,7 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler { inline void EmitOrLink(Label* label); inline void Emit32(uint32_t x); inline void Emit16(uint32_t x); + inline void Emit8(uint32_t x); inline void Emit(uint32_t bc, uint32_t arg); // Bytecode buffer. int length(); diff --git a/deps/v8/src/regexp-macro-assembler-tracer.cc b/deps/v8/src/regexp-macro-assembler-tracer.cc index f8432784f2..b7aeac48db 100644 --- a/deps/v8/src/regexp-macro-assembler-tracer.cc +++ b/deps/v8/src/regexp-macro-assembler-tracer.cc @@ -198,24 +198,55 @@ void RegExpMacroAssemblerTracer::LoadCurrentCharacter(int cp_offset, } +class PrintablePrinter { + public: + explicit PrintablePrinter(uc16 character) : character_(character) { } + + const char* operator*() { + if (character_ >= ' ' && character_ <= '~') { + buffer_[0] = '('; + buffer_[1] = static_cast<char>(character_); + buffer_[2] = ')'; + buffer_[3] = '\0'; + } else { + buffer_[0] = '\0'; + } + return &buffer_[0]; + }; + + private: + uc16 character_; + char buffer_[4]; +}; + + void RegExpMacroAssemblerTracer::CheckCharacterLT(uc16 limit, Label* on_less) { - PrintF(" CheckCharacterLT(c='u%04x', label[%08x]);\n", - limit, LabelToInt(on_less)); + PrintablePrinter printable(limit); + PrintF(" CheckCharacterLT(c=0x%04x%s, label[%08x]);\n", + limit, + *printable, + LabelToInt(on_less)); assembler_->CheckCharacterLT(limit, on_less); } void RegExpMacroAssemblerTracer::CheckCharacterGT(uc16 limit, Label* on_greater) { - PrintF(" CheckCharacterGT(c='u%04x', label[%08x]);\n", - limit, LabelToInt(on_greater)); + PrintablePrinter printable(limit); + PrintF(" CheckCharacterGT(c=0x%04x%s, label[%08x]);\n", + limit, + *printable, + LabelToInt(on_greater)); assembler_->CheckCharacterGT(limit, on_greater); } void RegExpMacroAssemblerTracer::CheckCharacter(unsigned c, Label* on_equal) { - PrintF(" CheckCharacter(c='u%04x', label[%08x]);\n", - c, LabelToInt(on_equal)); + PrintablePrinter printable(c); + PrintF(" CheckCharacter(c=0x%04x%s, label[%08x]);\n", + c, + *printable, + LabelToInt(on_equal)); assembler_->CheckCharacter(c, on_equal); } @@ -234,8 +265,11 @@ void RegExpMacroAssemblerTracer::CheckNotAtStart(Label* on_not_at_start) { void RegExpMacroAssemblerTracer::CheckNotCharacter(unsigned c, Label* on_not_equal) { - PrintF(" CheckNotCharacter(c='u%04x', label[%08x]);\n", - c, LabelToInt(on_not_equal)); + PrintablePrinter printable(c); + PrintF(" CheckNotCharacter(c=0x%04x%s, label[%08x]);\n", + c, + *printable, + LabelToInt(on_not_equal)); assembler_->CheckNotCharacter(c, on_not_equal); } @@ -244,8 +278,10 @@ void RegExpMacroAssemblerTracer::CheckCharacterAfterAnd( unsigned c, unsigned mask, Label* on_equal) { - PrintF(" CheckCharacterAfterAnd(c='u%04x', mask=0x%04x, label[%08x]);\n", + PrintablePrinter printable(c); + PrintF(" CheckCharacterAfterAnd(c=0x%04x%s, mask=0x%04x, label[%08x]);\n", c, + *printable, mask, LabelToInt(on_equal)); assembler_->CheckCharacterAfterAnd(c, mask, on_equal); @@ -256,8 +292,10 @@ void RegExpMacroAssemblerTracer::CheckNotCharacterAfterAnd( unsigned c, unsigned mask, Label* on_not_equal) { - PrintF(" CheckNotCharacterAfterAnd(c='u%04x', mask=0x%04x, label[%08x]);\n", + PrintablePrinter printable(c); + PrintF(" CheckNotCharacterAfterAnd(c=0x%04x%s, mask=0x%04x, label[%08x]);\n", c, + *printable, mask, LabelToInt(on_not_equal)); assembler_->CheckNotCharacterAfterAnd(c, mask, on_not_equal); @@ -269,7 +307,7 @@ void RegExpMacroAssemblerTracer::CheckNotCharacterAfterMinusAnd( uc16 minus, uc16 mask, Label* on_not_equal) { - PrintF(" CheckNotCharacterAfterMinusAnd(c='u%04x', minus=%04x, mask=0x%04x, " + PrintF(" CheckNotCharacterAfterMinusAnd(c=0x%04x, minus=%04x, mask=0x%04x, " "label[%08x]);\n", c, minus, @@ -279,6 +317,53 @@ void RegExpMacroAssemblerTracer::CheckNotCharacterAfterMinusAnd( } +void RegExpMacroAssemblerTracer::CheckCharacterInRange( + uc16 from, + uc16 to, + Label* on_not_in_range) { + PrintablePrinter printable_from(from); + PrintablePrinter printable_to(to); + PrintF(" CheckCharacterInRange(from=0x%04x%s, to=0x%04x%s, label[%08x]);\n", + from, + *printable_from, + to, + *printable_to, + LabelToInt(on_not_in_range)); + assembler_->CheckCharacterInRange(from, to, on_not_in_range); +} + + +void RegExpMacroAssemblerTracer::CheckCharacterNotInRange( + uc16 from, + uc16 to, + Label* on_in_range) { + PrintablePrinter printable_from(from); + PrintablePrinter printable_to(to); + PrintF( + " CheckCharacterNotInRange(from=0x%04x%s," " to=%04x%s, label[%08x]);\n", + from, + *printable_from, + to, + *printable_to, + LabelToInt(on_in_range)); + assembler_->CheckCharacterNotInRange(from, to, on_in_range); +} + + +void RegExpMacroAssemblerTracer::CheckBitInTable( + Handle<ByteArray> table, Label* on_bit_set) { + PrintF(" CheckBitInTable(label[%08x] ", LabelToInt(on_bit_set)); + for (int i = 0; i < kTableSize; i++) { + PrintF("%c", table->get(i) != 0 ? 'X' : '.'); + if (i % 32 == 31 && i != kTableMask) { + PrintF("\n "); + } + } + PrintF(");\n"); + assembler_->CheckBitInTable(table, on_bit_set); +} + + void RegExpMacroAssemblerTracer::CheckNotBackReference(int start_reg, Label* on_no_match) { PrintF(" CheckNotBackReference(register=%d, label[%08x]);\n", start_reg, @@ -314,7 +399,7 @@ void RegExpMacroAssemblerTracer::CheckCharacters(Vector<const uc16> str, PrintF(" %s(str=\"", check_end_of_string ? "CheckCharacters" : "CheckCharactersUnchecked"); for (int i = 0; i < str.length(); i++) { - PrintF("u%04x", str[i]); + PrintF("0x%04x", str[i]); } PrintF("\", cp_offset=%d, label[%08x])\n", cp_offset, LabelToInt(on_failure)); diff --git a/deps/v8/src/regexp-macro-assembler-tracer.h b/deps/v8/src/regexp-macro-assembler-tracer.h index 1cf0349d86..3fd4d8b39a 100644 --- a/deps/v8/src/regexp-macro-assembler-tracer.h +++ b/deps/v8/src/regexp-macro-assembler-tracer.h @@ -68,6 +68,13 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler { uc16 minus, uc16 and_with, Label* on_not_equal); + virtual void CheckCharacterInRange(uc16 from, + uc16 to, + Label* on_in_range); + virtual void CheckCharacterNotInRange(uc16 from, + uc16 to, + Label* on_not_in_range); + virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set); virtual bool CheckSpecialCharacterClass(uc16 type, Label* on_no_match); virtual void Fail(); diff --git a/deps/v8/src/regexp-macro-assembler.h b/deps/v8/src/regexp-macro-assembler.h index 0314c707c6..85874358e5 100644 --- a/deps/v8/src/regexp-macro-assembler.h +++ b/deps/v8/src/regexp-macro-assembler.h @@ -45,6 +45,11 @@ class RegExpMacroAssembler { static const int kMaxRegister = (1 << 16) - 1; static const int kMaxCPOffset = (1 << 15) - 1; static const int kMinCPOffset = -(1 << 15); + + static const int kTableSizeBits = 7; + static const int kTableSize = 1 << kTableSizeBits; + static const int kTableMask = kTableSize - 1; + enum IrregexpImplementation { kIA32Implementation, kARMImplementation, @@ -106,12 +111,23 @@ class RegExpMacroAssembler { virtual void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, Label* on_not_equal) = 0; - // Subtract a constant from the current character, then or with the given + // Subtract a constant from the current character, then and with the given // constant and then check for a match with c. virtual void CheckNotCharacterAfterMinusAnd(uc16 c, uc16 minus, uc16 and_with, Label* on_not_equal) = 0; + virtual void CheckCharacterInRange(uc16 from, + uc16 to, // Both inclusive. + Label* on_in_range) = 0; + virtual void CheckCharacterNotInRange(uc16 from, + uc16 to, // Both inclusive. + Label* on_not_in_range) = 0; + + // The current character (modulus the kTableSize) is looked up in the byte + // array, and if the found byte is non-zero, we jump to the on_bit_set label. + virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set) = 0; + virtual void CheckNotRegistersEqual(int reg1, int reg2, Label* on_not_equal) = 0; diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js index bc9508d817..a574f62bf6 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -278,11 +278,7 @@ function TrimRegExp(regexp) { function RegExpToString() { - // If this.source is an empty string, output /(?:)/. - // http://bugzilla.mozilla.org/show_bug.cgi?id=225550 - // ecma_2/RegExp/properties-001.js. - var src = this.source ? this.source : '(?:)'; - var result = '/' + src + '/'; + var result = '/' + this.source + '/'; if (this.global) result += 'g'; if (this.ignoreCase) result += 'i'; if (this.multiline) result += 'm'; @@ -296,7 +292,7 @@ function RegExpToString() { // of the last successful match. function RegExpGetLastMatch() { if (lastMatchInfoOverride !== null) { - return lastMatchInfoOverride[0]; + return OVERRIDE_MATCH(lastMatchInfoOverride); } var regExpSubject = LAST_SUBJECT(lastMatchInfo); return SubString(regExpSubject, @@ -334,8 +330,8 @@ function RegExpGetLeftContext() { subject = LAST_SUBJECT(lastMatchInfo); } else { var override = lastMatchInfoOverride; - start_index = override[override.length - 2]; - subject = override[override.length - 1]; + start_index = OVERRIDE_POS(override); + subject = OVERRIDE_SUBJECT(override); } return SubString(subject, 0, start_index); } @@ -349,8 +345,9 @@ function RegExpGetRightContext() { subject = LAST_SUBJECT(lastMatchInfo); } else { var override = lastMatchInfoOverride; - subject = override[override.length - 1]; - start_index = override[override.length - 2] + subject.length; + subject = OVERRIDE_SUBJECT(override); + var match = OVERRIDE_MATCH(override); + start_index = OVERRIDE_POS(override) + match.length; } return SubString(subject, start_index, subject.length); } @@ -362,7 +359,9 @@ function RegExpGetRightContext() { function RegExpMakeCaptureGetter(n) { return function() { if (lastMatchInfoOverride) { - if (n < lastMatchInfoOverride.length - 2) return lastMatchInfoOverride[n]; + if (n < lastMatchInfoOverride.length - 2) { + return OVERRIDE_CAPTURE(lastMatchInfoOverride, n); + } return ''; } var index = n * 2; diff --git a/deps/v8/src/rewriter.cc b/deps/v8/src/rewriter.cc index 55f93ee0d7..e58ddb417e 100644 --- a/deps/v8/src/rewriter.cc +++ b/deps/v8/src/rewriter.cc @@ -111,7 +111,7 @@ void Processor::VisitBlock(Block* node) { void Processor::VisitExpressionStatement(ExpressionStatement* node) { // Rewrite : <x>; -> .result = <x>; - if (!is_set_) { + if (!is_set_ && !node->expression()->IsThrow()) { node->set_expression(SetResult(node->expression())); if (!in_try_) is_set_ = true; } diff --git a/deps/v8/src/runtime-profiler.cc b/deps/v8/src/runtime-profiler.cc index 6ed4ff483a..568e48e412 100644 --- a/deps/v8/src/runtime-profiler.cc +++ b/deps/v8/src/runtime-profiler.cc @@ -65,6 +65,12 @@ static const int kSizeLimit = 1500; // Number of times a function has to be seen on the stack before it is // optimized. static const int kProfilerTicksBeforeOptimization = 2; +// If a function does not have enough type info (according to +// FLAG_type_info_threshold), but has seen a huge number of ticks, +// optimize it as it is. +static const int kTicksWhenNotEnoughTypeInfo = 100; +// We only have one byte to store the number of ticks. +STATIC_ASSERT(kTicksWhenNotEnoughTypeInfo < 256); // Maximum size in bytes of generated code for a function to be optimized // the very first time it is seen on the stack. @@ -88,12 +94,14 @@ RuntimeProfiler::RuntimeProfiler(Isolate* isolate) sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit), sampler_ticks_until_threshold_adjustment_( kSamplerTicksBetweenThresholdAdjustment), - sampler_window_position_(0) { + sampler_window_position_(0), + any_ic_changed_(false), + code_generated_(false) { ClearSampleBuffer(); } -void RuntimeProfiler::GlobalSetup() { +void RuntimeProfiler::GlobalSetUp() { ASSERT(!has_been_globally_set_up_); enabled_ = V8::UseCrankshaft() && FLAG_opt; #ifdef DEBUG @@ -103,20 +111,20 @@ void RuntimeProfiler::GlobalSetup() { static void GetICCounts(JSFunction* function, - int* ic_with_typeinfo_count, + int* ic_with_type_info_count, int* ic_total_count, int* percentage) { *ic_total_count = 0; - *ic_with_typeinfo_count = 0; + *ic_with_type_info_count = 0; Object* raw_info = function->shared()->code()->type_feedback_info(); if (raw_info->IsTypeFeedbackInfo()) { TypeFeedbackInfo* info = TypeFeedbackInfo::cast(raw_info); - *ic_with_typeinfo_count = info->ic_with_typeinfo_count(); + *ic_with_type_info_count = info->ic_with_type_info_count(); *ic_total_count = info->ic_total_count(); } *percentage = *ic_total_count > 0 - ? 100 * *ic_with_typeinfo_count / *ic_total_count + ? 100 * *ic_with_type_info_count / *ic_total_count : 100; } @@ -173,14 +181,10 @@ void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) { // prepared to generate it, but we don't expect to have to. bool found_code = false; Code* stack_check_code = NULL; -#if defined(V8_TARGET_ARCH_IA32) || \ - defined(V8_TARGET_ARCH_ARM) || \ - defined(V8_TARGET_ARCH_MIPS) if (FLAG_count_based_interrupts) { InterruptStub interrupt_stub; found_code = interrupt_stub.FindCodeInCache(&stack_check_code); } else // NOLINT -#endif { // NOLINT StackCheckStub check_stub; found_code = check_stub.FindCodeInCache(&stack_check_code); @@ -259,13 +263,14 @@ void RuntimeProfiler::OptimizeNow() { } } - if (function->IsMarkedForLazyRecompilation() && - function->shared()->code()->kind() == Code::FUNCTION) { - Code* unoptimized = function->shared()->code(); - int nesting = unoptimized->allow_osr_at_loop_nesting_level(); + Code* shared_code = function->shared()->code(); + if (shared_code->kind() != Code::FUNCTION) continue; + + if (function->IsMarkedForLazyRecompilation()) { + int nesting = shared_code->allow_osr_at_loop_nesting_level(); if (nesting == 0) AttemptOnStackReplacement(function); int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker); - unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting); + shared_code->set_allow_osr_at_loop_nesting_level(new_nesting); } // Do not record non-optimizable functions. @@ -283,7 +288,7 @@ void RuntimeProfiler::OptimizeNow() { } if (FLAG_watch_ic_patching) { - int ticks = function->shared()->profiler_ticks(); + int ticks = shared_code->profiler_ticks(); if (ticks >= kProfilerTicksBeforeOptimization) { int typeinfo, total, percentage; @@ -292,12 +297,10 @@ void RuntimeProfiler::OptimizeNow() { // If this particular function hasn't had any ICs patched for enough // ticks, optimize it now. Optimize(function, "hot and stable"); - } else if (ticks >= 100) { - // If this function does not have enough type info, but has - // seen a huge number of ticks, optimize it as it is. + } else if (ticks >= kTicksWhenNotEnoughTypeInfo) { Optimize(function, "not much type info but very hot"); } else { - function->shared()->set_profiler_ticks(ticks + 1); + shared_code->set_profiler_ticks(ticks + 1); if (FLAG_trace_opt_verbose) { PrintF("[not yet optimizing "); function->PrintName(); @@ -306,20 +309,12 @@ void RuntimeProfiler::OptimizeNow() { } } } else if (!any_ic_changed_ && - function->shared()->code()->instruction_size() < kMaxSizeEarlyOpt) { + shared_code->instruction_size() < kMaxSizeEarlyOpt) { // If no IC was patched since the last tick and this function is very // small, optimistically optimize it now. Optimize(function, "small function"); - } else if (!code_generated_ && - !any_ic_changed_ && - total_code_generated_ > 0 && - total_code_generated_ < 2000) { - // If no code was generated and no IC was patched since the last tick, - // but a little code has already been generated since last Reset(), - // then type info might already be stable and we can optimize now. - Optimize(function, "stable on startup"); } else { - function->shared()->set_profiler_ticks(ticks + 1); + shared_code->set_profiler_ticks(ticks + 1); } } else { // !FLAG_watch_ic_patching samples[sample_count++] = function; @@ -338,7 +333,6 @@ void RuntimeProfiler::OptimizeNow() { } if (FLAG_watch_ic_patching) { any_ic_changed_ = false; - code_generated_ = false; } else { // !FLAG_watch_ic_patching // Add the collected functions as samples. It's important not to do // this as part of collecting them because this will interfere with @@ -351,11 +345,7 @@ void RuntimeProfiler::OptimizeNow() { void RuntimeProfiler::NotifyTick() { -#if defined(V8_TARGET_ARCH_IA32) || \ - defined(V8_TARGET_ARCH_ARM) || \ - defined(V8_TARGET_ARCH_MIPS) if (FLAG_count_based_interrupts) return; -#endif isolate_->stack_guard()->RequestRuntimeProfilerTick(); } @@ -372,9 +362,7 @@ void RuntimeProfiler::SetUp() { void RuntimeProfiler::Reset() { - if (FLAG_watch_ic_patching) { - total_code_generated_ = 0; - } else { // !FLAG_watch_ic_patching + if (!FLAG_watch_ic_patching) { sampler_threshold_ = kSamplerThresholdInit; sampler_threshold_size_factor_ = kSamplerThresholdSizeFactorInit; sampler_ticks_until_threshold_adjustment_ = diff --git a/deps/v8/src/runtime-profiler.h b/deps/v8/src/runtime-profiler.h index e3388492cb..ab6cb378ea 100644 --- a/deps/v8/src/runtime-profiler.h +++ b/deps/v8/src/runtime-profiler.h @@ -43,7 +43,7 @@ class RuntimeProfiler { public: explicit RuntimeProfiler(Isolate* isolate); - static void GlobalSetup(); + static void GlobalSetUp(); static inline bool IsEnabled() { ASSERT(has_been_globally_set_up_); @@ -63,13 +63,6 @@ class RuntimeProfiler { void NotifyICChanged() { any_ic_changed_ = true; } - void NotifyCodeGenerated(int generated_code_size) { - if (FLAG_watch_ic_patching) { - code_generated_ = true; - total_code_generated_ += generated_code_size; - } - } - // Rate limiting support. // VM thread interface. @@ -130,7 +123,6 @@ class RuntimeProfiler { bool any_ic_changed_; bool code_generated_; - int total_code_generated_; // Possible state values: // -1 => the profiler thread is waiting on the semaphore diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 320ab59f3c..0b80effbf2 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -1289,90 +1289,79 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { // We have to declare a global const property. To capture we only // assign to it when evaluating the assignment for "const x = // <expr>" the initial value is the hole. - bool is_const_property = value->IsTheHole(); - bool is_function_declaration = false; - if (value->IsUndefined() || is_const_property) { + bool is_var = value->IsUndefined(); + bool is_const = value->IsTheHole(); + bool is_function = value->IsSharedFunctionInfo(); + bool is_module = value->IsJSModule(); + ASSERT(is_var + is_const + is_function + is_module == 1); + + if (is_var || is_const) { // Lookup the property in the global object, and don't set the // value of the variable if the property is already there. + // Do the lookup locally only, see ES5 errata. LookupResult lookup(isolate); - global->Lookup(*name, &lookup); + if (FLAG_es52_globals) + global->LocalLookup(*name, &lookup); + else + global->Lookup(*name, &lookup); if (lookup.IsProperty()) { // We found an existing property. Unless it was an interceptor // that claims the property is absent, skip this declaration. - if (lookup.type() != INTERCEPTOR) { - continue; - } + if (lookup.type() != INTERCEPTOR) continue; PropertyAttributes attributes = global->GetPropertyAttribute(*name); - if (attributes != ABSENT) { - continue; - } + if (attributes != ABSENT) continue; // Fall-through and introduce the absent property by using // SetProperty. } - } else { - is_function_declaration = true; + } else if (is_function) { // Copy the function and update its context. Use it as value. Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(value); Handle<JSFunction> function = - isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, - context, - TENURED); + isolate->factory()->NewFunctionFromSharedFunctionInfo( + shared, context, TENURED); value = function; } LookupResult lookup(isolate); global->LocalLookup(*name, &lookup); - // Compute the property attributes. According to ECMA-262, section - // 13, page 71, the property must be read-only and - // non-deletable. However, neither SpiderMonkey nor KJS creates the - // property as read-only, so we don't either. + // Compute the property attributes. According to ECMA-262, + // the property must be non-configurable except in eval. int attr = NONE; - if (!DeclareGlobalsEvalFlag::decode(flags)) { + bool is_eval = DeclareGlobalsEvalFlag::decode(flags); + if (!is_eval || is_module) { attr |= DONT_DELETE; } bool is_native = DeclareGlobalsNativeFlag::decode(flags); - if (is_const_property || (is_native && is_function_declaration)) { + if (is_const || is_module || (is_native && is_function)) { attr |= READ_ONLY; } LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags); - // Safari does not allow the invocation of callback setters for - // function declarations. To mimic this behavior, we do not allow - // the invocation of setters for function values. This makes a - // difference for global functions with the same names as event - // handlers such as "function onload() {}". Firefox does call the - // onload setter in those case and Safari does not. We follow - // Safari for compatibility. - if (is_function_declaration) { - if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) { - // Do not overwrite READ_ONLY properties. - if (lookup.GetAttributes() & READ_ONLY) { - if (language_mode != CLASSIC_MODE) { - Handle<Object> args[] = { name }; - return isolate->Throw(*isolate->factory()->NewTypeError( - "strict_cannot_assign", HandleVector(args, ARRAY_SIZE(args)))); - } - continue; + if (!lookup.IsProperty() || is_function || is_module) { + // If the local property exists, check that we can reconfigure it + // as required for function declarations. + if (lookup.IsProperty() && lookup.IsDontDelete()) { + if (lookup.IsReadOnly() || lookup.IsDontEnum() || + lookup.type() == CALLBACKS) { + return ThrowRedeclarationError( + isolate, is_function ? "function" : "module", name); } - // Do not change DONT_DELETE to false from true. - attr |= lookup.GetAttributes() & DONT_DELETE; + // If the existing property is not configurable, keep its attributes. + attr = lookup.GetAttributes(); } - PropertyAttributes attributes = static_cast<PropertyAttributes>(attr); - - RETURN_IF_EMPTY_HANDLE( - isolate, - JSObject::SetLocalPropertyIgnoreAttributes(global, name, value, - attributes)); + // Define or redefine own property. + RETURN_IF_EMPTY_HANDLE(isolate, + JSObject::SetLocalPropertyIgnoreAttributes( + global, name, value, static_cast<PropertyAttributes>(attr))); } else { - RETURN_IF_EMPTY_HANDLE( - isolate, - JSReceiver::SetProperty(global, name, value, - static_cast<PropertyAttributes>(attr), - language_mode == CLASSIC_MODE - ? kNonStrictMode : kStrictMode)); + // Do a [[Put]] on the existing (own) property. + RETURN_IF_EMPTY_HANDLE(isolate, + JSObject::SetProperty( + global, name, value, static_cast<PropertyAttributes>(attr), + language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode)); } } @@ -1405,6 +1394,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { if (attributes != ABSENT) { // The name was declared before; check for conflicting re-declarations. + // Note: this is actually inconsistent with what happens for globals (where + // we silently ignore such declarations). if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { // Functions are not read-only. ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); @@ -1467,9 +1458,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { return ThrowRedeclarationError(isolate, "const", name); } } - RETURN_IF_EMPTY_HANDLE( - isolate, - JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode)); + if (object->IsJSGlobalObject()) { + // Define own property on the global object. + RETURN_IF_EMPTY_HANDLE(isolate, + JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode)); + } else { + RETURN_IF_EMPTY_HANDLE(isolate, + JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode)); + } } return isolate->heap()->undefined_value(); @@ -1787,6 +1783,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) { ASSERT(args.length() == 5); CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); CONVERT_ARG_CHECKED(String, source, 1); + // If source is the empty string we set it to "(?:)" instead as + // suggested by ECMA-262, 5th, section 15.10.4.1. + if (source->length() == 0) source = isolate->heap()->query_colon_symbol(); Object* global = args[2]; if (!global->IsTrue()) global = isolate->heap()->false_value(); @@ -2101,7 +2100,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) { DescriptorArray* instance_desc = function->map()->instance_descriptors(); int index = instance_desc->Search(name); ASSERT(index != DescriptorArray::kNotFound); - PropertyDetails details(instance_desc->GetDetails(index)); + PropertyDetails details = instance_desc->GetDetails(index); CallbacksDescriptor new_desc(name, instance_desc->GetValue(index), static_cast<PropertyAttributes>(details.attributes() | READ_ONLY), @@ -2886,12 +2885,79 @@ void FindStringIndicesDispatch(Isolate* isolate, } +// Two smis before and after the match, for very long strings. +const int kMaxBuilderEntriesPerRegExpMatch = 5; + + +static void SetLastMatchInfoNoCaptures(Handle<String> subject, + Handle<JSArray> last_match_info, + int match_start, + int match_end) { + // Fill last_match_info with a single capture. + last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead); + AssertNoAllocation no_gc; + FixedArray* elements = FixedArray::cast(last_match_info->elements()); + RegExpImpl::SetLastCaptureCount(elements, 2); + RegExpImpl::SetLastInput(elements, *subject); + RegExpImpl::SetLastSubject(elements, *subject); + RegExpImpl::SetCapture(elements, 0, match_start); + RegExpImpl::SetCapture(elements, 1, match_end); +} + + +template <typename SubjectChar, typename PatternChar> +static bool SearchStringMultiple(Isolate* isolate, + Vector<const SubjectChar> subject, + Vector<const PatternChar> pattern, + String* pattern_string, + FixedArrayBuilder* builder, + int* match_pos) { + int pos = *match_pos; + int subject_length = subject.length(); + int pattern_length = pattern.length(); + int max_search_start = subject_length - pattern_length; + StringSearch<PatternChar, SubjectChar> search(isolate, pattern); + while (pos <= max_search_start) { + if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { + *match_pos = pos; + return false; + } + // Position of end of previous match. + int match_end = pos + pattern_length; + int new_pos = search.Search(subject, match_end); + if (new_pos >= 0) { + // A match. + if (new_pos > match_end) { + ReplacementStringBuilder::AddSubjectSlice(builder, + match_end, + new_pos); + } + pos = new_pos; + builder->Add(pattern_string); + } else { + break; + } + } + + if (pos < max_search_start) { + ReplacementStringBuilder::AddSubjectSlice(builder, + pos + pattern_length, + subject_length); + } + *match_pos = pos; + return true; +} + + + + template<typename ResultSeqString> -MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString( +MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString( Isolate* isolate, Handle<String> subject, Handle<JSRegExp> pattern_regexp, - Handle<String> replacement) { + Handle<String> replacement, + Handle<JSArray> last_match_info) { ASSERT(subject->IsFlat()); ASSERT(replacement->IsFlat()); @@ -2950,6 +3016,12 @@ MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString( subject_pos, subject_len); } + + SetLastMatchInfoNoCaptures(subject, + last_match_info, + indices.at(matches - 1), + indices.at(matches - 1) + pattern_len); + return *result; } @@ -2998,11 +3070,19 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString( compiled_replacement.simple_hint()) { if (subject_handle->HasOnlyAsciiChars() && replacement_handle->HasOnlyAsciiChars()) { - return StringReplaceStringWithString<SeqAsciiString>( - isolate, subject_handle, regexp_handle, replacement_handle); + return StringReplaceAtomRegExpWithString<SeqAsciiString>( + isolate, + subject_handle, + regexp_handle, + replacement_handle, + last_match_info_handle); } else { - return StringReplaceStringWithString<SeqTwoByteString>( - isolate, subject_handle, regexp_handle, replacement_handle); + return StringReplaceAtomRegExpWithString<SeqTwoByteString>( + isolate, + subject_handle, + regexp_handle, + replacement_handle, + last_match_info_handle); } } @@ -3091,21 +3171,29 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( Handle<String> subject_handle(subject); Handle<JSRegExp> regexp_handle(regexp); + Handle<JSArray> last_match_info_handle(last_match_info); // Shortcut for simple non-regexp global replacements if (regexp_handle->GetFlags().is_global() && regexp_handle->TypeTag() == JSRegExp::ATOM) { Handle<String> empty_string_handle(HEAP->empty_string()); if (subject_handle->HasOnlyAsciiChars()) { - return StringReplaceStringWithString<SeqAsciiString>( - isolate, subject_handle, regexp_handle, empty_string_handle); + return StringReplaceAtomRegExpWithString<SeqAsciiString>( + isolate, + subject_handle, + regexp_handle, + empty_string_handle, + last_match_info_handle); } else { - return StringReplaceStringWithString<SeqTwoByteString>( - isolate, subject_handle, regexp_handle, empty_string_handle); + return StringReplaceAtomRegExpWithString<SeqTwoByteString>( + isolate, + subject_handle, + regexp_handle, + empty_string_handle, + last_match_info_handle); } } - Handle<JSArray> last_match_info_handle(last_match_info); Handle<Object> match = RegExpImpl::Exec(regexp_handle, subject_handle, 0, @@ -3125,6 +3213,10 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( end = RegExpImpl::GetCapture(match_info_array, 1); } + bool global = regexp_handle->GetFlags().is_global(); + + if (start == end && !global) return *subject_handle; + int length = subject_handle->length(); int new_length = length - (end - start); if (new_length == 0) { @@ -3140,7 +3232,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( } // If the regexp isn't global, only match once. - if (!regexp_handle->GetFlags().is_global()) { + if (!global) { if (start > 0) { String::WriteToFlat(*subject_handle, answer->GetChars(), @@ -3639,70 +3731,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { } -// Two smis before and after the match, for very long strings. -const int kMaxBuilderEntriesPerRegExpMatch = 5; - - -static void SetLastMatchInfoNoCaptures(Handle<String> subject, - Handle<JSArray> last_match_info, - int match_start, - int match_end) { - // Fill last_match_info with a single capture. - last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead); - AssertNoAllocation no_gc; - FixedArray* elements = FixedArray::cast(last_match_info->elements()); - RegExpImpl::SetLastCaptureCount(elements, 2); - RegExpImpl::SetLastInput(elements, *subject); - RegExpImpl::SetLastSubject(elements, *subject); - RegExpImpl::SetCapture(elements, 0, match_start); - RegExpImpl::SetCapture(elements, 1, match_end); -} - - -template <typename SubjectChar, typename PatternChar> -static bool SearchStringMultiple(Isolate* isolate, - Vector<const SubjectChar> subject, - Vector<const PatternChar> pattern, - String* pattern_string, - FixedArrayBuilder* builder, - int* match_pos) { - int pos = *match_pos; - int subject_length = subject.length(); - int pattern_length = pattern.length(); - int max_search_start = subject_length - pattern_length; - StringSearch<PatternChar, SubjectChar> search(isolate, pattern); - while (pos <= max_search_start) { - if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { - *match_pos = pos; - return false; - } - // Position of end of previous match. - int match_end = pos + pattern_length; - int new_pos = search.Search(subject, match_end); - if (new_pos >= 0) { - // A match. - if (new_pos > match_end) { - ReplacementStringBuilder::AddSubjectSlice(builder, - match_end, - new_pos); - } - pos = new_pos; - builder->Add(pattern_string); - } else { - break; - } - } - - if (pos < max_search_start) { - ReplacementStringBuilder::AddSubjectSlice(builder, - pos + pattern_length, - subject_length); - } - *match_pos = pos; - return true; -} - - static bool SearchStringMultiple(Isolate* isolate, Handle<String> subject, Handle<String> pattern, @@ -3842,6 +3870,8 @@ static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( } +// Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain +// separate last match info. See comment on that function. static RegExpImpl::IrregexpResult SearchRegExpMultiple( Isolate* isolate, Handle<String> subject, @@ -3870,10 +3900,6 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple( // End of previous match. Differs from pos if match was empty. int match_end = 0; if (result == RegExpImpl::RE_SUCCESS) { - // Need to keep a copy of the previous match for creating last_match_info - // at the end, so we have two vectors that we swap between. - OffsetsVector registers2(required_registers, isolate); - Vector<int> prev_register_vector(registers2.vector(), registers2.length()); bool first = true; do { int match_start = register_vector[0]; @@ -3926,11 +3952,6 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple( elements->set(capture_count + 2, *subject); builder->Add(*isolate->factory()->NewJSArrayWithElements(elements)); } - // Swap register vectors, so the last successful match is in - // prev_register_vector. - Vector<int32_t> tmp = prev_register_vector; - prev_register_vector = register_vector; - register_vector = tmp; if (match_end > match_start) { pos = match_end; @@ -3962,12 +3983,12 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple( last_match_array->EnsureSize(last_match_array_size); AssertNoAllocation no_gc; FixedArray* elements = FixedArray::cast(last_match_array->elements()); + // We have to set this even though the rest of the last match array is + // ignored. RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); + // These are also read without consulting the override. RegExpImpl::SetLastSubject(elements, *subject); RegExpImpl::SetLastInput(elements, *subject); - for (int i = 0; i < last_match_capture_count; i++) { - RegExpImpl::SetCapture(elements, i, prev_register_vector[i]); - } return RegExpImpl::RE_SUCCESS; } } @@ -3976,6 +3997,9 @@ static RegExpImpl::IrregexpResult SearchRegExpMultiple( } +// This is only called for StringReplaceGlobalRegExpWithFunction. This sets +// lastMatchInfoOverride to maintain the last match info, so we don't need to +// set any other last match array info. RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { ASSERT(args.length() == 4); HandleScope handles(isolate); @@ -4669,7 +4693,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) { HandleScope scope; Object* raw_boilerplate_object = literals->get(literal_index); - Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object)); + Handle<JSArray> boilerplate(JSArray::cast(raw_boilerplate_object)); #if DEBUG ElementsKind elements_kind = object->GetElementsKind(); #endif @@ -4680,25 +4704,59 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) { if (value->IsNumber()) { ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS); JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS); - JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS); + if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(), + FAST_DOUBLE_ELEMENTS)) { + JSObject::TransitionElementsKind(boilerplate, FAST_DOUBLE_ELEMENTS); + } ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS); - FixedDoubleArray* double_array = - FixedDoubleArray::cast(object->elements()); + FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements()); HeapNumber* number = HeapNumber::cast(*value); double_array->set(store_index, number->Number()); } else { ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS || elements_kind == FAST_DOUBLE_ELEMENTS); JSObject::TransitionElementsKind(object, FAST_ELEMENTS); - JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS); - FixedArray* object_array = - FixedArray::cast(object->elements()); + if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(), + FAST_ELEMENTS)) { + JSObject::TransitionElementsKind(boilerplate, FAST_ELEMENTS); + } + FixedArray* object_array = FixedArray::cast(object->elements()); object_array->set(store_index, *value); } return *object; } +// Check whether debugger and is about to step into the callback that is passed +// to a built-in function such as Array.forEach. +RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) { + if (!isolate->IsDebuggerActive()) return isolate->heap()->false_value(); + CONVERT_ARG_CHECKED(Object, callback, 0); + // We do not step into the callback if it's a builtin or not even a function. + if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) { + return isolate->heap()->false_value(); + } + return isolate->heap()->true_value(); +} + + +// Set one shot breakpoints for the callback function that is passed to a +// built-in function such as Array.forEach to enable stepping into the callback. +RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) { + Debug* debug = isolate->debug(); + if (!debug->IsStepping()) return NULL; + CONVERT_ARG_CHECKED(Object, callback, 0); + HandleScope scope(isolate); + Handle<SharedFunctionInfo> shared_info(JSFunction::cast(callback)->shared()); + // When leaving the callback, step out has been activated, but not performed + // if we do not leave the builtin. To be able to step into the callback + // again, we need to clear the step out at this point. + debug->ClearStepOut(); + debug->FloodWithOneShot(shared_info); + return NULL; +} + + // Set a local property, even if it is READ_ONLY. If the property does not // exist, it will be added with attributes NONE. RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) { @@ -7582,7 +7640,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) { } } date->SetValue(value, is_value_nan); - return *date; + return value; } @@ -8043,8 +8101,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) { ASSERT(args.length() == 1); Handle<JSFunction> function = args.at<JSFunction>(0); - function->shared()->set_profiler_ticks(0); - // If the function is not compiled ignore the lazy // recompilation. This can happen if the debugger is activated and // the function is returned to the not compiled state. @@ -8067,6 +8123,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) { function->ReplaceCode(function->shared()->code()); return function->code(); } + function->shared()->code()->set_profiler_ticks(0); if (JSFunction::CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) { @@ -8123,6 +8180,14 @@ static void MaterializeArgumentsObjectInFrame(Isolate* isolate, ASSERT(*arguments != isolate->heap()->undefined_value()); } frame->SetExpression(i, *arguments); + if (FLAG_trace_deopt) { + PrintF("Materializing arguments object for frame %p - %p: %p ", + reinterpret_cast<void*>(frame->sp()), + reinterpret_cast<void*>(frame->fp()), + reinterpret_cast<void*>(*arguments)); + arguments->ShortPrint(); + PrintF("\n"); + } } } } @@ -8212,6 +8277,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); + Code* unoptimized = function->shared()->code(); + if (unoptimized->kind() == Code::FUNCTION) { + unoptimized->ClearInlineCaches(); + unoptimized->ClearTypeFeedbackCells(isolate->heap()); + } + return isolate->heap()->undefined_value(); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) { #if defined(USE_SIMULATOR) return isolate->heap()->true_value(); @@ -8251,10 +8329,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { if (!V8::UseCrankshaft()) { return Smi::FromInt(4); // 4 == "never". } + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); if (FLAG_always_opt) { - return Smi::FromInt(3); // 3 == "always". + // We may have always opt, but that is more best-effort than a real + // promise, so we still say "no" if it is not optimized. + return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always". + : Smi::FromInt(2); // 2 == "no". } - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes". : Smi::FromInt(2); // 2 == "no". } @@ -8358,14 +8439,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { PrintF("]\n"); } Handle<Code> check_code; -#if defined(V8_TARGET_ARCH_IA32) || \ - defined(V8_TARGET_ARCH_ARM) || \ - defined(V8_TARGET_ARCH_MIPS) if (FLAG_count_based_interrupts) { InterruptStub interrupt_stub; check_code = interrupt_stub.GetCode(); } else // NOLINT -#endif { // NOLINT StackCheckStub check_stub; check_code = check_stub.GetCode(); @@ -8399,6 +8476,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) { + RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); + return isolate->heap()->nan_value(); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) { HandleScope scope(isolate); ASSERT(args.length() >= 2); @@ -8598,6 +8681,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) { + NoHandleAllocation ha; + ASSERT(args.length() == 2); + CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 0); + CONVERT_ARG_HANDLE_CHECKED(JSModule, instance, 1); + + Context* context; + MaybeObject* maybe_context = + isolate->heap()->AllocateModuleContext(isolate->context(), + scope_info); + if (!maybe_context->To(&context)) return maybe_context; + // Also initialize the context slot of the instance object. + instance->set_context(context); + isolate->set_context(context); + + return context; +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { HandleScope scope(isolate); ASSERT(args.length() == 2); @@ -10929,10 +11031,10 @@ static Handle<JSObject> MaterializeModuleScope( } -// Iterate over the actual scopes visible from a stack frame. The iteration -// proceeds from the innermost visible nested scope outwards. All scopes are -// backed by an actual context except the local scope, which is inserted -// "artificially" in the context chain. +// Iterate over the actual scopes visible from a stack frame or from a closure. +// The iteration proceeds from the innermost visible nested scope outwards. +// All scopes are backed by an actual context except the local scope, +// which is inserted "artificially" in the context chain. class ScopeIterator { public: enum ScopeType { @@ -11033,6 +11135,18 @@ class ScopeIterator { } } + ScopeIterator(Isolate* isolate, + Handle<JSFunction> function) + : isolate_(isolate), + frame_(NULL), + inlined_jsframe_index_(0), + function_(function), + context_(function->context()) { + if (function->IsBuiltin()) { + context_ = Handle<Context>(); + } + } + // More scopes? bool Done() { return context_.is_null(); } @@ -11253,6 +11367,22 @@ static const int kScopeDetailsTypeIndex = 0; static const int kScopeDetailsObjectIndex = 1; static const int kScopeDetailsSize = 2; + +static MaybeObject* MaterializeScopeDetails(Isolate* isolate, + ScopeIterator* it) { + // Calculate the size of the result. + int details_size = kScopeDetailsSize; + Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); + + // Fill in scope details. + details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type())); + Handle<JSObject> scope_object = it->ScopeObject(); + RETURN_IF_EMPTY_HANDLE(isolate, scope_object); + details->set(kScopeDetailsObjectIndex, *scope_object); + + return *isolate->factory()->NewJSArrayWithElements(details); +} + // Return an array with scope details // args[0]: number: break id // args[1]: number: frame index @@ -11290,18 +11420,46 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { if (it.Done()) { return isolate->heap()->undefined_value(); } + return MaterializeScopeDetails(isolate, &it); +} - // Calculate the size of the result. - int details_size = kScopeDetailsSize; - Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); - // Fill in scope details. - details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type())); - Handle<JSObject> scope_object = it.ScopeObject(); - RETURN_IF_EMPTY_HANDLE(isolate, scope_object); - details->set(kScopeDetailsObjectIndex, *scope_object); +RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); - return *isolate->factory()->NewJSArrayWithElements(details); + // Check arguments. + CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); + + // Count the visible scopes. + int n = 0; + for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) { + n++; + } + + return Smi::FromInt(n); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) { + HandleScope scope(isolate); + ASSERT(args.length() == 2); + + // Check arguments. + CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); + CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); + + // Find the requested scope. + int n = 0; + ScopeIterator it(isolate, fun); + for (; !it.Done() && n < index; it.Next()) { + n++; + } + if (it.Done()) { + return isolate->heap()->undefined_value(); + } + + return MaterializeScopeDetails(isolate, &it); } diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index fe9cfd9b2f..a09d9cc3cc 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -77,6 +77,7 @@ namespace internal { \ /* Utilities */ \ F(CheckIsBootstrapping, 0, 1) \ + F(GetRootNaN, 0, 1) \ F(Call, -1 /* >= 2 */, 1) \ F(Apply, 5, 1) \ F(GetFunctionDelegate, 1, 1) \ @@ -88,6 +89,7 @@ namespace internal { F(NotifyDeoptimized, 1, 1) \ F(NotifyOSR, 0, 1) \ F(DeoptimizeFunction, 1, 1) \ + F(ClearFunctionTypeFeedback, 1, 1) \ F(RunningInSimulator, 0, 1) \ F(OptimizeFunctionOnNextCall, -1, 1) \ F(GetOptimizationStatus, 1, 1) \ @@ -97,6 +99,8 @@ namespace internal { F(AllocateInNewSpace, 1, 1) \ F(SetNativeFlag, 1, 1) \ F(StoreArrayLiteralElement, 5, 1) \ + F(DebugCallbackSupportsStepping, 1, 1) \ + F(DebugPrepareStepInIfStepping, 1, 1) \ \ /* Array join support */ \ F(PushIfAbsent, 2, 1) \ @@ -323,6 +327,7 @@ namespace internal { F(PushWithContext, 2, 1) \ F(PushCatchContext, 3, 1) \ F(PushBlockContext, 2, 1) \ + F(PushModuleContext, 2, 1) \ F(DeleteContextSlot, 2, 1) \ F(LoadContextSlot, 2, 2) \ F(LoadContextSlotNoReferenceError, 2, 2) \ @@ -400,6 +405,8 @@ namespace internal { F(GetFrameDetails, 2, 1) \ F(GetScopeCount, 2, 1) \ F(GetScopeDetails, 4, 1) \ + F(GetFunctionScopeCount, 1, 1) \ + F(GetFunctionScopeDetails, 2, 1) \ F(DebugPrintScopes, 0, 1) \ F(GetThreadCount, 1, 1) \ F(GetThreadDetails, 2, 1) \ diff --git a/deps/v8/src/runtime.js b/deps/v8/src/runtime.js index 53d9a39731..6b487349d2 100644 --- a/deps/v8/src/runtime.js +++ b/deps/v8/src/runtime.js @@ -47,7 +47,7 @@ var $String = global.String; var $Number = global.Number; var $Function = global.Function; var $Boolean = global.Boolean; -var $NaN = 0/0; +var $NaN = %GetRootNaN(); var builtins = this; // ECMA-262 Section 11.9.3. diff --git a/deps/v8/src/scanner.cc b/deps/v8/src/scanner.cc index 7901b5d826..f24af2ed26 100755 --- a/deps/v8/src/scanner.cc +++ b/deps/v8/src/scanner.cc @@ -611,7 +611,7 @@ void Scanner::SeekForward(int pos) { } -void Scanner::ScanEscape() { +bool Scanner::ScanEscape() { uc32 c = c0_; Advance(); @@ -621,7 +621,7 @@ void Scanner::ScanEscape() { if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance(); // Allow LF+CR newlines in multiline string literals. if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance(); - return; + return true; } switch (c) { @@ -635,13 +635,13 @@ void Scanner::ScanEscape() { case 't' : c = '\t'; break; case 'u' : { c = ScanHexNumber(4); - if (c < 0) c = 'u'; + if (c < 0) return false; break; } case 'v' : c = '\v'; break; case 'x' : { c = ScanHexNumber(2); - if (c < 0) c = 'x'; + if (c < 0) return false; break; } case '0' : // fall through @@ -654,10 +654,11 @@ void Scanner::ScanEscape() { case '7' : c = ScanOctalEscape(c, 2); break; } - // According to ECMA-262, 3rd, 7.8.4 (p 18ff) these - // should be illegal, but they are commonly handled - // as non-escaped characters by JS VMs. + // According to ECMA-262, section 7.8.4, characters not covered by the + // above cases should be illegal, but they are commonly handled as + // non-escaped characters by JS VMs. AddLiteralChar(c); + return true; } @@ -696,8 +697,7 @@ Token::Value Scanner::ScanString() { uc32 c = c0_; Advance(); if (c == '\\') { - if (c0_ < 0) return Token::ILLEGAL; - ScanEscape(); + if (c0_ < 0 || !ScanEscape()) return Token::ILLEGAL; } else { AddLiteralChar(c); } diff --git a/deps/v8/src/scanner.h b/deps/v8/src/scanner.h index 045e7d27a6..4de413b885 100644 --- a/deps/v8/src/scanner.h +++ b/deps/v8/src/scanner.h @@ -520,13 +520,16 @@ class Scanner { Token::Value ScanIdentifierOrKeyword(); Token::Value ScanIdentifierSuffix(LiteralScope* literal); - void ScanEscape(); Token::Value ScanString(); - // Decodes a unicode escape-sequence which is part of an identifier. + // Scans an escape-sequence which is part of a string and adds the + // decoded character to the current literal. Returns true if a pattern + // is scanned. + bool ScanEscape(); + // Decodes a Unicode escape-sequence which is part of an identifier. // If the escape sequence cannot be decoded the result is kBadChar. uc32 ScanIdentifierUnicodeEscape(); - // Recognizes a uniocde escape-sequence and adds its characters, + // Scans a Unicode escape-sequence and adds its characters, // uninterpreted, to the current literal. Used for parsing RegExp // flags. bool ScanLiteralUnicodeEscape(); diff --git a/deps/v8/src/scopeinfo.cc b/deps/v8/src/scopeinfo.cc index 0f36234701..f50af304a2 100644 --- a/deps/v8/src/scopeinfo.cc +++ b/deps/v8/src/scopeinfo.cc @@ -53,7 +53,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Scope* scope) { FunctionVariableInfo function_name_info; VariableMode function_variable_mode; if (scope->is_function_scope() && scope->function() != NULL) { - Variable* var = scope->function()->var(); + Variable* var = scope->function()->proxy()->var(); if (!var->is_used()) { function_name_info = UNUSED; } else if (var->IsContextSlot()) { @@ -129,8 +129,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Scope* scope) { // If present, add the function variable name and its index. ASSERT(index == scope_info->FunctionNameEntryIndex()); if (has_function_name) { - int var_index = scope->function()->var()->index(); - scope_info->set(index++, *scope->function()->name()); + int var_index = scope->function()->proxy()->var()->index(); + scope_info->set(index++, *scope->function()->proxy()->name()); scope_info->set(index++, Smi::FromInt(var_index)); ASSERT(function_name_info != STACK || (var_index == scope_info->StackLocalCount() && @@ -142,7 +142,9 @@ Handle<ScopeInfo> ScopeInfo::Create(Scope* scope) { ASSERT(index == scope_info->length()); ASSERT(scope->num_parameters() == scope_info->ParameterCount()); ASSERT(scope->num_stack_slots() == scope_info->StackSlotCount()); - ASSERT(scope->num_heap_slots() == scope_info->ContextLength()); + ASSERT(scope->num_heap_slots() == scope_info->ContextLength() || + (scope->num_heap_slots() == kVariablePartIndex && + scope_info->ContextLength() == 0)); return scope_info; } diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc index 859cbd1ae6..6f6032a320 100644 --- a/deps/v8/src/scopes.cc +++ b/deps/v8/src/scopes.cc @@ -388,14 +388,17 @@ Variable* Scope::LocalLookup(Handle<String> name) { // Check context slot lookup. VariableMode mode; + Variable::Location location = Variable::CONTEXT; InitializationFlag init_flag; int index = scope_info_->ContextSlotIndex(*name, &mode, &init_flag); if (index < 0) { // Check parameters. - mode = VAR; - init_flag = kCreatedInitialized; index = scope_info_->ParameterIndex(*name); if (index < 0) return NULL; + + mode = DYNAMIC; + location = Variable::LOOKUP; + init_flag = kCreatedInitialized; } Variable* var = @@ -405,21 +408,27 @@ Variable* Scope::LocalLookup(Handle<String> name) { true, Variable::NORMAL, init_flag); - var->AllocateTo(Variable::CONTEXT, index); + var->AllocateTo(location, index); return var; } Variable* Scope::LookupFunctionVar(Handle<String> name, AstNodeFactory<AstNullVisitor>* factory) { - if (function_ != NULL && function_->name().is_identical_to(name)) { - return function_->var(); + if (function_ != NULL && function_->proxy()->name().is_identical_to(name)) { + return function_->proxy()->var(); } else if (!scope_info_.is_null()) { // If we are backed by a scope info, try to lookup the variable there. VariableMode mode; int index = scope_info_->FunctionContextSlotIndex(*name, &mode); if (index < 0) return NULL; - Variable* var = DeclareFunctionVar(name, mode, factory); + Variable* var = new Variable( + this, name, mode, true /* is valid LHS */, + Variable::NORMAL, kCreatedInitialized); + VariableProxy* proxy = factory->NewVariableProxy(var); + VariableDeclaration* declaration = + factory->NewVariableDeclaration(proxy, mode, this); + DeclareFunctionVar(declaration); var->AllocateTo(Variable::CONTEXT, index); return var; } else { @@ -791,7 +800,7 @@ void Scope::Print(int n) { // Function name, if any (named function literals, only). if (function_ != NULL) { Indent(n1, "// (local) function name: "); - PrintName(function_->name()); + PrintName(function_->proxy()->name()); PrintF("\n"); } @@ -824,7 +833,7 @@ void Scope::Print(int n) { // Print locals. Indent(n1, "// function var\n"); if (function_ != NULL) { - PrintVar(n1, function_->var()); + PrintVar(n1, function_->proxy()->var()); } Indent(n1, "// temporary vars\n"); @@ -949,10 +958,14 @@ bool Scope::ResolveVariable(CompilationInfo* info, break; case BOUND_EVAL_SHADOWED: - // We found a variable variable binding that might be shadowed - // by 'eval' introduced variable bindings. + // We either found a variable binding that might be shadowed by eval or + // gave up on it (e.g. by encountering a local with the same in the outer + // scope which was not promoted to a context, this can happen if we use + // debugger to evaluate arbitrary expressions at a break point). if (var->is_global()) { var = NonLocal(proxy->name(), DYNAMIC_GLOBAL); + } else if (var->is_dynamic()) { + var = NonLocal(proxy->name(), DYNAMIC); } else { Variable* invalidated = var; var = NonLocal(proxy->name(), DYNAMIC_LOCAL); @@ -1086,7 +1099,7 @@ bool Scope::MustAllocateInContext(Variable* var) { // Exceptions: temporary variables are never allocated in a context; // catch-bound variables are always allocated in a context. if (var->mode() == TEMPORARY) return false; - if (is_catch_scope() || is_block_scope()) return true; + if (is_catch_scope() || is_block_scope() || is_module_scope()) return true; return var->has_forced_context_allocation() || scope_calls_eval_ || inner_scope_calls_eval_ || @@ -1204,7 +1217,7 @@ void Scope::AllocateNonParameterLocals() { // because of the current ScopeInfo implementation (see // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor). if (function_ != NULL) { - AllocateNonParameterLocal(function_->var()); + AllocateNonParameterLocal(function_->proxy()->var()); } } @@ -1230,7 +1243,8 @@ void Scope::AllocateVariablesRecursively() { // Force allocation of a context for this scope if necessary. For a 'with' // scope and for a function scope that makes an 'eval' call we need a context, // even if no local variables were statically allocated in the scope. - bool must_have_context = is_with_scope() || + // Likewise for modules. + bool must_have_context = is_with_scope() || is_module_scope() || (is_function_scope() && calls_eval()); // If we didn't allocate any locals in the local context, then we only @@ -1246,14 +1260,14 @@ void Scope::AllocateVariablesRecursively() { int Scope::StackLocalCount() const { return num_stack_slots() - - (function_ != NULL && function_->var()->IsStackLocal() ? 1 : 0); + (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); } int Scope::ContextLocalCount() const { if (num_heap_slots() == 0) return 0; return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - - (function_ != NULL && function_->var()->IsContextSlot() ? 1 : 0); + (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); } } } // namespace v8::internal diff --git a/deps/v8/src/scopes.h b/deps/v8/src/scopes.h index d315b7e5dc..e1a658aa8e 100644 --- a/deps/v8/src/scopes.h +++ b/deps/v8/src/scopes.h @@ -126,15 +126,9 @@ class Scope: public ZoneObject { // Declare the function variable for a function literal. This variable // is in an intermediate scope between this function scope and the the // outer scope. Only possible for function scopes; at most one variable. - template<class Visitor> - Variable* DeclareFunctionVar(Handle<String> name, - VariableMode mode, - AstNodeFactory<Visitor>* factory) { - ASSERT(is_function_scope() && function_ == NULL); - Variable* function_var = new Variable( - this, name, mode, true, Variable::NORMAL, kCreatedInitialized); - function_ = factory->NewVariableProxy(function_var); - return function_var; + void DeclareFunctionVar(VariableDeclaration* declaration) { + ASSERT(is_function_scope()); + function_ = declaration; } // Declare a parameter in this scope. When there are duplicated @@ -312,9 +306,8 @@ class Scope: public ZoneObject { Variable* receiver() { return receiver_; } // The variable holding the function literal for named function - // literals, or NULL. - // Only valid for function scopes. - VariableProxy* function() const { + // literals, or NULL. Only valid for function scopes. + VariableDeclaration* function() const { ASSERT(is_function_scope()); return function_; } @@ -446,7 +439,7 @@ class Scope: public ZoneObject { // Convenience variable. Variable* receiver_; // Function variable, if any; function scopes only. - VariableProxy* function_; + VariableDeclaration* function_; // Convenience variable; function scopes only. Variable* arguments_; // Interface; module scopes only. diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc index 01d5f1c7bc..cf8e5e18e6 100644 --- a/deps/v8/src/serialize.cc +++ b/deps/v8/src/serialize.cc @@ -244,7 +244,7 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) { "Isolate::" #hacker_name "_address", FOR_EACH_ISOLATE_ADDRESS_NAME(BUILD_NAME_LITERAL) NULL -#undef C +#undef BUILD_NAME_LITERAL }; for (uint16_t i = 0; i < Isolate::kIsolateAddressCount; ++i) { diff --git a/deps/v8/src/small-pointer-list.h b/deps/v8/src/small-pointer-list.h index 6c5ce890d2..75fea061ad 100644 --- a/deps/v8/src/small-pointer-list.h +++ b/deps/v8/src/small-pointer-list.h @@ -69,6 +69,12 @@ class SmallPointerList { data_ = kEmptyTag; } + void Sort() { + if ((data_ & kTagMask) == kListTag) { + list()->Sort(compare_value); + } + } + bool is_empty() const { return length() == 0; } int length() const { @@ -159,6 +165,10 @@ class SmallPointerList { private: typedef ZoneList<T*> PointerList; + static int compare_value(T* const* a, T* const* b) { + return Compare<T>(**a, **b); + } + static const intptr_t kEmptyTag = 1; static const intptr_t kSingletonTag = 0; static const intptr_t kListTag = 2; diff --git a/deps/v8/src/spaces-inl.h b/deps/v8/src/spaces-inl.h index 3709009c9b..ed78fc7a15 100644 --- a/deps/v8/src/spaces-inl.h +++ b/deps/v8/src/spaces-inl.h @@ -164,7 +164,7 @@ Page* Page::Initialize(Heap* heap, Executability executable, PagedSpace* owner) { Page* page = reinterpret_cast<Page*>(chunk); - ASSERT(chunk->size() == static_cast<size_t>(kPageSize)); + ASSERT(chunk->size() <= static_cast<size_t>(kPageSize)); ASSERT(chunk->owner() == owner); owner->IncreaseCapacity(page->area_size()); owner->Free(page->area_start(), page->area_size()); @@ -295,11 +295,27 @@ MaybeObject* PagedSpace::AllocateRaw(int size_in_bytes) { MaybeObject* NewSpace::AllocateRaw(int size_in_bytes) { Address old_top = allocation_info_.top; +#ifdef DEBUG + // If we are stressing compaction we waste some memory in new space + // in order to get more frequent GCs. + if (FLAG_stress_compaction && !HEAP->linear_allocation()) { + if (allocation_info_.limit - old_top >= size_in_bytes * 4) { + int filler_size = size_in_bytes * 4; + for (int i = 0; i < filler_size; i += kPointerSize) { + *(reinterpret_cast<Object**>(old_top + i)) = + HEAP->one_pointer_filler_map(); + } + old_top += filler_size; + allocation_info_.top += filler_size; + } + } +#endif + if (allocation_info_.limit - old_top < size_in_bytes) { return SlowAllocateRaw(size_in_bytes); } - Object* obj = HeapObject::FromAddress(allocation_info_.top); + Object* obj = HeapObject::FromAddress(old_top); allocation_info_.top += size_in_bytes; ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index defe352614..a0c8f2cba1 100644 --- a/deps/v8/src/spaces.cc +++ b/deps/v8/src/spaces.cc @@ -362,15 +362,22 @@ Address MemoryAllocator::AllocateAlignedMemory(size_t size, if (base == NULL) return NULL; if (executable == EXECUTABLE) { - CommitCodePage(&reservation, base, size); + if (!CommitCodePage(&reservation, base, size)) { + base = NULL; + } } else { - if (!reservation.Commit(base, - size, - executable == EXECUTABLE)) { - return NULL; + if (!reservation.Commit(base, size, false)) { + base = NULL; } } + if (base == NULL) { + // Failed to commit the body. Release the mapping and any partially + // commited regions inside it. + reservation.Release(); + return NULL; + } + controller->TakeControl(&reservation); return base; } @@ -565,11 +572,10 @@ MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t body_size, } -Page* MemoryAllocator::AllocatePage(PagedSpace* owner, +Page* MemoryAllocator::AllocatePage(intptr_t size, + PagedSpace* owner, Executability executable) { - MemoryChunk* chunk = AllocateChunk(owner->AreaSize(), - executable, - owner); + MemoryChunk* chunk = AllocateChunk(size, executable, owner); if (chunk == NULL) return NULL; @@ -578,8 +584,8 @@ Page* MemoryAllocator::AllocatePage(PagedSpace* owner, LargePage* MemoryAllocator::AllocateLargePage(intptr_t object_size, - Executability executable, - Space* owner) { + Space* owner, + Executability executable) { MemoryChunk* chunk = AllocateChunk(object_size, executable, owner); if (chunk == NULL) return NULL; return LargePage::Initialize(isolate_->heap(), chunk); @@ -833,7 +839,6 @@ MaybeObject* PagedSpace::FindObject(Address addr) { bool PagedSpace::CanExpand() { ASSERT(max_capacity_ % AreaSize() == 0); - ASSERT(Capacity() % AreaSize() == 0); if (Capacity() == max_capacity_) return false; @@ -848,8 +853,14 @@ bool PagedSpace::CanExpand() { bool PagedSpace::Expand() { if (!CanExpand()) return false; - Page* p = heap()->isolate()->memory_allocator()-> - AllocatePage(this, executable()); + intptr_t size = AreaSize(); + + if (anchor_.next_page() == &anchor_) { + size = SizeOfFirstPage(); + } + + Page* p = heap()->isolate()->memory_allocator()->AllocatePage( + size, this, executable()); if (p == NULL) return false; ASSERT(Capacity() <= max_capacity_); @@ -860,6 +871,38 @@ bool PagedSpace::Expand() { } +intptr_t PagedSpace::SizeOfFirstPage() { + int size = 0; + switch (identity()) { + case OLD_POINTER_SPACE: + size = 64 * kPointerSize * KB; + break; + case OLD_DATA_SPACE: + size = 192 * KB; + break; + case MAP_SPACE: + size = 128 * KB; + break; + case CELL_SPACE: + size = 96 * KB; + break; + case CODE_SPACE: + if (kPointerSize == 8) { + // On x64 we allocate code pages in a special way (from the reserved + // 2Byte area). That part of the code is not yet upgraded to handle + // small pages. + size = AreaSize(); + } else { + size = 384 * KB; + } + break; + default: + UNREACHABLE(); + } + return Min(size, AreaSize()); +} + + int PagedSpace::CountTotalPages() { PageIterator it(this); int count = 0; @@ -903,7 +946,6 @@ void PagedSpace::ReleasePage(Page* page) { } ASSERT(Capacity() > 0); - ASSERT(Capacity() % AreaSize() == 0); accounting_stats_.ShrinkSpace(AreaSize()); } @@ -1042,6 +1084,7 @@ bool NewSpace::SetUp(int reserved_semispace_capacity, if (!to_space_.Commit()) { return false; } + ASSERT(!from_space_.is_committed()); // No need to use memory yet. start_ = chunk_base_; address_mask_ = ~(2 * reserved_semispace_capacity - 1); @@ -1198,13 +1241,15 @@ MaybeObject* NewSpace::SlowAllocateRaw(int size_in_bytes) { allocation_info_.limit + inline_allocation_limit_step_, high); int bytes_allocated = static_cast<int>(new_top - top_on_previous_step_); - heap()->incremental_marking()->Step(bytes_allocated); + heap()->incremental_marking()->Step( + bytes_allocated, IncrementalMarking::GC_VIA_STACK_GUARD); top_on_previous_step_ = new_top; return AllocateRaw(size_in_bytes); } else if (AddFreshPage()) { // Switched to new page. Try allocating again. int bytes_allocated = static_cast<int>(old_top - top_on_previous_step_); - heap()->incremental_marking()->Step(bytes_allocated); + heap()->incremental_marking()->Step( + bytes_allocated, IncrementalMarking::GC_VIA_STACK_GUARD); top_on_previous_step_ = to_space_.page_low(); return AllocateRaw(size_in_bytes); } else { @@ -2250,8 +2295,6 @@ bool PagedSpace::AdvanceSweeper(intptr_t bytes_to_sweep) { first_unswept_page_ = p; } - heap()->LowerOldGenLimits(freed_bytes); - heap()->FreeQueuedChunks(); return IsSweepingComplete(); @@ -2581,7 +2624,7 @@ MaybeObject* LargeObjectSpace::AllocateRaw(int object_size, } LargePage* page = heap()->isolate()->memory_allocator()-> - AllocateLargePage(object_size, executable, this); + AllocateLargePage(object_size, this, executable); if (page == NULL) return Failure::RetryAfterGC(identity()); ASSERT(page->area_size() >= object_size); diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h index b614c3bd65..b0ecc5d004 100644 --- a/deps/v8/src/spaces.h +++ b/deps/v8/src/spaces.h @@ -637,8 +637,10 @@ class MemoryChunk { friend class MemoryAllocator; }; + STATIC_CHECK(sizeof(MemoryChunk) <= MemoryChunk::kHeaderSize); + // ----------------------------------------------------------------------------- // A page is a memory chunk of a size 1MB. Large object pages may be larger. // @@ -950,11 +952,11 @@ class MemoryAllocator { void TearDown(); - Page* AllocatePage(PagedSpace* owner, Executability executable); + Page* AllocatePage( + intptr_t size, PagedSpace* owner, Executability executable); - LargePage* AllocateLargePage(intptr_t object_size, - Executability executable, - Space* owner); + LargePage* AllocateLargePage( + intptr_t object_size, Space* owner, Executability executable); void Free(MemoryChunk* chunk); @@ -1040,7 +1042,9 @@ class MemoryAllocator { return CodePageAreaEndOffset() - CodePageAreaStartOffset(); } - static bool CommitCodePage(VirtualMemory* vm, Address start, size_t size); + MUST_USE_RESULT static bool CommitCodePage(VirtualMemory* vm, + Address start, + size_t size); private: Isolate* isolate_; @@ -1518,6 +1522,10 @@ class PagedSpace : public Space { return size_in_bytes - wasted; } + void ResetFreeList() { + free_list_.Reset(); + } + // Set space allocation info. void SetTop(Address top, Address limit) { ASSERT(top == limit || @@ -1625,6 +1633,8 @@ class PagedSpace : public Space { // Maximum capacity of this space. intptr_t max_capacity_; + intptr_t SizeOfFirstPage(); + // Accounting information for this space. AllocationStats accounting_stats_; @@ -2367,11 +2377,6 @@ class FixedSpace : public PagedSpace { // Prepares for a mark-compact GC. virtual void PrepareForMarkCompact(); - protected: - void ResetFreeList() { - free_list_.Reset(); - } - private: // The size of objects in this space. int object_size_in_bytes_; diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index 84dde3dc27..6115930b6c 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -189,7 +189,9 @@ function StringMatch(regexp) { if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0); %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); // lastMatchInfo is defined in regexp.js. - return %StringMatch(subject, regexp, lastMatchInfo); + var result = %StringMatch(subject, regexp, lastMatchInfo); + if (result !== null) lastMatchInfoOverride = null; + return result; } // Non-regexp argument. regexp = new $RegExp(regexp); @@ -235,10 +237,28 @@ function StringReplace(search, replace) { replace); } } else { - return %StringReplaceRegExpWithString(subject, - search, - TO_STRING_INLINE(replace), - lastMatchInfo); + if (lastMatchInfoOverride == null) { + return %StringReplaceRegExpWithString(subject, + search, + TO_STRING_INLINE(replace), + lastMatchInfo); + } else { + // We use this hack to detect whether StringReplaceRegExpWithString + // found at least one hit. In that case we need to remove any + // override. + var saved_subject = lastMatchInfo[LAST_SUBJECT_INDEX]; + lastMatchInfo[LAST_SUBJECT_INDEX] = 0; + var answer = %StringReplaceRegExpWithString(subject, + search, + TO_STRING_INLINE(replace), + lastMatchInfo); + if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) { + lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject; + } else { + lastMatchInfoOverride = null; + } + return answer; + } } } @@ -257,47 +277,34 @@ function StringReplace(search, replace) { if (start < 0) return subject; var end = start + search.length; - var builder = new ReplaceResultBuilder(subject); - // prefix - builder.addSpecialSlice(0, start); + var result = SubString(subject, 0, start); // Compute the string to replace with. if (IS_SPEC_FUNCTION(replace)) { var receiver = %GetDefaultReceiver(replace); - builder.add(%_CallFunction(receiver, - search, - start, - subject, - replace)); + result += %_CallFunction(receiver, search, start, subject, replace); } else { reusableMatchInfo[CAPTURE0] = start; reusableMatchInfo[CAPTURE1] = end; replace = TO_STRING_INLINE(replace); - ExpandReplacement(replace, subject, reusableMatchInfo, builder); + result = ExpandReplacement(replace, subject, reusableMatchInfo, result); } - // suffix - builder.addSpecialSlice(end, subject.length); - - return builder.generate(); + return result + SubString(subject, end, subject.length); } // Expand the $-expressions in the string and return a new string with // the result. -function ExpandReplacement(string, subject, matchInfo, builder) { +function ExpandReplacement(string, subject, matchInfo, result) { var length = string.length; - var builder_elements = builder.elements; var next = %StringIndexOf(string, '$', 0); if (next < 0) { - if (length > 0) builder_elements.push(string); - return; + if (length > 0) result += string; + return result; } - // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102. - var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match. - - if (next > 0) builder_elements.push(SubString(string, 0, next)); + if (next > 0) result += SubString(string, 0, next); while (true) { var expansion = '$'; @@ -306,51 +313,21 @@ function ExpandReplacement(string, subject, matchInfo, builder) { var peek = %_StringCharCodeAt(string, position); if (peek == 36) { // $$ ++position; - builder_elements.push('$'); + result += '$'; } else if (peek == 38) { // $& - match ++position; - builder.addSpecialSlice(matchInfo[CAPTURE0], - matchInfo[CAPTURE1]); + result += SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]); } else if (peek == 96) { // $` - prefix ++position; - builder.addSpecialSlice(0, matchInfo[CAPTURE0]); + result += SubString(subject, 0, matchInfo[CAPTURE0]); } else if (peek == 39) { // $' - suffix ++position; - builder.addSpecialSlice(matchInfo[CAPTURE1], subject.length); - } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9 - ++position; - var n = peek - 48; - if (position < length) { - peek = %_StringCharCodeAt(string, position); - // $nn, 01 <= nn <= 99 - if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) { - var nn = n * 10 + (peek - 48); - if (nn < m) { - // If the two digit capture reference is within range of - // the captures, we use it instead of the single digit - // one. Otherwise, we fall back to using the single - // digit reference. This matches the behavior of - // SpiderMonkey. - ++position; - n = nn; - } - } - } - if (0 < n && n < m) { - addCaptureString(builder, matchInfo, n); - } else { - // Because of the captures range check in the parsing of two - // digit capture references, we can only enter here when a - // single digit capture reference is outside the range of - // captures. - builder_elements.push('$'); - --position; - } + result += SubString(subject, matchInfo[CAPTURE1], subject.length); } else { - builder_elements.push('$'); + result += '$'; } } else { - builder_elements.push('$'); + result += '$'; } // Go the the next $ in the string. @@ -360,16 +337,17 @@ function ExpandReplacement(string, subject, matchInfo, builder) { // haven't reached the end, we need to append the suffix. if (next < 0) { if (position < length) { - builder_elements.push(SubString(string, position, length)); + result += SubString(string, position, length); } - return; + return result; } // Append substring between the previous and the next $ character. if (next > position) { - builder_elements.push(SubString(string, position, next)); + result += SubString(string, position, next); } } + return result; } @@ -386,18 +364,6 @@ function CaptureString(string, lastCaptureInfo, index) { } -// Add the string of a given regular expression capture to the -// ReplaceResultBuilder -function addCaptureString(builder, matchInfo, index) { - // Scale the index. - var scaled = index << 1; - // Compute start and end. - var start = matchInfo[CAPTURE(scaled)]; - if (start < 0) return; - var end = matchInfo[CAPTURE(scaled + 1)]; - builder.addSpecialSlice(start, end); -} - // TODO(lrn): This array will survive indefinitely if replace is never // called again. However, it will be empty, since the contents are cleared // in the finally block. @@ -427,14 +393,22 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { return subject; } var len = res.length; - var i = 0; if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) { + // If the number of captures is two then there are no explicit captures in + // the regexp, just the implicit capture that captures the whole match. In + // this case we can simplify quite a bit and end up with something faster. + // The builder will consist of some integers that indicate slices of the + // input string and some replacements that were returned from the replace + // function. var match_start = 0; var override = new InternalArray(null, 0, subject); var receiver = %GetDefaultReceiver(replace); - while (i < len) { + for (var i = 0; i < len; i++) { var elem = res[i]; if (%_IsSmi(elem)) { + // Integers represent slices of the original string. Use these to + // get the offsets we need for the override array (so things like + // RegExp.leftContext work during the callback function. if (elem > 0) { match_start = (elem >> 11) + (elem & 0x7ff); } else { @@ -446,23 +420,25 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { lastMatchInfoOverride = override; var func_result = %_CallFunction(receiver, elem, match_start, subject, replace); + // Overwrite the i'th element in the results with the string we got + // back from the callback function. res[i] = TO_STRING_INLINE(func_result); match_start += elem.length; } - i++; } } else { var receiver = %GetDefaultReceiver(replace); - while (i < len) { + for (var i = 0; i < len; i++) { var elem = res[i]; if (!%_IsSmi(elem)) { // elem must be an Array. // Use the apply argument as backing for global RegExp properties. lastMatchInfoOverride = elem; var func_result = %Apply(replace, receiver, elem, 0, elem.length); + // Overwrite the i'th element in the results with the string we got + // back from the callback function. res[i] = TO_STRING_INLINE(func_result); } - i++; } } var resultBuilder = new ReplaceResultBuilder(subject, res); @@ -476,9 +452,8 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { var matchInfo = DoRegExpExec(regexp, subject, 0); if (IS_NULL(matchInfo)) return subject; - var result = new ReplaceResultBuilder(subject); var index = matchInfo[CAPTURE0]; - result.addSpecialSlice(0, index); + var result = SubString(subject, 0, index); var endOfMatch = matchInfo[CAPTURE1]; // Compute the parameter list consisting of the match, captures, index, // and subject for the replace function invocation. @@ -490,8 +465,7 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { // No captures, only the match, which is always valid. var s = SubString(subject, index, endOfMatch); // Don't call directly to avoid exposing the built-in global object. - replacement = - %_CallFunction(receiver, s, index, subject, replace); + replacement = %_CallFunction(receiver, s, index, subject, replace); } else { var parameters = new InternalArray(m + 2); for (var j = 0; j < m; j++) { @@ -503,11 +477,10 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { replacement = %Apply(replace, receiver, parameters, 0, j + 2); } - result.add(replacement); // The add method converts to string if necessary. + result += replacement; // The add method converts to string if necessary. // Can't use matchInfo any more from here, since the function could // overwrite it. - result.addSpecialSlice(endOfMatch, subject.length); - return result.generate(); + return result + SubString(subject, endOfMatch, subject.length); } diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc index 3371b1bf4a..bd7163a2f1 100644 --- a/deps/v8/src/stub-cache.cc +++ b/deps/v8/src/stub-cache.cc @@ -939,7 +939,8 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) { ASSERT(args[0]->IsJSObject()); ASSERT(args[1]->IsJSObject()); - AccessorInfo* callback = AccessorInfo::cast(args[3]); + ASSERT(args[3]->IsSmi()); + AccessorInfo* callback = AccessorInfo::cast(args[4]); Address getter_address = v8::ToCData<Address>(callback->getter()); v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address); ASSERT(fun != NULL); @@ -950,7 +951,7 @@ RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) { // Leaving JavaScript. VMState state(isolate, EXTERNAL); ExternalCallbackScope call_scope(isolate, getter_address); - result = fun(v8::Utils::ToLocal(args.at<String>(4)), info); + result = fun(v8::Utils::ToLocal(args.at<String>(5)), info); } RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (result.IsEmpty()) return HEAP->undefined_value(); @@ -997,7 +998,8 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) { ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2); ASSERT(args[2]->IsJSObject()); // Receiver. ASSERT(args[3]->IsJSObject()); // Holder. - ASSERT(args.length() == 5); // Last arg is data object. + ASSERT(args[5]->IsSmi()); // Isolate. + ASSERT(args.length() == 6); Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); v8::NamedPropertyGetter getter = @@ -1050,7 +1052,7 @@ static MaybeObject* LoadWithInterceptor(Arguments* args, ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2); Handle<JSObject> receiver_handle = args->at<JSObject>(2); Handle<JSObject> holder_handle = args->at<JSObject>(3); - ASSERT(args->length() == 5); // Last arg is data object. + ASSERT(args->length() == 6); Isolate* isolate = receiver_handle->GetIsolate(); diff --git a/deps/v8/src/utils.cc b/deps/v8/src/utils.cc index 89ef4c6e3e..7e8c088dd4 100644 --- a/deps/v8/src/utils.cc +++ b/deps/v8/src/utils.cc @@ -89,4 +89,19 @@ char* SimpleStringBuilder::Finalize() { return buffer_.start(); } + +const DivMagicNumbers DivMagicNumberFor(int32_t divisor) { + switch (divisor) { + case 3: return DivMagicNumberFor3; + case 5: return DivMagicNumberFor5; + case 7: return DivMagicNumberFor7; + case 9: return DivMagicNumberFor9; + case 11: return DivMagicNumberFor11; + case 25: return DivMagicNumberFor25; + case 125: return DivMagicNumberFor125; + case 625: return DivMagicNumberFor625; + default: return InvalidDivMagicNumber; + } +} + } } // namespace v8::internal diff --git a/deps/v8/src/utils.h b/deps/v8/src/utils.h index 1d40c98b9e..f116c14db3 100644 --- a/deps/v8/src/utils.h +++ b/deps/v8/src/utils.h @@ -85,6 +85,32 @@ inline int WhichPowerOf2(uint32_t x) { } +// Magic numbers for integer division. +// These are kind of 2's complement reciprocal of the divisors. +// Details and proofs can be found in: +// - Hacker's Delight, Henry S. Warren, Jr. +// - The PowerPC Compiler Writer’s Guide +// and probably many others. +// See details in the implementation of the algorithm in +// lithium-codegen-arm.cc : LCodeGen::TryEmitSignedIntegerDivisionByConstant(). +struct DivMagicNumbers { + unsigned M; + unsigned s; +}; + +const DivMagicNumbers InvalidDivMagicNumber= {0, 0}; +const DivMagicNumbers DivMagicNumberFor3 = {0x55555556, 0}; +const DivMagicNumbers DivMagicNumberFor5 = {0x66666667, 1}; +const DivMagicNumbers DivMagicNumberFor7 = {0x92492493, 2}; +const DivMagicNumbers DivMagicNumberFor9 = {0x38e38e39, 1}; +const DivMagicNumbers DivMagicNumberFor11 = {0x2e8ba2e9, 1}; +const DivMagicNumbers DivMagicNumberFor25 = {0x51eb851f, 3}; +const DivMagicNumbers DivMagicNumberFor125 = {0x10624dd3, 3}; +const DivMagicNumbers DivMagicNumberFor625 = {0x68db8bad, 8}; + +const DivMagicNumbers DivMagicNumberFor(int32_t divisor); + + // The C++ standard leaves the semantics of '>>' undefined for // negative signed operands. Most implementations do the right thing, // though. diff --git a/deps/v8/src/v8-counters.h b/deps/v8/src/v8-counters.h index 6db9c77edc..94a5264380 100644 --- a/deps/v8/src/v8-counters.h +++ b/deps/v8/src/v8-counters.h @@ -236,6 +236,8 @@ namespace internal { SC(math_sin, V8.MathSin) \ SC(math_sqrt, V8.MathSqrt) \ SC(math_tan, V8.MathTan) \ + SC(array_bounds_checks_seen, V8.ArrayBoundsChecksSeen) \ + SC(array_bounds_checks_removed, V8.ArrayBoundsChecksRemoved) \ SC(transcendental_cache_hit, V8.TranscendentalCacheHit) \ SC(transcendental_cache_miss, V8.TranscendentalCacheMiss) \ SC(stack_interrupts, V8.StackInterrupts) \ diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc index 506f3f6606..2910a0700d 100644 --- a/deps/v8/src/v8.cc +++ b/deps/v8/src/v8.cc @@ -27,11 +27,13 @@ #include "v8.h" +#include "assembler.h" #include "isolate.h" #include "elements.h" #include "bootstrapper.h" #include "debug.h" #include "deoptimizer.h" +#include "frames.h" #include "heap-profiler.h" #include "hydrogen.h" #include "lithium-allocator.h" @@ -103,13 +105,21 @@ void V8::TearDown() { ASSERT(isolate->IsDefaultIsolate()); if (!has_been_set_up_ || has_been_disposed_) return; + + ElementsAccessor::TearDown(); + LOperand::TearDownCaches(); + RegisteredExtension::UnregisterAll(); + isolate->TearDown(); + delete isolate; is_running_ = false; has_been_disposed_ = true; delete call_completed_callbacks_; call_completed_callbacks_ = NULL; + + OS::TearDown(); } @@ -240,7 +250,6 @@ Object* V8::FillHeapNumberWithRandom(Object* heap_number, } void V8::InitializeOncePerProcessImpl() { - // Set up the platform OS support. OS::SetUp(); use_crankshaft_ = FLAG_crankshaft; @@ -254,7 +263,9 @@ void V8::InitializeOncePerProcessImpl() { use_crankshaft_ = false; } - RuntimeProfiler::GlobalSetup(); + OS::PostSetUp(); + + RuntimeProfiler::GlobalSetUp(); ElementsAccessor::InitializeOncePerProcess(); @@ -265,6 +276,9 @@ void V8::InitializeOncePerProcessImpl() { } LOperand::SetUpCaches(); + SetUpJSCallerSavedCodeData(); + SamplerRegistry::SetUp(); + ExternalReference::SetUp(); } void V8::InitializeOncePerProcess() { diff --git a/deps/v8/src/v8globals.h b/deps/v8/src/v8globals.h index bfc5e23390..6a1766a1a5 100644 --- a/deps/v8/src/v8globals.h +++ b/deps/v8/src/v8globals.h @@ -48,6 +48,10 @@ const intptr_t kObjectAlignmentMask = kObjectAlignment - 1; const intptr_t kPointerAlignment = (1 << kPointerSizeLog2); const intptr_t kPointerAlignmentMask = kPointerAlignment - 1; +// Desired alignment for double values. +const intptr_t kDoubleAlignment = 8; +const intptr_t kDoubleAlignmentMask = kDoubleAlignment - 1; + // Desired alignment for maps. #if V8_HOST_ARCH_64_BIT const intptr_t kMapAlignmentBits = kObjectAlignmentBits; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index d23fe618eb..0f263ee743 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -33,9 +33,9 @@ // NOTE these macros are used by the SCons build script so their names // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 -#define MINOR_VERSION 9 -#define BUILD_NUMBER 24 -#define PATCH_LEVEL 9 +#define MINOR_VERSION 11 +#define BUILD_NUMBER 1 +#define PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h index 60b29e6475..9f5f850294 100644 --- a/deps/v8/src/x64/assembler-x64.h +++ b/deps/v8/src/x64/assembler-x64.h @@ -629,7 +629,8 @@ class Assembler : public AssemblerBase { static const byte kJccShortPrefix = 0x70; static const byte kJncShortOpcode = kJccShortPrefix | not_carry; static const byte kJcShortOpcode = kJccShortPrefix | carry; - + static const byte kJnzShortOpcode = kJccShortPrefix | not_zero; + static const byte kJzShortOpcode = kJccShortPrefix | zero; // --------------------------------------------------------------------------- diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 2845039771..d179d2a5d5 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -3628,8 +3628,9 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { void CallFunctionStub::Generate(MacroAssembler* masm) { - // rdi : the function to call // rbx : cache cell for call target + // rdi : the function to call + Isolate* isolate = masm->isolate(); Label slow, non_function; // The receiver might implicitly be the global object. This is @@ -3644,9 +3645,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); __ j(not_equal, &call, Label::kNear); // Patch the receiver on the stack with the global receiver object. - __ movq(rbx, GlobalObjectOperand()); - __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); - __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rbx); + __ movq(rcx, GlobalObjectOperand()); + __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); + __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rcx); __ bind(&call); } @@ -3656,6 +3657,10 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); __ j(not_equal, &slow); + if (RecordCallTarget()) { + GenerateRecordCallTarget(masm); + } + // Fast-case: Just invoke the function. ParameterCount actual(argc_); @@ -3678,6 +3683,13 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { // Slow-case: Non-function called. __ bind(&slow); + if (RecordCallTarget()) { + // If there is a call target cache, mark it megamorphic in the + // non-function case. MegamorphicSentinel is an immortal immovable + // object (undefined) so no write barrier is needed. + __ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), + TypeFeedbackCells::MegamorphicSentinel(isolate)); + } // Check for function proxy. __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); __ j(not_equal, &non_function); @@ -5112,56 +5124,24 @@ void SubStringStub::Generate(MacroAssembler* masm) { // rax: string // rbx: instance type // Calculate length of sub string using the smi values. - Label result_longer_than_two; __ movq(rcx, Operand(rsp, kToOffset)); __ movq(rdx, Operand(rsp, kFromOffset)); __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. - __ cmpq(FieldOperand(rax, String::kLengthOffset), rcx); + __ cmpq(rcx, FieldOperand(rax, String::kLengthOffset)); Label not_original_string; - __ j(not_equal, ¬_original_string, Label::kNear); + // Shorter than original string's length: an actual substring. + __ j(below, ¬_original_string, Label::kNear); + // Longer than original string's length or negative: unsafe arguments. + __ j(above, &runtime); + // Return original string. Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->sub_string_native(), 1); __ ret(kArgumentsSize); __ bind(¬_original_string); - // Special handling of sub-strings of length 1 and 2. One character strings - // are handled in the runtime system (looked up in the single character - // cache). Two character strings are looked for in the symbol cache. __ SmiToInteger32(rcx, rcx); - __ cmpl(rcx, Immediate(2)); - __ j(greater, &result_longer_than_two); - __ j(less, &runtime); - - // Sub string of length 2 requested. - // rax: string - // rbx: instance type - // rcx: sub string length (value is 2) - // rdx: from index (smi) - __ JumpIfInstanceTypeIsNotSequentialAscii(rbx, rbx, &runtime); - - // Get the two characters forming the sub string. - __ SmiToInteger32(rdx, rdx); // From index is no longer smi. - __ movzxbq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize)); - __ movzxbq(rdi, - FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize + 1)); - - // Try to lookup two character string in symbol table. - Label make_two_character_string; - StringHelper::GenerateTwoCharacterSymbolTableProbe( - masm, rbx, rdi, r9, r11, r14, r15, &make_two_character_string); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - - __ bind(&make_two_character_string); - // Set up registers for allocating the two character string. - __ movzxwq(rbx, FieldOperand(rax, rdx, times_1, SeqAsciiString::kHeaderSize)); - __ AllocateAsciiString(rax, rcx, r11, r14, r15, &runtime); - __ movw(FieldOperand(rax, SeqAsciiString::kHeaderSize), rbx); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - __ bind(&result_longer_than_two); // rax: string // rbx: instance type // rcx: sub string length diff --git a/deps/v8/src/x64/debug-x64.cc b/deps/v8/src/x64/debug-x64.cc index eec83d9d1e..94a50eb53e 100644 --- a/deps/v8/src/x64/debug-x64.cc +++ b/deps/v8/src/x64/debug-x64.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -91,6 +91,8 @@ void BreakLocationIterator::ClearDebugBreakAtSlot() { rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength); } +const bool Debug::FramePaddingLayout::kIsSupported = false; + #define __ ACCESS_MASM(masm) diff --git a/deps/v8/src/x64/deoptimizer-x64.cc b/deps/v8/src/x64/deoptimizer-x64.cc index 2adf587f8c..f3046b9ce3 100644 --- a/deps/v8/src/x64/deoptimizer-x64.cc +++ b/deps/v8/src/x64/deoptimizer-x64.cc @@ -111,13 +111,21 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } +static const byte kJnsInstruction = 0x79; +static const byte kJnsOffset = 0x1f; +static const byte kJaeInstruction = 0x73; +static const byte kJaeOffset = 0x07; +static const byte kCallInstruction = 0xe8; +static const byte kNopByteOne = 0x66; +static const byte kNopByteTwo = 0x90; + void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, Address pc_after, Code* check_code, Code* replacement_code) { Address call_target_address = pc_after - kIntSize; - ASSERT(check_code->entry() == - Assembler::target_address_at(call_target_address)); + ASSERT_EQ(check_code->entry(), + Assembler::target_address_at(call_target_address)); // The stack check code matches the pattern: // // cmp rsp, <limit> @@ -135,11 +143,16 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, // test rax, <loop nesting depth> // ok: // - ASSERT(*(call_target_address - 3) == 0x73 && // jae - *(call_target_address - 2) == 0x07 && // offset - *(call_target_address - 1) == 0xe8); // call - *(call_target_address - 3) = 0x66; // 2 byte nop part 1 - *(call_target_address - 2) = 0x90; // 2 byte nop part 2 + if (FLAG_count_based_interrupts) { + ASSERT_EQ(kJnsInstruction, *(call_target_address - 3)); + ASSERT_EQ(kJnsOffset, *(call_target_address - 2)); + } else { + ASSERT_EQ(kJaeInstruction, *(call_target_address - 3)); + ASSERT_EQ(kJaeOffset, *(call_target_address - 2)); + } + ASSERT_EQ(kCallInstruction, *(call_target_address - 1)); + *(call_target_address - 3) = kNopByteOne; + *(call_target_address - 2) = kNopByteTwo; Assembler::set_target_address_at(call_target_address, replacement_code->entry()); @@ -157,11 +170,16 @@ void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code, Assembler::target_address_at(call_target_address)); // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to // restore the conditional branch. - ASSERT(*(call_target_address - 3) == 0x66 && // 2 byte nop part 1 - *(call_target_address - 2) == 0x90 && // 2 byte nop part 2 - *(call_target_address - 1) == 0xe8); // call - *(call_target_address - 3) = 0x73; // jae - *(call_target_address - 2) = 0x07; // offset + ASSERT_EQ(kNopByteOne, *(call_target_address - 3)); + ASSERT_EQ(kNopByteTwo, *(call_target_address - 2)); + ASSERT_EQ(kCallInstruction, *(call_target_address - 1)); + if (FLAG_count_based_interrupts) { + *(call_target_address - 3) = kJnsInstruction; + *(call_target_address - 2) = kJnsOffset; + } else { + *(call_target_address - 3) = kJaeInstruction; + *(call_target_address - 2) = kJaeOffset; + } Assembler::set_target_address_at(call_target_address, check_code->entry()); @@ -440,6 +458,8 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator, void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, int frame_index) { + Builtins* builtins = isolate_->builtins(); + Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); unsigned height = iterator->Next(); unsigned height_in_bytes = height * kPointerSize; @@ -447,7 +467,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, PrintF(" translating construct stub => height=%d\n", height_in_bytes); } - unsigned fixed_frame_size = 6 * kPointerSize; + unsigned fixed_frame_size = 7 * kPointerSize; unsigned output_frame_size = height_in_bytes + fixed_frame_size; // Allocate and store the output frame description. @@ -516,6 +536,16 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, top_address + output_offset, output_offset, value); } + // The output frame reflects a JSConstructStubGeneric frame. + output_offset -= kPointerSize; + value = reinterpret_cast<intptr_t>(construct_stub); + output_frame->SetFrameSlot(output_offset, value); + if (FLAG_trace_deopt) { + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" + V8PRIxPTR " ; code object\n", + top_address + output_offset, output_offset, value); + } + // Number of incoming arguments. output_offset -= kPointerSize; value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1)); @@ -539,8 +569,6 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, ASSERT(0 == output_offset); - Builtins* builtins = isolate_->builtins(); - Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); intptr_t pc = reinterpret_cast<intptr_t>( construct_stub->instruction_start() + isolate_->heap()->construct_stub_deopt_pc_offset()->value()); diff --git a/deps/v8/src/x64/disasm-x64.cc b/deps/v8/src/x64/disasm-x64.cc index adeda0bb08..7ed81b47e1 100644 --- a/deps/v8/src/x64/disasm-x64.cc +++ b/deps/v8/src/x64/disasm-x64.cc @@ -315,7 +315,8 @@ class DisassemblerX64 { rex_(0), operand_size_(0), group_1_prefix_(0), - byte_size_operand_(false) { + byte_size_operand_(false), + instruction_table_(instruction_table.Pointer()) { tmp_buffer_[0] = '\0'; } @@ -344,6 +345,7 @@ class DisassemblerX64 { byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. // Byte size operand override. bool byte_size_operand_; + const InstructionTable* const instruction_table_; void setRex(byte rex) { ASSERT_EQ(0x40, rex & 0xF0); @@ -1340,7 +1342,7 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer, data++; } - const InstructionDesc& idesc = instruction_table.Get().Get(current); + const InstructionDesc& idesc = instruction_table_->Get(current); byte_size_operand_ = idesc.byte_size_operation; switch (idesc.type) { case ZERO_OPERANDS_INSTR: diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index 85c5e758c0..a6c4c99785 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -34,6 +34,7 @@ #include "compiler.h" #include "debug.h" #include "full-codegen.h" +#include "isolate-inl.h" #include "parser.h" #include "scopes.h" #include "stub-cache.h" @@ -100,11 +101,6 @@ class JumpPatchSite BASE_EMBEDDED { }; -int FullCodeGenerator::self_optimization_header_size() { - return 20; -} - - // Generate code for a JS function. On entry to the function the receiver // and arguments have been pushed on the stack left to right, with the // return address on top of them. The actual argument count matches the @@ -122,32 +118,11 @@ void FullCodeGenerator::Generate() { CompilationInfo* info = info_; handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); + profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell( + Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget))); SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); - // We can optionally optimize based on counters rather than statistical - // sampling. - if (info->ShouldSelfOptimize()) { - if (FLAG_trace_opt_verbose) { - PrintF("[adding self-optimization header to %s]\n", - *info->function()->debug_name()->ToCString()); - } - has_self_optimization_header_ = true; - MaybeObject* maybe_cell = isolate()->heap()->AllocateJSGlobalPropertyCell( - Smi::FromInt(Compiler::kCallsUntilPrimitiveOpt)); - JSGlobalPropertyCell* cell; - if (maybe_cell->To(&cell)) { - __ movq(rax, Handle<JSGlobalPropertyCell>(cell), - RelocInfo::EMBEDDED_OBJECT); - __ SmiAddConstant(FieldOperand(rax, JSGlobalPropertyCell::kValueOffset), - Smi::FromInt(-1)); - Handle<Code> compile_stub( - isolate()->builtins()->builtin(Builtins::kLazyRecompile)); - __ j(zero, compile_stub, RelocInfo::CODE_TARGET); - ASSERT(masm_->pc_offset() == self_optimization_header_size()); - } - } - #ifdef DEBUG if (strlen(FLAG_stop_at) > 0 && info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { @@ -282,11 +257,11 @@ void FullCodeGenerator::Generate() { // For named function expressions, declare the function name as a // constant. if (scope()->is_function_scope() && scope()->function() != NULL) { - VariableProxy* proxy = scope()->function(); - ASSERT(proxy->var()->mode() == CONST || - proxy->var()->mode() == CONST_HARMONY); - ASSERT(proxy->var()->location() != Variable::UNALLOCATED); - EmitDeclaration(proxy, proxy->var()->mode(), NULL); + VariableDeclaration* function = scope()->function(); + ASSERT(function->proxy()->var()->mode() == CONST || + function->proxy()->var()->mode() == CONST_HARMONY); + ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); + VisitVariableDeclaration(function); } VisitDeclarations(scope()->declarations()); } @@ -322,14 +297,60 @@ void FullCodeGenerator::ClearAccumulator() { } +void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { + __ movq(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT); + __ SmiAddConstant(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), + Smi::FromInt(-delta)); +} + + +void FullCodeGenerator::EmitProfilingCounterReset() { + int reset_value = FLAG_interrupt_budget; + if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { + // Self-optimization is a one-off thing; if it fails, don't try again. + reset_value = Smi::kMaxValue; + } + if (isolate()->IsDebuggerActive()) { + // Detect debug break requests as soon as possible. + reset_value = 10; + } + __ movq(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT); + __ movq(kScratchRegister, + reinterpret_cast<uint64_t>(Smi::FromInt(reset_value)), + RelocInfo::NONE); + __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), + kScratchRegister); +} + + +static const int kMaxBackEdgeWeight = 127; +static const int kBackEdgeDistanceDivisor = 162; + + void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, Label* back_edge_target) { Comment cmnt(masm_, "[ Stack check"); Label ok; - __ CompareRoot(rsp, Heap::kStackLimitRootIndex); - __ j(above_equal, &ok, Label::kNear); - StackCheckStub stub; - __ CallStub(&stub); + + if (FLAG_count_based_interrupts) { + int weight = 1; + if (FLAG_weighted_back_edges) { + ASSERT(back_edge_target->is_bound()); + int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); + weight = Min(kMaxBackEdgeWeight, + Max(1, distance / kBackEdgeDistanceDivisor)); + } + EmitProfilingCounterDecrement(weight); + __ j(positive, &ok, Label::kNear); + InterruptStub stub; + __ CallStub(&stub); + } else { + __ CompareRoot(rsp, Heap::kStackLimitRootIndex); + __ j(above_equal, &ok, Label::kNear); + StackCheckStub stub; + __ CallStub(&stub); + } + // Record a mapping of this PC offset to the OSR id. This is used to find // the AST id from the unoptimized code in order to use it as a key into // the deoptimization input data found in the optimized code. @@ -342,6 +363,10 @@ void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, ASSERT(loop_depth() > 0); __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker))); + if (FLAG_count_based_interrupts) { + EmitProfilingCounterReset(); + } + __ bind(&ok); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); // Record a mapping of the OSR id to this PC. This is used if the OSR @@ -361,6 +386,31 @@ void FullCodeGenerator::EmitReturnSequence() { __ push(rax); __ CallRuntime(Runtime::kTraceExit, 1); } + if (FLAG_interrupt_at_exit || FLAG_self_optimization) { + // Pretend that the exit is a backwards jump to the entry. + int weight = 1; + if (info_->ShouldSelfOptimize()) { + weight = FLAG_interrupt_budget / FLAG_self_opt_count; + } else if (FLAG_weighted_back_edges) { + int distance = masm_->pc_offset(); + weight = Min(kMaxBackEdgeWeight, + Max(1, distance = kBackEdgeDistanceDivisor)); + } + EmitProfilingCounterDecrement(weight); + Label ok; + __ j(positive, &ok, Label::kNear); + __ push(rax); + if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { + __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); + __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); + } else { + InterruptStub stub; + __ CallStub(&stub); + } + __ pop(rax); + EmitProfilingCounterReset(); + __ bind(&ok); + } #ifdef DEBUG // Add a label for checking the size of the code used for returning. Label check_exit_codesize; @@ -703,61 +753,51 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, } -void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, - VariableMode mode, - FunctionLiteral* function) { +void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { + // The variable in the declaration always resides in the current function + // context. + ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); + if (FLAG_debug_code) { + // Check that we're not inside a with or catch context. + __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset)); + __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); + __ Check(not_equal, "Declaration in with context."); + __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); + __ Check(not_equal, "Declaration in catch context."); + } +} + + +void FullCodeGenerator::VisitVariableDeclaration( + VariableDeclaration* declaration) { // If it was not possible to allocate the variable at compile time, we // need to "declare" it at runtime to make sure it actually exists in the // local context. + VariableProxy* proxy = declaration->proxy(); + VariableMode mode = declaration->mode(); Variable* variable = proxy->var(); - bool binding_needs_init = (function == NULL) && - (mode == CONST || mode == CONST_HARMONY || mode == LET); + bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; switch (variable->location()) { case Variable::UNALLOCATED: - ++global_count_; + globals_->Add(variable->name()); + globals_->Add(variable->binding_needs_init() + ? isolate()->factory()->the_hole_value() + : isolate()->factory()->undefined_value()); break; case Variable::PARAMETER: case Variable::LOCAL: - if (function != NULL) { - Comment cmnt(masm_, "[ Declaration"); - VisitForAccumulatorValue(function); - __ movq(StackOperand(variable), result_register()); - } else if (binding_needs_init) { - Comment cmnt(masm_, "[ Declaration"); + if (hole_init) { + Comment cmnt(masm_, "[ VariableDeclaration"); __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); __ movq(StackOperand(variable), kScratchRegister); } break; case Variable::CONTEXT: - // The variable in the decl always resides in the current function - // context. - ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); - if (FLAG_debug_code) { - // Check that we're not inside a with or catch context. - __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset)); - __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); - __ Check(not_equal, "Declaration in with context."); - __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); - __ Check(not_equal, "Declaration in catch context."); - } - if (function != NULL) { - Comment cmnt(masm_, "[ Declaration"); - VisitForAccumulatorValue(function); - __ movq(ContextOperand(rsi, variable->index()), result_register()); - int offset = Context::SlotOffset(variable->index()); - // We know that we have written a function, which is not a smi. - __ RecordWriteContextSlot(rsi, - offset, - result_register(), - rcx, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - PrepareForBailoutForId(proxy->id(), NO_REGISTERS); - } else if (binding_needs_init) { - Comment cmnt(masm_, "[ Declaration"); + if (hole_init) { + Comment cmnt(masm_, "[ VariableDeclaration"); + EmitDebugCheckDeclarationContext(variable); __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); // No write barrier since the hole value is in old space. @@ -766,14 +806,12 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, break; case Variable::LOOKUP: { - Comment cmnt(masm_, "[ Declaration"); + Comment cmnt(masm_, "[ VariableDeclaration"); __ push(rsi); __ Push(variable->name()); // Declaration nodes are always introduced in one of four modes. - ASSERT(mode == VAR || - mode == CONST || - mode == CONST_HARMONY || - mode == LET); + ASSERT(mode == VAR || mode == LET || + mode == CONST || mode == CONST_HARMONY); PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; __ Push(Smi::FromInt(attr)); @@ -781,9 +819,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, // Note: For variables we must not push an initial value (such as // 'undefined') because we may have a (legal) redeclaration and we // must not destroy the current value. - if (function != NULL) { - VisitForStackValue(function); - } else if (binding_needs_init) { + if (hole_init) { __ PushRoot(Heap::kTheHoleValueRootIndex); } else { __ Push(Smi::FromInt(0)); // Indicates no initial value. @@ -795,6 +831,119 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, } +void FullCodeGenerator::VisitFunctionDeclaration( + FunctionDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: { + globals_->Add(variable->name()); + Handle<SharedFunctionInfo> function = + Compiler::BuildFunctionInfo(declaration->fun(), script()); + // Check for stack-overflow exception. + if (function.is_null()) return SetStackOverflow(); + globals_->Add(function); + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + VisitForAccumulatorValue(declaration->fun()); + __ movq(StackOperand(variable), result_register()); + break; + } + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + EmitDebugCheckDeclarationContext(variable); + VisitForAccumulatorValue(declaration->fun()); + __ movq(ContextOperand(rsi, variable->index()), result_register()); + int offset = Context::SlotOffset(variable->index()); + // We know that we have written a function, which is not a smi. + __ RecordWriteContextSlot(rsi, + offset, + result_register(), + rcx, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + PrepareForBailoutForId(proxy->id(), NO_REGISTERS); + break; + } + + case Variable::LOOKUP: { + Comment cmnt(masm_, "[ FunctionDeclaration"); + __ push(rsi); + __ Push(variable->name()); + __ Push(Smi::FromInt(NONE)); + VisitForStackValue(declaration->fun()); + __ CallRuntime(Runtime::kDeclareContextSlot, 4); + break; + } + } +} + + +void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + Handle<JSModule> instance = declaration->module()->interface()->Instance(); + ASSERT(!instance.is_null()); + + switch (variable->location()) { + case Variable::UNALLOCATED: { + Comment cmnt(masm_, "[ ModuleDeclaration"); + globals_->Add(variable->name()); + globals_->Add(instance); + Visit(declaration->module()); + break; + } + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ ModuleDeclaration"); + EmitDebugCheckDeclarationContext(variable); + __ Move(ContextOperand(rsi, variable->index()), instance); + Visit(declaration->module()); + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::LOOKUP: + UNREACHABLE(); + } +} + + +void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { + VariableProxy* proxy = declaration->proxy(); + Variable* variable = proxy->var(); + switch (variable->location()) { + case Variable::UNALLOCATED: + // TODO(rossberg) + break; + + case Variable::CONTEXT: { + Comment cmnt(masm_, "[ ImportDeclaration"); + EmitDebugCheckDeclarationContext(variable); + // TODO(rossberg) + break; + } + + case Variable::PARAMETER: + case Variable::LOCAL: + case Variable::LOOKUP: + UNREACHABLE(); + } +} + + +void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { + // TODO(rossberg) +} + + void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { // Call the runtime to declare the globals. __ push(rsi); // The context is the first argument. @@ -856,7 +1005,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // Record position before stub call for type feedback. SetSourcePosition(clause->position()); Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); - __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId()); + CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); patch_site.EmitPatchInfo(); __ testq(rax, rax); @@ -1155,7 +1304,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT; - __ call(ic, mode); + CallIC(ic, mode); } @@ -1236,7 +1385,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { __ Move(rcx, var->name()); __ movq(rax, GlobalObjectOperand()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); + CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); context()->Plug(rax); break; } @@ -1446,7 +1595,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ call(ic, RelocInfo::CODE_TARGET, key->id()); + CallIC(ic, RelocInfo::CODE_TARGET, key->id()); PrepareForBailoutForId(key->id(), NO_REGISTERS); } else { VisitForEffect(value); @@ -1716,14 +1865,14 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { Literal* key = prop->key()->AsLiteral(); __ Move(rcx, key->handle()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - __ call(ic, RelocInfo::CODE_TARGET, prop->id()); + CallIC(ic, RelocInfo::CODE_TARGET, prop->id()); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - __ call(ic, RelocInfo::CODE_TARGET, prop->id()); + CallIC(ic, RelocInfo::CODE_TARGET, prop->id()); } @@ -1745,7 +1894,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, __ bind(&stub_call); __ movq(rax, rcx); BinaryOpStub stub(op, mode); - __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); patch_site.EmitPatchInfo(); __ jmp(&done, Label::kNear); @@ -1794,7 +1943,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, __ pop(rdx); BinaryOpStub stub(op, mode); JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. - __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); patch_site.EmitPatchInfo(); context()->Plug(rax); } @@ -1835,7 +1984,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ call(ic); + CallIC(ic); break; } case KEYED_PROPERTY: { @@ -1848,7 +1997,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - __ call(ic); + CallIC(ic); break; } } @@ -1865,7 +2014,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); + CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); } else if (op == Token::INIT_CONST) { // Const initializers need a write barrier. ASSERT(!var->IsParameter()); // No const parameters. @@ -1973,7 +2122,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); // If the assignment ends an initialization block, revert to fast case. if (expr->ends_initialization_block()) { @@ -2013,7 +2162,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - __ call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); // If the assignment ends an initialization block, revert to fast case. if (expr->ends_initialization_block()) { @@ -2047,6 +2196,14 @@ void FullCodeGenerator::VisitProperty(Property* expr) { } +void FullCodeGenerator::CallIC(Handle<Code> code, + RelocInfo::Mode rmode, + unsigned ast_id) { + ic_total_count_++; + __ call(code, rmode, ast_id); +} + + void FullCodeGenerator::EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode) { @@ -2064,7 +2221,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, // Call the IC initialization code. Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); - __ call(ic, mode, expr->id()); + CallIC(ic, mode, expr->id()); RecordJSReturnSite(expr); // Restore context register. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); @@ -2097,7 +2254,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key. - __ call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); RecordJSReturnSite(expr); // Restore context register. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); @@ -2116,6 +2273,18 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { } // Record source position for debugger. SetSourcePosition(expr->position()); + + // Record call targets in unoptimized code, but not in the snapshot. + if (!Serializer::enabled()) { + flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); + Handle<Object> uninitialized = + TypeFeedbackCells::UninitializedSentinel(isolate()); + Handle<JSGlobalPropertyCell> cell = + isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); + RecordTypeFeedbackCell(expr->id(), cell); + __ Move(rbx, cell); + } + CallFunctionStub stub(arg_count, flags); __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize)); __ CallStub(&stub); @@ -3737,7 +3906,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { RelocInfo::Mode mode = RelocInfo::CODE_TARGET; Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode); - __ call(ic, mode, expr->id()); + CallIC(ic, mode, expr->id()); // Restore context register. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); } else { @@ -3895,7 +4064,7 @@ void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr, // accumulator register rax. VisitForAccumulatorValue(expr->expression()); SetSourcePosition(expr->position()); - __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); context()->Plug(rax); } @@ -4016,7 +4185,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ movq(rdx, rax); __ Move(rax, Smi::FromInt(1)); } - __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); + CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); patch_site.EmitPatchInfo(); __ bind(&done); @@ -4050,7 +4219,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); - __ call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { if (!context()->IsEffect()) { @@ -4067,7 +4236,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); - __ call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { if (!context()->IsEffect()) { @@ -4094,7 +4263,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); // Use a regular load, not a contextual load, to avoid a reference // error. - __ call(ic); + CallIC(ic); PrepareForBailout(expr, TOS_REG); context()->Plug(rax); } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { @@ -4274,7 +4443,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { // Record position and call the compare IC. SetSourcePosition(expr->position()); Handle<Code> ic = CompareIC::GetUninitialized(op); - __ call(ic, RelocInfo::CODE_TARGET, expr->id()); + CallIC(ic, RelocInfo::CODE_TARGET, expr->id()); patch_site.EmitPatchInfo(); PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); @@ -4354,7 +4523,8 @@ void FullCodeGenerator::LoadContextField(Register dst, int context_index) { void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { Scope* declaration_scope = scope()->DeclarationScope(); - if (declaration_scope->is_global_scope()) { + if (declaration_scope->is_global_scope() || + declaration_scope->is_module_scope()) { // Contexts nested in the global context have a canonical empty function // as their closure, not the anonymous closure containing the global // code. Pass a smi sentinel and let the runtime look up the empty diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc index 0632ce439f..6ba5fb6e2c 100644 --- a/deps/v8/src/x64/ic-x64.cc +++ b/deps/v8/src/x64/ic-x64.cc @@ -1741,11 +1741,11 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { // Activate inlined smi code. if (previous_state == UNINITIALIZED) { - PatchInlinedSmiCode(address()); + PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); } } -void PatchInlinedSmiCode(Address address) { +void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { // The address of the instruction following the call. Address test_instruction_address = address + Assembler::kCallTargetAddressOffset; @@ -1766,14 +1766,18 @@ void PatchInlinedSmiCode(Address address) { address, test_instruction_address, delta); } - // Patch with a short conditional jump. There must be a - // short jump-if-carry/not-carry at this position. + // Patch with a short conditional jump. Enabling means switching from a short + // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the + // reverse operation of that. Address jmp_address = test_instruction_address - delta; - ASSERT(*jmp_address == Assembler::kJncShortOpcode || - *jmp_address == Assembler::kJcShortOpcode); - Condition cc = *jmp_address == Assembler::kJncShortOpcode - ? not_zero - : zero; + ASSERT((check == ENABLE_INLINED_SMI_CHECK) + ? (*jmp_address == Assembler::kJncShortOpcode || + *jmp_address == Assembler::kJcShortOpcode) + : (*jmp_address == Assembler::kJnzShortOpcode || + *jmp_address == Assembler::kJzShortOpcode)); + Condition cc = (check == ENABLE_INLINED_SMI_CHECK) + ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) + : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); } diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index 2ba2c57f40..5f5c2af3a4 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -2016,8 +2016,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, RECORD_SAFEPOINT_WITH_REGISTERS, 2); ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check)); - ASSERT(instr->HasDeoptimizationEnvironment()); - LEnvironment* env = instr->deoptimization_environment(); + LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment(); safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); // Move result to a register that survives the end of the // PushSafepointRegisterScope. @@ -2224,41 +2223,35 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { Register result = ToRegister(instr->result()); int map_count = instr->hydrogen()->types()->length(); - Handle<String> name = instr->hydrogen()->name(); + bool need_generic = instr->hydrogen()->need_generic(); - if (map_count == 0) { - ASSERT(instr->hydrogen()->need_generic()); - __ Move(rcx, instr->hydrogen()->name()); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); - } else { - Label done; - for (int i = 0; i < map_count - 1; ++i) { - Handle<Map> map = instr->hydrogen()->types()->at(i); + if (map_count == 0 && !need_generic) { + DeoptimizeIf(no_condition, instr->environment()); + return; + } + Handle<String> name = instr->hydrogen()->name(); + Label done; + for (int i = 0; i < map_count; ++i) { + bool last = (i == map_count - 1); + Handle<Map> map = instr->hydrogen()->types()->at(i); + __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map); + if (last && !need_generic) { + DeoptimizeIf(not_equal, instr->environment()); + EmitLoadFieldOrConstantFunction(result, object, map, name); + } else { Label next; - __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map); __ j(not_equal, &next, Label::kNear); EmitLoadFieldOrConstantFunction(result, object, map, name); __ jmp(&done, Label::kNear); __ bind(&next); } - Handle<Map> map = instr->hydrogen()->types()->last(); - __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map); - if (instr->hydrogen()->need_generic()) { - Label generic; - __ j(not_equal, &generic, Label::kNear); - EmitLoadFieldOrConstantFunction(result, object, map, name); - __ jmp(&done, Label::kNear); - __ bind(&generic); - __ Move(rcx, instr->hydrogen()->name()); - Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); - } else { - DeoptimizeIf(not_equal, instr->environment()); - EmitLoadFieldOrConstantFunction(result, object, map, name); - } - __ bind(&done); } + if (need_generic) { + __ Move(rcx, name); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); + CallCode(ic, RelocInfo::CODE_TARGET, instr); + } + __ bind(&done); } @@ -2497,24 +2490,28 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { Register result = ToRegister(instr->result()); - // Check for arguments adapter frame. - Label done, adapted; - __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); - __ Cmp(Operand(result, StandardFrameConstants::kContextOffset), - Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); - __ j(equal, &adapted, Label::kNear); - - // No arguments adaptor frame. - __ movq(result, rbp); - __ jmp(&done, Label::kNear); + if (instr->hydrogen()->from_inlined()) { + __ lea(result, Operand(rsp, -2 * kPointerSize)); + } else { + // Check for arguments adapter frame. + Label done, adapted; + __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); + __ Cmp(Operand(result, StandardFrameConstants::kContextOffset), + Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); + __ j(equal, &adapted, Label::kNear); + + // No arguments adaptor frame. + __ movq(result, rbp); + __ jmp(&done, Label::kNear); - // Arguments adaptor frame present. - __ bind(&adapted); - __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); + // Arguments adaptor frame present. + __ bind(&adapted); + __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); - // Result is the frame pointer for the frame if not adapted and for the real - // frame below the adaptor frame if adapted. - __ bind(&done); + // Result is the frame pointer for the frame if not adapted and for the real + // frame below the adaptor frame if adapted. + __ bind(&done); + } } @@ -2622,7 +2619,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { // Invoke the function. __ bind(&invoke); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator( @@ -2640,6 +2637,11 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) { } +void LCodeGen::DoDrop(LDrop* instr) { + __ Drop(instr->count()); +} + + void LCodeGen::DoThisFunction(LThisFunction* instr) { Register result = ToRegister(instr->result()); __ LoadHeapObject(result, instr->hydrogen()->closure()); @@ -2684,7 +2686,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { void LCodeGen::CallKnownFunction(Handle<JSFunction> function, int arity, LInstruction* instr, - CallKind call_kind) { + CallKind call_kind, + RDIState rdi_state) { bool can_invoke_directly = !function->NeedsArgumentsAdaption() || function->shared()->formal_parameter_count() == arity; @@ -2692,7 +2695,9 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, RecordPosition(pointers->position()); if (can_invoke_directly) { - __ LoadHeapObject(rdi, function); + if (rdi_state == RDI_UNINITIALIZED) { + __ LoadHeapObject(rdi, function); + } // Change context if needed. bool change_context = @@ -2737,7 +2742,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { CallKnownFunction(instr->function(), instr->arity(), instr, - CALL_AS_METHOD); + CALL_AS_METHOD, + RDI_UNINITIALIZED); } @@ -3174,13 +3180,21 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { ASSERT(ToRegister(instr->function()).is(rdi)); ASSERT(instr->HasPointerMap()); - ASSERT(instr->HasDeoptimizationEnvironment()); - LPointerMap* pointers = instr->pointer_map(); - RecordPosition(pointers->position()); - SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); - ParameterCount count(instr->arity()); - __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); - __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + + if (instr->known_function().is_null()) { + LPointerMap* pointers = instr->pointer_map(); + RecordPosition(pointers->position()); + SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); + ParameterCount count(instr->arity()); + __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); + __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + } else { + CallKnownFunction(instr->known_function(), + instr->arity(), + instr, + CALL_AS_METHOD, + RDI_CONTAINS_TARGET); + } } @@ -3234,7 +3248,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { ASSERT(ToRegister(instr->result()).is(rax)); - CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); + CallKnownFunction(instr->target(), + instr->arity(), + instr, + CALL_AS_FUNCTION, + RDI_UNINITIALIZED); } @@ -3421,16 +3439,20 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { void LCodeGen::DoStoreKeyedFastDoubleElement( LStoreKeyedFastDoubleElement* instr) { XMMRegister value = ToDoubleRegister(instr->value()); - Label have_value; - __ ucomisd(value, value); - __ j(parity_odd, &have_value); // NaN. + if (instr->NeedsCanonicalization()) { + Label have_value; + + __ ucomisd(value, value); + __ j(parity_odd, &have_value); // NaN. - __ Set(kScratchRegister, BitCast<uint64_t>( - FixedDoubleArray::canonical_not_the_hole_nan_as_double())); - __ movq(value, kScratchRegister); + __ Set(kScratchRegister, BitCast<uint64_t>( + FixedDoubleArray::canonical_not_the_hole_nan_as_double())); + __ movq(value, kScratchRegister); + + __ bind(&have_value); + } - __ bind(&have_value); Operand double_store_operand = BuildFastArrayOperand( instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS, FixedDoubleArray::kHeaderSize - kHeapObjectTag); @@ -3953,12 +3975,21 @@ void LCodeGen::DoCheckMapCommon(Register reg, } -void LCodeGen::DoCheckMap(LCheckMap* instr) { +void LCodeGen::DoCheckMaps(LCheckMaps* instr) { LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister()); Register reg = ToRegister(input); - Handle<Map> map = instr->hydrogen()->map(); - DoCheckMapCommon(reg, map, instr->hydrogen()->mode(), instr->environment()); + + Label success; + SmallMapList* map_set = instr->hydrogen()->map_set(); + for (int i = 0; i < map_set->length() - 1; i++) { + Handle<Map> map = map_set->at(i); + __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP); + __ j(equal, &success); + } + Handle<Map> map = map_set->last(); + DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment()); + __ bind(&success); } @@ -4071,6 +4102,14 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { deferred->entry(), TAG_OBJECT); + __ bind(deferred->exit()); + if (FLAG_debug_code) { + Label is_in_new_space; + __ JumpIfInNewSpace(result, scratch, &is_in_new_space); + __ Abort("Allocated object is not in new-space"); + __ bind(&is_in_new_space); + } + // Load the initial map. Register map = scratch; __ LoadHeapObject(scratch, constructor); @@ -4105,14 +4144,14 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { __ movq(FieldOperand(result, property_offset), scratch); } } - - __ bind(deferred->exit()); } void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { Register result = ToRegister(instr->result()); Handle<JSFunction> constructor = instr->hydrogen()->constructor(); + Handle<Map> initial_map(constructor->initial_map()); + int instance_size = initial_map->instance_size(); // TODO(3095996): Get rid of this. For now, we need to make the // result register contain a valid pointer because it is already @@ -4120,8 +4159,8 @@ void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { __ Set(result, 0); PushSafepointRegistersScope scope(this); - __ PushHeapObject(constructor); - CallRuntimeFromDeferred(Runtime::kNewObject, 1, instr); + __ Push(Smi::FromInt(instance_size)); + CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); __ StoreToSafepointRegisterSlot(result, rax); } @@ -4250,9 +4289,10 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, __ movq(FieldOperand(result, total_offset), rcx); } } else if (elements->IsFixedArray()) { + Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); for (int i = 0; i < elements_length; i++) { int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i); - Handle<Object> value = JSObject::GetElement(object, i); + Handle<Object> value(fast_elements->get(i)); if (value->IsJSObject()) { Handle<JSObject> value_object = Handle<JSObject>::cast(value); __ lea(rcx, Operand(result, *offset)); @@ -4276,6 +4316,23 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, void LCodeGen::DoFastLiteral(LFastLiteral* instr) { int size = instr->hydrogen()->total_size(); + ElementsKind boilerplate_elements_kind = + instr->hydrogen()->boilerplate()->GetElementsKind(); + + // Deopt if the literal boilerplate ElementsKind is of a type different than + // the expected one. The check isn't necessary if the boilerplate has already + // been converted to FAST_ELEMENTS. + if (boilerplate_elements_kind != FAST_ELEMENTS) { + __ LoadHeapObject(rbx, instr->hydrogen()->boilerplate()); + __ movq(rcx, FieldOperand(rbx, HeapObject::kMapOffset)); + // Load the map's "bit field 2". + __ movb(rcx, FieldOperand(rcx, Map::kBitField2Offset)); + // Retrieve elements_kind from bit field 2. + __ and_(rcx, Immediate(Map::kElementsKindMask)); + __ cmpb(rcx, Immediate(boilerplate_elements_kind << + Map::kElementsKindShift)); + DeoptimizeIf(not_equal, instr->environment()); + } // Allocate all objects that are part of the literal in one big // allocation. This avoids multiple limit checks. @@ -4574,7 +4631,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { LOperand* key = instr->key(); EmitPushTaggedOperand(obj); EmitPushTaggedOperand(key); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); // Create safepoint generator that will also ensure enough space in the @@ -4592,7 +4649,7 @@ void LCodeGen::DoIn(LIn* instr) { LOperand* key = instr->key(); EmitPushTaggedOperand(key); EmitPushTaggedOperand(obj); - ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); SafepointGenerator safepoint_generator( diff --git a/deps/v8/src/x64/lithium-codegen-x64.h b/deps/v8/src/x64/lithium-codegen-x64.h index f5045b66a2..1331fba555 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.h +++ b/deps/v8/src/x64/lithium-codegen-x64.h @@ -196,12 +196,18 @@ class LCodeGen BASE_EMBEDDED { int argc, LInstruction* instr); + enum RDIState { + RDI_UNINITIALIZED, + RDI_CONTAINS_TARGET + }; + // Generate a direct call to a known function. Expects the function // to be in rdi. void CallKnownFunction(Handle<JSFunction> function, int arity, LInstruction* instr, - CallKind call_kind); + CallKind call_kind, + RDIState rdi_state); void RecordSafepointWithLazyDeopt(LInstruction* instr, diff --git a/deps/v8/src/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc index d3e4cddf74..3ba0cae7ad 100644 --- a/deps/v8/src/x64/lithium-x64.cc +++ b/deps/v8/src/x64/lithium-x64.cc @@ -110,22 +110,17 @@ void LInstruction::PrintTo(StringStream* stream) { } -template<int R, int I, int T> -void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) { +void LInstruction::PrintDataTo(StringStream* stream) { stream->Add("= "); - for (int i = 0; i < inputs_.length(); i++) { + for (int i = 0; i < InputCount(); i++) { if (i > 0) stream->Add(" "); - inputs_[i]->PrintTo(stream); + InputAt(i)->PrintTo(stream); } } -template<int R, int I, int T> -void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) { - for (int i = 0; i < results_.length(); i++) { - if (i > 0) stream->Add(" "); - results_[i]->PrintTo(stream); - } +void LInstruction::PrintOutputOperandTo(StringStream* stream) { + if (HasResult()) result()->PrintTo(stream); } @@ -727,22 +722,6 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { } -LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( - LInstruction* instr, int ast_id) { - ASSERT(instruction_pending_deoptimization_environment_ == NULL); - ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); - instruction_pending_deoptimization_environment_ = instr; - pending_deoptimization_ast_id_ = ast_id; - return instr; -} - - -void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { - instruction_pending_deoptimization_environment_ = NULL; - pending_deoptimization_ast_id_ = AstNode::kNoNumber; -} - - LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, HInstruction* hinstr, CanDeoptimize can_deoptimize) { @@ -755,8 +734,10 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, if (hinstr->HasObservableSideEffects()) { ASSERT(hinstr->next()->IsSimulate()); HSimulate* sim = HSimulate::cast(hinstr->next()); - instr = SetInstructionPendingDeoptimizationEnvironment( - instr, sim->ast_id()); + ASSERT(instruction_pending_deoptimization_environment_ == NULL); + ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); + instruction_pending_deoptimization_environment_ = instr; + pending_deoptimization_ast_id_ = sim->ast_id(); } // If instruction does not have side-effects lazy deoptimization @@ -774,12 +755,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, } -LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) { - instr->MarkAsSaveDoubles(); - return instr; -} - - LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) { ASSERT(!instr->HasPointerMap()); instr->set_pointer_map(new(zone()) LPointerMap(position_)); @@ -1285,6 +1260,7 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { ASSERT(instr->value()->representation().IsInteger32()); ASSERT(instr->representation().IsInteger32()); + if (instr->HasNoUses()) return NULL; LOperand* input = UseRegisterAtStart(instr->value()); LBitNotI* result = new(zone()) LBitNotI(input); return DefineSameAsFirst(result); @@ -1309,6 +1285,12 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { } +LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) { + UNIMPLEMENTED(); + return NULL; +} + + LInstruction* LChunkBuilder::DoMod(HMod* instr) { if (instr->representation().IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); @@ -1737,9 +1719,9 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { } -LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) { +LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { LOperand* value = UseRegisterAtStart(instr->value()); - LCheckMap* result = new(zone()) LCheckMap(value); + LCheckMaps* result = new(zone()) LCheckMaps(value); return AssignEnvironment(result); } @@ -2241,9 +2223,12 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { if (pending_deoptimization_ast_id_ == instr->ast_id()) { LLazyBailout* lazy_bailout = new(zone()) LLazyBailout; LInstruction* result = AssignEnvironment(lazy_bailout); + // Store the lazy deopt environment with the instruction if needed. Right + // now it is only used for LInstanceOfKnownGlobal. instruction_pending_deoptimization_environment_-> - set_deoptimization_environment(result->environment()); - ClearInstructionPendingDeoptimizationEnvironment(); + SetDeferredLazyDeoptimizationEnvironment(result->environment()); + instruction_pending_deoptimization_environment_ = NULL; + pending_deoptimization_ast_id_ = AstNode::kNoNumber; return result; } @@ -2270,6 +2255,9 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { undefined, instr->call_kind(), instr->is_construct()); + if (instr->arguments_var() != NULL) { + inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject()); + } current_block_->UpdateEnvironment(inner); chunk_->AddInlinedClosure(instr->closure()); return NULL; @@ -2277,10 +2265,21 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { + LInstruction* pop = NULL; + + HEnvironment* env = current_block_->last_environment(); + + if (instr->arguments_pushed()) { + int argument_count = env->arguments_environment()->parameter_count(); + pop = new(zone()) LDrop(argument_count); + argument_count_ -= argument_count; + } + HEnvironment* outer = current_block_->last_environment()-> DiscardInlined(false); current_block_->UpdateEnvironment(outer); - return NULL; + + return pop; } diff --git a/deps/v8/src/x64/lithium-x64.h b/deps/v8/src/x64/lithium-x64.h index 2d8fd2ecce..9083c1f8db 100644 --- a/deps/v8/src/x64/lithium-x64.h +++ b/deps/v8/src/x64/lithium-x64.h @@ -71,7 +71,7 @@ class LCodeGen; V(CallStub) \ V(CheckFunction) \ V(CheckInstanceType) \ - V(CheckMap) \ + V(CheckMaps) \ V(CheckNonSmi) \ V(CheckPrototypeMaps) \ V(CheckSmi) \ @@ -179,7 +179,8 @@ class LCodeGen; V(CheckMapValue) \ V(LoadFieldByIndex) \ V(DateField) \ - V(WrapReceiver) + V(WrapReceiver) \ + V(Drop) #define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \ @@ -203,16 +204,15 @@ class LInstruction: public ZoneObject { LInstruction() : environment_(NULL), hydrogen_value_(NULL), - is_call_(false), - is_save_doubles_(false) { } + is_call_(false) { } virtual ~LInstruction() { } virtual void CompileToNative(LCodeGen* generator) = 0; virtual const char* Mnemonic() const = 0; virtual void PrintTo(StringStream* stream); - virtual void PrintDataTo(StringStream* stream) = 0; - virtual void PrintOutputOperandTo(StringStream* stream) = 0; + virtual void PrintDataTo(StringStream* stream); + virtual void PrintOutputOperandTo(StringStream* stream); enum Opcode { // Declare a unique enum value for each instruction. @@ -247,22 +247,12 @@ class LInstruction: public ZoneObject { void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; } HValue* hydrogen_value() const { return hydrogen_value_; } - void set_deoptimization_environment(LEnvironment* env) { - deoptimization_environment_.set(env); - } - LEnvironment* deoptimization_environment() const { - return deoptimization_environment_.get(); - } - bool HasDeoptimizationEnvironment() const { - return deoptimization_environment_.is_set(); - } - void MarkAsCall() { is_call_ = true; } - void MarkAsSaveDoubles() { is_save_doubles_ = true; } + + virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { } // Interface to the register allocator and iterators. bool IsMarkedAsCall() const { return is_call_; } - bool IsMarkedAsSaveDoubles() const { return is_save_doubles_; } virtual bool HasResult() const = 0; virtual LOperand* result() = 0; @@ -283,9 +273,7 @@ class LInstruction: public ZoneObject { LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; - SetOncePointer<LEnvironment> deoptimization_environment_; bool is_call_; - bool is_save_doubles_; }; @@ -307,9 +295,6 @@ class LTemplateInstruction: public LInstruction { int TempCount() { return T; } LOperand* TempAt(int i) { return temps_[i]; } - virtual void PrintDataTo(StringStream* stream); - virtual void PrintOutputOperandTo(StringStream* stream); - protected: EmbeddedContainer<LOperand*, R> results_; EmbeddedContainer<LOperand*, I> inputs_; @@ -535,9 +520,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { class LArgumentsElements: public LTemplateInstruction<1, 0, 0> { public: - LArgumentsElements() { } - DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements") + DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements) }; @@ -831,6 +815,15 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) Handle<JSFunction> function() const { return hydrogen()->function(); } + LEnvironment* GetDeferredLazyDeoptimizationEnvironment() { + return lazy_deopt_env_; + } + virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { + lazy_deopt_env_ = env; + } + + private: + LEnvironment* lazy_deopt_env_; }; @@ -1358,6 +1351,19 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { }; +class LDrop: public LTemplateInstruction<0, 0, 0> { + public: + explicit LDrop(int count) : count_(count) { } + + int count() const { return count_; } + + DECLARE_CONCRETE_INSTRUCTION(Drop, "drop") + + private: + int count_; +}; + + class LThisFunction: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function") @@ -1434,6 +1440,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> { virtual void PrintDataTo(StringStream* stream); int arity() const { return hydrogen()->argument_count() - 1; } + Handle<JSFunction> known_function() { return hydrogen()->known_function(); } }; @@ -1707,6 +1714,8 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } + + bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } }; @@ -1857,14 +1866,14 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> { }; -class LCheckMap: public LTemplateInstruction<0, 1, 0> { +class LCheckMaps: public LTemplateInstruction<0, 1, 0> { public: - explicit LCheckMap(LOperand* value) { + explicit LCheckMaps(LOperand* value) { inputs_[0] = value; } - DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map") - DECLARE_HYDROGEN_ACCESSOR(CheckMap) + DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps") + DECLARE_HYDROGEN_ACCESSOR(CheckMaps) }; @@ -2335,11 +2344,6 @@ class LChunkBuilder BASE_EMBEDDED { LInstruction* instr, HInstruction* hinstr, CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); - LInstruction* MarkAsSaveDoubles(LInstruction* instr); - - LInstruction* SetInstructionPendingDeoptimizationEnvironment( - LInstruction* instr, int ast_id); - void ClearInstructionPendingDeoptimizationEnvironment(); LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, int* argument_index_accumulator); diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index f7db250f9e..3d380a2644 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -150,6 +150,20 @@ int MacroAssembler::LoadAddressSize(ExternalReference source) { } +void MacroAssembler::PushAddress(ExternalReference source) { + int64_t address = reinterpret_cast<int64_t>(source.address()); + if (is_int32(address) && !Serializer::enabled()) { + if (emit_debug_code()) { + movq(kScratchRegister, BitCast<int64_t>(kZapValue), RelocInfo::NONE); + } + push(Immediate(static_cast<int32_t>(address))); + return; + } + LoadAddress(kScratchRegister, source); + push(kScratchRegister); +} + + void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) { ASSERT(root_array_available_); movq(destination, Operand(kRootRegister, @@ -657,7 +671,7 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) { void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) { -#ifdef _WIN64 +#if defined(_WIN64) && !defined(__MINGW64__) // We need to prepare a slot for result handle on stack and put // a pointer to it into 1st arg register. EnterApiExitFrame(arg_stack_space + 1); @@ -705,7 +719,7 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, RelocInfo::RUNTIME_ENTRY); call(rax); -#ifdef _WIN64 +#if defined(_WIN64) && !defined(__MINGW64__) // rax keeps a pointer to v8::Handle, unpack it. movq(rax, Operand(rax, 0)); #endif @@ -4174,7 +4188,7 @@ bool AreAliased(Register r1, Register r2, Register r3, Register r4) { CodePatcher::CodePatcher(byte* address, int size) : address_(address), size_(size), - masm_(Isolate::Current(), address, size + Assembler::kGap) { + masm_(NULL, address, size + Assembler::kGap) { // Create a new macro assembler pointing to the address of the code to patch. // The size is adjusted with kGap on order for the assembler to generate size // bytes of instructions without failing with buffer size constraints. diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index 6bb5cfeb42..66587d5319 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -127,6 +127,8 @@ class MacroAssembler: public Assembler { // Returns the size of the code generated by LoadAddress. // Used by CallSize(ExternalReference) to find the size of a call. int LoadAddressSize(ExternalReference source); + // Pushes the address of the external reference onto the stack. + void PushAddress(ExternalReference source); // Operations on roots in the root-array. void LoadRoot(Register destination, Heap::RootListIndex index); diff --git a/deps/v8/src/x64/regexp-macro-assembler-x64.cc b/deps/v8/src/x64/regexp-macro-assembler-x64.cc index 837c2543c3..bf232bff9b 100644 --- a/deps/v8/src/x64/regexp-macro-assembler-x64.cc +++ b/deps/v8/src/x64/regexp-macro-assembler-x64.cc @@ -542,9 +542,13 @@ void RegExpMacroAssemblerX64::CheckNotCharacter(uint32_t c, void RegExpMacroAssemblerX64::CheckCharacterAfterAnd(uint32_t c, uint32_t mask, Label* on_equal) { - __ movl(rax, current_character()); - __ and_(rax, Immediate(mask)); - __ cmpl(rax, Immediate(c)); + if (c == 0) { + __ testl(current_character(), Immediate(mask)); + } else { + __ movl(rax, Immediate(mask)); + __ and_(rax, current_character()); + __ cmpl(rax, Immediate(c)); + } BranchOrBacktrack(equal, on_equal); } @@ -552,9 +556,13 @@ void RegExpMacroAssemblerX64::CheckCharacterAfterAnd(uint32_t c, void RegExpMacroAssemblerX64::CheckNotCharacterAfterAnd(uint32_t c, uint32_t mask, Label* on_not_equal) { - __ movl(rax, current_character()); - __ and_(rax, Immediate(mask)); - __ cmpl(rax, Immediate(c)); + if (c == 0) { + __ testl(current_character(), Immediate(mask)); + } else { + __ movl(rax, Immediate(mask)); + __ and_(rax, current_character()); + __ cmpl(rax, Immediate(c)); + } BranchOrBacktrack(not_equal, on_not_equal); } @@ -572,6 +580,42 @@ void RegExpMacroAssemblerX64::CheckNotCharacterAfterMinusAnd( } +void RegExpMacroAssemblerX64::CheckCharacterInRange( + uc16 from, + uc16 to, + Label* on_in_range) { + __ leal(rax, Operand(current_character(), -from)); + __ cmpl(rax, Immediate(to - from)); + BranchOrBacktrack(below_equal, on_in_range); +} + + +void RegExpMacroAssemblerX64::CheckCharacterNotInRange( + uc16 from, + uc16 to, + Label* on_not_in_range) { + __ leal(rax, Operand(current_character(), -from)); + __ cmpl(rax, Immediate(to - from)); + BranchOrBacktrack(above, on_not_in_range); +} + + +void RegExpMacroAssemblerX64::CheckBitInTable( + Handle<ByteArray> table, + Label* on_bit_set) { + __ Move(rax, table); + Register index = current_character(); + if (mode_ != ASCII || kTableMask != String::kMaxAsciiCharCode) { + __ movq(rbx, current_character()); + __ and_(rbx, Immediate(kTableMask)); + index = rbx; + } + __ cmpb(FieldOperand(rax, index, times_1, ByteArray::kHeaderSize), + Immediate(0)); + BranchOrBacktrack(not_equal, on_bit_set); +} + + bool RegExpMacroAssemblerX64::CheckSpecialCharacterClass(uc16 type, Label* on_no_match) { // Range checks (c in min..max) are generally implemented by an unsigned diff --git a/deps/v8/src/x64/regexp-macro-assembler-x64.h b/deps/v8/src/x64/regexp-macro-assembler-x64.h index 7102225e64..cd24b60981 100644 --- a/deps/v8/src/x64/regexp-macro-assembler-x64.h +++ b/deps/v8/src/x64/regexp-macro-assembler-x64.h @@ -75,6 +75,14 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { uc16 minus, uc16 mask, Label* on_not_equal); + virtual void CheckCharacterInRange(uc16 from, + uc16 to, + Label* on_in_range); + virtual void CheckCharacterNotInRange(uc16 from, + uc16 to, + Label* on_not_in_range); + virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set); + // Checks whether the given offset from the current position is before // the end of the string. virtual void CheckPosition(int cp_offset, Label* on_outside_input); diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index f07f6b6b72..5721e9b373 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -379,6 +379,7 @@ static void PushInterceptorArguments(MacroAssembler* masm, __ push(receiver); __ push(holder); __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset)); + __ PushAddress(ExternalReference::isolate_address()); } @@ -393,7 +394,7 @@ static void CompileCallLoadPropertyWithInterceptor( ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), masm->isolate()); - __ Set(rax, 5); + __ Set(rax, 6); __ LoadAddress(rbx, ref); CEntryStub stub(1); @@ -402,7 +403,7 @@ static void CompileCallLoadPropertyWithInterceptor( // Number of pointers to be reserved on stack for fast API call. -static const int kFastApiCallArguments = 3; +static const int kFastApiCallArguments = 4; // Reserves space for the extra arguments to API function in the @@ -452,10 +453,11 @@ static void GenerateFastApiCall(MacroAssembler* masm, // -- rsp[16] : api function // (first fast api call extra argument) // -- rsp[24] : api call data - // -- rsp[32] : last argument + // -- rsp[32] : isolate + // -- rsp[40] : last argument // -- ... - // -- rsp[(argc + 3) * 8] : first argument - // -- rsp[(argc + 4) * 8] : receiver + // -- rsp[(argc + 4) * 8] : first argument + // -- rsp[(argc + 5) * 8] : receiver // ----------------------------------- // Get the function and setup the context. Handle<JSFunction> function = optimization.constant_function(); @@ -473,11 +475,15 @@ static void GenerateFastApiCall(MacroAssembler* masm, } else { __ Move(Operand(rsp, 3 * kPointerSize), call_data); } + __ movq(kScratchRegister, ExternalReference::isolate_address()); + __ movq(Operand(rsp, 4 * kPointerSize), kScratchRegister); // Prepare arguments. - __ lea(rbx, Operand(rsp, 3 * kPointerSize)); + __ lea(rbx, Operand(rsp, 4 * kPointerSize)); -#ifdef _WIN64 +#if defined(__MINGW64__) + Register arguments_arg = rcx; +#elif defined(_WIN64) // Win64 uses first register--rcx--for returned value. Register arguments_arg = rdx; #else @@ -663,7 +669,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { __ CallExternalReference( ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), masm->isolate()), - 5); + 6); // Restore the name_ register. __ pop(name_); @@ -730,8 +736,10 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, Register scratch, Label* miss_label) { // Check that the map of the object hasn't changed. + CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS + : REQUIRE_EXACT_MAP; __ CheckMap(receiver_reg, Handle<Map>(object->map()), - miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); + miss_label, DO_SMI_CHECK, mode); // Perform global security token check if needed. if (object->IsJSGlobalProxy()) { @@ -1003,11 +1011,15 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, } else { __ Push(Handle<Object>(callback->data())); } + __ PushAddress(ExternalReference::isolate_address()); // isolate __ push(name_reg); // name // Save a pointer to where we pushed the arguments pointer. // This will be passed as the const AccessorInfo& to the C++ callback. -#ifdef _WIN64 +#if defined(__MINGW64__) + Register accessor_info_arg = rdx; + Register name_arg = rcx; +#elif defined(_WIN64) // Win64 uses first register--rcx--for returned value. Register accessor_info_arg = r8; Register name_arg = rdx; @@ -1020,14 +1032,14 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, __ movq(name_arg, rsp); __ push(scratch2); // Restore return address. - // 3 elements array for v8::Arguments::values_ and handler for name. - const int kStackSpace = 4; + // 4 elements array for v8::Arguments::values_ and handler for name. + const int kStackSpace = 5; // Allocate v8::AccessorInfo in non-GCed stack space. const int kArgStackSpace = 1; __ PrepareCallApiFunction(kArgStackSpace); - __ lea(rax, Operand(name_arg, 3 * kPointerSize)); + __ lea(rax, Operand(name_arg, 4 * kPointerSize)); // v8::AccessorInfo::args_. __ movq(StackSpaceOperand(0), rax); @@ -1102,13 +1114,20 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, name, miss); ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); + // Preserve the receiver register explicitly whenever it is different from + // the holder and it is needed should the interceptor return without any + // result. The CALLBACKS case needs the receiver to be passed into C++ code, + // the FIELD case might cause a miss during the prototype check. + bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); + bool must_preserve_receiver_reg = !receiver.is(holder_reg) && + (lookup->type() == CALLBACKS || must_perfrom_prototype_check); + // Save necessary data before invoking an interceptor. // Requires a frame to make GC aware of pushed pointers. { FrameScope frame_scope(masm(), StackFrame::INTERNAL); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { - // CALLBACKS case needs a receiver to be passed into C++ callback. + if (must_preserve_receiver_reg) { __ push(receiver); } __ push(holder_reg); @@ -1134,7 +1153,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, __ bind(&interceptor_failed); __ pop(name_reg); __ pop(holder_reg); - if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { + if (must_preserve_receiver_reg) { __ pop(receiver); } @@ -1143,7 +1162,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, // Check that the maps from interceptor's holder to lookup's holder // haven't changed. And load lookup's holder into |holder| register. - if (*interceptor_holder != lookup->holder()) { + if (must_perfrom_prototype_check) { holder_reg = CheckPrototypes(interceptor_holder, holder_reg, Handle<JSObject>(lookup->holder()), @@ -1177,6 +1196,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, __ push(holder_reg); __ Move(holder_reg, callback); __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); + __ PushAddress(ExternalReference::isolate_address()); __ push(holder_reg); __ push(name_reg); __ push(scratch2); // restore return address @@ -1184,7 +1204,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadCallbackProperty), isolate()); - __ TailCallExternalReference(ref, 5, 1); + __ TailCallExternalReference(ref, 6, 1); } } else { // !compile_followup_inline // Call the runtime system to load the interceptor. @@ -1199,7 +1219,7 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, ExternalReference ref = ExternalReference( IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); - __ TailCallExternalReference(ref, 5, 1); + __ TailCallExternalReference(ref, 6, 1); } } @@ -1991,7 +2011,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall( name, depth, &miss); // Move the return address on top of the stack. - __ movq(rax, Operand(rsp, 3 * kPointerSize)); + __ movq(rax, Operand(rsp, 4 * kPointerSize)); __ movq(Operand(rsp, 0 * kPointerSize), rax); GenerateFastApiCall(masm(), optimization, argc); @@ -3112,6 +3132,32 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( __ jmp(miss_ic, RelocInfo::CODE_TARGET); } + +static void GenerateSmiKeyCheck(MacroAssembler* masm, + Register key, + Register scratch, + XMMRegister xmm_scratch0, + XMMRegister xmm_scratch1, + Label* fail) { + // Check that key is a smi or a heap number containing a smi and branch + // if the check fails. + Label key_ok; + __ JumpIfSmi(key, &key_ok); + __ CheckMap(key, + masm->isolate()->factory()->heap_number_map(), + fail, + DONT_DO_SMI_CHECK); + __ movsd(xmm_scratch0, FieldOperand(key, HeapNumber::kValueOffset)); + __ cvttsd2si(scratch, xmm_scratch0); + __ cvtlsi2sd(xmm_scratch1, scratch); + __ ucomisd(xmm_scratch1, xmm_scratch0); + __ j(not_equal, fail); + __ j(parity_even, fail); // NaN. + __ Integer32ToSmi(key, scratch); + __ bind(&key_ok); +} + + void KeyedLoadStubCompiler::GenerateLoadExternalArray( MacroAssembler* masm, ElementsKind elements_kind) { @@ -3125,8 +3171,8 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(rax, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, rax, rcx, xmm0, xmm1, &miss_force_generic); // Check that the index is in range. __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); @@ -3260,8 +3306,8 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(rcx, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic); // Check that the index is in range. __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); @@ -3362,30 +3408,28 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( } else { // Perform float-to-int conversion with truncation (round-to-zero) // behavior. + // Fast path: use machine instruction to convert to int64. If that + // fails (out-of-range), go into the runtime. + __ cvttsd2siq(r8, xmm0); + __ Set(kScratchRegister, V8_UINT64_C(0x8000000000000000)); + __ cmpq(r8, kScratchRegister); + __ j(equal, &slow); - // Convert to int32 and store the low byte/word. - // If the value is NaN or +/-infinity, the result is 0x80000000, - // which is automatically zero when taken mod 2^n, n < 32. // rdx: value (converted to an untagged integer) // rdi: untagged index // rbx: base pointer of external storage switch (elements_kind) { case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ cvttsd2si(rdx, xmm0); - __ movb(Operand(rbx, rdi, times_1, 0), rdx); + __ movb(Operand(rbx, rdi, times_1, 0), r8); break; case EXTERNAL_SHORT_ELEMENTS: case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ cvttsd2si(rdx, xmm0); - __ movw(Operand(rbx, rdi, times_2, 0), rdx); + __ movw(Operand(rbx, rdi, times_2, 0), r8); break; case EXTERNAL_INT_ELEMENTS: case EXTERNAL_UNSIGNED_INT_ELEMENTS: - // Convert to int64, so that NaN and infinities become - // 0x8000000000000000, which is zero mod 2^32. - __ cvttsd2siq(rdx, xmm0); - __ movl(Operand(rbx, rdi, times_4, 0), rdx); + __ movl(Operand(rbx, rdi, times_4, 0), r8); break; case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_FLOAT_ELEMENTS: @@ -3442,8 +3486,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(rax, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, rax, rcx, xmm0, xmm1, &miss_force_generic); // Get the elements array. __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); @@ -3484,8 +3528,8 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(rax, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, rax, rcx, xmm0, xmm1, &miss_force_generic); // Get the elements array. __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); @@ -3540,8 +3584,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(rcx, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic); if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { __ JumpIfNotSmi(rax, &transition_elements_kind); @@ -3682,8 +3726,8 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. - // Check that the key is a smi. - __ JumpIfNotSmi(rcx, &miss_force_generic); + // Check that the key is a smi or a heap number convertible to a smi. + GenerateSmiKeyCheck(masm, rcx, rbx, xmm0, xmm1, &miss_force_generic); // Get the elements array. __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); @@ -3765,6 +3809,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // Increment the length of the array. __ Move(FieldOperand(rdx, JSArray::kLengthOffset), Smi::FromInt(1)); + __ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset)); __ jmp(&finish_store); __ bind(&check_capacity); diff --git a/deps/v8/test/cctest/test-accessors.cc b/deps/v8/test/cctest/test-accessors.cc index b1900f9ed3..0b342ff3d9 100644 --- a/deps/v8/test/cctest/test-accessors.cc +++ b/deps/v8/test/cctest/test-accessors.cc @@ -1,4 +1,4 @@ -// Copyright 2009 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -116,6 +116,8 @@ static v8::Handle<v8::Object> x_holder; static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) { ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + CHECK_EQ(isolate, info.GetIsolate()); CHECK_EQ(x_receiver, info.This()); CHECK_EQ(x_holder, info.Holder()); return v8_num(x_register); @@ -125,6 +127,8 @@ static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) { static void XSetter(Local<String> name, Local<Value> value, const AccessorInfo& info) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + CHECK_EQ(isolate, info.GetIsolate()); CHECK_EQ(x_holder, info.This()); CHECK_EQ(x_holder, info.Holder()); x_register = value->Int32Value(); @@ -236,12 +240,15 @@ THREADED_TEST(HandleScopePop) { static v8::Handle<Value> CheckAccessorArgsCorrect(Local<String> name, const AccessorInfo& info) { + CHECK(info.GetIsolate() == v8::Isolate::GetCurrent()); CHECK(info.This() == info.Holder()); CHECK(info.Data()->Equals(v8::String::New("data"))); ApiTestFuzzer::Fuzz(); + CHECK(info.GetIsolate() == v8::Isolate::GetCurrent()); CHECK(info.This() == info.Holder()); CHECK(info.Data()->Equals(v8::String::New("data"))); HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); + CHECK(info.GetIsolate() == v8::Isolate::GetCurrent()); CHECK(info.This() == info.Holder()); CHECK(info.Data()->Equals(v8::String::New("data"))); return v8::Integer::New(17); diff --git a/deps/v8/test/cctest/test-alloc.cc b/deps/v8/test/cctest/test-alloc.cc index 769fe7be29..e195d14923 100644 --- a/deps/v8/test/cctest/test-alloc.cc +++ b/deps/v8/test/cctest/test-alloc.cc @@ -34,6 +34,15 @@ using namespace v8::internal; +static inline void SimulateFullSpace(PagedSpace* space) { + int old_linear_size = static_cast<int>(space->limit() - space->top()); + space->Free(space->top(), old_linear_size); + space->SetTop(space->limit(), space->limit()); + space->ResetFreeList(); + space->ClearStats(); +} + + static MaybeObject* AllocateAfterFailures() { static int attempts = 0; if (++attempts < 3) return Failure::RetryAfterGC(); @@ -65,24 +74,12 @@ static MaybeObject* AllocateAfterFailures() { CHECK(!heap->CopyJSObject(JSObject::cast(object))->IsFailure()); // Old data space. - OldSpace* old_data_space = heap->old_data_space(); - static const int kOldDataSpaceFillerSize = ByteArray::SizeFor(0); - while (old_data_space->Available() > kOldDataSpaceFillerSize) { - CHECK(!heap->AllocateByteArray(0, TENURED)->IsFailure()); - } + SimulateFullSpace(heap->old_data_space()); CHECK(!heap->AllocateRawAsciiString(100, TENURED)->IsFailure()); // Old pointer space. - OldSpace* old_pointer_space = heap->old_pointer_space(); - static const int kOldPointerSpaceFillerLength = 10000; - static const int kOldPointerSpaceFillerSize = FixedArray::SizeFor( - kOldPointerSpaceFillerLength); - while (old_pointer_space->Available() > kOldPointerSpaceFillerSize) { - CHECK(!heap->AllocateFixedArray(kOldPointerSpaceFillerLength, TENURED)-> - IsFailure()); - } - CHECK(!heap->AllocateFixedArray(kOldPointerSpaceFillerLength, TENURED)-> - IsFailure()); + SimulateFullSpace(heap->old_pointer_space()); + CHECK(!heap->AllocateFixedArray(10000, TENURED)->IsFailure()); // Large object space. static const int kLargeObjectSpaceFillerLength = 300000; @@ -97,14 +94,9 @@ static MaybeObject* AllocateAfterFailures() { IsFailure()); // Map space. - MapSpace* map_space = heap->map_space(); - static const int kMapSpaceFillerSize = Map::kSize; - InstanceType instance_type = JS_OBJECT_TYPE; + SimulateFullSpace(heap->map_space()); int instance_size = JSObject::kHeaderSize; - while (map_space->Available() > kMapSpaceFillerSize) { - CHECK(!heap->AllocateMap(instance_type, instance_size)->IsFailure()); - } - CHECK(!heap->AllocateMap(instance_type, instance_size)->IsFailure()); + CHECK(!heap->AllocateMap(JS_OBJECT_TYPE, instance_size)->IsFailure()); // Test that we can allocate in old pointer space and code space. CHECK(!heap->AllocateFixedArray(100, TENURED)->IsFailure()); diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index b1a23c1ef7..8a1e914736 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -8608,6 +8608,8 @@ static void CheckInterceptorLoadIC(NamedPropertyGetter getter, static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name, const AccessorInfo& info) { ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + CHECK_EQ(isolate, info.GetIsolate()); CHECK_EQ(v8_str("data"), info.Data()); CHECK_EQ(v8_str("x"), name); return v8::Integer::New(42); @@ -9334,6 +9336,8 @@ static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name, static v8::Handle<Value> FastApiCallback_TrivialSignature( const v8::Arguments& args) { ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + CHECK_EQ(isolate, args.GetIsolate()); CHECK_EQ(args.This(), args.Holder()); CHECK(args.Data()->Equals(v8_str("method_data"))); return v8::Integer::New(args[0]->Int32Value() + 1); @@ -9342,6 +9346,8 @@ static v8::Handle<Value> FastApiCallback_TrivialSignature( static v8::Handle<Value> FastApiCallback_SimpleSignature( const v8::Arguments& args) { ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + CHECK_EQ(isolate, args.GetIsolate()); CHECK_EQ(args.This()->GetPrototype(), args.Holder()); CHECK(args.Data()->Equals(v8_str("method_data"))); // Note, we're using HasRealNamedProperty instead of Has to avoid @@ -10865,13 +10871,18 @@ THREADED_TEST(NestedHandleScopeAndContexts) { } +static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); } + + THREADED_TEST(ExternalAllocatedMemory) { v8::HandleScope outer; v8::Persistent<Context> env(Context::New()); CHECK(!env.IsEmpty()); - const int kSize = 1024*1024; - CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize); - CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0); + const intptr_t kSize = 1024*1024; + CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize)), + cast(kSize)); + CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize)), + cast(0)); } @@ -12365,6 +12376,46 @@ THREADED_TEST(ForceDeleteIC) { } +TEST(InlinedFunctionAcrossContexts) { + i::FLAG_allow_natives_syntax = true; + v8::HandleScope outer_scope; + v8::Persistent<v8::Context> ctx1 = v8::Context::New(); + v8::Persistent<v8::Context> ctx2 = v8::Context::New(); + ctx1->Enter(); + + { + v8::HandleScope inner_scope; + CompileRun("var G = 42; function foo() { return G; }"); + v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo")); + ctx2->Enter(); + ctx2->Global()->Set(v8_str("o"), foo); + v8::Local<v8::Value> res = CompileRun( + "function f() { return o(); }" + "for (var i = 0; i < 10; ++i) f();" + "%OptimizeFunctionOnNextCall(f);" + "f();"); + CHECK_EQ(42, res->Int32Value()); + ctx2->Exit(); + v8::Handle<v8::String> G_property = v8::String::New("G"); + CHECK(ctx1->Global()->ForceDelete(G_property)); + ctx2->Enter(); + ExpectString( + "(function() {" + " try {" + " return f();" + " } catch(e) {" + " return e.toString();" + " }" + " })()", + "ReferenceError: G is not defined"); + ctx2->Exit(); + ctx1->Exit(); + ctx1.Dispose(); + } + ctx2.Dispose(); +} + + v8::Persistent<Context> calling_context0; v8::Persistent<Context> calling_context1; v8::Persistent<Context> calling_context2; @@ -12430,19 +12481,16 @@ THREADED_TEST(GetCallingContext) { // Check that a variable declaration with no explicit initialization -// value does not shadow an existing property in the prototype chain. -// -// This is consistent with Firefox and Safari. -// -// See http://crbug.com/12548. +// value does shadow an existing property in the prototype chain. THREADED_TEST(InitGlobalVarInProtoChain) { + i::FLAG_es52_globals = true; v8::HandleScope scope; LocalContext context; // Introduce a variable in the prototype chain. CompileRun("__proto__.x = 42"); - v8::Handle<v8::Value> result = CompileRun("var x; x"); + v8::Handle<v8::Value> result = CompileRun("var x = 43; x"); CHECK(!result->IsUndefined()); - CHECK_EQ(42, result->Int32Value()); + CHECK_EQ(43, result->Int32Value()); } @@ -13947,75 +13995,104 @@ TEST(SourceURLInStackTrace) { } +static void CreateGarbageInOldSpace() { + v8::HandleScope scope; + i::AlwaysAllocateScope always_allocate; + for (int i = 0; i < 1000; i++) { + FACTORY->NewFixedArray(1000, i::TENURED); + } +} + // Test that idle notification can be handled and eventually returns true. -// This just checks the contract of the IdleNotification() function, -// and does not verify that it does reasonable work. -THREADED_TEST(IdleNotification) { +TEST(IdleNotification) { + const intptr_t MB = 1024 * 1024; v8::HandleScope scope; LocalContext env; - { - // Create garbage in old-space to generate work for idle notification. - i::AlwaysAllocateScope always_allocate; - for (int i = 0; i < 100; i++) { - FACTORY->NewFixedArray(1000, i::TENURED); - } + intptr_t initial_size = HEAP->SizeOfObjects(); + CreateGarbageInOldSpace(); + intptr_t size_with_garbage = HEAP->SizeOfObjects(); + CHECK_GT(size_with_garbage, initial_size + MB); + bool finished = false; + for (int i = 0; i < 200 && !finished; i++) { + finished = v8::V8::IdleNotification(); } - bool finshed_idle_work = false; - for (int i = 0; i < 100 && !finshed_idle_work; i++) { - finshed_idle_work = v8::V8::IdleNotification(); - } - CHECK(finshed_idle_work); + intptr_t final_size = HEAP->SizeOfObjects(); + CHECK(finished); + CHECK_LT(final_size, initial_size + 1); } -// Test that idle notification can be handled and eventually returns true. -// This just checks the contract of the IdleNotification() function, -// and does not verify that it does reasonable work. + +// Test that idle notification can be handled and eventually collects garbage. TEST(IdleNotificationWithSmallHint) { + const intptr_t MB = 1024 * 1024; + const int IdlePauseInMs = 900; v8::HandleScope scope; LocalContext env; - { - // Create garbage in old-space to generate work for idle notification. - i::AlwaysAllocateScope always_allocate; - for (int i = 0; i < 100; i++) { - FACTORY->NewFixedArray(1000, i::TENURED); - } + intptr_t initial_size = HEAP->SizeOfObjects(); + CreateGarbageInOldSpace(); + intptr_t size_with_garbage = HEAP->SizeOfObjects(); + CHECK_GT(size_with_garbage, initial_size + MB); + bool finished = false; + for (int i = 0; i < 200 && !finished; i++) { + finished = v8::V8::IdleNotification(IdlePauseInMs); } - intptr_t old_size = HEAP->SizeOfObjects(); - bool finshed_idle_work = false; - bool no_idle_work = v8::V8::IdleNotification(10); - for (int i = 0; i < 200 && !finshed_idle_work; i++) { - finshed_idle_work = v8::V8::IdleNotification(10); - } - intptr_t new_size = HEAP->SizeOfObjects(); - CHECK(finshed_idle_work); - CHECK(no_idle_work || new_size < old_size); + intptr_t final_size = HEAP->SizeOfObjects(); + CHECK(finished); + CHECK_LT(final_size, initial_size + 1); } -// This just checks the contract of the IdleNotification() function, -// and does not verify that it does reasonable work. +// Test that idle notification can be handled and eventually collects garbage. TEST(IdleNotificationWithLargeHint) { + const intptr_t MB = 1024 * 1024; + const int IdlePauseInMs = 900; v8::HandleScope scope; LocalContext env; - { - // Create garbage in old-space to generate work for idle notification. - i::AlwaysAllocateScope always_allocate; - for (int i = 0; i < 100; i++) { - FACTORY->NewFixedArray(1000, i::TENURED); - } - } - intptr_t old_size = HEAP->SizeOfObjects(); - bool finshed_idle_work = false; - bool no_idle_work = v8::V8::IdleNotification(900); - for (int i = 0; i < 200 && !finshed_idle_work; i++) { - finshed_idle_work = v8::V8::IdleNotification(900); + intptr_t initial_size = HEAP->SizeOfObjects(); + CreateGarbageInOldSpace(); + intptr_t size_with_garbage = HEAP->SizeOfObjects(); + CHECK_GT(size_with_garbage, initial_size + MB); + bool finished = false; + for (int i = 0; i < 200 && !finished; i++) { + finished = v8::V8::IdleNotification(IdlePauseInMs); } - intptr_t new_size = HEAP->SizeOfObjects(); - CHECK(finshed_idle_work); - CHECK(no_idle_work || new_size < old_size); + intptr_t final_size = HEAP->SizeOfObjects(); + CHECK(finished); + CHECK_LT(final_size, initial_size + 1); } +TEST(Regress2107) { + const intptr_t MB = 1024 * 1024; + const int kShortIdlePauseInMs = 100; + const int kLongIdlePauseInMs = 1000; + v8::HandleScope scope; + LocalContext env; + intptr_t initial_size = HEAP->SizeOfObjects(); + // Send idle notification to start a round of incremental GCs. + v8::V8::IdleNotification(kShortIdlePauseInMs); + // Emulate 7 page reloads. + for (int i = 0; i < 7; i++) { + v8::Persistent<v8::Context> ctx = v8::Context::New(); + ctx->Enter(); + CreateGarbageInOldSpace(); + ctx->Exit(); + ctx.Dispose(); + v8::V8::ContextDisposedNotification(); + v8::V8::IdleNotification(kLongIdlePauseInMs); + } + // Create garbage and check that idle notification still collects it. + CreateGarbageInOldSpace(); + intptr_t size_with_garbage = HEAP->SizeOfObjects(); + CHECK_GT(size_with_garbage, initial_size + MB); + bool finished = false; + for (int i = 0; i < 200 && !finished; i++) { + finished = v8::V8::IdleNotification(kShortIdlePauseInMs); + } + intptr_t final_size = HEAP->SizeOfObjects(); + CHECK_LT(final_size, initial_size + 1); +} + static uint32_t* stack_limit; static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) { @@ -16135,6 +16212,30 @@ THREADED_TEST(Regress93759) { } +THREADED_TEST(Regress125988) { + v8::HandleScope scope; + Handle<FunctionTemplate> intercept = FunctionTemplate::New(); + AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter); + LocalContext env; + env->Global()->Set(v8_str("Intercept"), intercept->GetFunction()); + CompileRun("var a = new Object();" + "var b = new Intercept();" + "var c = new Object();" + "c.__proto__ = b;" + "b.__proto__ = a;" + "a.x = 23;" + "for (var i = 0; i < 3; i++) c.x;"); + ExpectBoolean("c.hasOwnProperty('x')", false); + ExpectInt32("c.x", 23); + CompileRun("a.y = 42;" + "for (var i = 0; i < 3; i++) c.x;"); + ExpectBoolean("c.hasOwnProperty('x')", false); + ExpectInt32("c.x", 23); + ExpectBoolean("c.hasOwnProperty('y')", false); + ExpectInt32("c.y", 42); +} + + static void TestReceiver(Local<Value> expected_result, Local<Value> expected_receiver, const char* code) { @@ -16401,3 +16502,94 @@ TEST(PrimaryStubCache) { StubCacheHelper(false); } + +static int fatal_error_callback_counter = 0; +static void CountingErrorCallback(const char* location, const char* message) { + printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message); + fatal_error_callback_counter++; +} + + +TEST(StaticGetters) { + v8::HandleScope scope; + LocalContext context; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + i::Handle<i::Object> undefined_value = FACTORY->undefined_value(); + CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value); + CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value); + i::Handle<i::Object> null_value = FACTORY->null_value(); + CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value); + CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value); + i::Handle<i::Object> true_value = FACTORY->true_value(); + CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value); + CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value); + i::Handle<i::Object> false_value = FACTORY->false_value(); + CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value); + CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value); + + // Test after-death behavior. + CHECK(i::Internals::IsInitialized(isolate)); + CHECK_EQ(0, fatal_error_callback_counter); + v8::V8::SetFatalErrorHandler(CountingErrorCallback); + v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8"); + i::Isolate::Current()->TearDown(); + CHECK(!i::Internals::IsInitialized(isolate)); + CHECK_EQ(1, fatal_error_callback_counter); + CHECK(v8::Undefined().IsEmpty()); + CHECK_EQ(2, fatal_error_callback_counter); + CHECK(v8::Undefined(isolate).IsEmpty()); + CHECK_EQ(3, fatal_error_callback_counter); + CHECK(v8::Null().IsEmpty()); + CHECK_EQ(4, fatal_error_callback_counter); + CHECK(v8::Null(isolate).IsEmpty()); + CHECK_EQ(5, fatal_error_callback_counter); + CHECK(v8::True().IsEmpty()); + CHECK_EQ(6, fatal_error_callback_counter); + CHECK(v8::True(isolate).IsEmpty()); + CHECK_EQ(7, fatal_error_callback_counter); + CHECK(v8::False().IsEmpty()); + CHECK_EQ(8, fatal_error_callback_counter); + CHECK(v8::False(isolate).IsEmpty()); + CHECK_EQ(9, fatal_error_callback_counter); +} + + +TEST(IsolateEmbedderData) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + CHECK_EQ(NULL, isolate->GetData()); + CHECK_EQ(NULL, ISOLATE->GetData()); + static void* data1 = reinterpret_cast<void*>(0xacce55ed); + isolate->SetData(data1); + CHECK_EQ(data1, isolate->GetData()); + CHECK_EQ(data1, ISOLATE->GetData()); + static void* data2 = reinterpret_cast<void*>(0xdecea5ed); + ISOLATE->SetData(data2); + CHECK_EQ(data2, isolate->GetData()); + CHECK_EQ(data2, ISOLATE->GetData()); + ISOLATE->TearDown(); + CHECK_EQ(data2, isolate->GetData()); + CHECK_EQ(data2, ISOLATE->GetData()); +} + + +TEST(StringEmpty) { + v8::HandleScope scope; + LocalContext context; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + i::Handle<i::Object> empty_string = FACTORY->empty_symbol(); + CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string); + CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string); + + // Test after-death behavior. + CHECK(i::Internals::IsInitialized(isolate)); + CHECK_EQ(0, fatal_error_callback_counter); + v8::V8::SetFatalErrorHandler(CountingErrorCallback); + v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8"); + i::Isolate::Current()->TearDown(); + CHECK(!i::Internals::IsInitialized(isolate)); + CHECK_EQ(1, fatal_error_callback_counter); + CHECK(v8::String::Empty().IsEmpty()); + CHECK_EQ(2, fatal_error_callback_counter); + CHECK(v8::String::Empty(isolate).IsEmpty()); + CHECK_EQ(3, fatal_error_callback_counter); +} diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index ffa845813f..e40f406c3c 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -5013,7 +5013,10 @@ static void ThreadedMessageHandler(const v8::Debug::Message& message) { if (IsBreakEventMessage(print_buffer)) { // Check that we are inside the while loop. int source_line = GetSourceLineFromBreakEventMessage(print_buffer); - CHECK(8 <= source_line && source_line <= 13); + // TODO(2047): This should really be 8 <= source_line <= 13; but we + // currently have an off-by-one error when calculating the source + // position corresponding to the program counter at the debug break. + CHECK(7 <= source_line && source_line <= 13); threaded_debugging_barriers.barrier_2.Wait(); } } diff --git a/deps/v8/test/cctest/test-decls.cc b/deps/v8/test/cctest/test-decls.cc index aa733c70bc..e6bdc9f505 100644 --- a/deps/v8/test/cctest/test-decls.cc +++ b/deps/v8/test/cctest/test-decls.cc @@ -521,6 +521,7 @@ class ExistsInPrototypeContext: public DeclarationContext { TEST(ExistsInPrototype) { + i::FLAG_es52_globals = true; HandleScope scope; // Sanity check to make sure that the holder of the interceptor @@ -535,17 +536,17 @@ TEST(ExistsInPrototype) { { ExistsInPrototypeContext context; context.Check("var x; x", - 1, // get + 0, // get 0, - 1, // declaration - EXPECT_EXCEPTION); + 0, // declaration + EXPECT_RESULT, Undefined()); } { ExistsInPrototypeContext context; context.Check("var x = 0; x", 0, 0, - 1, // declaration + 0, // declaration EXPECT_RESULT, Number::New(0)); } @@ -553,7 +554,7 @@ TEST(ExistsInPrototype) { context.Check("const x; x", 0, 0, - 1, // declaration + 0, // declaration EXPECT_RESULT, Undefined()); } @@ -561,7 +562,7 @@ TEST(ExistsInPrototype) { context.Check("const x = 0; x", 0, 0, - 1, // declaration + 0, // declaration EXPECT_RESULT, Number::New(0)); } } @@ -583,13 +584,14 @@ class AbsentInPrototypeContext: public DeclarationContext { TEST(AbsentInPrototype) { + i::FLAG_es52_globals = true; HandleScope scope; { AbsentInPrototypeContext context; context.Check("if (false) { var x = 0; }; x", 0, 0, - 1, // declaration + 0, // declaration EXPECT_RESULT, Undefined()); } } diff --git a/deps/v8/test/cctest/test-disasm-x64.cc b/deps/v8/test/cctest/test-disasm-x64.cc index da85eb933e..c6332e249b 100644 --- a/deps/v8/test/cctest/test-disasm-x64.cc +++ b/deps/v8/test/cctest/test-disasm-x64.cc @@ -264,6 +264,7 @@ TEST(DisasmX64) { ExternalReference after_break_target = ExternalReference(Debug_Address::AfterBreakTarget(), assm.isolate()); + USE(after_break_target); #endif // ENABLE_DEBUGGER_SUPPORT __ jmp(ic, RelocInfo::CODE_TARGET); __ nop(); diff --git a/deps/v8/test/cctest/test-double.cc b/deps/v8/test/cctest/test-double.cc index 3594a4fe32..6ef42c64dd 100644 --- a/deps/v8/test/cctest/test-double.cc +++ b/deps/v8/test/cctest/test-double.cc @@ -112,21 +112,6 @@ TEST(IsInfinite) { } -TEST(IsNan) { - CHECK(Double(OS::nan_value()).IsNan()); - uint64_t other_nan = V8_2PART_UINT64_C(0xFFFFFFFF, 00000001); - CHECK(Double(other_nan).IsNan()); - CHECK(!Double(V8_INFINITY).IsNan()); - CHECK(!Double(-V8_INFINITY).IsNan()); - CHECK(!Double(0.0).IsNan()); - CHECK(!Double(-0.0).IsNan()); - CHECK(!Double(1.0).IsNan()); - CHECK(!Double(-1.0).IsNan()); - uint64_t min_double64 = V8_2PART_UINT64_C(0x00000000, 00000001); - CHECK(!Double(min_double64).IsNan()); -} - - TEST(Sign) { CHECK_EQ(1, Double(1.0).Sign()); CHECK_EQ(1, Double(V8_INFINITY).Sign()); diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index a56f250c2a..cbe8d4459c 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -2,11 +2,14 @@ // // Tests for heap profiler +#include <ctype.h> + #include "v8.h" #include "cctest.h" #include "heap-profiler.h" #include "snapshot.h" +#include "debug.h" #include "utils-inl.h" #include "../include/v8-profiler.h" @@ -31,10 +34,10 @@ class NamedEntriesDetector { CheckEntry(root); while (!list.is_empty()) { i::HeapEntry* entry = list.RemoveLast(); - i::Vector<i::HeapGraphEdge> children = entry->children(); + i::Vector<i::HeapGraphEdge*> children = entry->children(); for (int i = 0; i < children.length(); ++i) { - if (children[i].type() == i::HeapGraphEdge::kShortcut) continue; - i::HeapEntry* child = children[i].to(); + if (children[i]->type() == i::HeapGraphEdge::kShortcut) continue; + i::HeapEntry* child = children[i]->to(); if (!child->painted()) { list.Add(child); child->paint(); @@ -109,13 +112,13 @@ TEST(HeapSnapshot) { // Verify, that JS global object of env2 has '..2' properties. const v8::HeapGraphNode* a2_node = - GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2"); + GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2"); CHECK_NE(NULL, a2_node); CHECK_NE( - NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1")); + NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_1")); CHECK_NE( - NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2")); - CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2")); + NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2")); + CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2")); // Paint all nodes reachable from global object. NamedEntriesDetector det; @@ -137,12 +140,13 @@ TEST(HeapSnapshotObjectSizes) { CompileRun( "function X(a, b) { this.a = a; this.b = b; }\n" "x = new X(new X(), new X());\n" + "dummy = new X();\n" "(function() { x.a.a = x.b; })();"); const v8::HeapSnapshot* snapshot = v8::HeapProfiler::TakeSnapshot(v8_str("sizes")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* x = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "x"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "x"); CHECK_NE(NULL, x); const v8::HeapGraphNode* x1 = GetProperty(x, v8::HeapGraphEdge::kProperty, "a"); @@ -169,7 +173,7 @@ TEST(BoundFunctionInSnapshot) { v8::HeapProfiler::TakeSnapshot(v8_str("sizes")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* f = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "boundFunction"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "boundFunction"); CHECK(f); CHECK_EQ(v8::String::New("native_bind"), f->GetName()); const v8::HeapGraphNode* bindings = @@ -233,15 +237,15 @@ TEST(HeapSnapshotCodeObjects) { const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* compiled = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled"); CHECK_NE(NULL, compiled); CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType()); const v8::HeapGraphNode* lazy = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy"); CHECK_NE(NULL, lazy); CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType()); const v8::HeapGraphNode* anonymous = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous"); CHECK_NE(NULL, anonymous); CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType()); v8::String::AsciiValue anonymous_name(anonymous->GetName()); @@ -293,9 +297,9 @@ TEST(HeapSnapshotHeapNumbers) { const v8::HeapSnapshot* snapshot = v8::HeapProfiler::TakeSnapshot(v8_str("numbers")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); - CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a")); + CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a")); const v8::HeapGraphNode* b = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "b"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "b"); CHECK_NE(NULL, b); CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType()); } @@ -313,10 +317,10 @@ TEST(HeapSnapshotSlicedString) { v8::HeapProfiler::TakeSnapshot(v8_str("strings")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* parent_string = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "parent_string"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "parent_string"); CHECK_NE(NULL, parent_string); const v8::HeapGraphNode* child_string = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "child_string"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string"); CHECK_NE(NULL, child_string); const v8::HeapGraphNode* parent = GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent"); @@ -344,12 +348,12 @@ TEST(HeapSnapshotInternalReferences) { } -// Trying to introduce a check helper for uint64_t causes many +// Trying to introduce a check helper for uint32_t causes many // overloading ambiguities, so it seems easier just to cast // them to a signed type. -#define CHECK_EQ_UINT64_T(a, b) \ - CHECK_EQ(static_cast<int64_t>(a), static_cast<int64_t>(b)) -#define CHECK_NE_UINT64_T(a, b) \ +#define CHECK_EQ_SNAPSHOT_OBJECT_ID(a, b) \ + CHECK_EQ(static_cast<int32_t>(a), static_cast<int32_t>(b)) +#define CHECK_NE_SNAPSHOT_OBJECT_ID(a, b) \ CHECK((a) != (b)) // NOLINT TEST(HeapEntryIdsAndArrayShift) { @@ -378,31 +382,24 @@ TEST(HeapEntryIdsAndArrayShift) { const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1); const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2); - CHECK_NE_UINT64_T(0, global1->GetId()); - CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId()); + CHECK_NE_SNAPSHOT_OBJECT_ID(0, global1->GetId()); + CHECK_EQ_SNAPSHOT_OBJECT_ID(global1->GetId(), global2->GetId()); const v8::HeapGraphNode* a1 = GetProperty(global1, v8::HeapGraphEdge::kProperty, "a"); CHECK_NE(NULL, a1); - const v8::HeapGraphNode* e1 = - GetProperty(a1, v8::HeapGraphEdge::kHidden, "1"); - CHECK_NE(NULL, e1); const v8::HeapGraphNode* k1 = - GetProperty(e1, v8::HeapGraphEdge::kInternal, "elements"); + GetProperty(a1, v8::HeapGraphEdge::kInternal, "elements"); CHECK_NE(NULL, k1); const v8::HeapGraphNode* a2 = GetProperty(global2, v8::HeapGraphEdge::kProperty, "a"); CHECK_NE(NULL, a2); - const v8::HeapGraphNode* e2 = - GetProperty(a2, v8::HeapGraphEdge::kHidden, "1"); - CHECK_NE(NULL, e2); const v8::HeapGraphNode* k2 = - GetProperty(e2, v8::HeapGraphEdge::kInternal, "elements"); + GetProperty(a2, v8::HeapGraphEdge::kInternal, "elements"); CHECK_NE(NULL, k2); - CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId()); - CHECK_EQ_UINT64_T(e1->GetId(), e2->GetId()); - CHECK_EQ_UINT64_T(k1->GetId(), k2->GetId()); + CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId()); + CHECK_EQ_SNAPSHOT_OBJECT_ID(k1->GetId(), k2->GetId()); } TEST(HeapEntryIdsAndGC) { @@ -414,50 +411,56 @@ TEST(HeapEntryIdsAndGC) { "function B(x) { this.x = x; }\n" "var a = new A();\n" "var b = new B(a);"); + v8::Local<v8::String> s1_str = v8_str("s1"); + v8::Local<v8::String> s2_str = v8_str("s2"); const v8::HeapSnapshot* snapshot1 = - v8::HeapProfiler::TakeSnapshot(v8_str("s1")); + v8::HeapProfiler::TakeSnapshot(s1_str); HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); const v8::HeapSnapshot* snapshot2 = - v8::HeapProfiler::TakeSnapshot(v8_str("s2")); + v8::HeapProfiler::TakeSnapshot(s2_str); + + CHECK_GT(snapshot1->GetMaxSnapshotJSObjectId(), 7000); + CHECK(snapshot1->GetMaxSnapshotJSObjectId() <= + snapshot2->GetMaxSnapshotJSObjectId()); const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1); const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2); - CHECK_NE_UINT64_T(0, global1->GetId()); - CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId()); + CHECK_NE_SNAPSHOT_OBJECT_ID(0, global1->GetId()); + CHECK_EQ_SNAPSHOT_OBJECT_ID(global1->GetId(), global2->GetId()); const v8::HeapGraphNode* A1 = GetProperty(global1, v8::HeapGraphEdge::kProperty, "A"); CHECK_NE(NULL, A1); const v8::HeapGraphNode* A2 = GetProperty(global2, v8::HeapGraphEdge::kProperty, "A"); CHECK_NE(NULL, A2); - CHECK_NE_UINT64_T(0, A1->GetId()); - CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId()); + CHECK_NE_SNAPSHOT_OBJECT_ID(0, A1->GetId()); + CHECK_EQ_SNAPSHOT_OBJECT_ID(A1->GetId(), A2->GetId()); const v8::HeapGraphNode* B1 = GetProperty(global1, v8::HeapGraphEdge::kProperty, "B"); CHECK_NE(NULL, B1); const v8::HeapGraphNode* B2 = GetProperty(global2, v8::HeapGraphEdge::kProperty, "B"); CHECK_NE(NULL, B2); - CHECK_NE_UINT64_T(0, B1->GetId()); - CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId()); + CHECK_NE_SNAPSHOT_OBJECT_ID(0, B1->GetId()); + CHECK_EQ_SNAPSHOT_OBJECT_ID(B1->GetId(), B2->GetId()); const v8::HeapGraphNode* a1 = GetProperty(global1, v8::HeapGraphEdge::kProperty, "a"); CHECK_NE(NULL, a1); const v8::HeapGraphNode* a2 = GetProperty(global2, v8::HeapGraphEdge::kProperty, "a"); CHECK_NE(NULL, a2); - CHECK_NE_UINT64_T(0, a1->GetId()); - CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId()); + CHECK_NE_SNAPSHOT_OBJECT_ID(0, a1->GetId()); + CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId()); const v8::HeapGraphNode* b1 = GetProperty(global1, v8::HeapGraphEdge::kProperty, "b"); CHECK_NE(NULL, b1); const v8::HeapGraphNode* b2 = GetProperty(global2, v8::HeapGraphEdge::kProperty, "b"); CHECK_NE(NULL, b2); - CHECK_NE_UINT64_T(0, b1->GetId()); - CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId()); + CHECK_NE_SNAPSHOT_OBJECT_ID(0, b1->GetId()); + CHECK_EQ_SNAPSHOT_OBJECT_ID(b1->GetId(), b2->GetId()); } @@ -508,7 +511,7 @@ TEST(HeapEntryDominator) { const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); const v8::HeapGraphNode* node6 = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "node6"); CHECK_NE(NULL, node6); const v8::HeapGraphNode* node5 = GetProperty(node6, v8::HeapGraphEdge::kProperty, "a"); @@ -551,9 +554,14 @@ class TestJSONStream : public v8::OutputStream { memcpy(chunk.start(), buffer, chars_written); return kContinue; } + virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) { + ASSERT(false); + return kAbort; + } void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); } int eos_signaled() { return eos_signaled_; } int size() { return buffer_.size(); } + private: i::Collector<char> buffer_; int eos_signaled_; @@ -607,42 +615,37 @@ TEST(HeapSnapshotJSONSerialization) { env->Global()->Get(v8_str("parsed"))->ToObject(); CHECK(parsed_snapshot->Has(v8_str("snapshot"))); CHECK(parsed_snapshot->Has(v8_str("nodes"))); + CHECK(parsed_snapshot->Has(v8_str("edges"))); CHECK(parsed_snapshot->Has(v8_str("strings"))); // Get node and edge "member" offsets. v8::Local<v8::Value> meta_analysis_result = CompileRun( - "var parsed_meta = parsed.nodes[0];\n" - "var children_count_offset =" - " parsed_meta.fields.indexOf('children_count');\n" - "var children_offset =" - " parsed_meta.fields.indexOf('children');\n" - "var children_meta =" - " parsed_meta.types[children_offset];\n" - "var child_fields_count = children_meta.fields.length;\n" - "var child_type_offset =" - " children_meta.fields.indexOf('type');\n" - "var child_name_offset =" - " children_meta.fields.indexOf('name_or_index');\n" - "var child_to_node_offset =" - " children_meta.fields.indexOf('to_node');\n" + "var meta = parsed.snapshot.meta;\n" + "var edges_index_offset = meta.node_fields.indexOf('edges_index');\n" + "var node_fields_count = meta.node_fields.length;\n" + "var edge_fields_count = meta.edge_fields.length;\n" + "var edge_type_offset = meta.edge_fields.indexOf('type');\n" + "var edge_name_offset = meta.edge_fields.indexOf('name_or_index');\n" + "var edge_to_node_offset = meta.edge_fields.indexOf('to_node');\n" "var property_type =" - " children_meta.types[child_type_offset].indexOf('property');\n" + " meta.edge_types[edge_type_offset].indexOf('property');\n" "var shortcut_type =" - " children_meta.types[child_type_offset].indexOf('shortcut');"); + " meta.edge_types[edge_type_offset].indexOf('shortcut');\n" + "parsed.nodes.concat(0, 0, 0, 0, 0, 0, parsed.edges.length);"); CHECK(!meta_analysis_result.IsEmpty()); // A helper function for processing encoded nodes. CompileRun( "function GetChildPosByProperty(pos, prop_name, prop_type) {\n" " var nodes = parsed.nodes;\n" + " var edges = parsed.edges;\n" " var strings = parsed.strings;\n" - " for (var i = 0,\n" - " count = nodes[pos + children_count_offset] * child_fields_count;\n" - " i < count; i += child_fields_count) {\n" - " var child_pos = pos + children_offset + i;\n" - " if (nodes[child_pos + child_type_offset] === prop_type\n" - " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n" - " return nodes[child_pos + child_to_node_offset];\n" + " for (var i = nodes[pos + edges_index_offset],\n" + " count = nodes[pos + node_fields_count + edges_index_offset];\n" + " i < count; i += edge_fields_count) {\n" + " if (edges[i + edge_type_offset] === prop_type\n" + " && strings[edges[i + edge_name_offset]] === prop_name)\n" + " return edges[i + edge_to_node_offset];\n" " }\n" " return null;\n" "}\n"); @@ -651,8 +654,9 @@ TEST(HeapSnapshotJSONSerialization) { "GetChildPosByProperty(\n" " GetChildPosByProperty(\n" " GetChildPosByProperty(" - " parsed.nodes[1 + children_offset + child_to_node_offset]," - " \"b\",shortcut_type),\n" + " parsed.edges[parsed.nodes[edges_index_offset]" + " + edge_to_node_offset]," + " \"b\", property_type),\n" " \"x\", property_type)," " \"s\", property_type)"); CHECK(!string_obj_pos_val.IsEmpty()); @@ -685,6 +689,200 @@ TEST(HeapSnapshotJSONSerializationAborting) { CHECK_EQ(0, stream.eos_signaled()); } +namespace { + +class TestStatsStream : public v8::OutputStream { + public: + TestStatsStream() + : eos_signaled_(0), + updates_written_(0), + entries_count_(0), + entries_size_(0), + intervals_count_(0), + first_interval_index_(-1) { } + TestStatsStream(const TestStatsStream& stream) + : v8::OutputStream(stream), + eos_signaled_(stream.eos_signaled_), + updates_written_(stream.updates_written_), + entries_count_(stream.entries_count_), + entries_size_(stream.entries_size_), + intervals_count_(stream.intervals_count_), + first_interval_index_(stream.first_interval_index_) { } + virtual ~TestStatsStream() {} + virtual void EndOfStream() { ++eos_signaled_; } + virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) { + ASSERT(false); + return kAbort; + } + virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* buffer, + int updates_written) { + ++intervals_count_; + ASSERT(updates_written); + updates_written_ += updates_written; + entries_count_ = 0; + if (first_interval_index_ == -1 && updates_written != 0) + first_interval_index_ = buffer[0].index; + for (int i = 0; i < updates_written; ++i) { + entries_count_ += buffer[i].count; + entries_size_ += buffer[i].size; + } + + return kContinue; + } + int eos_signaled() { return eos_signaled_; } + int updates_written() { return updates_written_; } + uint32_t entries_count() const { return entries_count_; } + uint32_t entries_size() const { return entries_size_; } + int intervals_count() const { return intervals_count_; } + int first_interval_index() const { return first_interval_index_; } + + private: + int eos_signaled_; + int updates_written_; + uint32_t entries_count_; + uint32_t entries_size_; + int intervals_count_; + int first_interval_index_; +}; + +} // namespace + +static TestStatsStream GetHeapStatsUpdate() { + TestStatsStream stream; + v8::HeapProfiler::PushHeapObjectsStats(&stream); + CHECK_EQ(1, stream.eos_signaled()); + return stream; +} + + +TEST(HeapSnapshotObjectsStats) { + v8::HandleScope scope; + LocalContext env; + + v8::HeapProfiler::StartHeapObjectsTracking(); + // We have to call GC 5 times. In other case the garbage will be + // the reason of flakiness. + for (int i = 0; i < 5; ++i) { + HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); + } + + { + // Single chunk of data expected in update. Initial data. + TestStatsStream stats_update = GetHeapStatsUpdate(); + CHECK_EQ(1, stats_update.intervals_count()); + CHECK_EQ(1, stats_update.updates_written()); + CHECK_LT(0, stats_update.entries_size()); + CHECK_EQ(0, stats_update.first_interval_index()); + } + + // No data expected in update because nothing has happened. + CHECK_EQ(0, GetHeapStatsUpdate().updates_written()); + { + v8::HandleScope inner_scope_1; + v8_str("string1"); + { + // Single chunk of data with one new entry expected in update. + TestStatsStream stats_update = GetHeapStatsUpdate(); + CHECK_EQ(1, stats_update.intervals_count()); + CHECK_EQ(1, stats_update.updates_written()); + CHECK_LT(0, stats_update.entries_size()); + CHECK_EQ(1, stats_update.entries_count()); + CHECK_EQ(2, stats_update.first_interval_index()); + } + + // No data expected in update because nothing happened. + CHECK_EQ(0, GetHeapStatsUpdate().updates_written()); + + { + v8::HandleScope inner_scope_2; + v8_str("string2"); + + uint32_t entries_size; + { + v8::HandleScope inner_scope_3; + v8_str("string3"); + v8_str("string4"); + + { + // Single chunk of data with three new entries expected in update. + TestStatsStream stats_update = GetHeapStatsUpdate(); + CHECK_EQ(1, stats_update.intervals_count()); + CHECK_EQ(1, stats_update.updates_written()); + CHECK_LT(0, entries_size = stats_update.entries_size()); + CHECK_EQ(3, stats_update.entries_count()); + CHECK_EQ(4, stats_update.first_interval_index()); + } + } + + { + // Single chunk of data with two left entries expected in update. + TestStatsStream stats_update = GetHeapStatsUpdate(); + CHECK_EQ(1, stats_update.intervals_count()); + CHECK_EQ(1, stats_update.updates_written()); + CHECK_GT(entries_size, stats_update.entries_size()); + CHECK_EQ(1, stats_update.entries_count()); + // Two strings from forth interval were released. + CHECK_EQ(4, stats_update.first_interval_index()); + } + } + + { + // Single chunk of data with 0 left entries expected in update. + TestStatsStream stats_update = GetHeapStatsUpdate(); + CHECK_EQ(1, stats_update.intervals_count()); + CHECK_EQ(1, stats_update.updates_written()); + CHECK_EQ(0, stats_update.entries_size()); + CHECK_EQ(0, stats_update.entries_count()); + // The last string from forth interval was released. + CHECK_EQ(4, stats_update.first_interval_index()); + } + } + { + // Single chunk of data with 0 left entries expected in update. + TestStatsStream stats_update = GetHeapStatsUpdate(); + CHECK_EQ(1, stats_update.intervals_count()); + CHECK_EQ(1, stats_update.updates_written()); + CHECK_EQ(0, stats_update.entries_size()); + CHECK_EQ(0, stats_update.entries_count()); + // The only string from the second interval was released. + CHECK_EQ(2, stats_update.first_interval_index()); + } + + v8::Local<v8::Array> array = v8::Array::New(); + CHECK_EQ(0, array->Length()); + // Force array's buffer allocation. + array->Set(2, v8_num(7)); + + uint32_t entries_size; + { + // Single chunk of data with 2 entries expected in update. + TestStatsStream stats_update = GetHeapStatsUpdate(); + CHECK_EQ(1, stats_update.intervals_count()); + CHECK_EQ(1, stats_update.updates_written()); + CHECK_LT(0, entries_size = stats_update.entries_size()); + // They are the array and its buffer. + CHECK_EQ(2, stats_update.entries_count()); + CHECK_EQ(8, stats_update.first_interval_index()); + } + + for (int i = 0; i < 100; ++i) + array->Set(i, v8_num(i)); + + { + // Single chunk of data with 1 entry expected in update. + TestStatsStream stats_update = GetHeapStatsUpdate(); + CHECK_EQ(1, stats_update.intervals_count()); + // The first interval was changed because old buffer was collected. + // The second interval was changed because new buffer was allocated. + CHECK_EQ(2, stats_update.updates_written()); + CHECK_LT(entries_size, stats_update.entries_size()); + CHECK_EQ(2, stats_update.entries_count()); + CHECK_EQ(8, stats_update.first_interval_index()); + } + + v8::HeapProfiler::StopHeapObjectsTracking(); +} + static void CheckChildrenIds(const v8::HeapSnapshot* snapshot, const v8::HeapGraphNode* node, @@ -695,7 +893,7 @@ static void CheckChildrenIds(const v8::HeapSnapshot* snapshot, const v8::HeapGraphEdge* prop = node->GetChild(i); const v8::HeapGraphNode* child = snapshot->GetNodeById(prop->GetToNode()->GetId()); - CHECK_EQ_UINT64_T(prop->GetToNode()->GetId(), child->GetId()); + CHECK_EQ_SNAPSHOT_OBJECT_ID(prop->GetToNode()->GetId(), child->GetId()); CHECK_EQ(prop->GetToNode(), child); CheckChildrenIds(snapshot, child, level + 1, max_level); } @@ -715,6 +913,42 @@ TEST(HeapSnapshotGetNodeById) { } +TEST(HeapSnapshotGetSnapshotObjectId) { + v8::HandleScope scope; + LocalContext env; + CompileRun("globalObject = {};\n"); + const v8::HeapSnapshot* snapshot = + v8::HeapProfiler::TakeSnapshot(v8_str("get_snapshot_object_id")); + const v8::HeapGraphNode* global = GetGlobalObject(snapshot); + const v8::HeapGraphNode* global_object = + GetProperty(global, v8::HeapGraphEdge::kProperty, "globalObject"); + CHECK(global_object); + + v8::Local<v8::Value> globalObjectHandle = + env->Global()->Get(v8::String::New("globalObject")); + CHECK(!globalObjectHandle.IsEmpty()); + CHECK(globalObjectHandle->IsObject()); + + v8::SnapshotObjectId id = + v8::HeapProfiler::GetSnapshotObjectId(globalObjectHandle); + CHECK_NE(static_cast<int>(v8::HeapProfiler::kUnknownObjectId), + id); + CHECK_EQ(static_cast<int>(id), global_object->GetId()); +} + + +TEST(HeapSnapshotUnknownSnapshotObjectId) { + v8::HandleScope scope; + LocalContext env; + CompileRun("globalObject = {};\n"); + const v8::HeapSnapshot* snapshot = + v8::HeapProfiler::TakeSnapshot(v8_str("unknown_object_id")); + const v8::HeapGraphNode* node = + snapshot->GetNodeById(v8::HeapProfiler::kUnknownObjectId); + CHECK_EQ(NULL, node); +} + + namespace { class TestActivityControl : public v8::ActivityControl { @@ -953,9 +1187,8 @@ TEST(HeapSnapshotImplicitReferences) { v8::HeapProfiler::TakeSnapshot(v8_str("implicit_refs")); const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot); - // Use kShortcut type to skip intermediate JSGlobalPropertyCell const v8::HeapGraphNode* obj0 = GetProperty( - global_object, v8::HeapGraphEdge::kShortcut, "root_object"); + global_object, v8::HeapGraphEdge::kProperty, "root_object"); CHECK(obj0); CHECK_EQ(v8::HeapGraphNode::kObject, obj0->GetType()); const v8::HeapGraphNode* obj1 = GetProperty( @@ -1128,7 +1361,7 @@ TEST(GetHeapValue) { env->Global()->GetPrototype().As<v8::Object>(); CHECK(js_global == global->GetHeapValue()); const v8::HeapGraphNode* obj = GetProperty( - global, v8::HeapGraphEdge::kShortcut, "a"); + global, v8::HeapGraphEdge::kProperty, "a"); CHECK(obj->GetHeapValue()->IsObject()); v8::Local<v8::Object> js_obj = js_global->Get(v8_str("a")).As<v8::Object>(); CHECK(js_obj == obj->GetHeapValue()); @@ -1157,7 +1390,7 @@ TEST(GetHeapValueForDeletedObject) { v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* obj = GetProperty( - global, v8::HeapGraphEdge::kShortcut, "a"); + global, v8::HeapGraphEdge::kProperty, "a"); const v8::HeapGraphNode* prop = GetProperty( obj, v8::HeapGraphEdge::kProperty, "p"); { @@ -1244,7 +1477,7 @@ TEST(FastCaseGetter) { const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); const v8::HeapGraphNode* obj1 = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "obj1"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1"); CHECK_NE(NULL, obj1); const v8::HeapGraphNode* getterFunction = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get-propWithGetter"); @@ -1326,7 +1559,7 @@ TEST(SfiAndJsFunctionWeakRefs) { const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK_NE(NULL, global); const v8::HeapGraphNode* fun = - GetProperty(global, v8::HeapGraphEdge::kShortcut, "fun"); + GetProperty(global, v8::HeapGraphEdge::kProperty, "fun"); CHECK(HasWeakEdge(fun)); const v8::HeapGraphNode* shared = GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared"); @@ -1334,6 +1567,30 @@ TEST(SfiAndJsFunctionWeakRefs) { } +TEST(NoDebugObjectInSnapshot) { + v8::HandleScope scope; + LocalContext env; + + v8::internal::Isolate::Current()->debug()->Load(); + CompileRun("foo = {};"); + const v8::HeapSnapshot* snapshot = + v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); + const v8::HeapGraphNode* root = snapshot->GetRoot(); + int globals_count = 0; + for (int i = 0; i < root->GetChildrenCount(); ++i) { + const v8::HeapGraphEdge* edge = root->GetChild(i); + if (edge->GetType() == v8::HeapGraphEdge::kShortcut) { + ++globals_count; + const v8::HeapGraphNode* global = edge->GetToNode(); + const v8::HeapGraphNode* foo = + GetProperty(global, v8::HeapGraphEdge::kProperty, "foo"); + CHECK_NE(NULL, foo); + } + } + CHECK_EQ(1, globals_count); +} + + TEST(PersistentHandleCount) { v8::HandleScope scope; LocalContext env; @@ -1366,3 +1623,44 @@ TEST(PersistentHandleCount) { p_BBB.Dispose(); CHECK_EQ(global_handle_count, v8::HeapProfiler::GetPersistentHandleCount()); } + + +TEST(AllStrongGcRootsHaveNames) { + v8::HandleScope scope; + LocalContext env; + + CompileRun("foo = {};"); + const v8::HeapSnapshot* snapshot = + v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); + const v8::HeapGraphNode* gc_roots = GetNode( + snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)"); + CHECK_NE(NULL, gc_roots); + const v8::HeapGraphNode* strong_roots = GetNode( + gc_roots, v8::HeapGraphNode::kObject, "(Strong roots)"); + CHECK_NE(NULL, strong_roots); + for (int i = 0; i < strong_roots->GetChildrenCount(); ++i) { + const v8::HeapGraphEdge* edge = strong_roots->GetChild(i); + CHECK_EQ(v8::HeapGraphEdge::kInternal, edge->GetType()); + v8::String::AsciiValue name(edge->GetName()); + CHECK(isalpha(**name)); + } +} + + +TEST(NoRefsToNonEssentialEntries) { + v8::HandleScope scope; + LocalContext env; + CompileRun("global_object = {};\n"); + const v8::HeapSnapshot* snapshot = + v8::HeapProfiler::TakeSnapshot(v8_str("snapshot")); + const v8::HeapGraphNode* global = GetGlobalObject(snapshot); + const v8::HeapGraphNode* global_object = + GetProperty(global, v8::HeapGraphEdge::kProperty, "global_object"); + CHECK_NE(NULL, global_object); + const v8::HeapGraphNode* properties = + GetProperty(global_object, v8::HeapGraphEdge::kInternal, "properties"); + CHECK_EQ(NULL, properties); + const v8::HeapGraphNode* elements = + GetProperty(global_object, v8::HeapGraphEdge::kInternal, "elements"); + CHECK_EQ(NULL, elements); +} diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index 999e2c6651..72079dc2ae 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -1214,7 +1214,9 @@ TEST(TestSizeOfObjects) { // The heap size should go back to initial size after a full GC, even // though sweeping didn't finish yet. HEAP->CollectAllGarbage(Heap::kNoGCFlags); - CHECK(!HEAP->old_pointer_space()->IsSweepingComplete()); + + // Normally sweeping would not be complete here, but no guarantees. + CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects())); // Advancing the sweeper step-wise should not change the heap size. @@ -1264,9 +1266,9 @@ static void FillUpNewSpace(NewSpace* new_space) { v8::HandleScope scope; AlwaysAllocateScope always_allocate; intptr_t available = new_space->EffectiveCapacity() - new_space->Size(); - intptr_t number_of_fillers = (available / FixedArray::SizeFor(1000)) - 10; + intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1; for (intptr_t i = 0; i < number_of_fillers; i++) { - CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(1000, NOT_TENURED))); + CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED))); } } @@ -1275,6 +1277,13 @@ TEST(GrowAndShrinkNewSpace) { InitializeVM(); NewSpace* new_space = HEAP->new_space(); + if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) { + // The max size cannot exceed the reserved size, since semispaces must be + // always within the reserved space. We can't test new space growing and + // shrinking if the reserved size is the same as the minimum (initial) size. + return; + } + // Explicitly growing should double the space capacity. intptr_t old_capacity, new_capacity; old_capacity = new_space->Capacity(); @@ -1315,6 +1324,14 @@ TEST(GrowAndShrinkNewSpace) { TEST(CollectingAllAvailableGarbageShrinksNewSpace) { InitializeVM(); + + if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) { + // The max size cannot exceed the reserved size, since semispaces must be + // always within the reserved space. We can't test new space growing and + // shrinking if the reserved size is the same as the minimum (initial) size. + return; + } + v8::HandleScope scope; NewSpace* new_space = HEAP->new_space(); intptr_t old_capacity, new_capacity; @@ -1521,17 +1538,13 @@ TEST(InstanceOfStubWriteBarrier) { while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) && !marking->IsStopped()) { - marking->Step(MB); + // Discard any pending GC requests otherwise we will get GC when we enter + // code below. + marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); } CHECK(marking->IsMarking()); - // Discard any pending GC requests otherwise we will get GC when we enter - // code below. - if (ISOLATE->stack_guard()->IsGCRequest()) { - ISOLATE->stack_guard()->Continue(GC_REQUEST); - } - { v8::HandleScope scope; v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global(); @@ -1597,3 +1610,128 @@ TEST(PrototypeTransitionClearing) { HEAP->CollectAllGarbage(Heap::kNoGCFlags); CHECK(map->GetPrototypeTransition(*prototype)->IsMap()); } + + +TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) { + i::FLAG_allow_natives_syntax = true; +#ifdef DEBUG + i::FLAG_verify_heap = true; +#endif + InitializeVM(); + if (!i::V8::UseCrankshaft()) return; + v8::HandleScope outer_scope; + + { + v8::HandleScope scope; + CompileRun( + "function f () {" + " var s = 0;" + " for (var i = 0; i < 100; i++) s += i;" + " return s;" + "}" + "f(); f();" + "%OptimizeFunctionOnNextCall(f);" + "f();"); + } + Handle<JSFunction> f = + v8::Utils::OpenHandle( + *v8::Handle<v8::Function>::Cast( + v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); + CHECK(f->IsOptimized()); + + IncrementalMarking* marking = HEAP->incremental_marking(); + marking->Abort(); + marking->Start(); + + // The following two calls will increment HEAP->global_ic_age(). + const int kLongIdlePauseInMs = 1000; + v8::V8::ContextDisposedNotification(); + v8::V8::IdleNotification(kLongIdlePauseInMs); + + while (!marking->IsStopped() && !marking->IsComplete()) { + marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); + } + if (!marking->IsStopped() || marking->should_hurry()) { + // We don't normally finish a GC via Step(), we normally finish by + // setting the stack guard and then do the final steps in the stack + // guard interrupt. But here we didn't ask for that, and there is no + // JS code running to trigger the interrupt, so we explicitly finalize + // here. + HEAP->CollectAllGarbage(Heap::kNoGCFlags, + "Test finalizing incremental mark-sweep"); + } + + CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age()); + CHECK_EQ(0, f->shared()->opt_count()); + CHECK_EQ(0, f->shared()->code()->profiler_ticks()); +} + + +TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) { + i::FLAG_allow_natives_syntax = true; +#ifdef DEBUG + i::FLAG_verify_heap = true; +#endif + InitializeVM(); + if (!i::V8::UseCrankshaft()) return; + v8::HandleScope outer_scope; + + { + v8::HandleScope scope; + CompileRun( + "function f () {" + " var s = 0;" + " for (var i = 0; i < 100; i++) s += i;" + " return s;" + "}" + "f(); f();" + "%OptimizeFunctionOnNextCall(f);" + "f();"); + } + Handle<JSFunction> f = + v8::Utils::OpenHandle( + *v8::Handle<v8::Function>::Cast( + v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); + CHECK(f->IsOptimized()); + + HEAP->incremental_marking()->Abort(); + + // The following two calls will increment HEAP->global_ic_age(). + // Since incremental marking is off, IdleNotification will do full GC. + const int kLongIdlePauseInMs = 1000; + v8::V8::ContextDisposedNotification(); + v8::V8::IdleNotification(kLongIdlePauseInMs); + + CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age()); + CHECK_EQ(0, f->shared()->opt_count()); + CHECK_EQ(0, f->shared()->code()->profiler_ticks()); +} + + +// Test that HAllocateObject will always return an object in new-space. +TEST(OptimizedAllocationAlwaysInNewSpace) { + i::FLAG_allow_natives_syntax = true; + InitializeVM(); + if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return; + v8::HandleScope scope; + + FillUpNewSpace(HEAP->new_space()); + AlwaysAllocateScope always_allocate; + v8::Local<v8::Value> res = CompileRun( + "function c(x) {" + " this.x = x;" + " for (var i = 0; i < 32; i++) {" + " this['x' + i] = x;" + " }" + "}" + "function f(x) { return new c(x); };" + "f(1); f(2); f(3);" + "%OptimizeFunctionOnNextCall(f);" + "f(4);"); + CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value()); + + Handle<JSObject> o = + v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); + + CHECK(HEAP->InNewSpace(*o)); +} diff --git a/deps/v8/test/cctest/test-list.cc b/deps/v8/test/cctest/test-list.cc index 7520b05fcb..4c78f02cee 100644 --- a/deps/v8/test/cctest/test-list.cc +++ b/deps/v8/test/cctest/test-list.cc @@ -130,6 +130,18 @@ TEST(RemoveLast) { } +TEST(Allocate) { + List<int> list(4); + list.Add(1); + CHECK_EQ(1, list.length()); + list.Allocate(100); + CHECK_EQ(100, list.length()); + CHECK_LE(100, list.capacity()); + list[99] = 123; + CHECK_EQ(123, list[99]); +} + + TEST(Clear) { List<int> list(4); CHECK_EQ(0, list.length()); diff --git a/deps/v8/test/cctest/test-mark-compact.cc b/deps/v8/test/cctest/test-mark-compact.cc index 973af19662..700f3222ae 100644 --- a/deps/v8/test/cctest/test-mark-compact.cc +++ b/deps/v8/test/cctest/test-mark-compact.cc @@ -534,15 +534,15 @@ TEST(BootUpMemoryUse) { intptr_t booted_memory = MemoryInUse(); if (sizeof(initial_memory) == 8) { if (v8::internal::Snapshot::IsEnabled()) { - CHECK_LE(booted_memory - initial_memory, 6686 * 1024); // 6476. + CHECK_LE(booted_memory - initial_memory, 3600 * 1024); // 3396. } else { - CHECK_LE(booted_memory - initial_memory, 6809 * 1024); // 6628. + CHECK_LE(booted_memory - initial_memory, 3600 * 1024); // 3432. } } else { if (v8::internal::Snapshot::IsEnabled()) { - CHECK_LE(booted_memory - initial_memory, 6532 * 1024); // 6388. + CHECK_LE(booted_memory - initial_memory, 2800 * 1024); // 2484. } else { - CHECK_LE(booted_memory - initial_memory, 6940 * 1024); // 6456 + CHECK_LE(booted_memory - initial_memory, 2950 * 1024); // 2844 } } } diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index d941d0f7b0..e89e6cddc9 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -504,7 +504,10 @@ static RegExpNode* Compile(const char* input, bool multiline, bool is_ascii) { return NULL; Handle<String> pattern = isolate->factory()-> NewStringFromUtf8(CStrVector(input)); - RegExpEngine::Compile(&compile_data, false, multiline, pattern, is_ascii); + Handle<String> sample_subject = + isolate->factory()->NewStringFromUtf8(CStrVector("")); + RegExpEngine::Compile( + &compile_data, false, multiline, pattern, sample_subject, is_ascii); return compile_data.node; } @@ -1587,7 +1590,7 @@ TEST(CharClassDifference) { ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT); ZoneList<CharacterRange>* base = new ZoneList<CharacterRange>(1); base->Add(CharacterRange::Everything()); - Vector<const uc16> overlay = CharacterRange::GetWordBounds(); + Vector<const int> overlay = CharacterRange::GetWordBounds(); ZoneList<CharacterRange>* included = NULL; ZoneList<CharacterRange>* excluded = NULL; CharacterRange::Split(base, overlay, &included, &excluded); @@ -1596,7 +1599,7 @@ TEST(CharClassDifference) { if (in_base) { bool in_overlay = false; for (int j = 0; !in_overlay && j < overlay.length(); j += 2) { - if (overlay[j] <= i && i <= overlay[j+1]) + if (overlay[j] <= i && i < overlay[j+1]) in_overlay = true; } CHECK_EQ(in_overlay, InClass(i, included)); @@ -1669,16 +1672,6 @@ TEST(CanonicalizeCharacterSets) { ASSERT_EQ(30, list->at(0).to()); } -// Checks whether a character is in the set represented by a list of ranges. -static bool CharacterInSet(ZoneList<CharacterRange>* set, uc16 value) { - for (int i = 0; i < set->length(); i++) { - CharacterRange range = set->at(i); - if (range.from() <= value && value <= range.to()) { - return true; - } - } - return false; -} TEST(CharacterRangeMerge) { v8::internal::V8::Initialize(NULL); @@ -1765,67 +1758,6 @@ TEST(CharacterRangeMerge) { ZoneList<CharacterRange> first_only(4); ZoneList<CharacterRange> second_only(4); ZoneList<CharacterRange> both(4); - - // Merge one direction. - CharacterRange::Merge(&l1, &l2, &first_only, &second_only, &both); - - CHECK(CharacterRange::IsCanonical(&first_only)); - CHECK(CharacterRange::IsCanonical(&second_only)); - CHECK(CharacterRange::IsCanonical(&both)); - - for (uc16 i = 0; i < offset; i++) { - bool in_first = CharacterInSet(&l1, i); - bool in_second = CharacterInSet(&l2, i); - CHECK((in_first && !in_second) == CharacterInSet(&first_only, i)); - CHECK((!in_first && in_second) == CharacterInSet(&second_only, i)); - CHECK((in_first && in_second) == CharacterInSet(&both, i)); - } - - first_only.Clear(); - second_only.Clear(); - both.Clear(); - - // Merge other direction. - CharacterRange::Merge(&l2, &l1, &second_only, &first_only, &both); - - CHECK(CharacterRange::IsCanonical(&first_only)); - CHECK(CharacterRange::IsCanonical(&second_only)); - CHECK(CharacterRange::IsCanonical(&both)); - - for (uc16 i = 0; i < offset; i++) { - bool in_first = CharacterInSet(&l1, i); - bool in_second = CharacterInSet(&l2, i); - CHECK((in_first && !in_second) == CharacterInSet(&first_only, i)); - CHECK((!in_first && in_second) == CharacterInSet(&second_only, i)); - CHECK((in_first && in_second) == CharacterInSet(&both, i)); - } - - first_only.Clear(); - second_only.Clear(); - both.Clear(); - - // Merge but don't record all combinations. - CharacterRange::Merge(&l1, &l2, NULL, NULL, &both); - - CHECK(CharacterRange::IsCanonical(&both)); - - for (uc16 i = 0; i < offset; i++) { - bool in_first = CharacterInSet(&l1, i); - bool in_second = CharacterInSet(&l2, i); - CHECK((in_first && in_second) == CharacterInSet(&both, i)); - } - - // Merge into same set. - ZoneList<CharacterRange> all(4); - CharacterRange::Merge(&l1, &l2, &all, &all, &all); - - CHECK(CharacterRange::IsCanonical(&all)); - - for (uc16 i = 0; i < offset; i++) { - bool in_first = CharacterInSet(&l1, i); - bool in_second = CharacterInSet(&l2, i); - CHECK((in_first || in_second) == CharacterInSet(&all, i)); - } } diff --git a/deps/v8/test/cctest/test-spaces.cc b/deps/v8/test/cctest/test-spaces.cc index 92de2a60fa..0e957048ee 100644 --- a/deps/v8/test/cctest/test-spaces.cc +++ b/deps/v8/test/cctest/test-spaces.cc @@ -140,8 +140,8 @@ TEST(MemoryAllocator) { heap->MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE); - Page* first_page = - memory_allocator->AllocatePage(&faked_space, NOT_EXECUTABLE); + Page* first_page = memory_allocator->AllocatePage( + faked_space.AreaSize(), &faked_space, NOT_EXECUTABLE); first_page->InsertAfter(faked_space.anchor()->prev_page()); CHECK(first_page->is_valid()); @@ -153,8 +153,8 @@ TEST(MemoryAllocator) { } // Again, we should get n or n - 1 pages. - Page* other = - memory_allocator->AllocatePage(&faked_space, NOT_EXECUTABLE); + Page* other = memory_allocator->AllocatePage( + faked_space.AreaSize(), &faked_space, NOT_EXECUTABLE); CHECK(other->is_valid()); total_pages++; other->InsertAfter(first_page); diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index e11349bc85..d86886f9be 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -587,3 +587,88 @@ TEST(SliceFromSlice) { CHECK(SlicedString::cast(*string)->parent()->IsSeqString()); CHECK_EQ("cdefghijklmnopqrstuvwx", *(string->ToCString())); } + + +TEST(AsciiArrayJoin) { + // Set heap limits. + static const int K = 1024; + v8::ResourceConstraints constraints; + constraints.set_max_young_space_size(256 * K); + constraints.set_max_old_space_size(4 * K * K); + v8::SetResourceConstraints(&constraints); + + // String s is made of 2^17 = 131072 'c' characters and a is an array + // starting with 'bad', followed by 2^14 times the string s. That means the + // total length of the concatenated strings is 2^31 + 3. So on 32bit systems + // summing the lengths of the strings (as Smis) overflows and wraps. + static const char* join_causing_out_of_memory = + "var two_14 = Math.pow(2, 14);" + "var two_17 = Math.pow(2, 17);" + "var s = Array(two_17 + 1).join('c');" + "var a = ['bad'];" + "for (var i = 1; i <= two_14; i++) a.push(s);" + "a.join("");"; + + v8::HandleScope scope; + LocalContext context; + v8::V8::IgnoreOutOfMemoryException(); + v8::Local<v8::Script> script = + v8::Script::Compile(v8::String::New(join_causing_out_of_memory)); + v8::Local<v8::Value> result = script->Run(); + + // Check for out of memory state. + CHECK(result.IsEmpty()); + CHECK(context->HasOutOfMemoryException()); +} + + +static void CheckException(const char* source) { + // An empty handle is returned upon exception. + CHECK(CompileRun(source).IsEmpty()); +} + + +TEST(RobustSubStringStub) { + // This tests whether the SubStringStub can handle unsafe arguments. + // If not recognized, those unsafe arguments lead to out-of-bounds reads. + FLAG_allow_natives_syntax = true; + InitializeVM(); + HandleScope scope; + v8::Local<v8::Value> result; + Handle<String> string; + CompileRun("var short = 'abcdef';"); + + // Invalid indices. + CheckException("%_SubString(short, 0, 10000);"); + CheckException("%_SubString(short, -1234, 5);"); + CheckException("%_SubString(short, 5, 2);"); + // Special HeapNumbers. + CheckException("%_SubString(short, 1, Infinity);"); + CheckException("%_SubString(short, NaN, 5);"); + // String arguments. + CheckException("%_SubString(short, '2', '5');"); + // Ordinary HeapNumbers can be handled (in runtime). + result = CompileRun("%_SubString(short, Math.sqrt(4), 5.1);"); + string = v8::Utils::OpenHandle(v8::String::Cast(*result)); + CHECK_EQ("cde", *(string->ToCString())); + + CompileRun("var long = 'abcdefghijklmnopqrstuvwxyz';"); + // Invalid indices. + CheckException("%_SubString(long, 0, 10000);"); + CheckException("%_SubString(long, -1234, 17);"); + CheckException("%_SubString(long, 17, 2);"); + // Special HeapNumbers. + CheckException("%_SubString(long, 1, Infinity);"); + CheckException("%_SubString(long, NaN, 17);"); + // String arguments. + CheckException("%_SubString(long, '2', '17');"); + // Ordinary HeapNumbers within bounds can be handled (in runtime). + result = CompileRun("%_SubString(long, Math.sqrt(4), 17.1);"); + string = v8::Utils::OpenHandle(v8::String::Cast(*result)); + CHECK_EQ("cdefghijklmnopq", *(string->ToCString())); + + // Test that out-of-bounds substring of a slice fails when the indices + // would have been valid for the underlying string. + CompileRun("var slice = long.slice(1, 15);"); + CheckException("%_SubString(slice, 0, 17);"); +} diff --git a/deps/v8/test/cctest/test-thread-termination.cc b/deps/v8/test/cctest/test-thread-termination.cc index 1aa57e3081..cebabaa97e 100644 --- a/deps/v8/test/cctest/test-thread-termination.cc +++ b/deps/v8/test/cctest/test-thread-termination.cc @@ -255,6 +255,10 @@ TEST(TerminateMultipleV8ThreadsDefaultIsolate) { threads[i]->Join(); delete threads[i]; } + { + v8::Locker locker; + v8::Locker::StopPreemption(); + } delete semaphore; semaphore = NULL; diff --git a/deps/v8/test/cctest/test-weakmaps.cc b/deps/v8/test/cctest/test-weakmaps.cc index 56d593628a..7bba7b6486 100644 --- a/deps/v8/test/cctest/test-weakmaps.cc +++ b/deps/v8/test/cctest/test-weakmaps.cc @@ -48,11 +48,11 @@ static Handle<JSWeakMap> AllocateJSWeakMap() { static void PutIntoWeakMap(Handle<JSWeakMap> weakmap, Handle<JSObject> key, - int value) { + Handle<Object> value) { Handle<ObjectHashTable> table = PutIntoObjectHashTable( Handle<ObjectHashTable>(ObjectHashTable::cast(weakmap->table())), Handle<JSObject>(JSObject::cast(*key)), - Handle<Smi>(Smi::FromInt(value))); + value); weakmap->set_table(*table); } @@ -65,6 +65,7 @@ static void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) { TEST(Weakness) { + FLAG_incremental_marking = false; LocalContext context; v8::HandleScope scope; Handle<JSWeakMap> weakmap = AllocateJSWeakMap(); @@ -83,7 +84,9 @@ TEST(Weakness) { // Put entry into weak map. { v8::HandleScope scope; - PutIntoWeakMap(weakmap, Handle<JSObject>(JSObject::cast(*key)), 23); + PutIntoWeakMap(weakmap, + Handle<JSObject>(JSObject::cast(*key)), + Handle<Smi>(Smi::FromInt(23))); } CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements()); @@ -133,7 +136,7 @@ TEST(Shrinking) { Handle<Map> map = FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); for (int i = 0; i < 32; i++) { Handle<JSObject> object = FACTORY->NewJSObjectFromMap(map); - PutIntoWeakMap(weakmap, object, i); + PutIntoWeakMap(weakmap, object, Handle<Smi>(Smi::FromInt(i))); } } @@ -152,3 +155,72 @@ TEST(Shrinking) { // Check shrunk capacity. CHECK_EQ(32, ObjectHashTable::cast(weakmap->table())->Capacity()); } + + +// Test that weak map values on an evacuation candidate which are not reachable +// by other paths are correctly recorded in the slots buffer. +TEST(Regress2060a) { + FLAG_always_compact = true; + LocalContext context; + v8::HandleScope scope; + Handle<JSFunction> function = + FACTORY->NewFunction(FACTORY->function_symbol(), FACTORY->null_value()); + Handle<JSObject> key = FACTORY->NewJSObject(function); + Handle<JSWeakMap> weakmap = AllocateJSWeakMap(); + + // Start second old-space page so that values land on evacuation candidate. + Page* first_page = HEAP->old_pointer_space()->anchor()->next_page(); + FACTORY->NewFixedArray(900 * KB / kPointerSize, TENURED); + + // Fill up weak map with values on an evacuation candidate. + { + v8::HandleScope scope; + for (int i = 0; i < 32; i++) { + Handle<JSObject> object = FACTORY->NewJSObject(function, TENURED); + CHECK(!HEAP->InNewSpace(object->address())); + CHECK(!first_page->Contains(object->address())); + PutIntoWeakMap(weakmap, key, object); + } + } + + // Force compacting garbage collection. + CHECK(FLAG_always_compact); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); +} + + +// Test that weak map keys on an evacuation candidate which are reachable by +// other strong paths are correctly recorded in the slots buffer. +TEST(Regress2060b) { + FLAG_always_compact = true; +#ifdef DEBUG + FLAG_verify_heap = true; +#endif + LocalContext context; + v8::HandleScope scope; + Handle<JSFunction> function = + FACTORY->NewFunction(FACTORY->function_symbol(), FACTORY->null_value()); + + // Start second old-space page so that keys land on evacuation candidate. + Page* first_page = HEAP->old_pointer_space()->anchor()->next_page(); + FACTORY->NewFixedArray(900 * KB / kPointerSize, TENURED); + + // Fill up weak map with keys on an evacuation candidate. + Handle<JSObject> keys[32]; + for (int i = 0; i < 32; i++) { + keys[i] = FACTORY->NewJSObject(function, TENURED); + CHECK(!HEAP->InNewSpace(keys[i]->address())); + CHECK(!first_page->Contains(keys[i]->address())); + } + Handle<JSWeakMap> weakmap = AllocateJSWeakMap(); + for (int i = 0; i < 32; i++) { + PutIntoWeakMap(weakmap, keys[i], Handle<Smi>(Smi::FromInt(i))); + } + + // Force compacting garbage collection. The subsequent collections are used + // to verify that key references were actually updated. + CHECK(FLAG_always_compact); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); +} diff --git a/deps/v8/test/cctest/testcfg.py b/deps/v8/test/cctest/testcfg.py index b2eabc44eb..f1387e8a4f 100644 --- a/deps/v8/test/cctest/testcfg.py +++ b/deps/v8/test/cctest/testcfg.py @@ -53,6 +53,8 @@ class CcTestCase(test.TestCase): serialization_file = join('obj', 'test', self.mode, 'serdes') else: serialization_file = join('obj', 'serdes') + if not exists(join(self.context.buildspace, 'obj')): + os.makedirs(join(self.context.buildspace, 'obj')) serialization_file += '_' + self.GetName() serialization_file = join(self.context.buildspace, serialization_file) serialization_file += ''.join(self.variant_flags).replace('-', '_') diff --git a/deps/v8/test/mjsunit/accessor-map-sharing.js b/deps/v8/test/mjsunit/accessor-map-sharing.js new file mode 100644 index 0000000000..ab45afab05 --- /dev/null +++ b/deps/v8/test/mjsunit/accessor-map-sharing.js @@ -0,0 +1,176 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax + +// Handy abbreviations. +var dp = Object.defineProperty; +var gop = Object.getOwnPropertyDescriptor; + +function getter() { return 111; } +function setter(x) { print(222); } +function anotherGetter() { return 333; } +function anotherSetter(x) { print(444); } +var obj1, obj2; + +// Two objects with the same getter. +obj1 = {}; +dp(obj1, "alpha", { get: getter }); +obj2 = {}; +dp(obj2, "alpha", { get: getter }); +assertTrue(%HaveSameMap(obj1, obj2)); + +// Two objects with the same getter, oldskool. +obj1 = {}; +obj1.__defineGetter__("bravo", getter); +assertEquals(getter, obj1.__lookupGetter__("bravo")); +obj2 = {}; +obj2.__defineGetter__("bravo", getter); +assertEquals(getter, obj2.__lookupGetter__("bravo")); +assertTrue(%HaveSameMap(obj1, obj2)); + +// Two objects with the same setter. +obj1 = {}; +dp(obj1, "charlie", { set: setter }); +obj2 = {}; +dp(obj2, "charlie", { set: setter }); +assertTrue(%HaveSameMap(obj1, obj2)); + +// Two objects with the same setter, oldskool. +obj1 = {}; +obj1.__defineSetter__("delta", setter); +assertEquals(setter, obj1.__lookupSetter__("delta")); +obj2 = {}; +obj2.__defineSetter__("delta", setter); +assertEquals(setter, obj2.__lookupSetter__("delta")); +assertTrue(%HaveSameMap(obj1, obj2)); + +// Two objects with the same getter and setter. +obj1 = {}; +dp(obj1, "foxtrot", { get: getter, set: setter }); +obj2 = {}; +dp(obj2, "foxtrot", { get: getter, set: setter }); +assertTrue(%HaveSameMap(obj1, obj2)); + +// Two objects with the same getter and setter, set separately. +obj1 = {}; +dp(obj1, "golf", { get: getter, configurable: true }); +dp(obj1, "golf", { set: setter, configurable: true }); +obj2 = {}; +dp(obj2, "golf", { get: getter, configurable: true }); +dp(obj2, "golf", { set: setter, configurable: true }); +assertTrue(%HaveSameMap(obj1, obj2)); + +// Two objects with the same getter and setter, set separately, oldskool. +obj1 = {}; +obj1.__defineGetter__("hotel", getter); +obj1.__defineSetter__("hotel", setter); +obj2 = {}; +obj2.__defineGetter__("hotel", getter); +obj2.__defineSetter__("hotel", setter); +assertTrue(%HaveSameMap(obj1, obj2)); + +// Attribute-only change, shouldn't affect previous descriptor properties. +obj1 = {}; +dp(obj1, "india", { get: getter, configurable: true, enumerable: true }); +assertEquals(getter, gop(obj1, "india").get); +assertTrue(gop(obj1, "india").configurable); +assertTrue(gop(obj1, "india").enumerable); +dp(obj1, "india", { enumerable: false }); +assertEquals(getter, gop(obj1, "india").get); +assertTrue(gop(obj1, "india").configurable); +assertFalse(gop(obj1, "india").enumerable); + +// Attribute-only change, shouldn't affect objects with previously shared maps. +obj1 = {}; +dp(obj1, "juliet", { set: setter, configurable: true, enumerable: false }); +assertEquals(setter, gop(obj1, "juliet").set); +assertTrue(gop(obj1, "juliet").configurable); +assertFalse(gop(obj1, "juliet").enumerable); +obj2 = {}; +dp(obj2, "juliet", { set: setter, configurable: true, enumerable: false }); +assertEquals(setter, gop(obj2, "juliet").set); +assertTrue(gop(obj2, "juliet").configurable); +assertFalse(gop(obj2, "juliet").enumerable); +dp(obj1, "juliet", { set: setter, configurable: false, enumerable: true }); +assertEquals(setter, gop(obj1, "juliet").set); +assertFalse(gop(obj1, "juliet").configurable); +assertTrue(gop(obj1, "juliet").enumerable); +assertEquals(setter, gop(obj2, "juliet").set); +assertTrue(gop(obj2, "juliet").configurable); +assertFalse(gop(obj2, "juliet").enumerable); + +// Two objects with the different getters. +obj1 = {}; +dp(obj1, "kilo", { get: getter }); +obj2 = {}; +dp(obj2, "kilo", { get: anotherGetter }); +assertEquals(getter, gop(obj1, "kilo").get); +assertEquals(anotherGetter, gop(obj2, "kilo").get); +assertFalse(%HaveSameMap(obj1, obj2)); + +// Two objects with the same getters and different setters. +obj1 = {}; +dp(obj1, "lima", { get: getter, set: setter }); +obj2 = {}; +dp(obj2, "lima", { get: getter, set: anotherSetter }); +assertEquals(setter, gop(obj1, "lima").set); +assertEquals(anotherSetter, gop(obj2, "lima").set); +assertFalse(%HaveSameMap(obj1, obj2)); + +// Even 'undefined' is a kind of getter. +obj1 = {}; +dp(obj1, "mike", { get: undefined }); +assertTrue("mike" in obj1); +assertEquals(undefined, gop(obj1, "mike").get); +assertEquals(undefined, obj1.__lookupGetter__("mike")); +assertEquals(undefined, gop(obj1, "mike").set); +assertEquals(undefined, obj1.__lookupSetter__("mike")); + +// Even 'undefined' is a kind of setter. +obj1 = {}; +dp(obj1, "november", { set: undefined }); +assertTrue("november" in obj1); +assertEquals(undefined, gop(obj1, "november").get); +assertEquals(undefined, obj1.__lookupGetter__("november")); +assertEquals(undefined, gop(obj1, "november").set); +assertEquals(undefined, obj1.__lookupSetter__("november")); + +// Redefining a data property. +obj1 = {}; +obj1.oscar = 12345; +dp(obj1, "oscar", { set: setter }); +assertEquals(setter, gop(obj1, "oscar").set); + +// Re-adding the same getter/attributes pair. +obj1 = {}; +dp(obj1, "papa", { get: getter, configurable: true }); +dp(obj1, "papa", { get: getter, set: setter, configurable: true }); +assertEquals(getter, gop(obj1, "papa").get); +assertEquals(setter, gop(obj1, "papa").set); +assertTrue(gop(obj1, "papa").configurable); +assertFalse(gop(obj1, "papa").enumerable); diff --git a/deps/v8/test/mjsunit/array-bounds-check-removal.js b/deps/v8/test/mjsunit/array-bounds-check-removal.js new file mode 100644 index 0000000000..81064aa237 --- /dev/null +++ b/deps/v8/test/mjsunit/array-bounds-check-removal.js @@ -0,0 +1,145 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax --expose-gc + +var a = new Int32Array(1024); + +function test_base(base,cond) { + a[base + 1] = 1; + a[base + 4] = 2; + a[base + 3] = 3; + a[base + 2] = 4; + a[base + 4] = base + 4; + if (cond) { + a[base + 1] = 1; + a[base + 2] = 2; + a[base + 2] = 3; + a[base + 2] = 4; + a[base + 4] = base + 4; + } else { + a[base + 6] = 1; + a[base + 4] = 2; + a[base + 3] = 3; + a[base + 2] = 4; + a[base + 4] = base - 4; + } +} + +function check_test_base(base,cond) { + if (cond) { + assertEquals(1, a[base + 1]); + assertEquals(4, a[base + 2]); + assertEquals(base + 4, a[base + 4]); + } else { + assertEquals(1, a[base + 6]); + assertEquals(3, a[base + 3]); + assertEquals(4, a[base + 2]); + assertEquals(base - 4, a[base + 4]); + } +} + + +function test_minus(base,cond) { + a[base - 1] = 1; + a[base - 2] = 2; + a[base + 4] = 3; + a[base] = 4; + a[base + 4] = base + 4; + if (cond) { + a[base - 4] = 1; + a[base + 5] = 2; + a[base + 3] = 3; + a[base + 2] = 4; + a[base + 4] = base + 4; + } else { + a[base + 6] = 1; + a[base + 4] = 2; + a[base + 3] = 3; + a[base + 2] = 4; + a[base + 4] = base - 4; + } +} + +function check_test_minus(base,cond) { + if (cond) { + assertEquals(2, a[base + 5]); + assertEquals(3, a[base + 3]); + assertEquals(4, a[base + 2]); + assertEquals(base + 4, a[base + 4]); + } else { + assertEquals(1, a[base + 6]); + assertEquals(3, a[base + 3]); + assertEquals(4, a[base + 2]); + assertEquals(base - 4, a[base + 4]); + } +} + +test_base(1,true); +test_base(2,true); +test_base(1,false); +test_base(2,false); +%OptimizeFunctionOnNextCall(test_base); +test_base(3,true); +check_test_base(3,true); +test_base(3,false); +check_test_base(3,false); + +test_minus(5,true); +test_minus(6,true); +%OptimizeFunctionOnNextCall(test_minus); +test_minus(7,true); +check_test_minus(7,true); +test_minus(7,false); +check_test_minus(7,false); + +// Optimization status: +// YES: 1 +// NO: 2 +// ALWAYS: 3 +// NEVER: 4 + +if (false) { +test_base(5,true); +test_base(6,true); +test_base(5,false); +test_base(6,false); +%OptimizeFunctionOnNextCall(test_base); +test_base(-2,true); +assertTrue(%GetOptimizationStatus(test_base) != 1); + +test_base(5,true); +test_base(6,true); +test_base(5,false); +test_base(6,false); +%OptimizeFunctionOnNextCall(test_base); +test_base(2048,true); +assertTrue(%GetOptimizationStatus(test_base) != 1); +} + +gc(); + diff --git a/deps/v8/test/mjsunit/big-array-literal.js b/deps/v8/test/mjsunit/big-array-literal.js index a0fad7c2ee..8e0ff87277 100644 --- a/deps/v8/test/mjsunit/big-array-literal.js +++ b/deps/v8/test/mjsunit/big-array-literal.js @@ -25,6 +25,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// On MacOS, this test needs a stack size of at least 538 kBytes. +// Flags: --stack-size=600 + // Test that we can make large object literals that work. // Also test that we can attempt to make even larger object literals without // crashing. diff --git a/deps/v8/test/mjsunit/compiler/alloc-object-huge.js b/deps/v8/test/mjsunit/compiler/alloc-object-huge.js index d6d9f1b721..0b202f7580 100644 --- a/deps/v8/test/mjsunit/compiler/alloc-object-huge.js +++ b/deps/v8/test/mjsunit/compiler/alloc-object-huge.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --allow-natives-syntax --inline-construct --nolimit-inlining +// Flags: --allow-natives-syntax --inline-construct --max-inlined-source-size=999999 --max-inlined-nodes=999999 --max-inlined-nodes-cumulative=999999 // Test that huge constructors (more than 256 this assignments) are // handled correctly. diff --git a/deps/v8/test/mjsunit/compiler/inline-arguments.js b/deps/v8/test/mjsunit/compiler/inline-arguments.js index b6adf7f6cc..f8a247608b 100644 --- a/deps/v8/test/mjsunit/compiler/inline-arguments.js +++ b/deps/v8/test/mjsunit/compiler/inline-arguments.js @@ -113,3 +113,70 @@ F4(1); %OptimizeFunctionOnNextCall(test_adaptation); test_adaptation(); })(); + +// Test arguments access from the inlined function. +function uninlinable(v) { + assertEquals(0, v); + try { } catch (e) { } + return 0; +} + +function toarr_inner() { + var a = arguments; + var marker = a[0]; + uninlinable(uninlinable(0, 0), marker.x); + + var r = new Array(); + for (var i = a.length - 1; i >= 1; i--) { + r.push(a[i]); + } + + return r; +} + +function toarr1(marker, a, b, c) { + return toarr_inner(marker, a / 2, b / 2, c / 2); +} + +function toarr2(marker, a, b, c) { + var x = 0; + return uninlinable(uninlinable(0, 0), + x = toarr_inner(marker, a / 2, b / 2, c / 2)), x; +} + +function test_toarr(toarr) { + var marker = { x: 0 }; + assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6)); + assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6)); + %OptimizeFunctionOnNextCall(toarr); + assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6)); + delete marker.x; + assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6)); +} + +test_toarr(toarr1); +test_toarr(toarr2); + +// Test that arguments access from inlined function uses correct values. +(function () { + function inner(x, y) { + "use strict"; + x = 10; + y = 20; + for (var i = 0; i < 1; i++) { + for (var j = 1; j <= arguments.length; j++) { + return arguments[arguments.length - j]; + } + } + } + + function outer(x, y) { + return inner(x, y); + } + + assertEquals(2, outer(1, 2)); + assertEquals(2, outer(1, 2)); + assertEquals(2, outer(1, 2)); + %OptimizeFunctionOnNextCall(outer); + assertEquals(2, outer(1, 2)); +})(); diff --git a/deps/v8/test/mjsunit/compiler/inline-construct.js b/deps/v8/test/mjsunit/compiler/inline-construct.js index af9e69c940..7a3f1e44bd 100644 --- a/deps/v8/test/mjsunit/compiler/inline-construct.js +++ b/deps/v8/test/mjsunit/compiler/inline-construct.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --allow-natives-syntax --expose-gc --inline-construct +// Flags: --allow-natives-syntax --inline-construct // Test inlining of constructor calls. @@ -68,7 +68,9 @@ function TestInAllContexts(constructor) { %DeoptimizeFunction(value_context); %DeoptimizeFunction(test_context); %DeoptimizeFunction(effect_context); - gc(); // Makes V8 forget about type information for *_context. + %ClearFunctionTypeFeedback(value_context); + %ClearFunctionTypeFeedback(test_context); + %ClearFunctionTypeFeedback(effect_context); } diff --git a/deps/v8/test/mjsunit/compiler/literals.js b/deps/v8/test/mjsunit/compiler/literals.js index e910bb3c6a..8607cd9595 100644 --- a/deps/v8/test/mjsunit/compiler/literals.js +++ b/deps/v8/test/mjsunit/compiler/literals.js @@ -36,38 +36,38 @@ assertEquals(8, eval("6;'abc';8")); // Characters just outside the ranges of hex-escapes. // "/" comes just before "0". -assertEquals("x1/", "\x1/"); -assertEquals("u111/", "\u111/"); +assertThrows('"\\x1/"'); +assertThrows('"\\u111/"'); assertEquals("\\x1/", RegExp("\\x1/").source); assertEquals("\\u111/", RegExp("\\u111/").source); // ":" comes just after "9". -assertEquals("x1:", "\x1:"); -assertEquals("u111:", "\u111:"); +assertThrows('"\\x1:"'); +assertThrows('"\\u111:"'); assertEquals("\\x1:", /\x1:/.source); assertEquals("\\u111:", /\u111:/.source); // "`" comes just before "a". -assertEquals("x1`", "\x1`"); -assertEquals("u111`", "\u111`"); +assertThrows('"\\x1`"'); +assertThrows('"\\u111`"'); assertEquals("\\x1`", /\x1`/.source); assertEquals("\\u111`", /\u111`/.source); // "g" comes just before "f". -assertEquals("x1g", "\x1g"); -assertEquals("u111g", "\u111g"); +assertThrows('"\\x1g"'); +assertThrows('"\\u111g"'); assertEquals("\\x1g", /\x1g/.source); assertEquals("\\u111g", /\u111g/.source); // "@" comes just before "A". -assertEquals("x1@", "\x1@"); -assertEquals("u111@", "\u111@"); +assertThrows('"\\x1@"'); +assertThrows('"\\u111@"'); assertEquals("\\x1@", /\x1@/.source); assertEquals("\\u111@", /\u111@/.source); // "G" comes just after "F". -assertEquals("x1G", "\x1G"); -assertEquals("u111G", "\u111G"); +assertThrows('"\\x1G"'); +assertThrows('"\\u111G"'); assertEquals("\\x1G", /\x1G/.source); assertEquals("\\u111G", /\u111G/.source); diff --git a/deps/v8/test/mjsunit/compiler/optimize-bitnot.js b/deps/v8/test/mjsunit/compiler/optimize-bitnot.js new file mode 100644 index 0000000000..28315a4fe2 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/optimize-bitnot.js @@ -0,0 +1,42 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax + +function f(x) { + return ~~x; +} + +f(42); +f(42); +%OptimizeFunctionOnNextCall(f); +assertEquals(42, f(42)); +assertEquals(42, f(42.5)); +assertEquals(1/0, 1/f(-0)); +assertEquals(-1, f(0xffffffff)); +assertEquals(0, f(undefined)); +assertEquals(0, f("abc")); diff --git a/deps/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js b/deps/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js index cf25c0c095..efbb2cc8ca 100644 --- a/deps/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js +++ b/deps/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js @@ -148,20 +148,9 @@ function listener(event, exec_state, event_data, data) { assertFalse(frame.isConstructCall()); } - // When function f is optimized (1 means YES, see runtime.cc) we - // expect an optimized frame for f with g1, g2 and g3 inlined. - if (%GetOptimizationStatus(f) == 1) { - if (i == 1 || i == 2 || i == 3) { - assertTrue(frame.isOptimizedFrame()); - assertTrue(frame.isInlinedFrame()); - assertEquals(4 - i, frame.inlinedFrameIndex()); - } else if (i == 4) { - assertTrue(frame.isOptimizedFrame()); - assertFalse(frame.isInlinedFrame()); - } else { - assertFalse(frame.isOptimizedFrame()); - assertFalse(frame.isInlinedFrame()); - } + if (i > 4) { + assertFalse(frame.isOptimizedFrame()); + assertFalse(frame.isInlinedFrame()); } } diff --git a/deps/v8/test/mjsunit/debug-evaluate-locals-optimized.js b/deps/v8/test/mjsunit/debug-evaluate-locals-optimized.js index c88a683a8c..9c56a12be2 100644 --- a/deps/v8/test/mjsunit/debug-evaluate-locals-optimized.js +++ b/deps/v8/test/mjsunit/debug-evaluate-locals-optimized.js @@ -138,20 +138,9 @@ function listener(event, exec_state, event_data, data) { assertFalse(frame.isConstructCall()); } - // When function f is optimized (1 means YES, see runtime.cc) we - // expect an optimized frame for f with g1, g2 and g3 inlined. - if (%GetOptimizationStatus(f) == 1) { - if (i == 1 || i == 2 || i == 3) { - assertTrue(frame.isOptimizedFrame()); - assertTrue(frame.isInlinedFrame()); - assertEquals(4 - i, frame.inlinedFrameIndex()); - } else if (i == 4) { - assertTrue(frame.isOptimizedFrame()); - assertFalse(frame.isInlinedFrame()); - } else { - assertFalse(frame.isOptimizedFrame()); - assertFalse(frame.isInlinedFrame()); - } + if (i > 4) { + assertFalse(frame.isOptimizedFrame()); + assertFalse(frame.isInlinedFrame()); } } diff --git a/deps/v8/test/mjsunit/debug-function-scopes.js b/deps/v8/test/mjsunit/debug-function-scopes.js new file mode 100644 index 0000000000..4262b950da --- /dev/null +++ b/deps/v8/test/mjsunit/debug-function-scopes.js @@ -0,0 +1,162 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --expose-debug-as debug + +// Get the Debug object exposed from the debug context global object. +var Debug = debug.Debug; + +function CheckScope(scope_mirror, scope_expectations, expected_scope_type) { + assertEquals(expected_scope_type, scope_mirror.scopeType()); + + var scope_object = scope_mirror.scopeObject().value(); + + for (var name in scope_expectations) { + var actual = scope_object[name]; + var expected = scope_expectations[name]; + assertEquals(expected, actual); + } +} + +// A copy of the scope types from mirror-debugger.js. +var ScopeType = { Global: 0, + Local: 1, + With: 2, + Closure: 3, + Catch: 4, + Block: 5 }; + +var f1 = (function F1(x) { + function F2(y) { + var z = x + y; + with ({w: 5, v: "Capybara"}) { + var F3 = function(a, b) { + function F4(p) { + return p + a + b + z + w + v.length; + } + return F4; + } + return F3(4, 5); + } + } + return F2(17); +})(5); + +var mirror = Debug.MakeMirror(f1); + +assertEquals(5, mirror.scopeCount()); + +CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure); +CheckScope(mirror.scope(1), { w: 5, v: "Capybara" }, ScopeType.With); +CheckScope(mirror.scope(2), { y: 17, z: 22 }, ScopeType.Closure); +CheckScope(mirror.scope(3), { x: 5 }, ScopeType.Closure); +CheckScope(mirror.scope(4), {}, ScopeType.Global); + +var f2 = function() { return 5; } + +var mirror = Debug.MakeMirror(f2); + +assertEquals(1, mirror.scopeCount()); + +CheckScope(mirror.scope(0), {}, ScopeType.Global); + +var f3 = (function F1(invisible_parameter) { + var invisible1 = 1; + var visible1 = 10; + return (function F2() { + var invisible2 = 2; + return (function F3() { + var visible2 = 20; + var invisible2 = 3; + return (function () {return visible1 + visible2 + visible1a;}); + })(); + })(); +})(5); + +var mirror = Debug.MakeMirror(f3); + +assertEquals(3, mirror.scopeCount()); + +CheckScope(mirror.scope(0), { visible2: 20 }, ScopeType.Closure); +CheckScope(mirror.scope(1), { visible1: 10 }, ScopeType.Closure); +CheckScope(mirror.scope(2), {}, ScopeType.Global); + + +var f4 = (function One() { + try { + throw "I'm error 1"; + } catch (e1) { + try { + throw "I'm error 2"; + } catch (e2) { + return function GetError() { + return e1 + e2; + }; + } + } +})(); + +var mirror = Debug.MakeMirror(f4); + +assertEquals(3, mirror.scopeCount()); + +CheckScope(mirror.scope(0), { e2: "I'm error 2" }, ScopeType.Catch); +CheckScope(mirror.scope(1), { e1: "I'm error 1" }, ScopeType.Catch); +CheckScope(mirror.scope(2), {}, ScopeType.Global); + + +var f5 = (function Raz(p1, p2) { + var p3 = p1 + p2; + return (function() { + var p4 = 20; + var p5 = 21; + var p6 = 22; + return eval("(function(p7){return p1 + p4 + p6 + p7})"); + })(); +})(1,2); + +var mirror = Debug.MakeMirror(f5); + +assertEquals(3, mirror.scopeCount()); + +CheckScope(mirror.scope(0), { p4: 20, p6: 22 }, ScopeType.Closure); +CheckScope(mirror.scope(1), { p1: 1 }, ScopeType.Closure); +CheckScope(mirror.scope(2), {}, ScopeType.Global); + + +function CheckNoScopeVisible(f) { + var mirror = Debug.MakeMirror(f); + assertEquals(0, mirror.scopeCount()); +} + +CheckNoScopeVisible(Number); + +CheckNoScopeVisible(Function.toString); + +// This getter is known to be implemented as closure. +CheckNoScopeVisible(new Error().__lookupGetter__("stack")); + diff --git a/deps/v8/test/mjsunit/debug-liveedit-stack-padding.js b/deps/v8/test/mjsunit/debug-liveedit-stack-padding.js new file mode 100644 index 0000000000..36de356973 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-liveedit-stack-padding.js @@ -0,0 +1,88 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --expose-debug-as debug +// Get the Debug object exposed from the debug context global object. + +Debug = debug.Debug; + +SlimFunction = eval( + "(function() {\n " + + " return 'Cat';\n" + + "})\n" +); + +var script = Debug.findScript(SlimFunction); + +Debug.setScriptBreakPointById(script.id, 1, 0); + +var orig_animal = "'Cat'"; +var patch_pos = script.source.indexOf(orig_animal); +var new_animal_patch = "'Capybara'"; + +debugger_handler = (function() { + var already_called = false; + return function() { + if (already_called) { + return; + } + already_called = true; + + var change_log = new Array(); + try { + Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, + orig_animal.length, new_animal_patch, change_log); + } finally { + print("Change log: " + JSON.stringify(change_log) + "\n"); + } + }; +})(); + +var saved_exception = null; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + try { + debugger_handler(); + } catch (e) { + saved_exception = e; + } + } else { + print("Other: " + event); + } +} + +Debug.setListener(listener); + +var animal = SlimFunction(); + +if (saved_exception) { + print("Exception: " + saved_exception); + assertUnreachable(); +} + +assertEquals("Capybara", animal); diff --git a/deps/v8/test/mjsunit/debug-scripts-request.js b/deps/v8/test/mjsunit/debug-scripts-request.js index faa732e141..e027563b9b 100644 --- a/deps/v8/test/mjsunit/debug-scripts-request.js +++ b/deps/v8/test/mjsunit/debug-scripts-request.js @@ -78,8 +78,10 @@ function listener(event, exec_state, event_data, data) { var response = safeEval(dcp.processDebugJSONRequest(request)); assertTrue(response.success); - // Test filtering by id. - assertEquals(2, response.body.length); + // Test filtering by id. We have to get at least one script back, but + // the exact number depends on the timing of GC. + assertTrue(response.body.length >= 1); + var script = response.body[0]; var request = '{' + base_request + ',"arguments":{"ids":[' + script.id + ']}}'; diff --git a/deps/v8/test/mjsunit/debug-stepin-builtin-callback.js b/deps/v8/test/mjsunit/debug-stepin-builtin-callback.js new file mode 100644 index 0000000000..223159d4f5 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-stepin-builtin-callback.js @@ -0,0 +1,157 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --expose-debug-as debug + +// Test stepping into callbacks passed to builtin functions. + +Debug = debug.Debug + +var exception = false; + +function array_listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + if (breaks == 0) { + exec_state.prepareStep(Debug.StepAction.StepIn, 2); + breaks = 1; + } else if (breaks <= 3) { + breaks++; + // Check whether we break at the expected line. + print(event_data.sourceLineText()); + assertTrue(event_data.sourceLineText().indexOf("Expected to step") > 0); + exec_state.prepareStep(Debug.StepAction.StepIn, 3); + } + } + } catch (e) { + exception = true; + } +}; + +function cb_false(num) { + print("element " + num); // Expected to step to this point. + return false; +} + +function cb_true(num) { + print("element " + num); // Expected to step to this point. + return true; +} + +function cb_reduce(a, b) { + print("elements " + a + " and " + b); // Expected to step to this point. + return a + b; +} + +var a = [1, 2, 3, 4]; + +Debug.setListener(array_listener); + +var breaks = 0; +debugger; +a.forEach(cb_true); +assertFalse(exception); +assertEquals(4, breaks); + +breaks = 0; +debugger; +a.some(cb_false); +assertFalse(exception); +assertEquals(4, breaks); + +breaks = 0; +debugger; +a.every(cb_true); +assertEquals(4, breaks); +assertFalse(exception); + +breaks = 0; +debugger; +a.map(cb_true); +assertFalse(exception); +assertEquals(4, breaks); + +breaks = 0; +debugger; +a.filter(cb_true); +assertFalse(exception); +assertEquals(4, breaks); + +breaks = 0; +debugger; +a.reduce(cb_reduce); +assertFalse(exception); +assertEquals(4, breaks); + +breaks = 0; +debugger; +a.reduceRight(cb_reduce); +assertFalse(exception); +assertEquals(4, breaks); + +Debug.setListener(null); + + +// Test two levels of builtin callbacks: +// Array.forEach calls a callback function, which by itself uses +// Array.forEach with another callback function. + +function second_level_listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + if (breaks == 0) { + exec_state.prepareStep(Debug.StepAction.StepIn, 3); + breaks = 1; + } else if (breaks <= 16) { + breaks++; + // Check whether we break at the expected line. + assertTrue(event_data.sourceLineText().indexOf("Expected to step") > 0); + // Step two steps further every four breaks to skip the + // forEach call in the first level of recurision. + var step = (breaks % 4 == 1) ? 6 : 3; + exec_state.prepareStep(Debug.StepAction.StepIn, step); + } + } + } catch (e) { + exception = true; + } +}; + +function cb_foreach(num) { + a.forEach(cb_true); + print("back to the first level of recursion."); +} + +Debug.setListener(second_level_listener); + +breaks = 0; +debugger; +a.forEach(cb_foreach); +assertFalse(exception); +assertEquals(17, breaks); + +Debug.setListener(null); diff --git a/deps/v8/test/mjsunit/declare-locally.js b/deps/v8/test/mjsunit/declare-locally.js index 93fcb85f3c..20bfe6da1f 100644 --- a/deps/v8/test/mjsunit/declare-locally.js +++ b/deps/v8/test/mjsunit/declare-locally.js @@ -33,11 +33,13 @@ // This exercises the code in runtime.cc in // DeclareGlobal...Locally(). +// Flags: --es52_globals + this.__proto__.foo = 42; this.__proto__.bar = 87; -eval("assertEquals(42, foo); var foo = 87;"); +eval("assertEquals(undefined, foo); var foo = 87;"); assertEquals(87, foo); -eval("assertEquals(87, bar); const bar = 42;"); +eval("assertEquals(undefined, bar); const bar = 42;"); assertEquals(42, bar); diff --git a/deps/v8/test/mjsunit/error-constructors.js b/deps/v8/test/mjsunit/error-constructors.js index 966a1629d7..107164df56 100644 --- a/deps/v8/test/mjsunit/error-constructors.js +++ b/deps/v8/test/mjsunit/error-constructors.js @@ -25,39 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -var e = new Error(); -assertFalse(e.hasOwnProperty('message')); -Error.prototype.toString = Object.prototype.toString; -assertEquals("[object Error]", Error.prototype.toString()); -assertEquals(Object.prototype, Error.prototype.__proto__); - -// Check that error construction does not call setters for the -// properties on error objects in prototypes. -function fail() { assertTrue(false); }; -ReferenceError.prototype.__defineSetter__('stack', fail); -ReferenceError.prototype.__defineSetter__('message', fail); -ReferenceError.prototype.__defineSetter__('type', fail); -ReferenceError.prototype.__defineSetter__('arguments', fail); -var e0 = new ReferenceError(); -var e1 = new ReferenceError('123'); -assertTrue(e1.hasOwnProperty('message')); -assertTrue(e0.hasOwnProperty('stack')); -assertTrue(e1.hasOwnProperty('stack')); -assertTrue(e0.hasOwnProperty('type')); -assertTrue(e1.hasOwnProperty('type')); -assertTrue(e0.hasOwnProperty('arguments')); -assertTrue(e1.hasOwnProperty('arguments')); - -// Check that the name property on error prototypes is read-only and -// dont-delete. This is not specified, but allowing overwriting the -// name property with a getter can leaks error objects from different -// script tags in the same context in a browser setting. We therefore -// disallow changes to the name property on error objects. -assertEquals("ReferenceError", ReferenceError.prototype.name); -delete ReferenceError.prototype.name; -assertEquals("ReferenceError", ReferenceError.prototype.name); -ReferenceError.prototype.name = "not a reference error"; -assertEquals("ReferenceError", ReferenceError.prototype.name); +// Flags: --allow-natives-syntax // Check that message and name are not enumerable on Error objects. var desc = Object.getOwnPropertyDescriptor(Error.prototype, 'name'); @@ -75,8 +43,75 @@ assertFalse(desc['enumerable']); desc = Object.getOwnPropertyDescriptor(e, 'stack'); assertFalse(desc['enumerable']); +var e = new Error(); +assertFalse(e.hasOwnProperty('message')); + // name is not tested above, but in addition we should have no enumerable // properties, so we simply assert that. for (var v in e) { assertUnreachable(); } + +// Check that error construction does not call setters for the +// properties on error objects in prototypes. +function fail() { assertUnreachable(); }; +ReferenceError.prototype.__defineSetter__('name', fail); +ReferenceError.prototype.__defineSetter__('message', fail); +ReferenceError.prototype.__defineSetter__('type', fail); +ReferenceError.prototype.__defineSetter__('arguments', fail); +ReferenceError.prototype.__defineSetter__('stack', fail); + +var e = new ReferenceError(); +assertTrue(e.hasOwnProperty('stack')); +assertTrue(e.hasOwnProperty('type')); +assertTrue(e.hasOwnProperty('arguments')); + +var e = new ReferenceError('123'); +assertTrue(e.hasOwnProperty('message')); +assertTrue(e.hasOwnProperty('stack')); +assertTrue(e.hasOwnProperty('type')); +assertTrue(e.hasOwnProperty('arguments')); + +var e = %MakeReferenceError("my_test_error", [0, 1]); +assertTrue(e.hasOwnProperty('stack')); +assertTrue(e.hasOwnProperty('type')); +assertTrue(e.hasOwnProperty('arguments')); +assertEquals("my_test_error", e.type) + +// Check that intercepting property access from toString is prevented for +// compiler errors. This is not specified, but allowing interception +// through a getter can leak error objects from different +// script tags in the same context in a browser setting. +var errors = [SyntaxError, ReferenceError, TypeError]; +for (var i in errors) { + var name = errors[i].prototype.toString(); + // Monkey-patch prototype. + var props = ["name", "message", "type", "arguments", "stack"]; + for (var j in props) { + errors[i].prototype.__defineGetter__(props[j], fail); + } + // String conversion should not invoke monkey-patched getters on prototype. + var e = new errors[i]; + assertEquals(name, e.toString()); + // Custom getters in actual objects are welcome. + e.__defineGetter__("name", function() { return "mine"; }); + assertEquals("mine", e.toString()); +} + +// Monkey-patching non-static errors should still be observable. +function MyError() {} +MyError.prototype = new Error; +var errors = [Error, RangeError, EvalError, URIError, MyError]; +for (var i in errors) { + errors[i].prototype.__defineGetter__("name", function() { return "my"; }); + errors[i].prototype.__defineGetter__("message", function() { return "moo"; }); + var e = new errors[i]; + assertEquals("my: moo", e.toString()); +} + + +Error.prototype.toString = Object.prototype.toString; +assertEquals("[object Error]", Error.prototype.toString()); +assertEquals(Object.prototype, Error.prototype.__proto__); +var e = new Error("foo"); +assertEquals("[object Error]", e.toString()); diff --git a/deps/v8/test/mjsunit/harmony/debug-function-scopes.js b/deps/v8/test/mjsunit/harmony/debug-function-scopes.js new file mode 100644 index 0000000000..0113be672b --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/debug-function-scopes.js @@ -0,0 +1,115 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --expose-debug-as debug --harmony-scoping + +"use strict"; + +// Get the Debug object exposed from the debug context global object. +var Debug = debug.Debug; + +function CheckScope(scope_mirror, scope_expectations, expected_scope_type) { + assertEquals(expected_scope_type, scope_mirror.scopeType()); + + var scope_object = scope_mirror.scopeObject().value(); + + for (let name in scope_expectations) { + let actual = scope_object[name]; + let expected = scope_expectations[name]; + assertEquals(expected, actual); + } +} + +// A copy of the scope types from mirror-debugger.js. +var ScopeType = { Global: 0, + Local: 1, + With: 2, + Closure: 3, + Catch: 4, + Block: 5 }; + +var f1 = (function F1(x) { + function F2(y) { + var z = x + y; + { + var w = 5; + var v = "Capybara"; + var F3 = function(a, b) { + function F4(p) { + return p + a + b + z + w + v.length; + } + return F4; + } + return F3(4, 5); + } + } + return F2(17); +})(5); + +var mirror = Debug.MakeMirror(f1); + +assertEquals(4, mirror.scopeCount()); + +CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure); +CheckScope(mirror.scope(1), { z: 22, w: 5, v: "Capybara" }, ScopeType.Closure); +CheckScope(mirror.scope(2), { x: 5 }, ScopeType.Closure); +CheckScope(mirror.scope(3), {}, ScopeType.Global); + +var f2 = (function() { + var v1 = 3; + var v2 = 4; + let l0 = 0; + { + var v3 = 5; + let l1 = 6; + let l2 = 7; + { + var v4 = 8; + let l3 = 9; + { + var v5 = "Cat"; + let l4 = 11; + var v6 = l4; + return function() { + return l0 + v1 + v3 + l2 + l3 + v6; + }; + } + } + } +})(); + +var mirror = Debug.MakeMirror(f2); + +assertEquals(5, mirror.scopeCount()); + +// Implementation artifact: l4 isn't used in closure, but still it is saved. +CheckScope(mirror.scope(0), { l4: 11 }, ScopeType.Block); + +CheckScope(mirror.scope(1), { l3: 9 }, ScopeType.Block); +CheckScope(mirror.scope(2), { l1: 6, l2: 7 }, ScopeType.Block); +CheckScope(mirror.scope(3), { v1:3, l0: 0, v3: 5, v6: 11 }, ScopeType.Closure); +CheckScope(mirror.scope(4), {}, ScopeType.Global); diff --git a/deps/v8/test/mjsunit/harmony/module-linking.js b/deps/v8/test/mjsunit/harmony/module-linking.js new file mode 100644 index 0000000000..13ca6f782f --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/module-linking.js @@ -0,0 +1,121 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --harmony-modules --harmony-scoping + +// Test basic module linking. + +"use strict"; + +let log = ""; + +export let x = (log += "1"); + +export module B = A.B + +export module A { + export let x = (log += "2"); + let y = (log += "3"); + export function f() { log += "5" }; + export module B { + module BB = B; + export BB, x; + let x = (log += "4"); + f(); + let y = (log += "6"); + } + export let z = (log += "7"); + export module C { + export let z = (log += "8"); + export module D = B + export module C = A.C + } + module D {} +} + +export module M1 { + export module A2 = M2; + export let x = (log += "9"); +} +export module M2 { + export module A1 = M1; + export let x = (log += "0"); +} + +assertEquals("object", typeof A); +assertTrue('x' in A); +assertFalse('y' in A); +assertTrue('f' in A); +assertTrue('B' in A); +assertTrue('z' in A); +assertTrue('C' in A); +assertFalse('D' in A); + +assertEquals("object", typeof B); +assertTrue('BB' in B); +assertTrue('x' in B); +assertFalse('y' in B); + +assertEquals("object", typeof A.B); +assertTrue('BB' in A.B); +assertTrue('x' in A.B); +assertFalse('y' in A.B); + +assertEquals("object", typeof A.B.BB); +assertTrue('BB' in A.B.BB); +assertTrue('x' in A.B.BB); +assertFalse('y' in A.B.BB); + +assertEquals("object", typeof A.C); +assertTrue('z' in A.C); +assertTrue('D' in A.C); +assertTrue('C' in A.C); + +assertEquals("object", typeof M1); +assertEquals("object", typeof M2); +assertTrue('A2' in M1); +assertTrue('A1' in M2); +assertEquals("object", typeof M1.A2); +assertEquals("object", typeof M2.A1); +assertTrue('A1' in M1.A2); +assertTrue('A2' in M2.A1); +assertEquals("object", typeof M1.A2.A1); +assertEquals("object", typeof M2.A1.A2); + +assertSame(B, A.B); +assertSame(B, B.BB); +assertSame(B, A.C.D); +assertSame(A.C, A.C.C); +assertFalse(A.D === A.C.D); + +assertSame(M1, M2.A1); +assertSame(M2, M1.A2); +assertSame(M1, M1.A2.A1); +assertSame(M2, M2.A1.A2); + +// TODO(rossberg): inner declarations are not executed yet. +// assertEquals("1234567890", log); diff --git a/deps/v8/test/mjsunit/harmony/module-parsing.js b/deps/v8/test/mjsunit/harmony/module-parsing.js index 93e69e3ad9..cdd0a2e00d 100644 --- a/deps/v8/test/mjsunit/harmony/module-parsing.js +++ b/deps/v8/test/mjsunit/harmony/module-parsing.js @@ -70,7 +70,7 @@ module B { import i0 from I import i1, i2, i3, M from I - import i4, i5 from "http://where" + //import i4, i5 from "http://where" } module I { @@ -85,7 +85,7 @@ module D3 = D2 module E1 at "http://where" module E2 at "http://where"; -module E3 = E1.F +module E3 = E1 // Check that ASI does not interfere. @@ -103,11 +103,11 @@ at "file://local" import -x +vx , -y +vy from -"file://local" +B module Wrap { diff --git a/deps/v8/test/mjsunit/harmony/module-resolution.js b/deps/v8/test/mjsunit/harmony/module-resolution.js index f9f492cffc..a1b991749c 100644 --- a/deps/v8/test/mjsunit/harmony/module-resolution.js +++ b/deps/v8/test/mjsunit/harmony/module-resolution.js @@ -129,7 +129,7 @@ export module M2 { export module External at "external.js" export module External1 = External -export module ExternalA = External.A +//export module ExternalA = External.A export module InnerExternal { export module E at "external.js" } diff --git a/deps/v8/test/mjsunit/math-floor-of-div.js b/deps/v8/test/mjsunit/math-floor-of-div.js new file mode 100644 index 0000000000..e917182c71 --- /dev/null +++ b/deps/v8/test/mjsunit/math-floor-of-div.js @@ -0,0 +1,216 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax --nouse_inlining + +// Use this function as reference. Make sure it is not inlined. +function div(a, b) { + return a / b; +} + +var limit = 0x1000000; +var exhaustive_limit = 100; +var step = 10; +var values = [0x10000001, + 0x12345678, + -0x789abcdf, // 0x87654321 + 0x01234567, + 0x76543210, + -0x80000000, // 0x80000000 + 0x7fffffff, + -0x0fffffff, // 0xf0000001 + 0x00000010, + -0x01000000 // 0xff000000 + ]; + +function test_div() { + var c = 0; + for (var k = 0; k <= limit; k++) { + if (k > exhaustive_limit) { c += step; k += c; } + assertEquals(Math.floor(div(k, 1)), Math.floor(k / 1)); + assertEquals(Math.floor(div(k, -1)), Math.floor(k / -1)); + assertEquals(Math.floor(div(k, 2)), Math.floor(k / 2)); + assertEquals(Math.floor(div(k, -2)), Math.floor(k / -2)); + assertEquals(Math.floor(div(k, 3)), Math.floor(k / 3)); + assertEquals(Math.floor(div(k, -3)), Math.floor(k / -3)); + assertEquals(Math.floor(div(k, 4)), Math.floor(k / 4)); + assertEquals(Math.floor(div(k, -4)), Math.floor(k / -4)); + assertEquals(Math.floor(div(k, 5)), Math.floor(k / 5)); + assertEquals(Math.floor(div(k, -5)), Math.floor(k / -5)); + assertEquals(Math.floor(div(k, 6)), Math.floor(k / 6)); + assertEquals(Math.floor(div(k, -6)), Math.floor(k / -6)); + assertEquals(Math.floor(div(k, 7)), Math.floor(k / 7)); + assertEquals(Math.floor(div(k, -7)), Math.floor(k / -7)); + assertEquals(Math.floor(div(k, 8)), Math.floor(k / 8)); + assertEquals(Math.floor(div(k, -8)), Math.floor(k / -8)); + assertEquals(Math.floor(div(k, 9)), Math.floor(k / 9)); + assertEquals(Math.floor(div(k, -9)), Math.floor(k / -9)); + assertEquals(Math.floor(div(k, 10)), Math.floor(k / 10)); + assertEquals(Math.floor(div(k, -10)), Math.floor(k / -10)); + assertEquals(Math.floor(div(k, 11)), Math.floor(k / 11)); + assertEquals(Math.floor(div(k, -11)), Math.floor(k / -11)); + assertEquals(Math.floor(div(k, 12)), Math.floor(k / 12)); + assertEquals(Math.floor(div(k, -12)), Math.floor(k / -12)); + assertEquals(Math.floor(div(k, 13)), Math.floor(k / 13)); + assertEquals(Math.floor(div(k, -13)), Math.floor(k / -13)); + assertEquals(Math.floor(div(k, 14)), Math.floor(k / 14)); + assertEquals(Math.floor(div(k, -14)), Math.floor(k / -14)); + assertEquals(Math.floor(div(k, 15)), Math.floor(k / 15)); + assertEquals(Math.floor(div(k, -15)), Math.floor(k / -15)); + assertEquals(Math.floor(div(k, 16)), Math.floor(k / 16)); + assertEquals(Math.floor(div(k, -16)), Math.floor(k / -16)); + assertEquals(Math.floor(div(k, 17)), Math.floor(k / 17)); + assertEquals(Math.floor(div(k, -17)), Math.floor(k / -17)); + assertEquals(Math.floor(div(k, 18)), Math.floor(k / 18)); + assertEquals(Math.floor(div(k, -18)), Math.floor(k / -18)); + assertEquals(Math.floor(div(k, 19)), Math.floor(k / 19)); + assertEquals(Math.floor(div(k, -19)), Math.floor(k / -19)); + assertEquals(Math.floor(div(k, 20)), Math.floor(k / 20)); + assertEquals(Math.floor(div(k, -20)), Math.floor(k / -20)); + assertEquals(Math.floor(div(k, 21)), Math.floor(k / 21)); + assertEquals(Math.floor(div(k, -21)), Math.floor(k / -21)); + assertEquals(Math.floor(div(k, 22)), Math.floor(k / 22)); + assertEquals(Math.floor(div(k, -22)), Math.floor(k / -22)); + assertEquals(Math.floor(div(k, 23)), Math.floor(k / 23)); + assertEquals(Math.floor(div(k, -23)), Math.floor(k / -23)); + assertEquals(Math.floor(div(k, 24)), Math.floor(k / 24)); + assertEquals(Math.floor(div(k, -24)), Math.floor(k / -24)); + assertEquals(Math.floor(div(k, 25)), Math.floor(k / 25)); + assertEquals(Math.floor(div(k, -25)), Math.floor(k / -25)); + assertEquals(Math.floor(div(k, 125)), Math.floor(k / 125)); + assertEquals(Math.floor(div(k, -125)), Math.floor(k / -125)); + assertEquals(Math.floor(div(k, 625)), Math.floor(k / 625)); + assertEquals(Math.floor(div(k, -625)), Math.floor(k / -625)); + } + c = 0; + for (var k = 0; k <= limit; k++) { + if (k > exhaustive_limit) { c += step; k += c; } + assertEquals(Math.floor(div(-k, 1)), Math.floor(-k / 1)); + assertEquals(Math.floor(div(-k, -1)), Math.floor(-k / -1)); + assertEquals(Math.floor(div(-k, 2)), Math.floor(-k / 2)); + assertEquals(Math.floor(div(-k, -2)), Math.floor(-k / -2)); + assertEquals(Math.floor(div(-k, 3)), Math.floor(-k / 3)); + assertEquals(Math.floor(div(-k, -3)), Math.floor(-k / -3)); + assertEquals(Math.floor(div(-k, 4)), Math.floor(-k / 4)); + assertEquals(Math.floor(div(-k, -4)), Math.floor(-k / -4)); + assertEquals(Math.floor(div(-k, 5)), Math.floor(-k / 5)); + assertEquals(Math.floor(div(-k, -5)), Math.floor(-k / -5)); + assertEquals(Math.floor(div(-k, 6)), Math.floor(-k / 6)); + assertEquals(Math.floor(div(-k, -6)), Math.floor(-k / -6)); + assertEquals(Math.floor(div(-k, 7)), Math.floor(-k / 7)); + assertEquals(Math.floor(div(-k, -7)), Math.floor(-k / -7)); + assertEquals(Math.floor(div(-k, 8)), Math.floor(-k / 8)); + assertEquals(Math.floor(div(-k, -8)), Math.floor(-k / -8)); + assertEquals(Math.floor(div(-k, 9)), Math.floor(-k / 9)); + assertEquals(Math.floor(div(-k, -9)), Math.floor(-k / -9)); + assertEquals(Math.floor(div(-k, 10)), Math.floor(-k / 10)); + assertEquals(Math.floor(div(-k, -10)), Math.floor(-k / -10)); + assertEquals(Math.floor(div(-k, 11)), Math.floor(-k / 11)); + assertEquals(Math.floor(div(-k, -11)), Math.floor(-k / -11)); + assertEquals(Math.floor(div(-k, 12)), Math.floor(-k / 12)); + assertEquals(Math.floor(div(-k, -12)), Math.floor(-k / -12)); + assertEquals(Math.floor(div(-k, 13)), Math.floor(-k / 13)); + assertEquals(Math.floor(div(-k, -13)), Math.floor(-k / -13)); + assertEquals(Math.floor(div(-k, 14)), Math.floor(-k / 14)); + assertEquals(Math.floor(div(-k, -14)), Math.floor(-k / -14)); + assertEquals(Math.floor(div(-k, 15)), Math.floor(-k / 15)); + assertEquals(Math.floor(div(-k, -15)), Math.floor(-k / -15)); + assertEquals(Math.floor(div(-k, 16)), Math.floor(-k / 16)); + assertEquals(Math.floor(div(-k, -16)), Math.floor(-k / -16)); + assertEquals(Math.floor(div(-k, 17)), Math.floor(-k / 17)); + assertEquals(Math.floor(div(-k, -17)), Math.floor(-k / -17)); + assertEquals(Math.floor(div(-k, 18)), Math.floor(-k / 18)); + assertEquals(Math.floor(div(-k, -18)), Math.floor(-k / -18)); + assertEquals(Math.floor(div(-k, 19)), Math.floor(-k / 19)); + assertEquals(Math.floor(div(-k, -19)), Math.floor(-k / -19)); + assertEquals(Math.floor(div(-k, 20)), Math.floor(-k / 20)); + assertEquals(Math.floor(div(-k, -20)), Math.floor(-k / -20)); + assertEquals(Math.floor(div(-k, 21)), Math.floor(-k / 21)); + assertEquals(Math.floor(div(-k, -21)), Math.floor(-k / -21)); + assertEquals(Math.floor(div(-k, 22)), Math.floor(-k / 22)); + assertEquals(Math.floor(div(-k, -22)), Math.floor(-k / -22)); + assertEquals(Math.floor(div(-k, 23)), Math.floor(-k / 23)); + assertEquals(Math.floor(div(-k, -23)), Math.floor(-k / -23)); + assertEquals(Math.floor(div(-k, 24)), Math.floor(-k / 24)); + assertEquals(Math.floor(div(-k, -24)), Math.floor(-k / -24)); + assertEquals(Math.floor(div(-k, 25)), Math.floor(-k / 25)); + assertEquals(Math.floor(div(-k, -25)), Math.floor(-k / -25)); + assertEquals(Math.floor(div(-k, 125)), Math.floor(-k / 125)); + assertEquals(Math.floor(div(-k, -125)), Math.floor(-k / -125)); + assertEquals(Math.floor(div(-k, 625)), Math.floor(-k / 625)); + assertEquals(Math.floor(div(-k, -625)), Math.floor(-k / -625)); + } + // Test for edge cases. + // Use (values[key] | 0) to force the integer type. + for (var i = 0; i < values.length; i++) { + for (var j = 0; j < values.length; j++) { + assertEquals(Math.floor(div((values[i] | 0), (values[j] | 0))), + Math.floor((values[i] | 0) / (values[j] | 0))); + assertEquals(Math.floor(div(-(values[i] | 0), (values[j] | 0))), + Math.floor(-(values[i] | 0) / (values[j] | 0))); + assertEquals(Math.floor(div((values[i] | 0), -(values[j] | 0))), + Math.floor((values[i] | 0) / -(values[j] | 0))); + assertEquals(Math.floor(div(-(values[i] | 0), -(values[j] | 0))), + Math.floor(-(values[i] | 0) / -(values[j] | 0))); + } + } +} + +test_div(); +%OptimizeFunctionOnNextCall(test_div); +test_div(); + +// Test for negative zero and overflow. +// Separate the tests to prevent deoptimizations from making the other optimized +// test unreachable. + +function IsNegativeZero(x) { + assertTrue(x == 0); // Is 0 or -0. + var y = 1 / x; + assertFalse(isFinite(y)); + return y < 0; +} + +function test_div_deopt_minus_zero() { + var zero_in_array = [0]; + assertTrue(IsNegativeZero(Math.floor((zero_in_array[0] | 0) / -1))); +} + +function test_div_deopt_overflow() { + // We box the value in an array to avoid constant propagation. + var min_int_in_array = [-2147483648]; + // We use '| 0' to force the representation to int32. + assertEquals(-min_int_in_array[0], + Math.floor((min_int_in_array[0] | 0) / -1)); +} + +test_div_deopt_minus_zero(); +test_div_deopt_overflow(); +%OptimizeFunctionOnNextCall(test_div_deopt_minus_zero); +%OptimizeFunctionOnNextCall(test_div_deopt_overflow); +test_div_deopt_minus_zero(); +test_div_deopt_overflow(); diff --git a/deps/v8/test/mjsunit/mjsunit.js b/deps/v8/test/mjsunit/mjsunit.js index 033c78f4b0..65fb301b44 100644 --- a/deps/v8/test/mjsunit/mjsunit.js +++ b/deps/v8/test/mjsunit/mjsunit.js @@ -75,7 +75,7 @@ var assertTrue; // Checks that the found value is false. var assertFalse; -// Checks that the found value is null. Kept for historical compatability, +// Checks that the found value is null. Kept for historical compatibility, // please just use assertEquals(null, expected). var assertNull; diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index a1b927097a..ab5f2e3e76 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -64,6 +64,7 @@ regress/regress-524: (PASS || TIMEOUT), SKIP if $mode == debug # Stack manipulations in LiveEdit are buggy - see bug 915 debug-liveedit-check-stack: SKIP debug-liveedit-patch-positions-replace: SKIP +debug-liveedit-stack-padding: SKIP # Test Crankshaft compilation time. Expected to take too long in debug mode. regress/regress-1969: PASS, SKIP if $mode == debug diff --git a/deps/v8/test/mjsunit/regexp-capture-3.js b/deps/v8/test/mjsunit/regexp-capture-3.js index 50e423ff30..9bdd600599 100644 --- a/deps/v8/test/mjsunit/regexp-capture-3.js +++ b/deps/v8/test/mjsunit/regexp-capture-3.js @@ -25,6 +25,194 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"abcd".replace(/b/g, function() { }); +function oneMatch(re) { + "abcd".replace(re, function() { }); + assertEquals("abcd", RegExp.input); + assertEquals("a", RegExp.leftContext); + assertEquals("b", RegExp.lastMatch); + assertEquals("", RegExp.lastParen); + assertEquals(undefined, RegExp.lastIndex); + assertEquals(undefined, RegExp.index); + assertEquals("cd", RegExp.rightContext); + for (var i = 1; i < 10; i++) { + assertEquals("", RegExp['$' + i]); + } +} +oneMatch(/b/); +oneMatch(/b/g); + +"abcdabcd".replace(/b/g, function() { }); +assertEquals("abcdabcd", RegExp.input); +assertEquals("abcda", RegExp.leftContext); +assertEquals("b", RegExp.lastMatch); +assertEquals("", RegExp.lastParen); +assertEquals(undefined, RegExp.lastIndex); +assertEquals(undefined, RegExp.index); assertEquals("cd", RegExp.rightContext); +for (var i = 1; i < 10; i++) { + assertEquals("", RegExp['$' + i]); +} + +function captureMatch(re) { + "abcd".replace(re, function() { }); + assertEquals("abcd", RegExp.input); + assertEquals("a", RegExp.leftContext); + assertEquals("bc", RegExp.lastMatch); + assertEquals("c", RegExp.lastParen); + assertEquals(undefined, RegExp.lastIndex); + assertEquals(undefined, RegExp.index); + assertEquals("d", RegExp.rightContext); + assertEquals('b', RegExp.$1); + assertEquals('c', RegExp.$2); + for (var i = 3; i < 10; i++) { + assertEquals("", RegExp['$' + i]); + } +} + +captureMatch(/(b)(c)/); +captureMatch(/(b)(c)/g); + +"abcdabcd".replace(/(b)(c)/g, function() { }); +assertEquals("abcdabcd", RegExp.input); +assertEquals("abcda", RegExp.leftContext); +assertEquals("bc", RegExp.lastMatch); +assertEquals("c", RegExp.lastParen); +assertEquals(undefined, RegExp.lastIndex); +assertEquals(undefined, RegExp.index); +assertEquals("d", RegExp.rightContext); +assertEquals('b', RegExp.$1); +assertEquals('c', RegExp.$2); +for (var i = 3; i < 10; i++) { + assertEquals("", RegExp['$' + i]); +} + + +function Override() { + // Set the internal lastMatchInfoOverride. After calling this we do a normal + // match and verify the override was cleared and that we record the new + // captures. + "abcdabcd".replace(/(b)(c)/g, function() { }); +} + + +function TestOverride(input, expect, property, re_src) { + var re = new RegExp(re_src); + var re_g = new RegExp(re_src, "g"); + + function OverrideCase(fn) { + Override(); + fn(); + assertEquals(expect, RegExp[property]); + } + + OverrideCase(function() { return input.replace(re, "x"); }); + OverrideCase(function() { return input.replace(re_g, "x"); }); + OverrideCase(function() { return input.replace(re, ""); }); + OverrideCase(function() { return input.replace(re_g, ""); }); + OverrideCase(function() { return input.match(re); }); + OverrideCase(function() { return input.match(re_g); }); + OverrideCase(function() { return re.test(input); }); + OverrideCase(function() { return re_g.test(input); }); +} + +var input = "bar.foo baz......"; +var re_str = "(ba.).*?f"; +TestOverride(input, "bar", "$1", re_str); + +input = "foo bar baz"; +var re_str = "bar"; +TestOverride(input, "bar", "$&", re_str); + + +function no_last_match(fn) { + fn(); + assertEquals("hestfisk", RegExp.$1); +} + +/(hestfisk)/.test("There's no such thing as a hestfisk!"); + +no_last_match(function() { "foo".replace("f", ""); }); +no_last_match(function() { "foo".replace("f", "f"); }); +no_last_match(function() { "foo".split("o"); }); + +var base = "In the music. In the music. "; +var cons = base + base + base + base; +no_last_match(function() { cons.replace("x", "y"); }); +no_last_match(function() { cons.replace("e", "E"); }); + + +// Here's one that matches once, then tries to match again, but fails. +// Verify that the last match info is from the last match, not from the +// failure that came after. +"bar.foo baz......".replace(/(ba.).*?f/g, function() { return "x";}); +assertEquals("bar", RegExp.$1); + + +// A test that initially does a zero width match, but later does a non-zero +// width match. +var a = "foo bar baz".replace(/^|bar/g, ""); +assertEquals("foo baz", a); + +a = "foo bar baz".replace(/^|bar/g, "*"); +assertEquals("*foo * baz", a); + +// We test FilterASCII using regexps that will backtrack forever. Since +// a regexp with a non-ASCII character in it can never match an ASCII +// string we can test that the relevant node is removed by verifying that +// there is no hang. +function NoHang(re) { + print(re); + "This is an ASCII string that could take forever".match(re); +} + + +NoHang(/(((.*)*)*x)å/); // Continuation after loop is filtered, so is loop. +NoHang(/(((.*)*)*å)foo/); // Body of loop filtered. +NoHang(/å(((.*)*)*x)/); // Everything after a filtered character is filtered. +NoHang(/(((.*)*)*x)å/); // Everything before a filtered character is filtered. +NoHang(/[æøå](((.*)*)*x)/); // Everything after a filtered class is filtered. +NoHang(/(((.*)*)*x)[æøå]/); // Everything before a filtered class is filtered. +NoHang(/[^\x00-\x7f](((.*)*)*x)/); // After negated class. +NoHang(/(((.*)*)*x)[^\x00-\x7f]/); // Before negated class. +NoHang(/(?!(((.*)*)*x)å)foo/); // Negative lookahead is filtered. +NoHang(/(?!(((.*)*)*x))å/); // Continuation branch of negative lookahead. +NoHang(/(?=(((.*)*)*x)å)foo/); // Positive lookahead is filtered. +NoHang(/(?=(((.*)*)*x))å/); // Continuation branch of positive lookahead. +NoHang(/(?=å)(((.*)*)*x)/); // Positive lookahead also prunes continuation. +NoHang(/(æ|ø|å)(((.*)*)*x)/); // All branches of alternation are filtered. +NoHang(/(a|b|(((.*)*)*x))å/); // 1 out of 3 branches pruned. +NoHang(/(a|(((.*)*)*x)ø|(((.*)*)*x)å)/); // 2 out of 3 branches pruned. + +var s = "Don't prune based on a repetition of length 0"; +assertEquals(null, s.match(/å{1,1}prune/)); +assertEquals("prune", (s.match(/å{0,0}prune/)[0])); + +// Some very deep regexps where FilterASCII gives up in order not to make the +// stack overflow. +var regex6 = /a*\u0100*\w/; +var input0 = "a"; +regex6.exec(input0); + +var re = "\u0100*\\w"; + +for (var i = 0; i < 200; i++) re = "a*" + re; + +var regex7 = new RegExp(re); +regex7.exec(input0); + +var regex8 = new RegExp(re, "i"); +regex8.exec(input0); + +re = "[\u0100]*\\w"; +for (var i = 0; i < 200; i++) re = "a*" + re; + +var regex9 = new RegExp(re); +regex9.exec(input0); + +var regex10 = new RegExp(re, "i"); +regex10.exec(input0); + +var regex11 = /^(?:[^\u0000-\u0080]|[0-9a-z?,.!&\s#()])+$/i; +regex11.exec(input0); + diff --git a/deps/v8/test/mjsunit/regress/regress-1119.js b/deps/v8/test/mjsunit/regress/regress-1119.js index 16b2e4f935..5fd8f369b1 100644 --- a/deps/v8/test/mjsunit/regress/regress-1119.js +++ b/deps/v8/test/mjsunit/regress/regress-1119.js @@ -28,17 +28,19 @@ // Test runtime declaration of properties with var which are intercepted // by JS accessors. -__proto__.__defineSetter__("x", function() { hasBeenInvoked = true; }); -__proto__.__defineSetter__("y", function() { throw 'exception'; }); +// Flags: --es52_globals + +this.__defineSetter__("x", function() { hasBeenInvoked = true; }); +this.__defineSetter__("y", function() { throw 'exception'; }); var hasBeenInvoked = false; eval("try { } catch (e) { var x = false; }"); assertTrue(hasBeenInvoked); -var exception; +// This has to run in global scope, so cannot use assertThrows... try { eval("try { } catch (e) { var y = false; }"); + assertUnreachable(); } catch (e) { - exception = e; + assertEquals('exception', e); } -assertEquals('exception', exception); diff --git a/deps/v8/test/mjsunit/regress/regress-115452.js b/deps/v8/test/mjsunit/regress/regress-115452.js index 7e424ed88b..dc711581e9 100644 --- a/deps/v8/test/mjsunit/regress/regress-115452.js +++ b/deps/v8/test/mjsunit/regress/regress-115452.js @@ -27,22 +27,21 @@ // Test that a function declaration cannot overwrite a read-only property. -print(0) +// Flags: --es52_globals + function foobl() {} assertTrue(typeof this.foobl == "function"); assertTrue(Object.getOwnPropertyDescriptor(this, "foobl").writable); -print(1) Object.defineProperty(this, "foobl", {value: 1, writable: false}); assertSame(1, this.foobl); assertFalse(Object.getOwnPropertyDescriptor(this, "foobl").writable); -print(2) -eval("function foobl() {}"); +// This has to run in global scope, so cannot use assertThrows... +try { + eval("function foobl() {}"); // Should throw. + assertUnreachable(); +} catch (e) { + assertInstanceof(e, TypeError); +} assertSame(1, this.foobl); -assertFalse(Object.getOwnPropertyDescriptor(this, "foobl").writable); - -print(3) -eval("function foobl() {}"); -assertSame(1, this.foobl); -assertFalse(Object.getOwnPropertyDescriptor(this, "foobl").writable); diff --git a/deps/v8/test/mjsunit/regress/regress-1170.js b/deps/v8/test/mjsunit/regress/regress-1170.js index 66ed9f29e2..8c5f6f8ab4 100644 --- a/deps/v8/test/mjsunit/regress/regress-1170.js +++ b/deps/v8/test/mjsunit/regress/regress-1170.js @@ -25,48 +25,74 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Flags: --es52_globals + var setter_value = 0; -__proto__.__defineSetter__("a", function(v) { setter_value = v; }); +this.__defineSetter__("a", function(v) { setter_value = v; }); eval("var a = 1"); assertEquals(1, setter_value); -assertFalse(this.hasOwnProperty("a")); +assertFalse("value" in Object.getOwnPropertyDescriptor(this, "a")); eval("with({}) { eval('var a = 2') }"); assertEquals(2, setter_value); -assertFalse(this.hasOwnProperty("a")); +assertFalse("value" in Object.getOwnPropertyDescriptor(this, "a")); // Function declarations are treated specially to match Safari. We do // not call setters for them. +this.__defineSetter__("a", function(v) { assertUnreachable(); }); eval("function a() {}"); -assertTrue(this.hasOwnProperty("a")); +assertTrue("value" in Object.getOwnPropertyDescriptor(this, "a")); -__proto__.__defineSetter__("b", function(v) { assertUnreachable(); }); -var exception = false; +this.__defineSetter__("b", function(v) { setter_value = v; }); try { - eval("const b = 23"); + eval("const b = 3"); } catch(e) { - exception = true; - assertTrue(/TypeError/.test(e)); + assertUnreachable(); } -assertFalse(exception); +assertEquals(3, setter_value); -exception = false; try { eval("with({}) { eval('const b = 23') }"); } catch(e) { - exception = true; - assertTrue(/TypeError/.test(e)); + assertInstanceof(e, TypeError); } -assertTrue(exception); -__proto__.__defineSetter__("c", function(v) { throw 42; }); -exception = false; +this.__defineSetter__("c", function(v) { throw 42; }); try { eval("var c = 1"); + assertUnreachable(); } catch(e) { - exception = true; assertEquals(42, e); - assertFalse(this.hasOwnProperty("c")); + assertFalse("value" in Object.getOwnPropertyDescriptor(this, "c")); +} + + + + +__proto__.__defineSetter__("aa", function(v) { assertUnreachable(); }); +eval("var aa = 1"); +assertTrue(this.hasOwnProperty("aa")); + +__proto__.__defineSetter__("bb", function(v) { assertUnreachable(); }); +eval("with({}) { eval('var bb = 2') }"); +assertTrue(this.hasOwnProperty("bb")); + +// Function declarations are treated specially to match Safari. We do +// not call setters for them. +__proto__.__defineSetter__("cc", function(v) { assertUnreachable(); }); +eval("function cc() {}"); +assertTrue(this.hasOwnProperty("cc")); + +__proto__.__defineSetter__("dd", function(v) { assertUnreachable(); }); +try { + eval("const dd = 23"); +} catch(e) { + assertUnreachable(); +} + +try { + eval("with({}) { eval('const dd = 23') }"); +} catch(e) { + assertInstanceof(e, TypeError); } -assertTrue(exception); diff --git a/deps/v8/test/mjsunit/regress/regress-117409.js b/deps/v8/test/mjsunit/regress/regress-117409.js new file mode 100644 index 0000000000..9222191ae6 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-117409.js @@ -0,0 +1,52 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --expose-gc + +function KeyedStoreIC(a) { a[0] = Math.E; } + +// Create literal with a fast double elements backing store +var literal = [1.2]; + +// Specialize the IC for fast double elements +KeyedStoreIC(literal); +KeyedStoreIC(literal); + +// Trruncate array to 0 elements, at which point backing store will be replaced +// with empty fixed array. +literal.length = 0; + +// ArrayPush built-in will replace empty fixed array backing store with 19 +// elements fixed array backing store. This leads to a mismatch between the map +// and the backing store. Debug mode will crash here in set_elements accessor. +literal.push(Math.E, Math.E); + +// Corrupt the backing store! +KeyedStoreIC(literal); + +// Release mode will crash here when trying to visit parts of E as pointers. +gc(); diff --git a/deps/v8/test/mjsunit/regress/regress-119609.js b/deps/v8/test/mjsunit/regress/regress-119609.js new file mode 100644 index 0000000000..99041adaf4 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-119609.js @@ -0,0 +1,71 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --expose-debug-as debug + +Debug = debug.Debug; + +var exception = false; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + function lookup(name) { + return exec_state.frame(0).evaluate(name).value(); + } + + assertEquals(3, lookup("e")); + assertEquals(4, lookup("f")); + assertEquals(1, lookup("a")); + + try { + assertEquals(2, lookup("b")); + } catch (e) { + assertEquals("ReferenceError: b is not defined", e.toString()); + } + } + } catch (e) { + exception = e.toString() + e.stack; + } +} + +Debug.setListener(listener); + +function f(a, b) { + var c = 3; + function d(e, f) { + var g = a; + var h = c; + debugger; + } + + return d; +} + +f(1, 2)(3, 4); + +assertFalse(exception); diff --git a/deps/v8/test/mjsunit/regress/regress-120099.js b/deps/v8/test/mjsunit/regress/regress-120099.js new file mode 100644 index 0000000000..3b06f4da2c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-120099.js @@ -0,0 +1,40 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +'use strict'; + +var a = Object.create(Object.prototype); +var b = Object.create(Object.prototype); +assertFalse(a === b); + +Object.defineProperty(a, 'x', { value: 1 }); +assertTrue(a.x === 1); +assertTrue(b.x === undefined); + +b.x = 2; +assertTrue(a.x === 1); +assertTrue(b.x === 2); diff --git a/deps/v8/test/mjsunit/regress/regress-121407.js b/deps/v8/test/mjsunit/regress/regress-121407.js new file mode 100644 index 0000000000..25033fb525 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-121407.js @@ -0,0 +1,40 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +var a = [0,1,2,3]; +a[2000000] = 2000000; +a.length=2000; +for (var i = 0; i <= 256; i++) { + a[i] = new Object(); +} + +a = [0.5,1.5,2.5,3.5,4.5,5.5]; +a[2000000] = 2000000; +a.length=2000; +for (var i = 0; i <= 256; i++) { + a[i] = new Object(); +}
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/regress/regress-1217.js b/deps/v8/test/mjsunit/regress/regress-1217.js index 6530549864..e00d5371ad 100644 --- a/deps/v8/test/mjsunit/regress/regress-1217.js +++ b/deps/v8/test/mjsunit/regress/regress-1217.js @@ -30,7 +30,7 @@ var proto = RegExp.prototype; assertEquals("[object RegExp]", Object.prototype.toString.call(proto)); -assertEquals("", proto.source); +assertEquals("(?:)", proto.source); assertEquals(false, proto.global); assertEquals(false, proto.multiline); assertEquals(false, proto.ignoreCase); diff --git a/deps/v8/test/mjsunit/regress/regress-123512.js b/deps/v8/test/mjsunit/regress/regress-123512.js new file mode 100644 index 0000000000..8a747bc5f7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-123512.js @@ -0,0 +1,78 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax + +// Test that boilerplate objects for array literals with non-constant +// elements (which will contain the hole at non-constant positions) will +// not cause prototype chain lookups when generating optimized code. + +function f(x) { + return [x][0]; +} + +// Test data element on prototype. +Object.prototype[0] = 23; +assertSame(1, f(1)); +assertSame(2, f(2)); +%OptimizeFunctionOnNextCall(f); +assertSame(3, f(3)); +%DeoptimizeFunction(f); + +// Test accessor element on prototype. +Object.prototype.__defineGetter__(0, function() { throw Error(); }); +assertSame(4, f(4)); +assertSame(5, f(5)); +%OptimizeFunctionOnNextCall(f); +assertSame(6, f(6)); +%DeoptimizeFunction(f); + +// Test the same on boilerplate objects for object literals that contain +// both non-constant properties and non-constant elements. + +function g(x, y) { + var o = { foo:x, 0:y }; + return o.foo + o[0]; +} + +// Test data property and element on prototype. +Object.prototype[0] = 23; +Object.prototype.foo = 42; +assertSame(3, g(1, 2)); +assertSame(5, g(2, 3)); +%OptimizeFunctionOnNextCall(g); +assertSame(7, g(3, 4)); +%DeoptimizeFunction(g); + +// Test accessor property and element on prototype. +Object.prototype.__defineGetter__(0, function() { throw Error(); }); +Object.prototype.__defineGetter__('foo', function() { throw Error(); }); +assertSame(3, g(1, 2)); +assertSame(5, g(2, 3)); +%OptimizeFunctionOnNextCall(g); +assertSame(7, g(3, 4)); +%DeoptimizeFunction(g); diff --git a/deps/v8/test/mjsunit/regress/regress-123919.js b/deps/v8/test/mjsunit/regress/regress-123919.js new file mode 100644 index 0000000000..be3460815b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-123919.js @@ -0,0 +1,47 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax --gc-global + +function g(max,val) { + this.x = 0; + for (var i = 0; i < max; i++) { + this.x = i/100; + } + this.val = val; +} + +function f(max) { + var val = 0.5; + var obj = new g(max,val); + assertSame(val, obj.val); +} + +f(1); +f(1); +%OptimizeFunctionOnNextCall(f); +f(200000); diff --git a/deps/v8/test/mjsunit/regress/regress-124594.js b/deps/v8/test/mjsunit/regress/regress-124594.js new file mode 100644 index 0000000000..d51e1f661c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-124594.js @@ -0,0 +1,50 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax --expose-gc + +// Test that a GC inside a constructor frame is correctly handled right +// after we deoptimize from an inlined constructor to a constructor stub +// stack frame. + +function f(deopt) { + var x = 1; + if (deopt) { + x = x + "foo"; + gc(); + } + this.x = x; +} + +function g(deopt) { + return new f(deopt); +} + +assertEquals({x:1}, g(false)); +assertEquals({x:1}, g(false)); +%OptimizeFunctionOnNextCall(g); +assertEquals({x:"1foo"}, g(true)); diff --git a/deps/v8/test/mjsunit/regress/regress-125515.js b/deps/v8/test/mjsunit/regress/regress-125515.js new file mode 100644 index 0000000000..91650ceb8f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-125515.js @@ -0,0 +1,41 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --expose-gc --debug-code + +function test(a) { + a[0] = 1.5; + assertEquals(0, a.length = 0); +} +a = new Array(); +test(a); +test(a); +// Make sure that a ends up in old space +gc(); +gc(); +test(a); +test(a); diff --git a/deps/v8/test/mjsunit/regress/regress-126412.js b/deps/v8/test/mjsunit/regress/regress-126412.js new file mode 100644 index 0000000000..0677f70913 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-126412.js @@ -0,0 +1,33 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +"".match(/(A{9999999999}B|C*)*D/); +"C".match(/(A{9999999999}B|C*)*D/); +"".match(/(A{9999999999}B|C*)*/ ); +"C".match(/(A{9999999999}B|C*)*/ ); +"".match(/(9u|(2\`shj{2147483649,}\r|3|f|y|3*)+8\B)\W93+/); +"9u8 ".match(/(9u|(2\`shj{2147483649,}\r|3|f|y|3*)+8\B)\W93+/); diff --git a/deps/v8/test/mjsunit/regress/regress-1639-2.js b/deps/v8/test/mjsunit/regress/regress-1639-2.js index c439dd8fff..01f0dc2048 100644 --- a/deps/v8/test/mjsunit/regress/regress-1639-2.js +++ b/deps/v8/test/mjsunit/regress/regress-1639-2.js @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -28,6 +28,7 @@ // Flags: --expose-debug-as debug // Get the Debug object exposed from the debug context global object. Debug = debug.Debug +var exception = false; function sendCommand(state, cmd) { // Get the debug command processor in paused state. @@ -79,6 +80,7 @@ function listener(event, exec_state, event_data, data) { } } catch (e) { print(e); + exception = true; } } @@ -91,3 +93,4 @@ function a() { // Set a break point and call to invoke the debug event listener. Debug.setBreakPoint(a, 0, 0); a(); +assertFalse(exception); diff --git a/deps/v8/test/mjsunit/regress/regress-1639.js b/deps/v8/test/mjsunit/regress/regress-1639.js index ed68c97df8..47cdbc43c1 100644 --- a/deps/v8/test/mjsunit/regress/regress-1639.js +++ b/deps/v8/test/mjsunit/regress/regress-1639.js @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -29,6 +29,7 @@ // Get the Debug object exposed from the debug context global object. Debug = debug.Debug var breaks = 0; +var exception = false; function sendCommand(state, cmd) { // Get the debug command processor in paused state. @@ -47,15 +48,18 @@ function listener(event, exec_state, event_data, data) { "should not break on unexpected lines") assertEquals('BREAK ' + breaks, line.substr(-7)); breaks++; - sendCommand(exec_state, { - seq: 0, - type: "request", - command: "continue", - arguments: { stepaction: "next" } - }); + if (breaks < 4) { + sendCommand(exec_state, { + seq: 0, + type: "request", + command: "continue", + arguments: { stepaction: "next" } + }); + } } } catch (e) { print(e); + exception = true; } } @@ -82,4 +86,6 @@ function c() { // Set a break point and call to invoke the debug event listener. Debug.setBreakPoint(b, 0, 0); a(b); -// BREAK 3 +a(); // BREAK 3 + +assertFalse(exception); diff --git a/deps/v8/test/mjsunit/regress/regress-2027.js b/deps/v8/test/mjsunit/regress/regress-2027.js new file mode 100644 index 0000000000..00ed03f650 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2027.js @@ -0,0 +1,48 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +var d = new Date(2010, 1, 1); + +function Check(time) { + assertEquals(d.getTime(), time); +} + +Check(d.setMilliseconds(10)); +Check(d.setSeconds(10)); +Check(d.setMinutes(10)); +Check(d.setHours(10)); +Check(d.setDate(10)); +Check(d.setMonth(10)); +Check(d.setFullYear(2010)); +Check(d.setUTCMilliseconds(10)); +Check(d.setUTCSeconds(10)); +Check(d.setUTCMinutes(10)); +Check(d.setUTCHours(10)); +Check(d.setUTCDate(10)); +Check(d.setUTCMonth(10)); +Check(d.setUTCFullYear(2010)); + diff --git a/deps/v8/test/mjsunit/regress/regress-2030.js b/deps/v8/test/mjsunit/regress/regress-2030.js new file mode 100644 index 0000000000..fb5a3d0c46 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2030.js @@ -0,0 +1,53 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax + +function a() { + this.x = 1; +} +var aa = new a(); +%DebugPrint(aa); + +function b() { + this.z = 23; + this.x = 2; +} +var bb = new b(); +%DebugPrint(bb); + +function f(o) { + return o.x; +} + +assertSame(1, f(aa)); +assertSame(1, f(aa)); +assertSame(2, f(bb)); +assertSame(2, f(bb)); +%OptimizeFunctionOnNextCall(f); +assertSame(1, f(aa)); +assertSame(2, f(bb)); diff --git a/deps/v8/test/mjsunit/regress/regress-2032.js b/deps/v8/test/mjsunit/regress/regress-2032.js new file mode 100644 index 0000000000..ad6408d3d6 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2032.js @@ -0,0 +1,64 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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: http://code.google.com/p/v8/issues/detail?id=2032 + +// Case independent regexp that ends on the first character in a block. +assertTrue(/[@-A]/i.test("a")); +assertTrue(/[@-A]/i.test("A")); +assertTrue(/[@-A]/i.test("@")); + +assertFalse(/[@-A]/.test("a")); +assertTrue(/[@-A]/.test("A")); +assertTrue(/[@-A]/.test("@")); + +assertFalse(/[¿-À]/i.test('¾')); +assertTrue(/[¿-À]/i.test('¿')); +assertTrue(/[¿-À]/i.test('À')); +assertTrue(/[¿-À]/i.test('à')); +assertFalse(/[¿-À]/i.test('á')); +assertFalse(/[¿-À]/i.test('Á')); + +assertFalse(/[¿-À]/.test('¾')); +assertTrue(/[¿-À]/.test('¿')); +assertTrue(/[¿-À]/.test('À')); +assertFalse(/[¿-À]/.test('à')); +assertFalse(/[¿-À]/.test('á')); +assertFalse(/[¿-À]/.test('á')); +assertFalse(/[¿-À]/i.test('Á')); + +assertFalse(/[Ö-×]/i.test('Õ')); +assertTrue(/[Ö-×]/i.test('Ö')); +assertTrue(/[Ö-×]/i.test('ö')); +assertTrue(/[Ö-×]/i.test('×')); +assertFalse(/[Ö-×]/i.test('Ø')); + +assertFalse(/[Ö-×]/.test('Õ')); +assertTrue(/[Ö-×]/.test('Ö')); +assertFalse(/[Ö-×]/.test('ö')); +assertTrue(/[Ö-×]/.test('×')); +assertFalse(/[Ö-×]/.test('Ø')); diff --git a/deps/v8/test/mjsunit/regress/regress-2034.js b/deps/v8/test/mjsunit/regress/regress-2034.js new file mode 100644 index 0000000000..c510f97fc3 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2034.js @@ -0,0 +1,46 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --harmony-collections + +var key = {}; +var map = new WeakMap; +Object.preventExtensions(key); + +// Try querying using frozen key. +assertFalse(map.has(key)); +assertSame(undefined, map.get(key)); + +// Try adding using frozen key. +map.set(key, 1); +assertTrue(map.has(key)); +assertSame(1, map.get(key)); + +// Try deleting using frozen key. +map.delete(key, 1); +assertFalse(map.has(key)); +assertSame(undefined, map.get(key)); diff --git a/deps/v8/test/mjsunit/regress/regress-2045.js b/deps/v8/test/mjsunit/regress/regress-2045.js new file mode 100644 index 0000000000..822ee1fa46 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2045.js @@ -0,0 +1,49 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax + +function foo() { + assertEquals(2, arguments.length); +} + +function bar() { + G.x; + return foo.apply(this, arguments); +} + +function baz() { + return bar(1, 2); +} + +G = {x: 0}; +baz(); +baz(); +%OptimizeFunctionOnNextCall(baz); +baz(); +delete G.x; +baz(); diff --git a/deps/v8/test/mjsunit/regress/regress-2054.js b/deps/v8/test/mjsunit/regress/regress-2054.js new file mode 100644 index 0000000000..97b989c944 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2054.js @@ -0,0 +1,34 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Test that we can correctly optimize top level code that contains a +// throw (or return) as it's last statement. + +var N = 1e5; // Number of iterations that trigger optimization. +for (var i = 0; i < N; i++) { + if (i > N) throw new Error; +} diff --git a/deps/v8/test/mjsunit/regress/regress-2055.js b/deps/v8/test/mjsunit/regress/regress-2055.js new file mode 100644 index 0000000000..1eaf62c7da --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2055.js @@ -0,0 +1,48 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Test that array literal boilerplate objects can be transitioned while +// existing un-transitioned clones are still being populated. + +function test1(depth) { + if (--depth < 0) { + return []; + } else { + return [ 0, test1(depth) ]; + } +} +assertEquals([0,[0,[]]], test1(2)); + +function test2(depth) { + if (--depth < 0) { + return []; + } else { + var o = [ 0, test2(depth) ]; + return (depth == 0) ? 0.5 : o; + } +} +assertEquals([0,0.5], test2(2)); diff --git a/deps/v8/test/mjsunit/regress/regress-2056.js b/deps/v8/test/mjsunit/regress/regress-2056.js new file mode 100644 index 0000000000..d34a7500aa --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2056.js @@ -0,0 +1,66 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax + +var cases = [ + [0.0, 0.0, 0.0, 0,0], + [undefined, 0.0, NaN, NaN], + [0.0, undefined, NaN, NaN], + [NaN, 0.0, NaN, NaN], + [0.0, NaN, NaN, NaN], + [-NaN, 0.0, NaN, NaN], + [0.0, -NaN, NaN, NaN], + [Infinity, 0.0, Infinity, 0.0], + [0.0, Infinity, Infinity, 0.0], + [-Infinity, 0.0, 0.0, -Infinity], + [0.0, -Infinity, 0.0, -Infinity] +]; + +function do_min(a, b) { + return Math.min(a, b); +} + +function do_max(a, b) { + return Math.max(a, b); +} + +// Make sure that non-crankshaft results match expectations. +for (i = 0; i < cases.length; ++i) { + var c = cases[i]; + assertEquals(c[3], do_min(c[0], c[1])); + assertEquals(c[2], do_max(c[0], c[1])); +} + +// Make sure that crankshaft results match expectations. +for (i = 0; i < cases.length; ++i) { + var c = cases[i]; + %OptimizeFunctionOnNextCall(do_min); + %OptimizeFunctionOnNextCall(do_max); + assertEquals(c[3], do_min(c[0], c[1])); + assertEquals(c[2], do_max(c[0], c[1])); +} diff --git a/deps/v8/test/mjsunit/regress/regress-2058.js b/deps/v8/test/mjsunit/regress/regress-2058.js new file mode 100644 index 0000000000..9a69ea1621 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2058.js @@ -0,0 +1,37 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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 http://code.google.com/p/v8/issues/detail?id=2058 + +// A match after a replace with a function argument needs to reset +// the flag that determines whether we are using indices or substrings +// to indicate the last match. +"Now is the".replace(/Now (\w+) the/g, function() { + "foo bar".match(/( )/); + assertEquals(RegExp.$1, " "); +}) diff --git a/deps/v8/test/mjsunit/regress/regress-2110.js b/deps/v8/test/mjsunit/regress/regress-2110.js new file mode 100644 index 0000000000..d7f78d26a7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2110.js @@ -0,0 +1,53 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax + +var uint8 = new Uint8Array(1); + +function test() { + uint8[0] = 0x800000aa; + assertEquals(0xaa, uint8[0]); +} + +test(); +test(); +test(); +%OptimizeFunctionOnNextCall(test); +test(); + +var uint32 = new Uint32Array(1); + +function test2() { + uint32[0] = 0x80123456789abcde; + assertEquals(0x789ac000, uint32[0]); +} + +test2(); +test2(); +%OptimizeFunctionOnNextCall(test2); +test2(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-122271.js b/deps/v8/test/mjsunit/regress/regress-crbug-122271.js new file mode 100644 index 0000000000..3a99a7fa58 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-122271.js @@ -0,0 +1,49 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax + +// Tests that ElementsKind transitions and regular transitions don't +// interfere badly with each other. + +var a = [0, 0, 0, 1]; +var b = [0, 0, 0, "one"]; +var c = [0, 0, 0, 1]; +c.foo = "baz"; + +function foo(array) { + array.foo = "bar"; +} + +assertTrue(%HasFastSmiOnlyElements(a)); +assertTrue(%HasFastElements(b)); + +foo(a); +foo(b); + +assertTrue(%HasFastSmiOnlyElements(a)); +assertTrue(%HasFastElements(b)); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-126414.js b/deps/v8/test/mjsunit/regress/regress-crbug-126414.js new file mode 100644 index 0000000000..6674267d74 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-126414.js @@ -0,0 +1,32 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +function foo(bar) { + return arguments[bar]; +} +foo(0); // Handled in runtime. +foo(-536870912); // Triggers bug. diff --git a/deps/v8/test/mjsunit/regress/regress-fast-literal-transition.js b/deps/v8/test/mjsunit/regress/regress-fast-literal-transition.js new file mode 100644 index 0000000000..72110f5be2 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-fast-literal-transition.js @@ -0,0 +1,62 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Flags: --allow-natives-syntax --always-opt --expose-gc + +// Test that the elements kind of the boilerplate object is sufficiently +// checked in LFastLiteral, so that unoptimized code can transition the +// boilerplate. The --always-opt flag makes sure that optimized code is +// not thrown away at deoptimization. + +// The switch statement in f() makes sure that f() is not inlined. If we +// start inlining switch statements, we will still catch the bug on the +// final --stress-opt run. + +function f(x) { + switch(x) { + case 1: return 1.4; + case 2: return 1.5; + case 3: return {}; + default: gc(); + } +} + +function g(x) { + return [1.1, 1.2, 1.3, f(x)]; +} + +// Step 1: Optimize g() to contain a FAST_DOUBLE_ELEMENTS boilerplate. +assertEquals([1.1, 1.2, 1.3, 1.4], g(1)); +assertEquals([1.1, 1.2, 1.3, 1.5], g(2)); +%OptimizeFunctionOnNextCall(g); + +// Step 2: Deoptimize g() and transition to FAST_ELEMENTS boilerplate. +assertEquals([1.1, 1.2, 1.3, {}], g(3)); + +// Step 3: Cause a GC while broken clone of boilerplate is on the heap, +// hence causing heap verification to catch it. +assertEquals([1.1, 1.2, 1.3, undefined], g(4)); diff --git a/deps/v8/test/mjsunit/unicodelctest-no-optimization.js b/deps/v8/test/mjsunit/unicodelctest-no-optimization.js new file mode 100644 index 0000000000..3bcb5bf256 --- /dev/null +++ b/deps/v8/test/mjsunit/unicodelctest-no-optimization.js @@ -0,0 +1,4914 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. +// Flags: --noregexp-optimization + +// This regexp should pick up all lower case characters. The non-BMP +// characters are coded using explicit surrogate pairs. +var re = /^([a-zªµºß-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıijĵķ-ĸĺļľŀłńņň-ʼnŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżž-ƀƃƅƈƌ-ƍƒƕƙ-ƛƞơƣƥƨƪ-ƫƭưƴƶƹ-ƺƽ-ƿdžljnjǎǐǒǔǖǘǚǜ-ǝǟǡǣǥǧǩǫǭǯ-ǰdzǵǹǻǽǿȁȃȅȇȉȋȍȏȑȓȕȗșțȝȟȡȣȥȧȩȫȭȯȱȳ-ȹȼȿ-ɀɂɇɉɋɍɏ-ʓʕ-ʯͱͳͷͻ-ͽΐά-ώϐ-ϑϕ-ϗϙϛϝϟϡϣϥϧϩϫϭϯ-ϳϵϸϻ-ϼа-џѡѣѥѧѩѫѭѯѱѳѵѷѹѻѽѿҁҋҍҏґғҕҗҙқҝҟҡңҥҧҩҫҭүұҳҵҷҹһҽҿӂӄӆӈӊӌӎ-ӏӑӓӕӗәӛӝӟӡӣӥӧөӫӭӯӱӳӵӷӹӻӽӿԁԃԅԇԉԋԍԏԑԓԕԗԙԛԝԟԡԣա-ևᴀ-ᴫᵢ-ᵷᵹ-ᶚḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕ-ẝẟạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹỻỽỿ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶ-ᾷιῂ-ῄῆ-ῇῐ-ΐῖ-ῗῠ-ῧῲ-ῴῶ-ῷⁱⁿℊℎ-ℏℓℯℴℹℼ-ℽⅆ-ⅉⅎↄⰰ-ⱞⱡⱥ-ⱦⱨⱪⱬⱱⱳ-ⱴⱶ-ⱼⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⲳⲵⲷⲹⲻⲽⲿⳁⳃⳅⳇⳉⳋⳍⳏⳑⳓⳕⳗⳙⳛⳝⳟⳡⳣ-ⳤⴀ-ⴥꙁꙃꙅꙇꙉꙋꙍꙏꙑꙓꙕꙗꙙꙛꙝꙟꙣꙥꙧꙩꙫꙭꚁꚃꚅꚇꚉꚋꚍꚏꚑꚓꚕꚗꜣꜥꜧꜩꜫꜭꜯ-ꜱꜳꜵꜷꜹꜻꜽꜿꝁꝃꝅꝇꝉꝋꝍꝏꝑꝓꝕꝗꝙꝛꝝꝟꝡꝣꝥꝧꝩꝫꝭꝯꝱ-ꝸꝺꝼꝿꞁꞃꞅꞇꞌff-stﬓ-ﬗa-z]|\ud801[\udc28-\udc4f]|\ud835[\udc1a-\udc33\udc4e-\udc54\udc56-\udc67\udc82-\udc9b\udcb6-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udccf\udcea-\udd03\udd1e-\udd37\udd52-\udd6b\udd86-\udd9f\uddba-\uddd3\uddee-\ude07\ude22-\ude3b\ude56-\ude6f\ude8a-\udea5\udec2-\udeda\udedc-\udee1\udefc-\udf14\udf16-\udf1b\udf36-\udf4e\udf50-\udf55\udf70-\udf88\udf8a-\udf8f\udfaa-\udfc2\udfc4-\udfc9\udfcb])$/; + + +var answer = get_answer(); +var fuzz_answer = get_fuzz_answer(); + + +for (var i = 0; i < 0x10000; i++) { + var s = String.fromCharCode(i); + assertTrue(!!re.test(s) == !!answer[i]); +} + + +function BuildSurrogatePair(c) { + return String.fromCharCode(+0xd800 + (c >> 10)) + + String.fromCharCode(+0xdc00 + (c & 0x3ff)); +} + +fuzz_index = 0; +fuzz(); + +for (var i = 0x10000; i < 0x110000 && i < answer.length + 256; i++) { + var c = i - 0x10000; + assertTrue(!!re.test(BuildSurrogatePair(c)) == !!answer[i]); +} + +var seed = 49734321; + +function rand() { + // To make the test results predictable, we use a 100% deterministic + // alternative. + // Robert Jenkins' 32 bit integer hash function. + seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; + seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff; + seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; + seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff; + seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; + seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff; + return (seed & 0xffff) +} + + +// Random character. +function rc(last) { + var c = rand(); + // Increase the concentration of problematic values around the page + // edges. + if (rand() & 1) { + c = (c & 0xff80) + (c & 3) - 2; + } + // Increase the concentration of problematic values around the ends. + if (rand() & 31 == 0) c = 0xfff8 + (rand() & 7) + if (rand() & 31 == 0) c = (rand() & 7) + + // Increase the concentration of values near each other. + if (rand() & 1) c = last + (rand() & 15) - 8; + return c & 0xffff; // Only code unit values. +} + + +function fuzz() { + fuzz_index = 0; + seed = 49734321; + for (var i = 0; i < 1000; i++) { + print(i); + var len = rand() & 0x1f; + var ranges = new Array(len); + var last = rand(); + for (var j = 0; j < len; j++) { + ranges.push(last); + last = rc(last); + } + ranges.sort(function (a, b) { return a - b }); + var cc = ""; + for (var j = 0; j < len; j++) { + var ch = String.fromCharCode(ranges[j]); + if (ch == '\\' || ch == ']') ch = '\\' + ch; + cc += ch; + if (j < len - 1 && rand() & 1) cc += '-'; + } + var negated = (last & 2) != 0; + var prefix = negated ? "[^" : "["; + var re = new RegExp(prefix + cc + "]"); + for (var j = 0; j < len; j++) { + retest(re, (ranges[j] - 1), negated); + retest(re, (ranges[j]), negated); + retest(re, (ranges[j] + 1), negated); + } + } +} + + +function retest(re, code, negated) { + var s = String.fromCharCode(code >>> 0); + assertTrue(negated != (!!re.test(s) == !!fuzz_answer[fuzz_index++])); +} + + +function get_fuzz_answer() { + // Test data generated with V8 version 3.7. +return [ + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0, + + + 0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,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,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0, + 0,1,1,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,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,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,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,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + + 0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0, + 0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, +]; +} + + +function get_answer() { + // Test data generated with V8 version 3.7. +return [ + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + ,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, , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , ,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,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, ,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, ,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, , , ,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, ,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, ,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,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,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,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,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,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,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, ,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,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,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, ,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, ,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, ,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, ,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,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,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,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,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,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, ,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, ,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, ,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, ,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, ,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,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,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,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,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,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, , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , ,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,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, ,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, ,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, ,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,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, ,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, ,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, ,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, ,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,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,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,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,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,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,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,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, + 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,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,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,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,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,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,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,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, + 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,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,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, + 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,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, , , , , , , , , , , , , , , , , + , , , , , , , , , ,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,1,1,1,1,1, ,1]; +} diff --git a/deps/v8/test/mjsunit/unicodelctest.js b/deps/v8/test/mjsunit/unicodelctest.js new file mode 100644 index 0000000000..2caaabdcbe --- /dev/null +++ b/deps/v8/test/mjsunit/unicodelctest.js @@ -0,0 +1,4912 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// This regexp should pick up all lower case characters. The non-BMP +// characters are coded using explicit surrogate pairs. +var re = /^([a-zªµºß-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıijĵķ-ĸĺļľŀłńņň-ʼnŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżž-ƀƃƅƈƌ-ƍƒƕƙ-ƛƞơƣƥƨƪ-ƫƭưƴƶƹ-ƺƽ-ƿdžljnjǎǐǒǔǖǘǚǜ-ǝǟǡǣǥǧǩǫǭǯ-ǰdzǵǹǻǽǿȁȃȅȇȉȋȍȏȑȓȕȗșțȝȟȡȣȥȧȩȫȭȯȱȳ-ȹȼȿ-ɀɂɇɉɋɍɏ-ʓʕ-ʯͱͳͷͻ-ͽΐά-ώϐ-ϑϕ-ϗϙϛϝϟϡϣϥϧϩϫϭϯ-ϳϵϸϻ-ϼа-џѡѣѥѧѩѫѭѯѱѳѵѷѹѻѽѿҁҋҍҏґғҕҗҙқҝҟҡңҥҧҩҫҭүұҳҵҷҹһҽҿӂӄӆӈӊӌӎ-ӏӑӓӕӗәӛӝӟӡӣӥӧөӫӭӯӱӳӵӷӹӻӽӿԁԃԅԇԉԋԍԏԑԓԕԗԙԛԝԟԡԣա-ևᴀ-ᴫᵢ-ᵷᵹ-ᶚḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕ-ẝẟạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹỻỽỿ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶ-ᾷιῂ-ῄῆ-ῇῐ-ΐῖ-ῗῠ-ῧῲ-ῴῶ-ῷⁱⁿℊℎ-ℏℓℯℴℹℼ-ℽⅆ-ⅉⅎↄⰰ-ⱞⱡⱥ-ⱦⱨⱪⱬⱱⱳ-ⱴⱶ-ⱼⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⲳⲵⲷⲹⲻⲽⲿⳁⳃⳅⳇⳉⳋⳍⳏⳑⳓⳕⳗⳙⳛⳝⳟⳡⳣ-ⳤⴀ-ⴥꙁꙃꙅꙇꙉꙋꙍꙏꙑꙓꙕꙗꙙꙛꙝꙟꙣꙥꙧꙩꙫꙭꚁꚃꚅꚇꚉꚋꚍꚏꚑꚓꚕꚗꜣꜥꜧꜩꜫꜭꜯ-ꜱꜳꜵꜷꜹꜻꜽꜿꝁꝃꝅꝇꝉꝋꝍꝏꝑꝓꝕꝗꝙꝛꝝꝟꝡꝣꝥꝧꝩꝫꝭꝯꝱ-ꝸꝺꝼꝿꞁꞃꞅꞇꞌff-stﬓ-ﬗa-z]|\ud801[\udc28-\udc4f]|\ud835[\udc1a-\udc33\udc4e-\udc54\udc56-\udc67\udc82-\udc9b\udcb6-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udccf\udcea-\udd03\udd1e-\udd37\udd52-\udd6b\udd86-\udd9f\uddba-\uddd3\uddee-\ude07\ude22-\ude3b\ude56-\ude6f\ude8a-\udea5\udec2-\udeda\udedc-\udee1\udefc-\udf14\udf16-\udf1b\udf36-\udf4e\udf50-\udf55\udf70-\udf88\udf8a-\udf8f\udfaa-\udfc2\udfc4-\udfc9\udfcb])$/; + + +var answer = get_answer(); +var fuzz_answer = get_fuzz_answer(); + + +for (var i = 0; i < 0x10000; i++) { + var s = String.fromCharCode(i); + assertTrue(!!re.test(s) == !!answer[i]); +} + + +function BuildSurrogatePair(c) { + return String.fromCharCode(+0xd800 + (c >> 10)) + + String.fromCharCode(+0xdc00 + (c & 0x3ff)); +} + +fuzz_index = 0; +fuzz(); + +for (var i = 0x10000; i < 0x110000 && i < answer.length + 256; i++) { + var c = i - 0x10000; + assertTrue(!!re.test(BuildSurrogatePair(c)) == !!answer[i]); +} + +var seed = 49734321; + +function rand() { + // To make the test results predictable, we use a 100% deterministic + // alternative. + // Robert Jenkins' 32 bit integer hash function. + seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; + seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff; + seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; + seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff; + seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; + seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff; + return (seed & 0xffff) +} + + +// Random character. +function rc(last) { + var c = rand(); + // Increase the concentration of problematic values around the page + // edges. + if (rand() & 1) { + c = (c & 0xff80) + (c & 3) - 2; + } + // Increase the concentration of problematic values around the ends. + if (rand() & 31 == 0) c = 0xfff8 + (rand() & 7) + if (rand() & 31 == 0) c = (rand() & 7) + + // Increase the concentration of values near each other. + if (rand() & 1) c = last + (rand() & 15) - 8; + return c & 0xffff; // Only code unit values. +} + + +function fuzz() { + fuzz_index = 0; + seed = 49734321; + for (var i = 0; i < 1000; i++) { + var len = rand() & 0x1f; + var ranges = new Array(len); + var last = rand(); + for (var j = 0; j < len; j++) { + ranges.push(last); + last = rc(last); + } + ranges.sort(function (a, b) { return a - b }); + var cc = ""; + for (var j = 0; j < len; j++) { + var ch = String.fromCharCode(ranges[j]); + if (ch == '\\' || ch == ']') ch = '\\' + ch; + cc += ch; + if (j < len - 1 && rand() & 1) cc += '-'; + } + var negated = (last & 2) != 0; + var prefix = negated ? "[^" : "["; + var re = new RegExp(prefix + cc + "]"); + for (var j = 0; j < len; j++) { + retest(re, (ranges[j] - 1), negated); + retest(re, (ranges[j]), negated); + retest(re, (ranges[j] + 1), negated); + } + } +} + + +function retest(re, code, negated) { + var s = String.fromCharCode(code >>> 0); + assertTrue(negated != (!!re.test(s) == !!fuzz_answer[fuzz_index++])); +} + + +function get_fuzz_answer() { + // Test data generated with V8 version 3.7. +return [ + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0, + + + 0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,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,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0, + 0,1,1,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,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,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,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,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + + 0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0, + 0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0, + 0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0, + 0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + + 0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0, + 0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0, + + 0,1,1,1,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0, + 0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0, + 0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0, + 0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0, + 0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0, +]; +} + + +function get_answer() { + // Test data generated with V8 version 3.7. +return [ + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + ,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, , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , ,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,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, ,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, ,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, , , ,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, ,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, ,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,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,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,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,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,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,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, ,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,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,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, ,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, ,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, ,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, ,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,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,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,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,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,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, ,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, ,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, ,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, ,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, ,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,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,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,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,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,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, , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , + , , , , , , , , , , , , , , , ,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,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, ,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, ,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, ,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,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, ,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, ,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, ,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, ,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,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,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,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,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,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,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,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, + 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,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,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,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,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,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,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,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, + 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,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,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, + 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,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, , , , , , , , , , , , , , , , , + , , , , , , , , , ,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,1,1,1,1,1, ,1]; +} diff --git a/deps/v8/test/mozilla/mozilla.status b/deps/v8/test/mozilla/mozilla.status index e64959acfc..c30be5e095 100644 --- a/deps/v8/test/mozilla/mozilla.status +++ b/deps/v8/test/mozilla/mozilla.status @@ -592,6 +592,20 @@ js1_5/Regress/regress-416737-01: FAIL_OK js1_5/Regress/regress-416737-02: FAIL_OK +# Illegal escape-sequences in string literals. Has already been fixed +# by most engines (i.e. V8, JSC, Opera and FF). +ecma/Array/15.4.5.1-1: FAIL_OK +ecma/LexicalConventions/7.7.4: FAIL_OK +ecma_2/RegExp/hex-001: FAIL_OK +js1_2/regexp/hexadecimal: FAIL_OK + + +# The source field of RegExp objects is properly escaped. We match JSC. +ecma_2/RegExp/constructor-001: FAIL_OK +ecma_2/RegExp/function-001: FAIL_OK +ecma_2/RegExp/properties-001: FAIL_OK + + ##################### FAILING TESTS ##################### # This section is for tests that fail in V8 and pass in JSC. diff --git a/deps/v8/test/sputnik/sputnik.status b/deps/v8/test/sputnik/sputnik.status index a4c7d57ff0..52d126e65b 100644 --- a/deps/v8/test/sputnik/sputnik.status +++ b/deps/v8/test/sputnik/sputnik.status @@ -52,36 +52,14 @@ S15.10.2.11_A1_T3: FAIL # We are more lenient in which string character escapes we allow than # the spec (7.8.4 p. 19) wants us to be. This is for compatibility. -S7.8.4_A4.3_T2: FAIL_OK -S7.8.4_A4.3_T2: FAIL_OK -S7.8.4_A6.2_T2: FAIL_OK -S7.8.4_A6.1_T4: FAIL_OK -S7.8.4_A4.3_T4: FAIL_OK -S7.8.4_A7.2_T2: FAIL_OK -S7.8.4_A7.1_T4: FAIL_OK -S7.8.4_A6.4_T2: FAIL_OK -S7.8.4_A7.4_T2: FAIL_OK -S7.8.4_A7.2_T4: FAIL_OK -S7.8.4_A4.3_T6: FAIL_OK -S7.8.4_A7.2_T6: FAIL_OK -S7.8.4_A4.3_T1: FAIL_OK -S7.8.4_A6.2_T1: FAIL_OK -S7.8.4_A4.3_T3: FAIL_OK -S7.8.4_A7.2_T1: FAIL_OK -S7.8.4_A6.4_T1: FAIL_OK -S7.8.4_A7.2_T3: FAIL_OK -S7.8.4_A7.4_T1: FAIL_OK -S7.8.4_A4.3_T5: FAIL_OK -S7.8.4_A7.2_T5: FAIL_OK S7.8.4_A4.3_T1: FAIL_OK -S7.8.4_A6.2_T1: FAIL_OK +S7.8.4_A4.3_T2: FAIL_OK S7.8.4_A4.3_T3: FAIL_OK -S7.8.4_A7.2_T1: FAIL_OK +S7.8.4_A4.3_T4: FAIL_OK S7.8.4_A6.4_T1: FAIL_OK -S7.8.4_A7.2_T3: FAIL_OK +S7.8.4_A6.4_T2: FAIL_OK S7.8.4_A7.4_T1: FAIL_OK -S7.8.4_A4.3_T5: FAIL_OK -S7.8.4_A7.2_T5: FAIL_OK +S7.8.4_A7.4_T2: FAIL_OK # Sputnik expects unicode escape sequences in RegExp flags to be interpreted. # The specification requires them to be passed uninterpreted to the RegExp @@ -146,6 +124,16 @@ S15.3.4.2_A1_T1: FAIL_OK S8.5_A2.2: PASS, FAIL if $system == linux, FAIL if $system == macos S8.5_A2.1: PASS, FAIL if $system == linux, FAIL if $system == macos +# The source field of RegExp objects is properly escaped. We match JSC. +S15.10.4.1_A3_T1: FAIL_OK +S15.10.4.1_A3_T2: FAIL_OK +S15.10.4.1_A3_T3: FAIL_OK +S15.10.4.1_A3_T4: FAIL_OK +S15.10.4.1_A3_T5: FAIL_OK +S15.10.4.1_A4_T2: FAIL_OK +S15.10.4.1_A4_T3: FAIL_OK +S15.10.4.1_A4_T5: FAIL_OK + ##################### ES3 TESTS ######################### # These tests check for ES3 semantics, and differ from ES5. # When we follow ES5 semantics, it's ok to fail the test. diff --git a/deps/v8/test/test262/README b/deps/v8/test/test262/README index dae18433a5..59e7f5eb8b 100644 --- a/deps/v8/test/test262/README +++ b/deps/v8/test/test262/README @@ -4,11 +4,11 @@ tests from http://hg.ecmascript.org/tests/test262 -at revision 309 as 'data' in this directory. Using later version +at revision 334 as 'data' in this directory. Using later version may be possible but the tests are only known to pass (and indeed run) with that revision. -hg clone -r 309 http://hg.ecmascript.org/tests/test262 data +hg clone -r 334 http://hg.ecmascript.org/tests/test262 data If you do update to a newer revision you may have to change the test harness adapter code since it uses internal functionality from the diff --git a/deps/v8/test/test262/test262.status b/deps/v8/test/test262/test262.status index 67607fff9b..c75528995d 100644 --- a/deps/v8/test/test262/test262.status +++ b/deps/v8/test/test262/test262.status @@ -33,7 +33,18 @@ def FAIL_OK = FAIL, OKAY # '__proto__' should be treated as a normal property in JSON. S15.12.2_A1: FAIL +# Sequencing of getter side effects on receiver and argument properties +# is wrong. The receiver callback should be called before any arguments +# are evaluated. +# V8 Bug: http://code.google.com/p/v8/issues/detail?id=691 +11.2.3-3_3: FAIL + +# Prototypal inheritance of properties does not maintain accessibility. +# The [[CanPut]] operation should traverse the prototype chain to +# determine whether given property is writable or not. # V8 Bug: http://code.google.com/p/v8/issues/detail?id=1475 +8.14.4-8-b_1: FAIL +8.14.4-8-b_2: FAIL 15.2.3.6-4-405: FAIL 15.2.3.6-4-410: FAIL 15.2.3.6-4-415: FAIL @@ -52,23 +63,12 @@ S15.1.2.2_A5.1_T1: FAIL_OK S15.8.2.16_A7: PASS || FAIL_OK S15.8.2.18_A7: PASS || FAIL_OK -# We are more lenient in which string character escapes we allow than -# the spec (7.8.4 p. 19) wants us to be. This is for compatibility. -S7.8.4_A6.1_T4: FAIL_OK -S7.8.4_A6.2_T1: FAIL_OK -S7.8.4_A6.2_T2: FAIL_OK -S7.8.4_A7.1_T4: FAIL_OK -S7.8.4_A7.2_T1: FAIL_OK -S7.8.4_A7.2_T2: FAIL_OK -S7.8.4_A7.2_T3: FAIL_OK -S7.8.4_A7.2_T4: FAIL_OK -S7.8.4_A7.2_T5: FAIL_OK -S7.8.4_A7.2_T6: FAIL_OK - -# Linux and Mac defaults to extended 80 bit floating point format in the FPU. +# Linux for ia32 (and therefore simulators) default to extended 80 bit floating +# point formats, so these tests checking 64-bit FP precision fail. The other +# platforms/arch's pass these tests. # We follow the other major JS engines by keeping this default. -S8.5_A2.2: PASS if ($system != linux || $arch == x64), FAIL_OK if ($system == linux && $arch != x64) -S8.5_A2.1: PASS if ($system != linux || $arch == x64), FAIL_OK if ($system == linux && $arch != x64) +S8.5_A2.1: PASS || FAIL_OK +S8.5_A2.2: PASS || FAIL_OK ############################ INVALID TESTS ############################# diff --git a/deps/v8/test/test262/testcfg.py b/deps/v8/test/test262/testcfg.py index 294b39c916..07f760c8d7 100644 --- a/deps/v8/test/test262/testcfg.py +++ b/deps/v8/test/test262/testcfg.py @@ -1,4 +1,4 @@ -# Copyright 2011 the V8 project authors. All rights reserved. +# Copyright 2012 the V8 project authors. All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: @@ -31,11 +31,12 @@ import os from os.path import join, exists import urllib import hashlib +import sys import tarfile -TEST_262_ARCHIVE_REVISION = '3a890174343c' # This is the r309 revision. -TEST_262_ARCHIVE_MD5 = 'be5d4cfbe69cef70430907b8f3a92b50' +TEST_262_ARCHIVE_REVISION = 'fb327c439e20' # This is the r334 revision. +TEST_262_ARCHIVE_MD5 = '307acd166ec34629592f240dc12d57ed' TEST_262_URL = 'http://hg.ecmascript.org/tests/test262/archive/%s.tar.bz2' TEST_262_HARNESS = ['sta.js'] @@ -103,23 +104,29 @@ class Test262TestConfiguration(test.TestConfiguration): revision = TEST_262_ARCHIVE_REVISION archive_url = TEST_262_URL % revision archive_name = join(self.root, 'test262-%s.tar.bz2' % revision) - directory_name = join(self.root, "test262-%s" % revision) - if not exists(directory_name) or not exists(archive_name): - if not exists(archive_name): - print "Downloading test data from %s ..." % archive_url - urllib.urlretrieve(archive_url, archive_name) - if not exists(directory_name): - print "Extracting test262-%s.tar.bz2 ..." % revision - md5 = hashlib.md5() - with open(archive_name,'rb') as f: - for chunk in iter(lambda: f.read(8192), ''): - md5.update(chunk) - if md5.hexdigest() != TEST_262_ARCHIVE_MD5: - raise Exception("Hash mismatch of test data file") - archive = tarfile.open(archive_name, 'r:bz2') - archive.extractall(join(self.root)) - if not exists(join(self.root, 'data')): - os.symlink(directory_name, join(self.root, 'data')) + directory_name = join(self.root, 'data') + directory_old_name = join(self.root, 'data.old') + if not exists(archive_name): + print "Downloading test data from %s ..." % archive_url + urllib.urlretrieve(archive_url, archive_name) + if exists(directory_name): + os.rename(directory_name, directory_old_name) + if not exists(directory_name): + print "Extracting test262-%s.tar.bz2 ..." % revision + md5 = hashlib.md5() + with open(archive_name,'rb') as f: + for chunk in iter(lambda: f.read(8192), ''): + md5.update(chunk) + if md5.hexdigest() != TEST_262_ARCHIVE_MD5: + os.remove(archive_name) + raise Exception("Hash mismatch of test data file") + archive = tarfile.open(archive_name, 'r:bz2') + if sys.platform in ('win32', 'cygwin'): + # Magic incantation to allow longer path names on Windows. + archive.extractall(u'\\\\?\\%s' % self.root) + else: + archive.extractall(self.root) + os.rename(join(self.root, 'test262-%s' % revision), directory_name) def GetBuildRequirements(self): return ['d8'] diff --git a/deps/v8/tools/check-static-initializers.sh b/deps/v8/tools/check-static-initializers.sh index 18add3a63a..1103a97787 100644 --- a/deps/v8/tools/check-static-initializers.sh +++ b/deps/v8/tools/check-static-initializers.sh @@ -31,19 +31,25 @@ # Note that the project must be built with SCons before running this script. # Allow: -# - _GLOBAL__I__ZN2v88internal32AtomicOps_Internalx86CPUFeaturesE # - _GLOBAL__I__ZN2v810LineEditor6first_E -expected_static_init_count=2 +# - _GLOBAL__I__ZN2v88internal32AtomicOps_Internalx86CPUFeaturesE +# - _GLOBAL__I__ZN2v88internal8ThreadId18highest_thread_id_E +expected_static_init_count=3 v8_root=$(readlink -f $(dirname $BASH_SOURCE)/../) -d8="${v8_root}/d8" + +if [ -n "$1" ] ; then + d8="${v8_root}/$1" +else + d8="${v8_root}/d8" +fi if [ ! -f "$d8" ]; then - echo "Please build the project with SCons." + echo "d8 binary not found: $d8" exit 1 fi -static_inits=$(nm "$d8" | grep _GLOBAL__I | awk '{ print $NF; }') +static_inits=$(nm "$d8" | grep _GLOBAL_ | grep _I_ | awk '{ print $NF; }') static_init_count=$(echo "$static_inits" | wc -l) @@ -51,4 +57,7 @@ if [ $static_init_count -gt $expected_static_init_count ]; then echo "Too many static initializers." echo "$static_inits" exit 1 +else + echo "Static initializer check passed ($static_init_count initializers)." + exit 0 fi diff --git a/deps/v8/tools/common-includes.sh b/deps/v8/tools/common-includes.sh index 8f0e78b601..2b806caa5f 100644 --- a/deps/v8/tools/common-includes.sh +++ b/deps/v8/tools/common-includes.sh @@ -77,20 +77,27 @@ delete_branch() { persist() { local VARNAME=$1 local FILE="$PERSISTFILE_BASENAME-$VARNAME" - echo "${!VARNAME}" > $FILE + local VALUE="${!VARNAME}" + if [ -z "$VALUE" ] ; then + VALUE="__EMPTY__" + fi + echo "$VALUE" > $FILE } restore() { local VARNAME=$1 local FILE="$PERSISTFILE_BASENAME-$VARNAME" local VALUE="$(cat $FILE)" + [[ -z "$VALUE" ]] && die "Variable '$VARNAME' could not be restored." + if [ "$VALUE" == "__EMPTY__" ] ; then + VALUE="" + fi eval "$VARNAME=\"$VALUE\"" } restore_if_unset() { local VARNAME=$1 [[ -z "${!VARNAME}" ]] && restore "$VARNAME" - [[ -z "${!VARNAME}" ]] && die "Variable '$VARNAME' could not be restored." } initial_environment_checks() { @@ -175,9 +182,10 @@ the uploaded CL." # Takes a file containing the patch to apply as first argument. apply_patch() { - patch -p1 < "$1" > "$PATCH_OUTPUT_FILE" || \ + patch $REVERSE_PATCH -p1 < "$1" > "$PATCH_OUTPUT_FILE" || \ { cat "$PATCH_OUTPUT_FILE" && die "Applying the patch failed."; } - tee < "$PATCH_OUTPUT_FILE" >(awk '{print $NF}' >> "$TOUCHED_FILES_FILE") + tee < "$PATCH_OUTPUT_FILE" >(grep "patching file" \ + | awk '{print $NF}' >> "$TOUCHED_FILES_FILE") rm "$PATCH_OUTPUT_FILE" } diff --git a/deps/v8/tools/grokdump.py b/deps/v8/tools/grokdump.py index 9977289872..29d4755d6f 100755 --- a/deps/v8/tools/grokdump.py +++ b/deps/v8/tools/grokdump.py @@ -27,6 +27,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import cmd import ctypes import mmap import optparse @@ -36,6 +37,7 @@ import sys import types import codecs import re +import struct USAGE="""usage: %prog [OPTION]... @@ -106,6 +108,24 @@ class Descriptor(object): return Raw +def do_dump(reader, heap): + """Dump all available memory regions.""" + def dump_region(reader, start, size, location): + print "%s - %s" % (reader.FormatIntPtr(start), + reader.FormatIntPtr(start + size)) + for slot in xrange(start, + start + size, + reader.PointerSize()): + maybe_address = reader.ReadUIntPtr(slot) + heap_object = heap.FindObject(maybe_address) + print "%s: %s" % (reader.FormatIntPtr(slot), + reader.FormatIntPtr(maybe_address)) + if heap_object: + heap_object.Print(Printer()) + print + + reader.ForEachMemoryRegion(dump_region) + # Set of structures and constants that describe the layout of minidump # files. Based on MSDN and Google Breakpad. @@ -444,6 +464,33 @@ class MinidumpReader(object): location = self.FindLocation(address) return self.minidump[location:location + size] + def _ReadWord(self, location): + if self.arch == MD_CPU_ARCHITECTURE_AMD64: + return ctypes.c_uint64.from_buffer(self.minidump, location).value + elif self.arch == MD_CPU_ARCHITECTURE_X86: + return ctypes.c_uint32.from_buffer(self.minidump, location).value + + def ForEachMemoryRegion(self, cb): + if self.memory_list64 is not None: + for r in self.memory_list64.ranges: + location = self.memory_list64.base_rva + offset + cb(self, r.start, r.size, location) + offset += r.size + + if self.memory_list is not None: + for r in self.memory_list.ranges: + cb(self, r.start, r.memory.data_size, r.memory.rva) + + def FindWord(self, word): + def search_inside_region(reader, start, size, location): + for loc in xrange(location, location + size): + if reader._ReadWord(loc) == word: + slot = start + (loc - location) + print "%s: %s" % (reader.FormatIntPtr(slot), + reader.FormatIntPtr(word)) + + self.ForEachMemoryRegion(search_inside_region) + def FindLocation(self, address): offset = 0 if self.memory_list64 is not None: @@ -745,7 +792,10 @@ class ConsString(String): self.right = self.ObjectField(self.RightOffset()) def GetChars(self): - return self.left.GetChars() + self.right.GetChars() + try: + return self.left.GetChars() + self.right.GetChars() + except: + return "***CAUGHT EXCEPTION IN GROKDUMP***" class Oddball(HeapObject): @@ -1011,6 +1061,42 @@ CONTEXT_FOR_ARCH = { ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] } +class InspectionShell(cmd.Cmd): + def __init__(self, reader, heap): + cmd.Cmd.__init__(self) + self.reader = reader + self.heap = heap + self.prompt = "(grok) " + + def do_dd(self, address): + "Interpret memory at the given address (if available)"\ + " as a sequence of words." + start = int(address, 16) + for slot in xrange(start, + start + self.reader.PointerSize() * 10, + self.reader.PointerSize()): + maybe_address = self.reader.ReadUIntPtr(slot) + heap_object = self.heap.FindObject(maybe_address) + print "%s: %s" % (self.reader.FormatIntPtr(slot), + self.reader.FormatIntPtr(maybe_address)) + if heap_object: + heap_object.Print(Printer()) + print + + def do_s(self, word): + "Search for a given word in available memory regions" + word = int(word, 0) + print "searching for word", word + self.reader.FindWord(word) + + def do_list(self, smth): + """List all available memory regions.""" + def print_region(reader, start, size, location): + print "%s - %s" % (reader.FormatIntPtr(start), + reader.FormatIntPtr(start + size)) + + self.reader.ForEachMemoryRegion(print_region) + def AnalyzeMinidump(options, minidump_name): reader = MinidumpReader(options, minidump_name) DebugPrint("========================================") @@ -1045,21 +1131,29 @@ def AnalyzeMinidump(options, minidump_name): print FormatDisasmLine(start, heap, line) print - print "Annotated stack (from exception.esp to bottom):" - for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): - maybe_address = reader.ReadUIntPtr(slot) - heap_object = heap.FindObject(maybe_address) - print "%s: %s" % (reader.FormatIntPtr(slot), - reader.FormatIntPtr(maybe_address)) - if heap_object: - heap_object.Print(Printer()) - print + if options.full: + do_dump(reader, heap) + + if options.shell: + InspectionShell(reader, heap).cmdloop("type help to get help") + else: + print "Annotated stack (from exception.esp to bottom):" + for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): + maybe_address = reader.ReadUIntPtr(slot) + heap_object = heap.FindObject(maybe_address) + print "%s: %s" % (reader.FormatIntPtr(slot), + reader.FormatIntPtr(maybe_address)) + if heap_object: + heap_object.Print(Printer()) + print reader.Dispose() if __name__ == "__main__": parser = optparse.OptionParser(USAGE) + parser.add_option("-s", "--shell", dest="shell", action="store_true") + parser.add_option("-f", "--full", dest="full", action="store_true") options, args = parser.parse_args() if len(args) != 1: parser.print_help() diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp index 764789a8f4..46f85fe1ff 100644 --- a/deps/v8/tools/gyp/v8.gyp +++ b/deps/v8/tools/gyp/v8.gyp @@ -59,6 +59,11 @@ '../../src/v8dll-main.cc', ], 'conditions': [ + ['OS=="mac"', { + 'xcode_settings': { + 'OTHER_LDFLAGS': ['-dynamiclib', '-all_load'] + }, + }], ['OS=="win"', { 'defines': [ 'BUILDING_V8_SHARED', @@ -360,7 +365,7 @@ '../../src/jsregexp.h', '../../src/isolate.cc', '../../src/isolate.h', - '../../src/lazy-instance.h' + '../../src/lazy-instance.h', '../../src/list-inl.h', '../../src/list.h', '../../src/lithium.cc', @@ -395,6 +400,7 @@ '../../src/once.h', '../../src/parser.cc', '../../src/parser.h', + '../../src/platform-posix.h', '../../src/platform-tls-mac.h', '../../src/platform-tls-win32.h', '../../src/platform-tls.h', diff --git a/deps/v8/tools/merge-to-branch.sh b/deps/v8/tools/merge-to-branch.sh index 49bf3e4489..aa590a313c 100644 --- a/deps/v8/tools/merge-to-branch.sh +++ b/deps/v8/tools/merge-to-branch.sh @@ -49,6 +49,8 @@ OPTIONS: -h Show this message -s Specify the step where to start work. Default: 0. -p Specify a patch file to apply as part of the merge + -m Specify a commit message for the patch + -r Reverse specified patches EOF } @@ -68,7 +70,7 @@ restore_patch_commit_hashes_if_unset() { ########## Option parsing -while getopts ":hs:fp:" OPTION ; do +while getopts ":hs:fp:rm:" OPTION ; do case $OPTION in h) usage exit 0 @@ -77,6 +79,10 @@ while getopts ":hs:fp:" OPTION ; do ;; f) rm -f "$ALREADY_MERGING_SENTINEL_FILE" ;; + r) REVERSE_PATCH="--reverse" + ;; + m) NEW_COMMIT_MSG=$OPTARG + ;; s) START_STEP=$OPTARG ;; ?) echo "Illegal option: -$OPTARG" @@ -98,8 +104,13 @@ touch "$ALREADY_MERGING_SENTINEL_FILE" initial_environment_checks if [ $START_STEP -le $CURRENT_STEP ] ; then - if [ ${#@} -lt 2 ] && [ -z "$EXTRA_PATCH" ] ; then - die "Either a patch file or revision numbers must be specified" + if [ ${#@} -lt 2 ] ; then + if [ -z "$EXTRA_PATCH" ] ; then + die "Either a patch file or revision numbers must be specified" + fi + if [ -z "$NEW_COMMIT_MSG" ] ; then + die "You must specify a merge comment if no patches are specified" + fi fi echo ">>> Step $CURRENT_STEP: Preparation" MERGE_TO_BRANCH=$1 @@ -131,10 +142,12 @@ revisions associated with the patches." REVISION_LIST="$REVISION_LIST r$REVISION" let current+=1 done - if [ -z "$REVISION_LIST" ] ; then - NEW_COMMIT_MSG="Applied patch to $MERGE_TO_BRANCH branch." - else - NEW_COMMIT_MSG="Merged$REVISION_LIST into $MERGE_TO_BRANCH branch." + if [ -n "$REVISION_LIST" ] ; then + if [ -n "$REVERSE_PATCH" ] ; then + NEW_COMMIT_MSG="Rollback of$REVISION_LIST in $MERGE_TO_BRANCH branch." + else + NEW_COMMIT_MSG="Merged$REVISION_LIST into $MERGE_TO_BRANCH branch." + fi; fi; echo "$NEW_COMMIT_MSG" > $COMMITMSG_FILE diff --git a/deps/v8/tools/presubmit.py b/deps/v8/tools/presubmit.py index a5f4c614d0..a0b81e85f4 100755 --- a/deps/v8/tools/presubmit.py +++ b/deps/v8/tools/presubmit.py @@ -114,12 +114,15 @@ def CppLintWorker(command): while True: out_line = process.stderr.readline() if out_line == '' and process.poll() != None: + if error_count == -1: + print "Failed to process %s" % command.pop() + return 1 break m = LINT_OUTPUT_PATTERN.match(out_line) if m: out_lines += out_line error_count += 1 - sys.stderr.write(out_lines) + sys.stdout.write(out_lines) return error_count except KeyboardInterrupt: process.kill() @@ -300,7 +303,8 @@ class SourceProcessor(SourceFileProcessor): or (name == 'third_party') or (name == 'gyp') or (name == 'out') - or (name == 'obj')) + or (name == 'obj') + or (name == 'DerivedSources')) IGNORE_COPYRIGHTS = ['cpplint.py', 'earley-boyer.js', diff --git a/deps/v8/tools/push-to-trunk.sh b/deps/v8/tools/push-to-trunk.sh index 3fb5b34ed3..ff6dd1d776 100755 --- a/deps/v8/tools/push-to-trunk.sh +++ b/deps/v8/tools/push-to-trunk.sh @@ -130,6 +130,7 @@ if [ $START_STEP -le $CURRENT_STEP ] ; then | grep "^BUG=" | grep -v "BUG=$" | grep -v "BUG=none$" \ | sed -e 's/^/ /' \ | sed -e 's/BUG=v8:\(.*\)$/(issue \1)/' \ + | sed -e 's/BUG=chromium:\(.*\)$/(Chromium issue \1)/' \ | sed -e 's/BUG=\(.*\)$/(Chromium issue \1)/' \ >> "$CHANGELOG_ENTRY_FILE" # Append the commit's author for reference. @@ -320,6 +321,14 @@ if [ $START_STEP -le $CURRENT_STEP ] ; then || die "'git svn tag' failed." fi +if [ -z "$CHROME_PATH" ] ; then + echo ">>> (asking for Chromium checkout)" + echo -n "Do you have a \"NewGit\" Chromium checkout and want this script \ +to automate creation of the roll CL? If yes, enter the path to (and including) \ +the \"src\" directory here, otherwise just press <Return>: " + read CHROME_PATH +fi + if [ -n "$CHROME_PATH" ] ; then let CURRENT_STEP+=1 diff --git a/deps/v8/tools/test-wrapper-gypbuild.py b/deps/v8/tools/test-wrapper-gypbuild.py index fda4105a98..eda2459173 100755 --- a/deps/v8/tools/test-wrapper-gypbuild.py +++ b/deps/v8/tools/test-wrapper-gypbuild.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2011 the V8 project authors. All rights reserved. +# Copyright 2012 the V8 project authors. All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: @@ -56,6 +56,9 @@ def BuildOptions(): result.add_option("--no-presubmit", help='Skip presubmit checks', default=False, action="store_true") + result.add_option("--buildbot", + help='Adapt to path structure used on buildbots', + default=False, action="store_true") # Flags this wrapper script handles itself: result.add_option("-m", "--mode", @@ -144,14 +147,16 @@ def ProcessOptions(options): options.mode = options.mode.split(',') options.arch = options.arch.split(',') for mode in options.mode: - if not mode in ['debug', 'release']: + if not mode.lower() in ['debug', 'release']: print "Unknown mode %s" % mode return False for arch in options.arch: if not arch in ['ia32', 'x64', 'arm', 'mips']: print "Unknown architecture %s" % arch return False - + if options.buildbot: + # Buildbots run presubmit tests as a separate step. + options.no_presubmit = True return True @@ -213,22 +218,26 @@ def Main(): return 1 workspace = abspath(join(dirname(sys.argv[0]), '..')) + returncodes = 0 if not options.no_presubmit: print ">>> running presubmit tests" - subprocess.call([workspace + '/tools/presubmit.py']) + returncodes += subprocess.call([workspace + '/tools/presubmit.py']) args_for_children = [workspace + '/tools/test.py'] + PassOnOptions(options) args_for_children += ['--no-build', '--build-system=gyp'] for arg in args: args_for_children += [arg] - returncodes = 0 env = os.environ for mode in options.mode: for arch in options.arch: print ">>> running tests for %s.%s" % (arch, mode) - shellpath = workspace + '/' + options.outdir + '/' + arch + '.' + mode + if options.buildbot: + shellpath = workspace + '/' + options.outdir + '/' + mode + mode = mode.lower() + else: + shellpath = workspace + '/' + options.outdir + '/' + arch + '.' + mode env['LD_LIBRARY_PATH'] = shellpath + '/lib.target' shell = shellpath + "/d8" child = subprocess.Popen(' '.join(args_for_children + |