diff options
author | Fedor Indutny <fedor.indutny@gmail.com> | 2013-01-01 12:28:07 +0400 |
---|---|---|
committer | Fedor Indutny <fedor.indutny@gmail.com> | 2013-01-01 16:07:02 +0400 |
commit | 7b4d95a976f1b76e6dcefb6ca91dff738c80ab7a (patch) | |
tree | 1eb943733a2e660fc0183778fd441443e06196e2 | |
parent | 9e32c2ef3ede29ba0ae2086bdf658f6cd44182df (diff) | |
download | node-new-7b4d95a976f1b76e6dcefb6ca91dff738c80ab7a.tar.gz |
deps: update v8 to 3.15.11
494 files changed, 50379 insertions, 31813 deletions
diff --git a/deps/v8/.gitignore b/deps/v8/.gitignore index 77f38dd9c6..fe8425f021 100644 --- a/deps/v8/.gitignore +++ b/deps/v8/.gitignore @@ -18,6 +18,7 @@ #*# *~ .cpplint-cache +.d8_history d8 d8_g shell @@ -25,17 +26,32 @@ shell_g /build/Debug /build/gyp /build/Release -/obj/ -/out/ +/obj +/out +/test/cctest/cctest.status2 /test/es5conform/data +/test/message/message.status2 +/test/mjsunit/mjsunit.status2 +/test/mozilla/CHECKED_OUT_VERSION /test/mozilla/data +/test/mozilla/downloaded_* +/test/mozilla/mozilla.status2 +/test/preparser/preparser.status2 /test/sputnik/sputniktests /test/test262/data +/test/test262/test262-* +/test/test262/test262.status2 /third_party +/tools/jsfunfuzz +/tools/jsfunfuzz.zip /tools/oom_dump/oom_dump /tools/oom_dump/oom_dump.o /tools/visual_studio/Debug /tools/visual_studio/Release -/xcodebuild/ +/xcodebuild TAGS *.Makefile +GTAGS +GRTAGS +GSYMS +GPATH diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index 1156d94958..c279e7c2d9 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -20,6 +20,7 @@ Burcu Dogan <burcujdogan@gmail.com> Craig Schlenter <craig.schlenter@gmail.com> Daniel Andersson <kodandersson@gmail.com> Daniel James <dnljms@gmail.com> +Derek J Conrod <dconrod@codeaurora.org> Dineel D Sule <dsule@codeaurora.org> Erich Ocean <erich.ocean@me.com> Fedor Indutny <fedor@indutny.com> @@ -44,6 +45,7 @@ Paolo Giarrusso <p.giarrusso@gmail.com> Patrick Gansterer <paroga@paroga.com> Peter Varga <pvarga@inf.u-szeged.hu> Rafal Krypa <rafal@krypa.net> +Rajeev R Krithivasan <rkrithiv@codeaurora.org> Rene Rebe <rene@exactcode.de> Robert Mustacchi <rm@fingolfin.org> Rodolph Perfetta <rodolph.perfetta@arm.com> @@ -53,6 +55,7 @@ Sanjoy Das <sanjoy@playingwithpointers.com> Subrato K De <subratokde@codeaurora.org> Tobias Burnus <burnus@net-b.de> Vlad Burlik <vladbph@gmail.com> +Xi Qian <xi.qian@intel.com> Yuqiang Xian <yuqiang.xian@intel.com> Zaheer Ahmad <zahmad@codeaurora.org> Zhongping Wang <kewpie.w.zp@gmail.com> diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 7110aa83e3..52601a467e 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,310 @@ +2012-12-10: Version 3.15.11 + + Define CAN_USE_VFP2/3_INSTRUCTIONS based on arm_neon and arm_fpu GYP + flags. + + Performance and stability improvements on all platforms. + + +2012-12-07: Version 3.15.10 + + Enabled optimisation of functions inside eval. (issue 2315) + + Fixed spec violations in methods of Number.prototype. (issue 2443) + + Added GCTracer metrics for a scavenger GC for DOM wrappers. + + Performance and stability improvements on all platforms. + + +2012-12-06: Version 3.15.9 + + Fixed candidate eviction in code flusher. + (Chromium issue 159140) + + Iterate through all arguments for side effects in Math.min/max. + (issue 2444) + + Fixed spec violations related to regexp.lastIndex + (issue 2437, issue 2438) + + Performance and stability improvements on all platforms. + + +2012-12-04: Version 3.15.8 + + Enforced stack allocation of TryCatch blocks. + (issue 2166,chromium:152389) + + Fixed external exceptions in external try-catch handlers. + (issue 2166) + + Activated incremental code flushing by default. + + Performance and stability improvements on all platforms. + + +2012-11-30: Version 3.15.7 + + Activated code aging by default. + + Included more information in --prof log. + + Removed eager sweeping for lazy swept spaces. Try to find in + SlowAllocateRaw a bounded number of times a big enough memory slot. + (issue 2194) + + Performance and stability improvements on all platforms. + + +2012-11-26: Version 3.15.6 + + Ensure double arrays are filled with holes when extended from + variations of empty arrays. (Chromium issue 162085) + + Performance and stability improvements on all platforms. + + +2012-11-23: Version 3.15.5 + + Fixed JSON.stringify for objects with interceptor handlers. + (Chromium issue 161028) + + Fixed corner case in x64 compare stubs. (issue 2416) + + Performance and stability improvements on all platforms. + + +2012-11-16: Version 3.15.4 + + Fixed Array.prototype.join evaluation order. (issue 2263) + + Perform CPU sampling by CPU sampling thread only iff processing thread + is not running. (issue 2364) + + When using an Object as a set in Object.getOwnPropertyNames, null out + the proto. (issue 2410) + + Disabled EXTRA_CHECKS in Release build. + + Heap explorer: Show representation of strings. + + Removed 'type' and 'arguments' properties from Error object. + (issue 2397) + + Added atomics implementation for ThreadSanitizer v2. + (Chromium issue 128314) + + Fixed LiveEdit crashes when object/array literal is added. (issue 2368) + + Performance and stability improvements on all platforms. + + +2012-11-13: Version 3.15.3 + + Changed sample shell to send non-JS output (e.g. errors) to stderr + instead of stdout. + + Correctly check for stack overflow even when interrupt is pending. + (issue 214) + + Collect stack trace on stack overflow. (issue 2394) + + Performance and stability improvements on all platforms. + + +2012-11-12: Version 3.15.2 + + Function::GetScriptOrigin supplies sourceURL when script name is + not available. (Chromium issue 159413) + + Made formatting error message side-effect-free. (issue 2398) + + Fixed length check in JSON.stringify. (Chromium issue 160010) + + ES6: Added support for Set and Map clear method (issue 2400) + + Fixed slack tracking when instance prototype changes. + (Chromium issue 157019) + + Fixed disabling of code flusher while marking. (Chromium issue 159140) + + Added a test case for object grouping in a scavenger GC (issue 2077) + + Support shared library build of Android for v8. + (Chromium issue 158821) + + ES6: Added support for size to Set and Map (issue 2395) + + Performance and stability improvements on all platforms. + + +2012-11-06: Version 3.15.1 + + Put incremental code flushing behind a flag. (Chromium issue 159140) + + Performance and stability improvements on all platforms. + + +2012-10-31: Version 3.15.0 + + Loosened aligned code target requirement on ARM (issue 2380) + + Fixed JSON.parse to treat leading zeros correctly. + (Chromium issue 158185) + + Performance and stability improvements on all platforms. + + +2012-10-22: Version 3.14.5 + + Killed off the SCons based build. + + Added a faster API for creating v8::Integer objects. + + Speeded up function deoptimization by avoiding quadratic pass over + optimized function list. (Chromium issue 155270) + + Always invoke the default Array.sort functions from builtin functions. + (issue 2372) + + Reverted recent CPU profiler changes because they broke --prof. + (issue 2364) + + Switched code flushing to use different JSFunction field. + (issue 1609) + + Performance and stability improvements on all platforms. + + +2012-10-15: Version 3.14.4 + + Allow evals for debugger even if they are prohibited in the debugee + context. (Chromium issue 154733) + + Enabled --verify-heap in release mode (issue 2120) + + Performance and stability improvements on all platforms. + + +2012-10-11: Version 3.14.3 + + Use native context to retrieve ErrorMessageForCodeGenerationFromStrings + (Chromium issue 155076). + + Bumped variable limit further to 2^17 (Chromium issue 151625). + + Performance and stability improvements on all platforms. + + +2012-10-10: Version 3.14.2 + + ARM: allowed VFP3 instructions when hardfloat is enabled. + (Chromium issue 152506) + + Fixed instance_descriptors() and PushStackTraceAndDie regressions. + (Chromium issue 151749) + + Made GDBJIT interface compile again. (issue 1804) + + Fixed Accessors::FunctionGetPrototype's proto chain traversal. + (Chromium issue 143967) + + Made sure that names of temporaries do not clash with real variables. + (issue 2322) + + Rejected local module declarations. (Chromium issue 150628) + + Rejected uses of lexical for-loop variable on the RHS. (issue 2322) + + Fixed slot recording of code target patches. + (Chromium issue 152615,chromium:144230) + + Changed the Android makefile to use GCC 4.6 instead of GCC 4.4.3. + + Performance and stability improvements on all platforms. + + +2012-10-01: Version 3.14.1 + + Don't set -m32 flag when compiling with Android ARM compiler. + (Chromium issue 143889) + + Restore the descriptor array before returning allocation failure. + (Chromium issue 151750) + + Lowered kMaxVirtualRegisters (v8 issue 2139, Chromium issues 123822 and + 128252). + + Pull more recent gyp in 'make dependencies'. + + Made sure that the generic KeyedStoreIC changes length and element_kind + atomically (issue 2346). + + Bumped number of allowed variables per scope to 65535, to address GWT. + (Chromium issue 151625) + + Support sourceURL for dynamically inserted scripts (issue 2342). + + Performance and stability improvements on all platforms. + + +2012-09-20: Version 3.14.0 + + Fixed missing slot recording during clearing of CallICs. + (Chromium issue 144230) + + Fixed LBoundsCheck on x64 to handle (stack slot + constant) correctly. + (Chromium issue 150729) + + Fixed minus zero test. (Issue 2133) + + Fixed setting array length to zero for slow elements. + (Chromium issue 146910) + + Fixed lost arguments dropping in HLeaveInlined. + (Chromium issue 150545) + + Fixed casting error for receiver of interceptors. + (Chromium issue 149912) + + Throw a more descriptive exception when blocking 'eval' via CSP. + (Chromium issue 140191) + + Fixed debugger's eval when close to stack overflow. (issue 2318) + + Added checks to live edit. (issue 2297) + + Switched on code compaction on incremental GCs. + + Fixed caching of optimized code for OSR. (issue 2326) + + Not mask exception thrown by toString in String::UtfValue etc. + (issue 2317) + + Fixed API check for length of external arrays. (Chromium issue 148896) + + Ensure correct enumeration indices in the dict (Chromium issue 148376) + + Correctly initialize regexp global cache. (Chromium issue 148378) + + Fixed arguments object materialization during deopt. (issue 2261) + + Introduced new API to expose external string resource regardless of + encoding. + + Fixed CHECK failure in LCodeGen::DoWrapReceiver when + --deopt-every-n-times flag is present + (Chromium issue 148389) + + Fixed edge case of extension with NULL as source string. + (Chromium issue 144649) + + Fixed array index dehoisting. (Chromium issue 141395) + + Performance and stability improvements on all platforms. + + 2012-09-11: Version 3.13.7 Enable/disable LiveEdit using the (C++) debug API. diff --git a/deps/v8/DEPS b/deps/v8/DEPS index e50d1d20f6..8d66960f2d 100644 --- a/deps/v8/DEPS +++ b/deps/v8/DEPS @@ -5,7 +5,7 @@ deps = { # Remember to keep the revision in sync with the Makefile. "v8/build/gyp": - "http://gyp.googlecode.com/svn/trunk@1282", + "http://gyp.googlecode.com/svn/trunk@1501", } deps_os = { diff --git a/deps/v8/Makefile b/deps/v8/Makefile index f688f18b7c..b65ea4c9f9 100644 --- a/deps/v8/Makefile +++ b/deps/v8/Makefile @@ -24,14 +24,13 @@ # 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. -PYTHON ?= python # Variable default definitions. Override them by exporting them in your shell. CXX ?= g++ LINK ?= g++ OUTDIR ?= out -TESTJOBS ?= -j16 +TESTJOBS ?= GYPFLAGS ?= TESTFLAGS ?= ANDROID_NDK_ROOT ?= @@ -59,6 +58,10 @@ endif ifeq ($(objectprint), on) GYPFLAGS += -Dv8_object_print=1 endif +# verifyheap=on +ifeq ($(verifyheap), on) + GYPFLAGS += -Dv8_enable_verify_heap=1 +endif # snapshot=off ifeq ($(snapshot), off) GYPFLAGS += -Dv8_use_snapshot='false' @@ -80,9 +83,9 @@ ifeq ($(liveobjectlist), on) endif # vfp3=off ifeq ($(vfp3), off) - GYPFLAGS += -Dv8_can_use_vfp_instructions=false + GYPFLAGS += -Dv8_can_use_vfp3_instructions=false else - GYPFLAGS += -Dv8_can_use_vfp_instructions=true + GYPFLAGS += -Dv8_can_use_vfp3_instructions=true endif # debuggersupport=off ifeq ($(debuggersupport), off) @@ -113,8 +116,6 @@ ifeq ($(hardfp), on) GYPFLAGS += -Dv8_use_arm_eabi_hardfloat=true endif -GYPFLAGS += "-Dpython=$(PYTHON)" - # ----------------- available targets: -------------------- # - "dependencies": pulls in external dependencies (currently: GYP) # - any arch listed in ARCHES (see below) @@ -182,7 +183,7 @@ $(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()") \ + python -c "print raw_input().capitalize()") \ builddir="$(shell pwd)/$(OUTDIR)/$@" native: $(OUTDIR)/Makefile.native @@ -202,20 +203,20 @@ $(ANDROID_BUILDS): $(GYPFILES) $(ENVFILE) build/android.gypi \ # Test targets. check: all - @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \ + @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \ --arch=$(shell echo $(DEFAULT_ARCHES) | sed -e 's/ /,/g') \ $(TESTFLAGS) $(addsuffix .check,$(MODES)): $$(basename $$@) - @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \ + @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \ --mode=$(basename $@) $(TESTFLAGS) $(addsuffix .check,$(ARCHES)): $$(basename $$@) - @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \ + @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \ --arch=$(basename $@) $(TESTFLAGS) $(CHECKS): $$(basename $$@) - @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \ + @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \ --arch-and-mode=$(basename $@) $(TESTFLAGS) $(addsuffix .sync, $(ANDROID_BUILDS)): $$(basename $$@) @@ -223,16 +224,16 @@ $(addsuffix .sync, $(ANDROID_BUILDS)): $$(basename $$@) $(shell pwd) $(ANDROID_V8) $(addsuffix .check, $(ANDROID_BUILDS)): $$(basename $$@).sync - @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \ + @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \ --arch-and-mode=$(basename $@) \ --timeout=600 \ - --special-command="tools/android-run.py @" + --command-prefix="tools/android-run.py" $(addsuffix .check, $(ANDROID_ARCHES)): \ $(addprefix $$(basename $$@).,$(MODES)).check native.check: native - @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR)/native \ + @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR)/native \ --arch-and-mode=. $(TESTFLAGS) # Clean targets. You can clean each architecture individually, or everything. @@ -253,14 +254,14 @@ clean: $(addsuffix .clean, $(ARCHES) $(ANDROID_ARCHES)) native.clean OUT_MAKEFILES = $(addprefix $(OUTDIR)/Makefile.,$(ARCHES)) $(OUT_MAKEFILES): $(GYPFILES) $(ENVFILE) GYP_GENERATORS=make \ - $(PYTHON) build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ + build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ -Ibuild/standalone.gypi --depth=. \ -Dv8_target_arch=$(subst .,,$(suffix $@)) \ -S.$(subst .,,$(suffix $@)) $(GYPFLAGS) $(OUTDIR)/Makefile.native: $(GYPFILES) $(ENVFILE) GYP_GENERATORS=make \ - $(PYTHON) build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ + build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \ -Ibuild/standalone.gypi --depth=. -S.native $(GYPFLAGS) must-set-ANDROID_NDK_ROOT_OR_TOOLCHAIN: @@ -283,6 +284,7 @@ $(ENVFILE).new: echo "CXX=$(CXX)" >> $(ENVFILE).new # Dependencies. +# Remember to keep these in sync with the DEPS file. dependencies: svn checkout --force http://gyp.googlecode.com/svn/trunk build/gyp \ - --revision 1282 + --revision 1501 diff --git a/deps/v8/Makefile.android b/deps/v8/Makefile.android index a8d7fe148e..8e4ce0814a 100644 --- a/deps/v8/Makefile.android +++ b/deps/v8/Makefile.android @@ -48,11 +48,11 @@ endif ifeq ($(ARCH), android_arm) DEFINES = target_arch=arm v8_target_arch=arm android_target_arch=arm DEFINES += arm_neon=0 armv7=1 - TOOLCHAIN_ARCH = arm-linux-androideabi-4.4.3 + TOOLCHAIN_ARCH = arm-linux-androideabi-4.6 else ifeq ($(ARCH), android_ia32) DEFINES = target_arch=ia32 v8_target_arch=ia32 android_target_arch=x86 - TOOLCHAIN_ARCH = x86-4.4.3 + TOOLCHAIN_ARCH = x86-4.6 else $(error Target architecture "${ARCH}" is not supported) endif diff --git a/deps/v8/OWNERS b/deps/v8/OWNERS new file mode 100644 index 0000000000..941e5fe07d --- /dev/null +++ b/deps/v8/OWNERS @@ -0,0 +1,11 @@ +danno@chromium.org +jkummerow@chromium.org +mmassi@chromium.org +mstarzinger@chromium.org +mvstanton@chromium.org +rossberg@chromium.org +svenpanne@chromium.org +ulan@chromium.org +vegorov@chromium.org +verwaest@chromium.org +yangguo@chromium.org diff --git a/deps/v8/PRESUBMIT.py b/deps/v8/PRESUBMIT.py new file mode 100644 index 0000000000..0077be941a --- /dev/null +++ b/deps/v8/PRESUBMIT.py @@ -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. + +"""Top-level presubmit script for V8. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts +for more details about the presubmit API built into gcl. +""" + +def _V8PresubmitChecks(input_api, output_api): + """Runs the V8 presubmit checks.""" + import sys + sys.path.append(input_api.os_path.join( + input_api.PresubmitLocalPath(), 'tools')) + from presubmit import CppLintProcessor + from presubmit import SourceProcessor + + results = [] + if not CppLintProcessor().Run(input_api.PresubmitLocalPath()): + results.append(output_api.PresubmitError("C++ lint check failed")) + if not SourceProcessor().Run(input_api.PresubmitLocalPath()): + results.append(output_api.PresubmitError( + "Copyright header and trailing whitespaces check failed")) + return results + + +def _CommonChecks(input_api, output_api): + """Checks common to both upload and commit.""" + results = [] + results.extend(input_api.canned_checks.CheckOwners( + input_api, output_api, source_file_filter=None)) + return results + + +def CheckChangeOnUpload(input_api, output_api): + results = [] + results.extend(_CommonChecks(input_api, output_api)) + return results + + +def CheckChangeOnCommit(input_api, output_api): + results = [] + results.extend(_CommonChecks(input_api, output_api)) + results.extend(input_api.canned_checks.CheckChangeHasDescription( + input_api, output_api)) + results.extend(_V8PresubmitChecks(input_api, output_api)) + return results diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index ebce7ff892..5f8616a6b8 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -59,7 +59,7 @@ LIBRARY_FLAGS = { 'CPPDEFINES': ['V8_INTERPRETED_REGEXP'] }, 'mode:debug': { - 'CPPDEFINES': ['V8_ENABLE_CHECKS', 'OBJECT_PRINT'] + 'CPPDEFINES': ['V8_ENABLE_CHECKS', 'OBJECT_PRINT', 'VERIFY_HEAP'] }, 'objectprint:on': { 'CPPDEFINES': ['OBJECT_PRINT'], @@ -1157,6 +1157,11 @@ SIMPLE_OPTIONS = { 'default': 'on', 'help': 'use fpu instructions when building the snapshot [MIPS only]' }, + 'I_know_I_should_build_with_GYP': { + 'values': ['yes', 'no'], + 'default': 'no', + 'help': 'grace period: temporarily override SCons deprecation' + } } @@ -1257,7 +1262,35 @@ def IsLegal(env, option, values): return True +def WarnAboutDeprecation(): + print """ + ##################################################################### + # # + # LAST WARNING: Building V8 with SCons is deprecated. # + # # + # This only works because you have overridden the kill switch. # + # # + # MIGRATE TO THE GYP-BASED BUILD NOW! # + # # + # Instructions: http://code.google.com/p/v8/wiki/BuildingWithGYP. # + # # + ##################################################################### + """ + + def VerifyOptions(env): + if env['I_know_I_should_build_with_GYP'] != 'yes': + Abort("Building V8 with SCons is no longer supported. Please use GYP " + "instead; you can find instructions are at " + "http://code.google.com/p/v8/wiki/BuildingWithGYP.\n\n" + "Quitting.\n\n" + "For a limited grace period, you can specify " + "\"I_know_I_should_build_with_GYP=yes\" to override.") + else: + WarnAboutDeprecation() + import atexit + atexit.register(WarnAboutDeprecation) + if not IsLegal(env, 'mode', ['debug', 'release']): return False if not IsLegal(env, 'sample', ["shell", "process", "lineprocessor"]): @@ -1600,18 +1633,4 @@ try: 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/android.gypi b/deps/v8/build/android.gypi index d2d1a35726..67a9d35820 100644 --- a/deps/v8/build/android.gypi +++ b/deps/v8/build/android.gypi @@ -122,8 +122,6 @@ 'ldflags': [ '-nostdlib', '-Wl,--no-undefined', - # Don't export symbols from statically linked libraries. - '-Wl,--exclude-libs=ALL', ], 'libraries!': [ '-lrt', # librt is built into Bionic. @@ -219,6 +217,13 @@ ['_type=="shared_library"', { 'ldflags': [ '-Wl,-shared,-Bsymbolic', + '<(android_lib)/crtbegin_so.o', + ], + }], + ['_type=="static_library"', { + 'ldflags': [ + # Don't export symbols from statically linked libraries. + '-Wl,--exclude-libs=ALL', ], }], ], diff --git a/deps/v8/build/common.gypi b/deps/v8/build/common.gypi index 44cab4d0cb..e68ee15fde 100644 --- a/deps/v8/build/common.gypi +++ b/deps/v8/build/common.gypi @@ -43,7 +43,7 @@ # access is allowed for all CPUs. 'v8_can_use_unaligned_accesses%': 'default', - # Setting 'v8_can_use_vfp_instructions' to 'true' will enable use of ARM VFP + # Setting 'v8_can_use_vfp2_instructions' to 'true' will enable use of ARM VFP # instructions in the V8 generated code. VFP instructions will be enabled # both for the snapshot and for the ARM target. Leaving the default value # of 'false' will avoid VFP instructions in the snapshot and use CPU feature @@ -70,16 +70,15 @@ 'v8_enable_disassembler%': 0, - # Enable extra checks in API functions and other strategic places. - 'v8_enable_extra_checks%': 1, + 'v8_enable_gdbjit%': 0, 'v8_object_print%': 0, - 'v8_enable_gdbjit%': 0, - # Enable profiling support. Only required on Windows. 'v8_enable_prof%': 0, + 'v8_enable_verify_heap%': 0, + # Some versions of GCC 4.5 seem to need -fno-strict-aliasing. 'v8_no_strict_aliasing%': 0, @@ -103,9 +102,6 @@ # Interpreted regexp engine exists as platform-independent alternative # based where the regular expression is compiled to a bytecode. 'v8_interpreted_regexp%': 0, - - # Name of the python executable. - 'python%': 'python', }, 'target_defaults': { 'conditions': [ @@ -115,14 +111,14 @@ ['v8_enable_disassembler==1', { 'defines': ['ENABLE_DISASSEMBLER',], }], - ['v8_enable_extra_checks==1', { - 'defines': ['ENABLE_EXTRA_CHECKS',], + ['v8_enable_gdbjit==1', { + 'defines': ['ENABLE_GDB_JIT_INTERFACE',], }], ['v8_object_print==1', { 'defines': ['OBJECT_PRINT',], }], - ['v8_enable_gdbjit==1', { - 'defines': ['ENABLE_GDB_JIT_INTERFACE',], + ['v8_enable_verify_heap==1', { + 'defines': ['VERIFY_HEAP',], }], ['v8_interpreted_regexp==1', { 'defines': ['V8_INTERPRETED_REGEXP',], @@ -132,6 +128,11 @@ 'V8_TARGET_ARCH_ARM', ], 'conditions': [ + ['armv7==1', { + 'defines': [ + 'CAN_USE_ARMV7_INSTRUCTIONS=1', + ], + }], [ 'v8_can_use_unaligned_accesses=="true"', { 'defines': [ 'CAN_USE_UNALIGNED_ACCESSES=1', @@ -142,12 +143,16 @@ 'CAN_USE_UNALIGNED_ACCESSES=0', ], }], - [ 'v8_can_use_vfp2_instructions=="true"', { + # NEON implies VFP3 and VFP3 implies VFP2. + [ 'v8_can_use_vfp2_instructions=="true" or arm_neon==1 or \ + arm_fpu=="vfpv3" or arm_fpu=="vfpv3-d16"', { 'defines': [ 'CAN_USE_VFP2_INSTRUCTIONS', ], }], - [ 'v8_can_use_vfp3_instructions=="true"', { + # NEON implies VFP3. + [ 'v8_can_use_vfp3_instructions=="true" or arm_neon==1 or \ + arm_fpu=="vfpv3" or arm_fpu=="vfpv3-d16"', { 'defines': [ 'CAN_USE_VFP3_INSTRUCTIONS', ], @@ -198,10 +203,11 @@ ['mips_arch_variant=="mips32r2"', { 'cflags': ['-mips32r2', '-Wa,-mips32r2'], }], + ['mips_arch_variant=="mips32r1"', { + 'cflags': ['-mips32', '-Wa,-mips32'], + }], ['mips_arch_variant=="loongson"', { 'cflags': ['-mips3', '-Wa,-mips3'], - }, { - 'cflags': ['-mips32', '-Wa,-mips32'], }], ], }], @@ -274,7 +280,8 @@ }, }, }], - ['OS in "linux freebsd dragonflybsd openbsd solaris netbsd".split()', { + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \ + or OS=="netbsd"', { 'conditions': [ [ 'v8_no_strict_aliasing==1', { 'cflags': [ '-fno-strict-aliasing' ], @@ -284,8 +291,8 @@ ['OS=="solaris"', { 'defines': [ '__C99FEATURES__=1' ], # isinf() etc. }], - ['(OS=="linux" or OS=="freebsd" or OS=="dragonflybsd" or OS=="openbsd" \ - or OS=="solaris" or OS=="netbsd" or OS=="mac" or OS=="android") and \ + ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \ + or OS=="netbsd" or OS=="mac" or OS=="android") and \ (v8_target_arch=="arm" or v8_target_arch=="ia32" or \ v8_target_arch=="mipsel")', { # Check whether the host compiler and target compiler support the @@ -304,16 +311,21 @@ ['_toolset=="target"', { 'variables': { 'm32flag': '<!((echo | $(echo ${CXX_target:-${CXX:-$(which g++)}}) -m32 -E - > /dev/null 2>&1) && echo "-m32" || true)', + 'clang%': 0, }, - 'cflags': [ '<(m32flag)' ], - 'ldflags': [ '<(m32flag)' ], + 'conditions': [ + ['OS!="android" or clang==1', { + 'cflags': [ '<(m32flag)' ], + 'ldflags': [ '<(m32flag)' ], + }], + ], 'xcode_settings': { 'ARCHS': [ 'i386' ], }, }], ], }], - ['OS=="freebsd" or OS=="dragonflybsd" or OS=="openbsd"', { + ['OS=="freebsd" or OS=="openbsd"', { 'cflags': [ '-I/usr/local/include' ], }], ['OS=="netbsd"', { @@ -322,11 +334,15 @@ ], # conditions 'configurations': { 'Debug': { + 'variables': { + 'v8_enable_extra_checks%': 1, + }, 'defines': [ 'DEBUG', 'ENABLE_DISASSEMBLER', 'V8_ENABLE_CHECKS', 'OBJECT_PRINT', + 'VERIFY_HEAP', ], 'msvs_settings': { 'VCCLCompilerTool': { @@ -345,7 +361,10 @@ }, }, 'conditions': [ - ['OS in "linux freebsd dragonflybsd openbsd netbsd".split()', { + ['v8_enable_extra_checks==1', { + 'defines': ['ENABLE_EXTRA_CHECKS',], + }], + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', '-Wnon-virtual-dtor', '-Woverloaded-virtual' ], }], @@ -363,12 +382,32 @@ }], ], }], + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '0', # -O0 + }, + }], ], }, # Debug 'Release': { + 'variables': { + 'v8_enable_extra_checks%': 0, + }, 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="dragonflybsd" \ - or OS=="openbsd" or OS=="netbsd" or OS=="android"', { + ['v8_enable_extra_checks==1', { + 'defines': ['ENABLE_EXTRA_CHECKS',], + }], + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" \ + or OS=="android"', { + 'cflags!': [ + '-O2', + '-Os', + ], + 'cflags': [ + '-fdata-sections', + '-ffunction-sections', + '-O3', + ], 'conditions': [ [ 'gcc_version==44 and clang==0', { 'cflags': [ diff --git a/deps/v8/build/standalone.gypi b/deps/v8/build/standalone.gypi index e6c7088997..7145a16e0c 100644 --- a/deps/v8/build/standalone.gypi +++ b/deps/v8/build/standalone.gypi @@ -38,7 +38,8 @@ 'variables': { 'variables': { 'conditions': [ - ['OS!="win"', { + ['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 @@ -46,8 +47,9 @@ 'host_arch%': '<!(uname -m | sed -e "s/i.86/ia32/;\ s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/;s/mips.*/mipsel/")', - }], - ['OS=="win"', { + }, { + # OS!="linux" and OS!="freebsd" and OS!="openbsd" and + # OS!="netbsd" and OS!="mac" 'host_arch%': 'ia32', }], ], @@ -87,7 +89,8 @@ }, }, 'conditions': [ - ['OS!="win"', { + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \ + or OS=="netbsd"', { 'target_defaults': { 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', '-Wnon-virtual-dtor', '-pthread', '-fno-rtti', @@ -106,6 +109,8 @@ ], }, }], + # 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" + # or OS=="netbsd"' ['OS=="win"', { 'target_defaults': { 'defines': [ diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index c1e9a9e0b8..4d3597ac75 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -407,13 +407,28 @@ class V8EXPORT HeapProfiler { static const SnapshotObjectId kUnknownObjectId = 0; /** + * Callback interface for retrieving user friendly names of global objects. + */ + class ObjectNameResolver { + public: + /** + * Returns name to be used in the heap snapshot for given node. Returned + * string must stay alive until snapshot collection is completed. + */ + virtual const char* GetName(Handle<Object> object) = 0; + protected: + virtual ~ObjectNameResolver() {} + }; + + /** * Takes a heap snapshot and returns it. Title may be an empty string. * See HeapSnapshot::Type for types description. */ static const HeapSnapshot* TakeSnapshot( Handle<String> title, HeapSnapshot::Type type = HeapSnapshot::kFull, - ActivityControl* control = NULL); + ActivityControl* control = NULL, + ObjectNameResolver* global_object_name_resolver = NULL); /** * Starts tracking of heap objects population statistics. After calling diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index ddde388cd4..f577e937a5 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -76,6 +76,22 @@ #endif // _WIN32 +#if defined(__GNUC__) && !defined(DEBUG) +#define V8_INLINE(declarator) inline __attribute__((always_inline)) declarator +#elif defined(_MSC_VER) && !defined(DEBUG) +#define V8_INLINE(declarator) __forceinline declarator +#else +#define V8_INLINE(declarator) inline declarator +#endif + +#if defined(__GNUC__) && !V8_DISABLE_DEPRECATIONS +#define V8_DEPRECATED(declarator) declarator __attribute__ ((deprecated)) +#elif defined(_MSC_VER) && !V8_DISABLE_DEPRECATIONS +#define V8_DEPRECATED(declarator) __declspec(deprecated) declarator +#else +#define V8_DEPRECATED(declarator) declarator +#endif + /** * The v8 JavaScript engine. */ @@ -176,12 +192,12 @@ template <class T> class Handle { /** * Creates an empty handle. */ - inline Handle() : val_(0) {} + V8_INLINE(Handle()) : val_(0) {} /** * Creates a new handle for the specified value. */ - inline explicit Handle(T* val) : val_(val) {} + V8_INLINE(explicit Handle(T* val)) : val_(val) {} /** * Creates a handle for the contents of the specified handle. This @@ -193,7 +209,7 @@ template <class T> class Handle { * Handle<String> to a variable declared as Handle<Value>, is legal * because String is a subclass of Value. */ - template <class S> inline Handle(Handle<S> that) + template <class S> V8_INLINE(Handle(Handle<S> that)) : val_(reinterpret_cast<T*>(*that)) { /** * This check fails when trying to convert between incompatible @@ -206,16 +222,16 @@ template <class T> class Handle { /** * Returns true if the handle is empty. */ - inline bool IsEmpty() const { return val_ == 0; } + V8_INLINE(bool IsEmpty() const) { return val_ == 0; } /** * Sets the handle to be empty. IsEmpty() will then return true. */ - inline void Clear() { val_ = 0; } + V8_INLINE(void Clear()) { val_ = 0; } - inline T* operator->() const { return val_; } + V8_INLINE(T* operator->() const) { return val_; } - inline T* operator*() const { return val_; } + V8_INLINE(T* operator*() const) { return val_; } /** * Checks whether two handles are the same. @@ -223,7 +239,7 @@ template <class T> class Handle { * to which they refer are identical. * The handles' references are not checked. */ - template <class S> inline bool operator==(Handle<S> that) const { + template <class S> V8_INLINE(bool operator==(Handle<S> that) const) { internal::Object** a = reinterpret_cast<internal::Object**>(**this); internal::Object** b = reinterpret_cast<internal::Object**>(*that); if (a == 0) return b == 0; @@ -237,11 +253,11 @@ template <class T> class Handle { * the objects to which they refer are different. * The handles' references are not checked. */ - template <class S> inline bool operator!=(Handle<S> that) const { + template <class S> V8_INLINE(bool operator!=(Handle<S> that) const) { return !operator==(that); } - template <class S> static inline Handle<T> Cast(Handle<S> that) { + template <class S> V8_INLINE(static Handle<T> Cast(Handle<S> that)) { #ifdef V8_ENABLE_CHECKS // If we're going to perform the type check then we have to check // that the handle isn't empty before doing the checked cast. @@ -250,7 +266,7 @@ template <class T> class Handle { return Handle<T>(T::Cast(*that)); } - template <class S> inline Handle<S> As() { + template <class S> V8_INLINE(Handle<S> As()) { return Handle<S>::Cast(*this); } @@ -268,8 +284,8 @@ template <class T> class Handle { */ template <class T> class Local : public Handle<T> { public: - inline Local(); - template <class S> inline Local(Local<S> that) + V8_INLINE(Local()); + template <class S> V8_INLINE(Local(Local<S> that)) : Handle<T>(reinterpret_cast<T*>(*that)) { /** * This check fails when trying to convert between incompatible @@ -278,8 +294,8 @@ template <class T> class Local : public Handle<T> { */ TYPE_CHECK(T, S); } - template <class S> inline Local(S* that) : Handle<T>(that) { } - template <class S> static inline Local<T> Cast(Local<S> that) { + template <class S> V8_INLINE(Local(S* that) : Handle<T>(that)) { } + template <class S> V8_INLINE(static Local<T> Cast(Local<S> that)) { #ifdef V8_ENABLE_CHECKS // If we're going to perform the type check then we have to check // that the handle isn't empty before doing the checked cast. @@ -288,15 +304,17 @@ template <class T> class Local : public Handle<T> { return Local<T>(T::Cast(*that)); } - template <class S> inline Local<S> As() { + template <class S> V8_INLINE(Local<S> As()) { return Local<S>::Cast(*this); } - /** Create a local handle for the content of another handle. - * The referee is kept alive by the local handle even when - * the original handle is destroyed/disposed. + /** + * Create a local handle for the content of another handle. + * The referee is kept alive by the local handle even when + * the original handle is destroyed/disposed. */ - inline static Local<T> New(Handle<T> that); + V8_INLINE(static Local<T> New(Handle<T> that)); + V8_INLINE(static Local<T> New(Isolate* isolate, Handle<T> that)); }; @@ -323,7 +341,7 @@ template <class T> class Persistent : public Handle<T> { * Creates an empty persistent handle that doesn't point to any * storage cell. */ - inline Persistent(); + V8_INLINE(Persistent()); /** * Creates a persistent handle for the same storage cell as the @@ -336,7 +354,7 @@ template <class T> class Persistent : public Handle<T> { * Persistent<String> to a variable declared as Persistent<Value>, * is allowed as String is a subclass of Value. */ - template <class S> inline Persistent(Persistent<S> that) + template <class S> V8_INLINE(Persistent(Persistent<S> that)) : Handle<T>(reinterpret_cast<T*>(*that)) { /** * This check fails when trying to convert between incompatible @@ -346,16 +364,16 @@ template <class T> class Persistent : public Handle<T> { TYPE_CHECK(T, S); } - template <class S> inline Persistent(S* that) : Handle<T>(that) { } + template <class S> V8_INLINE(Persistent(S* that)) : Handle<T>(that) { } /** * "Casts" a plain handle which is known to be a persistent handle * to a persistent handle. */ - template <class S> explicit inline Persistent(Handle<S> that) + template <class S> explicit V8_INLINE(Persistent(Handle<S> that)) : Handle<T>(*that) { } - template <class S> static inline Persistent<T> Cast(Persistent<S> that) { + template <class S> V8_INLINE(static Persistent<T> Cast(Persistent<S> that)) { #ifdef V8_ENABLE_CHECKS // If we're going to perform the type check then we have to check // that the handle isn't empty before doing the checked cast. @@ -364,7 +382,7 @@ template <class T> class Persistent : public Handle<T> { return Persistent<T>(T::Cast(*that)); } - template <class S> inline Persistent<S> As() { + template <class S> V8_INLINE(Persistent<S> As()) { return Persistent<S>::Cast(*this); } @@ -372,7 +390,7 @@ template <class T> class Persistent : public Handle<T> { * Creates a new persistent handle for an existing local or * persistent handle. */ - inline static Persistent<T> New(Handle<T> that); + V8_INLINE(static Persistent<T> New(Handle<T> that)); /** * Releases the storage cell referenced by this persistent handle. @@ -380,7 +398,8 @@ template <class T> class Persistent : public Handle<T> { * This handle's reference, and any other references to the storage * cell remain and IsEmpty will still return false. */ - inline void Dispose(); + V8_INLINE(void Dispose()); + V8_INLINE(void Dispose(Isolate* isolate)); /** * Make the reference to this object weak. When only weak handles @@ -388,10 +407,13 @@ template <class T> class Persistent : public Handle<T> { * callback to the given V8::WeakReferenceCallback function, passing * it the object reference and the given parameters. */ - inline void MakeWeak(void* parameters, WeakReferenceCallback callback); + V8_INLINE(void MakeWeak(void* parameters, WeakReferenceCallback callback)); + V8_INLINE(void MakeWeak(Isolate* isolate, + void* parameters, + WeakReferenceCallback callback)); - /** Clears the weak reference to this object.*/ - inline void ClearWeak(); + /** Clears the weak reference to this object. */ + V8_INLINE(void ClearWeak()); /** * Marks the reference to this object independent. Garbage collector @@ -400,23 +422,42 @@ template <class T> class Persistent : public Handle<T> { * assume that it will be preceded by a global GC prologue callback * or followed by a global GC epilogue callback. */ - inline void MarkIndependent(); + V8_INLINE(void MarkIndependent()); + V8_INLINE(void MarkIndependent(Isolate* isolate)); /** - *Checks if the handle holds the only reference to an object. + * Marks the reference to this object partially dependent. Partially + * dependent handles only depend on other partially dependent handles and + * these dependencies are provided through object groups. It provides a way + * to build smaller object groups for young objects that represent only a + * subset of all external dependencies. This mark is automatically cleared + * after each garbage collection. */ - inline bool IsNearDeath() const; + V8_INLINE(void MarkPartiallyDependent()); + V8_INLINE(void MarkPartiallyDependent(Isolate* isolate)); - /** - * Returns true if the handle's reference is weak. - */ - inline bool IsWeak() const; + /** Returns true if this handle was previously marked as independent. */ + V8_INLINE(bool IsIndependent() const); + V8_INLINE(bool IsIndependent(Isolate* isolate) const); + + /** Checks if the handle holds the only reference to an object. */ + V8_INLINE(bool IsNearDeath() const); + + /** Returns true if the handle's reference is weak. */ + V8_INLINE(bool IsWeak() const); + V8_INLINE(bool IsWeak(Isolate* isolate) const); /** * Assigns a wrapper class ID to the handle. See RetainedObjectInfo * interface description in v8-profiler.h for details. */ - inline void SetWrapperClassId(uint16_t class_id); + V8_INLINE(void SetWrapperClassId(uint16_t class_id)); + + /** + * Returns the class ID previously assigned to this handle or 0 if no class + * ID was previously assigned. + */ + V8_INLINE(uint16_t WrapperClassId() const); private: friend class ImplementationUtilities; @@ -459,12 +500,14 @@ class V8EXPORT HandleScope { * Creates a new handle with the given value. */ static internal::Object** CreateHandle(internal::Object* value); + static internal::Object** CreateHandle(internal::Isolate* isolate, + internal::Object* value); // Faster version, uses HeapObject to obtain the current Isolate. static internal::Object** CreateHandle(internal::HeapObject* value); private: - // Make it impossible to create heap-allocated or illegal handle - // scopes by disallowing certain operations. + // Make it hard to create heap-allocated or illegal handle scopes by + // disallowing certain operations. HandleScope(const HandleScope&); void operator=(const HandleScope&); void* operator new(size_t size); @@ -477,7 +520,7 @@ class V8EXPORT HandleScope { internal::Object** next; internal::Object** limit; int level; - inline void Initialize() { + V8_INLINE(void Initialize()) { next = limit = NULL; level = 0; } @@ -570,16 +613,16 @@ class V8EXPORT ScriptData { // NOLINT */ class ScriptOrigin { public: - inline ScriptOrigin( + V8_INLINE(ScriptOrigin( Handle<Value> resource_name, Handle<Integer> resource_line_offset = Handle<Integer>(), - Handle<Integer> resource_column_offset = Handle<Integer>()) + Handle<Integer> resource_column_offset = Handle<Integer>())) : resource_name_(resource_name), resource_line_offset_(resource_line_offset), resource_column_offset_(resource_column_offset) { } - inline Handle<Value> ResourceName() const; - inline Handle<Integer> ResourceLineOffset() const; - inline Handle<Integer> ResourceColumnOffset() const; + V8_INLINE(Handle<Value> ResourceName() const); + V8_INLINE(Handle<Integer> ResourceLineOffset() const); + V8_INLINE(Handle<Integer> ResourceColumnOffset() const); private: Handle<Value> resource_name_; Handle<Integer> resource_line_offset_; @@ -867,13 +910,13 @@ class Value : public Data { * Returns true if this value is the undefined value. See ECMA-262 * 4.3.10. */ - inline bool IsUndefined() const; + V8_INLINE(bool IsUndefined() const); /** * Returns true if this value is the null value. See ECMA-262 * 4.3.11. */ - inline bool IsNull() const; + V8_INLINE(bool IsNull() const); /** * Returns true if this value is true. @@ -889,7 +932,7 @@ class Value : public Data { * Returns true if this value is an instance of the String type. * See ECMA-262 8.4. */ - inline bool IsString() const; + V8_INLINE(bool IsString() const); /** * Returns true if this value is a function. @@ -987,9 +1030,9 @@ class Value : public Data { V8EXPORT bool StrictEquals(Handle<Value> that) const; private: - inline bool QuickIsUndefined() const; - inline bool QuickIsNull() const; - inline bool QuickIsString() const; + V8_INLINE(bool QuickIsUndefined() const); + V8_INLINE(bool QuickIsNull() const); + V8_INLINE(bool QuickIsString() const); V8EXPORT bool FullIsUndefined() const; V8EXPORT bool FullIsNull() const; V8EXPORT bool FullIsString() const; @@ -1009,7 +1052,7 @@ class Primitive : public Value { }; class Boolean : public Primitive { public: V8EXPORT bool Value() const; - static inline Handle<Boolean> New(bool value); + V8_INLINE(static Handle<Boolean> New(bool value)); }; @@ -1018,6 +1061,11 @@ class Boolean : public Primitive { */ class String : public Primitive { public: + enum Encoding { + UNKNOWN_ENCODING = 0x1, + TWO_BYTE_ENCODING = 0x0, + ASCII_ENCODING = 0x4 + }; /** * Returns the number of characters in this string. */ @@ -1089,7 +1137,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); + V8_INLINE(static v8::Local<v8::String> Empty(Isolate* isolate)); /** * Returns true if the string is external @@ -1181,10 +1229,18 @@ class String : public Primitive { }; /** + * If the string is an external string, return the ExternalStringResourceBase + * regardless of the encoding, otherwise return NULL. The encoding of the + * string is returned in encoding_out. + */ + V8_INLINE(ExternalStringResourceBase* GetExternalStringResourceBase( + Encoding* encoding_out) const); + + /** * Get the ExternalStringResource for an external string. Returns * NULL if IsExternal() doesn't return true. */ - inline ExternalStringResource* GetExternalStringResource() const; + V8_INLINE(ExternalStringResource* GetExternalStringResource() const); /** * Get the ExternalAsciiStringResource for an external ASCII string. @@ -1193,7 +1249,7 @@ class String : public Primitive { V8EXPORT const ExternalAsciiStringResource* GetExternalAsciiStringResource() const; - static inline String* Cast(v8::Value* obj); + V8_INLINE(static String* Cast(v8::Value* obj)); /** * Allocates a new string from either UTF-8 encoded or ASCII data. @@ -1343,6 +1399,8 @@ class String : public Primitive { }; private: + V8EXPORT void VerifyExternalStringResourceBase(ExternalStringResourceBase* v, + Encoding encoding) const; V8EXPORT void VerifyExternalStringResource(ExternalStringResource* val) const; V8EXPORT static void CheckCast(v8::Value* obj); }; @@ -1355,7 +1413,7 @@ class Number : public Primitive { public: V8EXPORT double Value() const; V8EXPORT static Local<Number> New(double value); - static inline Number* Cast(v8::Value* obj); + V8_INLINE(static Number* Cast(v8::Value* obj)); private: V8EXPORT Number(); V8EXPORT static void CheckCast(v8::Value* obj); @@ -1369,8 +1427,10 @@ class Integer : public Number { public: V8EXPORT static Local<Integer> New(int32_t value); V8EXPORT static Local<Integer> NewFromUnsigned(uint32_t value); + V8EXPORT static Local<Integer> New(int32_t value, Isolate*); + V8EXPORT static Local<Integer> NewFromUnsigned(uint32_t value, Isolate*); V8EXPORT int64_t Value() const; - static inline Integer* Cast(v8::Value* obj); + V8_INLINE(static Integer* Cast(v8::Value* obj)); private: V8EXPORT Integer(); V8EXPORT static void CheckCast(v8::Value* obj); @@ -1565,16 +1625,42 @@ class Object : public Value { /** Gets the number of internal fields for this Object. */ V8EXPORT int InternalFieldCount(); - /** Gets the value in an internal field. */ - inline Local<Value> GetInternalField(int index); + + /** Gets the value from an internal field. */ + V8_INLINE(Local<Value> GetInternalField(int index)); + /** Sets the value in an internal field. */ V8EXPORT void SetInternalField(int index, Handle<Value> value); - /** Gets a native pointer from an internal field. */ - inline void* GetPointerFromInternalField(int index); + /** + * Gets a native pointer from an internal field. Deprecated. If the pointer is + * always 2-byte-aligned, use GetAlignedPointerFromInternalField instead, + * otherwise use a combination of GetInternalField, External::Cast and + * External::Value. + */ + V8EXPORT V8_DEPRECATED(void* GetPointerFromInternalField(int index)); + + /** + * Sets a native pointer in an internal field. Deprecated. If the pointer is + * always 2-byte aligned, use SetAlignedPointerInInternalField instead, + * otherwise use a combination of External::New and SetInternalField. + */ + V8_DEPRECATED(V8_INLINE(void SetPointerInInternalField(int index, + void* value))); + + /** + * Gets a 2-byte-aligned native pointer from an internal field. This field + * must have been set by SetAlignedPointerInInternalField, everything else + * leads to undefined behavior. + */ + V8_INLINE(void* GetAlignedPointerFromInternalField(int index)); - /** Sets a native pointer in an internal field. */ - V8EXPORT void SetPointerInInternalField(int index, void* value); + /** + * Sets a 2-byte-aligned native pointer in an internal field. To retrieve such + * a field, GetAlignedPointerFromInternalField must be used, everything else + * leads to undefined behavior. + */ + V8EXPORT void SetAlignedPointerInInternalField(int index, void* value); // Testers for local properties. V8EXPORT bool HasOwnProperty(Handle<String> key); @@ -1700,19 +1786,13 @@ class Object : public Value { Handle<Value> argv[]); V8EXPORT static Local<Object> New(); - static inline Object* Cast(Value* obj); + V8_INLINE(static Object* Cast(Value* obj)); private: V8EXPORT Object(); V8EXPORT static void CheckCast(Value* obj); - V8EXPORT Local<Value> CheckedGetInternalField(int index); - V8EXPORT void* SlowGetPointerFromInternalField(int index); - - /** - * If quick access to the internal field is possible this method - * returns the value. Otherwise an empty handle is returned. - */ - inline Local<Value> UncheckedGetInternalField(int index); + V8EXPORT Local<Value> SlowGetInternalField(int index); + V8EXPORT void* SlowGetAlignedPointerFromInternalField(int index); }; @@ -1735,7 +1815,7 @@ class Array : public Object { */ V8EXPORT static Local<Array> New(int length = 0); - static inline Array* Cast(Value* obj); + V8_INLINE(static Array* Cast(Value* obj)); private: V8EXPORT Array(); V8EXPORT static void CheckCast(Value* obj); @@ -1775,7 +1855,7 @@ class Function : public Object { V8EXPORT int GetScriptColumnNumber() const; V8EXPORT Handle<Value> GetScriptId() const; V8EXPORT ScriptOrigin GetScriptOrigin() const; - static inline Function* Cast(Value* obj); + V8_INLINE(static Function* Cast(Value* obj)); V8EXPORT static const int kLineOffsetNotFound; private: @@ -1797,7 +1877,7 @@ class Date : public Object { */ V8EXPORT double NumberValue() const; - static inline Date* Cast(v8::Value* obj); + V8_INLINE(static Date* Cast(v8::Value* obj)); /** * Notification that the embedder has changed the time zone, @@ -1830,7 +1910,7 @@ class NumberObject : public Object { */ V8EXPORT double NumberValue() const; - static inline NumberObject* Cast(v8::Value* obj); + V8_INLINE(static NumberObject* Cast(v8::Value* obj)); private: V8EXPORT static void CheckCast(v8::Value* obj); @@ -1849,7 +1929,7 @@ class BooleanObject : public Object { */ V8EXPORT bool BooleanValue() const; - static inline BooleanObject* Cast(v8::Value* obj); + V8_INLINE(static BooleanObject* Cast(v8::Value* obj)); private: V8EXPORT static void CheckCast(v8::Value* obj); @@ -1868,7 +1948,7 @@ class StringObject : public Object { */ V8EXPORT Local<String> StringValue() const; - static inline StringObject* Cast(v8::Value* obj); + V8_INLINE(static StringObject* Cast(v8::Value* obj)); private: V8EXPORT static void CheckCast(v8::Value* obj); @@ -1915,7 +1995,7 @@ class RegExp : public Object { */ V8EXPORT Flags GetFlags() const; - static inline RegExp* Cast(v8::Value* obj); + V8_INLINE(static RegExp* Cast(v8::Value* obj)); private: V8EXPORT static void CheckCast(v8::Value* obj); @@ -1923,29 +2003,22 @@ class RegExp : public Object { /** - * A JavaScript value that wraps a C++ void*. This type of value is - * mainly used to associate C++ data structures with JavaScript - * objects. - * - * The Wrap function V8 will return the most optimal Value object wrapping the - * C++ void*. The type of the value is not guaranteed to be an External object - * and no assumptions about its type should be made. To access the wrapped - * value Unwrap should be used, all other operations on that object will lead - * to unpredictable results. + * A JavaScript value that wraps a C++ void*. This type of value is mainly used + * to associate C++ data structures with JavaScript objects. */ class External : public Value { public: - V8EXPORT static Local<Value> Wrap(void* data); - static inline void* Unwrap(Handle<Value> obj); + /** Deprecated, use New instead. */ + V8_DEPRECATED(V8_INLINE(static Local<Value> Wrap(void* value))); + + /** Deprecated, use a combination of Cast and Value instead. */ + V8_DEPRECATED(V8_INLINE(static void* Unwrap(Handle<Value> obj))); V8EXPORT static Local<External> New(void* value); - static inline External* Cast(Value* obj); + V8_INLINE(static External* Cast(Value* obj)); V8EXPORT void* Value() const; private: - V8EXPORT External(); V8EXPORT static void CheckCast(v8::Value* obj); - static inline void* QuickUnwrap(Handle<v8::Value> obj); - V8EXPORT static void* FullUnwrap(Handle<v8::Value> obj); }; @@ -1960,7 +2033,7 @@ class V8EXPORT Template : public Data { /** Adds a property to each instance created by this template.*/ void Set(Handle<String> name, Handle<Data> value, PropertyAttribute attributes = None); - inline void Set(const char* name, Handle<Data> value); + V8_INLINE(void Set(const char* name, Handle<Data> value)); private: Template(); @@ -1977,14 +2050,14 @@ class V8EXPORT Template : public Data { */ class Arguments { public: - inline int Length() const; - inline Local<Value> operator[](int i) const; - inline Local<Function> Callee() const; - inline Local<Object> This() const; - inline Local<Object> Holder() const; - inline bool IsConstructCall() const; - inline Local<Value> Data() const; - inline Isolate* GetIsolate() const; + V8_INLINE(int Length() const); + V8_INLINE(Local<Value> operator[](int i) const); + V8_INLINE(Local<Function> Callee() const); + V8_INLINE(Local<Object> This() const); + V8_INLINE(Local<Object> Holder() const); + V8_INLINE(bool IsConstructCall() const); + V8_INLINE(Local<Value> Data() const); + V8_INLINE(Isolate* GetIsolate() const); private: static const int kIsolateIndex = 0; @@ -1993,10 +2066,10 @@ class Arguments { static const int kHolderIndex = -3; friend class ImplementationUtilities; - inline Arguments(internal::Object** implicit_args, + V8_INLINE(Arguments(internal::Object** implicit_args, internal::Object** values, int length, - bool is_construct_call); + bool is_construct_call)); internal::Object** implicit_args_; internal::Object** values_; int length_; @@ -2010,12 +2083,12 @@ class Arguments { */ class V8EXPORT AccessorInfo { public: - inline AccessorInfo(internal::Object** args) + V8_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; + V8_INLINE(Isolate* GetIsolate() const); + V8_INLINE(Local<Value> Data() const); + V8_INLINE(Local<Object> This() const); + V8_INLINE(Local<Object> Holder() const); private: internal::Object** args_; @@ -2580,7 +2653,7 @@ void V8EXPORT RegisterExtension(Extension* extension); */ class V8EXPORT DeclareExtension { public: - inline DeclareExtension(Extension* extension) { + V8_INLINE(DeclareExtension(Extension* extension)) { RegisterExtension(extension); } }; @@ -2594,10 +2667,10 @@ 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); +V8_INLINE(Handle<Primitive> Undefined(Isolate* isolate)); +V8_INLINE(Handle<Primitive> Null(Isolate* isolate)); +V8_INLINE(Handle<Boolean> True(Isolate* isolate)); +V8_INLINE(Handle<Boolean> False(Isolate* isolate)); /** @@ -2638,7 +2711,7 @@ bool V8EXPORT SetResourceConstraints(ResourceConstraints* constraints); typedef void (*FatalErrorCallback)(const char* location, const char* message); -typedef void (*MessageCallback)(Handle<Message> message, Handle<Value> data); +typedef void (*MessageCallback)(Handle<Message> message, Handle<Value> error); /** @@ -2751,6 +2824,7 @@ class V8EXPORT HeapStatistics { HeapStatistics(); size_t total_heap_size() { return total_heap_size_; } size_t total_heap_size_executable() { return total_heap_size_executable_; } + size_t total_physical_size() { return total_physical_size_; } size_t used_heap_size() { return used_heap_size_; } size_t heap_size_limit() { return heap_size_limit_; } @@ -2759,11 +2833,15 @@ class V8EXPORT HeapStatistics { void set_total_heap_size_executable(size_t size) { total_heap_size_executable_ = size; } + void set_total_physical_size(size_t size) { + total_physical_size_ = size; + } void set_used_heap_size(size_t size) { used_heap_size_ = size; } void set_heap_size_limit(size_t size) { heap_size_limit_ = size; } size_t total_heap_size_; size_t total_heap_size_executable_; + size_t total_physical_size_; size_t used_heap_size_; size_t heap_size_limit_; @@ -2849,13 +2927,13 @@ class V8EXPORT Isolate { /** * Associate embedder-specific data with the isolate */ - inline void SetData(void* data); + V8_INLINE(void SetData(void* data)); /** * Retrieve embedder-specific data from the isolate. * Returns NULL if SetData has never been called. */ - inline void* GetData(); + V8_INLINE(void* GetData()); private: Isolate(); @@ -2996,7 +3074,7 @@ typedef void (*JitCodeEventHandler)(const JitCodeEvent* event); /** - * Interface for iterating though all external resources in the heap. + * Interface for iterating through all external resources in the heap. */ class V8EXPORT ExternalResourceVisitor { // NOLINT public: @@ -3006,6 +3084,17 @@ class V8EXPORT ExternalResourceVisitor { // NOLINT /** + * Interface for iterating through all the persistent handles in the heap. + */ +class V8EXPORT PersistentHandleVisitor { // NOLINT + public: + virtual ~PersistentHandleVisitor() {} + virtual void VisitPersistentHandle(Persistent<Value> value, + uint16_t class_id) {} +}; + + +/** * Container class for static utility functions. */ class V8EXPORT V8 { @@ -3070,8 +3159,7 @@ class V8EXPORT V8 { * The same message listener can be added more than once and in that * case it will be called more than once for each message. */ - static bool AddMessageListener(MessageCallback that, - Handle<Value> data = Handle<Value>()); + static bool AddMessageListener(MessageCallback that); /** * Remove all message listeners from the specified callback function. @@ -3117,12 +3205,6 @@ class V8EXPORT V8 { static void SetCreateHistogramFunction(CreateHistogramCallback); static void SetAddHistogramSampleFunction(AddHistogramSampleCallback); - /** - * Enables the computation of a sliding window of states. The sliding - * window information is recorded in statistics counters. - */ - static void EnableSlidingStateWindow(); - /** Callback function for reporting failed access checks.*/ static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback); @@ -3217,12 +3299,19 @@ class V8EXPORT V8 { * After each garbage collection, object groups are removed. It is * intended to be used in the before-garbage-collection callback * function, for instance to simulate DOM tree connections among JS - * wrapper objects. + * wrapper objects. Object groups for all dependent handles need to + * be provided for kGCTypeMarkSweepCompact collections, for all other + * garbage collection types it is sufficient to provide object groups + * for partially dependent handles only. * See v8-profiler.h for RetainedObjectInfo interface description. */ static void AddObjectGroup(Persistent<Value>* objects, size_t length, RetainedObjectInfo* info = NULL); + static void AddObjectGroup(Isolate* isolate, + Persistent<Value>* objects, + size_t length, + RetainedObjectInfo* info = NULL); /** * Allows the host application to declare implicit references between @@ -3407,12 +3496,18 @@ class V8EXPORT V8 { /** * Iterates through all external resources referenced from current isolate - * heap. This method is not expected to be used except for debugging purposes - * and may be quite slow. + * heap. GC is not invoked prior to iterating, therefore there is no + * guarantee that visited objects are still alive. */ static void VisitExternalResources(ExternalResourceVisitor* visitor); /** + * Iterates through all the persistent handles in the current isolate's heap + * that have class_ids. + */ + static void VisitHandlesWithClassIds(PersistentHandleVisitor* visitor); + + /** * Optional notification that the embedder is idle. * V8 uses the notification to reduce memory footprint. * This call can be used repeatedly if the embedder remains idle. @@ -3445,15 +3540,32 @@ class V8EXPORT V8 { static internal::Object** GlobalizeReference(internal::Object** handle); static void DisposeGlobal(internal::Object** global_handle); + static void DisposeGlobal(internal::Isolate* isolate, + internal::Object** global_handle); static void MakeWeak(internal::Object** global_handle, void* data, WeakReferenceCallback); + static void MakeWeak(internal::Isolate* isolate, + internal::Object** global_handle, + void* data, + WeakReferenceCallback); static void ClearWeak(internal::Object** global_handle); static void MarkIndependent(internal::Object** global_handle); + static void MarkIndependent(internal::Isolate* isolate, + internal::Object** global_handle); + static void MarkPartiallyDependent(internal::Object** global_handle); + static void MarkPartiallyDependent(internal::Isolate* isolate, + internal::Object** global_handle); + static bool IsGlobalIndependent(internal::Object** global_handle); + static bool IsGlobalIndependent(internal::Isolate* isolate, + internal::Object** global_handle); static bool IsGlobalNearDeath(internal::Object** global_handle); static bool IsGlobalWeak(internal::Object** global_handle); + static bool IsGlobalWeak(internal::Isolate* isolate, + internal::Object** global_handle); static void SetWrapperClassId(internal::Object** global_handle, uint16_t class_id); + static uint16_t GetWrapperClassId(internal::Object** global_handle); template <class T> friend class Handle; template <class T> friend class Local; @@ -3468,7 +3580,9 @@ class V8EXPORT V8 { class V8EXPORT TryCatch { public: /** - * Creates a new try/catch block and registers it with v8. + * Creates a new try/catch block and registers it with v8. Note that + * all TryCatch blocks should be stack allocated because the memory + * location itself is compared against JavaScript try/catch blocks. */ TryCatch(); @@ -3558,6 +3672,12 @@ class V8EXPORT TryCatch { void SetCaptureMessage(bool value); private: + // Make it hard to create heap-allocated TryCatch blocks. + TryCatch(const TryCatch&); + void operator=(const TryCatch&); + void* operator new(size_t size); + void operator delete(void*, size_t); + v8::internal::Isolate* isolate_; void* next_; void* exception_; @@ -3699,12 +3819,45 @@ class V8EXPORT Context { static bool InContext(); /** - * Associate an additional data object with the context. This is mainly used - * with the debugger to provide additional information on the context through - * the debugger API. + * Gets embedder data with index 0. Deprecated, use GetEmbedderData with index + * 0 instead. */ - void SetData(Handle<String> data); - Local<Value> GetData(); + V8_DEPRECATED(V8_INLINE(Local<Value> GetData())); + + /** + * Sets embedder data with index 0. Deprecated, use SetEmbedderData with index + * 0 instead. + */ + V8_DEPRECATED(V8_INLINE(void SetData(Handle<Value> value))); + + /** + * Gets the embedder data with the given index, which must have been set by a + * previous call to SetEmbedderData with the same index. Note that index 0 + * currently has a special meaning for Chrome's debugger. + */ + V8_INLINE(Local<Value> GetEmbedderData(int index)); + + /** + * Sets the embedder data with the given index, growing the data as + * needed. Note that index 0 currently has a special meaning for Chrome's + * debugger. + */ + void SetEmbedderData(int index, Handle<Value> value); + + /** + * Gets a 2-byte-aligned native pointer from the embedder data with the given + * index, which must have bees set by a previous call to + * SetAlignedPointerInEmbedderData with the same index. Note that index 0 + * currently has a special meaning for Chrome's debugger. + */ + V8_INLINE(void* GetAlignedPointerFromEmbedderData(int index)); + + /** + * Sets a 2-byte-aligned native pointer in the embedder data with the given + * index, growing the data as needed. Note that index 0 currently has a + * special meaning for Chrome's debugger. + */ + void SetAlignedPointerInEmbedderData(int index, void* value); /** * Control whether code generation from strings is allowed. Calling @@ -3728,15 +3881,22 @@ class V8EXPORT Context { bool IsCodeGenerationFromStringsAllowed(); /** + * Sets the error description for the exception that is thrown when + * code generation from strings is not allowed and 'eval' or the 'Function' + * constructor are called. + */ + void SetErrorMessageForCodeGenerationFromStrings(Handle<String> message); + + /** * Stack-allocated class which sets the execution context for all * operations executed within a local scope. */ class Scope { public: - explicit inline Scope(Handle<Context> context) : context_(context) { + explicit V8_INLINE(Scope(Handle<Context> context)) : context_(context) { context_->Enter(); } - inline ~Scope() { context_->Exit(); } + V8_INLINE(~Scope()) { context_->Exit(); } private: Handle<Context> context_; }; @@ -3746,6 +3906,9 @@ class V8EXPORT Context { friend class Script; friend class Object; friend class Function; + + Local<Value> SlowGetEmbedderData(int index); + void* SlowGetAlignedPointerFromEmbedderData(int index); }; @@ -3974,47 +4137,27 @@ template <size_t ptr_size> struct SmiTagging; template <> struct SmiTagging<4> { static const int kSmiShiftSize = 0; static const int kSmiValueSize = 31; - static inline int SmiToInt(internal::Object* value) { + V8_INLINE(static int SmiToInt(internal::Object* value)) { int shift_bits = kSmiTagSize + kSmiShiftSize; // Throw away top 32 bits and shift down (requires >> to be sign extending). return static_cast<int>(reinterpret_cast<intptr_t>(value)) >> shift_bits; } - - // For 32-bit systems any 2 bytes aligned pointer can be encoded as smi - // with a plain reinterpret_cast. - static const uintptr_t kEncodablePointerMask = 0x1; - static const int kPointerToSmiShift = 0; }; // Smi constants for 64-bit systems. template <> struct SmiTagging<8> { static const int kSmiShiftSize = 31; static const int kSmiValueSize = 32; - static inline int SmiToInt(internal::Object* value) { + V8_INLINE(static int SmiToInt(internal::Object* value)) { int shift_bits = kSmiTagSize + kSmiShiftSize; // Shift down and throw away top 32 bits. return static_cast<int>(reinterpret_cast<intptr_t>(value) >> shift_bits); } - - // To maximize the range of pointers that can be encoded - // in the available 32 bits, we require them to be 8 bytes aligned. - // This gives 2 ^ (32 + 3) = 32G address space covered. - // It might be not enough to cover stack allocated objects on some platforms. - static const int kPointerAlignment = 3; - - static const uintptr_t kEncodablePointerMask = - ~(uintptr_t(0xffffffff) << kPointerAlignment); - - static const int kPointerToSmiShift = - kSmiTagSize + kSmiShiftSize - kPointerAlignment; }; typedef SmiTagging<kApiPointerSize> PlatformSmiTagging; const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize; const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize; -const uintptr_t kEncodablePointerMask = - PlatformSmiTagging::kEncodablePointerMask; -const int kPointerToSmiShift = PlatformSmiTagging::kPointerToSmiShift; /** * This class exports constants and functionality from within v8 that @@ -4032,8 +4175,13 @@ class Internals { static const int kOddballKindOffset = 3 * kApiPointerSize; static const int kForeignAddressOffset = kApiPointerSize; static const int kJSObjectHeaderSize = 3 * kApiPointerSize; + static const int kFixedArrayHeaderSize = 2 * kApiPointerSize; + static const int kContextHeaderSize = 2 * kApiPointerSize; + static const int kContextEmbedderDataIndex = 54; static const int kFullStringRepresentationMask = 0x07; + static const int kStringEncodingMask = 0x4; static const int kExternalTwoByteRepresentationTag = 0x02; + static const int kExternalAsciiRepresentationTag = 0x06; static const int kIsolateStateOffset = 0; static const int kIsolateEmbedderDataOffset = 1 * kApiPointerSize; @@ -4042,7 +4190,7 @@ class Internals { static const int kNullValueRootIndex = 7; static const int kTrueValueRootIndex = 8; static const int kFalseValueRootIndex = 9; - static const int kEmptySymbolRootIndex = 116; + static const int kEmptySymbolRootIndex = 119; static const int kJSObjectType = 0xaa; static const int kFirstNonstringType = 0x80; @@ -4052,85 +4200,80 @@ class Internals { static const int kUndefinedOddballKind = 5; static const int kNullOddballKind = 3; - static inline bool HasHeapObjectTag(internal::Object* value) { + V8_INLINE(static bool HasHeapObjectTag(internal::Object* value)) { return ((reinterpret_cast<intptr_t>(value) & kHeapObjectTagMask) == kHeapObjectTag); } - static inline bool HasSmiTag(internal::Object* value) { - return ((reinterpret_cast<intptr_t>(value) & kSmiTagMask) == kSmiTag); - } - - static inline int SmiValue(internal::Object* value) { + V8_INLINE(static int SmiValue(internal::Object* value)) { return PlatformSmiTagging::SmiToInt(value); } - static inline int GetInstanceType(internal::Object* obj) { + V8_INLINE(static int GetInstanceType(internal::Object* obj)) { typedef internal::Object O; O* map = ReadField<O*>(obj, kHeapObjectMapOffset); return ReadField<uint8_t>(map, kMapInstanceTypeOffset); } - static inline int GetOddballKind(internal::Object* obj) { + V8_INLINE(static 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); - } - - static inline void* GetExternalPointer(internal::Object* obj) { - if (HasSmiTag(obj)) { - return GetExternalPointerFromSmi(obj); - } else if (GetInstanceType(obj) == kForeignType) { - return ReadField<void*>(obj, kForeignAddressOffset); - } else { - return NULL; - } - } - - static inline bool IsExternalTwoByteString(int instance_type) { + V8_INLINE(static bool IsExternalTwoByteString(int instance_type)) { int representation = (instance_type & kFullStringRepresentationMask); return representation == kExternalTwoByteRepresentationTag; } - static inline bool IsInitialized(v8::Isolate* isolate) { + V8_INLINE(static 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) { + V8_INLINE(static 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) { + V8_INLINE(static 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) { + V8_INLINE(static 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) { + V8_INLINE(static T ReadField(Object* ptr, int offset)) { uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag; return *reinterpret_cast<T*>(addr); } - static inline bool CanCastToHeapObject(void* o) { return false; } - static inline bool CanCastToHeapObject(Context* o) { return true; } - static inline bool CanCastToHeapObject(String* o) { return true; } - static inline bool CanCastToHeapObject(Object* o) { return true; } - static inline bool CanCastToHeapObject(Message* o) { return true; } - static inline bool CanCastToHeapObject(StackTrace* o) { return true; } - static inline bool CanCastToHeapObject(StackFrame* o) { return true; } + template <typename T> + V8_INLINE(static T ReadEmbedderData(Context* context, int index)) { + typedef internal::Object O; + typedef internal::Internals I; + O* ctx = *reinterpret_cast<O**>(context); + int embedder_data_offset = I::kContextHeaderSize + + (internal::kApiPointerSize * I::kContextEmbedderDataIndex); + O* embedder_data = I::ReadField<O*>(ctx, embedder_data_offset); + int value_offset = + I::kFixedArrayHeaderSize + (internal::kApiPointerSize * index); + return I::ReadField<T>(embedder_data, value_offset); + } + + V8_INLINE(static bool CanCastToHeapObject(void* o)) { return false; } + V8_INLINE(static bool CanCastToHeapObject(Context* o)) { return true; } + V8_INLINE(static bool CanCastToHeapObject(String* o)) { return true; } + V8_INLINE(static bool CanCastToHeapObject(Object* o)) { return true; } + V8_INLINE(static bool CanCastToHeapObject(Message* o)) { return true; } + V8_INLINE(static bool CanCastToHeapObject(StackTrace* o)) { return true; } + V8_INLINE(static bool CanCastToHeapObject(StackFrame* o)) { return true; } }; } // namespace internal @@ -4154,6 +4297,16 @@ Local<T> Local<T>::New(Handle<T> that) { template <class T> + Local<T> Local<T>::New(Isolate* isolate, Handle<T> that) { + if (that.IsEmpty()) return Local<T>(); + T* that_ptr = *that; + internal::Object** p = reinterpret_cast<internal::Object**>(that_ptr); + return Local<T>(reinterpret_cast<T*>(HandleScope::CreateHandle( + reinterpret_cast<internal::Isolate*>(isolate), *p))); +} + + +template <class T> Persistent<T> Persistent<T>::New(Handle<T> that) { if (that.IsEmpty()) return Persistent<T>(); internal::Object** p = reinterpret_cast<internal::Object**>(*that); @@ -4162,6 +4315,21 @@ Persistent<T> Persistent<T>::New(Handle<T> that) { template <class T> +bool Persistent<T>::IsIndependent() const { + if (this->IsEmpty()) return false; + return V8::IsGlobalIndependent(reinterpret_cast<internal::Object**>(**this)); +} + + +template <class T> +bool Persistent<T>::IsIndependent(Isolate* isolate) const { + if (this->IsEmpty()) return false; + return V8::IsGlobalIndependent(reinterpret_cast<internal::Isolate*>(isolate), + reinterpret_cast<internal::Object**>(**this)); +} + + +template <class T> bool Persistent<T>::IsNearDeath() const { if (this->IsEmpty()) return false; return V8::IsGlobalNearDeath(reinterpret_cast<internal::Object**>(**this)); @@ -4176,6 +4344,14 @@ bool Persistent<T>::IsWeak() const { template <class T> +bool Persistent<T>::IsWeak(Isolate* isolate) const { + if (this->IsEmpty()) return false; + return V8::IsGlobalWeak(reinterpret_cast<internal::Isolate*>(isolate), + reinterpret_cast<internal::Object**>(**this)); +} + + +template <class T> void Persistent<T>::Dispose() { if (this->IsEmpty()) return; V8::DisposeGlobal(reinterpret_cast<internal::Object**>(**this)); @@ -4183,6 +4359,14 @@ void Persistent<T>::Dispose() { template <class T> +void Persistent<T>::Dispose(Isolate* isolate) { + if (this->IsEmpty()) return; + V8::DisposeGlobal(reinterpret_cast<internal::Isolate*>(isolate), + reinterpret_cast<internal::Object**>(**this)); +} + + +template <class T> Persistent<T>::Persistent() : Handle<T>() { } template <class T> @@ -4193,6 +4377,15 @@ void Persistent<T>::MakeWeak(void* parameters, WeakReferenceCallback callback) { } template <class T> +void Persistent<T>::MakeWeak(Isolate* isolate, void* parameters, + WeakReferenceCallback callback) { + V8::MakeWeak(reinterpret_cast<internal::Isolate*>(isolate), + reinterpret_cast<internal::Object**>(**this), + parameters, + callback); +} + +template <class T> void Persistent<T>::ClearWeak() { V8::ClearWeak(reinterpret_cast<internal::Object**>(**this)); } @@ -4203,10 +4396,32 @@ void Persistent<T>::MarkIndependent() { } template <class T> +void Persistent<T>::MarkIndependent(Isolate* isolate) { + V8::MarkIndependent(reinterpret_cast<internal::Isolate*>(isolate), + reinterpret_cast<internal::Object**>(**this)); +} + +template <class T> +void Persistent<T>::MarkPartiallyDependent() { + V8::MarkPartiallyDependent(reinterpret_cast<internal::Object**>(**this)); +} + +template <class T> +void Persistent<T>::MarkPartiallyDependent(Isolate* isolate) { + V8::MarkPartiallyDependent(reinterpret_cast<internal::Isolate*>(isolate), + reinterpret_cast<internal::Object**>(**this)); +} + +template <class T> void Persistent<T>::SetWrapperClassId(uint16_t class_id) { V8::SetWrapperClassId(reinterpret_cast<internal::Object**>(**this), class_id); } +template <class T> +uint16_t Persistent<T>::WrapperClassId() const { + return V8::GetWrapperClassId(reinterpret_cast<internal::Object**>(**this)); +} + Arguments::Arguments(internal::Object** implicit_args, internal::Object** values, int length, bool is_construct_call) @@ -4293,63 +4508,40 @@ void Template::Set(const char* name, v8::Handle<Data> value) { Local<Value> Object::GetInternalField(int index) { #ifndef V8_ENABLE_CHECKS - Local<Value> quick_result = UncheckedGetInternalField(index); - if (!quick_result.IsEmpty()) return quick_result; -#endif - return CheckedGetInternalField(index); -} - - -Local<Value> Object::UncheckedGetInternalField(int index) { typedef internal::Object O; typedef internal::Internals I; O* obj = *reinterpret_cast<O**>(this); + // Fast path: If the object is a plain JSObject, which is the common case, we + // know where to find the internal fields and can return the value directly. if (I::GetInstanceType(obj) == I::kJSObjectType) { - // If the object is a plain JSObject, which is the common case, - // we know where to find the internal fields and can return the - // value directly. int offset = I::kJSObjectHeaderSize + (internal::kApiPointerSize * index); O* value = I::ReadField<O*>(obj, offset); O** result = HandleScope::CreateHandle(value); return Local<Value>(reinterpret_cast<Value*>(result)); - } else { - return Local<Value>(); } -} - - -void* External::Unwrap(Handle<v8::Value> obj) { -#ifdef V8_ENABLE_CHECKS - return FullUnwrap(obj); -#else - return QuickUnwrap(obj); #endif + return SlowGetInternalField(index); } -void* External::QuickUnwrap(Handle<v8::Value> wrapper) { - typedef internal::Object O; - O* obj = *reinterpret_cast<O**>(const_cast<v8::Value*>(*wrapper)); - return internal::Internals::GetExternalPointer(obj); +void Object::SetPointerInInternalField(int index, void* value) { + SetInternalField(index, External::New(value)); } -void* Object::GetPointerFromInternalField(int index) { +void* Object::GetAlignedPointerFromInternalField(int index) { +#ifndef V8_ENABLE_CHECKS typedef internal::Object O; typedef internal::Internals I; - O* obj = *reinterpret_cast<O**>(this); - + // Fast path: If the object is a plain JSObject, which is the common case, we + // know where to find the internal fields and can return the value directly. if (I::GetInstanceType(obj) == I::kJSObjectType) { - // If the object is a plain JSObject, which is the common case, - // we know where to find the internal fields and can return the - // value directly. int offset = I::kJSObjectHeaderSize + (internal::kApiPointerSize * index); - O* value = I::ReadField<O*>(obj, offset); - return I::GetExternalPointer(value); + return I::ReadField<void*>(obj, offset); } - - return SlowGetPointerFromInternalField(index); +#endif + return SlowGetAlignedPointerFromInternalField(index); } @@ -4388,6 +4580,26 @@ String::ExternalStringResource* String::GetExternalStringResource() const { } +String::ExternalStringResourceBase* String::GetExternalStringResourceBase( + String::Encoding* encoding_out) const { + typedef internal::Object O; + typedef internal::Internals I; + O* obj = *reinterpret_cast<O**>(const_cast<String*>(this)); + int type = I::GetInstanceType(obj) & I::kFullStringRepresentationMask; + *encoding_out = static_cast<Encoding>(type & I::kStringEncodingMask); + ExternalStringResourceBase* resource = NULL; + if (type == I::kExternalAsciiRepresentationTag || + type == I::kExternalTwoByteRepresentationTag) { + void* value = I::ReadField<void*>(obj, I::kStringResourceOffset); + resource = static_cast<ExternalStringResourceBase*>(value); + } +#ifdef V8_ENABLE_CHECKS + VerifyExternalStringResourceBase(resource, *encoding_out); +#endif + return resource; +} + + bool Value::IsUndefined() const { #ifdef V8_ENABLE_CHECKS return FullIsUndefined(); @@ -4521,6 +4733,16 @@ Function* Function::Cast(v8::Value* value) { } +Local<Value> External::Wrap(void* value) { + return External::New(value); +} + + +void* External::Unwrap(Handle<v8::Value> obj) { + return External::Cast(*obj)->Value(); +} + + External* External::Cast(v8::Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); @@ -4597,6 +4819,37 @@ void* Isolate::GetData() { } +Local<Value> Context::GetData() { + return GetEmbedderData(0); +} + +void Context::SetData(Handle<Value> data) { + SetEmbedderData(0, data); +} + + +Local<Value> Context::GetEmbedderData(int index) { +#ifndef V8_ENABLE_CHECKS + typedef internal::Object O; + typedef internal::Internals I; + O** result = HandleScope::CreateHandle(I::ReadEmbedderData<O*>(this, index)); + return Local<Value>(reinterpret_cast<Value*>(result)); +#else + return SlowGetEmbedderData(index); +#endif +} + + +void* Context::GetAlignedPointerFromEmbedderData(int index) { +#ifndef V8_ENABLE_CHECKS + typedef internal::Internals I; + return I::ReadEmbedderData<void*>(this, index); +#else + return SlowGetAlignedPointerFromEmbedderData(index); +#endif +} + + /** * \example shell.cc * A simple shell that takes a list of expressions on the diff --git a/deps/v8/samples/shell.cc b/deps/v8/samples/shell.cc index 821ef75a76..62f404554b 100644 --- a/deps/v8/samples/shell.cc +++ b/deps/v8/samples/shell.cc @@ -72,7 +72,7 @@ int main(int argc, char* argv[]) { v8::HandleScope handle_scope; v8::Persistent<v8::Context> context = CreateShellContext(); if (context.IsEmpty()) { - printf("Error creating context\n"); + fprintf(stderr, "Error creating context\n"); return 1; } context->Enter(); @@ -226,7 +226,8 @@ int RunMain(int argc, char* argv[]) { // alone JavaScript engines. continue; } else if (strncmp(str, "--", 2) == 0) { - printf("Warning: unknown flag %s.\nTry --help for options\n", str); + fprintf(stderr, + "Warning: unknown flag %s.\nTry --help for options\n", str); } else if (strcmp(str, "-e") == 0 && i + 1 < argc) { // Execute argument given to -e option directly. v8::Handle<v8::String> file_name = v8::String::New("unnamed"); @@ -237,7 +238,7 @@ int RunMain(int argc, char* argv[]) { v8::Handle<v8::String> file_name = v8::String::New(str); v8::Handle<v8::String> source = ReadFile(str); if (source.IsEmpty()) { - printf("Error reading '%s'\n", str); + fprintf(stderr, "Error reading '%s'\n", str); continue; } if (!ExecuteString(source, file_name, false, true)) return 1; @@ -249,20 +250,20 @@ int RunMain(int argc, char* argv[]) { // The read-eval-execute loop of the shell. void RunShell(v8::Handle<v8::Context> context) { - printf("V8 version %s [sample shell]\n", v8::V8::GetVersion()); + fprintf(stderr, "V8 version %s [sample shell]\n", v8::V8::GetVersion()); static const int kBufferSize = 256; // Enter the execution environment before evaluating any code. v8::Context::Scope context_scope(context); v8::Local<v8::String> name(v8::String::New("(shell)")); while (true) { char buffer[kBufferSize]; - printf("> "); + fprintf(stderr, "> "); char* str = fgets(buffer, kBufferSize, stdin); if (str == NULL) break; v8::HandleScope handle_scope; ExecuteString(v8::String::New(str), name, true, true); } - printf("\n"); + fprintf(stderr, "\n"); } @@ -310,31 +311,31 @@ void ReportException(v8::TryCatch* try_catch) { if (message.IsEmpty()) { // V8 didn't provide any extra information about this error; just // print the exception. - printf("%s\n", exception_string); + fprintf(stderr, "%s\n", exception_string); } else { // Print (filename):(line number): (message). v8::String::Utf8Value filename(message->GetScriptResourceName()); const char* filename_string = ToCString(filename); int linenum = message->GetLineNumber(); - printf("%s:%i: %s\n", filename_string, linenum, exception_string); + fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string); // Print line of source code. v8::String::Utf8Value sourceline(message->GetSourceLine()); const char* sourceline_string = ToCString(sourceline); - printf("%s\n", sourceline_string); + fprintf(stderr, "%s\n", sourceline_string); // Print wavy underline (GetUnderline is deprecated). int start = message->GetStartColumn(); for (int i = 0; i < start; i++) { - printf(" "); + fprintf(stderr, " "); } int end = message->GetEndColumn(); for (int i = start; i < end; i++) { - printf("^"); + fprintf(stderr, "^"); } - printf("\n"); + fprintf(stderr, "\n"); v8::String::Utf8Value stack_trace(try_catch->StackTrace()); if (stack_trace.length() > 0) { const char* stack_trace_string = ToCString(stack_trace); - printf("%s\n", stack_trace_string); + fprintf(stderr, "%s\n", stack_trace_string); } } } diff --git a/deps/v8/src/accessors.cc b/deps/v8/src/accessors.cc index 9da6141c5b..efcaf8f294 100644 --- a/deps/v8/src/accessors.cc +++ b/deps/v8/src/accessors.cc @@ -42,15 +42,11 @@ namespace internal { template <class C> -static C* FindInPrototypeChain(Object* obj, bool* found_it) { - ASSERT(!*found_it); - Heap* heap = HEAP; - while (!Is<C>(obj)) { - if (obj == heap->null_value()) return NULL; - obj = obj->GetPrototype(); +static C* FindInstanceOf(Object* obj) { + for (Object* cur = obj; !cur->IsNull(); cur = cur->GetPrototype()) { + if (Is<C>(cur)) return C::cast(cur); } - *found_it = true; - return C::cast(obj); + return NULL; } @@ -81,10 +77,8 @@ MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) { MaybeObject* Accessors::ArrayGetLength(Object* object, void*) { // Traverse the prototype chain until we reach an array. - bool found_it = false; - JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it); - if (!found_it) return Smi::FromInt(0); - return holder->length(); + JSArray* holder = FindInstanceOf<JSArray>(object); + return holder == NULL ? Smi::FromInt(0) : holder->length(); } @@ -118,7 +112,7 @@ MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) { HandleScope scope(isolate); // Protect raw pointers. - Handle<JSObject> object_handle(object, isolate); + Handle<JSArray> array_handle(JSArray::cast(object), isolate); Handle<Object> value_handle(value, isolate); bool has_exception; @@ -128,7 +122,7 @@ MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) { if (has_exception) return Failure::Exception(); if (uint32_v->Number() == number_v->Number()) { - return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v); + return array_handle->SetElementsLength(*uint32_v); } return isolate->Throw( *isolate->factory()->NewRangeError("invalid_array_length", @@ -448,15 +442,12 @@ const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = { MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) { Heap* heap = Isolate::Current()->heap(); - bool found_it = false; - JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return heap->undefined_value(); + JSFunction* function = FindInstanceOf<JSFunction>(object); + if (function == NULL) return heap->undefined_value(); while (!function->should_have_prototype()) { - found_it = false; - function = FindInPrototypeChain<JSFunction>(object->GetPrototype(), - &found_it); + function = FindInstanceOf<JSFunction>(function->GetPrototype()); // There has to be one because we hit the getter. - ASSERT(found_it); + ASSERT(function != NULL); } if (!function->has_prototype()) { @@ -474,25 +465,46 @@ MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) { MaybeObject* Accessors::FunctionSetPrototype(JSObject* object, - Object* value, + Object* value_raw, void*) { - Heap* heap = object->GetHeap(); - bool found_it = false; - JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return heap->undefined_value(); - if (!function->should_have_prototype()) { + Isolate* isolate = object->GetIsolate(); + Heap* heap = isolate->heap(); + JSFunction* function_raw = FindInstanceOf<JSFunction>(object); + if (function_raw == NULL) return heap->undefined_value(); + if (!function_raw->should_have_prototype()) { // Since we hit this accessor, object will have no prototype property. return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(), - value, + value_raw, NONE); } - Object* prototype; - { MaybeObject* maybe_prototype = function->SetPrototype(value); - if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype; + HandleScope scope(isolate); + Handle<JSFunction> function(function_raw, isolate); + Handle<Object> value(value_raw, isolate); + + Handle<Object> old_value; + bool is_observed = + FLAG_harmony_observation && + *function == object && + function->map()->is_observed(); + if (is_observed) { + if (function->has_prototype()) + old_value = handle(function->prototype(), isolate); + else + old_value = isolate->factory()->NewFunctionPrototype(function); + } + + Handle<Object> result; + MaybeObject* maybe_result = function->SetPrototype(*value); + if (!maybe_result->ToHandle(&result, isolate)) return maybe_result; + ASSERT(function->prototype() == *value); + + if (is_observed && !old_value->SameValue(*value)) { + JSObject::EnqueueChangeRecord( + function, "updated", isolate->factory()->prototype_symbol(), old_value); } - ASSERT(function->prototype() == value); - return function; + + return *function; } @@ -509,22 +521,20 @@ const AccessorDescriptor Accessors::FunctionPrototype = { MaybeObject* Accessors::FunctionGetLength(Object* object, void*) { - bool found_it = false; - JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return Smi::FromInt(0); + JSFunction* function = FindInstanceOf<JSFunction>(object); + if (function == NULL) return Smi::FromInt(0); // Check if already compiled. - if (!function->shared()->is_compiled()) { - // If the function isn't compiled yet, the length is not computed - // correctly yet. Compile it now and return the right length. - HandleScope scope; - Handle<JSFunction> handle(function); - if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) { - return Failure::Exception(); - } - return Smi::FromInt(handle->shared()->length()); - } else { + if (function->shared()->is_compiled()) { return Smi::FromInt(function->shared()->length()); } + // If the function isn't compiled yet, the length is not computed correctly + // yet. Compile it now and return the right length. + HandleScope scope; + Handle<JSFunction> handle(function); + if (JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) { + return Smi::FromInt(handle->shared()->length()); + } + return Failure::Exception(); } @@ -541,10 +551,8 @@ const AccessorDescriptor Accessors::FunctionLength = { MaybeObject* Accessors::FunctionGetName(Object* object, void*) { - bool found_it = false; - JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return HEAP->undefined_value(); - return holder->shared()->name(); + JSFunction* holder = FindInstanceOf<JSFunction>(object); + return holder == NULL ? HEAP->undefined_value() : holder->shared()->name(); } @@ -589,9 +597,8 @@ static MaybeObject* ConstructArgumentsObjectForInlinedFunction( MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) { Isolate* isolate = Isolate::Current(); HandleScope scope(isolate); - bool found_it = false; - JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return isolate->heap()->undefined_value(); + JSFunction* holder = FindInstanceOf<JSFunction>(object); + if (holder == NULL) return isolate->heap()->undefined_value(); Handle<JSFunction> function(holder, isolate); if (function->shared()->native()) return isolate->heap()->null_value(); @@ -664,19 +671,6 @@ const AccessorDescriptor Accessors::FunctionArguments = { // -static MaybeObject* CheckNonStrictCallerOrThrow( - Isolate* isolate, - JSFunction* caller) { - DisableAssertNoAllocation enable_allocation; - if (!caller->shared()->is_classic_mode()) { - return isolate->Throw( - *isolate->factory()->NewTypeError("strict_caller", - HandleVector<Object>(NULL, 0))); - } - return caller; -} - - class FrameFunctionIterator { public: FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise) @@ -727,9 +721,8 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { Isolate* isolate = Isolate::Current(); HandleScope scope(isolate); AssertNoAllocation no_alloc; - bool found_it = false; - JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); - if (!found_it) return isolate->heap()->undefined_value(); + JSFunction* holder = FindInstanceOf<JSFunction>(object); + if (holder == NULL) return isolate->heap()->undefined_value(); if (holder->shared()->native()) return isolate->heap()->null_value(); Handle<JSFunction> function(holder, isolate); @@ -764,7 +757,14 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { if (caller->shared()->bound()) { return isolate->heap()->null_value(); } - return CheckNonStrictCallerOrThrow(isolate, caller); + // Censor if the caller is not a classic mode function. + // Change from ES5, which used to throw, see: + // https://bugs.ecmascript.org/show_bug.cgi?id=310 + if (!caller->shared()->is_classic_mode()) { + return isolate->heap()->null_value(); + } + + return caller; } @@ -780,7 +780,7 @@ const AccessorDescriptor Accessors::FunctionCaller = { // -MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) { +static inline Object* GetPrototypeSkipHiddenPrototypes(Object* receiver) { Object* current = receiver->GetPrototype(); while (current->IsJSObject() && JSObject::cast(current)->map()->is_hidden_prototype()) { @@ -790,12 +790,36 @@ MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) { } -MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver, - Object* value, +MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) { + return GetPrototypeSkipHiddenPrototypes(receiver); +} + + +MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver_raw, + Object* value_raw, void*) { - const bool skip_hidden_prototypes = true; + const bool kSkipHiddenPrototypes = true; // To be consistent with other Set functions, return the value. - return receiver->SetPrototype(value, skip_hidden_prototypes); + if (!(FLAG_harmony_observation && receiver_raw->map()->is_observed())) + return receiver_raw->SetPrototype(value_raw, kSkipHiddenPrototypes); + + Isolate* isolate = receiver_raw->GetIsolate(); + HandleScope scope(isolate); + Handle<JSObject> receiver(receiver_raw); + Handle<Object> value(value_raw); + Handle<Object> old_value(GetPrototypeSkipHiddenPrototypes(*receiver)); + + MaybeObject* result = receiver->SetPrototype(*value, kSkipHiddenPrototypes); + Handle<Object> hresult; + if (!result->ToHandle(&hresult, isolate)) return result; + + Handle<Object> new_value(GetPrototypeSkipHiddenPrototypes(*receiver)); + if (!new_value->SameValue(*old_value)) { + JSObject::EnqueueChangeRecord(receiver, "prototype", + isolate->factory()->Proto_symbol(), + old_value); + } + return *hresult; } diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index dcbc894574..95e5340a5a 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -630,7 +630,16 @@ void V8::MakeWeak(i::Object** object, void* parameters, i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "MakeWeak"); isolate->global_handles()->MakeWeak(object, parameters, - callback); + callback); +} + + +void V8::MakeWeak(i::Isolate* isolate, i::Object** object, + void* parameters, WeakReferenceCallback callback) { + ASSERT(isolate == i::Isolate::Current()); + LOG_API(isolate, "MakeWeak"); + isolate->global_handles()->MakeWeak(object, parameters, + callback); } @@ -643,11 +652,48 @@ void V8::ClearWeak(i::Object** obj) { void V8::MarkIndependent(i::Object** object) { i::Isolate* isolate = i::Isolate::Current(); - LOG_API(isolate, "MakeIndependent"); + LOG_API(isolate, "MarkIndependent"); isolate->global_handles()->MarkIndependent(object); } +void V8::MarkIndependent(i::Isolate* isolate, i::Object** object) { + ASSERT(isolate == i::Isolate::Current()); + LOG_API(isolate, "MarkIndependent"); + isolate->global_handles()->MarkIndependent(object); +} + + +void V8::MarkPartiallyDependent(i::Object** object) { + i::Isolate* isolate = i::Isolate::Current(); + LOG_API(isolate, "MarkPartiallyDependent"); + isolate->global_handles()->MarkPartiallyDependent(object); +} + + +void V8::MarkPartiallyDependent(i::Isolate* isolate, i::Object** object) { + ASSERT(isolate == i::Isolate::Current()); + LOG_API(isolate, "MarkPartiallyDependent"); + isolate->global_handles()->MarkPartiallyDependent(object); +} + + +bool V8::IsGlobalIndependent(i::Object** obj) { + i::Isolate* isolate = i::Isolate::Current(); + LOG_API(isolate, "IsGlobalIndependent"); + if (!isolate->IsInitialized()) return false; + return i::GlobalHandles::IsIndependent(obj); +} + + +bool V8::IsGlobalIndependent(i::Isolate* isolate, i::Object** obj) { + ASSERT(isolate == i::Isolate::Current()); + LOG_API(isolate, "IsGlobalIndependent"); + if (!isolate->IsInitialized()) return false; + return i::GlobalHandles::IsIndependent(obj); +} + + bool V8::IsGlobalNearDeath(i::Object** obj) { i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "IsGlobalNearDeath"); @@ -664,6 +710,14 @@ bool V8::IsGlobalWeak(i::Object** obj) { } +bool V8::IsGlobalWeak(i::Isolate* isolate, i::Object** obj) { + ASSERT(isolate == i::Isolate::Current()); + LOG_API(isolate, "IsGlobalWeak"); + if (!isolate->IsInitialized()) return false; + return i::GlobalHandles::IsWeak(obj); +} + + void V8::DisposeGlobal(i::Object** obj) { i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "DisposeGlobal"); @@ -671,6 +725,14 @@ void V8::DisposeGlobal(i::Object** obj) { isolate->global_handles()->Destroy(obj); } + +void V8::DisposeGlobal(i::Isolate* isolate, i::Object** obj) { + ASSERT(isolate == i::Isolate::Current()); + LOG_API(isolate, "DisposeGlobal"); + if (!isolate->IsInitialized()) return; + isolate->global_handles()->Destroy(obj); +} + // --- H a n d l e s --- @@ -724,6 +786,12 @@ i::Object** HandleScope::CreateHandle(i::Object* value) { } +i::Object** HandleScope::CreateHandle(i::Isolate* isolate, i::Object* value) { + ASSERT(isolate == i::Isolate::Current()); + return i::HandleScope::CreateHandle(value, isolate); +} + + i::Object** HandleScope::CreateHandle(i::HeapObject* value) { ASSERT(value->IsHeapObject()); return reinterpret_cast<i::Object**>( @@ -765,36 +833,77 @@ void Context::Exit() { } -void Context::SetData(v8::Handle<String> data) { - i::Handle<i::Context> env = Utils::OpenHandle(this); - i::Isolate* isolate = env->GetIsolate(); - if (IsDeadCheck(isolate, "v8::Context::SetData()")) return; - i::Handle<i::Object> raw_data = Utils::OpenHandle(*data); - ASSERT(env->IsNativeContext()); - if (env->IsNativeContext()) { - env->set_data(*raw_data); - } +static void* DecodeSmiToAligned(i::Object* value, const char* location) { + ApiCheck(value->IsSmi(), location, "Not a Smi"); + return reinterpret_cast<void*>(value); } -v8::Local<v8::Value> Context::GetData() { - i::Handle<i::Context> env = Utils::OpenHandle(this); - i::Isolate* isolate = env->GetIsolate(); - if (IsDeadCheck(isolate, "v8::Context::GetData()")) { - return v8::Local<Value>(); - } - i::Object* raw_result = NULL; - ASSERT(env->IsNativeContext()); - if (env->IsNativeContext()) { - raw_result = env->data(); - } else { - return Local<Value>(); +static i::Smi* EncodeAlignedAsSmi(void* value, const char* location) { + i::Smi* smi = reinterpret_cast<i::Smi*>(value); + ApiCheck(smi->IsSmi(), location, "Pointer is not aligned"); + return smi; +} + + +static i::Handle<i::FixedArray> EmbedderDataFor(Context* context, + int index, + bool can_grow, + const char* location) { + i::Handle<i::Context> env = Utils::OpenHandle(context); + bool ok = !IsDeadCheck(env->GetIsolate(), location) && + ApiCheck(env->IsNativeContext(), location, "Not a native context") && + ApiCheck(index >= 0, location, "Negative index"); + if (!ok) return i::Handle<i::FixedArray>(); + i::Handle<i::FixedArray> data(env->embedder_data()); + if (index < data->length()) return data; + if (!can_grow) { + Utils::ReportApiFailure(location, "Index too large"); + return i::Handle<i::FixedArray>(); } - i::Handle<i::Object> result(raw_result, isolate); + int new_size = i::Max(index, data->length() << 1) + 1; + data = env->GetIsolate()->factory()->CopySizeFixedArray(data, new_size); + env->set_embedder_data(*data); + return data; +} + + +v8::Local<v8::Value> Context::SlowGetEmbedderData(int index) { + const char* location = "v8::Context::GetEmbedderData()"; + i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, false, location); + if (data.is_null()) return Local<Value>(); + i::Handle<i::Object> result(data->get(index), data->GetIsolate()); return Utils::ToLocal(result); } +void Context::SetEmbedderData(int index, v8::Handle<Value> value) { + const char* location = "v8::Context::SetEmbedderData()"; + i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, true, location); + if (data.is_null()) return; + i::Handle<i::Object> val = Utils::OpenHandle(*value); + data->set(index, *val); + ASSERT_EQ(*Utils::OpenHandle(*value), + *Utils::OpenHandle(*GetEmbedderData(index))); +} + + +void* Context::SlowGetAlignedPointerFromEmbedderData(int index) { + const char* location = "v8::Context::GetAlignedPointerFromEmbedderData()"; + i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, false, location); + if (data.is_null()) return NULL; + return DecodeSmiToAligned(data->get(index), location); +} + + +void Context::SetAlignedPointerInEmbedderData(int index, void* value) { + const char* location = "v8::Context::SetAlignedPointerInEmbedderData()"; + i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, true, location); + data->set(index, EncodeAlignedAsSmi(value, location)); + ASSERT_EQ(value, GetAlignedPointerFromEmbedderData(index)); +} + + i::Object** v8::HandleScope::RawClose(i::Object** value) { if (!ApiCheck(!is_closed_, "v8::HandleScope::Close()", @@ -816,7 +925,7 @@ i::Object** v8::HandleScope::RawClose(i::Object** value) { } // Allocate a new handle on the previous handle block. - i::Handle<i::Object> handle(result); + i::Handle<i::Object> handle(result, isolate_); return handle.location(); } @@ -1151,7 +1260,7 @@ void FunctionTemplate::SetHiddenPrototype(bool value) { void FunctionTemplate::ReadOnlyPrototype() { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetPrototypeAttributes()")) { + if (IsDeadCheck(isolate, "v8::FunctionTemplate::ReadOnlyPrototype()")) { return; } ENTER_V8(isolate); @@ -1595,6 +1704,8 @@ Local<Value> Script::Run() { ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>()); LOG_API(isolate, "Script::Run"); ENTER_V8(isolate); + i::Logger::TimerEventScope timer_scope( + isolate, i::Logger::TimerEventScope::v8_execute); i::Object* raw_result = NULL; { i::HandleScope scope(isolate); @@ -2193,7 +2304,7 @@ bool Value::IsExternal() const { if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsExternal()")) { return false; } - return Utils::OpenHandle(this)->IsForeign(); + return Utils::OpenHandle(this)->IsExternal(); } @@ -2267,7 +2378,11 @@ static i::Object* LookupBuiltin(i::Isolate* isolate, static bool CheckConstructor(i::Isolate* isolate, i::Handle<i::JSObject> obj, const char* class_name) { - return obj->map()->constructor() == LookupBuiltin(isolate, class_name); + i::Object* constr = obj->map()->constructor(); + if (!constr->IsJSFunction()) return false; + i::JSFunction* func = i::JSFunction::cast(constr); + return func->shared()->native() && + constr == LookupBuiltin(isolate, class_name); } @@ -2422,8 +2537,7 @@ Local<Integer> Value::ToInteger() const { void External::CheckCast(v8::Value* that) { if (IsDeadCheck(i::Isolate::Current(), "v8::External::Cast()")) return; - i::Handle<i::Object> obj = Utils::OpenHandle(that); - ApiCheck(obj->IsForeign(), + ApiCheck(Utils::OpenHandle(that)->IsExternal(), "v8::External::Cast()", "Could not convert to external"); } @@ -2768,6 +2882,7 @@ bool v8::Object::Set(v8::Handle<Value> key, v8::Handle<Value> value, i::Handle<i::Object> value_obj = Utils::OpenHandle(*value); EXCEPTION_PREAMBLE(isolate); i::Handle<i::Object> obj = i::SetProperty( + isolate, self, key_obj, value_obj, @@ -3322,7 +3437,7 @@ v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) { i::Handle<i::JSObject> self = Utils::OpenHandle(this); i::Handle<i::String> key_obj = Utils::OpenHandle(*key); i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj); - i::Handle<i::Object> result(self->GetHiddenProperty(*key_symbol)); + i::Handle<i::Object> result(self->GetHiddenProperty(*key_symbol), isolate); if (result->IsUndefined()) return v8::Local<v8::Value>(); return Utils::ToLocal(result); } @@ -3559,6 +3674,8 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, return Local<v8::Value>()); LOG_API(isolate, "Object::CallAsFunction"); ENTER_V8(isolate); + i::Logger::TimerEventScope timer_scope( + isolate, i::Logger::TimerEventScope::v8_execute); i::HandleScope scope(isolate); i::Handle<i::JSObject> obj = Utils::OpenHandle(this); i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv); @@ -3590,6 +3707,8 @@ Local<v8::Value> Object::CallAsConstructor(int argc, return Local<v8::Object>()); LOG_API(isolate, "Object::CallAsConstructor"); ENTER_V8(isolate); + i::Logger::TimerEventScope timer_scope( + isolate, i::Logger::TimerEventScope::v8_execute); i::HandleScope scope(isolate); i::Handle<i::JSObject> obj = Utils::OpenHandle(this); STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**)); @@ -3632,6 +3751,8 @@ Local<v8::Object> Function::NewInstance(int argc, return Local<v8::Object>()); LOG_API(isolate, "Function::NewInstance"); ENTER_V8(isolate); + i::Logger::TimerEventScope timer_scope( + isolate, i::Logger::TimerEventScope::v8_execute); HandleScope scope; i::Handle<i::JSFunction> function = Utils::OpenHandle(this); STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**)); @@ -3650,6 +3771,8 @@ Local<v8::Value> Function::Call(v8::Handle<v8::Object> recv, int argc, ON_BAILOUT(isolate, "v8::Function::Call()", return Local<v8::Value>()); LOG_API(isolate, "Function::Call"); ENTER_V8(isolate); + i::Logger::TimerEventScope timer_scope( + isolate, i::Logger::TimerEventScope::v8_execute); i::Object* raw_result = NULL; { i::HandleScope scope(isolate); @@ -3693,8 +3816,9 @@ ScriptOrigin Function::GetScriptOrigin() const { i::Handle<i::JSFunction> func = Utils::OpenHandle(this); if (func->shared()->script()->IsScript()) { i::Handle<i::Script> script(i::Script::cast(func->shared()->script())); + i::Handle<i::Object> scriptName = GetScriptNameOrSourceURL(script); v8::ScriptOrigin origin( - Utils::ToLocal(i::Handle<i::Object>(script->name())), + Utils::ToLocal(scriptName), v8::Integer::New(script->line_offset()->value()), v8::Integer::New(script->column_offset()->value())); return origin; @@ -3757,7 +3881,7 @@ static int RecursivelySerializeToUtf8(i::String* string, int32_t* last_character) { int utf8_bytes = 0; while (true) { - if (string->IsAsciiRepresentation()) { + if (string->IsOneByteRepresentation()) { i::String::WriteToFlat(string, buffer, start, end); *last_character = unibrow::Utf16::kNoPreviousCharacter; return utf8_bytes + end - start; @@ -3857,7 +3981,7 @@ int String::WriteUtf8(char* buffer, FlattenString(str); // Flatten the string for efficiency. } int string_length = str->length(); - if (str->IsAsciiRepresentation()) { + if (str->IsOneByteRepresentation()) { int len; if (capacity == -1) { capacity = str->length() + 1; @@ -3991,7 +4115,7 @@ int String::WriteAscii(char* buffer, FlattenString(str); // Flatten the string for efficiency. } - if (str->IsAsciiRepresentation()) { + if (str->IsOneByteRepresentation()) { // WriteToFlat is faster than using the StringInputBuffer. if (length == -1) length = str->length() + 1; int len = i::Min(length, str->length() - start); @@ -4089,6 +4213,29 @@ void v8::String::VerifyExternalStringResource( CHECK_EQ(expected, value); } +void v8::String::VerifyExternalStringResourceBase( + v8::String::ExternalStringResourceBase* value, Encoding encoding) const { + i::Handle<i::String> str = Utils::OpenHandle(this); + const v8::String::ExternalStringResourceBase* expected; + Encoding expectedEncoding; + if (i::StringShape(*str).IsExternalAscii()) { + const void* resource = + i::Handle<i::ExternalAsciiString>::cast(str)->resource(); + expected = reinterpret_cast<const ExternalStringResourceBase*>(resource); + expectedEncoding = ASCII_ENCODING; + } else if (i::StringShape(*str).IsExternalTwoByte()) { + const void* resource = + i::Handle<i::ExternalTwoByteString>::cast(str)->resource(); + expected = reinterpret_cast<const ExternalStringResourceBase*>(resource); + expectedEncoding = TWO_BYTE_ENCODING; + } else { + expected = NULL; + expectedEncoding = str->IsOneByteRepresentation() ? ASCII_ENCODING + : TWO_BYTE_ENCODING; + } + CHECK_EQ(expected, value); + CHECK_EQ(expectedEncoding, encoding); +} const v8::String::ExternalAsciiStringResource* v8::String::GetExternalAsciiStringResource() const { @@ -4163,75 +4310,65 @@ int v8::Object::InternalFieldCount() { } -Local<Value> v8::Object::CheckedGetInternalField(int index) { +static bool InternalFieldOK(i::Handle<i::JSObject> obj, + int index, + const char* location) { + return !IsDeadCheck(obj->GetIsolate(), location) && + ApiCheck(index < obj->GetInternalFieldCount(), + location, + "Internal field out of bounds"); +} + + +Local<Value> v8::Object::SlowGetInternalField(int index) { i::Handle<i::JSObject> obj = Utils::OpenHandle(this); - if (IsDeadCheck(obj->GetIsolate(), "v8::Object::GetInternalField()")) { - return Local<Value>(); - } - if (!ApiCheck(index < obj->GetInternalFieldCount(), - "v8::Object::GetInternalField()", - "Reading internal field out of bounds")) { - return Local<Value>(); - } - i::Handle<i::Object> value(obj->GetInternalField(index)); - Local<Value> result = Utils::ToLocal(value); -#ifdef DEBUG - Local<Value> unchecked = UncheckedGetInternalField(index); - ASSERT(unchecked.IsEmpty() || (unchecked == result)); -#endif - return result; + const char* location = "v8::Object::GetInternalField()"; + if (!InternalFieldOK(obj, index, location)) return Local<Value>(); + i::Handle<i::Object> value(obj->GetInternalField(index), obj->GetIsolate()); + return Utils::ToLocal(value); } void v8::Object::SetInternalField(int index, v8::Handle<Value> value) { i::Handle<i::JSObject> obj = Utils::OpenHandle(this); - i::Isolate* isolate = obj->GetIsolate(); - if (IsDeadCheck(isolate, "v8::Object::SetInternalField()")) { - return; - } - if (!ApiCheck(index < obj->GetInternalFieldCount(), - "v8::Object::SetInternalField()", - "Writing internal field out of bounds")) { - return; - } - ENTER_V8(isolate); + const char* location = "v8::Object::SetInternalField()"; + if (!InternalFieldOK(obj, index, location)) return; i::Handle<i::Object> val = Utils::OpenHandle(*value); obj->SetInternalField(index, *val); + ASSERT_EQ(value, GetInternalField(index)); } -static bool CanBeEncodedAsSmi(void* ptr) { - const uintptr_t address = reinterpret_cast<uintptr_t>(ptr); - return ((address & i::kEncodablePointerMask) == 0); +void* v8::Object::SlowGetAlignedPointerFromInternalField(int index) { + i::Handle<i::JSObject> obj = Utils::OpenHandle(this); + const char* location = "v8::Object::GetAlignedPointerFromInternalField()"; + if (!InternalFieldOK(obj, index, location)) return NULL; + return DecodeSmiToAligned(obj->GetInternalField(index), location); } -static i::Smi* EncodeAsSmi(void* ptr) { - ASSERT(CanBeEncodedAsSmi(ptr)); - const uintptr_t address = reinterpret_cast<uintptr_t>(ptr); - i::Smi* result = reinterpret_cast<i::Smi*>(address << i::kPointerToSmiShift); - ASSERT(i::Internals::HasSmiTag(result)); - ASSERT_EQ(result, i::Smi::FromInt(result->value())); - ASSERT_EQ(ptr, i::Internals::GetExternalPointerFromSmi(result)); - return result; +void v8::Object::SetAlignedPointerInInternalField(int index, void* value) { + i::Handle<i::JSObject> obj = Utils::OpenHandle(this); + const char* location = "v8::Object::SetAlignedPointerInInternalField()"; + if (!InternalFieldOK(obj, index, location)) return; + obj->SetInternalField(index, EncodeAlignedAsSmi(value, location)); + ASSERT_EQ(value, GetAlignedPointerFromInternalField(index)); } -void v8::Object::SetPointerInInternalField(int index, void* value) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - ENTER_V8(isolate); - if (CanBeEncodedAsSmi(value)) { - Utils::OpenHandle(this)->SetInternalField(index, EncodeAsSmi(value)); - } else { - HandleScope scope; - i::Handle<i::Foreign> foreign = - isolate->factory()->NewForeign( - reinterpret_cast<i::Address>(value), i::TENURED); - if (!foreign.is_null()) { - Utils::OpenHandle(this)->SetInternalField(index, *foreign); - } - } - ASSERT_EQ(value, GetPointerFromInternalField(index)); +static void* ExternalValue(i::Object* obj) { + // Obscure semantics for undefined, but somehow checked in our unit tests... + if (obj->IsUndefined()) return NULL; + i::Object* foreign = i::JSObject::cast(obj)->GetInternalField(0); + return i::Foreign::cast(foreign)->foreign_address(); +} + + +void* Object::GetPointerFromInternalField(int index) { + i::Handle<i::JSObject> obj = Utils::OpenHandle(this); + const char* location = "v8::Object::GetPointerFromInternalField()"; + if (!InternalFieldOK(obj, index, location)) return NULL; + return ExternalValue(obj->GetInternalField(index)); } @@ -4286,6 +4423,7 @@ bool v8::V8::Dispose() { HeapStatistics::HeapStatistics(): total_heap_size_(0), total_heap_size_executable_(0), + total_physical_size_(0), used_heap_size_(0), heap_size_limit_(0) { } @@ -4295,6 +4433,7 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) { // Isolate is unitialized thus heap is not configured yet. heap_statistics->set_total_heap_size(0); heap_statistics->set_total_heap_size_executable(0); + heap_statistics->set_total_physical_size(0); heap_statistics->set_used_heap_size(0); heap_statistics->set_heap_size_limit(0); return; @@ -4304,6 +4443,7 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) { heap_statistics->set_total_heap_size(heap->CommittedMemory()); heap_statistics->set_total_heap_size_executable( heap->CommittedMemoryExecutable()); + heap_statistics->set_total_physical_size(heap->CommittedPhysicalMemory()); heap_statistics->set_used_heap_size(heap->SizeOfObjects()); heap_statistics->set_heap_size_limit(heap->MaxReserved()); } @@ -4316,6 +4456,30 @@ void v8::V8::VisitExternalResources(ExternalResourceVisitor* visitor) { } +void v8::V8::VisitHandlesWithClassIds(PersistentHandleVisitor* visitor) { + i::Isolate* isolate = i::Isolate::Current(); + IsDeadCheck(isolate, "v8::V8::VisitHandlesWithClassId"); + + i::AssertNoAllocation no_allocation; + + class VisitorAdapter : public i::ObjectVisitor { + public: + explicit VisitorAdapter(PersistentHandleVisitor* visitor) + : visitor_(visitor) {} + virtual void VisitPointers(i::Object** start, i::Object** end) { + UNREACHABLE(); + } + virtual void VisitEmbedderReference(i::Object** p, uint16_t class_id) { + visitor_->VisitPersistentHandle(ToApi<Value>(i::Handle<i::Object>(p)), + class_id); + } + private: + PersistentHandleVisitor* visitor_; + } visitor_adapter(visitor); + isolate->global_handles()->IterateAllRootsWithClassIds(&visitor_adapter); +} + + bool v8::V8::IdleNotification(int hint) { // Returning true tells the caller that it need not // continue to call IdleNotification. @@ -4516,13 +4680,14 @@ v8::Local<v8::Context> Context::GetCalling() { v8::Local<v8::Object> Context::Global() { - if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) { + i::Isolate* isolate = i::Isolate::Current(); + if (IsDeadCheck(isolate, "v8::Context::Global()")) { return Local<v8::Object>(); } i::Object** ctx = reinterpret_cast<i::Object**>(this); i::Handle<i::Context> context = i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx)); - i::Handle<i::Object> global(context->global_proxy()); + i::Handle<i::Object> global(context->global_proxy(), isolate); return Utils::ToLocal(i::Handle<i::JSObject>::cast(global)); } @@ -4579,11 +4744,32 @@ bool Context::IsCodeGenerationFromStringsAllowed() { } +void Context::SetErrorMessageForCodeGenerationFromStrings( + Handle<String> error) { + i::Isolate* isolate = i::Isolate::Current(); + if (IsDeadCheck(isolate, + "v8::Context::SetErrorMessageForCodeGenerationFromStrings()")) { + return; + } + ENTER_V8(isolate); + i::Object** ctx = reinterpret_cast<i::Object**>(this); + i::Handle<i::Context> context = + i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx)); + i::Handle<i::Object> error_handle = Utils::OpenHandle(*error); + context->set_error_message_for_code_gen_from_strings(*error_handle); +} + + void V8::SetWrapperClassId(i::Object** global_handle, uint16_t class_id) { i::GlobalHandles::SetWrapperClassId(global_handle, class_id); } +uint16_t V8::GetWrapperClassId(internal::Object** global_handle) { + return i::GlobalHandles::GetWrapperClassId(global_handle); +} + + Local<v8::Object> ObjectTemplate::NewInstance() { i::Isolate* isolate = i::Isolate::Current(); ON_BAILOUT(isolate, "v8::ObjectTemplate::NewInstance()", @@ -4622,74 +4808,20 @@ bool FunctionTemplate::HasInstance(v8::Handle<v8::Value> value) { } -static Local<External> ExternalNewImpl(void* data) { - return Utils::ToLocal(FACTORY->NewForeign(static_cast<i::Address>(data))); -} - -static void* ExternalValueImpl(i::Handle<i::Object> obj) { - return reinterpret_cast<void*>(i::Foreign::cast(*obj)->foreign_address()); -} - - -Local<Value> v8::External::Wrap(void* data) { - i::Isolate* isolate = i::Isolate::Current(); - STATIC_ASSERT(sizeof(data) == sizeof(i::Address)); - EnsureInitializedForIsolate(isolate, "v8::External::Wrap()"); - LOG_API(isolate, "External::Wrap"); - ENTER_V8(isolate); - - v8::Local<v8::Value> result = CanBeEncodedAsSmi(data) - ? Utils::ToLocal(i::Handle<i::Object>(EncodeAsSmi(data))) - : v8::Local<v8::Value>(ExternalNewImpl(data)); - - ASSERT_EQ(data, Unwrap(result)); - return result; -} - - -void* v8::Object::SlowGetPointerFromInternalField(int index) { - i::Handle<i::JSObject> obj = Utils::OpenHandle(this); - i::Object* value = obj->GetInternalField(index); - if (value->IsSmi()) { - return i::Internals::GetExternalPointerFromSmi(value); - } else if (value->IsForeign()) { - return reinterpret_cast<void*>(i::Foreign::cast(value)->foreign_address()); - } else { - return NULL; - } -} - - -void* v8::External::FullUnwrap(v8::Handle<v8::Value> wrapper) { - if (IsDeadCheck(i::Isolate::Current(), "v8::External::Unwrap()")) return 0; - i::Handle<i::Object> obj = Utils::OpenHandle(*wrapper); - void* result; - if (obj->IsSmi()) { - result = i::Internals::GetExternalPointerFromSmi(*obj); - } else if (obj->IsForeign()) { - result = ExternalValueImpl(obj); - } else { - result = NULL; - } - ASSERT_EQ(result, QuickUnwrap(wrapper)); - return result; -} - - -Local<External> v8::External::New(void* data) { - STATIC_ASSERT(sizeof(data) == sizeof(i::Address)); +Local<External> v8::External::New(void* value) { + STATIC_ASSERT(sizeof(value) == sizeof(i::Address)); i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::External::New()"); LOG_API(isolate, "External::New"); ENTER_V8(isolate); - return ExternalNewImpl(data); + i::Handle<i::JSObject> external = isolate->factory()->NewExternal(value); + return Utils::ExternalToLocal(external); } void* External::Value() const { - if (IsDeadCheck(i::Isolate::Current(), "v8::External::Value()")) return 0; - i::Handle<i::Object> obj = Utils::OpenHandle(this); - return ExternalValueImpl(obj); + if (IsDeadCheck(i::Isolate::Current(), "v8::External::Value()")) return NULL; + return ExternalValue(*Utils::OpenHandle(this)); } @@ -5155,24 +5287,39 @@ Local<Number> v8::Number::New(double value) { Local<Integer> v8::Integer::New(int32_t value) { i::Isolate* isolate = i::Isolate::UncheckedCurrent(); EnsureInitializedForIsolate(isolate, "v8::Integer::New()"); + return v8::Integer::New(value, reinterpret_cast<Isolate*>(isolate)); +} + + +Local<Integer> Integer::NewFromUnsigned(uint32_t value) { + i::Isolate* isolate = i::Isolate::Current(); + EnsureInitializedForIsolate(isolate, "v8::Integer::NewFromUnsigned()"); + return Integer::NewFromUnsigned(value, reinterpret_cast<Isolate*>(isolate)); +} + + +Local<Integer> v8::Integer::New(int32_t value, Isolate* isolate) { + i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); + ASSERT(internal_isolate->IsInitialized()); if (i::Smi::IsValid(value)) { return Utils::IntegerToLocal(i::Handle<i::Object>(i::Smi::FromInt(value), - isolate)); + internal_isolate)); } - ENTER_V8(isolate); - i::Handle<i::Object> result = isolate->factory()->NewNumber(value); + ENTER_V8(internal_isolate); + i::Handle<i::Object> result = internal_isolate->factory()->NewNumber(value); return Utils::IntegerToLocal(result); } -Local<Integer> Integer::NewFromUnsigned(uint32_t value) { +Local<Integer> v8::Integer::NewFromUnsigned(uint32_t value, Isolate* isolate) { + i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); + ASSERT(internal_isolate->IsInitialized()); bool fits_into_int32_t = (value & (1 << 31)) == 0; if (fits_into_int32_t) { - return Integer::New(static_cast<int32_t>(value)); + return Integer::New(static_cast<int32_t>(value), isolate); } - i::Isolate* isolate = i::Isolate::Current(); - ENTER_V8(isolate); - i::Handle<i::Object> result = isolate->factory()->NewNumber(value); + ENTER_V8(internal_isolate); + i::Handle<i::Object> result = internal_isolate->factory()->NewNumber(value); return Utils::IntegerToLocal(result); } @@ -5182,19 +5329,14 @@ void V8::IgnoreOutOfMemoryException() { } -bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) { +bool V8::AddMessageListener(MessageCallback that) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::V8::AddMessageListener()"); ON_BAILOUT(isolate, "v8::V8::AddMessageListener()", return false); ENTER_V8(isolate); i::HandleScope scope(isolate); NeanderArray listeners(isolate->factory()->message_listeners()); - NeanderObject obj(2); - obj.set(0, *isolate->factory()->NewForeign(FUNCTION_ADDR(that))); - obj.set(1, data.IsEmpty() ? - isolate->heap()->undefined_value() : - *Utils::OpenHandle(*data)); - listeners.add(obj.value()); + listeners.add(isolate->factory()->NewForeign(FUNCTION_ADDR(that))); return true; } @@ -5209,8 +5351,7 @@ void V8::RemoveMessageListeners(MessageCallback that) { for (int i = 0; i < listeners.length(); i++) { if (listeners.get(i)->IsUndefined()) continue; // skip deleted ones - NeanderObject listener(i::JSObject::cast(listeners.get(i))); - i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listener.get(0))); + i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listeners.get(i))); if (callback_obj->foreign_address() == FUNCTION_ADDR(that)) { listeners.set(i, isolate->heap()->undefined_value()); } @@ -5250,13 +5391,6 @@ void V8::SetAddHistogramSampleFunction(AddHistogramSampleCallback callback) { SetAddHistogramSampleFunction(callback); } -void V8::EnableSlidingStateWindow() { - i::Isolate* isolate = i::Isolate::Current(); - if (IsDeadCheck(isolate, "v8::V8::EnableSlidingStateWindow()")) return; - isolate->logger()->EnableSlidingStateWindow(); -} - - void V8::SetFailedAccessCheckCallbackFunction( FailedAccessCheckCallback callback) { i::Isolate* isolate = i::Isolate::Current(); @@ -5266,6 +5400,7 @@ void V8::SetFailedAccessCheckCallbackFunction( isolate->SetFailedAccessCheckCallback(callback); } + void V8::AddObjectGroup(Persistent<Value>* objects, size_t length, RetainedObjectInfo* info) { @@ -5277,6 +5412,19 @@ void V8::AddObjectGroup(Persistent<Value>* objects, } +void V8::AddObjectGroup(Isolate* exportedIsolate, + Persistent<Value>* objects, + size_t length, + RetainedObjectInfo* info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(exportedIsolate); + ASSERT(isolate == i::Isolate::Current()); + if (IsDeadCheck(isolate, "v8::V8::AddObjectGroup()")) return; + STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**)); + isolate->global_handles()->AddObjectGroup( + reinterpret_cast<i::Object***>(objects), length, info); +} + + void V8::AddImplicitReferences(Persistent<Object> parent, Persistent<Value>* children, size_t length) { @@ -6287,7 +6435,8 @@ SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Value> value) { const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title, HeapSnapshot::Type type, - ActivityControl* control) { + ActivityControl* control, + ObjectNameResolver* resolver) { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapProfiler::TakeSnapshot"); i::HeapSnapshot::Type internal_type = i::HeapSnapshot::kFull; @@ -6300,7 +6449,7 @@ const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title, } return reinterpret_cast<const HeapSnapshot*>( i::HeapProfiler::TakeSnapshot( - *Utils::OpenHandle(*title), internal_type, control)); + *Utils::OpenHandle(*title), internal_type, control, resolver)); } @@ -6411,6 +6560,7 @@ void Testing::PrepareStressRun(int run) { void Testing::DeoptimizeAll() { + i::HandleScope scope; internal::Deoptimizer::DeoptimizeAll(); } diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index 7197b6cb54..ca2240b640 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -201,8 +201,6 @@ class Utils { v8::internal::Handle<v8::internal::JSObject> obj); static inline Local<Array> ToLocal( v8::internal::Handle<v8::internal::JSArray> obj); - static inline Local<External> ToLocal( - v8::internal::Handle<v8::internal::Foreign> obj); static inline Local<Message> MessageToLocal( v8::internal::Handle<v8::internal::Object> obj); static inline Local<StackTrace> StackTraceToLocal( @@ -225,6 +223,8 @@ class Utils { v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj); static inline Local<TypeSwitch> ToLocal( v8::internal::Handle<v8::internal::TypeSwitchInfo> obj); + static inline Local<External> ExternalToLocal( + v8::internal::Handle<v8::internal::JSObject> obj); #define DECLARE_OPEN_HANDLE(From, To) \ static inline v8::internal::Handle<v8::internal::To> \ @@ -268,7 +268,6 @@ MAKE_TO_LOCAL(ToLocal, String, String) MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp) MAKE_TO_LOCAL(ToLocal, JSObject, Object) MAKE_TO_LOCAL(ToLocal, JSArray, Array) -MAKE_TO_LOCAL(ToLocal, Foreign, External) MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate) MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate) MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature) @@ -280,6 +279,7 @@ MAKE_TO_LOCAL(StackFrameToLocal, JSObject, StackFrame) MAKE_TO_LOCAL(NumberToLocal, Object, Number) MAKE_TO_LOCAL(IntegerToLocal, Object, Integer) MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32) +MAKE_TO_LOCAL(ExternalToLocal, JSObject, External) #undef MAKE_TO_LOCAL diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h index c47c094756..acd61feff8 100644 --- a/deps/v8/src/arm/assembler-arm-inl.h +++ b/deps/v8/src/arm/assembler-arm-inl.h @@ -75,7 +75,7 @@ Address RelocInfo::target_address_address() { ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY || rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE); - return reinterpret_cast<Address>(Assembler::target_address_address_at(pc_)); + return reinterpret_cast<Address>(Assembler::target_pointer_address_at(pc_)); } @@ -97,25 +97,30 @@ void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) { Object* RelocInfo::target_object() { ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); - return Memory::Object_at(Assembler::target_address_address_at(pc_)); + return reinterpret_cast<Object*>(Assembler::target_pointer_at(pc_)); } Handle<Object> RelocInfo::target_object_handle(Assembler* origin) { ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); - return Memory::Object_Handle_at(Assembler::target_address_address_at(pc_)); + return Handle<Object>(reinterpret_cast<Object**>( + Assembler::target_pointer_at(pc_))); } Object** RelocInfo::target_object_address() { + // Provide a "natural pointer" to the embedded object, + // which can be de-referenced during heap iteration. ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); - return reinterpret_cast<Object**>(Assembler::target_address_address_at(pc_)); + reconstructed_obj_ptr_ = + reinterpret_cast<Object*>(Assembler::target_pointer_at(pc_)); + return &reconstructed_obj_ptr_; } void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) { ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); - Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target)); + Assembler::set_target_pointer_at(pc_, reinterpret_cast<Address>(target)); if (mode == UPDATE_WRITE_BARRIER && host() != NULL && target->IsHeapObject()) { @@ -127,7 +132,8 @@ void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) { Address* RelocInfo::target_reference_address() { ASSERT(rmode_ == EXTERNAL_REFERENCE); - return reinterpret_cast<Address*>(Assembler::target_address_address_at(pc_)); + reconstructed_adr_ptr_ = Assembler::target_address_at(pc_); + return &reconstructed_adr_ptr_; } @@ -159,6 +165,24 @@ void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell, } +static const int kNoCodeAgeSequenceLength = 3; + +Code* RelocInfo::code_age_stub() { + ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); + return Code::GetCodeFromTargetAddress( + Memory::Address_at(pc_ + Assembler::kInstrSize * + (kNoCodeAgeSequenceLength - 1))); +} + + +void RelocInfo::set_code_age_stub(Code* stub) { + ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); + Memory::Address_at(pc_ + Assembler::kInstrSize * + (kNoCodeAgeSequenceLength - 1)) = + stub->instruction_start(); +} + + Address RelocInfo::call_address() { // The 2 instructions offset assumes patched debug break slot or return // sequence. @@ -232,6 +256,8 @@ void RelocInfo::Visit(ObjectVisitor* visitor) { visitor->VisitGlobalPropertyCell(this); } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { visitor->VisitExternalReference(this); + } else if (RelocInfo::IsCodeAgeSequence(mode)) { + visitor->VisitCodeAgeSequence(this); #ifdef ENABLE_DEBUGGER_SUPPORT // TODO(isolates): Get a cached isolate below. } else if (((RelocInfo::IsJSReturn(mode) && @@ -258,6 +284,8 @@ void RelocInfo::Visit(Heap* heap) { StaticVisitor::VisitGlobalPropertyCell(heap, this); } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { StaticVisitor::VisitExternalReference(this); + } else if (RelocInfo::IsCodeAgeSequence(mode)) { + StaticVisitor::VisitCodeAgeSequence(heap, this); #ifdef ENABLE_DEBUGGER_SUPPORT } else if (heap->isolate()->debug()->has_break_points() && ((RelocInfo::IsJSReturn(mode) && @@ -326,7 +354,7 @@ void Assembler::emit(Instr x) { } -Address Assembler::target_address_address_at(Address pc) { +Address Assembler::target_pointer_address_at(Address pc) { Address target_pc = pc; Instr instr = Memory::int32_at(target_pc); // If we have a bx instruction, the instruction before the bx is @@ -356,8 +384,63 @@ Address Assembler::target_address_address_at(Address pc) { } -Address Assembler::target_address_at(Address pc) { - return Memory::Address_at(target_address_address_at(pc)); +Address Assembler::target_pointer_at(Address pc) { + if (IsMovW(Memory::int32_at(pc))) { + ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); + Instruction* instr = Instruction::At(pc); + Instruction* next_instr = Instruction::At(pc + kInstrSize); + return reinterpret_cast<Address>( + (next_instr->ImmedMovwMovtValue() << 16) | + instr->ImmedMovwMovtValue()); + } + return Memory::Address_at(target_pointer_address_at(pc)); +} + + +Address Assembler::target_address_from_return_address(Address pc) { + // Returns the address of the call target from the return address that will + // be returned to after a call. +#ifdef USE_BLX + // Call sequence on V7 or later is : + // movw ip, #... @ call address low 16 + // movt ip, #... @ call address high 16 + // blx ip + // @ return address + // Or pre-V7 or cases that need frequent patching: + // ldr ip, [pc, #...] @ call address + // blx ip + // @ return address + Address candidate = pc - 2 * Assembler::kInstrSize; + Instr candidate_instr(Memory::int32_at(candidate)); + if (IsLdrPcImmediateOffset(candidate_instr)) { + return candidate; + } + candidate = pc - 3 * Assembler::kInstrSize; + ASSERT(IsMovW(Memory::int32_at(candidate)) && + IsMovT(Memory::int32_at(candidate + kInstrSize))); + return candidate; +#else + // Call sequence is: + // mov lr, pc + // ldr pc, [pc, #...] @ call address + // @ return address + return pc - kInstrSize; +#endif +} + + +Address Assembler::return_address_from_call_start(Address pc) { +#ifdef USE_BLX + if (IsLdrPcImmediateOffset(Memory::int32_at(pc))) { + return pc + kInstrSize * 2; + } else { + ASSERT(IsMovW(Memory::int32_at(pc))); + ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); + return pc + kInstrSize * 3; + } +#else + return pc + kInstrSize; +#endif } @@ -373,17 +456,53 @@ void Assembler::set_external_target_at(Address constant_pool_entry, } +static Instr EncodeMovwImmediate(uint32_t immediate) { + ASSERT(immediate < 0x10000); + return ((immediate & 0xf000) << 4) | (immediate & 0xfff); +} + + +void Assembler::set_target_pointer_at(Address pc, Address target) { + if (IsMovW(Memory::int32_at(pc))) { + ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); + uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc); + uint32_t immediate = reinterpret_cast<uint32_t>(target); + uint32_t intermediate = instr_ptr[0]; + intermediate &= ~EncodeMovwImmediate(0xFFFF); + intermediate |= EncodeMovwImmediate(immediate & 0xFFFF); + instr_ptr[0] = intermediate; + intermediate = instr_ptr[1]; + intermediate &= ~EncodeMovwImmediate(0xFFFF); + intermediate |= EncodeMovwImmediate(immediate >> 16); + instr_ptr[1] = intermediate; + ASSERT(IsMovW(Memory::int32_at(pc))); + ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); + CPU::FlushICache(pc, 2 * kInstrSize); + } else { + ASSERT(IsLdrPcImmediateOffset(Memory::int32_at(pc))); + Memory::Address_at(target_pointer_address_at(pc)) = target; + // Intuitively, we would think it is necessary to always flush the + // instruction cache after patching a target address in the code as follows: + // CPU::FlushICache(pc, sizeof(target)); + // However, on ARM, no instruction is actually patched in the case + // of embedded constants of the form: + // ldr ip, [pc, #...] + // since the instruction accessing this address in the constant pool remains + // unchanged. + } +} + + +Address Assembler::target_address_at(Address pc) { + return target_pointer_at(pc); +} + + void Assembler::set_target_address_at(Address pc, Address target) { - Memory::Address_at(target_address_address_at(pc)) = target; - // Intuitively, we would think it is necessary to flush the instruction cache - // after patching a target address in the code as follows: - // CPU::FlushICache(pc, sizeof(target)); - // However, on ARM, no instruction was actually patched by the assignment - // above; the target address is not part of an instruction, it is patched in - // the constant pool and is read via a data access; the instruction accessing - // this address in the constant pool remains unchanged. + set_target_pointer_at(pc, target); } + } } // namespace v8::internal #endif // V8_ARM_ASSEMBLER_ARM_INL_H_ diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index 30a8830c9e..47ea0e2066 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -77,6 +77,9 @@ static unsigned CpuFeaturesImpliedByCompiler() { #endif // defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(__VFP_FP__) // && !defined(__SOFTFP__) #endif // _arm__ + if (answer & (1u << ARMv7)) { + answer |= 1u << UNALIGNED_ACCESSES; + } return answer; } @@ -110,6 +113,14 @@ void CpuFeatures::Probe() { if (FLAG_enable_armv7) { supported_ |= 1u << ARMv7; } + + if (FLAG_enable_sudiv) { + supported_ |= 1u << SUDIV; + } + + if (FLAG_enable_movw_movt) { + supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS; + } #else // __arm__ // Probe for additional features not already known to be available. if (!IsSupported(VFP3) && OS::ArmCpuHasFeature(VFP3)) { @@ -125,6 +136,19 @@ void CpuFeatures::Probe() { found_by_runtime_probing_ |= 1u << ARMv7; } + if (!IsSupported(SUDIV) && OS::ArmCpuHasFeature(SUDIV)) { + found_by_runtime_probing_ |= 1u << SUDIV; + } + + if (!IsSupported(UNALIGNED_ACCESSES) && OS::ArmCpuHasFeature(ARMv7)) { + found_by_runtime_probing_ |= 1u << UNALIGNED_ACCESSES; + } + + if (OS::GetCpuImplementer() == QUALCOMM_IMPLEMENTER && + OS::ArmCpuHasFeature(ARMv7)) { + found_by_runtime_probing_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS; + } + supported_ |= found_by_runtime_probing_; #endif @@ -294,46 +318,11 @@ const Instr kLdrStrInstrArgumentMask = 0x0000ffff; const Instr kLdrStrOffsetMask = 0x00000fff; -// Spare buffer. -static const int kMinimalBufferSize = 4*KB; - - -Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size) - : AssemblerBase(arg_isolate), +Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) + : AssemblerBase(isolate, buffer, buffer_size), recorded_ast_id_(TypeFeedbackId::None()), - positions_recorder_(this), - emit_debug_code_(FLAG_debug_code), - predictable_code_size_(false) { - if (buffer == NULL) { - // Do our own buffer management. - if (buffer_size <= kMinimalBufferSize) { - buffer_size = kMinimalBufferSize; - - if (isolate()->assembler_spare_buffer() != NULL) { - buffer = isolate()->assembler_spare_buffer(); - isolate()->set_assembler_spare_buffer(NULL); - } - } - if (buffer == NULL) { - buffer_ = NewArray<byte>(buffer_size); - } else { - buffer_ = static_cast<byte*>(buffer); - } - buffer_size_ = buffer_size; - own_buffer_ = true; - - } else { - // Use externally provided buffer instead. - ASSERT(buffer_size > 0); - buffer_ = static_cast<byte*>(buffer); - buffer_size_ = buffer_size; - own_buffer_ = false; - } - - // Set up buffer pointers. - ASSERT(buffer_ != NULL); - pc_ = buffer_; - reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); + positions_recorder_(this) { + reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); num_pending_reloc_info_ = 0; next_buffer_check_ = 0; const_pool_blocked_nesting_ = 0; @@ -346,14 +335,6 @@ Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size) Assembler::~Assembler() { ASSERT(const_pool_blocked_nesting_ == 0); - if (own_buffer_) { - if (isolate()->assembler_spare_buffer() == NULL && - buffer_size_ == kMinimalBufferSize) { - isolate()->set_assembler_spare_buffer(buffer_); - } else { - DeleteArray(buffer_); - } - } } @@ -715,12 +696,6 @@ void Assembler::next(Label* L) { } -static Instr EncodeMovwImmediate(uint32_t immediate) { - ASSERT(immediate < 0x10000); - return ((immediate & 0xf000) << 4) | (immediate & 0xfff); -} - - // Low-level code emission routines depending on the addressing mode. // If this returns true then you have to use the rotate_imm and immed_8 // that it returns, because it may have already changed the instruction @@ -785,7 +760,7 @@ static bool fits_shifter(uint32_t imm32, // if they can be encoded in the ARM's 12 bits of immediate-offset instruction // space. There is no guarantee that the relocated location can be similarly // encoded. -bool Operand::must_use_constant_pool(const Assembler* assembler) const { +bool Operand::must_output_reloc_info(const Assembler* assembler) const { if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) { #ifdef DEBUG if (!Serializer::enabled()) { @@ -801,25 +776,28 @@ bool Operand::must_use_constant_pool(const Assembler* assembler) const { } +static bool use_movw_movt(const Operand& x, const Assembler* assembler) { + if (Assembler::use_immediate_embedded_pointer_loads(assembler)) { + return true; + } + if (x.must_output_reloc_info(assembler)) { + return false; + } + return CpuFeatures::IsSupported(ARMv7); +} + + bool Operand::is_single_instruction(const Assembler* assembler, Instr instr) const { if (rm_.is_valid()) return true; uint32_t dummy1, dummy2; - if (must_use_constant_pool(assembler) || + if (must_output_reloc_info(assembler) || !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) { // The immediate operand cannot be encoded as a shifter operand, or use of // constant pool is required. For a mov instruction not setting the // condition code additional instruction conventions can be used. if ((instr & ~kCondMask) == 13*B21) { // mov, S not set - if (must_use_constant_pool(assembler) || - !CpuFeatures::IsSupported(ARMv7)) { - // mov instruction will be an ldr from constant pool (one instruction). - return true; - } else { - // mov instruction will be a mov or movw followed by movt (two - // instructions). - return false; - } + return !use_movw_movt(*this, assembler); } else { // If this is not a mov or mvn instruction there will always an additional // instructions - either mov or ldr. The mov might actually be two @@ -835,6 +813,29 @@ bool Operand::is_single_instruction(const Assembler* assembler, } +void Assembler::move_32_bit_immediate(Condition cond, + Register rd, + SBit s, + const Operand& x) { + if (rd.code() != pc.code() && s == LeaveCC) { + if (use_movw_movt(x, this)) { + if (x.must_output_reloc_info(this)) { + RecordRelocInfo(x.rmode_, x.imm32_, DONT_USE_CONSTANT_POOL); + // Make sure the movw/movt doesn't get separated. + BlockConstPoolFor(2); + } + emit(cond | 0x30*B20 | rd.code()*B12 | + EncodeMovwImmediate(x.imm32_ & 0xffff)); + movt(rd, static_cast<uint32_t>(x.imm32_) >> 16, cond); + return; + } + } + + RecordRelocInfo(x.rmode_, x.imm32_, USE_CONSTANT_POOL); + ldr(rd, MemOperand(pc, 0), cond); +} + + void Assembler::addrmod1(Instr instr, Register rn, Register rd, @@ -845,7 +846,7 @@ void Assembler::addrmod1(Instr instr, // Immediate. uint32_t rotate_imm; uint32_t immed_8; - if (x.must_use_constant_pool(this) || + if (x.must_output_reloc_info(this) || !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) { // The immediate operand cannot be encoded as a shifter operand, so load // it first to register ip and change the original instruction to use ip. @@ -854,24 +855,19 @@ void Assembler::addrmod1(Instr instr, CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed Condition cond = Instruction::ConditionField(instr); if ((instr & ~kCondMask) == 13*B21) { // mov, S not set - if (x.must_use_constant_pool(this) || - !CpuFeatures::IsSupported(ARMv7)) { - RecordRelocInfo(x.rmode_, x.imm32_); - ldr(rd, MemOperand(pc, 0), cond); - } else { - // Will probably use movw, will certainly not use constant pool. - mov(rd, Operand(x.imm32_ & 0xffff), LeaveCC, cond); - movt(rd, static_cast<uint32_t>(x.imm32_) >> 16, cond); - } + move_32_bit_immediate(cond, rd, LeaveCC, x); } else { - // If this is not a mov or mvn instruction we may still be able to avoid - // a constant pool entry by using mvn or movw. - if (!x.must_use_constant_pool(this) && - (instr & kMovMvnMask) != kMovMvnPattern) { - mov(ip, x, LeaveCC, cond); - } else { - RecordRelocInfo(x.rmode_, x.imm32_); + if ((instr & kMovMvnMask) == kMovMvnPattern) { + // Moves need to use a constant pool entry. + RecordRelocInfo(x.rmode_, x.imm32_, USE_CONSTANT_POOL); ldr(ip, MemOperand(pc, 0), cond); + } else if (x.must_output_reloc_info(this)) { + // Otherwise, use most efficient form of fetching from constant pool. + move_32_bit_immediate(cond, ip, LeaveCC, x); + } else { + // If this is not a mov or mvn instruction we may still be able to + // avoid a constant pool entry by using mvn or movw. + mov(ip, x, LeaveCC, cond); } addrmod1(instr, rn, rd, Operand(ip)); } @@ -1178,6 +1174,9 @@ void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) { void Assembler::movw(Register reg, uint32_t immediate, Condition cond) { ASSERT(immediate < 0x10000); + // May use movw if supported, but on unsupported platforms will try to use + // equivalent rotated immed_8 value and other tricks before falling back to a + // constant pool load. mov(reg, Operand(immediate), LeaveCC, cond); } @@ -1207,6 +1206,22 @@ void Assembler::mla(Register dst, Register src1, Register src2, Register srcA, } +void Assembler::mls(Register dst, Register src1, Register src2, Register srcA, + Condition cond) { + ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc)); + emit(cond | B22 | B21 | dst.code()*B16 | srcA.code()*B12 | + src2.code()*B8 | B7 | B4 | src1.code()); +} + + +void Assembler::sdiv(Register dst, Register src1, Register src2, + Condition cond) { + ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); + emit(cond | B26 | B25| B24 | B20 | dst.code()*B16 | 0xf * B12 | + src2.code()*B8 | B4 | src1.code()); +} + + void Assembler::mul(Register dst, Register src1, Register src2, SBit s, Condition cond) { ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc)); @@ -1391,7 +1406,7 @@ void Assembler::msr(SRegisterFieldMask fields, const Operand& src, // Immediate. uint32_t rotate_imm; uint32_t immed_8; - if (src.must_use_constant_pool(this) || + if (src.must_output_reloc_info(this) || !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) { // Immediate operand cannot be encoded, load it first to register ip. RecordRelocInfo(src.rmode_, src.imm32_); @@ -1826,7 +1841,7 @@ void Assembler::vstr(const SwVfpRegister src, const Condition cond) { ASSERT(!operand.rm().is_valid()); ASSERT(operand.am_ == Offset); - vldr(src, operand.rn(), operand.offset(), cond); + vstr(src, operand.rn(), operand.offset(), cond); } @@ -1975,6 +1990,7 @@ static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) { void Assembler::vmov(const DwVfpRegister dst, double imm, + const Register scratch, const Condition cond) { // Dd = immediate // Instruction details available in ARM DDI 0406B, A8-640. @@ -1989,22 +2005,22 @@ void Assembler::vmov(const DwVfpRegister dst, // using vldr from a constant pool. uint32_t lo, hi; DoubleAsTwoUInt32(imm, &lo, &hi); + mov(ip, Operand(lo)); - if (lo == hi) { - // If the lo and hi parts of the double are equal, the literal is easier - // to create. This is the case with 0.0. - mov(ip, Operand(lo)); - vmov(dst, ip, ip); - } else { + if (scratch.is(no_reg)) { // Move the low part of the double into the lower of the corresponsing S // registers of D register dst. - mov(ip, Operand(lo)); vmov(dst.low(), ip, cond); // Move the high part of the double into the higher of the corresponsing S // registers of D register dst. mov(ip, Operand(hi)); vmov(dst.high(), ip, cond); + } else { + // Move the low and high parts of the double to a D register in one + // instruction. + mov(scratch, Operand(hi)); + vmov(dst, ip, scratch, cond); } } } @@ -2333,6 +2349,20 @@ void Assembler::vmul(const DwVfpRegister dst, } +void Assembler::vmla(const DwVfpRegister dst, + const DwVfpRegister src1, + const DwVfpRegister src2, + const Condition cond) { + // Instruction details available in ARM DDI 0406C.b, A8-892. + // cond(31-28) | 11100(27-23) | D=?(22) | 00(21-20) | Vn(19-16) | + // Vd(15-12) | 101(11-9) | sz(8)=1 | N=?(7) | op(6)=0 | M=?(5) | 0(4) | + // Vm(3-0) + unsigned x = (cond | 0x1C*B23 | src1.code()*B16 | + dst.code()*B12 | 0x5*B9 | B8 | src2.code()); + emit(x); +} + + void Assembler::vdiv(const DwVfpRegister dst, const DwVfpRegister src1, const DwVfpRegister src2, @@ -2408,15 +2438,35 @@ void Assembler::vsqrt(const DwVfpRegister dst, // Pseudo instructions. void Assembler::nop(int type) { - // This is mov rx, rx. - ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop. + // ARMv6{K/T2} and v7 have an actual NOP instruction but it serializes + // some of the CPU's pipeline and has to issue. Older ARM chips simply used + // MOV Rx, Rx as NOP and it performs better even in newer CPUs. + // We therefore use MOV Rx, Rx, even on newer CPUs, and use Rx to encode + // a type. + ASSERT(0 <= type && type <= 14); // mov pc, pc isn't a nop. emit(al | 13*B21 | type*B12 | type); } +bool Assembler::IsMovT(Instr instr) { + instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions + ((kNumRegisters-1)*B12) | // mask out register + EncodeMovwImmediate(0xFFFF)); // mask out immediate value + return instr == 0x34*B20; +} + + +bool Assembler::IsMovW(Instr instr) { + instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions + ((kNumRegisters-1)*B12) | // mask out destination + EncodeMovwImmediate(0xFFFF)); // mask out immediate value + return instr == 0x30*B20; +} + + bool Assembler::IsNop(Instr instr, int type) { + ASSERT(0 <= type && type <= 14); // mov pc, pc isn't a nop. // Check for mov rx, rx where x = type. - ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop. return instr == (al | 13*B21 | type*B12 | type); } @@ -2532,18 +2582,21 @@ void Assembler::dd(uint32_t data) { } -void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { +void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data, + UseConstantPoolMode mode) { // We do not try to reuse pool constants. RelocInfo rinfo(pc_, rmode, data, NULL); if (((rmode >= RelocInfo::JS_RETURN) && (rmode <= RelocInfo::DEBUG_BREAK_SLOT)) || - (rmode == RelocInfo::CONST_POOL)) { + (rmode == RelocInfo::CONST_POOL) || + mode == DONT_USE_CONSTANT_POOL) { // Adjust code for new modes. ASSERT(RelocInfo::IsDebugBreakSlot(rmode) || RelocInfo::IsJSReturn(rmode) || RelocInfo::IsComment(rmode) || RelocInfo::IsPosition(rmode) - || RelocInfo::IsConstPool(rmode)); + || RelocInfo::IsConstPool(rmode) + || mode == DONT_USE_CONSTANT_POOL); // These modes do not need an entry in the constant pool. } else { ASSERT(num_pending_reloc_info_ < kMaxNumPendingRelocInfo); @@ -2648,9 +2701,9 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) { b(&after_pool); } - // Put down constant pool marker "Undefined instruction" as specified by - // A5.6 (ARMv7) Instruction set encoding. - emit(kConstantPoolMarker | num_pending_reloc_info_); + // Put down constant pool marker "Undefined instruction". + emit(kConstantPoolMarker | + EncodeConstantPoolLength(num_pending_reloc_info_)); // Emit constant pool entries. for (int i = 0; i < num_pending_reloc_info_; i++) { @@ -2662,17 +2715,19 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) { Instr instr = instr_at(rinfo.pc()); // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0. - ASSERT(IsLdrPcImmediateOffset(instr) && - GetLdrRegisterImmediateOffset(instr) == 0); - - int delta = pc_ - rinfo.pc() - kPcLoadDelta; - // 0 is the smallest delta: - // ldr rd, [pc, #0] - // constant pool marker - // data - ASSERT(is_uint12(delta)); - - instr_at_put(rinfo.pc(), SetLdrRegisterImmediateOffset(instr, delta)); + if (IsLdrPcImmediateOffset(instr) && + GetLdrRegisterImmediateOffset(instr) == 0) { + int delta = pc_ - rinfo.pc() - kPcLoadDelta; + // 0 is the smallest delta: + // ldr rd, [pc, #0] + // constant pool marker + // data + ASSERT(is_uint12(delta)); + + instr_at_put(rinfo.pc(), SetLdrRegisterImmediateOffset(instr, delta)); + } else { + ASSERT(IsMovW(instr)); + } emit(rinfo.data()); } diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index 7f2ce30aee..3b9bb804fd 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -425,7 +425,7 @@ class Operand BASE_EMBEDDED { // actual instruction to use is required for this calculation. For other // instructions instr is ignored. bool is_single_instruction(const Assembler* assembler, Instr instr = 0) const; - bool must_use_constant_pool(const Assembler* assembler) const; + bool must_output_reloc_info(const Assembler* assembler) const; inline int32_t immediate() const { ASSERT(!rm_.is_valid()); @@ -511,6 +511,10 @@ class CpuFeatures : public AllStatic { ASSERT(initialized_); if (f == VFP3 && !FLAG_enable_vfp3) return false; if (f == VFP2 && !FLAG_enable_vfp2) return false; + if (f == SUDIV && !FLAG_enable_sudiv) return false; + if (f == UNALIGNED_ACCESSES && !FLAG_enable_unaligned_accesses) { + return false; + } return (supported_ & (1u << f)) != 0; } @@ -643,15 +647,7 @@ class Assembler : public AssemblerBase { // is too small, a fatal error occurs. No deallocation of the buffer is done // upon destruction of the assembler. Assembler(Isolate* isolate, void* buffer, int buffer_size); - ~Assembler(); - - // Overrides the default provided by FLAG_debug_code. - void set_emit_debug_code(bool value) { emit_debug_code_ = value; } - - // Avoids using instructions that vary in size in unpredictable ways between - // the snapshot and the running VM. This is needed by the full compiler so - // that it can recompile code with debug support and fix the PC. - void set_predictable_code_size(bool value) { predictable_code_size_ = value; } + virtual ~Assembler(); // GetCode emits any pending (non-emitted) code and fills the descriptor // desc. GetCode() is idempotent; it returns the same result if no other @@ -685,13 +681,25 @@ class Assembler : public AssemblerBase { void label_at_put(Label* L, int at_offset); // Return the address in the constant pool of the code target address used by - // the branch/call instruction at pc. - INLINE(static Address target_address_address_at(Address pc)); + // the branch/call instruction at pc, or the object in a mov. + INLINE(static Address target_pointer_address_at(Address pc)); + + // Read/Modify the pointer in the branch/call/move instruction at pc. + INLINE(static Address target_pointer_at(Address pc)); + INLINE(static void set_target_pointer_at(Address pc, Address target)); // Read/Modify the code target address in the branch/call instruction at pc. INLINE(static Address target_address_at(Address pc)); INLINE(static void set_target_address_at(Address pc, Address target)); + // Return the code target address at a call site from the return address + // of that call in the instruction stream. + INLINE(static Address target_address_from_return_address(Address pc)); + + // Given the address of the beginning of a call, return the address + // in the instruction stream that the call will return from. + INLINE(static Address return_address_from_call_start(Address pc)); + // This sets the branch destination (which is in the constant pool on ARM). // This is for calls and branches within generated code. inline static void deserialization_set_special_target_at( @@ -710,22 +718,6 @@ class Assembler : public AssemblerBase { // Size of an instruction. static const int kInstrSize = sizeof(Instr); - // Distance between the instruction referring to the address of the call - // target and the return address. -#ifdef USE_BLX - // Call sequence is: - // ldr ip, [pc, #...] @ call address - // blx ip - // @ return address - static const int kCallTargetAddressOffset = 2 * kInstrSize; -#else - // Call sequence is: - // mov lr, pc - // ldr pc, [pc, #...] @ call address - // @ return address - static const int kCallTargetAddressOffset = kInstrSize; -#endif - // Distance between start of patched return sequence and the emitted address // to jump to. #ifdef USE_BLX @@ -754,6 +746,12 @@ class Assembler : public AssemblerBase { static const int kPatchDebugBreakSlotAddressOffset = kInstrSize; #endif +#ifdef USE_BLX + static const int kPatchDebugBreakSlotReturnOffset = 2 * kInstrSize; +#else + static const int kPatchDebugBreakSlotReturnOffset = kInstrSize; +#endif + // Difference between address of current opcode and value read from pc // register. static const int kPcLoadDelta = 8; @@ -869,6 +867,12 @@ class Assembler : public AssemblerBase { void mla(Register dst, Register src1, Register src2, Register srcA, SBit s = LeaveCC, Condition cond = al); + void mls(Register dst, Register src1, Register src2, Register srcA, + Condition cond = al); + + void sdiv(Register dst, Register src1, Register src2, + Condition cond = al); + void mul(Register dst, Register src1, Register src2, SBit s = LeaveCC, Condition cond = al); @@ -1053,6 +1057,7 @@ class Assembler : public AssemblerBase { void vmov(const DwVfpRegister dst, double imm, + const Register scratch = no_reg, const Condition cond = al); void vmov(const SwVfpRegister dst, const SwVfpRegister src, @@ -1121,6 +1126,10 @@ class Assembler : public AssemblerBase { const DwVfpRegister src1, const DwVfpRegister src2, const Condition cond = al); + void vmla(const DwVfpRegister dst, + const DwVfpRegister src1, + const DwVfpRegister src2, + const Condition cond = al); void vdiv(const DwVfpRegister dst, const DwVfpRegister src1, const DwVfpRegister src2, @@ -1172,7 +1181,19 @@ class Assembler : public AssemblerBase { // Jump unconditionally to given label. void jmp(Label* L) { b(L, al); } - bool predictable_code_size() const { return predictable_code_size_; } + static bool use_immediate_embedded_pointer_loads( + const Assembler* assembler) { +#ifdef USE_BLX + return CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) && + (assembler == NULL || !assembler->predictable_code_size()); +#else + // If not using BLX, all loads from the constant pool cannot be immediate, + // because the ldr pc, [pc + #xxxx] used for calls must be a single + // instruction and cannot be easily distinguished out of context from + // other loads that could use movw/movt. + return false; +#endif + } // Check the code size generated from label to here. int SizeOfCodeGeneratedSince(Label* label) { @@ -1255,8 +1276,6 @@ class Assembler : public AssemblerBase { void db(uint8_t data); void dd(uint32_t data); - int pc_offset() const { return pc_ - buffer_; } - PositionsRecorder* positions_recorder() { return &positions_recorder_; } // Read/patch instructions @@ -1294,12 +1313,16 @@ class Assembler : public AssemblerBase { static Register GetCmpImmediateRegister(Instr instr); static int GetCmpImmediateRawImmediate(Instr instr); static bool IsNop(Instr instr, int type = NON_MARKING_NOP); + static bool IsMovT(Instr instr); + static bool IsMovW(Instr instr); // Constants in pools are accessed via pc relative addressing, which can // reach +/-4KB thereby defining a maximum distance between the instruction // and the accessed constant. static const int kMaxDistToPool = 4*KB; static const int kMaxNumPendingRelocInfo = kMaxDistToPool/kInstrSize; + STATIC_ASSERT((kConstantPoolLengthMaxMask & kMaxNumPendingRelocInfo) == + kMaxNumPendingRelocInfo); // Postpone the generation of the constant pool for the specified number of // instructions. @@ -1314,8 +1337,6 @@ class Assembler : public AssemblerBase { // the relocation info. TypeFeedbackId recorded_ast_id_; - bool emit_debug_code() const { return emit_debug_code_; } - int buffer_space() const { return reloc_info_writer.pos() - pc_; } // Decode branch instruction at pos and return branch target pos @@ -1357,13 +1378,6 @@ class Assembler : public AssemblerBase { } private: - // Code buffer: - // The buffer into which code and relocation info are generated. - byte* buffer_; - int buffer_size_; - // True if the assembler owns the buffer, false if buffer is external. - bool own_buffer_; - int next_buffer_check_; // pc offset of next buffer check // Code generation @@ -1372,7 +1386,6 @@ class Assembler : public AssemblerBase { // not have to check for overflow. The same is true for writes of large // relocation info entries. static const int kGap = 32; - byte* pc_; // the program counter; moves forward // Constant pool generation // Pools are emitted in the instruction stream, preferably after unconditional @@ -1432,6 +1445,12 @@ class Assembler : public AssemblerBase { void GrowBuffer(); inline void emit(Instr x); + // 32-bit immediate values + void move_32_bit_immediate(Condition cond, + Register rd, + SBit s, + const Operand& x); + // Instruction generation void addrmod1(Instr instr, Register rn, Register rd, const Operand& x); void addrmod2(Instr instr, Register rd, const MemOperand& x); @@ -1445,8 +1464,14 @@ class Assembler : public AssemblerBase { void link_to(Label* L, Label* appendix); void next(Label* L); + enum UseConstantPoolMode { + USE_CONSTANT_POOL, + DONT_USE_CONSTANT_POOL + }; + // Record reloc info for current pc_ - void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); + void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0, + UseConstantPoolMode mode = USE_CONSTANT_POOL); friend class RegExpMacroAssemblerARM; friend class RelocInfo; @@ -1454,10 +1479,6 @@ class Assembler : public AssemblerBase { friend class BlockConstPoolScope; PositionsRecorder positions_recorder_; - - bool emit_debug_code_; - bool predictable_code_size_; - friend class PositionsRecorder; friend class EnsureSpace; }; diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index 2d1d7b1199..24d14e8c8a 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -1226,6 +1226,39 @@ void Builtins::Generate_LazyRecompile(MacroAssembler* masm) { } +static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) { + // For now, we are relying on the fact that make_code_young doesn't do any + // garbage collection which allows us to save/restore the registers without + // worrying about which of them contain pointers. We also don't build an + // internal frame to make the code faster, since we shouldn't have to do stack + // crawls in MakeCodeYoung. This seems a bit fragile. + + // The following registers must be saved and restored when calling through to + // the runtime: + // r0 - contains return address (beginning of patch sequence) + // r1 - function object + FrameScope scope(masm, StackFrame::MANUAL); + __ stm(db_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit()); + __ PrepareCallCFunction(1, 0, r1); + __ CallCFunction( + ExternalReference::get_make_code_young_function(masm->isolate()), 1); + __ ldm(ia_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit()); + __ mov(pc, r0); +} + +#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \ +void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \ + MacroAssembler* masm) { \ + GenerateMakeCodeYoungAgainCommon(masm); \ +} \ +void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \ + MacroAssembler* masm) { \ + GenerateMakeCodeYoungAgainCommon(masm); \ +} +CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR) +#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR + + static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, Deoptimizer::BailoutType type) { { diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 5bb2116263..9484f85f97 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -41,8 +41,7 @@ namespace internal { static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, - Condition cond, - bool never_nan_nan); + Condition cond); static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs, Register rhs, @@ -627,24 +626,6 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm, } -void FloatingPointHelper::LoadOperands( - MacroAssembler* masm, - FloatingPointHelper::Destination destination, - Register heap_number_map, - Register scratch1, - Register scratch2, - Label* slow) { - - // Load right operand (r0) to d6 or r2/r3. - LoadNumber(masm, destination, - r0, d7, r2, r3, heap_number_map, scratch1, scratch2, slow); - - // Load left operand (r1) to d7 or r0/r1. - LoadNumber(masm, destination, - r1, d6, r0, r1, heap_number_map, scratch1, scratch2, slow); -} - - void FloatingPointHelper::LoadNumber(MacroAssembler* masm, Destination destination, Register object, @@ -655,11 +636,9 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm, Register scratch1, Register scratch2, Label* not_number) { - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); Label is_smi, done; @@ -716,11 +695,9 @@ void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm, Register scratch3, DwVfpRegister double_scratch, Label* not_number) { - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); Label done; Label not_in_int32_range; @@ -752,13 +729,13 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm, Register int_scratch, Destination destination, DwVfpRegister double_dst, - Register dst1, - Register dst2, + Register dst_mantissa, + Register dst_exponent, Register scratch2, SwVfpRegister single_scratch) { ASSERT(!int_scratch.is(scratch2)); - ASSERT(!int_scratch.is(dst1)); - ASSERT(!int_scratch.is(dst2)); + ASSERT(!int_scratch.is(dst_mantissa)); + ASSERT(!int_scratch.is(dst_exponent)); Label done; @@ -767,56 +744,57 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm, __ vmov(single_scratch, int_scratch); __ vcvt_f64_s32(double_dst, single_scratch); if (destination == kCoreRegisters) { - __ vmov(dst1, dst2, double_dst); + __ vmov(dst_mantissa, dst_exponent, double_dst); } } else { Label fewer_than_20_useful_bits; // Expected output: - // | dst2 | dst1 | + // | dst_exponent | dst_mantissa | // | s | exp | mantissa | // Check for zero. __ cmp(int_scratch, Operand::Zero()); - __ mov(dst2, int_scratch); - __ mov(dst1, int_scratch); + __ mov(dst_exponent, int_scratch); + __ mov(dst_mantissa, int_scratch); __ b(eq, &done); // Preload the sign of the value. - __ and_(dst2, int_scratch, Operand(HeapNumber::kSignMask), SetCC); + __ and_(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask), SetCC); // Get the absolute value of the object (as an unsigned integer). __ rsb(int_scratch, int_scratch, Operand::Zero(), SetCC, mi); // Get mantissa[51:20]. // Get the position of the first set bit. - __ CountLeadingZeros(dst1, int_scratch, scratch2); - __ rsb(dst1, dst1, Operand(31)); + __ CountLeadingZeros(dst_mantissa, int_scratch, scratch2); + __ rsb(dst_mantissa, dst_mantissa, Operand(31)); // Set the exponent. - __ add(scratch2, dst1, Operand(HeapNumber::kExponentBias)); - __ Bfi(dst2, scratch2, scratch2, + __ add(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias)); + __ Bfi(dst_exponent, scratch2, scratch2, HeapNumber::kExponentShift, HeapNumber::kExponentBits); // Clear the first non null bit. __ mov(scratch2, Operand(1)); - __ bic(int_scratch, int_scratch, Operand(scratch2, LSL, dst1)); + __ bic(int_scratch, int_scratch, Operand(scratch2, LSL, dst_mantissa)); - __ cmp(dst1, Operand(HeapNumber::kMantissaBitsInTopWord)); + __ cmp(dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord)); // Get the number of bits to set in the lower part of the mantissa. - __ sub(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC); + __ sub(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord), + SetCC); __ b(mi, &fewer_than_20_useful_bits); // Set the higher 20 bits of the mantissa. - __ orr(dst2, dst2, Operand(int_scratch, LSR, scratch2)); + __ orr(dst_exponent, dst_exponent, Operand(int_scratch, LSR, scratch2)); __ rsb(scratch2, scratch2, Operand(32)); - __ mov(dst1, Operand(int_scratch, LSL, scratch2)); + __ mov(dst_mantissa, Operand(int_scratch, LSL, scratch2)); __ b(&done); __ bind(&fewer_than_20_useful_bits); - __ rsb(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord)); + __ rsb(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord)); __ mov(scratch2, Operand(int_scratch, LSL, scratch2)); - __ orr(dst2, dst2, scratch2); + __ orr(dst_exponent, dst_exponent, scratch2); // Set dst1 to 0. - __ mov(dst1, Operand::Zero()); + __ mov(dst_mantissa, Operand::Zero()); } __ bind(&done); } @@ -826,8 +804,9 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, Register object, Destination destination, DwVfpRegister double_dst, - Register dst1, - Register dst2, + DwVfpRegister double_scratch, + Register dst_mantissa, + Register dst_exponent, Register heap_number_map, Register scratch1, Register scratch2, @@ -843,16 +822,14 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, __ JumpIfNotSmi(object, &obj_is_not_smi); __ SmiUntag(scratch1, object); - ConvertIntToDouble(masm, scratch1, destination, double_dst, dst1, dst2, - scratch2, single_scratch); + ConvertIntToDouble(masm, scratch1, destination, double_dst, dst_mantissa, + dst_exponent, scratch2, single_scratch); __ b(&done); __ bind(&obj_is_not_smi); - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32); // Load the number. @@ -863,36 +840,62 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, __ vldr(double_dst, scratch1, HeapNumber::kValueOffset); __ EmitVFPTruncate(kRoundToZero, - single_scratch, - double_dst, scratch1, + double_dst, scratch2, + double_scratch, kCheckForInexactConversion); // Jump to not_int32 if the operation did not succeed. __ b(ne, not_int32); if (destination == kCoreRegisters) { - __ vmov(dst1, dst2, double_dst); + __ vmov(dst_mantissa, dst_exponent, double_dst); } } else { ASSERT(!scratch1.is(object) && !scratch2.is(object)); - // Load the double value in the destination registers.. - __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset)); + // Load the double value in the destination registers. + bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent); + if (save_registers) { + // Save both output registers, because the other one probably holds + // an important value too. + __ Push(dst_exponent, dst_mantissa); + } + __ Ldrd(dst_mantissa, dst_exponent, + FieldMemOperand(object, HeapNumber::kValueOffset)); // Check for 0 and -0. - __ bic(scratch1, dst1, Operand(HeapNumber::kSignMask)); - __ orr(scratch1, scratch1, Operand(dst2)); + Label zero; + __ bic(scratch1, dst_exponent, Operand(HeapNumber::kSignMask)); + __ orr(scratch1, scratch1, Operand(dst_mantissa)); __ cmp(scratch1, Operand::Zero()); - __ b(eq, &done); + __ b(eq, &zero); // Check that the value can be exactly represented by a 32-bit integer. // Jump to not_int32 if that's not the case. - DoubleIs32BitInteger(masm, dst1, dst2, scratch1, scratch2, not_int32); + Label restore_input_and_miss; + DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2, + &restore_input_and_miss); - // dst1 and dst2 were trashed. Reload the double value. - __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset)); + // dst_* were trashed. Reload the double value. + if (save_registers) { + __ Pop(dst_exponent, dst_mantissa); + } + __ Ldrd(dst_mantissa, dst_exponent, + FieldMemOperand(object, HeapNumber::kValueOffset)); + __ b(&done); + + __ bind(&restore_input_and_miss); + if (save_registers) { + __ Pop(dst_exponent, dst_mantissa); + } + __ b(not_int32); + + __ bind(&zero); + if (save_registers) { + __ Drop(2); + } } __ bind(&done); @@ -906,7 +909,8 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm, Register scratch1, Register scratch2, Register scratch3, - DwVfpRegister double_scratch, + DwVfpRegister double_scratch0, + DwVfpRegister double_scratch1, Label* not_int32) { ASSERT(!dst.is(object)); ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object)); @@ -914,38 +918,34 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm, !scratch1.is(scratch3) && !scratch2.is(scratch3)); - Label done; + Label done, maybe_undefined; __ UntagAndJumpIfSmi(dst, object, &done); - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } - __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32); + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); + + __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, &maybe_undefined); // Object is a heap number. // Convert the floating point value to a 32-bit integer. if (CpuFeatures::IsSupported(VFP2)) { CpuFeatures::Scope scope(VFP2); - SwVfpRegister single_scratch = double_scratch.low(); + // Load the double value. __ sub(scratch1, object, Operand(kHeapObjectTag)); - __ vldr(double_scratch, scratch1, HeapNumber::kValueOffset); + __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset); __ EmitVFPTruncate(kRoundToZero, - single_scratch, - double_scratch, + dst, + double_scratch0, scratch1, - scratch2, + double_scratch1, kCheckForInexactConversion); // Jump to not_int32 if the operation did not succeed. __ b(ne, not_int32); - // Get the result in the destination register. - __ vmov(dst, single_scratch); - } else { // Load the double value in the destination registers. __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset)); @@ -973,20 +973,28 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm, __ tst(scratch1, Operand(HeapNumber::kSignMask)); __ rsb(dst, dst, Operand::Zero(), LeaveCC, mi); } + __ b(&done); + + __ bind(&maybe_undefined); + __ CompareRoot(object, Heap::kUndefinedValueRootIndex); + __ b(ne, not_int32); + // |undefined| is truncated to 0. + __ mov(dst, Operand(Smi::FromInt(0))); + // Fall through. __ bind(&done); } void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm, - Register src1, - Register src2, + Register src_exponent, + Register src_mantissa, Register dst, Register scratch, Label* not_int32) { // Get exponent alone in scratch. __ Ubfx(scratch, - src1, + src_exponent, HeapNumber::kExponentShift, HeapNumber::kExponentBits); @@ -1006,11 +1014,11 @@ void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm, // Another way to put it is that if (exponent - signbit) > 30 then the // number cannot be represented as an int32. Register tmp = dst; - __ sub(tmp, scratch, Operand(src1, LSR, 31)); + __ sub(tmp, scratch, Operand(src_exponent, LSR, 31)); __ cmp(tmp, Operand(30)); __ b(gt, not_int32); // - Bits [21:0] in the mantissa are not null. - __ tst(src2, Operand(0x3fffff)); + __ tst(src_mantissa, Operand(0x3fffff)); __ b(ne, not_int32); // Otherwise the exponent needs to be big enough to shift left all the @@ -1021,19 +1029,19 @@ void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm, // Get the 32 higher bits of the mantissa in dst. __ Ubfx(dst, - src2, + src_mantissa, HeapNumber::kMantissaBitsInTopWord, 32 - HeapNumber::kMantissaBitsInTopWord); __ orr(dst, dst, - Operand(src1, LSL, HeapNumber::kNonMantissaBitsInTopWord)); + Operand(src_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord)); // Create the mask and test the lower bits (of the higher bits). __ rsb(scratch, scratch, Operand(32)); - __ mov(src2, Operand(1)); - __ mov(src1, Operand(src2, LSL, scratch)); - __ sub(src1, src1, Operand(1)); - __ tst(dst, src1); + __ mov(src_mantissa, Operand(1)); + __ mov(src_exponent, Operand(src_mantissa, LSL, scratch)); + __ sub(src_exponent, src_exponent, Operand(1)); + __ tst(dst, src_exponent); __ b(ne, not_int32); } @@ -1157,48 +1165,43 @@ void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { // for "identity and not NaN". static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, - Condition cond, - bool never_nan_nan) { + Condition cond) { Label not_identical; Label heap_number, return_equal; __ cmp(r0, r1); __ b(ne, ¬_identical); - // The two objects are identical. If we know that one of them isn't NaN then - // we now know they test equal. - if (cond != eq || !never_nan_nan) { - // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), - // so we do the second best thing - test it ourselves. - // They are both equal and they are not both Smis so both of them are not - // Smis. If it's not a heap number, then return equal. - if (cond == lt || cond == gt) { - __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE); + // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), + // so we do the second best thing - test it ourselves. + // They are both equal and they are not both Smis so both of them are not + // Smis. If it's not a heap number, then return equal. + if (cond == lt || cond == gt) { + __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE); + __ b(ge, slow); + } else { + __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); + __ b(eq, &heap_number); + // Comparing JS objects with <=, >= is complicated. + if (cond != eq) { + __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE)); __ b(ge, slow); - } else { - __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); - __ b(eq, &heap_number); - // Comparing JS objects with <=, >= is complicated. - if (cond != eq) { - __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE)); - __ b(ge, slow); - // Normally here we fall through to return_equal, but undefined is - // special: (undefined == undefined) == true, but - // (undefined <= undefined) == false! See ECMAScript 11.8.5. - if (cond == le || cond == ge) { - __ cmp(r4, Operand(ODDBALL_TYPE)); - __ b(ne, &return_equal); - __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); - __ cmp(r0, r2); - __ b(ne, &return_equal); - if (cond == le) { - // undefined <= undefined should fail. - __ mov(r0, Operand(GREATER)); - } else { - // undefined >= undefined should fail. - __ mov(r0, Operand(LESS)); - } - __ Ret(); + // Normally here we fall through to return_equal, but undefined is + // special: (undefined == undefined) == true, but + // (undefined <= undefined) == false! See ECMAScript 11.8.5. + if (cond == le || cond == ge) { + __ cmp(r4, Operand(ODDBALL_TYPE)); + __ b(ne, &return_equal); + __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); + __ cmp(r0, r2); + __ b(ne, &return_equal); + if (cond == le) { + // undefined <= undefined should fail. + __ mov(r0, Operand(GREATER)); + } else { + // undefined >= undefined should fail. + __ mov(r0, Operand(LESS)); } + __ Ret(); } } } @@ -1213,47 +1216,45 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, } __ Ret(); - if (cond != eq || !never_nan_nan) { - // For less and greater we don't have to check for NaN since the result of - // x < x is false regardless. For the others here is some code to check - // for NaN. - if (cond != lt && cond != gt) { - __ bind(&heap_number); - // It is a heap number, so return non-equal if it's NaN and equal if it's - // not NaN. - - // The representation of NaN values has all exponent bits (52..62) set, - // and not all mantissa bits (0..51) clear. - // Read top bits of double representation (second word of value). - __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); - // Test that exponent bits are all set. - __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits); - // NaNs have all-one exponents so they sign extend to -1. - __ cmp(r3, Operand(-1)); - __ b(ne, &return_equal); - - // Shift out flag and all exponent bits, retaining only mantissa. - __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord)); - // Or with all low-bits of mantissa. - __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); - __ orr(r0, r3, Operand(r2), SetCC); - // For equal we already have the right value in r0: Return zero (equal) - // if all bits in mantissa are zero (it's an Infinity) and non-zero if - // not (it's a NaN). For <= and >= we need to load r0 with the failing - // value if it's a NaN. - if (cond != eq) { - // All-zero means Infinity means equal. - __ Ret(eq); - if (cond == le) { - __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. - } else { - __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. - } + // For less and greater we don't have to check for NaN since the result of + // x < x is false regardless. For the others here is some code to check + // for NaN. + if (cond != lt && cond != gt) { + __ bind(&heap_number); + // It is a heap number, so return non-equal if it's NaN and equal if it's + // not NaN. + + // The representation of NaN values has all exponent bits (52..62) set, + // and not all mantissa bits (0..51) clear. + // Read top bits of double representation (second word of value). + __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); + // Test that exponent bits are all set. + __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits); + // NaNs have all-one exponents so they sign extend to -1. + __ cmp(r3, Operand(-1)); + __ b(ne, &return_equal); + + // Shift out flag and all exponent bits, retaining only mantissa. + __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord)); + // Or with all low-bits of mantissa. + __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); + __ orr(r0, r3, Operand(r2), SetCC); + // For equal we already have the right value in r0: Return zero (equal) + // if all bits in mantissa are zero (it's an Infinity) and non-zero if + // not (it's a NaN). For <= and >= we need to load r0 with the failing + // value if it's a NaN. + if (cond != eq) { + // All-zero means Infinity means equal. + __ Ret(eq); + if (cond == le) { + __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. + } else { + __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. } - __ Ret(); } - // No fall through here. + __ Ret(); } + // No fall through here. __ bind(¬_identical); } @@ -1687,42 +1688,60 @@ void NumberToStringStub::Generate(MacroAssembler* masm) { } -// On entry lhs_ and rhs_ are the values to be compared. +static void ICCompareStub_CheckInputType(MacroAssembler* masm, + Register input, + Register scratch, + CompareIC::State expected, + Label* fail) { + Label ok; + if (expected == CompareIC::SMI) { + __ JumpIfNotSmi(input, fail); + } else if (expected == CompareIC::HEAP_NUMBER) { + __ JumpIfSmi(input, &ok); + __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail, + DONT_DO_SMI_CHECK); + } + // We could be strict about symbol/string here, but as long as + // hydrogen doesn't care, the stub doesn't have to care either. + __ bind(&ok); +} + + +// On entry r1 and r2 are the values to be compared. // On exit r0 is 0, positive or negative to indicate the result of // the comparison. -void CompareStub::Generate(MacroAssembler* masm) { - ASSERT((lhs_.is(r0) && rhs_.is(r1)) || - (lhs_.is(r1) && rhs_.is(r0))); +void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { + Register lhs = r1; + Register rhs = r0; + Condition cc = GetCondition(); + + Label miss; + ICCompareStub_CheckInputType(masm, lhs, r2, left_, &miss); + ICCompareStub_CheckInputType(masm, rhs, r3, right_, &miss); Label slow; // Call builtin. Label not_smis, both_loaded_as_doubles, lhs_not_nan; - if (include_smi_compare_) { - Label not_two_smis, smi_done; - __ orr(r2, r1, r0); - __ JumpIfNotSmi(r2, ¬_two_smis); - __ mov(r1, Operand(r1, ASR, 1)); - __ sub(r0, r1, Operand(r0, ASR, 1)); - __ Ret(); - __ bind(¬_two_smis); - } else if (FLAG_debug_code) { - __ orr(r2, r1, r0); - __ tst(r2, Operand(kSmiTagMask)); - __ Assert(ne, "CompareStub: unexpected smi operands."); - } + Label not_two_smis, smi_done; + __ orr(r2, r1, r0); + __ JumpIfNotSmi(r2, ¬_two_smis); + __ mov(r1, Operand(r1, ASR, 1)); + __ sub(r0, r1, Operand(r0, ASR, 1)); + __ Ret(); + __ bind(¬_two_smis); // NOTICE! This code is only reached after a smi-fast-case check, so // it is certain that at least one operand isn't a smi. // Handle the case where the objects are identical. Either returns the answer // or goes to slow. Only falls through if the objects were not identical. - EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); + EmitIdenticalObjectComparison(masm, &slow, cc); // If either is a Smi (we know that not both are), then they can only // be strictly equal if the other is a HeapNumber. STATIC_ASSERT(kSmiTag == 0); ASSERT_EQ(0, Smi::FromInt(0)); - __ and_(r2, lhs_, Operand(rhs_)); + __ and_(r2, lhs, Operand(rhs)); __ JumpIfNotSmi(r2, ¬_smis); // One operand is a smi. EmitSmiNonsmiComparison generates code that can: // 1) Return the answer. @@ -1733,7 +1752,7 @@ void CompareStub::Generate(MacroAssembler* masm) { // comparison. If VFP3 is supported the double values of the numbers have // been loaded into d7 and d6. Otherwise, the double values have been loaded // into r0, r1, r2, and r3. - EmitSmiNonsmiComparison(masm, lhs_, rhs_, &lhs_not_nan, &slow, strict_); + EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict()); __ bind(&both_loaded_as_doubles); // The arguments have been converted to doubles and stored in d6 and d7, if @@ -1756,7 +1775,7 @@ void CompareStub::Generate(MacroAssembler* masm) { // If one of the sides was a NaN then the v flag is set. Load r0 with // whatever it takes to make the comparison fail, since comparisons with NaN // always fail. - if (cc_ == lt || cc_ == le) { + if (cc == lt || cc == le) { __ mov(r0, Operand(GREATER)); } else { __ mov(r0, Operand(LESS)); @@ -1765,19 +1784,19 @@ void CompareStub::Generate(MacroAssembler* masm) { } else { // Checks for NaN in the doubles we have loaded. Can return the answer or // fall through if neither is a NaN. Also binds lhs_not_nan. - EmitNanCheck(masm, &lhs_not_nan, cc_); + EmitNanCheck(masm, &lhs_not_nan, cc); // Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns the // answer. Never falls through. - EmitTwoNonNanDoubleComparison(masm, cc_); + EmitTwoNonNanDoubleComparison(masm, cc); } __ bind(¬_smis); // At this point we know we are dealing with two different objects, // and neither of them is a Smi. The objects are in rhs_ and lhs_. - if (strict_) { + if (strict()) { // This returns non-equal for some object types, or falls through if it // was not lucky. - EmitStrictTwoHeapObjectCompare(masm, lhs_, rhs_); + EmitStrictTwoHeapObjectCompare(masm, lhs, rhs); } Label check_for_symbols; @@ -1787,8 +1806,8 @@ void CompareStub::Generate(MacroAssembler* masm) { // that case. If the inputs are not doubles then jumps to check_for_symbols. // In this case r2 will contain the type of rhs_. Never falls through. EmitCheckForTwoHeapNumbers(masm, - lhs_, - rhs_, + lhs, + rhs, &both_loaded_as_doubles, &check_for_symbols, &flat_string_check); @@ -1796,31 +1815,31 @@ void CompareStub::Generate(MacroAssembler* masm) { __ bind(&check_for_symbols); // In the strict case the EmitStrictTwoHeapObjectCompare already took care of // symbols. - if (cc_ == eq && !strict_) { + if (cc == eq && !strict()) { // Returns an answer for two symbols or two detectable objects. // Otherwise jumps to string case or not both strings case. // Assumes that r2 is the type of rhs_ on entry. - EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check, &slow); + EmitCheckForSymbolsOrObjects(masm, lhs, rhs, &flat_string_check, &slow); } // Check for both being sequential ASCII strings, and inline if that is the // case. __ bind(&flat_string_check); - __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow); + __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, r2, r3, &slow); __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3); - if (cc_ == eq) { + if (cc == eq) { StringCompareStub::GenerateFlatAsciiStringEquals(masm, - lhs_, - rhs_, + lhs, + rhs, r2, r3, r4); } else { StringCompareStub::GenerateCompareFlatAsciiStrings(masm, - lhs_, - rhs_, + lhs, + rhs, r2, r3, r4, @@ -1830,18 +1849,18 @@ void CompareStub::Generate(MacroAssembler* masm) { __ bind(&slow); - __ Push(lhs_, rhs_); + __ Push(lhs, rhs); // Figure out which native to call and setup the arguments. Builtins::JavaScript native; - if (cc_ == eq) { - native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; + if (cc == eq) { + native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; } else { native = Builtins::COMPARE; int ncr; // NaN compare result - if (cc_ == lt || cc_ == le) { + if (cc == lt || cc == le) { ncr = GREATER; } else { - ASSERT(cc_ == gt || cc_ == ge); // remaining cases + ASSERT(cc == gt || cc == ge); // remaining cases ncr = LESS; } __ mov(r0, Operand(Smi::FromInt(ncr))); @@ -1851,6 +1870,9 @@ void CompareStub::Generate(MacroAssembler* masm) { // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) // tagged as a small integer. __ InvokeBuiltin(native, JUMP_FUNCTION); + + __ bind(&miss); + GenerateMiss(masm); } @@ -2334,20 +2356,23 @@ void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { } +void BinaryOpStub::Initialize() { + platform_specific_bit_ = CpuFeatures::IsSupported(VFP2); +} + + void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { Label get_result; __ Push(r1, r0); __ mov(r2, Operand(Smi::FromInt(MinorKey()))); - __ mov(r1, Operand(Smi::FromInt(op_))); - __ mov(r0, Operand(Smi::FromInt(operands_type_))); - __ Push(r2, r1, r0); + __ push(r2); __ TailCallExternalReference( ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()), - 5, + 3, 1); } @@ -2358,59 +2383,8 @@ void BinaryOpStub::GenerateTypeTransitionWithSavedArgs( } -void BinaryOpStub::Generate(MacroAssembler* masm) { - // Explicitly allow generation of nested stubs. It is safe here because - // generation code does not use any raw pointers. - AllowStubCallsScope allow_stub_calls(masm, true); - - switch (operands_type_) { - case BinaryOpIC::UNINITIALIZED: - GenerateTypeTransition(masm); - break; - case BinaryOpIC::SMI: - GenerateSmiStub(masm); - break; - case BinaryOpIC::INT32: - GenerateInt32Stub(masm); - break; - case BinaryOpIC::HEAP_NUMBER: - GenerateHeapNumberStub(masm); - break; - case BinaryOpIC::ODDBALL: - GenerateOddballStub(masm); - break; - case BinaryOpIC::BOTH_STRING: - GenerateBothStringStub(masm); - break; - case BinaryOpIC::STRING: - GenerateStringStub(masm); - break; - case BinaryOpIC::GENERIC: - GenerateGeneric(masm); - break; - default: - UNREACHABLE(); - } -} - - -void BinaryOpStub::PrintName(StringStream* stream) { - const char* op_name = Token::Name(op_); - const char* overwrite_name; - switch (mode_) { - case NO_OVERWRITE: overwrite_name = "Alloc"; break; - case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; - case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; - default: overwrite_name = "UnknownOverwrite"; break; - } - stream->Add("BinaryOpStub_%s_%s_%s", - op_name, - overwrite_name, - BinaryOpIC::GetName(operands_type_)); -} - - -void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) { +void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm, + Token::Value op) { Register left = r1; Register right = r0; Register scratch1 = r7; @@ -2420,7 +2394,7 @@ void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) { STATIC_ASSERT(kSmiTag == 0); Label not_smi_result; - switch (op_) { + switch (op) { case Token::ADD: __ add(right, left, Operand(right), SetCC); // Add optimistically. __ Ret(vc); @@ -2535,10 +2509,24 @@ void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) { } -void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, - bool smi_operands, - Label* not_numbers, - Label* gc_required) { +void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, + Register result, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* gc_required, + OverwriteMode mode); + + +void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, + BinaryOpIC::TypeInfo left_type, + BinaryOpIC::TypeInfo right_type, + bool smi_operands, + Label* not_numbers, + Label* gc_required, + Label* miss, + Token::Value op, + OverwriteMode mode) { Register left = r1; Register right = r0; Register scratch1 = r7; @@ -2546,15 +2534,21 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, Register scratch3 = r4; ASSERT(smi_operands || (not_numbers != NULL)); - if (smi_operands && FLAG_debug_code) { - __ AbortIfNotSmi(left); - __ AbortIfNotSmi(right); + if (smi_operands) { + __ AssertSmi(left); + __ AssertSmi(right); + } + if (left_type == BinaryOpIC::SMI) { + __ JumpIfNotSmi(left, miss); + } + if (right_type == BinaryOpIC::SMI) { + __ JumpIfNotSmi(right, miss); } Register heap_number_map = r6; __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); - switch (op_) { + switch (op) { case Token::ADD: case Token::SUB: case Token::MUL: @@ -2564,25 +2558,44 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, // depending on whether VFP3 is available or not. FloatingPointHelper::Destination destination = CpuFeatures::IsSupported(VFP2) && - op_ != Token::MOD ? + op != Token::MOD ? FloatingPointHelper::kVFPRegisters : FloatingPointHelper::kCoreRegisters; // Allocate new heap number for result. Register result = r5; - GenerateHeapResultAllocation( - masm, result, heap_number_map, scratch1, scratch2, gc_required); + BinaryOpStub_GenerateHeapResultAllocation( + masm, result, heap_number_map, scratch1, scratch2, gc_required, mode); // Load the operands. if (smi_operands) { FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); } else { - FloatingPointHelper::LoadOperands(masm, - destination, - heap_number_map, - scratch1, - scratch2, - not_numbers); + // Load right operand to d7 or r2/r3. + if (right_type == BinaryOpIC::INT32) { + FloatingPointHelper::LoadNumberAsInt32Double( + masm, right, destination, d7, d8, r2, r3, heap_number_map, + scratch1, scratch2, s0, miss); + } else { + Label* fail = (right_type == BinaryOpIC::HEAP_NUMBER) ? miss + : not_numbers; + FloatingPointHelper::LoadNumber( + masm, destination, right, d7, r2, r3, heap_number_map, + scratch1, scratch2, fail); + } + // Load left operand to d6 or r0/r1. This keeps r0/r1 intact if it + // jumps to |miss|. + if (left_type == BinaryOpIC::INT32) { + FloatingPointHelper::LoadNumberAsInt32Double( + masm, left, destination, d6, d8, r0, r1, heap_number_map, + scratch1, scratch2, s0, miss); + } else { + Label* fail = (left_type == BinaryOpIC::HEAP_NUMBER) ? miss + : not_numbers; + FloatingPointHelper::LoadNumber( + masm, destination, left, d6, r0, r1, heap_number_map, + scratch1, scratch2, fail); + } } // Calculate the result. @@ -2591,7 +2604,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, // d6: Left value // d7: Right value CpuFeatures::Scope scope(VFP2); - switch (op_) { + switch (op) { case Token::ADD: __ vadd(d5, d6, d7); break; @@ -2615,7 +2628,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, } else { // Call the C function to handle the double operation. FloatingPointHelper::CallCCodeForDoubleOperation(masm, - op_, + op, result, scratch1); if (FLAG_debug_code) { @@ -2656,7 +2669,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, } Label result_not_a_smi; - switch (op_) { + switch (op) { case Token::BIT_OR: __ orr(r2, r3, Operand(r2)); break; @@ -2707,8 +2720,9 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, __ AllocateHeapNumber( result, scratch1, scratch2, heap_number_map, gc_required); } else { - GenerateHeapResultAllocation( - masm, result, heap_number_map, scratch1, scratch2, gc_required); + BinaryOpStub_GenerateHeapResultAllocation( + masm, result, heap_number_map, scratch1, scratch2, gc_required, + mode); } // r2: Answer as signed int32. @@ -2723,7 +2737,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, // mentioned above SHR needs to always produce a positive result. CpuFeatures::Scope scope(VFP2); __ vmov(s0, r2); - if (op_ == Token::SHR) { + if (op == Token::SHR) { __ vcvt_f64_u32(d0, s0); } else { __ vcvt_f64_s32(d0, s0); @@ -2748,12 +2762,14 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, // Generate the smi code. If the operation on smis are successful this return is // generated. If the result is not a smi and heap number allocation is not // requested the code falls through. If number allocation is requested but a -// heap number cannot be allocated the code jumps to the lable gc_required. -void BinaryOpStub::GenerateSmiCode( +// heap number cannot be allocated the code jumps to the label gc_required. +void BinaryOpStub_GenerateSmiCode( MacroAssembler* masm, Label* use_runtime, Label* gc_required, - SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { + Token::Value op, + BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results, + OverwriteMode mode) { Label not_smis; Register left = r1; @@ -2766,12 +2782,14 @@ void BinaryOpStub::GenerateSmiCode( __ JumpIfNotSmi(scratch1, ¬_smis); // If the smi-smi operation results in a smi return is generated. - GenerateSmiSmiOperation(masm); + BinaryOpStub_GenerateSmiSmiOperation(masm, op); // If heap number results are possible generate the result in an allocated // heap number. - if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { - GenerateFPOperation(masm, true, use_runtime, gc_required); + if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) { + BinaryOpStub_GenerateFPOperation( + masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true, + use_runtime, gc_required, ¬_smis, op, mode); } __ bind(¬_smis); } @@ -2783,14 +2801,14 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { if (result_type_ == BinaryOpIC::UNINITIALIZED || result_type_ == BinaryOpIC::SMI) { // Only allow smi results. - GenerateSmiCode(masm, &call_runtime, NULL, NO_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, NULL, op_, NO_HEAPNUMBER_RESULTS, mode_); } else { // Allow heap number result and don't make a transition if a heap number // cannot be allocated. - GenerateSmiCode(masm, - &call_runtime, - &call_runtime, - ALLOW_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS, + mode_); } // Code falls through if the result is not returned as either a smi or heap @@ -2798,23 +2816,14 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { GenerateTypeTransition(masm); __ bind(&call_runtime); + GenerateRegisterArgsPush(masm); GenerateCallRuntime(masm); } -void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { - ASSERT(operands_type_ == BinaryOpIC::STRING); - ASSERT(op_ == Token::ADD); - // Try to add arguments as strings, otherwise, transition to the generic - // BinaryOpIC type. - GenerateAddStrings(masm); - GenerateTypeTransition(masm); -} - - void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { Label call_runtime; - ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); + ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING); ASSERT(op_ == Token::ADD); // If both arguments are strings, call the string add stub. // Otherwise, do a transition. @@ -2843,14 +2852,13 @@ void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { - ASSERT(operands_type_ == BinaryOpIC::INT32); + ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); Register left = r1; Register right = r0; Register scratch1 = r7; Register scratch2 = r9; DwVfpRegister double_scratch = d0; - SwVfpRegister single_scratch = s3; Register heap_number_result = no_reg; Register heap_number_map = r6; @@ -2866,7 +2874,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Label skip; __ orr(scratch1, left, right); __ JumpIfNotSmi(scratch1, &skip); - GenerateSmiSmiOperation(masm); + BinaryOpStub_GenerateSmiSmiOperation(masm, op_); // Fall through if the result is not a smi. __ bind(&skip); @@ -2876,6 +2884,15 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { case Token::MUL: case Token::DIV: case Token::MOD: { + // It could be that only SMIs have been seen at either the left + // or the right operand. For precise type feedback, patch the IC + // again if this changes. + if (left_type_ == BinaryOpIC::SMI) { + __ JumpIfNotSmi(left, &transition); + } + if (right_type_ == BinaryOpIC::SMI) { + __ JumpIfNotSmi(right, &transition); + } // Load both operands and check that they are 32-bit integer. // Jump to type transition if they are not. The registers r0 and r1 (right // and left) are preserved for the runtime call. @@ -2888,6 +2905,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { right, destination, d7, + d8, r2, r3, heap_number_map, @@ -2899,6 +2917,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { left, destination, d6, + d8, r4, r5, heap_number_map, @@ -2934,10 +2953,10 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { // transition. __ EmitVFPTruncate(kRoundToZero, - single_scratch, - d5, scratch1, - scratch2); + d5, + scratch2, + d8); if (result_type_ <= BinaryOpIC::INT32) { // If the ne condition is set, result does @@ -2946,7 +2965,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { } // Check if the result fits in a smi. - __ vmov(scratch1, single_scratch); __ add(scratch2, scratch1, Operand(0x40000000), SetCC); // If not try to return a heap number. __ b(mi, &return_heap_number); @@ -2973,12 +2991,13 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { : BinaryOpIC::INT32)) { // We are using vfp registers so r5 is available. heap_number_result = r5; - GenerateHeapResultAllocation(masm, - heap_number_result, - heap_number_map, - scratch1, - scratch2, - &call_runtime); + BinaryOpStub_GenerateHeapResultAllocation(masm, + heap_number_result, + heap_number_map, + scratch1, + scratch2, + &call_runtime, + mode_); __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); __ vstr(d5, r0, HeapNumber::kValueOffset); __ mov(r0, heap_number_result); @@ -2997,12 +3016,13 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { // Allocate a heap number to store the result. heap_number_result = r5; - GenerateHeapResultAllocation(masm, - heap_number_result, - heap_number_map, - scratch1, - scratch2, - &pop_and_call_runtime); + BinaryOpStub_GenerateHeapResultAllocation(masm, + heap_number_result, + heap_number_map, + scratch1, + scratch2, + &pop_and_call_runtime, + mode_); // Load the left value from the value saved on the stack. __ Pop(r1, r0); @@ -3041,6 +3061,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { scratch2, scratch3, d0, + d1, &transition); FloatingPointHelper::LoadNumberAsInt32(masm, right, @@ -3050,6 +3071,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { scratch2, scratch3, d0, + d1, &transition); // The ECMA-262 standard specifies that, for shift operations, only the @@ -3105,12 +3127,13 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { __ bind(&return_heap_number); heap_number_result = r5; - GenerateHeapResultAllocation(masm, - heap_number_result, - heap_number_map, - scratch1, - scratch2, - &call_runtime); + BinaryOpStub_GenerateHeapResultAllocation(masm, + heap_number_result, + heap_number_map, + scratch1, + scratch2, + &call_runtime, + mode_); if (CpuFeatures::IsSupported(VFP2)) { CpuFeatures::Scope scope(VFP2); @@ -3154,6 +3177,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { } __ bind(&call_runtime); + GenerateRegisterArgsPush(masm); GenerateCallRuntime(masm); } @@ -3192,20 +3216,32 @@ void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { - Label call_runtime; - GenerateFPOperation(masm, false, &call_runtime, &call_runtime); + Label call_runtime, transition; + BinaryOpStub_GenerateFPOperation( + masm, left_type_, right_type_, false, + &transition, &call_runtime, &transition, op_, mode_); + + __ bind(&transition); + GenerateTypeTransition(masm); __ bind(&call_runtime); + GenerateRegisterArgsPush(masm); GenerateCallRuntime(masm); } void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { - Label call_runtime, call_string_add_or_runtime; + Label call_runtime, call_string_add_or_runtime, transition; - GenerateSmiCode(masm, &call_runtime, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS, mode_); - GenerateFPOperation(masm, false, &call_string_add_or_runtime, &call_runtime); + BinaryOpStub_GenerateFPOperation( + masm, left_type_, right_type_, false, + &call_string_add_or_runtime, &call_runtime, &transition, op_, mode_); + + __ bind(&transition); + GenerateTypeTransition(masm); __ bind(&call_string_add_or_runtime); if (op_ == Token::ADD) { @@ -3213,6 +3249,7 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { } __ bind(&call_runtime); + GenerateRegisterArgsPush(masm); GenerateCallRuntime(masm); } @@ -3248,61 +3285,20 @@ void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { } -void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { - GenerateRegisterArgsPush(masm); - switch (op_) { - case Token::ADD: - __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); - break; - case Token::SUB: - __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); - break; - case Token::MUL: - __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); - break; - case Token::DIV: - __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); - break; - case Token::MOD: - __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); - break; - case Token::BIT_OR: - __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); - break; - case Token::BIT_AND: - __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); - break; - case Token::BIT_XOR: - __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); - break; - case Token::SAR: - __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); - break; - case Token::SHR: - __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); - break; - case Token::SHL: - __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); - break; - default: - UNREACHABLE(); - } -} - - -void BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, - Register result, - Register heap_number_map, - Register scratch1, - Register scratch2, - Label* gc_required) { +void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, + Register result, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* gc_required, + OverwriteMode mode) { // Code below will scratch result if allocation fails. To keep both arguments // intact for the runtime call result cannot be one of these. ASSERT(!result.is(r0) && !result.is(r1)); - if (mode_ == OVERWRITE_LEFT || mode_ == OVERWRITE_RIGHT) { + if (mode == OVERWRITE_LEFT || mode == OVERWRITE_RIGHT) { Label skip_allocation, allocated; - Register overwritable_operand = mode_ == OVERWRITE_LEFT ? r1 : r0; + Register overwritable_operand = mode == OVERWRITE_LEFT ? r1 : r0; // If the overwritable operand is already an object, we skip the // allocation of a heap number. __ JumpIfNotSmi(overwritable_operand, &skip_allocation); @@ -3315,7 +3311,7 @@ void BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, __ mov(result, Operand(overwritable_operand)); __ bind(&allocated); } else { - ASSERT(mode_ == NO_OVERWRITE); + ASSERT(mode == NO_OVERWRITE); __ AllocateHeapNumber( result, scratch1, scratch2, heap_number_map, gc_required); } @@ -3444,8 +3440,8 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { ExternalReference(RuntimeFunction(), masm->isolate()); __ TailCallExternalReference(runtime_function, 1, 1); } else { - ASSERT(CpuFeatures::IsSupported(VFP3)); - CpuFeatures::Scope scope(VFP3); + ASSERT(CpuFeatures::IsSupported(VFP2)); + CpuFeatures::Scope scope(VFP2); Label no_update; Label skip_cache; @@ -3636,13 +3632,13 @@ void MathPowStub::Generate(MacroAssembler* masm) { Label not_plus_half; // Test for 0.5. - __ vmov(double_scratch, 0.5); + __ vmov(double_scratch, 0.5, scratch); __ VFPCompareAndSetFlags(double_exponent, double_scratch); __ b(ne, ¬_plus_half); // Calculates square root of base. Check for the special case of // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). - __ vmov(double_scratch, -V8_INFINITY); + __ vmov(double_scratch, -V8_INFINITY, scratch); __ VFPCompareAndSetFlags(double_base, double_scratch); __ vneg(double_result, double_scratch, eq); __ b(eq, &done); @@ -3653,20 +3649,20 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ jmp(&done); __ bind(¬_plus_half); - __ vmov(double_scratch, -0.5); + __ vmov(double_scratch, -0.5, scratch); __ VFPCompareAndSetFlags(double_exponent, double_scratch); __ b(ne, &call_runtime); // Calculates square root of base. Check for the special case of // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). - __ vmov(double_scratch, -V8_INFINITY); + __ vmov(double_scratch, -V8_INFINITY, scratch); __ VFPCompareAndSetFlags(double_base, double_scratch); __ vmov(double_result, kDoubleRegZero, eq); __ b(eq, &done); // Add +0 to convert -0 to +0. __ vadd(double_scratch, double_base, kDoubleRegZero); - __ vmov(double_result, 1.0); + __ vmov(double_result, 1.0, scratch); __ vsqrt(double_scratch, double_scratch); __ vdiv(double_result, double_result, double_scratch); __ jmp(&done); @@ -3701,7 +3697,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ mov(exponent, scratch); } __ vmov(double_scratch, double_base); // Back up base. - __ vmov(double_result, 1.0); + __ vmov(double_result, 1.0, scratch2); // Get absolute value of exponent. __ cmp(scratch, Operand(0)); @@ -3717,7 +3713,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ cmp(exponent, Operand(0)); __ b(ge, &done); - __ vmov(double_scratch, 1.0); + __ vmov(double_scratch, 1.0, scratch); __ vdiv(double_result, double_scratch, double_result); // Test whether result is zero. Bail out to check for subnormal result. // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. @@ -4930,7 +4926,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // subject: Subject string // regexp_data: RegExp data (FixedArray) // r0: Instance type of subject string - STATIC_ASSERT(4 == kAsciiStringTag); + STATIC_ASSERT(4 == kOneByteStringTag); STATIC_ASSERT(kTwoByteStringTag == 0); // Find the code object based on the assumptions above. __ and_(r0, r0, Operand(kStringEncodingMask)); @@ -5154,7 +5150,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ ldr(subject, FieldMemOperand(subject, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ sub(subject, subject, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); @@ -5232,12 +5228,12 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { // Set FixedArray length. __ mov(r6, Operand(r5, LSL, kSmiTagSize)); __ str(r6, FieldMemOperand(r3, FixedArray::kLengthOffset)); - // Fill contents of fixed-array with the-hole. - __ mov(r2, Operand(factory->the_hole_value())); + // Fill contents of fixed-array with undefined. + __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - // Fill fixed array elements with hole. + // Fill fixed array elements with undefined. // r0: JSArray, tagged. - // r2: the hole. + // r2: undefined. // r3: Start of elements in FixedArray. // r5: Number of elements to fill. Label loop; @@ -5432,48 +5428,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) { } -// Unfortunately you have to run without snapshots to see most of these -// names in the profile since most compare stubs end up in the snapshot. -void CompareStub::PrintName(StringStream* stream) { - ASSERT((lhs_.is(r0) && rhs_.is(r1)) || - (lhs_.is(r1) && rhs_.is(r0))); - const char* cc_name; - switch (cc_) { - case lt: cc_name = "LT"; break; - case gt: cc_name = "GT"; break; - case le: cc_name = "LE"; break; - case ge: cc_name = "GE"; break; - case eq: cc_name = "EQ"; break; - case ne: cc_name = "NE"; break; - default: cc_name = "UnknownCondition"; break; - } - bool is_equality = cc_ == eq || cc_ == ne; - stream->Add("CompareStub_%s", cc_name); - stream->Add(lhs_.is(r0) ? "_r0" : "_r1"); - stream->Add(rhs_.is(r0) ? "_r0" : "_r1"); - if (strict_ && is_equality) stream->Add("_STRICT"); - if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); - if (!include_number_compare_) stream->Add("_NO_NUMBER"); - if (!include_smi_compare_) stream->Add("_NO_SMI"); -} - - -int CompareStub::MinorKey() { - // Encode the three parameters in a unique 16 bit value. To avoid duplicate - // stubs the never NaN NaN condition is only taken into account if the - // condition is equals. - ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 12)); - ASSERT((lhs_.is(r0) && rhs_.is(r1)) || - (lhs_.is(r1) && rhs_.is(r0))); - return ConditionField::encode(static_cast<unsigned>(cc_) >> 28) - | RegisterField::encode(lhs_.is(r0)) - | StrictField::encode(strict_) - | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) - | IncludeNumberCompareField::encode(include_number_compare_) - | IncludeSmiCompareField::encode(include_smi_compare_); -} - - // StringCharCodeAtGenerator void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { Label flat_string; @@ -5923,7 +5877,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, // Check if the two characters match. // Assumes that word load is little endian. - __ ldrh(scratch, FieldMemOperand(candidate, SeqAsciiString::kHeaderSize)); + __ ldrh(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize)); __ cmp(chars, scratch); __ b(eq, &found_in_symbol_table); __ bind(&next_probe[i]); @@ -6006,23 +5960,28 @@ void SubStringStub::Generate(MacroAssembler* masm) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); - // I.e., arithmetic shift right by one un-smi-tags. - __ mov(r2, Operand(r2, ASR, 1), SetCC); - __ mov(r3, Operand(r3, ASR, 1), SetCC, cc); - // If either to or from had the smi tag bit set, then carry is set now. - __ b(cs, &runtime); // Either "from" or "to" is not a smi. + // Arithmetic shift right by one un-smi-tags. In this case we rotate right + // instead because we bail out on non-smi values: ROR and ASR are equivalent + // for smis but they set the flags in a way that's easier to optimize. + __ mov(r2, Operand(r2, ROR, 1), SetCC); + __ mov(r3, Operand(r3, ROR, 1), SetCC, cc); + // If either to or from had the smi tag bit set, then C is set now, and N + // has the same value: we rotated by 1, so the bottom bit is now the top bit. // We want to bailout to runtime here if From is negative. In that case, the // next instruction is not executed and we fall through to bailing out to - // runtime. pl is the opposite of mi. - // Both r2 and r3 are untagged integers. - __ sub(r2, r2, Operand(r3), SetCC, pl); - __ b(mi, &runtime); // Fail if from > to. + // runtime. + // Executed if both r2 and r3 are untagged integers. + __ sub(r2, r2, Operand(r3), SetCC, cc); + // One of the above un-smis or the above SUB could have set N==1. + __ b(mi, &runtime); // Either "from" or "to" is not an smi, or from > to. // Make sure first argument is a string. __ ldr(r0, MemOperand(sp, kStringOffset)); STATIC_ASSERT(kSmiTag == 0); - __ JumpIfSmi(r0, &runtime); - Condition is_string = masm->IsObjectStringType(r0, r1); + // Do a JumpIfSmi, but fold its jump into the subsequent string test. + __ tst(r0, Operand(kSmiTagMask)); + Condition is_string = masm->IsObjectStringType(r0, r1, ne); + ASSERT(is_string == eq); __ b(NegateCondition(is_string), &runtime); // Short-cut for the case of trivial substring. @@ -6093,7 +6052,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { // string's encoding is wrong because we always have to recheck encoding of // the newly created string's parent anyways due to externalized strings. Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ tst(r1, Operand(kStringEncodingMask)); __ b(eq, &two_byte_slice); @@ -6131,12 +6090,12 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ bind(&sequential_string); // Locate first character of underlying subject string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); - __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); + __ add(r5, r5, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ bind(&allocate_result); // Sequential acii string. Allocate the result. - STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); + STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); __ tst(r1, Operand(kStringEncodingMask)); __ b(eq, &two_byte_sequential); @@ -6146,13 +6105,13 @@ void SubStringStub::Generate(MacroAssembler* masm) { // Locate first character of substring to copy. __ add(r5, r5, r3); // Locate first character of result. - __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(r1, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); // r0: result string // r1: first character of result string // r2: result string length // r5: first character of substring to copy - STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); + STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, COPY_ASCII | DEST_ALWAYS_ALIGNED); __ jmp(&return_r0); @@ -6277,7 +6236,7 @@ void StringCompareStub::GenerateAsciiCharsCompareLoop( // doesn't need an additional compare. __ SmiUntag(length); __ add(scratch1, length, - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ add(left, left, Operand(scratch1)); __ add(right, right, Operand(scratch1)); __ rsb(length, length, Operand::Zero()); @@ -6430,8 +6389,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { &call_runtime); // Get the two characters forming the sub string. - __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); - __ ldrb(r3, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); + __ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize)); + __ ldrb(r3, FieldMemOperand(r1, SeqOneByteString::kHeaderSize)); // Try to lookup two character string in symbol table. If it is not found // just allocate a new one. @@ -6450,7 +6409,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { // in a little endian mode) __ mov(r6, Operand(2)); __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime); - __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); + __ strh(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize)); __ IncrementCounter(counters->string_add_native(), 1, r2, r3); __ add(sp, sp, Operand(2 * kPointerSize)); __ Ret(); @@ -6500,11 +6459,6 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ tst(r4, Operand(kAsciiDataHintMask)); __ tst(r5, Operand(kAsciiDataHintMask), ne); __ b(ne, &ascii_data); - __ eor(r4, r4, Operand(r5)); - STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); - __ and_(r4, r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); - __ cmp(r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); - __ b(eq, &ascii_data); // Allocate a two byte cons string. __ AllocateTwoByteConsString(r7, r6, r4, r5, &call_runtime); @@ -6537,10 +6491,10 @@ void StringAddStub::Generate(MacroAssembler* masm) { STATIC_ASSERT(kSeqStringTag == 0); __ tst(r4, Operand(kStringRepresentationMask)); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); __ add(r7, r0, - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag), + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag), LeaveCC, eq); __ b(eq, &first_prepared); @@ -6553,10 +6507,10 @@ void StringAddStub::Generate(MacroAssembler* masm) { STATIC_ASSERT(kSeqStringTag == 0); __ tst(r5, Operand(kStringRepresentationMask)); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); __ add(r1, r1, - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag), + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag), LeaveCC, eq); __ b(eq, &second_prepared); @@ -6579,7 +6533,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ b(eq, &non_ascii_string_add_flat_result); __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime); - __ add(r6, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(r6, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); // r0: result string. // r7: first character of first string. // r1: first character of second string. @@ -6670,7 +6624,7 @@ void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, void ICCompareStub::GenerateSmis(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::SMIS); + ASSERT(state_ == CompareIC::SMI); Label miss; __ orr(r2, r1, r0); __ JumpIfNotSmi(r2, &miss); @@ -6691,31 +6645,53 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) { void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::HEAP_NUMBERS); + ASSERT(state_ == CompareIC::HEAP_NUMBER); Label generic_stub; Label unordered, maybe_undefined1, maybe_undefined2; Label miss; - __ and_(r2, r1, Operand(r0)); - __ JumpIfSmi(r2, &generic_stub); - __ CompareObjectType(r0, r2, r2, HEAP_NUMBER_TYPE); - __ b(ne, &maybe_undefined1); - __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); - __ b(ne, &maybe_undefined2); + if (left_ == CompareIC::SMI) { + __ JumpIfNotSmi(r1, &miss); + } + if (right_ == CompareIC::SMI) { + __ JumpIfNotSmi(r0, &miss); + } // Inlining the double comparison and falling back to the general compare - // stub if NaN is involved or VFP3 is unsupported. + // stub if NaN is involved or VFP2 is unsupported. if (CpuFeatures::IsSupported(VFP2)) { CpuFeatures::Scope scope(VFP2); - // Load left and right operand - __ sub(r2, r1, Operand(kHeapObjectTag)); - __ vldr(d0, r2, HeapNumber::kValueOffset); + // Load left and right operand. + Label done, left, left_smi, right_smi; + __ JumpIfSmi(r0, &right_smi); + __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1, + DONT_DO_SMI_CHECK); __ sub(r2, r0, Operand(kHeapObjectTag)); __ vldr(d1, r2, HeapNumber::kValueOffset); + __ b(&left); + __ bind(&right_smi); + __ SmiUntag(r2, r0); // Can't clobber r0 yet. + SwVfpRegister single_scratch = d2.low(); + __ vmov(single_scratch, r2); + __ vcvt_f64_s32(d1, single_scratch); + + __ bind(&left); + __ JumpIfSmi(r1, &left_smi); + __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2, + DONT_DO_SMI_CHECK); + __ sub(r2, r1, Operand(kHeapObjectTag)); + __ vldr(d0, r2, HeapNumber::kValueOffset); + __ b(&done); + __ bind(&left_smi); + __ SmiUntag(r2, r1); // Can't clobber r1 yet. + single_scratch = d3.low(); + __ vmov(single_scratch, r2); + __ vcvt_f64_s32(d0, single_scratch); - // Compare operands + __ bind(&done); + // Compare operands. __ VFPCompareAndSetFlags(d0, d1); // Don't base result on status bits when a NaN is involved. @@ -6729,14 +6705,16 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { } __ bind(&unordered); - CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0); __ bind(&generic_stub); + ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC, + CompareIC::GENERIC); __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); __ bind(&maybe_undefined1); if (Token::IsOrderedRelationalCompareOp(op_)) { __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); __ b(ne, &miss); + __ JumpIfSmi(r1, &unordered); __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); __ b(ne, &maybe_undefined2); __ jmp(&unordered); @@ -6754,7 +6732,7 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::SYMBOLS); + ASSERT(state_ == CompareIC::SYMBOL); Label miss; // Registers containing left and right operands respectively. @@ -6792,7 +6770,7 @@ void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { void ICCompareStub::GenerateStrings(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::STRINGS); + ASSERT(state_ == CompareIC::STRING); Label miss; bool equality = Token::IsEqualityOp(op_); @@ -6870,7 +6848,7 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) { void ICCompareStub::GenerateObjects(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::OBJECTS); + ASSERT(state_ == CompareIC::OBJECT); Label miss; __ and_(r2, r1, Operand(r0)); __ JumpIfSmi(r2, &miss); @@ -7064,8 +7042,7 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, ASSERT(!name.is(scratch1)); ASSERT(!name.is(scratch2)); - // Assert that name contains a string. - if (FLAG_debug_code) __ AbortIfNotString(name); + __ AssertString(name); // Compute the capacity mask. __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset)); @@ -7262,6 +7239,7 @@ static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { #undef REG + bool RecordWriteStub::IsPregenerated() { for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; !entry->object.is(no_reg); @@ -7303,6 +7281,11 @@ void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { } +bool CodeStub::CanUseFPRegisters() { + return CpuFeatures::IsSupported(VFP2); +} + + // Takes the input in 3 registers: address_ value_ and object_. A pointer to // the value has just been written into the object, now this stub makes sure // we keep the GC informed. The word in the object where the value has been @@ -7398,12 +7381,7 @@ void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { ASSERT(!address.is(r0)); __ Move(address, regs_.address()); __ Move(r0, regs_.object()); - if (mode == INCREMENTAL_COMPACTION) { - __ Move(r1, address); - } else { - ASSERT(mode == INCREMENTAL); - __ ldr(r1, MemOperand(address, 0)); - } + __ Move(r1, address); __ mov(r2, Operand(ExternalReference::isolate_address())); AllowExternalCallThatCantCauseGC scope(masm); @@ -7431,6 +7409,16 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker( Label need_incremental; Label need_incremental_pop_scratch; + __ and_(regs_.scratch0(), regs_.object(), Operand(~Page::kPageAlignmentMask)); + __ ldr(regs_.scratch1(), + MemOperand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset)); + __ sub(regs_.scratch1(), regs_.scratch1(), Operand(1), SetCC); + __ str(regs_.scratch1(), + MemOperand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset)); + __ b(mi, &need_incremental); + // Let's look at the color of the object: If it is not black we don't have // to inform the incremental marker. __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black); @@ -7551,7 +7539,9 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. __ bind(&double_elements); __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset)); - __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r2, + __ StoreNumberToDoubleElements(r0, r3, + // Overwrites all regs after this. + r5, r6, r7, r9, r2, &slow_elements); __ Ret(); } @@ -7559,6 +7549,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { if (entry_hook_ != NULL) { + PredictableCodeSizeScope predictable(masm, 4 * Assembler::kInstrSize); ProfileEntryHookStub stub; __ push(lr); __ CallStub(&stub); @@ -7570,7 +7561,7 @@ void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { void ProfileEntryHookStub::Generate(MacroAssembler* masm) { // The entry hook is a "push lr" instruction, followed by a call. const int32_t kReturnAddressDistanceFromFunctionStart = - Assembler::kCallTargetAddressOffset + Assembler::kInstrSize; + 3 * Assembler::kInstrSize; // Save live volatile registers. __ Push(lr, r5, r1); diff --git a/deps/v8/src/arm/code-stubs-arm.h b/deps/v8/src/arm/code-stubs-arm.h index 3ddc405715..0443cf799c 100644 --- a/deps/v8/src/arm/code-stubs-arm.h +++ b/deps/v8/src/arm/code-stubs-arm.h @@ -142,108 +142,6 @@ class UnaryOpStub: public CodeStub { }; -class BinaryOpStub: public CodeStub { - public: - BinaryOpStub(Token::Value op, OverwriteMode mode) - : op_(op), - mode_(mode), - operands_type_(BinaryOpIC::UNINITIALIZED), - result_type_(BinaryOpIC::UNINITIALIZED) { - use_vfp2_ = CpuFeatures::IsSupported(VFP2); - ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); - } - - BinaryOpStub( - int key, - BinaryOpIC::TypeInfo operands_type, - BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED) - : op_(OpBits::decode(key)), - mode_(ModeBits::decode(key)), - use_vfp2_(VFP2Bits::decode(key)), - operands_type_(operands_type), - result_type_(result_type) { } - - private: - enum SmiCodeGenerateHeapNumberResults { - ALLOW_HEAPNUMBER_RESULTS, - NO_HEAPNUMBER_RESULTS - }; - - Token::Value op_; - OverwriteMode mode_; - bool use_vfp2_; - - // Operand type information determined at runtime. - BinaryOpIC::TypeInfo operands_type_; - BinaryOpIC::TypeInfo result_type_; - - virtual void PrintName(StringStream* stream); - - // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM. - class ModeBits: public BitField<OverwriteMode, 0, 2> {}; - class OpBits: public BitField<Token::Value, 2, 7> {}; - class VFP2Bits: public BitField<bool, 9, 1> {}; - class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {}; - class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {}; - - Major MajorKey() { return BinaryOp; } - int MinorKey() { - return OpBits::encode(op_) - | ModeBits::encode(mode_) - | VFP2Bits::encode(use_vfp2_) - | OperandTypeInfoBits::encode(operands_type_) - | ResultTypeInfoBits::encode(result_type_); - } - - void Generate(MacroAssembler* masm); - void GenerateGeneric(MacroAssembler* masm); - void GenerateSmiSmiOperation(MacroAssembler* masm); - void GenerateFPOperation(MacroAssembler* masm, - bool smi_operands, - Label* not_numbers, - Label* gc_required); - void GenerateSmiCode(MacroAssembler* masm, - Label* use_runtime, - Label* gc_required, - SmiCodeGenerateHeapNumberResults heapnumber_results); - void GenerateLoadArguments(MacroAssembler* masm); - void GenerateReturn(MacroAssembler* masm); - void GenerateUninitializedStub(MacroAssembler* masm); - void GenerateSmiStub(MacroAssembler* masm); - void GenerateInt32Stub(MacroAssembler* masm); - void GenerateHeapNumberStub(MacroAssembler* masm); - void GenerateOddballStub(MacroAssembler* masm); - void GenerateStringStub(MacroAssembler* masm); - void GenerateBothStringStub(MacroAssembler* masm); - void GenerateGenericStub(MacroAssembler* masm); - void GenerateAddStrings(MacroAssembler* masm); - void GenerateCallRuntime(MacroAssembler* masm); - - void GenerateHeapResultAllocation(MacroAssembler* masm, - Register result, - Register heap_number_map, - Register scratch1, - Register scratch2, - Label* gc_required); - void GenerateRegisterArgsPush(MacroAssembler* masm); - void GenerateTypeTransition(MacroAssembler* masm); - void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); - - virtual int GetCodeKind() { return Code::BINARY_OP_IC; } - - virtual InlineCacheState GetICState() { - return BinaryOpIC::ToState(operands_type_); - } - - virtual void FinishCode(Handle<Code> code) { - code->set_binary_op_type(operands_type_); - code->set_binary_op_result_type(result_type_); - } - - friend class CodeGenerator; -}; - - class StringHelper : public AllStatic { public: // Generate code for copying characters using a simple loop. This should only @@ -724,20 +622,6 @@ class FloatingPointHelper : public AllStatic { Register scratch1, Register scratch2); - // Loads objects from r0 and r1 (right and left in binary operations) into - // floating point registers. Depending on the destination the values ends up - // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the destination is - // floating point registers VFP3 must be supported. If core registers are - // requested when VFP3 is supported d6 and d7 will still be scratched. If - // either r0 or r1 is not a number (not smi and not heap number object) the - // not_number label is jumped to with r0 and r1 intact. - static void LoadOperands(MacroAssembler* masm, - FloatingPointHelper::Destination destination, - Register heap_number_map, - Register scratch1, - Register scratch2, - Label* not_number); - // Convert the smi or heap number in object to an int32 using the rules // for ToInt32 as described in ECMAScript 9.5.: the value is truncated // and brought into the range -2^31 .. +2^31 - 1. @@ -773,6 +657,7 @@ class FloatingPointHelper : public AllStatic { Register object, Destination destination, DwVfpRegister double_dst, + DwVfpRegister double_scratch, Register dst1, Register dst2, Register heap_number_map, @@ -794,7 +679,8 @@ class FloatingPointHelper : public AllStatic { Register scratch1, Register scratch2, Register scratch3, - DwVfpRegister double_scratch, + DwVfpRegister double_scratch0, + DwVfpRegister double_scratch1, Label* not_int32); // Generate non VFP3 code to check if a double can be exactly represented by a @@ -834,7 +720,12 @@ class FloatingPointHelper : public AllStatic { Register heap_number_result, Register scratch); - private: + // Loads the objects from |object| into floating point registers. + // Depending on |destination| the value ends up either in |dst| or + // in |dst1|/|dst2|. If |destination| is kVFPRegisters, then VFP3 + // must be supported. If kCoreRegisters are requested and VFP3 is + // supported, |dst| will be scratched. If |object| is neither smi nor + // heap number, |not_number| is jumped to with |object| still intact. static void LoadNumber(MacroAssembler* masm, FloatingPointHelper::Destination destination, Register object, diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 09166c3c01..bb771b18e2 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -31,11 +31,11 @@ #include "codegen.h" #include "macro-assembler.h" +#include "simulator-arm.h" namespace v8 { namespace internal { -#define __ ACCESS_MASM(masm) UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { switch (type) { @@ -49,6 +49,74 @@ UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { } +#define __ masm. + + +#if defined(USE_SIMULATOR) +byte* fast_exp_arm_machine_code = NULL; +double fast_exp_simulator(double x) { + return Simulator::current(Isolate::Current())->CallFP( + fast_exp_arm_machine_code, x, 0); +} +#endif + + +UnaryMathFunction CreateExpFunction() { + if (!CpuFeatures::IsSupported(VFP2)) return &exp; + if (!FLAG_fast_math) return &exp; + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == NULL) return &exp; + ExternalReference::InitializeMathExpData(); + + MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); + + { + CpuFeatures::Scope use_vfp(VFP2); + DoubleRegister input = d0; + DoubleRegister result = d1; + DoubleRegister double_scratch1 = d2; + DoubleRegister double_scratch2 = d3; + Register temp1 = r4; + Register temp2 = r5; + Register temp3 = r6; + + if (masm.use_eabi_hardfloat()) { + // Input value is in d0 anyway, nothing to do. + } else { + __ vmov(input, r0, r1); + } + __ Push(temp3, temp2, temp1); + MathExpGenerator::EmitMathExp( + &masm, input, result, double_scratch1, double_scratch2, + temp1, temp2, temp3); + __ Pop(temp3, temp2, temp1); + if (masm.use_eabi_hardfloat()) { + __ vmov(d0, result); + } else { + __ vmov(r0, r1, result); + } + __ Ret(); + } + + CodeDesc desc; + masm.GetCode(&desc); + + CPU::FlushICache(buffer, actual_size); + OS::ProtectCode(buffer, actual_size); + +#if !defined(USE_SIMULATOR) + return FUNCTION_CAST<UnaryMathFunction>(buffer); +#else + fast_exp_arm_machine_code = buffer; + return &fast_exp_simulator; +#endif +} + + +#undef __ + + UnaryMathFunction CreateSqrtFunction() { return &sqrt; } @@ -73,6 +141,8 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { // ------------------------------------------------------------------------- // Code generators +#define __ ACCESS_MASM(masm) + void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( MacroAssembler* masm) { // ----------- S t a t e ------------- @@ -192,7 +262,7 @@ void ElementsTransitionGenerator::GenerateSmiToDouble( HeapObject::kMapOffset, r3, r9, - kLRHasBeenSaved, + kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); @@ -416,7 +486,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, __ b(ne, &external_string); // Prepare sequential strings - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ add(string, string, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); @@ -450,8 +520,188 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, __ bind(&done); } + +void SeqStringSetCharGenerator::Generate(MacroAssembler* masm, + String::Encoding encoding, + Register string, + Register index, + Register value) { + if (FLAG_debug_code) { + __ tst(index, Operand(kSmiTagMask)); + __ Check(eq, "Non-smi index"); + __ tst(value, Operand(kSmiTagMask)); + __ Check(eq, "Non-smi value"); + + __ ldr(ip, FieldMemOperand(string, String::kLengthOffset)); + __ cmp(index, ip); + __ Check(lt, "Index is too large"); + + __ cmp(index, Operand(Smi::FromInt(0))); + __ Check(ge, "Index is negative"); + + __ ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset)); + __ ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset)); + + __ and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask)); + static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; + static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; + __ cmp(ip, Operand(encoding == String::ONE_BYTE_ENCODING + ? one_byte_seq_type : two_byte_seq_type)); + __ Check(eq, "Unexpected string type"); + } + + __ add(ip, + string, + Operand(SeqString::kHeaderSize - kHeapObjectTag)); + __ SmiUntag(value, value); + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + if (encoding == String::ONE_BYTE_ENCODING) { + // Smis are tagged by left shift by 1, thus LSR by 1 to smi-untag inline. + __ strb(value, MemOperand(ip, index, LSR, 1)); + } else { + // No need to untag a smi for two-byte addressing. + __ strh(value, MemOperand(ip, index)); + } +} + + +static MemOperand ExpConstant(int index, Register base) { + return MemOperand(base, index * kDoubleSize); +} + + +void MathExpGenerator::EmitMathExp(MacroAssembler* masm, + DoubleRegister input, + DoubleRegister result, + DoubleRegister double_scratch1, + DoubleRegister double_scratch2, + Register temp1, + Register temp2, + Register temp3) { + ASSERT(!input.is(result)); + ASSERT(!input.is(double_scratch1)); + ASSERT(!input.is(double_scratch2)); + ASSERT(!result.is(double_scratch1)); + ASSERT(!result.is(double_scratch2)); + ASSERT(!double_scratch1.is(double_scratch2)); + ASSERT(!temp1.is(temp2)); + ASSERT(!temp1.is(temp3)); + ASSERT(!temp2.is(temp3)); + ASSERT(ExternalReference::math_exp_constants(0).address() != NULL); + + Label done; + + __ mov(temp3, Operand(ExternalReference::math_exp_constants(0))); + + __ vldr(double_scratch1, ExpConstant(0, temp3)); + __ vmov(result, kDoubleRegZero); + __ VFPCompareAndSetFlags(double_scratch1, input); + __ b(ge, &done); + __ vldr(double_scratch2, ExpConstant(1, temp3)); + __ VFPCompareAndSetFlags(input, double_scratch2); + __ vldr(result, ExpConstant(2, temp3)); + __ b(ge, &done); + __ vldr(double_scratch1, ExpConstant(3, temp3)); + __ vldr(result, ExpConstant(4, temp3)); + __ vmul(double_scratch1, double_scratch1, input); + __ vadd(double_scratch1, double_scratch1, result); + __ vmov(temp2, temp1, double_scratch1); + __ vsub(double_scratch1, double_scratch1, result); + __ vldr(result, ExpConstant(6, temp3)); + __ vldr(double_scratch2, ExpConstant(5, temp3)); + __ vmul(double_scratch1, double_scratch1, double_scratch2); + __ vsub(double_scratch1, double_scratch1, input); + __ vsub(result, result, double_scratch1); + __ vmul(input, double_scratch1, double_scratch1); + __ vmul(result, result, input); + __ mov(temp1, Operand(temp2, LSR, 11)); + __ vldr(double_scratch2, ExpConstant(7, temp3)); + __ vmul(result, result, double_scratch2); + __ vsub(result, result, double_scratch1); + __ vldr(double_scratch2, ExpConstant(8, temp3)); + __ vadd(result, result, double_scratch2); + __ movw(ip, 0x7ff); + __ and_(temp2, temp2, Operand(ip)); + __ add(temp1, temp1, Operand(0x3ff)); + __ mov(temp1, Operand(temp1, LSL, 20)); + + // Must not call ExpConstant() after overwriting temp3! + __ mov(temp3, Operand(ExternalReference::math_exp_log_table())); + __ ldr(ip, MemOperand(temp3, temp2, LSL, 3)); + __ add(temp3, temp3, Operand(kPointerSize)); + __ ldr(temp2, MemOperand(temp3, temp2, LSL, 3)); + __ orr(temp1, temp1, temp2); + __ vmov(input, ip, temp1); + __ vmul(result, result, input); + __ bind(&done); +} + #undef __ +// add(r0, pc, Operand(-8)) +static const uint32_t kCodeAgePatchFirstInstruction = 0xe24f0008; + +static byte* GetNoCodeAgeSequence(uint32_t* length) { + // The sequence of instructions that is patched out for aging code is the + // following boilerplate stack-building prologue that is found in FUNCTIONS + static bool initialized = false; + static uint32_t sequence[kNoCodeAgeSequenceLength]; + byte* byte_sequence = reinterpret_cast<byte*>(sequence); + *length = kNoCodeAgeSequenceLength * Assembler::kInstrSize; + if (!initialized) { + CodePatcher patcher(byte_sequence, kNoCodeAgeSequenceLength); + PredictableCodeSizeScope scope(patcher.masm(), *length); + patcher.masm()->stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); + patcher.masm()->LoadRoot(ip, Heap::kUndefinedValueRootIndex); + patcher.masm()->add(fp, sp, Operand(2 * kPointerSize)); + initialized = true; + } + return byte_sequence; +} + + +bool Code::IsYoungSequence(byte* sequence) { + uint32_t young_length; + byte* young_sequence = GetNoCodeAgeSequence(&young_length); + bool result = !memcmp(sequence, young_sequence, young_length); + ASSERT(result || + Memory::uint32_at(sequence) == kCodeAgePatchFirstInstruction); + return result; +} + + +void Code::GetCodeAgeAndParity(byte* sequence, Age* age, + MarkingParity* parity) { + if (IsYoungSequence(sequence)) { + *age = kNoAge; + *parity = NO_MARKING_PARITY; + } else { + Address target_address = Memory::Address_at( + sequence + Assembler::kInstrSize * (kNoCodeAgeSequenceLength - 1)); + Code* stub = GetCodeFromTargetAddress(target_address); + GetCodeAgeAndParity(stub, age, parity); + } +} + + +void Code::PatchPlatformCodeAge(byte* sequence, + Code::Age age, + MarkingParity parity) { + uint32_t young_length; + byte* young_sequence = GetNoCodeAgeSequence(&young_length); + if (age == kNoAge) { + memcpy(sequence, young_sequence, young_length); + CPU::FlushICache(sequence, young_length); + } else { + Code* stub = GetCodeAgeStub(age, parity); + CodePatcher patcher(sequence, young_length / Assembler::kInstrSize); + patcher.masm()->add(r0, pc, Operand(-8)); + patcher.masm()->ldr(pc, MemOperand(pc, -4)); + patcher.masm()->dd(reinterpret_cast<uint32_t>(stub->instruction_start())); + } +} + + } } // namespace v8::internal #endif // V8_TARGET_ARCH_ARM diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index c340e6b108..8f0033e2ce 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -88,6 +88,22 @@ class StringCharLoadGenerator : public AllStatic { DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator); }; + +class MathExpGenerator : public AllStatic { + public: + static void EmitMathExp(MacroAssembler* masm, + DoubleRegister input, + DoubleRegister result, + DoubleRegister double_scratch1, + DoubleRegister double_scratch2, + Register temp1, + Register temp2, + Register temp3); + + private: + DISALLOW_COPY_AND_ASSIGN(MathExpGenerator); +}; + } } // namespace v8::internal #endif // V8_ARM_CODEGEN_ARM_H_ diff --git a/deps/v8/src/arm/constants-arm.h b/deps/v8/src/arm/constants-arm.h index 5aadc3caeb..a569383f24 100644 --- a/deps/v8/src/arm/constants-arm.h +++ b/deps/v8/src/arm/constants-arm.h @@ -75,10 +75,6 @@ #endif -#if CAN_USE_UNALIGNED_ACCESSES -#define V8_TARGET_CAN_READ_UNALIGNED 1 -#endif - // Using blx may yield better code, so use it when required or when available #if defined(USE_THUMB_INTERWORK) || defined(CAN_USE_ARMV5_INSTRUCTIONS) #define USE_BLX 1 @@ -88,9 +84,18 @@ namespace v8 { namespace internal { // Constant pool marker. -const int kConstantPoolMarkerMask = 0xffe00000; -const int kConstantPoolMarker = 0x0c000000; -const int kConstantPoolLengthMask = 0x001ffff; +// Use UDF, the permanently undefined instruction. +const int kConstantPoolMarkerMask = 0xfff000f0; +const int kConstantPoolMarker = 0xe7f000f0; +const int kConstantPoolLengthMaxMask = 0xffff; +inline int EncodeConstantPoolLength(int length) { + ASSERT((length & kConstantPoolLengthMaxMask) == length); + return ((length & 0xfff0) << 4) | (length & 0xf); +} +inline int DecodeConstantPoolLength(int instr) { + ASSERT((instr & kConstantPoolMarkerMask) == kConstantPoolMarker); + return ((instr >> 4) & 0xfff0) | (instr & 0xf); +} // Number of registers in normal ARM mode. const int kNumRegisters = 16; @@ -691,6 +696,9 @@ class Instruction { && (Bit(20) == 0) && ((Bit(7) == 0)); } + // Test for a nop instruction, which falls under type 1. + inline bool IsNopType1() const { return Bits(24, 0) == 0x0120F000; } + // Test for a stop instruction. inline bool IsStop() const { return (TypeValue() == 7) && (Bit(24) == 1) && (SvcValue() >= kStopCode); diff --git a/deps/v8/src/arm/debug-arm.cc b/deps/v8/src/arm/debug-arm.cc index 3e7a1e9d0e..c2941be06d 100644 --- a/deps/v8/src/arm/debug-arm.cc +++ b/deps/v8/src/arm/debug-arm.cc @@ -48,7 +48,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() { // add sp, sp, #4 // bx lr // to a call to the debug break return code. - // #if USE_BLX + // #ifdef USE_BLX // ldr ip, [pc, #0] // blx ip // #else @@ -99,7 +99,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() { // mov r2, r2 // mov r2, r2 // to a call to the debug break slot code. - // #if USE_BLX + // #ifdef USE_BLX // ldr ip, [pc, #0] // blx ip // #else diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index 5339be1d84..ee2a581a57 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -104,19 +104,7 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { // ignore all slots that might have been recorded on it. isolate->heap()->mark_compact_collector()->InvalidateCode(code); - // Iterate over all the functions which share the same code object - // and make them use unoptimized version. - Context* context = function->context()->native_context(); - Object* element = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); - SharedFunctionInfo* shared = function->shared(); - while (!element->IsUndefined()) { - JSFunction* func = JSFunction::cast(element); - // Grab element before code replacement as ReplaceCode alters the list. - element = func->next_function_link(); - if (func->code() == code) { - func->ReplaceCode(shared->code()); - } - } + ReplaceCodeForRelatedFunctions(function, code); if (FLAG_trace_deopt) { PrintF("[forced deoptimization: "); @@ -126,7 +114,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } -static const int32_t kBranchBeforeStackCheck = 0x2a000001; static const int32_t kBranchBeforeInterrupt = 0x5a000004; @@ -135,24 +122,21 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, Code* check_code, Code* replacement_code) { const int kInstrSize = Assembler::kInstrSize; - // The call of the stack guard check has the following form: - // e1 5d 00 0c cmp sp, <limit> - // 2a 00 00 01 bcs ok + // The back edge bookkeeping code matches the pattern: + // + // <decrement profiling counter> + // 2a 00 00 01 bpl ok // e5 9f c? ?? ldr ip, [pc, <stack guard address>] // e1 2f ff 3c blx ip ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp); ASSERT(Assembler::IsLdrPcImmediateOffset( Assembler::instr_at(pc_after - 2 * kInstrSize))); - if (FLAG_count_based_interrupts) { - ASSERT_EQ(kBranchBeforeInterrupt, - Memory::int32_at(pc_after - 3 * kInstrSize)); - } else { - ASSERT_EQ(kBranchBeforeStackCheck, - Memory::int32_at(pc_after - 3 * kInstrSize)); - } + ASSERT_EQ(kBranchBeforeInterrupt, + Memory::int32_at(pc_after - 3 * kInstrSize)); // We patch the code to the following form: - // e1 5d 00 0c cmp sp, <limit> + // + // <decrement profiling counter> // e1 a0 00 00 mov r0, r0 (NOP) // e5 9f c? ?? ldr ip, [pc, <on-stack replacement address>] // e1 2f ff 3c blx ip @@ -189,15 +173,9 @@ void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code, // Replace NOP with conditional jump. CodePatcher patcher(pc_after - 3 * kInstrSize, 1); - if (FLAG_count_based_interrupts) { - patcher.masm()->b(+16, pl); - ASSERT_EQ(kBranchBeforeInterrupt, - Memory::int32_at(pc_after - 3 * kInstrSize)); - } else { - patcher.masm()->b(+4, cs); - ASSERT_EQ(kBranchBeforeStackCheck, - Memory::int32_at(pc_after - 3 * kInstrSize)); - } + patcher.masm()->b(+16, pl); + ASSERT_EQ(kBranchBeforeInterrupt, + Memory::int32_at(pc_after - 3 * kInstrSize)); // Replace the stack check address in the constant pool // with the entry address of the replacement code. diff --git a/deps/v8/src/arm/disasm-arm.cc b/deps/v8/src/arm/disasm-arm.cc index 96a7d3ce6b..cb0a6cb5c7 100644 --- a/deps/v8/src/arm/disasm-arm.cc +++ b/deps/v8/src/arm/disasm-arm.cc @@ -692,11 +692,19 @@ void Decoder::DecodeType01(Instruction* instr) { // Rn field to encode it. Format(instr, "mul'cond's 'rn, 'rm, 'rs"); } else { - // The MLA instruction description (A 4.1.28) refers to the order - // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the - // Rn field to encode the Rd register and the Rd field to encode - // the Rn register. - Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd"); + if (instr->Bit(22) == 0) { + // The MLA instruction description (A 4.1.28) refers to the order + // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the + // Rn field to encode the Rd register and the Rd field to encode + // the Rn register. + Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd"); + } else { + // The MLS instruction description (A 4.1.29) refers to the order + // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the + // Rn field to encode the Rd register and the Rd field to encode + // the Rn register. + Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd"); + } } } else { // The signed/long multiply instructions use the terms RdHi and RdLo @@ -822,6 +830,8 @@ void Decoder::DecodeType01(Instruction* instr) { } else { Unknown(instr); // not used by V8 } + } else if ((type == 1) && instr->IsNopType1()) { + Format(instr, "nop'cond"); } else { switch (instr->OpcodeField()) { case AND: { @@ -974,6 +984,17 @@ void Decoder::DecodeType3(Instruction* instr) { break; } case db_x: { + if (FLAG_enable_sudiv) { + if (!instr->HasW()) { + if (instr->Bits(5, 4) == 0x1) { + if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) { + // SDIV (in V8 notation matching ARM ISA format) rn = rm/rs + Format(instr, "sdiv'cond'b 'rn, 'rm, 'rs"); + break; + } + } + } + } Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w"); break; } @@ -1077,6 +1098,7 @@ int Decoder::DecodeType7(Instruction* instr) { // Dd = vadd(Dn, Dm) // Dd = vsub(Dn, Dm) // Dd = vmul(Dn, Dm) +// Dd = vmla(Dn, Dm) // Dd = vdiv(Dn, Dm) // vcmp(Dd, Dm) // vmrs @@ -1139,6 +1161,12 @@ void Decoder::DecodeTypeVFP(Instruction* instr) { } else { Unknown(instr); // Not used by V8. } + } else if ((instr->Opc1Value() == 0x0) && !(instr->Opc3Value() & 0x1)) { + if (instr->SzValue() == 0x1) { + Format(instr, "vmla.f64'cond 'Dd, 'Dn, 'Dm"); + } else { + Unknown(instr); // Not used by V8. + } } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) { if (instr->SzValue() == 0x1) { Format(instr, "vdiv.f64'cond 'Dd, 'Dn, 'Dm"); @@ -1367,7 +1395,7 @@ bool Decoder::IsConstantPoolAt(byte* instr_ptr) { int Decoder::ConstantPoolSizeAt(byte* instr_ptr) { if (IsConstantPoolAt(instr_ptr)) { int instruction_bits = *(reinterpret_cast<int*>(instr_ptr)); - return instruction_bits & kConstantPoolLengthMask; + return DecodeConstantPoolLength(instruction_bits); } else { return -1; } @@ -1389,8 +1417,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) { if ((instruction_bits & kConstantPoolMarkerMask) == kConstantPoolMarker) { out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "constant pool begin (length %d)", - instruction_bits & - kConstantPoolLengthMask); + DecodeConstantPoolLength(instruction_bits)); return Instruction::kInstrSize; } switch (instr->TypeValue()) { diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index b2f629b26c..3b560fedfa 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -130,7 +130,7 @@ void FullCodeGenerator::Generate() { handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell( - Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget))); + Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); @@ -164,14 +164,19 @@ void FullCodeGenerator::Generate() { int locals_count = info->scope()->num_stack_slots(); - __ Push(lr, fp, cp, r1); - if (locals_count > 0) { + info->set_prologue_offset(masm_->pc_offset()); + { + PredictableCodeSizeScope predictible_code_size_scope( + masm_, kNoCodeAgeSequenceLength * Assembler::kInstrSize); + // The following three instructions must remain together and unmodified + // for code aging to work properly. + __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); // Load undefined value here, so the value is ready for the loop // below. __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); + // Adjust FP to point to saved FP. + __ add(fp, sp, Operand(2 * kPointerSize)); } - // Adjust fp to point to caller's fp. - __ add(fp, sp, Operand(2 * kPointerSize)); { Comment cmnt(masm_, "[ Allocate locals"); for (int i = 0; i < locals_count; i++) { @@ -287,6 +292,7 @@ void FullCodeGenerator::Generate() { __ LoadRoot(ip, Heap::kStackLimitRootIndex); __ cmp(sp, Operand(ip)); __ b(hs, &ok); + PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize); StackCheckStub stub; __ CallStub(&stub); __ bind(&ok); @@ -341,41 +347,31 @@ void FullCodeGenerator::EmitProfilingCounterReset() { } -void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, - Label* back_edge_target) { - Comment cmnt(masm_, "[ Stack check"); +void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, + Label* back_edge_target) { + Comment cmnt(masm_, "[ Back edge bookkeeping"); // Block literal pools whilst emitting stack check code. Assembler::BlockConstPoolScope block_const_pool(masm_); Label ok; - 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 / kBackEdgeDistanceUnit)); - } - EmitProfilingCounterDecrement(weight); - __ b(pl, &ok); - InterruptStub stub; - __ CallStub(&stub); - } else { - __ LoadRoot(ip, Heap::kStackLimitRootIndex); - __ cmp(sp, Operand(ip)); - __ b(hs, &ok); - StackCheckStub stub; - __ CallStub(&stub); + 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 / kBackEdgeDistanceUnit)); } + EmitProfilingCounterDecrement(weight); + __ b(pl, &ok); + InterruptStub 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. - RecordStackCheck(stmt->OsrEntryId()); + RecordBackEdge(stmt->OsrEntryId()); - if (FLAG_count_based_interrupts) { - EmitProfilingCounterReset(); - } + EmitProfilingCounterReset(); __ bind(&ok); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); @@ -437,6 +433,8 @@ void FullCodeGenerator::EmitReturnSequence() { // tool from instrumenting as we rely on the code size here. int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize; CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); + // TODO(svenpanne) The code below is sometimes 4 words, sometimes 5! + PredictableCodeSizeScope predictable(masm_, -1); __ RecordJSReturn(); masm_->mov(sp, fp); masm_->ldm(ia_w, sp, fp.bit() | lr.bit()); @@ -911,34 +909,33 @@ void FullCodeGenerator::VisitFunctionDeclaration( void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { - VariableProxy* proxy = declaration->proxy(); - Variable* variable = proxy->var(); - Handle<JSModule> instance = declaration->module()->interface()->Instance(); - ASSERT(!instance.is_null()); + Variable* variable = declaration->proxy()->var(); + ASSERT(variable->location() == Variable::CONTEXT); + ASSERT(variable->interface()->IsFrozen()); - switch (variable->location()) { - case Variable::UNALLOCATED: { - Comment cmnt(masm_, "[ ModuleDeclaration"); - globals_->Add(variable->name(), zone()); - globals_->Add(instance, zone()); - Visit(declaration->module()); - break; - } + Comment cmnt(masm_, "[ ModuleDeclaration"); + EmitDebugCheckDeclarationContext(variable); - case Variable::CONTEXT: { - Comment cmnt(masm_, "[ ModuleDeclaration"); - EmitDebugCheckDeclarationContext(variable); - __ mov(r1, Operand(instance)); - __ str(r1, ContextOperand(cp, variable->index())); - Visit(declaration->module()); - break; - } + // Load instance object. + __ LoadContext(r1, scope_->ContextChainLength(scope_->GlobalScope())); + __ ldr(r1, ContextOperand(r1, variable->interface()->Index())); + __ ldr(r1, ContextOperand(r1, Context::EXTENSION_INDEX)); - case Variable::PARAMETER: - case Variable::LOCAL: - case Variable::LOOKUP: - UNREACHABLE(); - } + // Assign it. + __ str(r1, ContextOperand(cp, variable->index())); + // We know that we have written a module, which is not a smi. + __ RecordWriteContextSlot(cp, + Context::SlotOffset(variable->index()), + r1, + r3, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS); + + // Traverse into body. + Visit(declaration->module()); } @@ -981,6 +978,14 @@ void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { } +void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) { + // Call the runtime to declare the modules. + __ Push(descriptions); + __ CallRuntime(Runtime::kDeclareModules, 1); + // Return value is ignored. +} + + void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { Comment cmnt(masm_, "[ SwitchStatement"); Breakable nested_statement(this, stmt); @@ -1137,7 +1142,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ cmp(r1, Operand(Smi::FromInt(0))); __ b(eq, &no_descriptors); - __ LoadInstanceDescriptors(r0, r2, r4); + __ LoadInstanceDescriptors(r0, r2); __ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheOffset)); __ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheBridgeCacheOffset)); @@ -1235,7 +1240,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ add(r0, r0, Operand(Smi::FromInt(1))); __ push(r0); - EmitStackCheck(stmt, &loop); + EmitBackEdgeBookkeeping(stmt, &loop); __ b(&loop); // Remove the pointers stored on the stack. @@ -1388,9 +1393,9 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, } else if (var->mode() == DYNAMIC_LOCAL) { Variable* local = var->local_if_not_shadowed(); __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); - if (local->mode() == CONST || - local->mode() == CONST_HARMONY || - local->mode() == LET) { + if (local->mode() == LET || + local->mode() == CONST || + local->mode() == CONST_HARMONY) { __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); if (local->mode() == CONST) { __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); @@ -2183,43 +2188,16 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { ASSERT(prop != NULL); ASSERT(prop->key()->AsLiteral() != NULL); - // If the assignment starts a block of assignments to the same object, - // change to slow case to avoid the quadratic behavior of repeatedly - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value. - __ push(ip); - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - // Record source code position before IC call. SetSourcePosition(expr->position()); __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); - // Load receiver to r1. Leave a copy in the stack if needed for turning the - // receiver into fast case. - if (expr->ends_initialization_block()) { - __ ldr(r1, MemOperand(sp)); - } else { - __ pop(r1); - } + __ pop(r1); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ push(r0); // Result of assignment, saved even if not needed. - // Receiver is under the result value. - __ ldr(ip, MemOperand(sp, kPointerSize)); - __ push(ip); - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(r0); - __ Drop(1); - } PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(r0); } @@ -2228,44 +2206,16 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { // Assignment to a property, using a keyed store IC. - // If the assignment starts a block of assignments to the same object, - // change to slow case to avoid the quadratic behavior of repeatedly - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - // Receiver is now under the key and value. - __ ldr(ip, MemOperand(sp, 2 * kPointerSize)); - __ push(ip); - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - // Record source code position before IC call. SetSourcePosition(expr->position()); __ pop(r1); // Key. - // Load receiver to r2. Leave a copy in the stack if needed for turning the - // receiver into fast case. - if (expr->ends_initialization_block()) { - __ ldr(r2, MemOperand(sp)); - } else { - __ pop(r2); - } + __ pop(r2); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ push(r0); // Result of assignment, saved even if not needed. - // Receiver is under the result value. - __ ldr(ip, MemOperand(sp, kPointerSize)); - __ push(ip); - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(r0); - __ Drop(1); - } PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(r0); } @@ -2294,7 +2244,9 @@ void FullCodeGenerator::CallIC(Handle<Code> code, RelocInfo::Mode rmode, TypeFeedbackId ast_id) { ic_total_count_++; - __ Call(code, rmode, ast_id); + // All calls must have a predictable size in full-codegen code to ensure that + // the debugger can patch them correctly. + __ Call(code, rmode, ast_id, al, NEVER_INLINE_TARGET_ADDRESS); } void FullCodeGenerator::EmitCallWithIC(Call* expr, @@ -2424,7 +2376,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { VariableProxy* proxy = callee->AsVariableProxy(); Property* property = callee->AsProperty(); - if (proxy != NULL && proxy->var()->is_possibly_eval()) { + if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { // In a call to eval, we first call %ResolvePossiblyDirectEval to // resolve the function we need to call and the receiver of the // call. Then we call the resolved function using the given @@ -2714,7 +2666,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - if (generate_debug_code_) __ AbortIfSmi(r0); + __ AssertNotSmi(r0); __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); __ ldrb(ip, FieldMemOperand(r1, Map::kBitField2Offset)); @@ -2729,26 +2681,31 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ b(eq, if_false); // Look for valueOf symbol in the descriptor array, and indicate false if - // found. The type is not checked, so if it is a transition it is a false - // negative. - __ LoadInstanceDescriptors(r1, r4, r3); - __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset)); - // r4: descriptor array - // r3: length of descriptor array - // Calculate the end of the descriptor array. + // found. Since we omit an enumeration index check, if it is added via a + // transition that shares its descriptor array, this is a false positive. + Label entry, loop, done; + + // Skip loop if no descriptors are valid. + __ NumberOfOwnDescriptors(r3, r1); + __ cmp(r3, Operand(0)); + __ b(eq, &done); + + __ LoadInstanceDescriptors(r1, r4); + // r4: descriptor array. + // r3: valid entries in the descriptor array. STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); STATIC_ASSERT(kPointerSize == 4); - __ add(r2, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ mov(ip, Operand(DescriptorArray::kDescriptorSize)); + __ mul(r3, r3, ip); + // Calculate location of the first key name. + __ add(r4, r4, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag)); + // Calculate the end of the descriptor array. + __ mov(r2, r4); __ add(r2, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); - // Calculate location of the first key name. - __ add(r4, - r4, - Operand(DescriptorArray::kFirstOffset - kHeapObjectTag)); // Loop through all the keys in the descriptor array. If one of these is the // symbol valueOf the result is false. - Label entry, loop; // The use of ip to store the valueOf symbol asumes that it is not otherwise // used in the loop below. __ mov(ip, Operand(FACTORY->value_of_symbol())); @@ -2762,7 +2719,8 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ cmp(r4, Operand(r2)); __ b(ne, &loop); - // If a valueOf property is not found on the object check that it's + __ bind(&done); + // If a valueOf property is not found on the object check that its // prototype is the un-modified String prototype. If not result is false. __ ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset)); __ JumpIfSmi(r2, if_false); @@ -3173,6 +3131,39 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) { } +void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { + ZoneList<Expression*>* args = expr->arguments(); + ASSERT_EQ(3, args->length()); + + VisitForStackValue(args->at(1)); // index + VisitForStackValue(args->at(2)); // value + __ pop(r2); + __ pop(r1); + VisitForAccumulatorValue(args->at(0)); // string + + static const String::Encoding encoding = String::ONE_BYTE_ENCODING; + SeqStringSetCharGenerator::Generate(masm_, encoding, r0, r1, r2); + context()->Plug(r0); +} + + +void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { + ZoneList<Expression*>* args = expr->arguments(); + ASSERT_EQ(3, args->length()); + + VisitForStackValue(args->at(1)); // index + VisitForStackValue(args->at(2)); // value + __ pop(r2); + __ pop(r1); + VisitForAccumulatorValue(args->at(0)); // string + + static const String::Encoding encoding = String::TWO_BYTE_ENCODING; + SeqStringSetCharGenerator::Generate(masm_, encoding, r0, r1, r2); + context()->Plug(r0); +} + + + void FullCodeGenerator::EmitMathPow(CallRuntime* expr) { // Load the arguments on the stack and call the runtime function. ZoneList<Expression*>* args = expr->arguments(); @@ -3583,8 +3574,7 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) { ASSERT(args->length() == 1); VisitForAccumulatorValue(args->at(0)); - __ AbortIfNotString(r0); - + __ AssertString(r0); __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); __ IndexFromHash(r0, r0); @@ -3666,7 +3656,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset)); __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); - __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset)); + __ ldr(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset)); __ add(string_length, string_length, Operand(scratch1), SetCC); __ b(vs, &bailout); __ cmp(element, elements_end); @@ -3695,7 +3685,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // Add (separator length times array_length) - separator length to the // string_length to get the length of the result string. array_length is not // smi but the other values are, so the result is a smi - __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); + __ ldr(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); __ sub(string_length, string_length, Operand(scratch1)); __ smull(scratch2, ip, array_length, scratch1); // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are @@ -3733,10 +3723,10 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { array_length = no_reg; __ add(result_pos, result, - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); // Check the length of the separator. - __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); + __ ldr(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); __ cmp(scratch1, Operand(Smi::FromInt(1))); __ b(eq, &one_char_separator); __ b(gt, &long_separator); @@ -3752,7 +3742,9 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); __ SmiUntag(string_length); - __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(string, + string, + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ CopyBytes(string, result_pos, string_length, scratch1); __ cmp(element, elements_end); __ b(lt, &empty_separator_loop); // End while (element < elements_end). @@ -3762,7 +3754,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // One-character separator case __ bind(&one_char_separator); // Replace separator with its ASCII character value. - __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize)); + __ ldrb(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize)); // Jump into the loop after the code that copies the separator, so the first // element is not preceded by a separator __ jmp(&one_char_separator_loop_entry); @@ -3782,7 +3774,9 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); __ SmiUntag(string_length); - __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(string, + string, + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ CopyBytes(string, result_pos, string_length, scratch1); __ cmp(element, elements_end); __ b(lt, &one_char_separator_loop); // End while (element < elements_end). @@ -3803,14 +3797,16 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ SmiUntag(string_length); __ add(string, separator, - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ CopyBytes(string, result_pos, string_length, scratch1); __ bind(&long_separator); __ ldr(string, MemOperand(element, kPointerSize, PostIndex)); __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset)); __ SmiUntag(string_length); - __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(string, + string, + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ CopyBytes(string, result_pos, string_length, scratch1); __ cmp(element, elements_end); __ b(lt, &long_separator_loop); // End while (element < elements_end). @@ -4115,7 +4111,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { // Call stub. Undo operation first. __ sub(r0, r0, Operand(Smi::FromInt(count_value))); } - __ mov(r1, Operand(Smi::FromInt(count_value))); + __ mov(r1, r0); + __ mov(r0, Operand(Smi::FromInt(count_value))); // Record position before stub call. SetSourcePosition(expr->position()); @@ -4340,29 +4337,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { default: { VisitForAccumulatorValue(expr->right()); - Condition cond = eq; - switch (op) { - case Token::EQ_STRICT: - case Token::EQ: - cond = eq; - break; - case Token::LT: - cond = lt; - break; - case Token::GT: - cond = gt; - break; - case Token::LTE: - cond = le; - break; - case Token::GTE: - cond = ge; - break; - case Token::IN: - case Token::INSTANCEOF: - default: - UNREACHABLE(); - } + Condition cond = CompareIC::ComputeCondition(op); __ pop(r1); bool inline_smi_code = ShouldInlineSmiCase(op); diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 404f3c6145..29a3687aa9 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -1301,6 +1301,143 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, } +static void KeyedStoreGenerateGenericHelper( + MacroAssembler* masm, + Label* fast_object, + Label* fast_double, + Label* slow, + KeyedStoreCheckMap check_map, + KeyedStoreIncrementLength increment_length, + Register value, + Register key, + Register receiver, + Register receiver_map, + Register elements_map, + Register elements) { + Label transition_smi_elements; + Label finish_object_store, non_double_value, transition_double_elements; + Label fast_double_without_map_check; + + // Fast case: Do the store, could be either Object or double. + __ bind(fast_object); + Register scratch_value = r4; + Register address = r5; + if (check_map == kCheckMap) { + __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); + __ cmp(elements_map, + Operand(masm->isolate()->factory()->fixed_array_map())); + __ b(ne, fast_double); + } + // Smi stores don't require further checks. + Label non_smi_value; + __ JumpIfNotSmi(value, &non_smi_value); + + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ add(scratch_value, key, Operand(Smi::FromInt(1))); + __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); + } + // It's irrelevant whether array is smi-only or not when writing a smi. + __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); + __ str(value, MemOperand(address)); + __ Ret(); + + __ bind(&non_smi_value); + // Escape to elements kind transition case. + __ CheckFastObjectElements(receiver_map, scratch_value, + &transition_smi_elements); + + // Fast elements array, store the value to the elements backing store. + __ bind(&finish_object_store); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ add(scratch_value, key, Operand(Smi::FromInt(1))); + __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); + } + __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); + __ str(value, MemOperand(address)); + // Update write barrier for the elements array address. + __ mov(scratch_value, value); // Preserve the value which is returned. + __ RecordWrite(elements, + address, + scratch_value, + kLRHasNotBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ Ret(); + + __ bind(fast_double); + if (check_map == kCheckMap) { + // Check for fast double array case. If this fails, call through to the + // runtime. + __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex); + __ b(ne, slow); + } + __ bind(&fast_double_without_map_check); + __ StoreNumberToDoubleElements(value, + key, + elements, // Overwritten. + r3, // Scratch regs... + r4, + r5, + r6, + &transition_double_elements); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ add(scratch_value, key, Operand(Smi::FromInt(1))); + __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); + } + __ Ret(); + + __ bind(&transition_smi_elements); + // Transition the array appropriately depending on the value type. + __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset)); + __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex); + __ b(ne, &non_double_value); + + // Value is a double. Transition FAST_SMI_ELEMENTS -> + // FAST_DOUBLE_ELEMENTS and complete the store. + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_DOUBLE_ELEMENTS, + receiver_map, + r4, + slow); + ASSERT(receiver_map.is(r3)); // Transition code expects map in r3 + ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow); + __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ jmp(&fast_double_without_map_check); + + __ bind(&non_double_value); + // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_ELEMENTS, + receiver_map, + r4, + slow); + ASSERT(receiver_map.is(r3)); // Transition code expects map in r3 + ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); + __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); + + __ bind(&transition_double_elements); + // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a + // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and + // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS + __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, + FAST_ELEMENTS, + receiver_map, + r4, + slow); + ASSERT(receiver_map.is(r3)); // Transition code expects map in r3 + ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow); + __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); +} + + void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode) { // ---------- S t a t e -------------- @@ -1309,11 +1446,9 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // -- r2 : receiver // -- lr : return address // ----------------------------------- - Label slow, array, extra, check_if_double_array; - Label fast_object_with_map_check, fast_object_without_map_check; - Label fast_double_with_map_check, fast_double_without_map_check; - Label transition_smi_elements, finish_object_store, non_double_value; - Label transition_double_elements; + Label slow, fast_object, fast_object_grow; + Label fast_double, fast_double_grow; + Label array, extra, check_if_double_array; // Register usage. Register value = r0; @@ -1348,7 +1483,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // Check array bounds. Both the key and the length of FixedArray are smis. __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset)); __ cmp(key, Operand(ip)); - __ b(lo, &fast_object_with_map_check); + __ b(lo, &fast_object); // Slow case, handle jump to runtime. __ bind(&slow); @@ -1373,21 +1508,13 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ cmp(elements_map, Operand(masm->isolate()->factory()->fixed_array_map())); __ b(ne, &check_if_double_array); - // Calculate key + 1 as smi. - STATIC_ASSERT(kSmiTag == 0); - __ add(r4, key, Operand(Smi::FromInt(1))); - __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); - __ b(&fast_object_without_map_check); + __ jmp(&fast_object_grow); __ bind(&check_if_double_array); __ cmp(elements_map, Operand(masm->isolate()->factory()->fixed_double_array_map())); __ b(ne, &slow); - // Add 1 to key, and go to common element store code for doubles. - STATIC_ASSERT(kSmiTag == 0); - __ add(r4, key, Operand(Smi::FromInt(1))); - __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); - __ jmp(&fast_double_without_map_check); + __ jmp(&fast_double_grow); // Array case: Get the length and the elements array from the JS // array. Check that the array is in fast mode (and writable); if it @@ -1399,106 +1526,15 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset)); __ cmp(key, Operand(ip)); __ b(hs, &extra); - // Fall through to fast case. - - __ bind(&fast_object_with_map_check); - Register scratch_value = r4; - Register address = r5; - __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); - __ cmp(elements_map, - Operand(masm->isolate()->factory()->fixed_array_map())); - __ b(ne, &fast_double_with_map_check); - __ bind(&fast_object_without_map_check); - // Smi stores don't require further checks. - Label non_smi_value; - __ JumpIfNotSmi(value, &non_smi_value); - // It's irrelevant whether array is smi-only or not when writing a smi. - __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); - __ str(value, MemOperand(address)); - __ Ret(); - __ bind(&non_smi_value); - // Escape to elements kind transition case. - __ CheckFastObjectElements(receiver_map, scratch_value, - &transition_smi_elements); - // Fast elements array, store the value to the elements backing store. - __ bind(&finish_object_store); - __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); - __ str(value, MemOperand(address)); - // Update write barrier for the elements array address. - __ mov(scratch_value, value); // Preserve the value which is returned. - __ RecordWrite(elements, - address, - scratch_value, - kLRHasNotBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - __ Ret(); - - __ bind(&fast_double_with_map_check); - // Check for fast double array case. If this fails, call through to the - // runtime. - __ cmp(elements_map, - Operand(masm->isolate()->factory()->fixed_double_array_map())); - __ b(ne, &slow); - __ bind(&fast_double_without_map_check); - __ StoreNumberToDoubleElements(value, - key, - receiver, - elements, - r3, - r4, - r5, - r6, - &transition_double_elements); - __ Ret(); - - __ bind(&transition_smi_elements); - // Transition the array appropriately depending on the value type. - __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset)); - __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex); - __ b(ne, &non_double_value); - - // Value is a double. Transition FAST_SMI_ELEMENTS -> - // FAST_DOUBLE_ELEMENTS and complete the store. - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS, - receiver_map, - r4, - &slow); - ASSERT(receiver_map.is(r3)); // Transition code expects map in r3 - ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow); - __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ jmp(&fast_double_without_map_check); - - __ bind(&non_double_value); - // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - r4, - &slow); - ASSERT(receiver_map.is(r3)); // Transition code expects map in r3 - ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); - __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); - - __ bind(&transition_double_elements); - // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a - // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and - // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - r4, - &slow); - ASSERT(receiver_map.is(r3)); // Transition code expects map in r3 - ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow); - __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); + KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, + &slow, kCheckMap, kDontIncrementLength, + value, key, receiver, receiver_map, + elements_map, elements); + KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, + &slow, kDontCheckMap, kIncrementLength, + value, key, receiver, receiver_map, + elements_map, elements); } @@ -1662,42 +1698,21 @@ Condition CompareIC::ComputeCondition(Token::Value op) { } -void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { - HandleScope scope; - Handle<Code> rewritten; - State previous_state = GetState(); - State state = TargetState(previous_state, false, x, y); - if (state == GENERIC) { - CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0); - rewritten = stub.GetCode(); - } else { - ICCompareStub stub(op_, state); - if (state == KNOWN_OBJECTS) { - stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map())); - } - rewritten = stub.GetCode(); - } - set_target(*rewritten); - -#ifdef DEBUG - if (FLAG_trace_ic) { - PrintF("[CompareIC (%s->%s)#%s]\n", - GetStateName(previous_state), - GetStateName(state), - Token::Name(op_)); - } -#endif +bool CompareIC::HasInlinedSmiCode(Address address) { + // The address of the instruction following the call. + Address cmp_instruction_address = + Assembler::return_address_from_call_start(address); - // Activate inlined smi code. - if (previous_state == UNINITIALIZED) { - PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); - } + // If the instruction following the call is not a cmp rx, #yyy, nothing + // was inlined. + Instr instr = Assembler::instr_at(cmp_instruction_address); + return Assembler::IsCmpImmediate(instr); } void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { Address cmp_instruction_address = - address + Assembler::kCallTargetAddressOffset; + Assembler::return_address_from_call_start(address); // If the instruction following the call is not a cmp rx, #yyy, nothing // was inlined. diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index fc1d64079a..4203673733 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -177,6 +177,7 @@ const char* LArithmeticT::Mnemonic() const { case Token::BIT_AND: return "bit-and-t"; case Token::BIT_OR: return "bit-or-t"; case Token::BIT_XOR: return "bit-xor-t"; + case Token::ROR: return "ror-t"; case Token::SHL: return "shl-t"; case Token::SAR: return "sar-t"; case Token::SHR: return "shr-t"; @@ -194,22 +195,22 @@ void LGoto::PrintDataTo(StringStream* stream) { void LBranch::PrintDataTo(StringStream* stream) { stream->Add("B%d | B%d on ", true_block_id(), false_block_id()); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); } void LCmpIDAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - InputAt(0)->PrintTo(stream); + left()->PrintTo(stream); stream->Add(" %s ", Token::String(op())); - InputAt(1)->PrintTo(stream); + right()->PrintTo(stream); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); } void LIsNilAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(kind() == kStrictEquality ? " === " : " == "); stream->Add(nil() == kNullValue ? "null" : "undefined"); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); @@ -218,57 +219,57 @@ void LIsNilAndBranch::PrintDataTo(StringStream* stream) { void LIsObjectAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_object("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsStringAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_string("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_smi("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_undetectable("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LStringCompareAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if string_compare("); - InputAt(0)->PrintTo(stream); - InputAt(1)->PrintTo(stream); + left()->PrintTo(stream); + right()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_instance_type("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_cached_array_index("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if class_of_test("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(), true_block_id(), @@ -278,7 +279,7 @@ void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(" == \"%s\" then B%d else B%d", *hydrogen()->type_literal()->ToCString(), true_block_id(), false_block_id()); @@ -292,26 +293,31 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) { void LUnaryMathOperation::PrintDataTo(StringStream* stream) { stream->Add("/%s ", hydrogen()->OpName()); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); +} + + +void LMathExp::PrintDataTo(StringStream* stream) { + value()->PrintTo(stream); } void LLoadContextSlot::PrintDataTo(StringStream* stream) { - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); stream->Add("[%d]", slot_index()); } void LStoreContextSlot::PrintDataTo(StringStream* stream) { - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); stream->Add("[%d] <- ", slot_index()); - InputAt(1)->PrintTo(stream); + value()->PrintTo(stream); } void LInvokeFunction::PrintDataTo(StringStream* stream) { stream->Add("= "); - InputAt(0)->PrintTo(stream); + function()->PrintTo(stream); stream->Add(" #%d / ", arity()); } @@ -340,17 +346,15 @@ void LCallKnownGlobal::PrintDataTo(StringStream* stream) { void LCallNew::PrintDataTo(StringStream* stream) { stream->Add("= "); - InputAt(0)->PrintTo(stream); + constructor()->PrintTo(stream); stream->Add(" #%d / ", arity()); } void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { arguments()->PrintTo(stream); - stream->Add(" length "); length()->PrintTo(stream); - stream->Add(" index "); index()->PrintTo(stream); } @@ -374,20 +378,27 @@ void LStoreNamedGeneric::PrintDataTo(StringStream* stream) { } -void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) { - object()->PrintTo(stream); +void LLoadKeyed::PrintDataTo(StringStream* stream) { + elements()->PrintTo(stream); stream->Add("["); key()->PrintTo(stream); - stream->Add("] <- "); - value()->PrintTo(stream); + if (hydrogen()->IsDehoisted()) { + stream->Add(" + %d]", additional_index()); + } else { + stream->Add("]"); + } } -void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) { +void LStoreKeyed::PrintDataTo(StringStream* stream) { elements()->PrintTo(stream); stream->Add("["); key()->PrintTo(stream); - stream->Add("] <- "); + if (hydrogen()->IsDehoisted()) { + stream->Add(" + %d] <-", additional_index()); + } else { + stream->Add("] <- "); + } value()->PrintTo(stream); } @@ -860,6 +871,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment( argument_count_, value_count, outer, + hydrogen_env->entry(), zone()); int argument_index = *argument_index_accumulator; for (int i = 0; i < value_count; ++i) { @@ -1034,6 +1046,15 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { LOperand* input = UseFixedDouble(instr->value(), d2); LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL); return MarkAsCall(DefineFixedDouble(result, d2), instr); + } else if (op == kMathExp) { + ASSERT(instr->representation().IsDouble()); + ASSERT(instr->value()->representation().IsDouble()); + LOperand* input = UseTempRegister(instr->value()); + LOperand* temp1 = TempRegister(); + LOperand* temp2 = TempRegister(); + LOperand* double_temp = FixedTemp(d3); // Chosen by fair dice roll. + LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2); + return DefineAsRegister(result); } else if (op == kMathPowHalf) { LOperand* input = UseFixedDouble(instr->value(), d2); LOperand* temp = FixedTemp(d3); @@ -1041,7 +1062,8 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { return DefineFixedDouble(result, d2); } else { LOperand* input = UseRegisterAtStart(instr->value()); - LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL; + + LOperand* temp = (op == kMathRound) ? FixedTemp(d3) : NULL; LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp); switch (op) { case kMathAbs: @@ -1108,6 +1130,11 @@ LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) { } +LInstruction* LChunkBuilder::DoRor(HRor* instr) { + return DoShift(Token::ROR, instr); +} + + LInstruction* LChunkBuilder::DoShr(HShr* instr) { return DoShift(Token::SHR, instr); } @@ -1306,8 +1333,21 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { return DefineAsRegister(mul); } else if (instr->representation().IsDouble()) { - return DoArithmeticD(Token::MUL, instr); + if (instr->UseCount() == 1 && instr->uses().value()->IsAdd()) { + HAdd* add = HAdd::cast(instr->uses().value()); + if (instr == add->left()) { + // This mul is the lhs of an add. The add and mul will be folded + // into a multiply-add. + return NULL; + } + if (instr == add->right() && !add->left()->IsMul()) { + // This mul is the rhs of an add, where the lhs is not another mul. + // The add and mul will be folded into a multiply-add. + return NULL; + } + } + return DoArithmeticD(Token::MUL, instr); } else { return DoArithmeticT(Token::MUL, instr); } @@ -1318,6 +1358,12 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { if (instr->representation().IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); + + if (instr->left()->IsConstant()) { + // If lhs is constant, do reverse subtraction instead. + return DoRSub(instr); + } + LOperand* left = UseRegisterAtStart(instr->left()); LOperand* right = UseOrConstantAtStart(instr->right()); LSubI* sub = new(zone()) LSubI(left, right); @@ -1334,6 +1380,32 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { } +LInstruction* LChunkBuilder::DoRSub(HSub* instr) { + ASSERT(instr->representation().IsInteger32()); + ASSERT(instr->left()->representation().IsInteger32()); + ASSERT(instr->right()->representation().IsInteger32()); + + // Note: The lhs of the subtraction becomes the rhs of the + // reverse-subtraction. + LOperand* left = UseRegisterAtStart(instr->right()); + LOperand* right = UseOrConstantAtStart(instr->left()); + LRSubI* rsb = new(zone()) LRSubI(left, right); + LInstruction* result = DefineAsRegister(rsb); + if (instr->CheckFlag(HValue::kCanOverflow)) { + result = AssignEnvironment(result); + } + return result; +} + + +LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) { + LOperand* multiplier_op = UseRegisterAtStart(mul->left()); + LOperand* multiplicand_op = UseRegisterAtStart(mul->right()); + LOperand* addend_op = UseRegisterAtStart(addend); + return DefineSameAsFirst(new(zone()) LMultiplyAddD(addend_op, multiplier_op, + multiplicand_op)); +} + LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { if (instr->representation().IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); @@ -1347,6 +1419,14 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { } return result; } else if (instr->representation().IsDouble()) { + if (instr->left()->IsMul()) + return DoMultiplyAdd(HMul::cast(instr->left()), instr->right()); + + if (instr->right()->IsMul()) { + ASSERT(!instr->left()->IsMul()); + return DoMultiplyAdd(HMul::cast(instr->right()), instr->left()); + } + return DoArithmeticD(Token::ADD, instr); } else { ASSERT(instr->representation().IsTagged()); @@ -1412,7 +1492,7 @@ LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) { LInstruction* LChunkBuilder::DoCompareIDAndBranch( HCompareIDAndBranch* instr) { - Representation r = instr->GetInputRepresentation(); + Representation r = instr->representation(); if (r.IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); @@ -1566,6 +1646,16 @@ LInstruction* LChunkBuilder::DoDateField(HDateField* instr) { } +LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { + LOperand* string = UseRegister(instr->string()); + LOperand* index = UseRegister(instr->index()); + LOperand* value = UseRegister(instr->value()); + LSeqStringSetChar* result = + new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value); + return DefineAsRegister(result); +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LOperand* value = UseRegisterOrConstantAtStart(instr->index()); LOperand* length = UseRegister(instr->length()); @@ -1617,8 +1707,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { LOperand* temp1 = TempRegister(); LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() : NULL; - LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d11) - : NULL; + LOperand* temp3 = FixedTemp(d11); res = DefineSameAsFirst(new(zone()) LTaggedToI(value, temp1, temp2, @@ -1690,10 +1779,10 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { - LOperand* temp1 = TempRegister(); + LUnallocated* temp1 = TempRegister(); LOperand* temp2 = TempRegister(); - LInstruction* result = new(zone()) LCheckPrototypeMaps(temp1, temp2); - return AssignEnvironment(result); + LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2); + return AssignEnvironment(Define(result, temp1)); } @@ -1861,53 +1950,40 @@ LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( } -LInstruction* LChunkBuilder::DoLoadKeyedFastElement( - HLoadKeyedFastElement* instr) { - ASSERT(instr->representation().IsTagged()); +LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { ASSERT(instr->key()->representation().IsInteger32() || instr->key()->representation().IsTagged()); - LOperand* obj = UseRegisterAtStart(instr->object()); - LOperand* key = UseRegisterOrConstantAtStart(instr->key()); - LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key); - if (instr->RequiresHoleCheck()) AssignEnvironment(result); - return DefineAsRegister(result); -} - - -LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement( - HLoadKeyedFastDoubleElement* instr) { - ASSERT(instr->representation().IsDouble()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - LOperand* elements = UseTempRegister(instr->elements()); + ElementsKind elements_kind = instr->elements_kind(); LOperand* key = UseRegisterOrConstantAtStart(instr->key()); - LLoadKeyedFastDoubleElement* result = - new(zone()) LLoadKeyedFastDoubleElement(elements, key); - return AssignEnvironment(DefineAsRegister(result)); -} + LLoadKeyed* result = NULL; + if (!instr->is_external()) { + LOperand* obj = NULL; + if (instr->representation().IsDouble()) { + obj = UseTempRegister(instr->elements()); + } else { + ASSERT(instr->representation().IsTagged()); + obj = UseRegisterAtStart(instr->elements()); + } + result = new(zone()) LLoadKeyed(obj, key); + } else { + ASSERT( + (instr->representation().IsInteger32() && + (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && + (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || + (instr->representation().IsDouble() && + ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || + (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); + LOperand* external_pointer = UseRegister(instr->elements()); + result = new(zone()) LLoadKeyed(external_pointer, key); + } -LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( - HLoadKeyedSpecializedArrayElement* instr) { - ElementsKind elements_kind = instr->elements_kind(); - ASSERT( - (instr->representation().IsInteger32() && - (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && - (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || - (instr->representation().IsDouble() && - ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || - (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - LOperand* external_pointer = UseRegister(instr->external_pointer()); - LOperand* key = UseRegisterOrConstant(instr->key()); - LLoadKeyedSpecializedArrayElement* result = - new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key); - LInstruction* load_instr = DefineAsRegister(result); + DefineAsRegister(result); // An unsigned int array load might overflow and cause a deopt, make sure it // has an environment. - return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ? - AssignEnvironment(load_instr) : load_instr; + bool can_deoptimize = instr->RequiresHoleCheck() || + (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS); + return can_deoptimize ? AssignEnvironment(result) : result; } @@ -1921,66 +1997,48 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { } -LInstruction* LChunkBuilder::DoStoreKeyedFastElement( - HStoreKeyedFastElement* instr) { - bool needs_write_barrier = instr->NeedsWriteBarrier(); - ASSERT(instr->value()->representation().IsTagged()); - ASSERT(instr->object()->representation().IsTagged()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* obj = UseTempRegister(instr->object()); - LOperand* val = needs_write_barrier - ? UseTempRegister(instr->value()) - : UseRegisterAtStart(instr->value()); - LOperand* key = needs_write_barrier - ? UseTempRegister(instr->key()) - : UseRegisterOrConstantAtStart(instr->key()); - return new(zone()) LStoreKeyedFastElement(obj, key, val); -} - - -LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement( - HStoreKeyedFastDoubleElement* instr) { - ASSERT(instr->value()->representation().IsDouble()); - ASSERT(instr->elements()->representation().IsTagged()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* elements = UseRegisterAtStart(instr->elements()); - LOperand* val = UseTempRegister(instr->value()); - LOperand* key = UseRegisterOrConstantAtStart(instr->key()); +LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { + ElementsKind elements_kind = instr->elements_kind(); - return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val); -} + if (!instr->is_external()) { + ASSERT(instr->elements()->representation().IsTagged()); + bool needs_write_barrier = instr->NeedsWriteBarrier(); + LOperand* object = NULL; + LOperand* key = NULL; + LOperand* val = NULL; + + if (instr->value()->representation().IsDouble()) { + object = UseRegisterAtStart(instr->elements()); + val = UseTempRegister(instr->value()); + key = UseRegisterOrConstantAtStart(instr->key()); + } else { + ASSERT(instr->value()->representation().IsTagged()); + object = UseTempRegister(instr->elements()); + val = needs_write_barrier ? UseTempRegister(instr->value()) + : UseRegisterAtStart(instr->value()); + key = needs_write_barrier ? UseTempRegister(instr->key()) + : UseRegisterOrConstantAtStart(instr->key()); + } + return new(zone()) LStoreKeyed(object, key, val); + } -LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( - HStoreKeyedSpecializedArrayElement* instr) { - ElementsKind elements_kind = instr->elements_kind(); ASSERT( (instr->value()->representation().IsInteger32() && (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || (instr->value()->representation().IsDouble() && ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || - (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); - ASSERT(instr->external_pointer()->representation().IsExternal()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* external_pointer = UseRegister(instr->external_pointer()); + (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); + ASSERT(instr->elements()->representation().IsExternal()); bool val_is_temp_register = elements_kind == EXTERNAL_PIXEL_ELEMENTS || elements_kind == EXTERNAL_FLOAT_ELEMENTS; - LOperand* val = val_is_temp_register - ? UseTempRegister(instr->value()) + LOperand* val = val_is_temp_register ? UseTempRegister(instr->value()) : UseRegister(instr->value()); - LOperand* key = UseRegisterOrConstant(instr->key()); - - return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer, - key, - val); + LOperand* key = UseRegisterOrConstantAtStart(instr->key()); + LOperand* external_pointer = UseRegister(instr->elements()); + return new(zone()) LStoreKeyed(external_pointer, key, val); } @@ -2126,6 +2184,7 @@ LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) { LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) { + ASSERT(argument_count_ == 0); allocator_->MarkAsOsrEntry(); current_block_->last_environment()->set_ast_id(instr->ast_id()); return AssignEnvironment(new(zone()) LOsrEntry); @@ -2164,12 +2223,10 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { - LOperand* arguments = UseRegister(instr->arguments()); + LOperand* args = UseRegister(instr->arguments()); LOperand* length = UseTempRegister(instr->length()); LOperand* index = UseRegister(instr->index()); - LAccessArgumentsAt* result = - new(zone()) LAccessArgumentsAt(arguments, length, index); - return AssignEnvironment(DefineAsRegister(result)); + return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index)); } @@ -2204,7 +2261,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { env->set_ast_id(instr->ast_id()); env->Drop(instr->pop_count()); - for (int i = 0; i < instr->values()->length(); ++i) { + for (int i = instr->values()->length() - 1; i >= 0; --i) { HValue* value = instr->values()->at(i); if (instr->HasAssignedIndexAt(i)) { env->Bind(instr->GetAssignedIndexAt(i), value); @@ -2253,6 +2310,7 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { if (instr->arguments_var() != NULL) { inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject()); } + inner->set_entry(instr); current_block_->UpdateEnvironment(inner); chunk_->AddInlinedClosure(instr->closure()); return NULL; @@ -2264,7 +2322,7 @@ LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { HEnvironment* env = current_block_->last_environment(); - if (instr->arguments_pushed()) { + if (env->entry()->arguments_pushed()) { int argument_count = env->arguments_environment()->parameter_count(); pop = new(zone()) LDrop(argument_count); argument_count_ -= argument_count; @@ -2295,9 +2353,7 @@ LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) { LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) { LOperand* map = UseRegister(instr->map()); - LOperand* scratch = TempRegister(); - return AssignEnvironment(DefineAsRegister( - new(zone()) LForInCacheArray(map, scratch))); + return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map))); } diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index e6e102f762..7397b4bc8d 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -125,18 +125,18 @@ class LCodeGen; V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ - V(LoadKeyedFastDoubleElement) \ - V(LoadKeyedFastElement) \ + V(LoadKeyed) \ V(LoadKeyedGeneric) \ - V(LoadKeyedSpecializedArrayElement) \ V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ V(MapEnumLength) \ + V(MathExp) \ V(MathFloorOfDiv) \ V(MathMinMax) \ V(ModI) \ V(MulI) \ + V(MultiplyAddD) \ V(NumberTagD) \ V(NumberTagI) \ V(NumberTagU) \ @@ -150,6 +150,7 @@ class LCodeGen; V(Random) \ V(RegExpLiteral) \ V(Return) \ + V(SeqStringSetChar) \ V(ShiftI) \ V(SmiTag) \ V(SmiUntag) \ @@ -157,10 +158,8 @@ class LCodeGen; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ - V(StoreKeyedFastDoubleElement) \ - V(StoreKeyedFastElement) \ + V(StoreKeyed) \ V(StoreKeyedGeneric) \ - V(StoreKeyedSpecializedArrayElement) \ V(StoreNamedField) \ V(StoreNamedGeneric) \ V(StringAdd) \ @@ -169,6 +168,7 @@ class LCodeGen; V(StringCompareAndBranch) \ V(StringLength) \ V(SubI) \ + V(RSubI) \ V(TaggedToI) \ V(ThisFunction) \ V(Throw) \ @@ -261,9 +261,6 @@ class LInstruction: public ZoneObject { virtual bool HasResult() const = 0; virtual LOperand* result() = 0; - virtual int TempCount() = 0; - virtual LOperand* TempAt(int i) = 0; - LOperand* FirstInput() { return InputAt(0); } LOperand* Output() { return HasResult() ? result() : NULL; } @@ -277,6 +274,10 @@ class LInstruction: public ZoneObject { virtual int InputCount() = 0; virtual LOperand* InputAt(int i) = 0; + friend class TempIterator; + virtual int TempCount() = 0; + virtual LOperand* TempAt(int i) = 0; + LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; @@ -296,11 +297,6 @@ class LTemplateInstruction: public LInstruction { void set_result(LOperand* operand) { results_[0] = operand; } LOperand* result() { return results_[0]; } - LOperand* InputAt(int i) { return inputs_[i]; } - - int TempCount() { return T; } - LOperand* TempAt(int i) { return temps_[i]; } - protected: EmbeddedContainer<LOperand*, R> results_; EmbeddedContainer<LOperand*, I> inputs_; @@ -308,6 +304,10 @@ class LTemplateInstruction: public LInstruction { private: virtual int InputCount() { return I; } + virtual LOperand* InputAt(int i) { return inputs_[i]; } + + virtual int TempCount() { return T; } + virtual LOperand* TempAt(int i) { return temps_[i]; } }; @@ -525,6 +525,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = elements; } + LOperand* elements() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length") }; @@ -551,16 +553,22 @@ class LModI: public LTemplateInstruction<1, 2, 3> { // Used for the standard case. LModI(LOperand* left, LOperand* right, - LOperand* temp1, + LOperand* temp, LOperand* temp2, LOperand* temp3) { inputs_[0] = left; inputs_[1] = right; - temps_[0] = temp1; + temps_[0] = temp; temps_[1] = temp2; temps_[2] = temp3; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + LOperand* temp3() { return temps_[2]; } + DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i") DECLARE_HYDROGEN_ACCESSOR(Mod) }; @@ -573,6 +581,9 @@ class LDivI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i") DECLARE_HYDROGEN_ACCESSOR(Div) }; @@ -588,6 +599,10 @@ class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div") DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv) }; @@ -601,11 +616,33 @@ class LMulI: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i") DECLARE_HYDROGEN_ACCESSOR(Mul) }; +// Instruction for computing multiplier * multiplicand + addend. +class LMultiplyAddD: public LTemplateInstruction<1, 3, 0> { + public: + LMultiplyAddD(LOperand* addend, LOperand* multiplier, + LOperand* multiplicand) { + inputs_[0] = addend; + inputs_[1] = multiplier; + inputs_[2] = multiplicand; + } + + LOperand* addend() { return inputs_[0]; } + LOperand* multiplier() { return inputs_[1]; } + LOperand* multiplicand() { return inputs_[2]; } + + DECLARE_CONCRETE_INSTRUCTION(MultiplyAddD, "multiply-add-d") +}; + + class LCmpIDAndBranch: public LControlInstruction<2, 0> { public: LCmpIDAndBranch(LOperand* left, LOperand* right) { @@ -613,12 +650,15 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch) Token::Value op() const { return hydrogen()->token(); } bool is_double() const { - return hydrogen()->GetInputRepresentation().IsDouble(); + return hydrogen()->representation().IsDouble(); } virtual void PrintDataTo(StringStream* stream); @@ -632,6 +672,9 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation") DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation) @@ -640,6 +683,30 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> { }; +class LMathExp: public LTemplateInstruction<1, 1, 3> { + public: + LMathExp(LOperand* value, + LOperand* double_temp, + LOperand* temp1, + LOperand* temp2) { + inputs_[0] = value; + temps_[0] = temp1; + temps_[1] = temp2; + temps_[2] = double_temp; + ExternalReference::InitializeMathExpData(); + } + + LOperand* value() { return inputs_[0]; } + LOperand* temp1() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + LOperand* double_temp() { return temps_[2]; } + + DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp") + + virtual void PrintDataTo(StringStream* stream); +}; + + class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { public: LCmpObjectEqAndBranch(LOperand* left, LOperand* right) { @@ -647,6 +714,9 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareObjectEqAndBranch) @@ -659,6 +729,8 @@ class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> { inputs_[0] = left; } + LOperand* left() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch, "cmp-constant-eq-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareConstantEqAndBranch) @@ -671,6 +743,8 @@ class LIsNilAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch) @@ -688,6 +762,9 @@ class LIsObjectAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch) @@ -702,6 +779,9 @@ class LIsStringAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch) @@ -715,6 +795,8 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch) @@ -729,6 +811,9 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, "is-undetectable-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch) @@ -744,6 +829,9 @@ class LStringCompareAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch, "string-compare-and-branch") DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch) @@ -760,6 +848,8 @@ class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch, "has-instance-type-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch) @@ -774,6 +864,8 @@ class LGetCachedArrayIndex: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex, "get-cached-array-index") DECLARE_HYDROGEN_ACCESSOR(GetCachedArrayIndex) }; @@ -785,6 +877,8 @@ class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch, "has-cached-array-index-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch) @@ -800,6 +894,9 @@ class LClassOfTestAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch") DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) @@ -815,6 +912,9 @@ class LCmpT: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t") DECLARE_HYDROGEN_ACCESSOR(CompareGeneric) @@ -829,6 +929,9 @@ class LInstanceOf: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of") }; @@ -840,6 +943,9 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal, "instance-of-known-global") DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) @@ -879,6 +985,9 @@ class LBitI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + Token::Value op() const { return hydrogen()->op(); } DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i") @@ -895,7 +1004,8 @@ class LShiftI: public LTemplateInstruction<1, 2, 0> { } Token::Value op() const { return op_; } - + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } bool can_deopt() const { return can_deopt_; } DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i") @@ -913,11 +1023,29 @@ class LSubI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i") DECLARE_HYDROGEN_ACCESSOR(Sub) }; +class LRSubI: public LTemplateInstruction<1, 2, 0> { + public: + LRSubI(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } + + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(RSubI, "rsub-i") + DECLARE_HYDROGEN_ACCESSOR(Sub) +}; + + class LConstantI: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ConstantI, "constant-i") @@ -951,6 +1079,8 @@ class LBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_HYDROGEN_ACCESSOR(Branch) @@ -965,6 +1095,9 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareMap) @@ -986,6 +1119,8 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) }; @@ -997,6 +1132,8 @@ class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength, "fixed-array-base-length") DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength) @@ -1009,6 +1146,8 @@ class LMapEnumLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MapEnumLength, "map-enum-length") }; @@ -1019,6 +1158,8 @@ class LElementsKind: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind") DECLARE_HYDROGEN_ACCESSOR(ElementsKind) }; @@ -1031,6 +1172,9 @@ class LValueOf: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value-of") DECLARE_HYDROGEN_ACCESSOR(ValueOf) }; @@ -1043,31 +1187,39 @@ class LDateField: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* date() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + Smi* index() const { return index_; } + DECLARE_CONCRETE_INSTRUCTION(ValueOf, "date-field") DECLARE_HYDROGEN_ACCESSOR(ValueOf) - Smi* index() const { return index_; } private: Smi* index_; }; -class LSetDateField: public LTemplateInstruction<1, 2, 1> { +class LSeqStringSetChar: public LTemplateInstruction<1, 3, 0> { public: - LSetDateField(LOperand* date, LOperand* value, LOperand* temp, int index) - : index_(index) { - inputs_[0] = date; - inputs_[1] = value; - temps_[0] = temp; + LSeqStringSetChar(String::Encoding encoding, + LOperand* string, + LOperand* index, + LOperand* value) : encoding_(encoding) { + inputs_[0] = string; + inputs_[1] = index; + inputs_[2] = value; } - DECLARE_CONCRETE_INSTRUCTION(DateField, "date-set-field") - DECLARE_HYDROGEN_ACCESSOR(DateField) + String::Encoding encoding() { return encoding_; } + LOperand* string() { return inputs_[0]; } + LOperand* index() { return inputs_[1]; } + LOperand* value() { return inputs_[2]; } - int index() const { return index_; } + DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char") + DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar) private: - int index_; + String::Encoding encoding_; }; @@ -1077,6 +1229,8 @@ class LThrow: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Throw, "throw") }; @@ -1087,6 +1241,8 @@ class LBitNotI: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") }; @@ -1098,6 +1254,9 @@ class LAddI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i") DECLARE_HYDROGEN_ACCESSOR(Add) }; @@ -1110,6 +1269,9 @@ class LMathMinMax: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max") DECLARE_HYDROGEN_ACCESSOR(MathMinMax) }; @@ -1122,6 +1284,9 @@ class LPower: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(Power, "power") DECLARE_HYDROGEN_ACCESSOR(Power) }; @@ -1133,6 +1298,8 @@ class LRandom: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } + LOperand* global_object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Random, "random") DECLARE_HYDROGEN_ACCESSOR(Random) }; @@ -1147,6 +1314,8 @@ class LArithmeticD: public LTemplateInstruction<1, 2, 0> { } Token::Value op() const { return op_; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } virtual Opcode opcode() const { return LInstruction::kArithmeticD; } virtual void CompileToNative(LCodeGen* generator); @@ -1165,12 +1334,14 @@ class LArithmeticT: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + Token::Value op() const { return op_; } + virtual Opcode opcode() const { return LInstruction::kArithmeticT; } virtual void CompileToNative(LCodeGen* generator); virtual const char* Mnemonic() const; - Token::Value op() const { return op_; } - private: Token::Value op_; }; @@ -1182,6 +1353,8 @@ class LReturn: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Return, "return") }; @@ -1192,6 +1365,8 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field") DECLARE_HYDROGEN_ACCESSOR(LoadNamedField) }; @@ -1203,10 +1378,10 @@ class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic) - - LOperand* object() { return inputs_[0]; } }; @@ -1216,10 +1391,11 @@ class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric) - LOperand* object() { return inputs_[0]; } Handle<Object> name() const { return hydrogen()->name(); } }; @@ -1230,10 +1406,10 @@ class LLoadFunctionPrototype: public LTemplateInstruction<1, 1, 0> { inputs_[0] = function; } + LOperand* function() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype") DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype) - - LOperand* function() { return inputs_[0]; } }; @@ -1243,6 +1419,8 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements") }; @@ -1253,75 +1431,48 @@ class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer, "load-external-array-pointer") }; -class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { +class LLoadKeyed: public LTemplateInstruction<1, 2, 0> { public: - LLoadKeyedFastElement(LOperand* elements, LOperand* key) { + LLoadKeyed(LOperand* elements, LOperand* key) { inputs_[0] = elements; inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement) - LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - -class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> { - public: - LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) { - inputs_[0] = elements; - inputs_[1] = key; + ElementsKind elements_kind() const { + return hydrogen()->elements_kind(); } - - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement, - "load-keyed-fast-double-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement) - - LOperand* elements() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - -class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> { - public: - LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) { - inputs_[0] = external_pointer; - inputs_[1] = key; + bool is_external() const { + return hydrogen()->is_external(); } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement, - "load-keyed-specialized-array-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement) + DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") + DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) - LOperand* external_pointer() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - ElementsKind elements_kind() const { - return hydrogen()->elements_kind(); - } + virtual void PrintDataTo(StringStream* stream); uint32_t additional_index() const { return hydrogen()->index_offset(); } }; class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> { public: - LLoadKeyedGeneric(LOperand* obj, LOperand* key) { - inputs_[0] = obj; + LLoadKeyedGeneric(LOperand* object, LOperand* key) { + inputs_[0] = object; inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") - LOperand* object() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") }; @@ -1338,10 +1489,11 @@ class LLoadGlobalGeneric: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } + LOperand* global_object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic") DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric) - LOperand* global_object() { return inputs_[0]; } Handle<Object> name() const { return hydrogen()->name(); } bool for_typeof() const { return hydrogen()->for_typeof(); } }; @@ -1354,10 +1506,11 @@ class LStoreGlobalCell: public LTemplateInstruction<0, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell, "store-global-cell") DECLARE_HYDROGEN_ACCESSOR(StoreGlobalCell) - - LOperand* value() { return inputs_[0]; } }; @@ -1369,12 +1522,13 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> { inputs_[1] = value; } + LOperand* global_object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic") DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric) - LOperand* global_object() { return InputAt(0); } Handle<Object> name() const { return hydrogen()->name(); } - LOperand* value() { return InputAt(1); } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; @@ -1385,10 +1539,11 @@ class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } + LOperand* context() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot") DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot) - LOperand* context() { return InputAt(0); } int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); @@ -1402,11 +1557,12 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 0> { inputs_[1] = value; } + LOperand* context() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot") DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot) - LOperand* context() { return InputAt(0); } - LOperand* value() { return InputAt(1); } int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); @@ -1419,6 +1575,8 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument") }; @@ -1455,9 +1613,9 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } - DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context") + LOperand* context() { return inputs_[0]; } - LOperand* context() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context") }; @@ -1476,7 +1634,7 @@ class LGlobalObject: public LTemplateInstruction<1, 1, 0> { DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") - LOperand* context() { return InputAt(0); } + LOperand* context() { return inputs_[0]; } }; @@ -1486,9 +1644,9 @@ class LGlobalReceiver: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } - DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver") + LOperand* global_object() { return inputs_[0]; } - LOperand* global() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver") }; @@ -1510,11 +1668,11 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> { inputs_[0] = function; } + LOperand* function() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function") DECLARE_HYDROGEN_ACCESSOR(InvokeFunction) - LOperand* function() { return inputs_[0]; } - virtual void PrintDataTo(StringStream* stream); int arity() const { return hydrogen()->argument_count() - 1; } @@ -1528,6 +1686,8 @@ class LCallKeyed: public LTemplateInstruction<1, 1, 0> { inputs_[0] = key; } + LOperand* key() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed") DECLARE_HYDROGEN_ACCESSOR(CallKeyed) @@ -1556,10 +1716,11 @@ class LCallFunction: public LTemplateInstruction<1, 1, 0> { inputs_[0] = function; } + LOperand* function() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function") DECLARE_HYDROGEN_ACCESSOR(CallFunction) - LOperand* function() { return inputs_[0]; } int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -1594,6 +1755,8 @@ class LCallNew: public LTemplateInstruction<1, 1, 0> { inputs_[0] = constructor; } + LOperand* constructor() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new") DECLARE_HYDROGEN_ACCESSOR(CallNew) @@ -1619,6 +1782,8 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double") }; @@ -1629,6 +1794,8 @@ class LUint32ToDouble: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double") }; @@ -1639,6 +1806,8 @@ class LNumberTagI: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i") }; @@ -1649,18 +1818,24 @@ class LNumberTagU: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u") }; class LNumberTagD: public LTemplateInstruction<1, 1, 2> { public: - LNumberTagD(LOperand* value, LOperand* temp1, LOperand* temp2) { + LNumberTagD(LOperand* value, LOperand* temp, LOperand* temp2) { inputs_[0] = value; - temps_[0] = temp1; + temps_[0] = temp; temps_[1] = temp2; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d") }; @@ -1668,12 +1843,16 @@ class LNumberTagD: public LTemplateInstruction<1, 1, 2> { // Sometimes truncating conversion from a tagged value to an int32. class LDoubleToI: public LTemplateInstruction<1, 1, 2> { public: - LDoubleToI(LOperand* value, LOperand* temp1, LOperand* temp2) { + LDoubleToI(LOperand* value, LOperand* temp, LOperand* temp2) { inputs_[0] = value; - temps_[0] = temp1; + temps_[0] = temp; temps_[1] = temp2; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -1685,15 +1864,20 @@ class LDoubleToI: public LTemplateInstruction<1, 1, 2> { class LTaggedToI: public LTemplateInstruction<1, 1, 3> { public: LTaggedToI(LOperand* value, - LOperand* temp1, + LOperand* temp, LOperand* temp2, LOperand* temp3) { inputs_[0] = value; - temps_[0] = temp1; + temps_[0] = temp; temps_[1] = temp2; temps_[2] = temp3; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + LOperand* temp3() { return temps_[2]; } + DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -1707,6 +1891,8 @@ class LSmiTag: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag") }; @@ -1717,6 +1903,8 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag") DECLARE_HYDROGEN_ACCESSOR(Change) }; @@ -1729,10 +1917,11 @@ class LSmiUntag: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } - DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag") - + LOperand* value() { return inputs_[0]; } bool needs_check() const { return needs_check_; } + DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag") + private: bool needs_check_; }; @@ -1740,20 +1929,21 @@ class LSmiUntag: public LTemplateInstruction<1, 1, 0> { class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { public: - LStoreNamedField(LOperand* obj, LOperand* val, LOperand* temp) { - inputs_[0] = obj; - inputs_[1] = val; + LStoreNamedField(LOperand* object, LOperand* value, LOperand* temp) { + inputs_[0] = object; + inputs_[1] = value; temps_[0] = temp; } + LOperand* object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field") DECLARE_HYDROGEN_ACCESSOR(StoreNamedField) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* value() { return inputs_[1]; } - Handle<Object> name() const { return hydrogen()->name(); } bool is_in_object() { return hydrogen()->is_in_object(); } int offset() { return hydrogen()->offset(); } @@ -1763,109 +1953,67 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> { public: - LStoreNamedGeneric(LOperand* obj, LOperand* val) { - inputs_[0] = obj; - inputs_[1] = val; + LStoreNamedGeneric(LOperand* object, LOperand* value) { + inputs_[0] = object; + inputs_[1] = value; } + LOperand* object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic") DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* value() { return inputs_[1]; } Handle<Object> name() const { return hydrogen()->name(); } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; -class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> { +class LStoreKeyed: public LTemplateInstruction<0, 3, 0> { public: - LStoreKeyedFastElement(LOperand* obj, LOperand* key, LOperand* val) { - inputs_[0] = obj; + LStoreKeyed(LOperand* object, LOperand* key, LOperand* value) { + inputs_[0] = object; inputs_[1] = key; - inputs_[2] = val; + inputs_[2] = value; } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement, - "store-keyed-fast-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement) - - virtual void PrintDataTo(StringStream* stream); - - LOperand* object() { return inputs_[0]; } + bool is_external() const { return hydrogen()->is_external(); } + LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - -class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> { - public: - LStoreKeyedFastDoubleElement(LOperand* elements, - LOperand* key, - LOperand* val) { - inputs_[0] = elements; - inputs_[1] = key; - inputs_[2] = val; + ElementsKind elements_kind() const { + return hydrogen()->elements_kind(); } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement, - "store-keyed-fast-double-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement) + DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed") + DECLARE_HYDROGEN_ACCESSOR(StoreKeyed) virtual void PrintDataTo(StringStream* stream); - - LOperand* elements() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } - bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } + uint32_t additional_index() const { return hydrogen()->index_offset(); } }; class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { public: - LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val) { + LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* value) { inputs_[0] = obj; inputs_[1] = key; - inputs_[2] = val; + inputs_[2] = value; } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric) - - virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } - StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } -}; -class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> { - public: - LStoreKeyedSpecializedArrayElement(LOperand* external_pointer, - LOperand* key, - LOperand* val) { - inputs_[0] = external_pointer; - inputs_[1] = key; - inputs_[2] = val; - } + DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic") + DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric) - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement, - "store-keyed-specialized-array-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement) + virtual void PrintDataTo(StringStream* stream); - LOperand* external_pointer() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } - ElementsKind elements_kind() const { - return hydrogen()->elements_kind(); - } - uint32_t additional_index() const { return hydrogen()->index_offset(); } + StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; @@ -1873,21 +2021,22 @@ class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> { public: LTransitionElementsKind(LOperand* object, LOperand* new_map_temp, - LOperand* temp_reg) { + LOperand* temp) { inputs_[0] = object; temps_[0] = new_map_temp; - temps_[1] = temp_reg; + temps_[1] = temp; } + LOperand* object() { return inputs_[0]; } + LOperand* new_map_temp() { return temps_[0]; } + LOperand* temp() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind, "transition-elements-kind") DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* new_map_reg() { return temps_[0]; } - LOperand* temp_reg() { return temps_[1]; } Handle<Map> original_map() { return hydrogen()->original_map(); } Handle<Map> transitioned_map() { return hydrogen()->transitioned_map(); } }; @@ -1900,11 +2049,11 @@ class LStringAdd: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } - DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add") - DECLARE_HYDROGEN_ACCESSOR(StringAdd) - LOperand* left() { return inputs_[0]; } LOperand* right() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add") + DECLARE_HYDROGEN_ACCESSOR(StringAdd) }; @@ -1916,11 +2065,11 @@ class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> { inputs_[1] = index; } - DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at") - DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt) - LOperand* string() { return inputs_[0]; } LOperand* index() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at") + DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt) }; @@ -1930,10 +2079,10 @@ class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> { inputs_[0] = char_code; } + LOperand* char_code() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code") DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode) - - LOperand* char_code() { return inputs_[0]; } }; @@ -1943,10 +2092,10 @@ class LStringLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = string; } + LOperand* string() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length") DECLARE_HYDROGEN_ACCESSOR(StringLength) - - LOperand* string() { return inputs_[0]; } }; @@ -1956,7 +2105,7 @@ class LCheckFunction: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } - LOperand* value() { return InputAt(0); } + LOperand* value() { return inputs_[0]; } DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") DECLARE_HYDROGEN_ACCESSOR(CheckFunction) @@ -1969,6 +2118,8 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type") DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType) }; @@ -1980,18 +2131,23 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps") DECLARE_HYDROGEN_ACCESSOR(CheckMaps) }; -class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> { +class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 2> { public: - LCheckPrototypeMaps(LOperand* temp1, LOperand* temp2) { - temps_[0] = temp1; + LCheckPrototypeMaps(LOperand* temp, LOperand* temp2) { + temps_[0] = temp; temps_[1] = temp2; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) @@ -2006,6 +2162,8 @@ class LCheckSmi: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi") }; @@ -2016,18 +2174,21 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi") }; class LClampDToUint8: public LTemplateInstruction<1, 1, 1> { public: - LClampDToUint8(LOperand* value, LOperand* temp) { - inputs_[0] = value; + LClampDToUint8(LOperand* unclamped, LOperand* temp) { + inputs_[0] = unclamped; temps_[0] = temp; } LOperand* unclamped() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(ClampDToUint8, "clamp-d-to-uint8") }; @@ -2035,8 +2196,8 @@ class LClampDToUint8: public LTemplateInstruction<1, 1, 1> { class LClampIToUint8: public LTemplateInstruction<1, 1, 0> { public: - explicit LClampIToUint8(LOperand* value) { - inputs_[0] = value; + explicit LClampIToUint8(LOperand* unclamped) { + inputs_[0] = unclamped; } LOperand* unclamped() { return inputs_[0]; } @@ -2047,12 +2208,13 @@ class LClampIToUint8: public LTemplateInstruction<1, 1, 0> { class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { public: - LClampTToUint8(LOperand* value, LOperand* temp) { - inputs_[0] = value; + LClampTToUint8(LOperand* unclamped, LOperand* temp) { + inputs_[0] = unclamped; temps_[0] = temp; } LOperand* unclamped() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8, "clamp-t-to-uint8") }; @@ -2060,11 +2222,14 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { class LAllocateObject: public LTemplateInstruction<1, 0, 2> { public: - LAllocateObject(LOperand* temp1, LOperand* temp2) { - temps_[0] = temp1; + LAllocateObject(LOperand* temp, LOperand* temp2) { + temps_[0] = temp; temps_[1] = temp2; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object") DECLARE_HYDROGEN_ACCESSOR(AllocateObject) }; @@ -2113,6 +2278,8 @@ class LToFastProperties: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties") DECLARE_HYDROGEN_ACCESSOR(ToFastProperties) }; @@ -2124,6 +2291,8 @@ class LTypeof: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof") }; @@ -2134,6 +2303,8 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch") DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch) @@ -2149,6 +2320,8 @@ class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { temps_[0] = temp; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch, "is-construct-call-and-branch") }; @@ -2156,15 +2329,15 @@ class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { class LDeleteProperty: public LTemplateInstruction<1, 2, 0> { public: - LDeleteProperty(LOperand* obj, LOperand* key) { - inputs_[0] = obj; + LDeleteProperty(LOperand* object, LOperand* key) { + inputs_[0] = object; inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") - LOperand* object() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") }; @@ -2229,15 +2402,13 @@ class LForInPrepareMap: public LTemplateInstruction<1, 1, 0> { }; -class LForInCacheArray: public LTemplateInstruction<1, 1, 1> { +class LForInCacheArray: public LTemplateInstruction<1, 1, 0> { public: - explicit LForInCacheArray(LOperand* map, LOperand* scratch) { + explicit LForInCacheArray(LOperand* map) { inputs_[0] = map; - temps_[0] = scratch; } LOperand* map() { return inputs_[0]; } - LOperand* scratch() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray, "for-in-cache-array") @@ -2311,6 +2482,9 @@ class LChunkBuilder BASE_EMBEDDED { HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) #undef DECLARE_DO + LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend); + LInstruction* DoRSub(HSub* instr); + static bool HasMagicNumberForDivisor(int32_t divisor); static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val); static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val); diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index e9ba5eec72..06b021669b 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -146,8 +146,20 @@ bool LCodeGen::GeneratePrologue() { __ bind(&ok); } - __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); - __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP. + + info()->set_prologue_offset(masm_->pc_offset()); + { + PredictableCodeSizeScope predictible_code_size_scope( + masm_, kNoCodeAgeSequenceLength * Assembler::kInstrSize); + // The following three instructions must remain together and unmodified + // for code aging to work properly. + __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); + // Load undefined value here, so the value is ready for the loop + // below. + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); + // Adjust FP to point to saved FP. + __ add(fp, sp, Operand(2 * kPointerSize)); + } // Reserve space for the stack slots needed by the code. int slots = GetStackSlotCount(); @@ -222,7 +234,30 @@ bool LCodeGen::GenerateBody() { } if (emit_instructions) { - Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); + if (FLAG_code_comments) { + HValue* hydrogen = instr->hydrogen_value(); + if (hydrogen != NULL) { + if (hydrogen->IsChange()) { + HValue* changed_value = HChange::cast(hydrogen)->value(); + int use_id = 0; + const char* use_mnemo = "dead"; + if (hydrogen->UseCount() >= 1) { + HValue* use_value = hydrogen->uses().value(); + use_id = use_value->id(); + use_mnemo = use_value->Mnemonic(); + } + Comment(";;; @%d: %s. <of #%d %s for #%d %s>", + current_instruction_, instr->Mnemonic(), + changed_value->id(), changed_value->Mnemonic(), + use_id, use_mnemo); + } else { + Comment(";;; @%d: %s. <#%d>", current_instruction_, + instr->Mnemonic(), hydrogen->id()); + } + } else { + Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); + } + } instr->CompileToNative(this); } } @@ -464,7 +499,9 @@ MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const { void LCodeGen::WriteTranslation(LEnvironment* environment, - Translation* translation) { + Translation* translation, + int* arguments_index, + int* arguments_count) { if (environment == NULL) return; // The translation includes one command per value in the environment. @@ -472,7 +509,17 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, // The output frame height does not include the parameters. int height = translation_size - environment->parameter_count(); - WriteTranslation(environment->outer(), translation); + // Function parameters are arguments to the outermost environment. The + // arguments index points to the first element of a sequence of tagged + // values on the stack that represent the arguments. This needs to be + // kept in sync with the LArgumentsElements implementation. + *arguments_index = -environment->parameter_count(); + *arguments_count = environment->parameter_count(); + + WriteTranslation(environment->outer(), + translation, + arguments_index, + arguments_count); int closure_id = *info()->closure() != *environment->closure() ? DefineDeoptimizationLiteral(environment->closure()) : Translation::kSelfLiteralId; @@ -498,6 +545,17 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); break; } + + // Inlined frames which push their arguments cause the index to be + // bumped and a new stack area to be used for materialization. + if (environment->entry() != NULL && + environment->entry()->arguments_pushed()) { + *arguments_index = *arguments_index < 0 + ? GetStackSlotCount() + : *arguments_index + *arguments_count; + *arguments_count = environment->entry()->arguments_count() + 1; + } + for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); // spilled_registers_ and spilled_double_registers_ are either @@ -509,7 +567,9 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, AddToTranslation(translation, environment->spilled_registers()[value->index()], environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } else if ( value->IsDoubleRegister() && environment->spilled_double_registers()[value->index()] != NULL) { @@ -518,14 +578,18 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation, environment->spilled_double_registers()[value->index()], false, - false); + false, + *arguments_index, + *arguments_count); } } AddToTranslation(translation, value, environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } } @@ -533,12 +597,14 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, void LCodeGen::AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32) { + bool is_uint32, + int arguments_index, + int arguments_count) { if (op == NULL) { // TODO(twuerthinger): Introduce marker operands to indicate that this value // is not present and must be reconstructed from the deoptimizer. Currently // this is only used for the arguments object. - translation->StoreArgumentsObject(); + translation->StoreArgumentsObject(arguments_index, arguments_count); } else if (op->IsStackSlot()) { if (is_tagged) { translation->StoreStackSlot(op->index()); @@ -577,22 +643,24 @@ void LCodeGen::AddToTranslation(Translation* translation, void LCodeGen::CallCode(Handle<Code> code, RelocInfo::Mode mode, - LInstruction* instr) { - CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); + LInstruction* instr, + TargetAddressStorageMode storage_mode) { + CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, storage_mode); } void LCodeGen::CallCodeGeneric(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr, - SafepointMode safepoint_mode) { + SafepointMode safepoint_mode, + TargetAddressStorageMode storage_mode) { ASSERT(instr != NULL); // Block literal pool emission to ensure nop indicating no inlined smi code // is in the correct position. Assembler::BlockConstPoolScope block_const_pool(masm()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); - __ Call(code, mode); + __ Call(code, mode, TypeFeedbackId::None(), al, storage_mode); RecordSafepointWithLazyDeopt(instr, safepoint_mode); // Signal that we don't inline smi code before these stubs in the @@ -644,15 +712,16 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, int frame_count = 0; int jsframe_count = 0; + int args_index = 0; + int args_count = 0; for (LEnvironment* e = environment; e != NULL; e = e->outer()) { ++frame_count; if (e->frame_type() == JS_FUNCTION) { ++jsframe_count; } } - Translation translation(&translations_, frame_count, jsframe_count, - zone()); - WriteTranslation(environment, &translation); + Translation translation(&translations_, frame_count, jsframe_count, zone()); + WriteTranslation(environment, &translation, &args_index, &args_count); int deoptimization_index = deoptimizations_.length(); int pc_offset = masm()->pc_offset(); environment->Register(deoptimization_index, @@ -919,7 +988,7 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { void LCodeGen::DoModI(LModI* instr) { if (instr->hydrogen()->HasPowerOf2Divisor()) { - Register dividend = ToRegister(instr->InputAt(0)); + Register dividend = ToRegister(instr->left()); Register result = ToRegister(instr->result()); int32_t divisor = @@ -944,112 +1013,135 @@ void LCodeGen::DoModI(LModI* instr) { } // These registers hold untagged 32 bit values. - Register left = ToRegister(instr->InputAt(0)); - Register right = ToRegister(instr->InputAt(1)); + Register left = ToRegister(instr->left()); + Register right = ToRegister(instr->right()); Register result = ToRegister(instr->result()); + Label done; - Register scratch = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); - DwVfpRegister dividend = ToDoubleRegister(instr->TempAt(1)); - DwVfpRegister divisor = ToDoubleRegister(instr->TempAt(2)); - DwVfpRegister quotient = double_scratch0(); - - ASSERT(!dividend.is(divisor)); - ASSERT(!dividend.is(quotient)); - ASSERT(!divisor.is(quotient)); - ASSERT(!scratch.is(left)); - ASSERT(!scratch.is(right)); - ASSERT(!scratch.is(result)); + if (CpuFeatures::IsSupported(SUDIV)) { + CpuFeatures::Scope scope(SUDIV); + // Check for x % 0. + if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { + __ cmp(right, Operand(0)); + DeoptimizeIf(eq, instr->environment()); + } - Label done, vfp_modulo, both_positive, right_negative; + // For r3 = r1 % r2; we can have the following ARM code + // sdiv r3, r1, r2 + // mls r3, r3, r2, r1 - // Check for x % 0. - if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { - __ cmp(right, Operand(0)); - DeoptimizeIf(eq, instr->environment()); - } + __ sdiv(result, left, right); + __ mls(result, result, right, left); + __ cmp(result, Operand(0)); + __ b(ne, &done); - __ Move(result, left); + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { + __ cmp(left, Operand(0)); + DeoptimizeIf(lt, instr->environment()); + } + } else { + Register scratch = scratch0(); + Register scratch2 = ToRegister(instr->temp()); + DwVfpRegister dividend = ToDoubleRegister(instr->temp2()); + DwVfpRegister divisor = ToDoubleRegister(instr->temp3()); + DwVfpRegister quotient = double_scratch0(); + + ASSERT(!dividend.is(divisor)); + ASSERT(!dividend.is(quotient)); + ASSERT(!divisor.is(quotient)); + ASSERT(!scratch.is(left)); + ASSERT(!scratch.is(right)); + ASSERT(!scratch.is(result)); + + Label vfp_modulo, both_positive, right_negative; + + // Check for x % 0. + if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { + __ cmp(right, Operand(0)); + DeoptimizeIf(eq, instr->environment()); + } - // (0 % x) must yield 0 (if x is finite, which is the case here). - __ cmp(left, Operand(0)); - __ b(eq, &done); - // Preload right in a vfp register. - __ vmov(divisor.low(), right); - __ b(lt, &vfp_modulo); + __ Move(result, left); - __ cmp(left, Operand(right)); - __ b(lt, &done); - - // Check for (positive) power of two on the right hand side. - __ JumpIfNotPowerOfTwoOrZeroAndNeg(right, - scratch, - &right_negative, - &both_positive); - // Perform modulo operation (scratch contains right - 1). - __ and_(result, scratch, Operand(left)); - __ b(&done); + // (0 % x) must yield 0 (if x is finite, which is the case here). + __ cmp(left, Operand(0)); + __ b(eq, &done); + // Preload right in a vfp register. + __ vmov(divisor.low(), right); + __ b(lt, &vfp_modulo); - __ bind(&right_negative); - // Negate right. The sign of the divisor does not matter. - __ rsb(right, right, Operand(0)); - - __ bind(&both_positive); - const int kUnfolds = 3; - // If the right hand side is smaller than the (nonnegative) - // left hand side, the left hand side is the result. - // Else try a few subtractions of the left hand side. - __ mov(scratch, left); - for (int i = 0; i < kUnfolds; i++) { - // Check if the left hand side is less or equal than the - // the right hand side. - __ cmp(scratch, Operand(right)); - __ mov(result, scratch, LeaveCC, lt); + __ cmp(left, Operand(right)); __ b(lt, &done); - // If not, reduce the left hand side by the right hand - // side and check again. - if (i < kUnfolds - 1) __ sub(scratch, scratch, right); - } - - __ bind(&vfp_modulo); - // Load the arguments in VFP registers. - // The divisor value is preloaded before. Be careful that 'right' is only live - // on entry. - __ vmov(dividend.low(), left); - // From here on don't use right as it may have been reallocated (for example - // to scratch2). - right = no_reg; - - __ vcvt_f64_s32(dividend, dividend.low()); - __ vcvt_f64_s32(divisor, divisor.low()); - - // We do not care about the sign of the divisor. - __ vabs(divisor, divisor); - // Compute the quotient and round it to a 32bit integer. - __ vdiv(quotient, dividend, divisor); - __ vcvt_s32_f64(quotient.low(), quotient); - __ vcvt_f64_s32(quotient, quotient.low()); - - // Compute the remainder in result. - DwVfpRegister double_scratch = dividend; - __ vmul(double_scratch, divisor, quotient); - __ vcvt_s32_f64(double_scratch.low(), double_scratch); - __ vmov(scratch, double_scratch.low()); - - if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { - __ sub(result, left, scratch); - } else { - Label ok; - // Check for -0. - __ sub(scratch2, left, scratch, SetCC); - __ b(ne, &ok); - __ cmp(left, Operand(0)); - DeoptimizeIf(mi, instr->environment()); - __ bind(&ok); - // Load the result and we are done. - __ mov(result, scratch2); - } + // Check for (positive) power of two on the right hand side. + __ JumpIfNotPowerOfTwoOrZeroAndNeg(right, + scratch, + &right_negative, + &both_positive); + // Perform modulo operation (scratch contains right - 1). + __ and_(result, scratch, Operand(left)); + __ b(&done); + + __ bind(&right_negative); + // Negate right. The sign of the divisor does not matter. + __ rsb(right, right, Operand(0)); + + __ bind(&both_positive); + const int kUnfolds = 3; + // If the right hand side is smaller than the (nonnegative) + // left hand side, the left hand side is the result. + // Else try a few subtractions of the left hand side. + __ mov(scratch, left); + for (int i = 0; i < kUnfolds; i++) { + // Check if the left hand side is less or equal than the + // the right hand side. + __ cmp(scratch, Operand(right)); + __ mov(result, scratch, LeaveCC, lt); + __ b(lt, &done); + // If not, reduce the left hand side by the right hand + // side and check again. + if (i < kUnfolds - 1) __ sub(scratch, scratch, right); + } + + __ bind(&vfp_modulo); + // Load the arguments in VFP registers. + // The divisor value is preloaded before. Be careful that 'right' + // is only live on entry. + __ vmov(dividend.low(), left); + // From here on don't use right as it may have been reallocated + // (for example to scratch2). + right = no_reg; + + __ vcvt_f64_s32(dividend, dividend.low()); + __ vcvt_f64_s32(divisor, divisor.low()); + + // We do not care about the sign of the divisor. + __ vabs(divisor, divisor); + // Compute the quotient and round it to a 32bit integer. + __ vdiv(quotient, dividend, divisor); + __ vcvt_s32_f64(quotient.low(), quotient); + __ vcvt_f64_s32(quotient, quotient.low()); + + // Compute the remainder in result. + DwVfpRegister double_scratch = dividend; + __ vmul(double_scratch, divisor, quotient); + __ vcvt_s32_f64(double_scratch.low(), double_scratch); + __ vmov(scratch, double_scratch.low()); + + if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { + __ sub(result, left, scratch); + } else { + Label ok; + // Check for -0. + __ sub(scratch2, left, scratch, SetCC); + __ b(ne, &ok); + __ cmp(left, Operand(0)); + DeoptimizeIf(mi, instr->environment()); + __ bind(&ok); + // Load the result and we are done. + __ mov(result, scratch2); + } + } __ bind(&done); } @@ -1154,15 +1246,18 @@ void LCodeGen::DoDivI(LDivI* instr) { DeferredDivI(LCodeGen* codegen, LDivI* instr) : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { - codegen()->DoDeferredBinaryOpStub(instr_, Token::DIV); + codegen()->DoDeferredBinaryOpStub(instr_->pointer_map(), + instr_->left(), + instr_->right(), + Token::DIV); } virtual LInstruction* instr() { return instr_; } private: LDivI* instr_; }; - const Register left = ToRegister(instr->InputAt(0)); - const Register right = ToRegister(instr->InputAt(1)); + const Register left = ToRegister(instr->left()); + const Register right = ToRegister(instr->right()); const Register scratch = scratch0(); const Register result = ToRegister(instr->result()); @@ -1229,17 +1324,29 @@ void LCodeGen::DoDivI(LDivI* instr) { } +void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) { + DwVfpRegister addend = ToDoubleRegister(instr->addend()); + DwVfpRegister multiplier = ToDoubleRegister(instr->multiplier()); + DwVfpRegister multiplicand = ToDoubleRegister(instr->multiplicand()); + + // This is computed in-place. + ASSERT(addend.is(ToDoubleRegister(instr->result()))); + + __ vmla(addend, multiplier, multiplicand); +} + + 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 left = ToRegister(instr->left()); + const Register remainder = ToRegister(instr->temp()); 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))); + ASSERT(instr->right()->IsConstantOperand()); + int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); if (divisor < 0) { __ cmp(left, Operand(0)); DeoptimizeIf(eq, instr->environment()); @@ -1257,11 +1364,12 @@ void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { } -template<int T> -void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, +void LCodeGen::DoDeferredBinaryOpStub(LPointerMap* pointer_map, + LOperand* left_argument, + LOperand* right_argument, Token::Value op) { - Register left = ToRegister(instr->InputAt(0)); - Register right = ToRegister(instr->InputAt(1)); + Register left = ToRegister(left_argument); + Register right = ToRegister(right_argument); PushSafepointRegistersScope scope(this, Safepoint::kWithRegistersAndDoubles); // Move left to r1 and right to r0 for the stub call. @@ -1280,7 +1388,7 @@ void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, } BinaryOpStub stub(op, OVERWRITE_LEFT); __ CallStub(&stub); - RecordSafepointWithRegistersAndDoubles(instr->pointer_map(), + RecordSafepointWithRegistersAndDoubles(pointer_map, 0, Safepoint::kNoLazyDeopt); // Overwrite the stored value of r0 with the result of the stub. @@ -1292,8 +1400,8 @@ void LCodeGen::DoMulI(LMulI* instr) { Register scratch = scratch0(); Register result = ToRegister(instr->result()); // Note that result may alias left. - Register left = ToRegister(instr->InputAt(0)); - LOperand* right_op = instr->InputAt(1); + Register left = ToRegister(instr->left()); + LOperand* right_op = instr->right(); bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); bool bailout_on_minus_zero = @@ -1360,7 +1468,7 @@ void LCodeGen::DoMulI(LMulI* instr) { } else { Register right = EmitLoadRegister(right_op, scratch); if (bailout_on_minus_zero) { - __ orr(ToRegister(instr->TempAt(0)), left, right); + __ orr(ToRegister(instr->temp()), left, right); } if (can_overflow) { @@ -1377,7 +1485,7 @@ void LCodeGen::DoMulI(LMulI* instr) { Label done; __ cmp(result, Operand(0)); __ b(ne, &done); - __ cmp(ToRegister(instr->TempAt(0)), Operand(0)); + __ cmp(ToRegister(instr->temp()), Operand(0)); DeoptimizeIf(mi, instr->environment()); __ bind(&done); } @@ -1386,8 +1494,8 @@ void LCodeGen::DoMulI(LMulI* instr) { void LCodeGen::DoBitI(LBitI* instr) { - LOperand* left_op = instr->InputAt(0); - LOperand* right_op = instr->InputAt(1); + LOperand* left_op = instr->left(); + LOperand* right_op = instr->right(); ASSERT(left_op->IsRegister()); Register left = ToRegister(left_op); Register result = ToRegister(instr->result()); @@ -1420,14 +1528,17 @@ void LCodeGen::DoBitI(LBitI* instr) { void LCodeGen::DoShiftI(LShiftI* instr) { // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so // result may alias either of them. - LOperand* right_op = instr->InputAt(1); - Register left = ToRegister(instr->InputAt(0)); + LOperand* right_op = instr->right(); + Register left = ToRegister(instr->left()); Register result = ToRegister(instr->result()); Register scratch = scratch0(); if (right_op->IsRegister()) { // Mask the right_op operand. __ and_(scratch, ToRegister(right_op), Operand(0x1F)); switch (instr->op()) { + case Token::ROR: + __ mov(result, Operand(left, ROR, scratch)); + break; case Token::SAR: __ mov(result, Operand(left, ASR, scratch)); break; @@ -1451,6 +1562,13 @@ void LCodeGen::DoShiftI(LShiftI* instr) { int value = ToInteger32(LConstantOperand::cast(right_op)); uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); switch (instr->op()) { + case Token::ROR: + if (shift_count != 0) { + __ mov(result, Operand(left, ROR, shift_count)); + } else { + __ Move(result, left); + } + break; case Token::SAR: if (shift_count != 0) { __ mov(result, Operand(left, ASR, shift_count)); @@ -1485,8 +1603,8 @@ void LCodeGen::DoShiftI(LShiftI* instr) { void LCodeGen::DoSubI(LSubI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); LOperand* result = instr->result(); bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); SBit set_cond = can_overflow ? SetCC : LeaveCC; @@ -1505,6 +1623,27 @@ void LCodeGen::DoSubI(LSubI* instr) { } +void LCodeGen::DoRSubI(LRSubI* instr) { + LOperand* left = instr->left(); + LOperand* right = instr->right(); + LOperand* result = instr->result(); + bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); + SBit set_cond = can_overflow ? SetCC : LeaveCC; + + if (right->IsStackSlot() || right->IsArgument()) { + Register right_reg = EmitLoadRegister(right, ip); + __ rsb(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond); + } else { + ASSERT(right->IsRegister() || right->IsConstantOperand()); + __ rsb(ToRegister(result), ToRegister(left), ToOperand(right), set_cond); + } + + if (can_overflow) { + DeoptimizeIf(vs, instr->environment()); + } +} + + void LCodeGen::DoConstantI(LConstantI* instr) { ASSERT(instr->result()->IsRegister()); __ mov(ToRegister(instr->result()), Operand(instr->value())); @@ -1515,7 +1654,7 @@ void LCodeGen::DoConstantD(LConstantD* instr) { ASSERT(instr->result()->IsDoubleRegister()); DwVfpRegister result = ToDoubleRegister(instr->result()); double v = instr->value(); - __ Vmov(result, v); + __ Vmov(result, v, scratch0()); } @@ -1532,28 +1671,28 @@ void LCodeGen::DoConstantT(LConstantT* instr) { void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset)); } void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset)); } void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) { Register result = ToRegister(instr->result()); - Register map = ToRegister(instr->InputAt(0)); + Register map = ToRegister(instr->value()); __ EnumLength(result, map); } void LCodeGen::DoElementsKind(LElementsKind* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); // Load map into |result|. __ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset)); @@ -1566,9 +1705,9 @@ void LCodeGen::DoElementsKind(LElementsKind* instr) { void LCodeGen::DoValueOf(LValueOf* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); - Register map = ToRegister(instr->TempAt(0)); + Register map = ToRegister(instr->temp()); Label done; // If the object is a smi return the object. @@ -1587,9 +1726,9 @@ void LCodeGen::DoValueOf(LValueOf* instr) { void LCodeGen::DoDateField(LDateField* instr) { - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->date()); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); Smi* index = instr->index(); Label runtime, done; ASSERT(object.is(result)); @@ -1625,15 +1764,24 @@ void LCodeGen::DoDateField(LDateField* instr) { } +void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { + SeqStringSetCharGenerator::Generate(masm(), + instr->encoding(), + ToRegister(instr->string()), + ToRegister(instr->index()), + ToRegister(instr->value())); +} + + void LCodeGen::DoBitNotI(LBitNotI* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); __ mvn(result, Operand(input)); } void LCodeGen::DoThrow(LThrow* instr) { - Register input_reg = EmitLoadRegister(instr->InputAt(0), ip); + Register input_reg = EmitLoadRegister(instr->value(), ip); __ push(input_reg); CallRuntime(Runtime::kThrow, 1, instr); @@ -1644,8 +1792,8 @@ void LCodeGen::DoThrow(LThrow* instr) { void LCodeGen::DoAddI(LAddI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); LOperand* result = instr->result(); bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); SBit set_cond = can_overflow ? SetCC : LeaveCC; @@ -1665,8 +1813,8 @@ void LCodeGen::DoAddI(LAddI* instr) { void LCodeGen::DoMathMinMax(LMathMinMax* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); HMathMinMax::Operation operation = instr->hydrogen()->operation(); Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge; if (instr->hydrogen()->representation().IsInteger32()) { @@ -1727,8 +1875,8 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { void LCodeGen::DoArithmeticD(LArithmeticD* instr) { - DoubleRegister left = ToDoubleRegister(instr->InputAt(0)); - DoubleRegister right = ToDoubleRegister(instr->InputAt(1)); + DoubleRegister left = ToDoubleRegister(instr->left()); + DoubleRegister right = ToDoubleRegister(instr->right()); DoubleRegister result = ToDoubleRegister(instr->result()); switch (instr->op()) { case Token::ADD: @@ -1767,8 +1915,8 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { void LCodeGen::DoArithmeticT(LArithmeticT* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(r1)); - ASSERT(ToRegister(instr->InputAt(1)).is(r0)); + ASSERT(ToRegister(instr->left()).is(r1)); + ASSERT(ToRegister(instr->right()).is(r0)); ASSERT(ToRegister(instr->result()).is(r0)); BinaryOpStub stub(instr->op(), NO_OVERWRITE); @@ -1813,11 +1961,11 @@ void LCodeGen::DoBranch(LBranch* instr) { Representation r = instr->hydrogen()->value()->representation(); if (r.IsInteger32()) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); __ cmp(reg, Operand(0)); EmitBranch(true_block, false_block, ne); } else if (r.IsDouble()) { - DoubleRegister reg = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister reg = ToDoubleRegister(instr->value()); Register scratch = scratch0(); // Test the double value. Zero and NaN are false. @@ -1826,7 +1974,7 @@ void LCodeGen::DoBranch(LBranch* instr) { EmitBranch(true_block, false_block, eq); } else { ASSERT(r.IsTagged()); - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); HType type = instr->hydrogen()->value()->type(); if (type.IsBoolean()) { __ CompareRoot(reg, Heap::kTrueValueRootIndex); @@ -1965,8 +2113,8 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); Condition cond = TokenToCondition(instr->op(), false); @@ -2006,8 +2154,8 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); - Register right = ToRegister(instr->InputAt(1)); + Register left = ToRegister(instr->left()); + Register right = ToRegister(instr->right()); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -2017,7 +2165,7 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); + Register left = ToRegister(instr->left()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2028,7 +2176,7 @@ void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { Register scratch = scratch0(); - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); int false_block = chunk_->LookupDestination(instr->false_block_id()); // If the expression is known to be untagged or a smi, then it's definitely @@ -2096,8 +2244,8 @@ Condition LCodeGen::EmitIsObject(Register input, void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp1 = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp1 = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2122,8 +2270,8 @@ Condition LCodeGen::EmitIsString(Register input, void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp1 = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp1 = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2140,15 +2288,15 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); - Register input_reg = EmitLoadRegister(instr->InputAt(0), ip); + Register input_reg = EmitLoadRegister(instr->value(), ip); __ tst(input_reg, Operand(kSmiTagMask)); EmitBranch(true_block, false_block, eq); } void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register input = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2218,7 +2366,7 @@ static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { Register scratch = scratch0(); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2233,10 +2381,10 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); - __ AbortIfNotString(input); + __ AssertString(input); __ ldr(result, FieldMemOperand(input, String::kHashFieldOffset)); __ IndexFromHash(result, result); @@ -2245,7 +2393,7 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { void LCodeGen::DoHasCachedArrayIndexAndBranch( LHasCachedArrayIndexAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register scratch = scratch0(); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -2326,9 +2474,9 @@ void LCodeGen::EmitClassOfTest(Label* is_true, void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register temp = scratch0(); - Register temp2 = ToRegister(instr->TempAt(0)); + Register temp2 = ToRegister(instr->temp()); Handle<String> class_name = instr->hydrogen()->class_name(); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -2344,8 +2492,8 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = instr->true_block_id(); int false_block = instr->false_block_id(); @@ -2356,8 +2504,8 @@ void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { void LCodeGen::DoInstanceOf(LInstanceOf* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(r0)); // Object is in r0. - ASSERT(ToRegister(instr->InputAt(1)).is(r1)); // Function is in r1. + ASSERT(ToRegister(instr->left()).is(r0)); // Object is in r0. + ASSERT(ToRegister(instr->right()).is(r1)); // Function is in r1. InstanceofStub stub(InstanceofStub::kArgsInRegisters); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); @@ -2388,8 +2536,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr); Label done, false_result; - Register object = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register object = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); Register result = ToRegister(instr->result()); ASSERT(object.is(r0)); @@ -2412,6 +2560,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { // We use Factory::the_hole_value() on purpose instead of loading from the // root array to force relocation to be able to later patch with // the cached map. + PredictableCodeSizeScope predictable(masm_, 5 * Assembler::kInstrSize); Handle<JSGlobalPropertyCell> cell = factory()->NewJSGlobalPropertyCell(factory()->the_hole_value()); __ mov(ip, Operand(Handle<Object>(cell))); @@ -2469,10 +2618,13 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, // Get the temp register reserved by the instruction. This needs to be r4 as // its slot of the pushing of safepoint registers is used to communicate the // offset to the location of the map check. - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); ASSERT(temp.is(r4)); __ LoadHeapObject(InstanceofStub::right(), instr->function()); static const int kAdditionalDelta = 5; + // Make sure that code size is predicable, since we use specific constants + // offsets in the code to find embedded values.. + PredictableCodeSizeScope predictable(masm_, 6 * Assembler::kInstrSize); int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta; Label before_push_delta; __ bind(&before_push_delta); @@ -2566,7 +2718,7 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { // it as no longer deleted. if (instr->hydrogen()->RequiresHoleCheck()) { // We use a temp to check the payload (CompareRoot might clobber ip). - Register payload = ToRegister(instr->TempAt(0)); + Register payload = ToRegister(instr->temp()); __ ldr(payload, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset)); __ CompareRoot(payload, Heap::kTheHoleValueRootIndex); DeoptimizeIf(eq, instr->environment()); @@ -2645,7 +2797,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->object()); Register result = ToRegister(instr->result()); if (instr->hydrogen()->is_in_object()) { __ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset())); @@ -2736,7 +2888,7 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { if (need_generic) { __ mov(r2, Operand(name)); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } __ bind(&done); } @@ -2749,7 +2901,7 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { // Name is always in r2. __ mov(r2, Operand(instr->name())); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } @@ -2799,7 +2951,7 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->object()); Register scratch = scratch0(); __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset)); @@ -2834,7 +2986,7 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) { void LCodeGen::DoLoadExternalArrayPointer( LLoadExternalArrayPointer* instr) { Register to_reg = ToRegister(instr->result()); - Register from_reg = ToRegister(instr->InputAt(0)); + Register from_reg = ToRegister(instr->object()); __ ldr(to_reg, FieldMemOperand(from_reg, ExternalArray::kExternalPointerOffset)); } @@ -2845,63 +2997,95 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { Register length = ToRegister(instr->length()); Register index = ToRegister(instr->index()); Register result = ToRegister(instr->result()); - - // Bailout index is not a valid argument index. Use unsigned check to get - // negative check for free. - __ sub(length, length, index, SetCC); - DeoptimizeIf(ls, instr->environment()); - // There are two words between the frame pointer and the last argument. // Subtracting from length accounts for one of them add one more. + __ sub(length, length, index); __ add(length, length, Operand(1)); __ ldr(result, MemOperand(arguments, length, LSL, kPointerSizeLog2)); } -void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { - Register elements = ToRegister(instr->elements()); - Register result = ToRegister(instr->result()); - Register scratch = scratch0(); - Register store_base = scratch; - int offset = 0; - - if (instr->key()->IsConstantOperand()) { - LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); - offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + - instr->additional_index()); - store_base = elements; - } else { - Register key = EmitLoadRegister(instr->key(), scratch0()); - // Even though the HLoadKeyedFastElement instruction forces the input - // representation for the key to be an integer, the input gets replaced - // during bound check elimination with the index argument to the bounds - // check, which can be tagged, so that case must be handled here, too. - if (instr->hydrogen()->key()->representation().IsTagged()) { - __ add(scratch, elements, - Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); - } else { - __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); +void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { + Register external_pointer = ToRegister(instr->elements()); + Register key = no_reg; + ElementsKind elements_kind = instr->elements_kind(); + bool key_is_constant = instr->key()->IsConstantOperand(); + int constant_key = 0; + if (key_is_constant) { + constant_key = ToInteger32(LConstantOperand::cast(instr->key())); + if (constant_key & 0xF0000000) { + Abort("array index constant value too big."); } - offset = FixedArray::OffsetOfElementAt(instr->additional_index()); + } else { + key = ToRegister(instr->key()); } - __ ldr(result, FieldMemOperand(store_base, offset)); + int element_size_shift = ElementsKindToShiftSize(elements_kind); + int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) + ? (element_size_shift - kSmiTagSize) : element_size_shift; + int additional_offset = instr->additional_index() << element_size_shift; - // Check for the hole value. - if (instr->hydrogen()->RequiresHoleCheck()) { - if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { - __ tst(result, Operand(kSmiTagMask)); - DeoptimizeIf(ne, instr->environment()); - } else { - __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); - __ cmp(result, scratch); - DeoptimizeIf(eq, instr->environment()); + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || + elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { + CpuFeatures::Scope scope(VFP3); + DwVfpRegister result = ToDoubleRegister(instr->result()); + Operand operand = key_is_constant + ? Operand(constant_key << element_size_shift) + : Operand(key, LSL, shift_size); + __ add(scratch0(), external_pointer, operand); + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { + __ vldr(result.low(), scratch0(), additional_offset); + __ vcvt_f64_f32(result, result.low()); + } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS + __ vldr(result, scratch0(), additional_offset); + } + } else { + Register result = ToRegister(instr->result()); + MemOperand mem_operand = PrepareKeyedOperand( + key, external_pointer, key_is_constant, constant_key, + element_size_shift, shift_size, + instr->additional_index(), additional_offset); + switch (elements_kind) { + case EXTERNAL_BYTE_ELEMENTS: + __ ldrsb(result, mem_operand); + break; + case EXTERNAL_PIXEL_ELEMENTS: + case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: + __ ldrb(result, mem_operand); + break; + case EXTERNAL_SHORT_ELEMENTS: + __ ldrsh(result, mem_operand); + break; + case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: + __ ldrh(result, mem_operand); + break; + case EXTERNAL_INT_ELEMENTS: + __ ldr(result, mem_operand); + break; + case EXTERNAL_UNSIGNED_INT_ELEMENTS: + __ ldr(result, mem_operand); + if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { + __ cmp(result, Operand(0x80000000)); + DeoptimizeIf(cs, instr->environment()); + } + break; + case EXTERNAL_FLOAT_ELEMENTS: + case EXTERNAL_DOUBLE_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_DOUBLE_ELEMENTS: + case FAST_ELEMENTS: + case FAST_SMI_ELEMENTS: + case DICTIONARY_ELEMENTS: + case NON_STRICT_ARGUMENTS_ELEMENTS: + UNREACHABLE(); + break; } } } -void LCodeGen::DoLoadKeyedFastDoubleElement( - LLoadKeyedFastDoubleElement* instr) { +void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { Register elements = ToRegister(instr->elements()); bool key_is_constant = instr->key()->IsConstantOperand(); Register key = no_reg; @@ -2933,13 +3117,65 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( (instr->additional_index() << element_size_shift))); } + __ vldr(result, elements, 0); if (instr->hydrogen()->RequiresHoleCheck()) { __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); __ cmp(scratch, Operand(kHoleNanUpper32)); DeoptimizeIf(eq, instr->environment()); } +} - __ vldr(result, elements, 0); + +void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { + Register elements = ToRegister(instr->elements()); + Register result = ToRegister(instr->result()); + Register scratch = scratch0(); + Register store_base = scratch; + int offset = 0; + + if (instr->key()->IsConstantOperand()) { + LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); + offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + + instr->additional_index()); + store_base = elements; + } else { + Register key = EmitLoadRegister(instr->key(), scratch0()); + // Even though the HLoadKeyed instruction forces the input + // representation for the key to be an integer, the input gets replaced + // during bound check elimination with the index argument to the bounds + // check, which can be tagged, so that case must be handled here, too. + if (instr->hydrogen()->key()->representation().IsTagged()) { + __ add(scratch, elements, + Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); + } else { + __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); + } + offset = FixedArray::OffsetOfElementAt(instr->additional_index()); + } + __ ldr(result, FieldMemOperand(store_base, offset)); + + // Check for the hole value. + if (instr->hydrogen()->RequiresHoleCheck()) { + if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { + __ tst(result, Operand(kSmiTagMask)); + DeoptimizeIf(ne, instr->environment()); + } else { + __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); + __ cmp(result, scratch); + DeoptimizeIf(eq, instr->environment()); + } + } +} + + +void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { + if (instr->is_external()) { + DoLoadKeyedExternalArray(instr); + } else if (instr->hydrogen()->representation().IsDouble()) { + DoLoadKeyedFixedDoubleArray(instr); + } else { + DoLoadKeyedFixedArray(instr); + } } @@ -2979,93 +3215,12 @@ MemOperand LCodeGen::PrepareKeyedOperand(Register key, } -void LCodeGen::DoLoadKeyedSpecializedArrayElement( - LLoadKeyedSpecializedArrayElement* instr) { - Register external_pointer = ToRegister(instr->external_pointer()); - Register key = no_reg; - ElementsKind elements_kind = instr->elements_kind(); - bool key_is_constant = instr->key()->IsConstantOperand(); - int constant_key = 0; - if (key_is_constant) { - constant_key = ToInteger32(LConstantOperand::cast(instr->key())); - if (constant_key & 0xF0000000) { - Abort("array index constant value too big."); - } - } else { - key = ToRegister(instr->key()); - } - int element_size_shift = ElementsKindToShiftSize(elements_kind); - int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) - ? (element_size_shift - kSmiTagSize) : element_size_shift; - int additional_offset = instr->additional_index() << element_size_shift; - - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || - elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { - CpuFeatures::Scope scope(VFP3); - DwVfpRegister result = ToDoubleRegister(instr->result()); - Operand operand = key_is_constant - ? Operand(constant_key << element_size_shift) - : Operand(key, LSL, shift_size); - __ add(scratch0(), external_pointer, operand); - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { - __ vldr(result.low(), scratch0(), additional_offset); - __ vcvt_f64_f32(result, result.low()); - } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS - __ vldr(result, scratch0(), additional_offset); - } - } else { - Register result = ToRegister(instr->result()); - MemOperand mem_operand = PrepareKeyedOperand( - key, external_pointer, key_is_constant, constant_key, - element_size_shift, shift_size, - instr->additional_index(), additional_offset); - switch (elements_kind) { - case EXTERNAL_BYTE_ELEMENTS: - __ ldrsb(result, mem_operand); - break; - case EXTERNAL_PIXEL_ELEMENTS: - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ ldrb(result, mem_operand); - break; - case EXTERNAL_SHORT_ELEMENTS: - __ ldrsh(result, mem_operand); - break; - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ ldrh(result, mem_operand); - break; - case EXTERNAL_INT_ELEMENTS: - __ ldr(result, mem_operand); - break; - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ ldr(result, mem_operand); - if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { - __ cmp(result, Operand(0x80000000)); - DeoptimizeIf(cs, instr->environment()); - } - break; - case EXTERNAL_FLOAT_ELEMENTS: - case EXTERNAL_DOUBLE_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - case FAST_HOLEY_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_ELEMENTS: - case FAST_SMI_ELEMENTS: - case DICTIONARY_ELEMENTS: - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNREACHABLE(); - break; - } - } -} - - void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(r1)); ASSERT(ToRegister(instr->key()).is(r0)); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } @@ -3091,7 +3246,7 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { - Register elem = ToRegister(instr->InputAt(0)); + Register elem = ToRegister(instr->elements()); Register result = ToRegister(instr->result()); Label done; @@ -3210,7 +3365,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { - LOperand* argument = instr->InputAt(0); + LOperand* argument = instr->value(); if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { Abort("DoPushArgument not implemented for double type."); } else { @@ -3262,7 +3417,7 @@ void LCodeGen::DoGlobalObject(LGlobalObject* instr) { void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { - Register global = ToRegister(instr->global()); + Register global = ToRegister(instr->global_object()); Register result = ToRegister(instr->result()); __ ldr(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset)); } @@ -3322,7 +3477,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); Register scratch = scratch0(); @@ -3388,7 +3543,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); __ cmp(input, Operand(0)); __ Move(result, input, pl); @@ -3418,7 +3573,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { Representation r = instr->hydrogen()->value()->representation(); if (r.IsDouble()) { - DwVfpRegister input = ToDoubleRegister(instr->InputAt(0)); + DwVfpRegister input = ToDoubleRegister(instr->value()); DwVfpRegister result = ToDoubleRegister(instr->result()); __ vabs(result, input); } else if (r.IsInteger32()) { @@ -3427,7 +3582,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { // Representation is tagged. DeferredMathAbsTaggedHeapNumber* deferred = new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); // Smi check. __ JumpIfNotSmi(input, deferred->entry()); // If smi, handle it directly. @@ -3438,29 +3593,24 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); Register result = ToRegister(instr->result()); - SwVfpRegister single_scratch = double_scratch0().low(); - Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); + Register scratch = scratch0(); __ EmitVFPTruncate(kRoundToMinusInf, - single_scratch, + result, input, - scratch1, - scratch2); + scratch, + double_scratch0()); DeoptimizeIf(ne, instr->environment()); - // Move the result back to general purpose register r0. - __ vmov(result, single_scratch); - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { // Test for -0. Label done; __ cmp(result, Operand(0)); __ b(ne, &done); - __ vmov(scratch1, input.high()); - __ tst(scratch1, Operand(HeapNumber::kSignMask)); + __ vmov(scratch, input.high()); + __ tst(scratch, Operand(HeapNumber::kSignMask)); DeoptimizeIf(ne, instr->environment()); __ bind(&done); } @@ -3468,8 +3618,9 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); Register result = ToRegister(instr->result()); + DwVfpRegister double_scratch1 = ToDoubleRegister(instr->temp()); Register scratch = scratch0(); Label done, check_sign_on_zero; @@ -3494,12 +3645,12 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { __ cmp(scratch, Operand(HeapNumber::kExponentBias + 32)); DeoptimizeIf(ge, instr->environment()); + __ Vmov(double_scratch0(), 0.5, scratch); + __ vadd(double_scratch0(), input, double_scratch0()); + // Save the original sign for later comparison. __ and_(scratch, result, Operand(HeapNumber::kSignMask)); - __ Vmov(double_scratch0(), 0.5); - __ vadd(double_scratch0(), input, double_scratch0()); - // Check sign of the result: if the sign changed, the input // value was in ]0.5, 0[ and the result should be -0. __ vmov(result, double_scratch0().high()); @@ -3512,12 +3663,11 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { } __ EmitVFPTruncate(kRoundToMinusInf, - double_scratch0().low(), - double_scratch0(), result, - scratch); + double_scratch0(), + scratch, + double_scratch1); DeoptimizeIf(ne, instr->environment()); - __ vmov(result, double_scratch0().low()); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { // Test for -0. @@ -3533,22 +3683,22 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); DoubleRegister result = ToDoubleRegister(instr->result()); __ vsqrt(result, input); } void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); DoubleRegister result = ToDoubleRegister(instr->result()); - DoubleRegister temp = ToDoubleRegister(instr->TempAt(0)); + DoubleRegister temp = ToDoubleRegister(instr->temp()); // Note that according to ECMA-262 15.8.2.13: // Math.pow(-Infinity, 0.5) == Infinity // Math.sqrt(-Infinity) == NaN Label done; - __ vmov(temp, -V8_INFINITY); + __ vmov(temp, -V8_INFINITY, scratch0()); __ VFPCompareAndSetFlags(input, temp); __ vneg(result, temp, eq); __ b(&done, eq); @@ -3564,11 +3714,11 @@ void LCodeGen::DoPower(LPower* instr) { Representation exponent_type = instr->hydrogen()->right()->representation(); // Having marked this as a call, we can use any registers. // Just make sure that the input/output registers are the expected ones. - ASSERT(!instr->InputAt(1)->IsDoubleRegister() || - ToDoubleRegister(instr->InputAt(1)).is(d2)); - ASSERT(!instr->InputAt(1)->IsRegister() || - ToRegister(instr->InputAt(1)).is(r2)); - ASSERT(ToDoubleRegister(instr->InputAt(0)).is(d1)); + ASSERT(!instr->right()->IsDoubleRegister() || + ToDoubleRegister(instr->right()).is(d2)); + ASSERT(!instr->right()->IsRegister() || + ToRegister(instr->right()).is(r2)); + ASSERT(ToDoubleRegister(instr->left()).is(d1)); ASSERT(ToDoubleRegister(instr->result()).is(d3)); if (exponent_type.IsTagged()) { @@ -3608,7 +3758,7 @@ void LCodeGen::DoRandom(LRandom* instr) { // Having marked this instruction as a call we can use any // registers. ASSERT(ToDoubleRegister(instr->result()).is(d7)); - ASSERT(ToRegister(instr->InputAt(0)).is(r0)); + ASSERT(ToRegister(instr->global_object()).is(r0)); static const int kSeedSize = sizeof(uint32_t); STATIC_ASSERT(kPointerSize == kSeedSize); @@ -3670,6 +3820,20 @@ void LCodeGen::DoDeferredRandom(LRandom* instr) { } +void LCodeGen::DoMathExp(LMathExp* instr) { + DoubleRegister input = ToDoubleRegister(instr->value()); + DoubleRegister result = ToDoubleRegister(instr->result()); + DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp()); + DoubleRegister double_scratch2 = double_scratch0(); + Register temp1 = ToRegister(instr->temp1()); + Register temp2 = ToRegister(instr->temp2()); + + MathExpGenerator::EmitMathExp( + masm(), input, result, double_scratch1, double_scratch2, + temp1, temp2, scratch0()); +} + + void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { ASSERT(ToDoubleRegister(instr->result()).is(d2)); TranscendentalCacheStub stub(TranscendentalCache::LOG, @@ -3765,7 +3929,7 @@ void LCodeGen::DoCallKeyed(LCallKeyed* instr) { int arity = instr->arity(); Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arity); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); } @@ -3778,7 +3942,7 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) { Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity, mode); __ mov(r2, Operand(instr->name())); - CallCode(ic, mode, instr); + CallCode(ic, mode, instr, NEVER_INLINE_TARGET_ADDRESS); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); } @@ -3803,7 +3967,7 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity, mode); __ mov(r2, Operand(instr->name())); - CallCode(ic, mode, instr); + CallCode(ic, mode, instr, NEVER_INLINE_TARGET_ADDRESS); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); } @@ -3819,7 +3983,7 @@ void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { void LCodeGen::DoCallNew(LCallNew* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(r1)); + ASSERT(ToRegister(instr->constructor()).is(r1)); ASSERT(ToRegister(instr->result()).is(r0)); CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); @@ -3845,7 +4009,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { __ mov(scratch, Operand(instr->transition())); __ str(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); if (instr->hydrogen()->NeedsWriteBarrierForMap()) { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); // Update the write barrier for the map field. __ RecordWriteField(object, HeapObject::kMapOffset, @@ -3903,7 +4067,7 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) ? isolate()->builtins()->StoreIC_Initialize_Strict() : isolate()->builtins()->StoreIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } @@ -3945,102 +4109,8 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { } -void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { - Register value = ToRegister(instr->value()); - Register elements = ToRegister(instr->object()); - Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; - Register scratch = scratch0(); - Register store_base = scratch; - int offset = 0; - - // Do the store. - if (instr->key()->IsConstantOperand()) { - ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); - LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); - offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + - instr->additional_index()); - store_base = elements; - } else { - // Even though the HLoadKeyedFastElement instruction forces the input - // representation for the key to be an integer, the input gets replaced - // during bound check elimination with the index argument to the bounds - // check, which can be tagged, so that case must be handled here, too. - if (instr->hydrogen()->key()->representation().IsTagged()) { - __ add(scratch, elements, - Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); - } else { - __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); - } - offset = FixedArray::OffsetOfElementAt(instr->additional_index()); - } - __ str(value, FieldMemOperand(store_base, offset)); - - if (instr->hydrogen()->NeedsWriteBarrier()) { - HType type = instr->hydrogen()->value()->type(); - SmiCheck check_needed = - type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; - // Compute address of modified element and store it into key register. - __ add(key, store_base, Operand(offset - kHeapObjectTag)); - __ RecordWrite(elements, - key, - value, - kLRHasBeenSaved, - kSaveFPRegs, - EMIT_REMEMBERED_SET, - check_needed); - } -} - - -void LCodeGen::DoStoreKeyedFastDoubleElement( - LStoreKeyedFastDoubleElement* instr) { - DwVfpRegister value = ToDoubleRegister(instr->value()); - Register elements = ToRegister(instr->elements()); - Register key = no_reg; - Register scratch = scratch0(); - bool key_is_constant = instr->key()->IsConstantOperand(); - int constant_key = 0; - - // Calculate the effective address of the slot in the array to store the - // double value. - if (key_is_constant) { - constant_key = ToInteger32(LConstantOperand::cast(instr->key())); - if (constant_key & 0xF0000000) { - Abort("array index constant value too big."); - } - } else { - key = ToRegister(instr->key()); - } - int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); - int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) - ? (element_size_shift - kSmiTagSize) : element_size_shift; - Operand operand = key_is_constant - ? Operand((constant_key << element_size_shift) + - FixedDoubleArray::kHeaderSize - kHeapObjectTag) - : Operand(key, LSL, shift_size); - __ add(scratch, elements, operand); - if (!key_is_constant) { - __ add(scratch, scratch, - Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); - } - - 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); - } - - __ vstr(value, scratch, instr->additional_index() << element_size_shift); -} - - -void LCodeGen::DoStoreKeyedSpecializedArrayElement( - LStoreKeyedSpecializedArrayElement* instr) { - - Register external_pointer = ToRegister(instr->external_pointer()); +void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { + Register external_pointer = ToRegister(instr->elements()); Register key = no_reg; ElementsKind elements_kind = instr->elements_kind(); bool key_is_constant = instr->key()->IsConstantOperand(); @@ -4109,6 +4179,110 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( } +void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { + DwVfpRegister value = ToDoubleRegister(instr->value()); + Register elements = ToRegister(instr->elements()); + Register key = no_reg; + Register scratch = scratch0(); + bool key_is_constant = instr->key()->IsConstantOperand(); + int constant_key = 0; + + // Calculate the effective address of the slot in the array to store the + // double value. + if (key_is_constant) { + constant_key = ToInteger32(LConstantOperand::cast(instr->key())); + if (constant_key & 0xF0000000) { + Abort("array index constant value too big."); + } + } else { + key = ToRegister(instr->key()); + } + int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); + int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) + ? (element_size_shift - kSmiTagSize) : element_size_shift; + Operand operand = key_is_constant + ? Operand((constant_key << element_size_shift) + + FixedDoubleArray::kHeaderSize - kHeapObjectTag) + : Operand(key, LSL, shift_size); + __ add(scratch, elements, operand); + if (!key_is_constant) { + __ add(scratch, scratch, + Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); + } + + 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(), + no_reg, vs); + } + + __ vstr(value, scratch, instr->additional_index() << element_size_shift); +} + + +void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { + Register value = ToRegister(instr->value()); + Register elements = ToRegister(instr->elements()); + Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) + : no_reg; + Register scratch = scratch0(); + Register store_base = scratch; + int offset = 0; + + // Do the store. + if (instr->key()->IsConstantOperand()) { + ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); + LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); + offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + + instr->additional_index()); + store_base = elements; + } else { + // Even though the HLoadKeyed instruction forces the input + // representation for the key to be an integer, the input gets replaced + // during bound check elimination with the index argument to the bounds + // check, which can be tagged, so that case must be handled here, too. + if (instr->hydrogen()->key()->representation().IsTagged()) { + __ add(scratch, elements, + Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); + } else { + __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); + } + offset = FixedArray::OffsetOfElementAt(instr->additional_index()); + } + __ str(value, FieldMemOperand(store_base, offset)); + + if (instr->hydrogen()->NeedsWriteBarrier()) { + HType type = instr->hydrogen()->value()->type(); + SmiCheck check_needed = + type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; + // Compute address of modified element and store it into key register. + __ add(key, store_base, Operand(offset - kHeapObjectTag)); + __ RecordWrite(elements, + key, + value, + kLRHasBeenSaved, + kSaveFPRegs, + EMIT_REMEMBERED_SET, + check_needed); + } +} + + +void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { + // By cases: external, fast double + if (instr->is_external()) { + DoStoreKeyedExternalArray(instr); + } else if (instr->hydrogen()->value()->representation().IsDouble()) { + DoStoreKeyedFixedDoubleArray(instr); + } else { + DoStoreKeyedFixedArray(instr); + } +} + + void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(r2)); ASSERT(ToRegister(instr->key()).is(r1)); @@ -4117,13 +4291,13 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() : isolate()->builtins()->KeyedStoreIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { Register object_reg = ToRegister(instr->object()); - Register new_map_reg = ToRegister(instr->new_map_reg()); + Register new_map_reg = ToRegister(instr->new_map_temp()); Register scratch = scratch0(); Handle<Map> from_map = instr->original_map(); @@ -4144,7 +4318,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { scratch, kLRHasBeenSaved, kDontSaveFPRegs); } else if (IsFastSmiElementsKind(from_kind) && IsFastDoubleElementsKind(to_kind)) { - Register fixed_object_reg = ToRegister(instr->temp_reg()); + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(r2)); ASSERT(new_map_reg.is(r3)); __ mov(fixed_object_reg, object_reg); @@ -4152,7 +4326,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { RelocInfo::CODE_TARGET, instr); } else if (IsFastDoubleElementsKind(from_kind) && IsFastObjectElementsKind(to_kind)) { - Register fixed_object_reg = ToRegister(instr->temp_reg()); + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(r2)); ASSERT(new_map_reg.is(r3)); __ mov(fixed_object_reg, object_reg); @@ -4220,9 +4394,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { __ push(index); } CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); - if (FLAG_debug_code) { - __ AbortIfNotSmi(r0); - } + __ AssertSmi(r0); __ SmiUntag(r0); __ StoreToSafepointRegisterSlot(r0, result); } @@ -4277,14 +4449,14 @@ void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { void LCodeGen::DoStringLength(LStringLength* instr) { - Register string = ToRegister(instr->InputAt(0)); + Register string = ToRegister(instr->string()); Register result = ToRegister(instr->result()); __ ldr(result, FieldMemOperand(string, String::kLengthOffset)); } void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() || input->IsStackSlot()); LOperand* output = instr->result(); ASSERT(output->IsDoubleRegister()); @@ -4301,7 +4473,7 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); LOperand* output = instr->result(); SwVfpRegister flt_scratch = double_scratch0().low(); @@ -4317,7 +4489,7 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_, - instr_->InputAt(0), + instr_->value(), SIGNED_INT32); } virtual LInstruction* instr() { return instr_; } @@ -4325,7 +4497,7 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { LNumberTagI* instr_; }; - Register src = ToRegister(instr->InputAt(0)); + Register src = ToRegister(instr->value()); Register dst = ToRegister(instr->result()); DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr); @@ -4342,7 +4514,7 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_, - instr_->InputAt(0), + instr_->value(), UNSIGNED_INT32); } virtual LInstruction* instr() { return instr_; } @@ -4350,7 +4522,7 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { LNumberTagU* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() && input->Equals(instr->result())); Register reg = ToRegister(input); @@ -4392,7 +4564,7 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, if (FLAG_inline_new) { __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(r5, r3, r4, r6, &slow); + __ AllocateHeapNumber(r5, r3, r4, r6, &slow, DONT_TAG_RESULT); __ Move(dst, r5); __ b(&done); } @@ -4407,12 +4579,13 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, __ StoreToSafepointRegisterSlot(ip, dst); CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); __ Move(dst, r0); + __ sub(dst, dst, Operand(kHeapObjectTag)); // Done. Put the value in dbl_scratch into the value of the allocated heap // number. __ bind(&done); - __ sub(ip, dst, Operand(kHeapObjectTag)); - __ vstr(dbl_scratch, ip, HeapNumber::kValueOffset); + __ vstr(dbl_scratch, dst, HeapNumber::kValueOffset); + __ add(dst, dst, Operand(kHeapObjectTag)); __ StoreToSafepointRegisterSlot(dst, dst); } @@ -4428,22 +4601,25 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { LNumberTagD* instr_; }; - DoubleRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input_reg = ToDoubleRegister(instr->value()); Register scratch = scratch0(); Register reg = ToRegister(instr->result()); - Register temp1 = ToRegister(instr->TempAt(0)); - Register temp2 = ToRegister(instr->TempAt(1)); + Register temp1 = ToRegister(instr->temp()); + Register temp2 = ToRegister(instr->temp2()); DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); if (FLAG_inline_new) { __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry()); + // We want the untagged address first for performance + __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(), + DONT_TAG_RESULT); } else { __ jmp(deferred->entry()); } __ bind(deferred->exit()); - __ sub(ip, reg, Operand(kHeapObjectTag)); - __ vstr(input_reg, ip, HeapNumber::kValueOffset); + __ vstr(input_reg, reg, HeapNumber::kValueOffset); + // Now that we have finished with the object's real address tag it + __ add(reg, reg, Operand(kHeapObjectTag)); } @@ -4456,18 +4632,19 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); + __ sub(r0, r0, Operand(kHeapObjectTag)); __ StoreToSafepointRegisterSlot(r0, reg); } void LCodeGen::DoSmiTag(LSmiTag* instr) { ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); - __ SmiTag(ToRegister(instr->result()), ToRegister(instr->InputAt(0))); + __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value())); } void LCodeGen::DoSmiUntag(LSmiUntag* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); if (instr->needs_check()) { STATIC_ASSERT(kHeapObjectTag == 1); @@ -4539,11 +4716,11 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { - Register input_reg = ToRegister(instr->InputAt(0)); + Register input_reg = ToRegister(instr->value()); Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); + Register scratch2 = ToRegister(instr->temp()); DwVfpRegister double_scratch = double_scratch0(); - SwVfpRegister single_scratch = double_scratch.low(); + DwVfpRegister double_scratch2 = ToDoubleRegister(instr->temp3()); ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1)); @@ -4562,8 +4739,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { __ cmp(scratch1, Operand(ip)); if (instr->truncating()) { - Register scratch3 = ToRegister(instr->TempAt(1)); - DwVfpRegister double_scratch2 = ToDoubleRegister(instr->TempAt(2)); + Register scratch3 = ToRegister(instr->temp2()); ASSERT(!scratch3.is(input_reg) && !scratch3.is(scratch1) && !scratch3.is(scratch2)); @@ -4585,7 +4761,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { __ EmitECMATruncate(input_reg, double_scratch2, - single_scratch, + double_scratch, scratch1, scratch2, scratch3); @@ -4598,14 +4774,12 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { __ sub(ip, input_reg, Operand(kHeapObjectTag)); __ vldr(double_scratch, ip, HeapNumber::kValueOffset); __ EmitVFPTruncate(kRoundToZero, - single_scratch, + input_reg, double_scratch, scratch1, - scratch2, + double_scratch2, kCheckForInexactConversion); DeoptimizeIf(ne, instr->environment()); - // Load the result. - __ vmov(input_reg, single_scratch); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { __ cmp(input_reg, Operand(0)); @@ -4630,7 +4804,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { LTaggedToI* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); ASSERT(input->Equals(instr->result())); @@ -4649,7 +4823,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); LOperand* result = instr->result(); ASSERT(result->IsDoubleRegister()); @@ -4667,54 +4841,52 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Register result_reg = ToRegister(instr->result()); Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); - DwVfpRegister double_input = ToDoubleRegister(instr->InputAt(0)); - SwVfpRegister single_scratch = double_scratch0().low(); + Register scratch2 = ToRegister(instr->temp()); + DwVfpRegister double_input = ToDoubleRegister(instr->value()); + DwVfpRegister double_scratch = double_scratch0(); Label done; if (instr->truncating()) { - Register scratch3 = ToRegister(instr->TempAt(1)); + Register scratch3 = ToRegister(instr->temp2()); __ EmitECMATruncate(result_reg, double_input, - single_scratch, + double_scratch, scratch1, scratch2, scratch3); } else { - VFPRoundingMode rounding_mode = kRoundToMinusInf; - __ EmitVFPTruncate(rounding_mode, - single_scratch, + __ EmitVFPTruncate(kRoundToMinusInf, + result_reg, double_input, scratch1, - scratch2, + double_scratch, kCheckForInexactConversion); + // Deoptimize if we had a vfp invalid exception, // including inexact operation. DeoptimizeIf(ne, instr->environment()); - // Retrieve the result. - __ vmov(result_reg, single_scratch); } __ bind(&done); } void LCodeGen::DoCheckSmi(LCheckSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); __ tst(ToRegister(input), Operand(kSmiTagMask)); DeoptimizeIf(ne, instr->environment()); } void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); __ tst(ToRegister(input), Operand(kSmiTagMask)); DeoptimizeIf(eq, instr->environment()); } void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register scratch = scratch0(); __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); @@ -4787,7 +4959,7 @@ void LCodeGen::DoCheckMapCommon(Register reg, void LCodeGen::DoCheckMaps(LCheckMaps* instr) { Register scratch = scratch0(); - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); Register reg = ToRegister(input); @@ -4807,7 +4979,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) { void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { DoubleRegister value_reg = ToDoubleRegister(instr->unclamped()); Register result_reg = ToRegister(instr->result()); - DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0)); + DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); __ ClampDoubleToUint8(result_reg, value_reg, temp_reg); } @@ -4823,7 +4995,7 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { Register scratch = scratch0(); Register input_reg = ToRegister(instr->unclamped()); Register result_reg = ToRegister(instr->result()); - DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0)); + DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); Label is_smi, done, heap_number; // Both smi and heap number cases are handled. @@ -4857,8 +5029,9 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { - Register temp1 = ToRegister(instr->TempAt(0)); - Register temp2 = ToRegister(instr->TempAt(1)); + ASSERT(instr->temp()->Equals(instr->result())); + Register temp1 = ToRegister(instr->temp()); + Register temp2 = ToRegister(instr->temp2()); Handle<JSObject> holder = instr->holder(); Handle<JSObject> current_prototype = instr->prototype(); @@ -4881,7 +5054,6 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { DoCheckMapCommon(temp1, temp2, Handle<Map>(current_prototype->map()), ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment()); - DeoptimizeIf(ne, instr->environment()); } @@ -4900,8 +5072,8 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { new(zone()) DeferredAllocateObject(this, instr); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->TempAt(0)); - Register scratch2 = ToRegister(instr->TempAt(1)); + Register scratch = ToRegister(instr->temp()); + Register scratch2 = ToRegister(instr->temp2()); Handle<JSFunction> constructor = instr->hydrogen()->constructor(); Handle<Map> initial_map(constructor->initial_map()); int instance_size = initial_map->instance_size(); @@ -5193,7 +5365,7 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { void LCodeGen::DoToFastProperties(LToFastProperties* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(r0)); + ASSERT(ToRegister(instr->value()).is(r0)); __ push(r0); CallRuntime(Runtime::kToFastProperties, 1, instr); } @@ -5274,14 +5446,14 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); __ push(input); CallRuntime(Runtime::kTypeof, 1, instr); } void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); Label* true_label = chunk_->GetAssemblyLabel(true_block); @@ -5371,7 +5543,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { - Register temp1 = ToRegister(instr->TempAt(0)); + Register temp1 = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -5492,6 +5664,7 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { __ cmp(sp, Operand(ip)); __ b(hs, &done); StackCheckStub stub; + PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); EnsureSpaceForLazyDeopt(); __ bind(&done); @@ -5572,7 +5745,6 @@ void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { Register map = ToRegister(instr->map()); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->scratch()); Label load_cache, done; __ EnumLength(result, map); __ cmp(result, Operand(Smi::FromInt(0))); @@ -5581,7 +5753,7 @@ void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { __ jmp(&done); __ bind(&load_cache); - __ LoadInstanceDescriptors(map, result, scratch); + __ LoadInstanceDescriptors(map, result); __ ldr(result, FieldMemOperand(result, DescriptorArray::kEnumCacheOffset)); __ ldr(result, diff --git a/deps/v8/src/arm/lithium-codegen-arm.h b/deps/v8/src/arm/lithium-codegen-arm.h index fd4a2a5ca7..921285b0d2 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.h +++ b/deps/v8/src/arm/lithium-codegen-arm.h @@ -110,8 +110,9 @@ class LCodeGen BASE_EMBEDDED { void FinishCode(Handle<Code> code); // Deferred code support. - template<int T> - void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, + void DoDeferredBinaryOpStub(LPointerMap* pointer_map, + LOperand* left_argument, + LOperand* right_argument, Token::Value op); void DoDeferredNumberTagD(LNumberTagD* instr); @@ -147,7 +148,10 @@ class LCodeGen BASE_EMBEDDED { int additional_offset); // Emit frame translation commands for an environment. - void WriteTranslation(LEnvironment* environment, Translation* translation); + void WriteTranslation(LEnvironment* environment, + Translation* translation, + int* arguments_index, + int* arguments_count); // Declare methods that deal with the individual node types. #define DECLARE_DO(type) void Do##type(L##type* node); @@ -209,14 +213,18 @@ class LCodeGen BASE_EMBEDDED { RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS }; - void CallCode(Handle<Code> code, - RelocInfo::Mode mode, - LInstruction* instr); + void CallCode( + Handle<Code> code, + RelocInfo::Mode mode, + LInstruction* instr, + TargetAddressStorageMode storage_mode = CAN_INLINE_TARGET_ADDRESS); - void CallCodeGeneric(Handle<Code> code, - RelocInfo::Mode mode, - LInstruction* instr, - SafepointMode safepoint_mode); + void CallCodeGeneric( + Handle<Code> code, + RelocInfo::Mode mode, + LInstruction* instr, + SafepointMode safepoint_mode, + TargetAddressStorageMode storage_mode = CAN_INLINE_TARGET_ADDRESS); void CallRuntime(const Runtime::Function* function, int num_arguments, @@ -258,7 +266,9 @@ class LCodeGen BASE_EMBEDDED { void AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32); + bool is_uint32, + int arguments_index, + int arguments_count); void PopulateDeoptimizationData(Handle<Code> code); int DefineDeoptimizationLiteral(Handle<Object> literal); @@ -367,6 +377,12 @@ class LCodeGen BASE_EMBEDDED { }; void EnsureSpaceForLazyDeopt(); + void DoLoadKeyedExternalArray(LLoadKeyed* instr); + void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); + void DoLoadKeyedFixedArray(LLoadKeyed* instr); + void DoStoreKeyedExternalArray(LStoreKeyed* instr); + void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); + void DoStoreKeyedFixedArray(LStoreKeyed* instr); Zone* zone_; LPlatformChunk* const chunk_; diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 2a677be525..dc1dc1da9b 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -108,7 +108,7 @@ void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode, int MacroAssembler::CallSize(Register target, Condition cond) { -#if USE_BLX +#ifdef USE_BLX return kInstrSize; #else return 2 * kInstrSize; @@ -121,7 +121,7 @@ void MacroAssembler::Call(Register target, Condition cond) { BlockConstPoolScope block_const_pool(this); Label start; bind(&start); -#if USE_BLX +#ifdef USE_BLX blx(target, cond); #else // set lr for return at current pc + 8 @@ -158,15 +158,29 @@ int MacroAssembler::CallSizeNotPredictableCodeSize( void MacroAssembler::Call(Address target, RelocInfo::Mode rmode, - Condition cond) { + Condition cond, + TargetAddressStorageMode mode) { // Block constant pool for the call instruction sequence. BlockConstPoolScope block_const_pool(this); Label start; bind(&start); -#if USE_BLX - // On ARMv5 and after the recommended call sequence is: - // ldr ip, [pc, #...] - // blx ip + + bool old_predictable_code_size = predictable_code_size(); + if (mode == NEVER_INLINE_TARGET_ADDRESS) { + set_predictable_code_size(true); + } + +#ifdef USE_BLX + // Call sequence on V7 or later may be : + // movw ip, #... @ call address low 16 + // movt ip, #... @ call address high 16 + // blx ip + // @ return address + // Or for pre-V7 or values that may be back-patched + // to avoid ICache flushes: + // ldr ip, [pc, #...] @ call address + // blx ip + // @ return address // Statement positions are expected to be recorded when the target // address is loaded. The mov method will automatically record @@ -177,15 +191,16 @@ void MacroAssembler::Call(Address target, mov(ip, Operand(reinterpret_cast<int32_t>(target), rmode)); blx(ip, cond); - ASSERT(kCallTargetAddressOffset == 2 * kInstrSize); #else // Set lr for return at current pc + 8. mov(lr, Operand(pc), LeaveCC, cond); // Emit a ldr<cond> pc, [pc + offset of target in constant pool]. mov(pc, Operand(reinterpret_cast<int32_t>(target), rmode), LeaveCC, cond); - ASSERT(kCallTargetAddressOffset == kInstrSize); #endif ASSERT_EQ(CallSize(target, rmode, cond), SizeOfCodeGeneratedSince(&start)); + if (mode == NEVER_INLINE_TARGET_ADDRESS) { + set_predictable_code_size(old_predictable_code_size); + } } @@ -200,7 +215,8 @@ int MacroAssembler::CallSize(Handle<Code> code, void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode, TypeFeedbackId ast_id, - Condition cond) { + Condition cond, + TargetAddressStorageMode mode) { Label start; bind(&start); ASSERT(RelocInfo::IsCodeTarget(rmode)); @@ -209,9 +225,7 @@ void MacroAssembler::Call(Handle<Code> code, rmode = RelocInfo::CODE_TARGET_WITH_ID; } // 'code' is always generated ARM code, never THUMB code - Call(reinterpret_cast<Address>(code.location()), rmode, cond); - ASSERT_EQ(CallSize(code, rmode, ast_id, cond), - SizeOfCodeGeneratedSince(&start)); + Call(reinterpret_cast<Address>(code.location()), rmode, cond, mode); } @@ -288,17 +302,15 @@ void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) { void MacroAssembler::And(Register dst, Register src1, const Operand& src2, Condition cond) { if (!src2.is_reg() && - !src2.must_use_constant_pool(this) && + !src2.must_output_reloc_info(this) && src2.immediate() == 0) { mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, cond); - } else if (!src2.is_single_instruction(this) && - !src2.must_use_constant_pool(this) && + !src2.must_output_reloc_info(this) && CpuFeatures::IsSupported(ARMv7) && IsPowerOf2(src2.immediate() + 1)) { ubfx(dst, src1, 0, WhichPowerOf2(static_cast<uint32_t>(src2.immediate()) + 1), cond); - } else { and_(dst, src1, src2, LeaveCC, cond); } @@ -363,12 +375,14 @@ void MacroAssembler::Bfi(Register dst, } -void MacroAssembler::Bfc(Register dst, int lsb, int width, Condition cond) { +void MacroAssembler::Bfc(Register dst, Register src, int lsb, int width, + Condition cond) { ASSERT(lsb < 32); if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) { int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1); - bic(dst, dst, Operand(mask)); + bic(dst, src, Operand(mask)); } else { + Move(dst, src, cond); bfc(dst, lsb, width, cond); } } @@ -408,6 +422,17 @@ void MacroAssembler::Usat(Register dst, int satpos, const Operand& src, void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index, Condition cond) { + if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) && + !Heap::RootCanBeWrittenAfterInitialization(index) && + !predictable_code_size()) { + Handle<Object> root(isolate()->heap()->roots_array_start()[index]); + if (!isolate()->heap()->InNewSpace(*root)) { + // The CPU supports fast immediate values, and this root will never + // change. We will load it as a relocatable immediate value. + mov(destination, Operand(root), LeaveCC, cond); + return; + } + } ldr(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), cond); } @@ -789,6 +814,7 @@ void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1, void MacroAssembler::Vmov(const DwVfpRegister dst, const double imm, + const Register scratch, const Condition cond) { ASSERT(CpuFeatures::IsEnabled(VFP2)); static const DoubleRepresentation minus_zero(-0.0); @@ -800,7 +826,7 @@ void MacroAssembler::Vmov(const DwVfpRegister dst, } else if (value.bits == minus_zero.bits) { vneg(dst, kDoubleRegZero, cond); } else { - vmov(dst, imm, cond); + vmov(dst, imm, scratch, cond); } } @@ -1567,7 +1593,11 @@ void MacroAssembler::AllocateInNewSpace(int object_size, Register topaddr = scratch1; Register obj_size_reg = scratch2; mov(topaddr, Operand(new_space_allocation_top)); - mov(obj_size_reg, Operand(object_size)); + Operand obj_size_operand = Operand(object_size); + if (!obj_size_operand.is_single_instruction(this)) { + // We are about to steal IP, so we need to load this value first + mov(obj_size_reg, obj_size_operand); + } // This code stores a temporary value in ip. This is OK, as the code below // does not need ip for implicit literal generation. @@ -1589,7 +1619,13 @@ void MacroAssembler::AllocateInNewSpace(int object_size, // Calculate new top and bail out if new space is exhausted. Use result // to calculate the new top. - add(scratch2, result, Operand(obj_size_reg), SetCC); + if (obj_size_operand.is_single_instruction(this)) { + // We can add the size as an immediate + add(scratch2, result, obj_size_operand, SetCC); + } else { + // Doesn't fit in an immediate, we have to use the register + add(scratch2, result, obj_size_reg, SetCC); + } b(cs, gc_required); cmp(scratch2, Operand(ip)); b(hi, gc_required); @@ -1751,10 +1787,10 @@ void MacroAssembler::AllocateAsciiString(Register result, Label* gc_required) { // Calculate the number of bytes needed for the characters in the string while // observing object alignment. - ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); + ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); ASSERT(kCharSize == 1); add(scratch1, length, - Operand(kObjectAlignmentMask + SeqAsciiString::kHeaderSize)); + Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize)); and_(scratch1, scratch1, Operand(~kObjectAlignmentMask)); // Allocate ASCII string in new space. @@ -1920,13 +1956,13 @@ void MacroAssembler::CheckFastSmiElements(Register map, void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, Register key_reg, - Register receiver_reg, Register elements_reg, Register scratch1, Register scratch2, Register scratch3, Register scratch4, - Label* fail) { + Label* fail, + int elements_offset) { Label smi_value, maybe_nan, have_double_value, is_nan, done; Register mantissa_reg = scratch2; Register exponent_reg = scratch3; @@ -1953,8 +1989,10 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, bind(&have_double_value); add(scratch1, elements_reg, Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize)); - str(mantissa_reg, FieldMemOperand(scratch1, FixedDoubleArray::kHeaderSize)); - uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); + str(mantissa_reg, FieldMemOperand( + scratch1, FixedDoubleArray::kHeaderSize - elements_offset)); + uint32_t offset = FixedDoubleArray::kHeaderSize - elements_offset + + sizeof(kHoleNanLower32); str(exponent_reg, FieldMemOperand(scratch1, offset)); jmp(&done); @@ -1975,7 +2013,8 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, bind(&smi_value); add(scratch1, elements_reg, - Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); + Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag - + elements_offset)); add(scratch1, scratch1, Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize)); // scratch1 is now effective address of the double element @@ -1987,7 +2026,7 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, destination = FloatingPointHelper::kCoreRegisters; } - Register untagged_value = receiver_reg; + Register untagged_value = elements_reg; SmiUntag(untagged_value, value_reg); FloatingPointHelper::ConvertIntToDouble(this, untagged_value, @@ -2184,12 +2223,28 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, add(r6, r6, Operand(1)); str(r6, MemOperand(r7, kLevelOffset)); + if (FLAG_log_timer_events) { + FrameScope frame(this, StackFrame::MANUAL); + PushSafepointRegisters(); + PrepareCallCFunction(0, r0); + CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0); + PopSafepointRegisters(); + } + // Native call returns to the DirectCEntry stub which redirects to the // return address pushed on stack (could have moved after GC). // DirectCEntry stub itself is generated early and never moves. DirectCEntryStub stub; stub.GenerateCall(this, function); + if (FLAG_log_timer_events) { + FrameScope frame(this, StackFrame::MANUAL); + PushSafepointRegisters(); + PrepareCallCFunction(0, r0); + CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0); + PopSafepointRegisters(); + } + Label promote_scheduled_exception; Label delete_allocated_handles; Label leave_exit_frame; @@ -2435,17 +2490,38 @@ void MacroAssembler::ConvertToInt32(Register source, } +void MacroAssembler::TryFastDoubleToInt32(Register result, + DwVfpRegister double_input, + DwVfpRegister double_scratch, + Label* done) { + ASSERT(!double_input.is(double_scratch)); + + vcvt_s32_f64(double_scratch.low(), double_input); + vmov(result, double_scratch.low()); + vcvt_f64_s32(double_scratch, double_scratch.low()); + VFPCompareAndSetFlags(double_input, double_scratch); + b(eq, done); +} + + void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode, - SwVfpRegister result, + Register result, DwVfpRegister double_input, - Register scratch1, - Register scratch2, + Register scratch, + DwVfpRegister double_scratch, CheckForInexactConversion check_inexact) { + ASSERT(!result.is(scratch)); + ASSERT(!double_input.is(double_scratch)); + ASSERT(CpuFeatures::IsSupported(VFP2)); CpuFeatures::Scope scope(VFP2); - Register prev_fpscr = scratch1; - Register scratch = scratch2; + Register prev_fpscr = result; + Label done; + + // Test for values that can be exactly represented as a signed 32-bit integer. + TryFastDoubleToInt32(result, double_input, double_scratch, &done); + // Convert to integer, respecting rounding mode. int32_t check_inexact_conversion = (check_inexact == kCheckForInexactConversion) ? kVFPInexactExceptionBit : 0; @@ -2467,7 +2543,7 @@ void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode, vmsr(scratch); // Convert the argument to an integer. - vcvt_s32_f64(result, + vcvt_s32_f64(double_scratch.low(), double_input, (rounding_mode == kRoundToZero) ? kDefaultRoundToZero : kFPSCRRounding); @@ -2476,8 +2552,12 @@ void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode, vmrs(scratch); // Restore FPSCR. vmsr(prev_fpscr); + // Move the converted value into the result register. + vmov(result, double_scratch.low()); // Check for vfp exceptions. tst(scratch, Operand(kVFPExceptionMask | check_inexact_conversion)); + + bind(&done); } @@ -2556,7 +2636,7 @@ void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result, void MacroAssembler::EmitECMATruncate(Register result, DwVfpRegister double_input, - SwVfpRegister single_scratch, + DwVfpRegister double_scratch, Register scratch, Register input_high, Register input_low) { @@ -2567,16 +2647,18 @@ void MacroAssembler::EmitECMATruncate(Register result, ASSERT(!scratch.is(result) && !scratch.is(input_high) && !scratch.is(input_low)); - ASSERT(!single_scratch.is(double_input.low()) && - !single_scratch.is(double_input.high())); + ASSERT(!double_input.is(double_scratch)); Label done; + // Test for values that can be exactly represented as a signed 32-bit integer. + TryFastDoubleToInt32(result, double_input, double_scratch, &done); + // Clear cumulative exception flags. ClearFPSCRBits(kVFPExceptionMask, scratch); // Try a conversion to a signed integer. - vcvt_s32_f64(single_scratch, double_input); - vmov(result, single_scratch); + vcvt_s32_f64(double_scratch.low(), double_input); + vmov(result, double_scratch.low()); // Retrieve he FPSCR. vmrs(scratch); // Check for overflow and NaNs. @@ -3017,38 +3099,46 @@ void MacroAssembler::JumpIfEitherSmi(Register reg1, } -void MacroAssembler::AbortIfSmi(Register object) { - STATIC_ASSERT(kSmiTag == 0); - tst(object, Operand(kSmiTagMask)); - Assert(ne, "Operand is a smi"); +void MacroAssembler::AssertNotSmi(Register object) { + if (emit_debug_code()) { + STATIC_ASSERT(kSmiTag == 0); + tst(object, Operand(kSmiTagMask)); + Check(ne, "Operand is a smi"); + } } -void MacroAssembler::AbortIfNotSmi(Register object) { - STATIC_ASSERT(kSmiTag == 0); - tst(object, Operand(kSmiTagMask)); - Assert(eq, "Operand is not smi"); +void MacroAssembler::AssertSmi(Register object) { + if (emit_debug_code()) { + STATIC_ASSERT(kSmiTag == 0); + tst(object, Operand(kSmiTagMask)); + Check(eq, "Operand is not smi"); + } } -void MacroAssembler::AbortIfNotString(Register object) { - STATIC_ASSERT(kSmiTag == 0); - tst(object, Operand(kSmiTagMask)); - Assert(ne, "Operand is not a string"); - push(object); - ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); - CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); - pop(object); - Assert(lo, "Operand is not a string"); +void MacroAssembler::AssertString(Register object) { + if (emit_debug_code()) { + STATIC_ASSERT(kSmiTag == 0); + tst(object, Operand(kSmiTagMask)); + Check(ne, "Operand is a smi and not a string"); + push(object); + ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); + CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); + pop(object); + Check(lo, "Operand is not a string"); + } } -void MacroAssembler::AbortIfNotRootValue(Register src, - Heap::RootListIndex root_value_index, - const char* message) { - CompareRoot(src, root_value_index); - Assert(eq, message); +void MacroAssembler::AssertRootValue(Register src, + Heap::RootListIndex root_value_index, + const char* message) { + if (emit_debug_code()) { + CompareRoot(src, root_value_index); + Check(eq, message); + } } @@ -3106,7 +3196,8 @@ void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1, Register scratch2, Register heap_number_map, - Label* gc_required) { + Label* gc_required, + TaggingMode tagging_mode) { // Allocate an object in the heap for the heap number and tag it as a heap // object. AllocateInNewSpace(HeapNumber::kSize, @@ -3114,11 +3205,16 @@ void MacroAssembler::AllocateHeapNumber(Register result, scratch1, scratch2, gc_required, - TAG_OBJECT); + tagging_mode == TAG_RESULT ? TAG_OBJECT : + NO_ALLOCATION_FLAGS); // Store heap number map in the allocated object. AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); - str(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset)); + if (tagging_mode == TAG_RESULT) { + str(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset)); + } else { + str(heap_number_map, MemOperand(result, HeapObject::kMapOffset)); + } } @@ -3189,17 +3285,17 @@ void MacroAssembler::CopyBytes(Register src, cmp(length, Operand(kPointerSize)); b(lt, &byte_loop); ldr(scratch, MemOperand(src, kPointerSize, PostIndex)); -#if CAN_USE_UNALIGNED_ACCESSES - str(scratch, MemOperand(dst, kPointerSize, PostIndex)); -#else - strb(scratch, MemOperand(dst, 1, PostIndex)); - mov(scratch, Operand(scratch, LSR, 8)); - strb(scratch, MemOperand(dst, 1, PostIndex)); - mov(scratch, Operand(scratch, LSR, 8)); - strb(scratch, MemOperand(dst, 1, PostIndex)); - mov(scratch, Operand(scratch, LSR, 8)); - strb(scratch, MemOperand(dst, 1, PostIndex)); -#endif + if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) { + str(scratch, MemOperand(dst, kPointerSize, PostIndex)); + } else { + strb(scratch, MemOperand(dst, 1, PostIndex)); + mov(scratch, Operand(scratch, LSR, 8)); + strb(scratch, MemOperand(dst, 1, PostIndex)); + mov(scratch, Operand(scratch, LSR, 8)); + strb(scratch, MemOperand(dst, 1, PostIndex)); + mov(scratch, Operand(scratch, LSR, 8)); + strb(scratch, MemOperand(dst, 1, PostIndex)); + } sub(length, length, Operand(kPointerSize)); b(&word_loop); @@ -3274,8 +3370,10 @@ void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii( Register scratch2, Label* failure) { int kFlatAsciiStringMask = - kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; + kIsNotStringMask | kStringEncodingMask | kAsciiDataHintMask | + kStringRepresentationMask; int kFlatAsciiStringTag = ASCII_STRING_TYPE; + ASSERT_EQ(ASCII_STRING_TYPE, ASCII_STRING_TYPE & kFlatAsciiStringMask); and_(scratch1, first, Operand(kFlatAsciiStringMask)); and_(scratch2, second, Operand(kFlatAsciiStringMask)); cmp(scratch1, Operand(kFlatAsciiStringTag)); @@ -3289,8 +3387,10 @@ void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(Register type, Register scratch, Label* failure) { int kFlatAsciiStringMask = - kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; + kIsNotStringMask | kStringEncodingMask | kAsciiDataHintMask | + kStringRepresentationMask; int kFlatAsciiStringTag = ASCII_STRING_TYPE; + ASSERT_EQ(ASCII_STRING_TYPE, ASCII_STRING_TYPE & kFlatAsciiStringMask); and_(scratch, type, Operand(kFlatAsciiStringMask)); cmp(scratch, Operand(kFlatAsciiStringTag)); b(ne, failure); @@ -3481,7 +3581,7 @@ void MacroAssembler::CheckPageFlag( int mask, Condition cc, Label* condition_met) { - and_(scratch, object, Operand(~Page::kPageAlignmentMask)); + Bfc(scratch, object, 0, kPageSizeBits); ldr(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset)); tst(scratch, Operand(mask)); b(cc, condition_met); @@ -3630,7 +3730,7 @@ void MacroAssembler::EnsureNotWhite( // For ASCII (char-size of 1) we shift the smi tag away to get the length. // For UC16 (char-size of 2) we just leave the smi tag in place, thereby // getting the length multiplied by 2. - ASSERT(kAsciiStringTag == 4 && kStringEncodingMask == 4); + ASSERT(kOneByteStringTag == 4 && kStringEncodingMask == 4); ASSERT(kSmiTag == 0 && kSmiTagSize == 1); ldr(ip, FieldMemOperand(value, String::kLengthOffset)); tst(instance_type, Operand(kStringEncodingMask)); @@ -3676,7 +3776,7 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg, // Double value is >= 255, return 255. bind(&above_zero); - Vmov(temp_double_reg, 255.0); + Vmov(temp_double_reg, 255.0, result_reg); VFPCompareAndSetFlags(input_reg, temp_double_reg); b(le, &in_bounds); mov(result_reg, Operand(255)); @@ -3698,22 +3798,14 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg, void MacroAssembler::LoadInstanceDescriptors(Register map, - Register descriptors, - Register scratch) { - Register temp = descriptors; - ldr(temp, FieldMemOperand(map, Map::kTransitionsOrBackPointerOffset)); - - Label ok, fail; - CheckMap(temp, - scratch, - isolate()->factory()->fixed_array_map(), - &fail, - DONT_DO_SMI_CHECK); - ldr(descriptors, FieldMemOperand(temp, TransitionArray::kDescriptorsOffset)); - jmp(&ok); - bind(&fail); - mov(descriptors, Operand(FACTORY->empty_descriptor_array())); - bind(&ok); + Register descriptors) { + ldr(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset)); +} + + +void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { + ldr(dst, FieldMemOperand(map, Map::kBitField3Offset)); + DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); } diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 8eb97125ea..15cef16f05 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -68,6 +68,13 @@ enum AllocationFlags { SIZE_IN_WORDS = 1 << 2 }; +// Flags used for AllocateHeapNumber +enum TaggingMode { + // Tag the result. + TAG_RESULT, + // Don't tag + DONT_TAG_RESULT +}; // Flags used for the ObjectToDoubleVFPRegister function. enum ObjectToDoubleFlags { @@ -95,6 +102,11 @@ bool AreAliased(Register reg1, #endif +enum TargetAddressStorageMode { + CAN_INLINE_TARGET_ADDRESS, + NEVER_INLINE_TARGET_ADDRESS +}; + // MacroAssembler implements a collection of frequently used macros. class MacroAssembler: public Assembler { public: @@ -114,7 +126,9 @@ class MacroAssembler: public Assembler { static int CallSizeNotPredictableCodeSize(Address target, RelocInfo::Mode rmode, Condition cond = al); - void Call(Address target, RelocInfo::Mode rmode, Condition cond = al); + void Call(Address target, RelocInfo::Mode rmode, + Condition cond = al, + TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS); int CallSize(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, TypeFeedbackId ast_id = TypeFeedbackId::None(), @@ -122,7 +136,8 @@ class MacroAssembler: public Assembler { void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, TypeFeedbackId ast_id = TypeFeedbackId::None(), - Condition cond = al); + Condition cond = al, + TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS); void Ret(Condition cond = al); // Emit code to discard a non-negative number of pointer-sized elements @@ -154,7 +169,7 @@ class MacroAssembler: public Assembler { int lsb, int width, Condition cond = al); - void Bfc(Register dst, int lsb, int width, Condition cond = al); + void Bfc(Register dst, Register src, int lsb, int width, Condition cond = al); void Usat(Register dst, int satpos, const Operand& src, Condition cond = al); @@ -307,6 +322,7 @@ class MacroAssembler: public Assembler { // Push a handle. void Push(Handle<Object> handle); + void Push(Smi* smi) { Push(Handle<Smi>(smi)); } // Push two registers. Pushes leftmost register first (to highest address). void Push(Register src1, Register src2, Condition cond = al) { @@ -483,6 +499,7 @@ class MacroAssembler: public Assembler { void Vmov(const DwVfpRegister dst, const double imm, + const Register scratch = no_reg, const Condition cond = al); // Enter exit frame. @@ -730,7 +747,8 @@ class MacroAssembler: public Assembler { Register scratch1, Register scratch2, Register heap_number_map, - Label* gc_required); + Label* gc_required, + TaggingMode tagging_mode = TAG_RESULT); void AllocateHeapNumberWithValue(Register result, DwVfpRegister value, Register scratch1, @@ -814,13 +832,14 @@ class MacroAssembler: public Assembler { // case scratch2, scratch3 and scratch4 are unmodified. void StoreNumberToDoubleElements(Register value_reg, Register key_reg, - Register receiver_reg, + // All regs below here overwritten. Register elements_reg, Register scratch1, Register scratch2, Register scratch3, Register scratch4, - Label* fail); + Label* fail, + int elements_offset = 0); // Compare an object's map with the specified map and its transitioned // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Condition flags are @@ -875,12 +894,15 @@ class MacroAssembler: public Assembler { // Load and check the instance type of an object for being a string. // Loads the type into the second argument register. - // Returns a condition that will be enabled if the object was a string. + // Returns a condition that will be enabled if the object was a string + // and the passed-in condition passed. If the passed-in condition failed + // then flags remain unchanged. Condition IsObjectStringType(Register obj, - Register type) { - ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset)); - ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset)); - tst(type, Operand(kIsNotStringMask)); + Register type, + Condition cond = al) { + ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset), cond); + ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset), cond); + tst(type, Operand(kIsNotStringMask), cond); ASSERT_EQ(0, kStringTag); return eq; } @@ -937,21 +959,30 @@ class MacroAssembler: public Assembler { DwVfpRegister double_scratch, Label *not_int32); - // Truncates a double using a specific rounding mode. + // Try to convert a double to a signed 32-bit integer. If the double value + // can be exactly represented as an integer, the code jumps to 'done' and + // 'result' contains the integer value. Otherwise, the code falls through. + void TryFastDoubleToInt32(Register result, + DwVfpRegister double_input, + DwVfpRegister double_scratch, + Label* done); + + // Truncates a double using a specific rounding mode, and writes the value + // to the result register. // Clears the z flag (ne condition) if an overflow occurs. - // If exact_conversion is true, the z flag is also cleared if the conversion - // was inexact, i.e. if the double value could not be converted exactly - // to a 32bit integer. + // If kCheckForInexactConversion is passed, the z flag is also cleared if the + // conversion was inexact, i.e. if the double value could not be converted + // exactly to a 32-bit integer. void EmitVFPTruncate(VFPRoundingMode rounding_mode, - SwVfpRegister result, + Register result, DwVfpRegister double_input, - Register scratch1, - Register scratch2, + Register scratch, + DwVfpRegister double_scratch, CheckForInexactConversion check = kDontCheckForInexactConversion); // Helper for EmitECMATruncate. - // This will truncate a floating-point value outside of the singed 32bit + // This will truncate a floating-point value outside of the signed 32bit // integer range to a 32bit signed integer. // Expects the double value loaded in input_high and input_low. // Exits with the answer in 'result'. @@ -966,7 +997,7 @@ class MacroAssembler: public Assembler { // Exits with 'result' holding the answer and all other registers clobbered. void EmitECMATruncate(Register result, DwVfpRegister double_input, - SwVfpRegister single_scratch, + DwVfpRegister double_scratch, Register scratch, Register scratch2, Register scratch3); @@ -1183,7 +1214,7 @@ class MacroAssembler: public Assembler { // Souce and destination can be the same register. void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case); - // Jump the register contains a smi. + // Jump if the register contains a smi. inline void JumpIfSmi(Register value, Label* smi_label) { tst(value, Operand(kSmiTagMask)); b(eq, smi_label); @@ -1198,17 +1229,18 @@ class MacroAssembler: public Assembler { // Jump if either of the registers contain a smi. void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi); - // Abort execution if argument is a smi. Used in debug code. - void AbortIfSmi(Register object); - void AbortIfNotSmi(Register object); + // Abort execution if argument is a smi, enabled via --debug-code. + void AssertNotSmi(Register object); + void AssertSmi(Register object); - // Abort execution if argument is a string. Used in debug code. - void AbortIfNotString(Register object); + // Abort execution if argument is a string, enabled via --debug-code. + void AssertString(Register object); - // Abort execution if argument is not the root value with the given index. - void AbortIfNotRootValue(Register src, - Heap::RootListIndex root_value_index, - const char* message); + // Abort execution if argument is not the root value with the given index, + // enabled via --debug-code. + void AssertRootValue(Register src, + Heap::RootListIndex root_value_index, + const char* message); // --------------------------------------------------------------------------- // HeapNumber utilities @@ -1269,10 +1301,17 @@ class MacroAssembler: public Assembler { DoubleRegister temp_double_reg); - void LoadInstanceDescriptors(Register map, - Register descriptors, - Register scratch); + void LoadInstanceDescriptors(Register map, Register descriptors); void EnumLength(Register dst, Register map); + void NumberOfOwnDescriptors(Register dst, Register map); + + template<typename Field> + void DecodeField(Register reg) { + static const int shift = Field::kShift; + static const int mask = (Field::kMask >> shift) << kSmiTagSize; + mov(reg, Operand(reg, LSR, shift)); + and_(reg, reg, Operand(mask)); + } // Activation support. void EnterFrame(StackFrame::Type type); diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index 66cdd8435e..d852d23760 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -1150,7 +1150,7 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); // Current string. - bool is_ascii = subject->IsAsciiRepresentationUnderneath(); + bool is_ascii = subject->IsOneByteRepresentationUnderneath(); ASSERT(re_code->instruction_start() <= *return_address); ASSERT(*return_address <= @@ -1181,7 +1181,7 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, } // String might have changed. - if (subject_tmp->IsAsciiRepresentation() != is_ascii) { + if (subject_tmp->IsOneByteRepresentation() != is_ascii) { // If we changed between an ASCII and an UC16 string, the specialized // code cannot be used, and we need to restart regexp matching from // scratch (including, potentially, compiling a new version of the code). @@ -1358,6 +1358,11 @@ void RegExpMacroAssemblerARM::CallCFunctionUsingStub( } +bool RegExpMacroAssemblerARM::CanReadUnaligned() { + return CpuFeatures::IsSupported(UNALIGNED_ACCESSES) && !slow_safe(); +} + + void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset, int characters) { Register offset = current_input_offset(); @@ -1370,9 +1375,9 @@ void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset, // and the operating system running on the target allow it. // If unaligned load/stores are not supported then this function must only // be used to load a single character at a time. -#if !V8_TARGET_CAN_READ_UNALIGNED - ASSERT(characters == 1); -#endif + if (!CanReadUnaligned()) { + ASSERT(characters == 1); + } if (mode_ == ASCII) { if (characters == 4) { diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.h b/deps/v8/src/arm/regexp-macro-assembler-arm.h index f723fa212f..c45669ae89 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.h +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.h @@ -109,6 +109,7 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); virtual void ClearRegisters(int reg_from, int reg_to); virtual void WriteStackPointerToRegister(int reg); + virtual bool CanReadUnaligned(); // Called from RegExp if the stack-guard is triggered. // If the code object is relocated, the return address is fixed before diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index a057de58cc..d11e340a9b 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -1066,111 +1066,83 @@ void Simulator::TrashCallerSaveRegisters() { int Simulator::ReadW(int32_t addr, Instruction* instr) { -#if V8_TARGET_CAN_READ_UNALIGNED - intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); - return *ptr; -#else - if ((addr & 3) == 0) { + if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) { intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); return *ptr; + } else { + PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", + addr, + reinterpret_cast<intptr_t>(instr)); + UNIMPLEMENTED(); + return 0; } - PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", - addr, - reinterpret_cast<intptr_t>(instr)); - UNIMPLEMENTED(); - return 0; -#endif } void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { -#if V8_TARGET_CAN_READ_UNALIGNED - intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); - *ptr = value; - return; -#else - if ((addr & 3) == 0) { + if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) { intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); *ptr = value; - return; + } else { + PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", + addr, + reinterpret_cast<intptr_t>(instr)); + UNIMPLEMENTED(); } - PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", - addr, - reinterpret_cast<intptr_t>(instr)); - UNIMPLEMENTED(); -#endif } uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { -#if V8_TARGET_CAN_READ_UNALIGNED - uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); - return *ptr; -#else - if ((addr & 1) == 0) { + if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); return *ptr; + } else { + PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" + V8PRIxPTR "\n", + addr, + reinterpret_cast<intptr_t>(instr)); + UNIMPLEMENTED(); + return 0; } - PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", - addr, - reinterpret_cast<intptr_t>(instr)); - UNIMPLEMENTED(); - return 0; -#endif } int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { -#if V8_TARGET_CAN_READ_UNALIGNED - int16_t* ptr = reinterpret_cast<int16_t*>(addr); - return *ptr; -#else - if ((addr & 1) == 0) { + if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { int16_t* ptr = reinterpret_cast<int16_t*>(addr); return *ptr; + } else { + PrintF("Unaligned signed halfword read at 0x%08x\n", addr); + UNIMPLEMENTED(); + return 0; } - PrintF("Unaligned signed halfword read at 0x%08x\n", addr); - UNIMPLEMENTED(); - return 0; -#endif } void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { -#if V8_TARGET_CAN_READ_UNALIGNED - uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); - *ptr = value; - return; -#else - if ((addr & 1) == 0) { + if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); *ptr = value; - return; + } else { + PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" + V8PRIxPTR "\n", + addr, + reinterpret_cast<intptr_t>(instr)); + UNIMPLEMENTED(); } - PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", - addr, - reinterpret_cast<intptr_t>(instr)); - UNIMPLEMENTED(); -#endif } void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { -#if V8_TARGET_CAN_READ_UNALIGNED - int16_t* ptr = reinterpret_cast<int16_t*>(addr); - *ptr = value; - return; -#else - if ((addr & 1) == 0) { + if (FLAG_enable_unaligned_accesses || (addr & 1) == 0) { int16_t* ptr = reinterpret_cast<int16_t*>(addr); *ptr = value; - return; + } else { + PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", + addr, + reinterpret_cast<intptr_t>(instr)); + UNIMPLEMENTED(); } - PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", - addr, - reinterpret_cast<intptr_t>(instr)); - UNIMPLEMENTED(); -#endif } @@ -1199,37 +1171,26 @@ void Simulator::WriteB(int32_t addr, int8_t value) { int32_t* Simulator::ReadDW(int32_t addr) { -#if V8_TARGET_CAN_READ_UNALIGNED - int32_t* ptr = reinterpret_cast<int32_t*>(addr); - return ptr; -#else - if ((addr & 3) == 0) { + if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) { int32_t* ptr = reinterpret_cast<int32_t*>(addr); return ptr; + } else { + PrintF("Unaligned read at 0x%08x\n", addr); + UNIMPLEMENTED(); + return 0; } - PrintF("Unaligned read at 0x%08x\n", addr); - UNIMPLEMENTED(); - return 0; -#endif } void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) { -#if V8_TARGET_CAN_READ_UNALIGNED - int32_t* ptr = reinterpret_cast<int32_t*>(addr); - *ptr++ = value1; - *ptr = value2; - return; -#else - if ((addr & 3) == 0) { + if (FLAG_enable_unaligned_accesses || (addr & 3) == 0) { int32_t* ptr = reinterpret_cast<int32_t*>(addr); *ptr++ = value1; *ptr = value2; - return; + } else { + PrintF("Unaligned write at 0x%08x\n", addr); + UNIMPLEMENTED(); } - PrintF("Unaligned write at 0x%08x\n", addr); - UNIMPLEMENTED(); -#endif } @@ -1426,7 +1387,14 @@ int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) { } case ROR: { - UNIMPLEMENTED(); + if (shift_amount == 0) { + *carry_out = c_flag_; + } else { + uint32_t left = static_cast<uint32_t>(result) >> shift_amount; + uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount); + result = right | left; + *carry_out = (static_cast<uint32_t>(result) >> 31) != 0; + } break; } @@ -1498,7 +1466,14 @@ int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) { } case ROR: { - UNIMPLEMENTED(); + if (shift_amount == 0) { + *carry_out = c_flag_; + } else { + uint32_t left = static_cast<uint32_t>(result) >> shift_amount; + uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount); + result = right | left; + *carry_out = (static_cast<uint32_t>(result) >> 31) != 0; + } break; } @@ -1986,11 +1961,23 @@ void Simulator::DecodeType01(Instruction* instr) { SetNZFlags(alu_out); } } else { - // The MLA instruction description (A 4.1.28) refers to the order - // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the - // Rn field to encode the Rd register and the Rd field to encode - // the Rn register. - Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd"); + int rd = instr->RdValue(); + int32_t acc_value = get_register(rd); + if (instr->Bit(22) == 0) { + // The MLA instruction description (A 4.1.28) refers to the order + // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the + // Rn field to encode the Rd register and the Rd field to encode + // the Rn register. + // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd"); + int32_t mul_out = rm_val * rs_val; + int32_t result = acc_value + mul_out; + set_register(rn, result); + } else { + // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd"); + int32_t mul_out = rm_val * rs_val; + int32_t result = acc_value - mul_out; + set_register(rn, result); + } } } else { // The signed/long multiply instructions use the terms RdHi and RdLo @@ -2210,6 +2197,8 @@ void Simulator::DecodeType01(Instruction* instr) { PrintF("%08x\n", instr->InstructionBits()); UNIMPLEMENTED(); } + } else if ((type == 1) && instr->IsNopType1()) { + // NOP. } else { int rd = instr->RdValue(); int rn = instr->RnValue(); @@ -2546,6 +2535,25 @@ void Simulator::DecodeType3(Instruction* instr) { break; } case db_x: { + if (FLAG_enable_sudiv) { + if (!instr->HasW()) { + if (instr->Bits(5, 4) == 0x1) { + if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) { + // sdiv (in V8 notation matching ARM ISA format) rn = rm/rs + // Format(instr, "'sdiv'cond'b 'rn, 'rm, 'rs); + int rm = instr->RmValue(); + int32_t rm_val = get_register(rm); + int rs = instr->RsValue(); + int32_t rs_val = get_register(rs); + int32_t ret_val = 0; + ASSERT(rs_val != 0); + ret_val = rm_val/rs_val; + set_register(rn, ret_val); + return; + } + } + } + } // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w"); addr = rn_val - shifter_operand; if (instr->HasW()) { @@ -2770,6 +2778,20 @@ void Simulator::DecodeTypeVFP(Instruction* instr) { double dm_value = get_double_from_d_register(vm); double dd_value = dn_value * dm_value; set_d_register_from_double(vd, dd_value); + } else if ((instr->Opc1Value() == 0x0) && !(instr->Opc3Value() & 0x1)) { + // vmla + if (instr->SzValue() != 0x1) { + UNREACHABLE(); // Not used by V8. + } + + double dd_value = get_double_from_d_register(vd); + double dn_value = get_double_from_d_register(vn); + double dm_value = get_double_from_d_register(vm); + + // Note: we do the mul and add in separate steps to avoid getting a result + // with too high precision. + set_d_register_from_double(vd, dn_value * dm_value); + set_d_register_from_double(vd, get_double_from_d_register(vd) + dd_value); } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) { // vdiv if (instr->SzValue() != 0x1) { @@ -3279,33 +3301,7 @@ void Simulator::Execute() { } -int32_t Simulator::Call(byte* entry, int argument_count, ...) { - va_list parameters; - va_start(parameters, argument_count); - // Set up arguments - - // First four arguments passed in registers. - ASSERT(argument_count >= 4); - set_register(r0, va_arg(parameters, int32_t)); - set_register(r1, va_arg(parameters, int32_t)); - set_register(r2, va_arg(parameters, int32_t)); - set_register(r3, va_arg(parameters, int32_t)); - - // Remaining arguments passed on stack. - int original_stack = get_register(sp); - // Compute position of stack on entry to generated code. - int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)); - if (OS::ActivationFrameAlignment() != 0) { - entry_stack &= -OS::ActivationFrameAlignment(); - } - // Store remaining arguments on stack, from low to high memory. - intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); - for (int i = 4; i < argument_count; i++) { - stack_argument[i - 4] = va_arg(parameters, int32_t); - } - va_end(parameters); - set_register(sp, entry_stack); - +void Simulator::CallInternal(byte* entry) { // Prepare to execute the code at entry set_register(pc, reinterpret_cast<int32_t>(entry)); // Put down marker for end of simulation. The simulator will stop simulation @@ -3359,6 +3355,37 @@ int32_t Simulator::Call(byte* entry, int argument_count, ...) { set_register(r9, r9_val); set_register(r10, r10_val); set_register(r11, r11_val); +} + + +int32_t Simulator::Call(byte* entry, int argument_count, ...) { + va_list parameters; + va_start(parameters, argument_count); + // Set up arguments + + // First four arguments passed in registers. + ASSERT(argument_count >= 4); + set_register(r0, va_arg(parameters, int32_t)); + set_register(r1, va_arg(parameters, int32_t)); + set_register(r2, va_arg(parameters, int32_t)); + set_register(r3, va_arg(parameters, int32_t)); + + // Remaining arguments passed on stack. + int original_stack = get_register(sp); + // Compute position of stack on entry to generated code. + int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)); + if (OS::ActivationFrameAlignment() != 0) { + entry_stack &= -OS::ActivationFrameAlignment(); + } + // Store remaining arguments on stack, from low to high memory. + intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); + for (int i = 4; i < argument_count; i++) { + stack_argument[i - 4] = va_arg(parameters, int32_t); + } + va_end(parameters); + set_register(sp, entry_stack); + + CallInternal(entry); // Pop stack passed arguments. CHECK_EQ(entry_stack, get_register(sp)); @@ -3369,6 +3396,27 @@ int32_t Simulator::Call(byte* entry, int argument_count, ...) { } +double Simulator::CallFP(byte* entry, double d0, double d1) { + if (use_eabi_hardfloat()) { + set_d_register_from_double(0, d0); + set_d_register_from_double(1, d1); + } else { + int buffer[2]; + ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0)); + memcpy(buffer, &d0, sizeof(d0)); + set_dw_register(0, buffer); + memcpy(buffer, &d1, sizeof(d1)); + set_dw_register(2, buffer); + } + CallInternal(entry); + if (use_eabi_hardfloat()) { + return get_double_from_d_register(0); + } else { + return get_double_from_register_pair(0); + } +} + + uintptr_t Simulator::PushAddress(uintptr_t address) { int new_sp = get_register(sp) - sizeof(uintptr_t); uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp); diff --git a/deps/v8/src/arm/simulator-arm.h b/deps/v8/src/arm/simulator-arm.h index abc91bbc42..ec47fa1f1c 100644 --- a/deps/v8/src/arm/simulator-arm.h +++ b/deps/v8/src/arm/simulator-arm.h @@ -205,6 +205,8 @@ class Simulator { // generated RegExp code with 7 parameters. This is a convenience function, // which sets up the simulator state and grabs the result on return. int32_t Call(byte* entry, int argument_count, ...); + // Alternative: call a 2-argument double function. + double CallFP(byte* entry, double d0, double d1); // Push an address onto the JS stack. uintptr_t PushAddress(uintptr_t address); @@ -356,6 +358,8 @@ class Simulator { template<class InputType, int register_size> void SetVFPRegister(int reg_index, const InputType& value); + void CallInternal(byte* entry); + // Architecture state. // Saturating instructions require a Q flag to indicate saturation. // There is currently no way to read the CPSR directly, and thus read the Q diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 66714f8e44..a194dfae5b 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -327,18 +327,23 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, Register dst, Register src, Handle<JSObject> holder, - int index) { - // Adjust for the number of properties stored in the holder. - index -= holder->map()->inobject_properties(); - if (index < 0) { - // Get the property straight out of the holder. - int offset = holder->map()->instance_size() + (index * kPointerSize); + PropertyIndex index) { + if (index.is_header_index()) { + int offset = index.header_index() * kPointerSize; __ ldr(dst, FieldMemOperand(src, offset)); } else { - // Calculate the offset into the properties array. - int offset = index * kPointerSize + FixedArray::kHeaderSize; - __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset)); - __ ldr(dst, FieldMemOperand(dst, offset)); + // Adjust for the number of properties stored in the holder. + int slot = index.field_index() - holder->map()->inobject_properties(); + if (slot < 0) { + // Get the property straight out of the holder. + int offset = holder->map()->instance_size() + (slot * kPointerSize); + __ ldr(dst, FieldMemOperand(src, offset)); + } else { + // Calculate the offset into the properties array. + int offset = slot * kPointerSize + FixedArray::kHeaderSize; + __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset)); + __ ldr(dst, FieldMemOperand(dst, offset)); + } } } @@ -1196,7 +1201,7 @@ void StubCompiler::GenerateLoadField(Handle<JSObject> object, Register scratch1, Register scratch2, Register scratch3, - int index, + PropertyIndex index, Handle<String> name, Label* miss) { // Check that the receiver isn't a smi. @@ -1545,7 +1550,7 @@ void CallStubCompiler::GenerateMissBranch() { Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name) { // ----------- S t a t e ------------- // -- r2 : name @@ -1618,7 +1623,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( Label call_builtin; if (argc == 1) { // Otherwise fall through to call the builtin. - Label attempt_to_grow_elements; + Label attempt_to_grow_elements, with_write_barrier, check_double; Register elements = r6; Register end_elements = r5; @@ -1629,10 +1634,9 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( __ CheckMap(elements, r0, Heap::kFixedArrayMapRootIndex, - &call_builtin, + &check_double, DONT_DO_SMI_CHECK); - // Get the array's length into r0 and calculate new length. __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); STATIC_ASSERT(kSmiTagSize == 1); @@ -1647,7 +1651,6 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( __ b(gt, &attempt_to_grow_elements); // Check if value is a smi. - Label with_write_barrier; __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); __ JumpIfNotSmi(r4, &with_write_barrier); @@ -1667,6 +1670,40 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( __ Drop(argc + 1); __ Ret(); + __ bind(&check_double); + + // Check that the elements are in fast mode and writable. + __ CheckMap(elements, + r0, + Heap::kFixedDoubleArrayMapRootIndex, + &call_builtin, + DONT_DO_SMI_CHECK); + + // Get the array's length into r0 and calculate new length. + __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); + STATIC_ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0); + __ add(r0, r0, Operand(Smi::FromInt(argc))); + + // Get the elements' length. + __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); + + // Check if we could survive without allocation. + __ cmp(r0, r4); + __ b(gt, &call_builtin); + + __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); + __ StoreNumberToDoubleElements( + r4, r0, elements, r3, r5, r2, r9, + &call_builtin, argc * kDoubleSize); + + // Save new length. + __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); + + // Check for a smi. + __ Drop(argc + 1); + __ Ret(); + __ bind(&with_write_barrier); __ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset)); @@ -1678,6 +1715,11 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( // In case of fast smi-only, convert to fast object, otherwise bail out. __ bind(¬_fast_object); __ CheckFastSmiElements(r3, r7, &call_builtin); + + __ ldr(r7, FieldMemOperand(r4, HeapObject::kMapOffset)); + __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); + __ cmp(r7, ip); + __ b(eq, &call_builtin); // edx: receiver // r3: map Label try_holey_map; @@ -2912,7 +2954,7 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name, Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name) { // ----------- S t a t e ------------- // -- r0 : receiver @@ -3101,7 +3143,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal( Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name, Handle<JSObject> receiver, Handle<JSObject> holder, - int index) { + PropertyIndex index) { // ----------- S t a t e ------------- // -- lr : return address // -- r0 : key @@ -3467,7 +3509,13 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( // r1: constructor function // r2: initial map // r7: undefined + ASSERT(function->has_initial_map()); __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset)); +#ifdef DEBUG + int instance_size = function->initial_map()->instance_size(); + __ cmp(r3, Operand(instance_size >> kPointerSizeLog2)); + __ Check(eq, "Instance size of initial map changed."); +#endif __ AllocateInNewSpace(r3, r4, r5, r6, &generic_stub_call, SIZE_IN_WORDS); // Allocated the JSObject, now initialize the fields. Map is set to initial @@ -3525,7 +3573,6 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( } // Fill the unused in-object property fields with undefined. - ASSERT(function->has_initial_map()); for (int i = shared->this_property_assignments_count(); i < function->initial_map()->inobject_properties(); i++) { @@ -3646,6 +3693,7 @@ static void GenerateSmiKeyCheck(MacroAssembler* masm, Register scratch0, Register scratch1, DwVfpRegister double_scratch0, + DwVfpRegister double_scratch1, Label* fail) { if (CpuFeatures::IsSupported(VFP2)) { CpuFeatures::Scope scope(VFP2); @@ -3662,13 +3710,12 @@ static void GenerateSmiKeyCheck(MacroAssembler* masm, __ sub(ip, key, Operand(kHeapObjectTag)); __ vldr(double_scratch0, ip, HeapNumber::kValueOffset); __ EmitVFPTruncate(kRoundToZero, - double_scratch0.low(), - double_scratch0, scratch0, + double_scratch0, scratch1, + double_scratch1, kCheckForInexactConversion); __ b(ne, fail); - __ vmov(scratch0, double_scratch0.low()); __ TrySmiTag(scratch0, fail, scratch1); __ mov(key, scratch0); __ bind(&key_ok); @@ -3696,7 +3743,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // have been verified by the caller to not be a smi. // Check that the key is a smi or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, key, r4, r5, d1, &miss_force_generic); + GenerateSmiKeyCheck(masm, key, r4, r5, d1, d2, &miss_force_generic); __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); // r3: elements array @@ -3787,36 +3834,42 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ Ret(); __ bind(&box_int); - // Allocate a HeapNumber for the result and perform int-to-double - // conversion. Don't touch r0 or r1 as they are needed if allocation - // fails. - __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(r5, r3, r4, r6, &slow); - // Now we can use r0 for the result as key is not needed any more. - __ mov(r0, r5); - if (CpuFeatures::IsSupported(VFP2)) { CpuFeatures::Scope scope(VFP2); + // Allocate a HeapNumber for the result and perform int-to-double + // conversion. Don't touch r0 or r1 as they are needed if allocation + // fails. + __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); + + __ AllocateHeapNumber(r5, r3, r4, r6, &slow, DONT_TAG_RESULT); + // Now we can use r0 for the result as key is not needed any more. + __ add(r0, r5, Operand(kHeapObjectTag)); __ vmov(s0, value); __ vcvt_f64_s32(d0, s0); - __ sub(r3, r0, Operand(kHeapObjectTag)); - __ vstr(d0, r3, HeapNumber::kValueOffset); + __ vstr(d0, r5, HeapNumber::kValueOffset); __ Ret(); } else { - Register dst1 = r1; - Register dst2 = r3; + // Allocate a HeapNumber for the result and perform int-to-double + // conversion. Don't touch r0 or r1 as they are needed if allocation + // fails. + __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); + __ AllocateHeapNumber(r5, r3, r4, r6, &slow, TAG_RESULT); + // Now we can use r0 for the result as key is not needed any more. + __ mov(r0, r5); + Register dst_mantissa = r1; + Register dst_exponent = r3; FloatingPointHelper::Destination dest = FloatingPointHelper::kCoreRegisters; FloatingPointHelper::ConvertIntToDouble(masm, value, dest, d0, - dst1, - dst2, + dst_mantissa, + dst_exponent, r9, s0); - __ str(dst1, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); - __ str(dst2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); + __ str(dst_mantissa, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); + __ str(dst_exponent, FieldMemOperand(r0, HeapNumber::kExponentOffset)); __ Ret(); } } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { @@ -3838,13 +3891,12 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // conversion. Don't use r0 and r1 as AllocateHeapNumber clobbers all // registers - also when jumping due to exhausted young space. __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(r2, r3, r4, r6, &slow); + __ AllocateHeapNumber(r2, r3, r4, r6, &slow, DONT_TAG_RESULT); __ vcvt_f64_u32(d0, s0); - __ sub(r1, r2, Operand(kHeapObjectTag)); - __ vstr(d0, r1, HeapNumber::kValueOffset); + __ vstr(d0, r2, HeapNumber::kValueOffset); - __ mov(r0, r2); + __ add(r0, r2, Operand(kHeapObjectTag)); __ Ret(); } else { // Check whether unsigned integer fits into smi. @@ -3876,7 +3928,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // clobbers all registers - also when jumping due to exhausted young // space. __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(r4, r5, r7, r6, &slow); + __ AllocateHeapNumber(r4, r5, r7, r6, &slow, TAG_RESULT); __ str(hiword, FieldMemOperand(r4, HeapNumber::kExponentOffset)); __ str(loword, FieldMemOperand(r4, HeapNumber::kMantissaOffset)); @@ -3893,19 +3945,18 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // AllocateHeapNumber clobbers all registers - also when jumping due to // exhausted young space. __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(r2, r3, r4, r6, &slow); + __ AllocateHeapNumber(r2, r3, r4, r6, &slow, DONT_TAG_RESULT); __ vcvt_f64_f32(d0, s0); - __ sub(r1, r2, Operand(kHeapObjectTag)); - __ vstr(d0, r1, HeapNumber::kValueOffset); + __ vstr(d0, r2, HeapNumber::kValueOffset); - __ mov(r0, r2); + __ add(r0, r2, Operand(kHeapObjectTag)); __ Ret(); } else { // Allocate a HeapNumber for the result. Don't use r0 and r1 as // AllocateHeapNumber clobbers all registers - also when jumping due to // exhausted young space. __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(r3, r4, r5, r6, &slow); + __ AllocateHeapNumber(r3, r4, r5, r6, &slow, TAG_RESULT); // VFP is not available, do manual single to double conversion. // r2: floating point value (binary32) @@ -3961,18 +4012,17 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // AllocateHeapNumber clobbers all registers - also when jumping due to // exhausted young space. __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(r2, r3, r4, r6, &slow); - __ sub(r1, r2, Operand(kHeapObjectTag)); - __ vstr(d0, r1, HeapNumber::kValueOffset); + __ AllocateHeapNumber(r2, r3, r4, r6, &slow, DONT_TAG_RESULT); + __ vstr(d0, r2, HeapNumber::kValueOffset); - __ mov(r0, r2); + __ add(r0, r2, Operand(kHeapObjectTag)); __ Ret(); } else { // Allocate a HeapNumber for the result. Don't use r0 and r1 as // AllocateHeapNumber clobbers all registers - also when jumping due to // exhausted young space. __ LoadRoot(r7, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(r4, r5, r6, r7, &slow); + __ AllocateHeapNumber(r4, r5, r6, r7, &slow, TAG_RESULT); __ str(r2, FieldMemOperand(r4, HeapNumber::kMantissaOffset)); __ str(r3, FieldMemOperand(r4, HeapNumber::kExponentOffset)); @@ -4030,7 +4080,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // have been verified by the caller to not be a smi. // Check that the key is a smi or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, key, r4, r5, d1, &miss_force_generic); + GenerateSmiKeyCheck(masm, key, r4, r5, d1, d2, &miss_force_generic); __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); @@ -4088,7 +4138,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( } FloatingPointHelper::ConvertIntToDouble( masm, r5, destination, - d0, r6, r7, // These are: double_dst, dst1, dst2. + d0, r6, r7, // These are: double_dst, dst_mantissa, dst_exponent. r4, s2); // These are: scratch2, single_scratch. if (destination == FloatingPointHelper::kVFPRegisters) { CpuFeatures::Scope scope(VFP2); @@ -4147,7 +4197,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // not include -kHeapObjectTag into it. __ sub(r5, value, Operand(kHeapObjectTag)); __ vldr(d0, r5, HeapNumber::kValueOffset); - __ EmitECMATruncate(r5, d0, s2, r6, r7, r9); + __ EmitECMATruncate(r5, d0, d1, r6, r7, r9); switch (elements_kind) { case EXTERNAL_BYTE_ELEMENTS: @@ -4365,7 +4415,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { // have been verified by the caller to not be a smi. // Check that the key is a smi or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, r0, r4, r5, d1, &miss_force_generic); + GenerateSmiKeyCheck(masm, r0, r4, r5, d1, d2, &miss_force_generic); // Get the elements array. __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset)); @@ -4417,7 +4467,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( // have been verified by the caller to not be a smi. // 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); + GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, d2, &miss_force_generic); // Get the elements array. __ ldr(elements_reg, @@ -4439,7 +4489,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( // Non-NaN. Allocate a new heap number and copy the double value into it. __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3, - heap_number_map, &slow_allocate_heapnumber); + heap_number_map, &slow_allocate_heapnumber, TAG_RESULT); // Don't need to reload the upper 32 bits of the double, it's already in // scratch. @@ -4493,7 +4543,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( // have been verified by the caller to not be a smi. // 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); + GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, d2, &miss_force_generic); if (IsFastSmiElementsKind(elements_kind)) { __ JumpIfNotSmi(value_reg, &transition_elements_kind); @@ -4640,9 +4690,12 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // -- r1 : key // -- r2 : receiver // -- lr : return address - // -- r3 : scratch + // -- r3 : scratch (elements backing store) // -- r4 : scratch // -- r5 : scratch + // -- r6 : scratch + // -- r7 : scratch + // -- r9 : scratch // ----------------------------------- Label miss_force_generic, transition_elements_kind, grow, slow; Label finish_store, check_capacity; @@ -4655,13 +4708,14 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( Register scratch2 = r5; Register scratch3 = r6; Register scratch4 = r7; + Register scratch5 = r9; Register length_reg = r7; // 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 or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, &miss_force_generic); + GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, d2, &miss_force_generic); __ ldr(elements_reg, FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); @@ -4685,7 +4739,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ bind(&finish_store); __ StoreNumberToDoubleElements(value_reg, key_reg, - receiver_reg, + // All registers after this are overwritten. elements_reg, scratch1, scratch2, @@ -4733,8 +4787,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT); - // Initialize the new FixedDoubleArray. Leave elements unitialized for - // efficiency, they are guaranteed to be initialized before use. + // Initialize the new FixedDoubleArray. __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex); __ str(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset)); __ mov(scratch1, @@ -4742,6 +4795,25 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ str(scratch1, FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset)); + __ mov(scratch1, elements_reg); + __ StoreNumberToDoubleElements(value_reg, + key_reg, + // All registers after this are overwritten. + scratch1, + scratch2, + scratch3, + scratch4, + scratch5, + &transition_elements_kind); + + __ mov(scratch1, Operand(kHoleNanLower32)); + __ mov(scratch2, Operand(kHoleNanUpper32)); + for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { + int offset = FixedDoubleArray::OffsetOfElementAt(i); + __ str(scratch1, FieldMemOperand(elements_reg, offset)); + __ str(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize)); + } + // Install the new backing store in the JSArray. __ str(elements_reg, FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); @@ -4754,7 +4826,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); __ ldr(elements_reg, FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); - __ jmp(&finish_store); + __ Ret(); __ bind(&check_capacity); // Make sure that the backing store can hold additional elements. diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index 1cedd8d476..47f796d2b1 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -62,7 +62,7 @@ function GetSortedArrayKeys(array, intervals) { } } } - keys.sort(function(a, b) { return a - b; }); + %_CallFunction(keys, function(a, b) { return a - b; }, ArraySort); return keys; } @@ -413,6 +413,7 @@ function ArrayJoin(separator) { ["Array.prototype.join"]); } + var length = TO_UINT32(this.length); if (IS_UNDEFINED(separator)) { separator = ','; } else if (!IS_STRING(separator)) { @@ -422,7 +423,7 @@ function ArrayJoin(separator) { var result = %_FastAsciiArrayJoin(this, separator); if (!IS_UNDEFINED(result)) return result; - return Join(this, TO_UINT32(this.length), separator, ConvertToString); + return Join(this, length, separator, ConvertToString); } @@ -441,8 +442,8 @@ function ArrayPop() { } n--; var value = this[n]; - this.length = n; delete this[n]; + this.length = n; return value; } @@ -581,7 +582,7 @@ function ArrayShift() { var first = this[0]; - if (IS_ARRAY(this)) { + if (IS_ARRAY(this) && !%IsObserved(this)) { SmartMove(this, 0, 1, len, 0); } else { SimpleMove(this, 0, 1, len, 0); @@ -602,7 +603,7 @@ function ArrayUnshift(arg1) { // length == 1 var len = TO_UINT32(this.length); var num_arguments = %_ArgumentsLength(); - if (IS_ARRAY(this)) { + if (IS_ARRAY(this) && !%IsObserved(this)) { SmartMove(this, 0, 0, len, num_arguments); } else { SimpleMove(this, 0, 0, len, num_arguments); @@ -649,6 +650,7 @@ function ArraySlice(start, end) { if (end_i < start_i) return result; if (IS_ARRAY(this) && + !%IsObserved(this) && (end_i > 1000) && (%EstimateNumberOfElements(this) < end_i)) { SmartSlice(this, start_i, end_i - start_i, len, result); @@ -705,7 +707,9 @@ function ArraySplice(start, delete_count) { var use_simple_splice = true; - if (IS_ARRAY(this) && num_additional_args !== del_count) { + if (IS_ARRAY(this) && + !%IsObserved(this) && + num_additional_args !== del_count) { // If we are only deleting/moving a few things near the end of the // array then the simple version is going to be faster, because it // doesn't touch most of the array. @@ -1549,9 +1553,11 @@ function SetUpArray() { // exposed to user code. // Adding only the functions that are actually used. SetUpLockedPrototype(InternalArray, $Array(), $Array( + "indexOf", getFunction("indexOf", ArrayIndexOf), "join", getFunction("join", ArrayJoin), "pop", getFunction("pop", ArrayPop), - "push", getFunction("push", ArrayPush) + "push", getFunction("push", ArrayPush), + "splice", getFunction("splice", ArraySplice) )); } diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index a58f77f74b..25157be2eb 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -103,15 +103,78 @@ static DoubleConstant double_constants; const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING"; +static bool math_exp_data_initialized = false; +static Mutex* math_exp_data_mutex = NULL; +static double* math_exp_constants_array = NULL; +static double* math_exp_log_table_array = NULL; + // ----------------------------------------------------------------------------- // Implementation of AssemblerBase -AssemblerBase::AssemblerBase(Isolate* isolate) +AssemblerBase::AssemblerBase(Isolate* isolate, void* buffer, int buffer_size) : isolate_(isolate), - jit_cookie_(0) { + jit_cookie_(0), + emit_debug_code_(FLAG_debug_code), + predictable_code_size_(false) { if (FLAG_mask_constants_with_cookie && isolate != NULL) { jit_cookie_ = V8::RandomPrivate(isolate); } + + if (buffer == NULL) { + // Do our own buffer management. + if (buffer_size <= kMinimalBufferSize) { + buffer_size = kMinimalBufferSize; + if (isolate->assembler_spare_buffer() != NULL) { + buffer = isolate->assembler_spare_buffer(); + isolate->set_assembler_spare_buffer(NULL); + } + } + if (buffer == NULL) buffer = NewArray<byte>(buffer_size); + own_buffer_ = true; + } else { + // Use externally provided buffer instead. + ASSERT(buffer_size > 0); + own_buffer_ = false; + } + buffer_ = static_cast<byte*>(buffer); + buffer_size_ = buffer_size; + + pc_ = buffer_; +} + + +AssemblerBase::~AssemblerBase() { + if (own_buffer_) { + if (isolate() != NULL && + isolate()->assembler_spare_buffer() == NULL && + buffer_size_ == kMinimalBufferSize) { + isolate()->set_assembler_spare_buffer(buffer_); + } else { + DeleteArray(buffer_); + } + } +} + + +// ----------------------------------------------------------------------------- +// Implementation of PredictableCodeSizeScope + +PredictableCodeSizeScope::PredictableCodeSizeScope(AssemblerBase* assembler, + int expected_size) + : assembler_(assembler), + expected_size_(expected_size), + start_offset_(assembler->pc_offset()), + old_value_(assembler->predictable_code_size()) { + assembler_->set_predictable_code_size(true); +} + + +PredictableCodeSizeScope::~PredictableCodeSizeScope() { + // TODO(svenpanne) Remove the 'if' when everything works. + if (expected_size_ >= 0) { + CHECK_EQ(expected_size_, assembler_->pc_offset() - start_offset_); + } + assembler_->set_predictable_code_size(old_value_); } @@ -313,6 +376,7 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) { #ifdef DEBUG byte* begin_pos = pos_; #endif + ASSERT(rinfo->rmode() < RelocInfo::NUMBER_OF_MODES); ASSERT(rinfo->pc() - last_pc_ >= 0); ASSERT(RelocInfo::LAST_STANDARD_NONCOMPACT_ENUM - RelocInfo::LAST_COMPACT_ENUM <= kMaxStandardNonCompactModes); @@ -570,6 +634,15 @@ void RelocIterator::next() { } } } + if (code_age_sequence_ != NULL) { + byte* old_code_age_sequence = code_age_sequence_; + code_age_sequence_ = NULL; + if (SetMode(RelocInfo::CODE_AGE_SEQUENCE)) { + rinfo_.data_ = 0; + rinfo_.pc_ = old_code_age_sequence; + return; + } + } done_ = true; } @@ -585,6 +658,12 @@ RelocIterator::RelocIterator(Code* code, int mode_mask) { mode_mask_ = mode_mask; last_id_ = 0; last_position_ = 0; + byte* sequence = code->FindCodeAgeSequence(); + if (sequence != NULL && !Code::IsYoungSequence(sequence)) { + code_age_sequence_ = sequence; + } else { + code_age_sequence_ = NULL; + } if (mode_mask_ == 0) pos_ = end_; next(); } @@ -600,6 +679,7 @@ RelocIterator::RelocIterator(const CodeDesc& desc, int mode_mask) { mode_mask_ = mode_mask; last_id_ = 0; last_position_ = 0; + code_age_sequence_ = NULL; if (mode_mask_ == 0) pos_ = end_; next(); } @@ -652,6 +732,8 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) { UNREACHABLE(); #endif return "debug break slot"; + case RelocInfo::CODE_AGE_SEQUENCE: + return "code_age_sequence"; case RelocInfo::NUMBER_OF_MODES: UNREACHABLE(); return "number_of_modes"; @@ -697,7 +779,7 @@ void RelocInfo::Print(FILE* out) { #endif // ENABLE_DISASSEMBLER -#ifdef DEBUG +#ifdef VERIFY_HEAP void RelocInfo::Verify() { switch (rmode_) { case EMBEDDED_OBJECT: @@ -717,12 +799,12 @@ void RelocInfo::Verify() { case CODE_TARGET: { // convert inline target address to code object Address addr = target_address(); - ASSERT(addr != NULL); + CHECK(addr != NULL); // Check that we can find the right code object. Code* code = Code::GetCodeFromTargetAddress(addr); Object* found = HEAP->FindCodeObject(addr); - ASSERT(found->IsCode()); - ASSERT(code->address() == HeapObject::cast(found)->address()); + CHECK(found->IsCode()); + CHECK(code->address() == HeapObject::cast(found)->address()); break; } case RUNTIME_ENTRY: @@ -739,9 +821,12 @@ void RelocInfo::Verify() { case NUMBER_OF_MODES: UNREACHABLE(); break; + case CODE_AGE_SEQUENCE: + ASSERT(Code::IsYoungSequence(pc_) || code_age_stub()->IsCode()); + break; } } -#endif // DEBUG +#endif // VERIFY_HEAP // ----------------------------------------------------------------------------- @@ -756,6 +841,70 @@ void ExternalReference::SetUp() { double_constants.canonical_non_hole_nan = OS::nan_value(); double_constants.the_hole_nan = BitCast<double>(kHoleNanInt64); double_constants.negative_infinity = -V8_INFINITY; + + math_exp_data_mutex = OS::CreateMutex(); +} + + +void ExternalReference::InitializeMathExpData() { + // Early return? + if (math_exp_data_initialized) return; + + math_exp_data_mutex->Lock(); + if (!math_exp_data_initialized) { + // If this is changed, generated code must be adapted too. + const int kTableSizeBits = 11; + const int kTableSize = 1 << kTableSizeBits; + const double kTableSizeDouble = static_cast<double>(kTableSize); + + math_exp_constants_array = new double[9]; + // Input values smaller than this always return 0. + math_exp_constants_array[0] = -708.39641853226408; + // Input values larger than this always return +Infinity. + math_exp_constants_array[1] = 709.78271289338397; + math_exp_constants_array[2] = V8_INFINITY; + // The rest is black magic. Do not attempt to understand it. It is + // loosely based on the "expd" function published at: + // http://herumi.blogspot.com/2011/08/fast-double-precision-exponential.html + const double constant3 = (1 << kTableSizeBits) / log(2.0); + math_exp_constants_array[3] = constant3; + math_exp_constants_array[4] = + static_cast<double>(static_cast<int64_t>(3) << 51); + math_exp_constants_array[5] = 1 / constant3; + math_exp_constants_array[6] = 3.0000000027955394; + math_exp_constants_array[7] = 0.16666666685227835; + math_exp_constants_array[8] = 1; + + math_exp_log_table_array = new double[kTableSize]; + for (int i = 0; i < kTableSize; i++) { + double value = pow(2, i / kTableSizeDouble); + + uint64_t bits = BitCast<uint64_t, double>(value); + bits &= (static_cast<uint64_t>(1) << 52) - 1; + double mantissa = BitCast<double, uint64_t>(bits); + + // <just testing> + uint64_t doublebits; + memcpy(&doublebits, &value, sizeof doublebits); + doublebits &= (static_cast<uint64_t>(1) << 52) - 1; + double mantissa2; + memcpy(&mantissa2, &doublebits, sizeof mantissa2); + CHECK_EQ(mantissa, mantissa2); + // </just testing> + + math_exp_log_table_array[i] = mantissa; + } + + math_exp_data_initialized = true; + } + math_exp_data_mutex->Unlock(); +} + + +void ExternalReference::TearDownMathExpData() { + delete[] math_exp_constants_array; + delete[] math_exp_log_table_array; + delete math_exp_data_mutex; } @@ -874,6 +1023,13 @@ ExternalReference ExternalReference::get_date_field_function( } +ExternalReference ExternalReference::get_make_code_young_function( + Isolate* isolate) { + return ExternalReference(Redirect( + isolate, FUNCTION_ADDR(Code::MakeCodeAgeSequenceYoung))); +} + + ExternalReference ExternalReference::date_cache_stamp(Isolate* isolate) { return ExternalReference(isolate->date_cache()->stamp_address()); } @@ -900,6 +1056,20 @@ ExternalReference ExternalReference::compute_output_frames_function( } +ExternalReference ExternalReference::log_enter_external_function( + Isolate* isolate) { + return ExternalReference( + Redirect(isolate, FUNCTION_ADDR(Logger::EnterExternal))); +} + + +ExternalReference ExternalReference::log_leave_external_function( + Isolate* isolate) { + return ExternalReference( + Redirect(isolate, FUNCTION_ADDR(Logger::LeaveExternal))); +} + + ExternalReference ExternalReference::keyed_lookup_cache_keys(Isolate* isolate) { return ExternalReference(isolate->keyed_lookup_cache()->keys_address()); } @@ -1186,6 +1356,19 @@ ExternalReference ExternalReference::math_log_double_function( } +ExternalReference ExternalReference::math_exp_constants(int constant_index) { + ASSERT(math_exp_data_initialized); + return ExternalReference( + reinterpret_cast<void*>(math_exp_constants_array + constant_index)); +} + + +ExternalReference ExternalReference::math_exp_log_table() { + ASSERT(math_exp_data_initialized); + return ExternalReference(reinterpret_cast<void*>(math_exp_log_table_array)); +} + + ExternalReference ExternalReference::page_flags(Page* page) { return ExternalReference(reinterpret_cast<Address>(page) + MemoryChunk::kFlagsOffset); diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index cb5a72d755..4639374c22 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -56,18 +56,56 @@ struct StatsCounter; class AssemblerBase: public Malloced { public: - explicit AssemblerBase(Isolate* isolate); + AssemblerBase(Isolate* isolate, void* buffer, int buffer_size); + virtual ~AssemblerBase(); Isolate* isolate() const { return isolate_; } - int jit_cookie() { return jit_cookie_; } + int jit_cookie() const { return jit_cookie_; } + + bool emit_debug_code() const { return emit_debug_code_; } + void set_emit_debug_code(bool value) { emit_debug_code_ = value; } + + bool predictable_code_size() const { return predictable_code_size_; } + void set_predictable_code_size(bool value) { predictable_code_size_ = value; } // Overwrite a host NaN with a quiet target NaN. Used by mksnapshot for // cross-snapshotting. static void QuietNaN(HeapObject* nan) { } + int pc_offset() const { return static_cast<int>(pc_ - buffer_); } + + static const int kMinimalBufferSize = 4*KB; + + protected: + // The buffer into which code and relocation info are generated. It could + // either be owned by the assembler or be provided externally. + byte* buffer_; + int buffer_size_; + bool own_buffer_; + + // The program counter, which points into the buffer above and moves forward. + byte* pc_; + private: Isolate* isolate_; int jit_cookie_; + bool emit_debug_code_; + bool predictable_code_size_; +}; + + +// Avoids using instructions that vary in size in unpredictable ways between the +// snapshot and the running VM. +class PredictableCodeSizeScope { + public: + PredictableCodeSizeScope(AssemblerBase* assembler, int expected_size); + ~PredictableCodeSizeScope(); + + private: + AssemblerBase* assembler_; + int expected_size_; + int start_offset_; + bool old_value_; }; @@ -211,6 +249,12 @@ class RelocInfo BASE_EMBEDDED { // Pseudo-types NUMBER_OF_MODES, // There are at most 15 modes with noncompact encoding. NONE, // never recorded + CODE_AGE_SEQUENCE, // Not stored in RelocInfo array, used explictly by + // code aging. + FIRST_REAL_RELOC_MODE = CODE_TARGET, + LAST_REAL_RELOC_MODE = CONST_POOL, + FIRST_PSEUDO_RELOC_MODE = CODE_AGE_SEQUENCE, + LAST_PSEUDO_RELOC_MODE = CODE_AGE_SEQUENCE, LAST_CODE_ENUM = DEBUG_BREAK, LAST_GCED_ENUM = GLOBAL_PROPERTY_CELL, // Modes <= LAST_COMPACT_ENUM are guaranteed to have compact encoding. @@ -225,6 +269,15 @@ class RelocInfo BASE_EMBEDDED { : pc_(pc), rmode_(rmode), data_(data), host_(host) { } + static inline bool IsRealRelocMode(Mode mode) { + return mode >= FIRST_REAL_RELOC_MODE && + mode <= LAST_REAL_RELOC_MODE; + } + static inline bool IsPseudoRelocMode(Mode mode) { + ASSERT(!IsRealRelocMode(mode)); + return mode >= FIRST_PSEUDO_RELOC_MODE && + mode <= LAST_PSEUDO_RELOC_MODE; + } static inline bool IsConstructCall(Mode mode) { return mode == CONSTRUCT_CALL; } @@ -262,6 +315,9 @@ class RelocInfo BASE_EMBEDDED { static inline bool IsDebugBreakSlot(Mode mode) { return mode == DEBUG_BREAK_SLOT; } + static inline bool IsCodeAgeSequence(Mode mode) { + return mode == CODE_AGE_SEQUENCE; + } static inline int ModeMask(Mode mode) { return 1 << mode; } // Accessors @@ -294,7 +350,8 @@ class RelocInfo BASE_EMBEDDED { INLINE(Handle<JSGlobalPropertyCell> target_cell_handle()); INLINE(void set_target_cell(JSGlobalPropertyCell* cell, WriteBarrierMode mode = UPDATE_WRITE_BARRIER)); - + INLINE(Code* code_age_stub()); + INLINE(void set_code_age_stub(Code* stub)); // Read the address of the word containing the target_address in an // instruction stream. What this means exactly is architecture-independent. @@ -349,8 +406,7 @@ class RelocInfo BASE_EMBEDDED { static const char* RelocModeName(Mode rmode); void Print(FILE* out); #endif // ENABLE_DISASSEMBLER -#ifdef DEBUG - // Debugging +#ifdef VERIFY_HEAP void Verify(); #endif @@ -369,19 +425,17 @@ class RelocInfo BASE_EMBEDDED { Mode rmode_; intptr_t data_; Code* host_; -#ifdef V8_TARGET_ARCH_MIPS - // Code and Embedded Object pointers in mips are stored split + // Code and Embedded Object pointers on some platforms are stored split // across two consecutive 32-bit instructions. Heap management // routines expect to access these pointers indirectly. The following - // location provides a place for these pointers to exist natually + // location provides a place for these pointers to exist naturally // when accessed via the Iterator. Object* reconstructed_obj_ptr_; // External-reference pointers are also split across instruction-pairs - // in mips, but are accessed via indirect pointers. This location + // on some platforms, but are accessed via indirect pointers. This location // provides a place for that pointer to exist naturally. Its address // is returned by RelocInfo::target_reference_address(). Address reconstructed_adr_ptr_; -#endif // V8_TARGET_ARCH_MIPS friend class RelocIterator; }; @@ -490,6 +544,7 @@ class RelocIterator: public Malloced { byte* pos_; byte* end_; + byte* code_age_sequence_; RelocInfo rinfo_; bool done_; int mode_mask_; @@ -549,6 +604,8 @@ class ExternalReference BASE_EMBEDDED { }; static void SetUp(); + static void InitializeMathExpData(); + static void TearDownMathExpData(); typedef void* ExternalReferenceRedirector(void* original, Type type); @@ -598,10 +655,16 @@ class ExternalReference BASE_EMBEDDED { static ExternalReference get_date_field_function(Isolate* isolate); static ExternalReference date_cache_stamp(Isolate* isolate); + static ExternalReference get_make_code_young_function(Isolate* isolate); + // Deoptimization support. static ExternalReference new_deoptimizer_function(Isolate* isolate); static ExternalReference compute_output_frames_function(Isolate* isolate); + // Log support. + static ExternalReference log_enter_external_function(Isolate* isolate); + static ExternalReference log_leave_external_function(Isolate* isolate); + // Static data in the keyed lookup cache. static ExternalReference keyed_lookup_cache_keys(Isolate* isolate); static ExternalReference keyed_lookup_cache_field_offsets(Isolate* isolate); @@ -668,6 +731,9 @@ class ExternalReference BASE_EMBEDDED { static ExternalReference math_tan_double_function(Isolate* isolate); static ExternalReference math_log_double_function(Isolate* isolate); + static ExternalReference math_exp_constants(int constant_index); + static ExternalReference math_exp_log_table(); + static ExternalReference page_flags(Page* page); Address address() const {return reinterpret_cast<Address>(address_);} diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 6b68705d27..232cb739a1 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -103,6 +103,7 @@ VariableProxy::VariableProxy(Isolate* isolate, void VariableProxy::BindTo(Variable* var) { ASSERT(var_ == NULL); // must be bound only once ASSERT(var != NULL); // must bind + ASSERT(!FLAG_harmony_modules || interface_->IsUnified(var->interface())); ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name())); // Ideally CONST-ness should match. However, this is very hard to achieve // because we don't know the exact semantics of conflicting (const and @@ -126,8 +127,6 @@ Assignment::Assignment(Isolate* isolate, pos_(pos), binary_operation_(NULL), assignment_id_(GetNextId(isolate)), - block_start_(false), - block_end_(false), is_monomorphic_(false) { } @@ -478,6 +477,7 @@ void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle, void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) { TypeInfo info = oracle->SwitchType(this); + if (info.IsUninitialized()) info = TypeInfo::Unknown(); if (info.IsSmi()) { compare_type_ = SMI_ONLY; } else if (info.IsSymbol()) { @@ -606,18 +606,6 @@ void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) { } -void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) { - TypeInfo info = oracle->CompareType(this); - if (info.IsSmi()) { - compare_type_ = SMI_ONLY; - } else if (info.IsNonPrimitive()) { - compare_type_ = OBJECT_ONLY; - } else { - ASSERT(compare_type_ == NONE); - } -} - - void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { receiver_type_ = oracle->ObjectLiteralStoreIsMonomorphic(this) ? oracle->GetObjectLiteralStoreMap(this) @@ -1072,16 +1060,14 @@ REGULAR_NODE(CallNew) // LOOKUP variables only result from constructs that cannot be inlined anyway. REGULAR_NODE(VariableProxy) -// We currently do not optimize any modules. Note in particular, that module -// instance objects associated with ModuleLiterals are allocated during -// scope resolution, and references to them are embedded into the code. -// That code may hence neither be cached nor re-compiled. +// We currently do not optimize any modules. DONT_OPTIMIZE_NODE(ModuleDeclaration) DONT_OPTIMIZE_NODE(ImportDeclaration) DONT_OPTIMIZE_NODE(ExportDeclaration) DONT_OPTIMIZE_NODE(ModuleVariable) DONT_OPTIMIZE_NODE(ModulePath) DONT_OPTIMIZE_NODE(ModuleUrl) +DONT_OPTIMIZE_NODE(ModuleStatement) DONT_OPTIMIZE_NODE(WithStatement) DONT_OPTIMIZE_NODE(TryCatchStatement) DONT_OPTIMIZE_NODE(TryFinallyStatement) diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index e72296cff7..d299f19a23 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -75,6 +75,7 @@ namespace internal { #define STATEMENT_NODE_LIST(V) \ V(Block) \ + V(ModuleStatement) \ V(ExpressionStatement) \ V(EmptyStatement) \ V(IfStatement) \ @@ -522,7 +523,7 @@ class ModuleDeclaration: public Declaration { ModuleDeclaration(VariableProxy* proxy, Module* module, Scope* scope) - : Declaration(proxy, LET, scope), + : Declaration(proxy, MODULE, scope), module_(module) { } @@ -645,6 +646,25 @@ class ModuleUrl: public Module { }; +class ModuleStatement: public Statement { + public: + DECLARE_NODE_TYPE(ModuleStatement) + + VariableProxy* proxy() const { return proxy_; } + Block* body() const { return body_; } + + protected: + ModuleStatement(VariableProxy* proxy, Block* body) + : proxy_(proxy), + body_(body) { + } + + private: + VariableProxy* proxy_; + Block* body_; +}; + + class IterationStatement: public BreakableStatement { public: // Type testing & conversion. @@ -1417,7 +1437,7 @@ class VariableProxy: public Expression { void MarkAsTrivial() { is_trivial_ = true; } void MarkAsLValue() { is_lvalue_ = true; } - // Bind this proxy to the variable var. + // Bind this proxy to the variable var. Interfaces must match. void BindTo(Variable* var); protected: @@ -1777,9 +1797,6 @@ class CompareOperation: public Expression { // Type feedback information. TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); } - void RecordTypeFeedback(TypeFeedbackOracle* oracle); - bool IsSmiCompare() { return compare_type_ == SMI_ONLY; } - bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; } // Match special cases. bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check); @@ -1796,8 +1813,7 @@ class CompareOperation: public Expression { op_(op), left_(left), right_(right), - pos_(pos), - compare_type_(NONE) { + pos_(pos) { ASSERT(Token::IsCompareOp(op)); } @@ -1806,9 +1822,6 @@ class CompareOperation: public Expression { Expression* left_; Expression* right_; int pos_; - - enum CompareTypeFeedback { NONE, SMI_ONLY, OBJECT_ONLY }; - CompareTypeFeedback compare_type_; }; @@ -1870,15 +1883,6 @@ class Assignment: public Expression { // This check relies on the definition order of token in token.h. bool is_compound() const { return op() > Token::ASSIGN; } - // An initialization block is a series of statments of the form - // x.y.z.a = ...; x.y.z.b = ...; etc. The parser marks the beginning and - // ending of these blocks to allow for optimizations of initialization - // blocks. - bool starts_initialization_block() { return block_start_; } - bool ends_initialization_block() { return block_end_; } - void mark_block_start() { block_start_ = true; } - void mark_block_end() { block_end_ = true; } - BailoutId AssignmentId() const { return assignment_id_; } // Type feedback information. @@ -1911,9 +1915,6 @@ class Assignment: public Expression { BinaryOperation* binary_operation_; const BailoutId assignment_id_; - bool block_start_; - bool block_end_; - bool is_monomorphic_; SmallMapList receiver_types_; }; @@ -2659,6 +2660,11 @@ class AstNodeFactory BASE_EMBEDDED { STATEMENT_WITH_LABELS(SwitchStatement) #undef STATEMENT_WITH_LABELS + ModuleStatement* NewModuleStatement(VariableProxy* proxy, Block* body) { + ModuleStatement* stmt = new(zone_) ModuleStatement(proxy, body); + VISIT_AND_RETURN(ModuleStatement, stmt) + } + ExpressionStatement* NewExpressionStatement(Expression* expression) { ExpressionStatement* stmt = new(zone_) ExpressionStatement(expression); VISIT_AND_RETURN(ExpressionStatement, stmt) diff --git a/deps/v8/src/atomicops.h b/deps/v8/src/atomicops.h index e2057ed073..da33b29685 100644 --- a/deps/v8/src/atomicops.h +++ b/deps/v8/src/atomicops.h @@ -69,7 +69,11 @@ typedef intptr_t Atomic64; // Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or // Atomic64 routines below, depending on your architecture. +#if defined(__OpenBSD__) && defined(__i386__) +typedef Atomic32 AtomicWord; +#else typedef intptr_t AtomicWord; +#endif // Atomically execute: // result = *ptr; @@ -147,7 +151,9 @@ Atomic64 Release_Load(volatile const Atomic64* ptr); } } // namespace v8::internal // Include our platform specific implementation. -#if defined(_MSC_VER) && \ +#if defined(THREAD_SANITIZER) +#include "atomicops_internals_tsan.h" +#elif defined(_MSC_VER) && \ (defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64)) #include "atomicops_internals_x86_msvc.h" #elif defined(__APPLE__) && \ diff --git a/deps/v8/src/atomicops_internals_tsan.h b/deps/v8/src/atomicops_internals_tsan.h new file mode 100644 index 0000000000..6559336ad9 --- /dev/null +++ b/deps/v8/src/atomicops_internals_tsan.h @@ -0,0 +1,335 @@ +// 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 file is an internal atomic implementation for compiler-based +// ThreadSanitizer. Use base/atomicops.h instead. + +#ifndef V8_ATOMICOPS_INTERNALS_TSAN_H_ +#define V8_ATOMICOPS_INTERNALS_TSAN_H_ + +// This struct is not part of the public API of this module; clients may not +// use it. (However, it's exported via BASE_EXPORT because clients implicitly +// do use it at link time by inlining these functions.) +// Features of this x86. Values may not be correct before main() is run, +// but are set conservatively. +struct AtomicOps_x86CPUFeatureStruct { + bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence + // after acquire compare-and-swap. + bool has_sse2; // Processor has SSE2. +}; +extern struct AtomicOps_x86CPUFeatureStruct + AtomicOps_Internalx86CPUFeatures; + +#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") + +namespace v8 { +namespace internal { + +#ifndef TSAN_INTERFACE_ATOMIC_H +#define TSAN_INTERFACE_ATOMIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef char __tsan_atomic8; +typedef short __tsan_atomic16; // NOLINT +typedef int __tsan_atomic32; +typedef long __tsan_atomic64; // NOLINT + +typedef enum { + __tsan_memory_order_relaxed = (1 << 0) + 100500, + __tsan_memory_order_consume = (1 << 1) + 100500, + __tsan_memory_order_acquire = (1 << 2) + 100500, + __tsan_memory_order_release = (1 << 3) + 100500, + __tsan_memory_order_acq_rel = (1 << 4) + 100500, + __tsan_memory_order_seq_cst = (1 << 5) + 100500, +} __tsan_memory_order; + +__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8* a, + __tsan_memory_order mo); +__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16* a, + __tsan_memory_order mo); +__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32* a, + __tsan_memory_order mo); +__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64* a, + __tsan_memory_order mo); + +void __tsan_atomic8_store(volatile __tsan_atomic8* a, __tsan_atomic8 v, + __tsan_memory_order mo); +void __tsan_atomic16_store(volatile __tsan_atomic16* a, __tsan_atomic16 v, + __tsan_memory_order mo); +void __tsan_atomic32_store(volatile __tsan_atomic32* a, __tsan_atomic32 v, + __tsan_memory_order mo); +void __tsan_atomic64_store(volatile __tsan_atomic64* a, __tsan_atomic64 v, + __tsan_memory_order mo); + +__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8* a, + __tsan_atomic8 v, __tsan_memory_order mo); +__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16* a, + __tsan_atomic16 v, __tsan_memory_order mo); +__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32* a, + __tsan_atomic32 v, __tsan_memory_order mo); +__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64* a, + __tsan_atomic64 v, __tsan_memory_order mo); + +__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8* a, + __tsan_atomic8 v, __tsan_memory_order mo); +__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16* a, + __tsan_atomic16 v, __tsan_memory_order mo); +__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32* a, + __tsan_atomic32 v, __tsan_memory_order mo); +__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64* a, + __tsan_atomic64 v, __tsan_memory_order mo); + +__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8* a, + __tsan_atomic8 v, __tsan_memory_order mo); +__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16* a, + __tsan_atomic16 v, __tsan_memory_order mo); +__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32* a, + __tsan_atomic32 v, __tsan_memory_order mo); +__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64* a, + __tsan_atomic64 v, __tsan_memory_order mo); + +__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8* a, + __tsan_atomic8 v, __tsan_memory_order mo); +__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16* a, + __tsan_atomic16 v, __tsan_memory_order mo); +__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32* a, + __tsan_atomic32 v, __tsan_memory_order mo); +__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64* a, + __tsan_atomic64 v, __tsan_memory_order mo); + +__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8* a, + __tsan_atomic8 v, __tsan_memory_order mo); +__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16* a, + __tsan_atomic16 v, __tsan_memory_order mo); +__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32* a, + __tsan_atomic32 v, __tsan_memory_order mo); +__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64* a, + __tsan_atomic64 v, __tsan_memory_order mo); + +int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8* a, + __tsan_atomic8* c, __tsan_atomic8 v, __tsan_memory_order mo); +int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16* a, + __tsan_atomic16* c, __tsan_atomic16 v, __tsan_memory_order mo); +int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32* a, + __tsan_atomic32* c, __tsan_atomic32 v, __tsan_memory_order mo); +int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64* a, + __tsan_atomic64* c, __tsan_atomic64 v, __tsan_memory_order mo); + +int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8* a, + __tsan_atomic8* c, __tsan_atomic8 v, __tsan_memory_order mo); +int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16* a, + __tsan_atomic16* c, __tsan_atomic16 v, __tsan_memory_order mo); +int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32* a, + __tsan_atomic32* c, __tsan_atomic32 v, __tsan_memory_order mo); +int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64* a, + __tsan_atomic64* c, __tsan_atomic64 v, __tsan_memory_order mo); + +void __tsan_atomic_thread_fence(__tsan_memory_order mo); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // #ifndef TSAN_INTERFACE_ATOMIC_H + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 cmp = old_value; + __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value, + __tsan_memory_order_relaxed); + return cmp; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + return __tsan_atomic32_exchange(ptr, new_value, + __tsan_memory_order_relaxed); +} + +inline Atomic32 Acquire_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + return __tsan_atomic32_exchange(ptr, new_value, + __tsan_memory_order_acquire); +} + +inline Atomic32 Release_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + return __tsan_atomic32_exchange(ptr, new_value, + __tsan_memory_order_release); +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return increment + __tsan_atomic32_fetch_add(ptr, increment, + __tsan_memory_order_relaxed); +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return increment + __tsan_atomic32_fetch_add(ptr, increment, + __tsan_memory_order_acq_rel); +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 cmp = old_value; + __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value, + __tsan_memory_order_acquire); + return cmp; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 cmp = old_value; + __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value, + __tsan_memory_order_release); + return cmp; +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed); +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed); + __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + __tsan_atomic32_store(ptr, value, __tsan_memory_order_release); +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed); +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire); +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); + return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed); +} + +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 cmp = old_value; + __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value, + __tsan_memory_order_relaxed); + return cmp; +} + +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed); +} + +inline Atomic64 Acquire_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire); +} + +inline Atomic64 Release_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release); +} + +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return increment + __tsan_atomic64_fetch_add(ptr, increment, + __tsan_memory_order_relaxed); +} + +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return increment + __tsan_atomic64_fetch_add(ptr, increment, + __tsan_memory_order_acq_rel); +} + +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { + __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed); +} + +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { + __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed); + __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); +} + +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { + __tsan_atomic64_store(ptr, value, __tsan_memory_order_release); +} + +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { + return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed); +} + +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { + return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire); +} + +inline Atomic64 Release_Load(volatile const Atomic64* ptr) { + __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); + return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed); +} + +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 cmp = old_value; + __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value, + __tsan_memory_order_acquire); + return cmp; +} + +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 cmp = old_value; + __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value, + __tsan_memory_order_release); + return cmp; +} + +inline void MemoryBarrier() { + __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); +} + +} // namespace internal +} // namespace v8 + +#undef ATOMICOPS_COMPILER_BARRIER + +#endif // V8_ATOMICOPS_INTERNALS_TSAN_H_ diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 992659edce..8d529506f2 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -384,7 +384,7 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target, void Genesis::SetFunctionInstanceDescriptor( Handle<Map> map, PrototypePropertyMode prototypeMode) { int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5; - Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(size)); + Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(0, size)); DescriptorArray::WhitenessWitness witness(*descriptors); Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength)); @@ -397,7 +397,7 @@ void Genesis::SetFunctionInstanceDescriptor( } PropertyAttributes attribs = static_cast<PropertyAttributes>( DONT_ENUM | DONT_DELETE | READ_ONLY); - Map::SetDescriptors(map, descriptors); + map->set_instance_descriptors(*descriptors); { // Add length. CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs); @@ -525,7 +525,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) { void Genesis::SetStrictFunctionInstanceDescriptor( Handle<Map> map, PrototypePropertyMode prototypeMode) { int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5; - Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(size)); + Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(0, size)); DescriptorArray::WhitenessWitness witness(*descriptors); Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength)); @@ -538,7 +538,7 @@ void Genesis::SetStrictFunctionInstanceDescriptor( } PropertyAttributes attribs = static_cast<PropertyAttributes>( DONT_ENUM | DONT_DELETE); - Map::SetDescriptors(map, descriptors); + map->set_instance_descriptors(*descriptors); { // Add length. CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs); @@ -637,7 +637,7 @@ static void SetAccessors(Handle<Map> map, Handle<String> name, Handle<JSFunction> func) { DescriptorArray* descs = map->instance_descriptors(); - int number = descs->Search(*name); + int number = descs->SearchWithCache(*name, *map); AccessorPair* accessors = AccessorPair::cast(descs->GetValue(number)); accessors->set_getter(*func); accessors->set_setter(*func); @@ -868,13 +868,14 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, array_function->shared()->set_length(1); Handle<Map> initial_map(array_function->initial_map()); - Handle<DescriptorArray> array_descriptors(factory->NewDescriptorArray(1)); + Handle<DescriptorArray> array_descriptors( + factory->NewDescriptorArray(0, 1)); DescriptorArray::WhitenessWitness witness(*array_descriptors); Handle<Foreign> array_length(factory->NewForeign(&Accessors::ArrayLength)); PropertyAttributes attribs = static_cast<PropertyAttributes>( DONT_ENUM | DONT_DELETE); - Map::SetDescriptors(initial_map, array_descriptors); + initial_map->set_instance_descriptors(*array_descriptors); { // Add length. CallbacksDescriptor d(*factory->length_symbol(), *array_length, attribs); @@ -915,14 +916,15 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, Handle<Map> string_map = Handle<Map>(native_context()->string_function()->initial_map()); - Handle<DescriptorArray> string_descriptors(factory->NewDescriptorArray(1)); + Handle<DescriptorArray> string_descriptors( + factory->NewDescriptorArray(0, 1)); DescriptorArray::WhitenessWitness witness(*string_descriptors); Handle<Foreign> string_length( factory->NewForeign(&Accessors::StringLength)); PropertyAttributes attribs = static_cast<PropertyAttributes>( DONT_ENUM | DONT_DELETE | READ_ONLY); - Map::SetDescriptors(string_map, string_descriptors); + string_map->set_instance_descriptors(*string_descriptors); { // Add length. CallbacksDescriptor d(*factory->length_symbol(), *string_length, attribs); @@ -956,9 +958,9 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, PropertyAttributes final = static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY); - Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(5); + Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 5); DescriptorArray::WhitenessWitness witness(*descriptors); - Map::SetDescriptors(initial_map, descriptors); + initial_map->set_instance_descriptors(*descriptors); { // ECMA-262, section 15.10.7.1. @@ -1082,11 +1084,11 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, LookupResult lookup(isolate); result->LocalLookup(heap->callee_symbol(), &lookup); ASSERT(lookup.IsField()); - ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsCalleeIndex); + ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsCalleeIndex); result->LocalLookup(heap->length_symbol(), &lookup); ASSERT(lookup.IsField()); - ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex); + ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsLengthIndex); ASSERT(result->map()->inobject_properties() > Heap::kArgumentsCalleeIndex); ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex); @@ -1140,9 +1142,9 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, Heap::kArgumentsObjectSizeStrict); // Create the descriptor array for the arguments object. - Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(3); + Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 3); DescriptorArray::WhitenessWitness witness(*descriptors); - Map::SetDescriptors(map, descriptors); + map->set_instance_descriptors(*descriptors); { // length FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM); @@ -1184,7 +1186,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, LookupResult lookup(isolate); result->LocalLookup(heap->length_symbol(), &lookup); ASSERT(lookup.IsField()); - ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex); + ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsLengthIndex); ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex); @@ -1238,8 +1240,9 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, // Initialize the out of memory slot. native_context()->set_out_of_memory(heap->false_value()); - // Initialize the data slot. - native_context()->set_data(heap->undefined_value()); + // Initialize the embedder data slot. + Handle<FixedArray> embedder_data = factory->NewFixedArray(2); + native_context()->set_embedder_data(*embedder_data); { // Initialize the random seed slot. @@ -1338,7 +1341,7 @@ bool Genesis::CompileScriptCached(Vector<const char> name, // If we can't find the function in the cache, we compile a new // function and insert it into the cache. if (cache == NULL || !cache->Lookup(name, &function_info)) { - ASSERT(source->IsAsciiRepresentation()); + ASSERT(source->IsOneByteRepresentation()); Handle<String> script_name = factory->NewStringFromUtf8(name); function_info = Compiler::Compile( source, @@ -1413,6 +1416,11 @@ void Genesis::InstallExperimentalNativeFunctions() { INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap); INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate); } + if (FLAG_harmony_observation) { + INSTALL_NATIVE(JSFunction, "NotifyChange", observers_notify_change); + INSTALL_NATIVE(JSFunction, "DeliverChangeRecords", + observers_deliver_changes); + } } #undef INSTALL_NATIVE @@ -1487,7 +1495,7 @@ bool Genesis::InstallNatives() { Handle<Map> script_map = Handle<Map>(script_fun->initial_map()); Handle<DescriptorArray> script_descriptors( - factory()->NewDescriptorArray(13)); + factory()->NewDescriptorArray(0, 13)); DescriptorArray::WhitenessWitness witness(*script_descriptors); Handle<Foreign> script_source( @@ -1532,7 +1540,7 @@ bool Genesis::InstallNatives() { factory()->NewForeign(&Accessors::ScriptEvalFromFunctionName)); PropertyAttributes attribs = static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY); - Map::SetDescriptors(script_map, script_descriptors); + script_map->set_instance_descriptors(*script_descriptors); { CallbacksDescriptor d( @@ -1665,14 +1673,15 @@ bool Genesis::InstallNatives() { // Make "length" magic on instances. Handle<Map> initial_map(array_function->initial_map()); - Handle<DescriptorArray> array_descriptors(factory()->NewDescriptorArray(1)); + Handle<DescriptorArray> array_descriptors( + factory()->NewDescriptorArray(0, 1)); DescriptorArray::WhitenessWitness witness(*array_descriptors); Handle<Foreign> array_length(factory()->NewForeign( &Accessors::ArrayLength)); PropertyAttributes attribs = static_cast<PropertyAttributes>( DONT_ENUM | DONT_DELETE); - Map::SetDescriptors(initial_map, array_descriptors); + initial_map->set_instance_descriptors(*array_descriptors); { // Add length. CallbacksDescriptor d( @@ -1765,16 +1774,17 @@ bool Genesis::InstallNatives() { // Update map with length accessor from Array and add "index" and "input". Handle<DescriptorArray> reresult_descriptors = - factory()->NewDescriptorArray(3); + factory()->NewDescriptorArray(0, 3); DescriptorArray::WhitenessWitness witness(*reresult_descriptors); - Map::SetDescriptors(initial_map, reresult_descriptors); + initial_map->set_instance_descriptors(*reresult_descriptors); { JSFunction* array_function = native_context()->array_function(); Handle<DescriptorArray> array_descriptors( array_function->initial_map()->instance_descriptors()); String* length = heap()->length_symbol(); - int old = array_descriptors->SearchWithCache(length); + int old = array_descriptors->SearchWithCache( + length, array_function->initial_map()); ASSERT(old != DescriptorArray::kNotFound); CallbacksDescriptor desc(length, array_descriptors->GetValue(old), @@ -1802,7 +1812,7 @@ bool Genesis::InstallNatives() { native_context()->set_regexp_result_map(*initial_map); } -#ifdef DEBUG +#ifdef VERIFY_HEAP builtins->Verify(); #endif @@ -1824,6 +1834,11 @@ bool Genesis::InstallExperimentalNatives() { "native collection.js") == 0) { if (!CompileExperimentalBuiltin(isolate(), i)) return false; } + if (FLAG_harmony_observation && + strcmp(ExperimentalNatives::GetScriptName(i).start(), + "native object-observe.js") == 0) { + if (!CompileExperimentalBuiltin(isolate(), i)) return false; + } } InstallExperimentalNativeFunctions(); diff --git a/deps/v8/src/bootstrapper.h b/deps/v8/src/bootstrapper.h index 179e65c354..d61c0313f2 100644 --- a/deps/v8/src/bootstrapper.h +++ b/deps/v8/src/bootstrapper.h @@ -54,7 +54,7 @@ class SourceCodeCache BASE_EMBEDDED { bool Lookup(Vector<const char> name, Handle<SharedFunctionInfo>* handle) { for (int i = 0; i < cache_->length(); i+=2) { - SeqAsciiString* str = SeqAsciiString::cast(cache_->get(i)); + SeqOneByteString* str = SeqOneByteString::cast(cache_->get(i)); if (str->IsEqualTo(name)) { *handle = Handle<SharedFunctionInfo>( SharedFunctionInfo::cast(cache_->get(i + 1))); diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index ffaaf8b1ea..d62713db4c 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -268,7 +268,7 @@ static MaybeObject* ArrayCodeGenericCommon(Arguments* args, maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements); } FixedArrayBase* elms; - if (!maybe_elms->To<FixedArrayBase>(&elms)) return maybe_elms; + if (!maybe_elms->To(&elms)) return maybe_elms; // Fill in the content switch (array->GetElementsKind()) { @@ -325,6 +325,18 @@ BUILTIN(ArrayCodeGeneric) { } +static void MoveDoubleElements(FixedDoubleArray* dst, + int dst_index, + FixedDoubleArray* src, + int src_index, + int len) { + if (len == 0) return; + memmove(dst->data_start() + dst_index, + src->data_start() + src_index, + len * kDoubleSize); +} + + static void MoveElements(Heap* heap, AssertNoAllocation* no_gc, FixedArray* dst, @@ -351,24 +363,39 @@ static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) { } -static FixedArray* LeftTrimFixedArray(Heap* heap, - FixedArray* elms, - int to_trim) { +static void FillWithHoles(FixedDoubleArray* dst, int from, int to) { + for (int i = from; i < to; i++) { + dst->set_the_hole(i); + } +} + + +static FixedArrayBase* LeftTrimFixedArray(Heap* heap, + FixedArrayBase* elms, + int to_trim) { + Map* map = elms->map(); + int entry_size; + if (elms->IsFixedArray()) { + entry_size = kPointerSize; + } else { + entry_size = kDoubleSize; + } ASSERT(elms->map() != HEAP->fixed_cow_array_map()); // For now this trick is only applied to fixed arrays in new and paged space. // In large object space the object's start must coincide with chunk // and thus the trick is just not applicable. ASSERT(!HEAP->lo_space()->Contains(elms)); - STATIC_ASSERT(FixedArray::kMapOffset == 0); - STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize); - STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize); + STATIC_ASSERT(FixedArrayBase::kMapOffset == 0); + STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize); + STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize); Object** former_start = HeapObject::RawField(elms, 0); const int len = elms->length(); - if (to_trim > FixedArray::kHeaderSize / kPointerSize && + if (to_trim * entry_size > FixedArrayBase::kHeaderSize && + elms->IsFixedArray() && !heap->new_space()->Contains(elms)) { // If we are doing a big trim in old space then we zap the space that was // formerly part of the array so that the GC (aided by the card-based @@ -382,14 +409,15 @@ static FixedArray* LeftTrimFixedArray(Heap* heap, // Technically in new space this write might be omitted (except for // debug mode which iterates through the heap), but to play safer // we still do it. - heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize); + heap->CreateFillerObjectAt(elms->address(), to_trim * entry_size); - former_start[to_trim] = heap->fixed_array_map(); - former_start[to_trim + 1] = Smi::FromInt(len - to_trim); + int new_start_index = to_trim * (entry_size / kPointerSize); + former_start[new_start_index] = map; + former_start[new_start_index + 1] = Smi::FromInt(len - to_trim); // Maintain marking consistency for HeapObjectIterator and // IncrementalMarking. - int size_delta = to_trim * kPointerSize; + int size_delta = to_trim * entry_size; if (heap->marking()->TransferMark(elms->address(), elms->address() + size_delta)) { MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); @@ -397,8 +425,8 @@ static FixedArray* LeftTrimFixedArray(Heap* heap, HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(), elms->address() + size_delta)); - return FixedArray::cast(HeapObject::FromAddress( - elms->address() + to_trim * kPointerSize)); + return FixedArrayBase::cast(HeapObject::FromAddress( + elms->address() + to_trim * entry_size)); } @@ -427,19 +455,14 @@ static inline MaybeObject* EnsureJSArrayWithWritableFastElements( Map* map = elms->map(); if (map == heap->fixed_array_map()) { if (args == NULL || array->HasFastObjectElements()) return elms; - 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->HasFastObjectElements() || - maybe_writable_result->IsFailure()) { + !maybe_writable_result->To(&elms)) { return maybe_writable_result; } + } else if (map == heap->fixed_double_array_map()) { + if (args == NULL) return elms; } else { return NULL; } @@ -449,13 +472,28 @@ static inline MaybeObject* EnsureJSArrayWithWritableFastElements( int args_length = args->length(); if (first_added_arg >= args_length) return array->elements(); - MaybeObject* maybe_array = array->EnsureCanContainElements( - args, - first_added_arg, - args_length - first_added_arg, - DONT_ALLOW_DOUBLE_ELEMENTS); - if (maybe_array->IsFailure()) return maybe_array; - return array->elements(); + ElementsKind origin_kind = array->map()->elements_kind(); + ASSERT(!IsFastObjectElementsKind(origin_kind)); + ElementsKind target_kind = origin_kind; + int arg_count = args->length() - first_added_arg; + Object** arguments = args->arguments() - first_added_arg - (arg_count - 1); + for (int i = 0; i < arg_count; i++) { + Object* arg = arguments[i]; + if (arg->IsHeapObject()) { + if (arg->IsHeapNumber()) { + target_kind = FAST_DOUBLE_ELEMENTS; + } else { + target_kind = FAST_ELEMENTS; + break; + } + } + } + if (target_kind != origin_kind) { + MaybeObject* maybe_failure = array->TransitionElementsKind(target_kind); + if (maybe_failure->IsFailure()) return maybe_failure; + return array->elements(); + } + return elms; } @@ -499,127 +537,200 @@ MUST_USE_RESULT static MaybeObject* CallJsBuiltin( BUILTIN(ArrayPush) { Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); - Object* elms_obj; - { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1); - if (maybe_elms_obj == NULL) { - return CallJsBuiltin(isolate, "ArrayPush", args); - } - if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; + FixedArrayBase* elms_obj; + MaybeObject* maybe_elms_obj = + EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1); + if (maybe_elms_obj == NULL) { + return CallJsBuiltin(isolate, "ArrayPush", args); } - FixedArray* elms = FixedArray::cast(elms_obj); - JSArray* array = JSArray::cast(receiver); + if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj; - int len = Smi::cast(array->length())->value(); - int to_add = args.length() - 1; - if (to_add == 0) { - return Smi::FromInt(len); + if (FLAG_harmony_observation && + JSObject::cast(receiver)->map()->is_observed()) { + return CallJsBuiltin(isolate, "ArrayPush", args); } - // Currently fixed arrays cannot grow too big, so - // we should never hit this case. - ASSERT(to_add <= (Smi::kMaxValue - len)); - int new_length = len + to_add; + JSArray* array = JSArray::cast(receiver); + ElementsKind kind = array->GetElementsKind(); - if (new_length > elms->length()) { - // New backing storage is needed. - int capacity = new_length + (new_length >> 1) + 16; - Object* obj; - { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; + if (IsFastSmiOrObjectElementsKind(kind)) { + FixedArray* elms = FixedArray::cast(elms_obj); + + int len = Smi::cast(array->length())->value(); + int to_add = args.length() - 1; + if (to_add == 0) { + return Smi::FromInt(len); } - FixedArray* new_elms = FixedArray::cast(obj); + // Currently fixed arrays cannot grow too big, so + // we should never hit this case. + ASSERT(to_add <= (Smi::kMaxValue - len)); - ElementsKind kind = array->GetElementsKind(); - CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, 0, len); - FillWithHoles(heap, new_elms, new_length, capacity); + int new_length = len + to_add; - elms = new_elms; - } + if (new_length > elms->length()) { + // New backing storage is needed. + int capacity = new_length + (new_length >> 1) + 16; + FixedArray* new_elms; + MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); + if (!maybe_obj->To(&new_elms)) return maybe_obj; - // Add the provided values. - AssertNoAllocation no_gc; - WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); - for (int index = 0; index < to_add; index++) { - elms->set(index + len, args[index + 1], mode); - } + ElementsAccessor* accessor = array->GetElementsAccessor(); + MaybeObject* maybe_failure = accessor->CopyElements( + NULL, 0, new_elms, kind, 0, + ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj); + ASSERT(!maybe_failure->IsFailure()); + USE(maybe_failure); - if (elms != array->elements()) { - array->set_elements(elms); - } + elms = new_elms; + } - // Set the length. - array->set_length(Smi::FromInt(new_length)); - return Smi::FromInt(new_length); + // Add the provided values. + AssertNoAllocation no_gc; + WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); + for (int index = 0; index < to_add; index++) { + elms->set(index + len, args[index + 1], mode); + } + + if (elms != array->elements()) { + array->set_elements(elms); + } + + // Set the length. + array->set_length(Smi::FromInt(new_length)); + return Smi::FromInt(new_length); + } else { + int len = Smi::cast(array->length())->value(); + int elms_len = elms_obj->length(); + + int to_add = args.length() - 1; + if (to_add == 0) { + return Smi::FromInt(len); + } + // Currently fixed arrays cannot grow too big, so + // we should never hit this case. + ASSERT(to_add <= (Smi::kMaxValue - len)); + + int new_length = len + to_add; + + FixedDoubleArray* new_elms; + + if (new_length > elms_len) { + // New backing storage is needed. + int capacity = new_length + (new_length >> 1) + 16; + MaybeObject* maybe_obj = + heap->AllocateUninitializedFixedDoubleArray(capacity); + if (!maybe_obj->To(&new_elms)) return maybe_obj; + + ElementsAccessor* accessor = array->GetElementsAccessor(); + MaybeObject* maybe_failure = accessor->CopyElements( + NULL, 0, new_elms, kind, 0, + ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj); + ASSERT(!maybe_failure->IsFailure()); + USE(maybe_failure); + } else { + // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the + // empty_fixed_array. + new_elms = FixedDoubleArray::cast(elms_obj); + } + + // Add the provided values. + AssertNoAllocation no_gc; + int index; + for (index = 0; index < to_add; index++) { + Object* arg = args[index + 1]; + new_elms->set(index + len, arg->Number()); + } + + if (new_elms != array->elements()) { + array->set_elements(new_elms); + } + + // Set the length. + array->set_length(Smi::FromInt(new_length)); + return Smi::FromInt(new_length); + } } BUILTIN(ArrayPop) { Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); - Object* elms_obj; - { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); - if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args); - if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; - } - FixedArray* elms = FixedArray::cast(elms_obj); + FixedArrayBase* elms_obj; + MaybeObject* maybe_elms = + EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); + if (maybe_elms == NULL) return CallJsBuiltin(isolate, "ArrayPop", args); + if (!maybe_elms->To(&elms_obj)) return maybe_elms; + JSArray* array = JSArray::cast(receiver); + if (FLAG_harmony_observation && array->map()->is_observed()) { + return CallJsBuiltin(isolate, "ArrayPop", args); + } + int len = Smi::cast(array->length())->value(); if (len == 0) return heap->undefined_value(); - // Get top element - MaybeObject* top = elms->get(len - 1); - - // Set the length. - array->set_length(Smi::FromInt(len - 1)); - - if (!top->IsTheHole()) { - // Delete the top element. - elms->set_the_hole(len - 1); - return top; + ElementsAccessor* accessor = array->GetElementsAccessor(); + int new_length = len - 1; + MaybeObject* maybe_result; + if (accessor->HasElement(array, array, new_length, elms_obj)) { + maybe_result = accessor->Get(array, array, new_length, elms_obj); + } else { + maybe_result = array->GetPrototype()->GetElement(len - 1); } - - top = array->GetPrototype()->GetElement(len - 1); - - return top; + if (maybe_result->IsFailure()) return maybe_result; + MaybeObject* maybe_failure = + accessor->SetLength(array, Smi::FromInt(new_length)); + if (maybe_failure->IsFailure()) return maybe_failure; + return maybe_result; } BUILTIN(ArrayShift) { Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); - Object* elms_obj; - { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); - if (maybe_elms_obj == NULL) - return CallJsBuiltin(isolate, "ArrayShift", args); - if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; - } + FixedArrayBase* elms_obj; + MaybeObject* maybe_elms_obj = + EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); + if (maybe_elms_obj == NULL) + return CallJsBuiltin(isolate, "ArrayShift", args); + if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj; + if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { return CallJsBuiltin(isolate, "ArrayShift", args); } - FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); - ASSERT(array->HasFastSmiOrObjectElements()); + + if (FLAG_harmony_observation && array->map()->is_observed()) { + return CallJsBuiltin(isolate, "ArrayShift", args); + } int len = Smi::cast(array->length())->value(); if (len == 0) return heap->undefined_value(); // Get first element - Object* first = elms->get(0); + ElementsAccessor* accessor = array->GetElementsAccessor(); + Object* first; + MaybeObject* maybe_first = accessor->Get(receiver, array, 0, elms_obj); + if (!maybe_first->To(&first)) return maybe_first; if (first->IsTheHole()) { first = heap->undefined_value(); } - if (!heap->lo_space()->Contains(elms)) { - array->set_elements(LeftTrimFixedArray(heap, elms, 1)); + if (!heap->lo_space()->Contains(elms_obj)) { + array->set_elements(LeftTrimFixedArray(heap, elms_obj, 1)); } else { // Shift the elements. - AssertNoAllocation no_gc; - MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1); - elms->set(len - 1, heap->the_hole_value()); + if (elms_obj->IsFixedArray()) { + FixedArray* elms = FixedArray::cast(elms_obj); + AssertNoAllocation no_gc; + MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1); + elms->set(len - 1, heap->the_hole_value()); + } else { + FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj); + MoveDoubleElements(elms, 0, elms, 1, len - 1); + elms->set_the_hole(len - 1); + } } // Set the length. @@ -632,19 +743,25 @@ BUILTIN(ArrayShift) { BUILTIN(ArrayUnshift) { Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); - Object* elms_obj; - { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); - if (maybe_elms_obj == NULL) - return CallJsBuiltin(isolate, "ArrayUnshift", args); - if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; - } + FixedArrayBase* elms_obj; + MaybeObject* maybe_elms_obj = + EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); + if (maybe_elms_obj == NULL) + return CallJsBuiltin(isolate, "ArrayUnshift", args); + if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj; + if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { return CallJsBuiltin(isolate, "ArrayUnshift", args); } - FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); - ASSERT(array->HasFastSmiOrObjectElements()); + if (!array->HasFastSmiOrObjectElements()) { + return CallJsBuiltin(isolate, "ArrayUnshift", args); + } + FixedArray* elms = FixedArray::cast(elms_obj); + + if (FLAG_harmony_observation && array->map()->is_observed()) { + return CallJsBuiltin(isolate, "ArrayUnshift", args); + } int len = Smi::cast(array->length())->value(); int to_add = args.length() - 1; @@ -661,14 +778,18 @@ BUILTIN(ArrayUnshift) { if (new_length > elms->length()) { // New backing storage is needed. int capacity = new_length + (new_length >> 1) + 16; - Object* obj; - { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - FixedArray* new_elms = FixedArray::cast(obj); + FixedArray* new_elms; + MaybeObject* maybe_elms = heap->AllocateUninitializedFixedArray(capacity); + if (!maybe_elms->To(&new_elms)) return maybe_elms; + ElementsKind kind = array->GetElementsKind(); - CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, to_add, len); - FillWithHoles(heap, new_elms, new_length, capacity); + ElementsAccessor* accessor = array->GetElementsAccessor(); + MaybeObject* maybe_failure = accessor->CopyElements( + NULL, 0, new_elms, kind, to_add, + ElementsAccessor::kCopyToEndAndInitializeToHole, elms); + ASSERT(!maybe_failure->IsFailure()); + USE(maybe_failure); + elms = new_elms; array->set_elements(elms); } else { @@ -692,16 +813,20 @@ BUILTIN(ArrayUnshift) { BUILTIN(ArraySlice) { Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); - FixedArray* elms; + FixedArrayBase* elms; int len = -1; if (receiver->IsJSArray()) { JSArray* array = JSArray::cast(receiver); - if (!array->HasFastSmiOrObjectElements() || - !IsJSArrayFastElementMovingAllowed(heap, array)) { + if (!IsJSArrayFastElementMovingAllowed(heap, array)) { + return CallJsBuiltin(isolate, "ArraySlice", args); + } + + if (array->HasFastElements()) { + elms = array->elements(); + } else { return CallJsBuiltin(isolate, "ArraySlice", args); } - elms = FixedArray::cast(array->elements()); len = Smi::cast(array->length())->value(); } else { // Array.slice(arguments, ...) is quite a common idiom (notably more @@ -710,15 +835,19 @@ BUILTIN(ArraySlice) { isolate->context()->native_context()->arguments_boilerplate()->map(); bool is_arguments_object_with_fast_elements = - receiver->IsJSObject() - && JSObject::cast(receiver)->map() == arguments_map - && JSObject::cast(receiver)->HasFastSmiOrObjectElements(); + receiver->IsJSObject() && + JSObject::cast(receiver)->map() == arguments_map; if (!is_arguments_object_with_fast_elements) { return CallJsBuiltin(isolate, "ArraySlice", args); } - elms = FixedArray::cast(JSObject::cast(receiver)->elements()); - Object* len_obj = JSObject::cast(receiver) - ->InObjectPropertyAt(Heap::kArgumentsLengthIndex); + JSObject* object = JSObject::cast(receiver); + + if (object->HasFastElements()) { + elms = object->elements(); + } else { + return CallJsBuiltin(isolate, "ArraySlice", args); + } + Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); if (!len_obj->IsSmi()) { return CallJsBuiltin(isolate, "ArraySlice", args); } @@ -726,12 +855,27 @@ BUILTIN(ArraySlice) { if (len > elms->length()) { return CallJsBuiltin(isolate, "ArraySlice", args); } + } + + JSObject* object = JSObject::cast(receiver); + ElementsKind kind = object->GetElementsKind(); + + if (IsHoleyElementsKind(kind)) { + bool packed = true; + ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); for (int i = 0; i < len; i++) { - if (elms->get(i) == heap->the_hole_value()) { - return CallJsBuiltin(isolate, "ArraySlice", args); + if (!accessor->HasElement(object, object, i, elms)) { + packed = false; + break; } } + if (packed) { + kind = GetPackedElementsKind(kind); + } else if (!receiver->IsJSArray()) { + return CallJsBuiltin(isolate, "ArraySlice", args); + } } + ASSERT(len >= 0); int n_arguments = args.length() - 1; @@ -744,6 +888,12 @@ BUILTIN(ArraySlice) { Object* arg1 = args[1]; if (arg1->IsSmi()) { relative_start = Smi::cast(arg1)->value(); + } else if (arg1->IsHeapNumber()) { + double start = HeapNumber::cast(arg1)->value(); + if (start < kMinInt || start > kMaxInt) { + return CallJsBuiltin(isolate, "ArraySlice", args); + } + relative_start = static_cast<int>(start); } else if (!arg1->IsUndefined()) { return CallJsBuiltin(isolate, "ArraySlice", args); } @@ -751,6 +901,12 @@ BUILTIN(ArraySlice) { Object* arg2 = args[2]; if (arg2->IsSmi()) { relative_end = Smi::cast(arg2)->value(); + } else if (arg2->IsHeapNumber()) { + double end = HeapNumber::cast(arg2)->value(); + if (end < kMinInt || end > kMaxInt) { + return CallJsBuiltin(isolate, "ArraySlice", args); + } + relative_end = static_cast<int>(end); } else if (!arg2->IsUndefined()) { return CallJsBuiltin(isolate, "ArraySlice", args); } @@ -765,21 +921,24 @@ BUILTIN(ArraySlice) { int final = (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len); - ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind(); - // Calculate the length of result array. int result_len = Max(final - k, 0); - MaybeObject* maybe_array = - heap->AllocateJSArrayAndStorage(elements_kind, - result_len, - result_len); JSArray* result_array; + MaybeObject* maybe_array = heap->AllocateJSArrayAndStorage(kind, + result_len, + result_len); + + AssertNoAllocation no_gc; + if (result_len == 0) return maybe_array; if (!maybe_array->To(&result_array)) return maybe_array; - CopyObjectToObjectElements(elms, elements_kind, k, - FixedArray::cast(result_array->elements()), - elements_kind, 0, result_len); + ElementsAccessor* accessor = object->GetElementsAccessor(); + MaybeObject* maybe_failure = + accessor->CopyElements(NULL, k, result_array->elements(), + kind, 0, result_len, elms); + ASSERT(!maybe_failure->IsFailure()); + USE(maybe_failure); return result_array; } @@ -788,19 +947,22 @@ BUILTIN(ArraySlice) { BUILTIN(ArraySplice) { Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); - Object* elms_obj; - { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3); - if (maybe_elms_obj == NULL) - return CallJsBuiltin(isolate, "ArraySplice", args); - if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; + FixedArrayBase* elms_obj; + MaybeObject* maybe_elms = + EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3); + if (maybe_elms == NULL) { + return CallJsBuiltin(isolate, "ArraySplice", args); } + if (!maybe_elms->To(&elms_obj)) return maybe_elms; + if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { return CallJsBuiltin(isolate, "ArraySplice", args); } - FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); - ASSERT(array->HasFastSmiOrObjectElements()); + + if (FLAG_harmony_observation && array->map()->is_observed()) { + return CallJsBuiltin(isolate, "ArraySplice", args); + } int len = Smi::cast(array->length())->value(); @@ -811,6 +973,12 @@ BUILTIN(ArraySplice) { Object* arg1 = args[1]; if (arg1->IsSmi()) { relative_start = Smi::cast(arg1)->value(); + } else if (arg1->IsHeapNumber()) { + double start = HeapNumber::cast(arg1)->value(); + if (start < kMinInt || start > kMaxInt) { + return CallJsBuiltin(isolate, "ArraySplice", args); + } + relative_start = static_cast<int>(start); } else if (!arg1->IsUndefined()) { return CallJsBuiltin(isolate, "ArraySplice", args); } @@ -840,51 +1008,84 @@ BUILTIN(ArraySplice) { actual_delete_count = Min(Max(value, 0), len - actual_start); } + ElementsKind elements_kind = array->GetElementsKind(); + + int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; + int new_length = len - actual_delete_count + item_count; + + // For double mode we do not support changing the length. + if (new_length > len && IsFastDoubleElementsKind(elements_kind)) { + return CallJsBuiltin(isolate, "ArraySplice", args); + } + + if (new_length == 0) { + MaybeObject* maybe_array = heap->AllocateJSArrayWithElements( + elms_obj, elements_kind, actual_delete_count); + if (maybe_array->IsFailure()) return maybe_array; + array->set_elements(heap->empty_fixed_array()); + array->set_length(Smi::FromInt(0)); + return maybe_array; + } + JSArray* result_array = NULL; - ElementsKind elements_kind = - JSObject::cast(receiver)->GetElementsKind(); MaybeObject* maybe_array = heap->AllocateJSArrayAndStorage(elements_kind, actual_delete_count, actual_delete_count); if (!maybe_array->To(&result_array)) return maybe_array; - { - // Fill newly created array. - CopyObjectToObjectElements(elms, elements_kind, actual_start, - FixedArray::cast(result_array->elements()), - elements_kind, 0, actual_delete_count); + if (actual_delete_count > 0) { + AssertNoAllocation no_gc; + ElementsAccessor* accessor = array->GetElementsAccessor(); + MaybeObject* maybe_failure = + accessor->CopyElements(NULL, actual_start, result_array->elements(), + elements_kind, 0, actual_delete_count, elms_obj); + // Cannot fail since the origin and target array are of the same elements + // kind. + ASSERT(!maybe_failure->IsFailure()); + USE(maybe_failure); } - int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; - int new_length = len - actual_delete_count + item_count; - bool elms_changed = false; if (item_count < actual_delete_count) { // Shrink the array. - const bool trim_array = !heap->lo_space()->Contains(elms) && + const bool trim_array = !heap->lo_space()->Contains(elms_obj) && ((actual_start + item_count) < (len - actual_delete_count - actual_start)); if (trim_array) { const int delta = actual_delete_count - item_count; - { + if (elms_obj->IsFixedDoubleArray()) { + FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj); + MoveDoubleElements(elms, delta, elms, 0, actual_start); + } else { + FixedArray* elms = FixedArray::cast(elms_obj); AssertNoAllocation no_gc; MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start); } - elms = LeftTrimFixedArray(heap, elms, delta); + elms_obj = LeftTrimFixedArray(heap, elms_obj, delta); elms_changed = true; } else { - AssertNoAllocation no_gc; - MoveElements(heap, &no_gc, - elms, actual_start + item_count, - elms, actual_start + actual_delete_count, - (len - actual_delete_count - actual_start)); - FillWithHoles(heap, elms, new_length, len); + if (elms_obj->IsFixedDoubleArray()) { + FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj); + MoveDoubleElements(elms, actual_start + item_count, + elms, actual_start + actual_delete_count, + (len - actual_delete_count - actual_start)); + FillWithHoles(elms, new_length, len); + } else { + FixedArray* elms = FixedArray::cast(elms_obj); + AssertNoAllocation no_gc; + MoveElements(heap, &no_gc, + elms, actual_start + item_count, + elms, actual_start + actual_delete_count, + (len - actual_delete_count - actual_start)); + FillWithHoles(heap, elms, new_length, len); + } } } else if (item_count > actual_delete_count) { + FixedArray* elms = FixedArray::cast(elms_obj); // Currently fixed arrays cannot grow too big, so // we should never hit this case. ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len)); @@ -893,28 +1094,29 @@ BUILTIN(ArraySplice) { if (new_length > elms->length()) { // New backing storage is needed. int capacity = new_length + (new_length >> 1) + 16; - Object* obj; - { MaybeObject* maybe_obj = - heap->AllocateUninitializedFixedArray(capacity); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - FixedArray* new_elms = FixedArray::cast(obj); + FixedArray* new_elms; + MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); + if (!maybe_obj->To(&new_elms)) return maybe_obj; - { + AssertNoAllocation no_gc; + + ElementsKind kind = array->GetElementsKind(); + ElementsAccessor* accessor = array->GetElementsAccessor(); + if (actual_start > 0) { // Copy the part before actual_start as is. - ElementsKind kind = array->GetElementsKind(); - CopyObjectToObjectElements(elms, kind, 0, - new_elms, kind, 0, actual_start); - const int to_copy = len - actual_delete_count - actual_start; - CopyObjectToObjectElements(elms, kind, - actual_start + actual_delete_count, - new_elms, kind, - actual_start + item_count, to_copy); + MaybeObject* maybe_failure = accessor->CopyElements( + NULL, 0, new_elms, kind, 0, actual_start, elms); + ASSERT(!maybe_failure->IsFailure()); + USE(maybe_failure); } - - FillWithHoles(heap, new_elms, new_length, capacity); - - elms = new_elms; + MaybeObject* maybe_failure = accessor->CopyElements( + NULL, actual_start + actual_delete_count, new_elms, kind, + actual_start + item_count, + ElementsAccessor::kCopyToEndAndInitializeToHole, elms); + ASSERT(!maybe_failure->IsFailure()); + USE(maybe_failure); + + elms_obj = new_elms; elms_changed = true; } else { AssertNoAllocation no_gc; @@ -925,16 +1127,28 @@ BUILTIN(ArraySplice) { } } - AssertNoAllocation no_gc; - WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); - for (int k = actual_start; k < actual_start + item_count; k++) { - elms->set(k, args[3 + k - actual_start], mode); + if (IsFastDoubleElementsKind(elements_kind)) { + FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj); + for (int k = actual_start; k < actual_start + item_count; k++) { + Object* arg = args[3 + k - actual_start]; + if (arg->IsSmi()) { + elms->set(k, Smi::cast(arg)->value()); + } else { + elms->set(k, HeapNumber::cast(arg)->value()); + } + } + } else { + FixedArray* elms = FixedArray::cast(elms_obj); + AssertNoAllocation no_gc; + WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); + for (int k = actual_start; k < actual_start + item_count; k++) { + elms->set(k, args[3 + k - actual_start], mode); + } } if (elms_changed) { - array->set_elements(elms); + array->set_elements(elms_obj); } - // Set the length. array->set_length(Smi::FromInt(new_length)); @@ -956,14 +1170,15 @@ BUILTIN(ArrayConcat) { int n_arguments = args.length(); int result_len = 0; ElementsKind elements_kind = GetInitialFastElementsKind(); + bool has_double = false; + bool is_holey = false; for (int i = 0; i < n_arguments; i++) { Object* arg = args[i]; if (!arg->IsJSArray() || - !JSArray::cast(arg)->HasFastSmiOrObjectElements() || + !JSArray::cast(arg)->HasFastElements() || JSArray::cast(arg)->GetPrototype() != array_proto) { return CallJsBuiltin(isolate, "ArrayConcat", args); } - int len = Smi::cast(JSArray::cast(arg)->length())->value(); // We shouldn't overflow when adding another len. @@ -973,47 +1188,51 @@ BUILTIN(ArrayConcat) { result_len += len; ASSERT(result_len >= 0); - if (result_len > FixedArray::kMaxLength) { + if (result_len > FixedDoubleArray::kMaxLength) { return CallJsBuiltin(isolate, "ArrayConcat", args); } - if (!JSArray::cast(arg)->HasFastSmiElements()) { - if (IsFastSmiElementsKind(elements_kind)) { - if (IsFastHoleyElementsKind(elements_kind)) { - elements_kind = FAST_HOLEY_ELEMENTS; - } else { - elements_kind = FAST_ELEMENTS; - } - } - } - - if (JSArray::cast(arg)->HasFastHoleyElements()) { - elements_kind = GetHoleyElementsKind(elements_kind); + ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind(); + has_double = has_double || IsFastDoubleElementsKind(arg_kind); + is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); + if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) { + elements_kind = arg_kind; } } - // Allocate result. + if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind); + + // If a double array is concatted into a fast elements array, the fast + // elements array needs to be initialized to contain proper holes, since + // boxing doubles may cause incremental marking. + ArrayStorageAllocationMode mode = + has_double && IsFastObjectElementsKind(elements_kind) + ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS; JSArray* result_array; + // Allocate result. MaybeObject* maybe_array = heap->AllocateJSArrayAndStorage(elements_kind, result_len, - result_len); + result_len, + mode); if (!maybe_array->To(&result_array)) return maybe_array; if (result_len == 0) return result_array; - // Copy data. - int start_pos = 0; - FixedArray* result_elms(FixedArray::cast(result_array->elements())); + int j = 0; + FixedArrayBase* storage = result_array->elements(); for (int i = 0; i < n_arguments; i++) { JSArray* array = JSArray::cast(args[i]); int len = Smi::cast(array->length())->value(); - FixedArray* elms = FixedArray::cast(array->elements()); - CopyObjectToObjectElements(elms, elements_kind, 0, - result_elms, elements_kind, - start_pos, len); - start_pos += len; + if (len > 0) { + ElementsAccessor* accessor = array->GetElementsAccessor(); + MaybeObject* maybe_failure = + accessor->CopyElements(array, 0, storage, elements_kind, j, len); + if (maybe_failure->IsFailure()) return maybe_failure; + j += len; + } } - ASSERT(start_pos == result_len); + + ASSERT(j == result_len); return result_array; } @@ -1033,12 +1252,28 @@ BUILTIN(StrictModePoisonPill) { // +// Searches the hidden prototype chain of the given object for the first +// object that is an instance of the given type. If no such object can +// be found then Heap::null_value() is returned. +static inline Object* FindHidden(Heap* heap, + Object* object, + FunctionTemplateInfo* type) { + if (object->IsInstanceOf(type)) return object; + Object* proto = object->GetPrototype(); + if (proto->IsJSObject() && + JSObject::cast(proto)->map()->is_hidden_prototype()) { + return FindHidden(heap, proto, type); + } + return heap->null_value(); +} + + // Returns the holder JSObject if the function can legally be called // with this receiver. Returns Heap::null_value() if the call is // illegal. Any arguments that don't fit the expected type is -// overwritten with undefined. Arguments that do fit the expected -// type is overwritten with the object in the prototype chain that -// actually has that type. +// overwritten with undefined. Note that holder and the arguments are +// implicitly rewritten with the first object in the hidden prototype +// chain that actually has the expected type. static inline Object* TypeCheck(Heap* heap, int argc, Object** argv, @@ -1051,15 +1286,10 @@ static inline Object* TypeCheck(Heap* heap, SignatureInfo* sig = SignatureInfo::cast(sig_obj); // If necessary, check the receiver Object* recv_type = sig->receiver(); - Object* holder = recv; if (!recv_type->IsUndefined()) { - for (; holder != heap->null_value(); holder = holder->GetPrototype()) { - if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) { - break; - } - } - if (holder == heap->null_value()) return holder; + holder = FindHidden(heap, holder, FunctionTemplateInfo::cast(recv_type)); + if (holder == heap->null_value()) return heap->null_value(); } Object* args_obj = sig->args(); // If there is no argument signature we're done @@ -1072,13 +1302,9 @@ static inline Object* TypeCheck(Heap* heap, if (argtype->IsUndefined()) continue; Object** arg = &argv[-1 - i]; Object* current = *arg; - for (; current != heap->null_value(); current = current->GetPrototype()) { - if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) { - *arg = current; - break; - } - } - if (current == heap->null_value()) *arg = heap->undefined_value(); + current = FindHidden(heap, current, FunctionTemplateInfo::cast(argtype)); + if (current == heap->null_value()) current = heap->undefined_value(); + *arg = current; } return holder; } @@ -1620,7 +1846,7 @@ void Builtins::SetUp(bool create_heap_objects) { // For now we generate builtin adaptor code into a stack-allocated // buffer, before copying it into individual code objects. Be careful // with alignment, some platforms don't like unaligned code. - union { int force_alignment; byte buffer[4*KB]; } u; + union { int force_alignment; byte buffer[8*KB]; } u; // Traverse the list of builtins and generate an adaptor in a // separate code object for each one. diff --git a/deps/v8/src/builtins.h b/deps/v8/src/builtins.h index ca70ae5403..a2f752e052 100644 --- a/deps/v8/src/builtins.h +++ b/deps/v8/src/builtins.h @@ -38,6 +38,25 @@ enum BuiltinExtraArguments { }; +#define CODE_AGE_LIST_WITH_ARG(V, A) \ + V(Quadragenarian, A) \ + V(Quinquagenarian, A) \ + V(Sexagenarian, A) \ + V(Septuagenarian, A) \ + V(Octogenarian, A) + +#define CODE_AGE_LIST_IGNORE_ARG(X, V) V(X) + +#define CODE_AGE_LIST(V) \ + CODE_AGE_LIST_WITH_ARG(CODE_AGE_LIST_IGNORE_ARG, V) + +#define DECLARE_CODE_AGE_BUILTIN(C, V) \ + V(Make##C##CodeYoungAgainOddMarking, BUILTIN, \ + UNINITIALIZED, Code::kNoExtraICState) \ + V(Make##C##CodeYoungAgainEvenMarking, BUILTIN, \ + UNINITIALIZED, Code::kNoExtraICState) + + // Define list of builtins implemented in C++. #define BUILTIN_LIST_C(V) \ V(Illegal, NO_EXTRA_ARGUMENTS) \ @@ -195,8 +214,8 @@ enum BuiltinExtraArguments { Code::kNoExtraICState) \ \ V(OnStackReplacement, BUILTIN, UNINITIALIZED, \ - Code::kNoExtraICState) - + Code::kNoExtraICState) \ + CODE_AGE_LIST_WITH_ARG(DECLARE_CODE_AGE_BUILTIN, V) #ifdef ENABLE_DEBUGGER_SUPPORT // Define list of builtins used by the debugger implemented in assembly. @@ -379,6 +398,14 @@ class Builtins { static void Generate_StringConstructCode(MacroAssembler* masm); static void Generate_OnStackReplacement(MacroAssembler* masm); +#define DECLARE_CODE_AGE_BUILTIN_GENERATOR(C) \ + static void Generate_Make##C##CodeYoungAgainEvenMarking( \ + MacroAssembler* masm); \ + static void Generate_Make##C##CodeYoungAgainOddMarking( \ + MacroAssembler* masm); + CODE_AGE_LIST(DECLARE_CODE_AGE_BUILTIN_GENERATOR) +#undef DECLARE_CODE_AGE_BUILTIN_GENERATOR + static void InitBuiltinFunctionTable(); bool initialized_; diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index 59a4cdf823..276c87ebd0 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -37,11 +37,11 @@ namespace v8 { namespace internal { -bool CodeStub::FindCodeInCache(Code** code_out) { - Heap* heap = Isolate::Current()->heap(); - int index = heap->code_stubs()->FindEntry(GetKey()); +bool CodeStub::FindCodeInCache(Code** code_out, Isolate* isolate) { + UnseededNumberDictionary* stubs = isolate->heap()->code_stubs(); + int index = stubs->FindEntry(GetKey()); if (index != UnseededNumberDictionary::kNotFound) { - *code_out = Code::cast(heap->code_stubs()->ValueAt(index)); + *code_out = Code::cast(stubs->ValueAt(index)); return true; } return false; @@ -93,8 +93,8 @@ Handle<Code> CodeStub::GetCode() { Heap* heap = isolate->heap(); Code* code; if (UseSpecialCache() - ? FindCodeInSpecialCache(&code) - : FindCodeInCache(&code)) { + ? FindCodeInSpecialCache(&code, isolate) + : FindCodeInCache(&code, isolate)) { ASSERT(IsPregenerated() == code->is_pregenerated()); return Handle<Code>(code); } @@ -142,7 +142,9 @@ Handle<Code> CodeStub::GetCode() { } Activate(code); - ASSERT(!NeedsImmovableCode() || heap->lo_space()->Contains(code)); + ASSERT(!NeedsImmovableCode() || + heap->lo_space()->Contains(code) || + heap->code_space()->FirstPage()->Contains(code->address())); return Handle<Code>(code, isolate); } @@ -167,6 +169,122 @@ void CodeStub::PrintName(StringStream* stream) { } +void BinaryOpStub::Generate(MacroAssembler* masm) { + // Explicitly allow generation of nested stubs. It is safe here because + // generation code does not use any raw pointers. + AllowStubCallsScope allow_stub_calls(masm, true); + + BinaryOpIC::TypeInfo operands_type = Max(left_type_, right_type_); + if (left_type_ == BinaryOpIC::ODDBALL && right_type_ == BinaryOpIC::ODDBALL) { + // The OddballStub handles a number and an oddball, not two oddballs. + operands_type = BinaryOpIC::GENERIC; + } + switch (operands_type) { + case BinaryOpIC::UNINITIALIZED: + GenerateTypeTransition(masm); + break; + case BinaryOpIC::SMI: + GenerateSmiStub(masm); + break; + case BinaryOpIC::INT32: + GenerateInt32Stub(masm); + break; + case BinaryOpIC::HEAP_NUMBER: + GenerateHeapNumberStub(masm); + break; + case BinaryOpIC::ODDBALL: + GenerateOddballStub(masm); + break; + case BinaryOpIC::STRING: + GenerateStringStub(masm); + break; + case BinaryOpIC::GENERIC: + GenerateGeneric(masm); + break; + default: + UNREACHABLE(); + } +} + + +#define __ ACCESS_MASM(masm) + + +void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { + switch (op_) { + case Token::ADD: + __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); + break; + case Token::SUB: + __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); + break; + case Token::MUL: + __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); + break; + case Token::DIV: + __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); + break; + case Token::MOD: + __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); + break; + case Token::BIT_OR: + __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); + break; + case Token::BIT_AND: + __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); + break; + case Token::BIT_XOR: + __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); + break; + case Token::SAR: + __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); + break; + case Token::SHR: + __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); + break; + case Token::SHL: + __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); + break; + default: + UNREACHABLE(); + } +} + + +#undef __ + + +void BinaryOpStub::PrintName(StringStream* stream) { + const char* op_name = Token::Name(op_); + const char* overwrite_name; + switch (mode_) { + case NO_OVERWRITE: overwrite_name = "Alloc"; break; + case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; + case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; + default: overwrite_name = "UnknownOverwrite"; break; + } + stream->Add("BinaryOpStub_%s_%s_%s+%s", + op_name, + overwrite_name, + BinaryOpIC::GetName(left_type_), + BinaryOpIC::GetName(right_type_)); +} + + +void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { + ASSERT(left_type_ == BinaryOpIC::STRING || right_type_ == BinaryOpIC::STRING); + ASSERT(op_ == Token::ADD); + if (left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING) { + GenerateBothStringStub(masm); + return; + } + // Try to add arguments as strings, otherwise, transition to the generic + // BinaryOpIC type. + GenerateAddStrings(masm); + GenerateTypeTransition(masm); +} + + void ICCompareStub::AddToSpecialCache(Handle<Code> new_object) { ASSERT(*known_map_ != NULL); Isolate* isolate = new_object->GetIsolate(); @@ -179,8 +297,7 @@ void ICCompareStub::AddToSpecialCache(Handle<Code> new_object) { } -bool ICCompareStub::FindCodeInSpecialCache(Code** code_out) { - Isolate* isolate = known_map_->GetIsolate(); +bool ICCompareStub::FindCodeInSpecialCache(Code** code_out, Isolate* isolate) { Factory* factory = isolate->factory(); Code::Flags flags = Code::ComputeFlags( static_cast<Code::Kind>(GetCodeKind()), @@ -194,7 +311,12 @@ bool ICCompareStub::FindCodeInSpecialCache(Code** code_out) { flags)); if (probe->IsCode()) { *code_out = Code::cast(*probe); - ASSERT(op_ == (*code_out)->compare_operation() + Token::EQ); +#ifdef DEBUG + Token::Value cached_op; + ICCompareStub::DecodeMinorKey((*code_out)->stub_info(), NULL, NULL, NULL, + &cached_op); + ASSERT(op_ == cached_op); +#endif return true; } return false; @@ -202,7 +324,33 @@ bool ICCompareStub::FindCodeInSpecialCache(Code** code_out) { int ICCompareStub::MinorKey() { - return OpField::encode(op_ - Token::EQ) | StateField::encode(state_); + return OpField::encode(op_ - Token::EQ) | + LeftStateField::encode(left_) | + RightStateField::encode(right_) | + HandlerStateField::encode(state_); +} + + +void ICCompareStub::DecodeMinorKey(int minor_key, + CompareIC::State* left_state, + CompareIC::State* right_state, + CompareIC::State* handler_state, + Token::Value* op) { + if (left_state) { + *left_state = + static_cast<CompareIC::State>(LeftStateField::decode(minor_key)); + } + if (right_state) { + *right_state = + static_cast<CompareIC::State>(RightStateField::decode(minor_key)); + } + if (handler_state) { + *handler_state = + static_cast<CompareIC::State>(HandlerStateField::decode(minor_key)); + } + if (op) { + *op = static_cast<Token::Value>(OpField::decode(minor_key) + Token::EQ); + } } @@ -211,27 +359,28 @@ void ICCompareStub::Generate(MacroAssembler* masm) { case CompareIC::UNINITIALIZED: GenerateMiss(masm); break; - case CompareIC::SMIS: + case CompareIC::SMI: GenerateSmis(masm); break; - case CompareIC::HEAP_NUMBERS: + case CompareIC::HEAP_NUMBER: GenerateHeapNumbers(masm); break; - case CompareIC::STRINGS: + case CompareIC::STRING: GenerateStrings(masm); break; - case CompareIC::SYMBOLS: + case CompareIC::SYMBOL: GenerateSymbols(masm); break; - case CompareIC::OBJECTS: + case CompareIC::OBJECT: GenerateObjects(masm); break; case CompareIC::KNOWN_OBJECTS: ASSERT(*known_map_ != NULL); GenerateKnownObjects(masm); break; - default: - UNREACHABLE(); + case CompareIC::GENERIC: + GenerateGeneric(masm); + break; } } diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index f19063230a..ae113f5729 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -141,7 +141,7 @@ class CodeStub BASE_EMBEDDED { bool CompilingCallsToThisStubIsGCSafe() { bool is_pregenerated = IsPregenerated(); Code* code = NULL; - CHECK(!is_pregenerated || FindCodeInCache(&code)); + CHECK(!is_pregenerated || FindCodeInCache(&code, Isolate::Current())); return is_pregenerated; } @@ -160,7 +160,10 @@ class CodeStub BASE_EMBEDDED { virtual bool SometimesSetsUpAFrame() { return true; } // Lookup the code in the (possibly custom) cache. - bool FindCodeInCache(Code** code_out); + bool FindCodeInCache(Code** code_out, Isolate* isolate); + + protected: + static bool CanUseFPRegisters(); private: // Nonvirtual wrapper around the stub-specific Generate function. Call @@ -199,7 +202,9 @@ class CodeStub BASE_EMBEDDED { virtual void AddToSpecialCache(Handle<Code> new_object) { } // Find code in a specialized cache, work is delegated to the specific stub. - virtual bool FindCodeInSpecialCache(Code** code_out) { return false; } + virtual bool FindCodeInSpecialCache(Code** code_out, Isolate* isolate) { + return false; + } // If a stub uses a special cache override this. virtual bool UseSpecialCache() { return false; } @@ -479,10 +484,132 @@ class MathPowStub: public CodeStub { }; +class BinaryOpStub: public CodeStub { + public: + BinaryOpStub(Token::Value op, OverwriteMode mode) + : op_(op), + mode_(mode), + platform_specific_bit_(false), + left_type_(BinaryOpIC::UNINITIALIZED), + right_type_(BinaryOpIC::UNINITIALIZED), + result_type_(BinaryOpIC::UNINITIALIZED) { + Initialize(); + ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); + } + + BinaryOpStub( + int key, + BinaryOpIC::TypeInfo left_type, + BinaryOpIC::TypeInfo right_type, + BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED) + : op_(OpBits::decode(key)), + mode_(ModeBits::decode(key)), + platform_specific_bit_(PlatformSpecificBits::decode(key)), + left_type_(left_type), + right_type_(right_type), + result_type_(result_type) { } + + static void decode_types_from_minor_key(int minor_key, + BinaryOpIC::TypeInfo* left_type, + BinaryOpIC::TypeInfo* right_type, + BinaryOpIC::TypeInfo* result_type) { + *left_type = + static_cast<BinaryOpIC::TypeInfo>(LeftTypeBits::decode(minor_key)); + *right_type = + static_cast<BinaryOpIC::TypeInfo>(RightTypeBits::decode(minor_key)); + *result_type = + static_cast<BinaryOpIC::TypeInfo>(ResultTypeBits::decode(minor_key)); + } + + static Token::Value decode_op_from_minor_key(int minor_key) { + return static_cast<Token::Value>(OpBits::decode(minor_key)); + } + + enum SmiCodeGenerateHeapNumberResults { + ALLOW_HEAPNUMBER_RESULTS, + NO_HEAPNUMBER_RESULTS + }; + + private: + Token::Value op_; + OverwriteMode mode_; + bool platform_specific_bit_; // Indicates SSE3 on IA32, VFP2 on ARM. + + // Operand type information determined at runtime. + BinaryOpIC::TypeInfo left_type_; + BinaryOpIC::TypeInfo right_type_; + BinaryOpIC::TypeInfo result_type_; + + virtual void PrintName(StringStream* stream); + + // Minor key encoding in 19 bits TTTRRRLLLSOOOOOOOMM. + class ModeBits: public BitField<OverwriteMode, 0, 2> {}; + class OpBits: public BitField<Token::Value, 2, 7> {}; + class PlatformSpecificBits: public BitField<bool, 9, 1> {}; + class LeftTypeBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {}; + class RightTypeBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {}; + class ResultTypeBits: public BitField<BinaryOpIC::TypeInfo, 16, 3> {}; + + Major MajorKey() { return BinaryOp; } + int MinorKey() { + return OpBits::encode(op_) + | ModeBits::encode(mode_) + | PlatformSpecificBits::encode(platform_specific_bit_) + | LeftTypeBits::encode(left_type_) + | RightTypeBits::encode(right_type_) + | ResultTypeBits::encode(result_type_); + } + + + // Platform-independent implementation. + void Generate(MacroAssembler* masm); + void GenerateCallRuntime(MacroAssembler* masm); + + // Platform-independent signature, platform-specific implementation. + void Initialize(); + void GenerateAddStrings(MacroAssembler* masm); + void GenerateBothStringStub(MacroAssembler* masm); + void GenerateGeneric(MacroAssembler* masm); + void GenerateGenericStub(MacroAssembler* masm); + void GenerateHeapNumberStub(MacroAssembler* masm); + void GenerateInt32Stub(MacroAssembler* masm); + void GenerateLoadArguments(MacroAssembler* masm); + void GenerateOddballStub(MacroAssembler* masm); + void GenerateRegisterArgsPush(MacroAssembler* masm); + void GenerateReturn(MacroAssembler* masm); + void GenerateSmiStub(MacroAssembler* masm); + void GenerateStringStub(MacroAssembler* masm); + void GenerateTypeTransition(MacroAssembler* masm); + void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); + void GenerateUninitializedStub(MacroAssembler* masm); + + // Entirely platform-specific methods are defined as static helper + // functions in the <arch>/code-stubs-<arch>.cc files. + + virtual int GetCodeKind() { return Code::BINARY_OP_IC; } + + virtual InlineCacheState GetICState() { + return BinaryOpIC::ToState(Max(left_type_, right_type_)); + } + + virtual void FinishCode(Handle<Code> code) { + code->set_stub_info(MinorKey()); + } + + friend class CodeGenerator; +}; + + class ICCompareStub: public CodeStub { public: - ICCompareStub(Token::Value op, CompareIC::State state) - : op_(op), state_(state) { + ICCompareStub(Token::Value op, + CompareIC::State left, + CompareIC::State right, + CompareIC::State handler) + : op_(op), + left_(left), + right_(right), + state_(handler) { ASSERT(Token::IsCompareOp(op)); } @@ -490,13 +617,24 @@ class ICCompareStub: public CodeStub { void set_known_map(Handle<Map> map) { known_map_ = map; } + static void DecodeMinorKey(int minor_key, + CompareIC::State* left_state, + CompareIC::State* right_state, + CompareIC::State* handler_state, + Token::Value* op); + + static CompareIC::State CompareState(int minor_key) { + return static_cast<CompareIC::State>(HandlerStateField::decode(minor_key)); + } + private: class OpField: public BitField<int, 0, 3> { }; - class StateField: public BitField<int, 3, 5> { }; + class LeftStateField: public BitField<int, 3, 3> { }; + class RightStateField: public BitField<int, 6, 3> { }; + class HandlerStateField: public BitField<int, 9, 3> { }; virtual void FinishCode(Handle<Code> code) { - code->set_compare_state(state_); - code->set_compare_operation(op_ - Token::EQ); + code->set_stub_info(MinorKey()); } virtual CodeStub::Major MajorKey() { return CompareIC; } @@ -511,117 +649,23 @@ class ICCompareStub: public CodeStub { void GenerateObjects(MacroAssembler* masm); void GenerateMiss(MacroAssembler* masm); void GenerateKnownObjects(MacroAssembler* masm); + void GenerateGeneric(MacroAssembler* masm); bool strict() const { return op_ == Token::EQ_STRICT; } Condition GetCondition() const { return CompareIC::ComputeCondition(op_); } virtual void AddToSpecialCache(Handle<Code> new_object); - virtual bool FindCodeInSpecialCache(Code** code_out); + virtual bool FindCodeInSpecialCache(Code** code_out, Isolate* isolate); virtual bool UseSpecialCache() { return state_ == CompareIC::KNOWN_OBJECTS; } Token::Value op_; + CompareIC::State left_; + CompareIC::State right_; CompareIC::State state_; Handle<Map> known_map_; }; -// Flags that control the compare stub code generation. -enum CompareFlags { - NO_COMPARE_FLAGS = 0, - NO_SMI_COMPARE_IN_STUB = 1 << 0, - NO_NUMBER_COMPARE_IN_STUB = 1 << 1, - CANT_BOTH_BE_NAN = 1 << 2 -}; - - -enum NaNInformation { - kBothCouldBeNaN, - kCantBothBeNaN -}; - - -class CompareStub: public CodeStub { - public: - CompareStub(Condition cc, - bool strict, - CompareFlags flags, - Register lhs, - Register rhs) : - cc_(cc), - strict_(strict), - never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0), - include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0), - include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0), - lhs_(lhs), - rhs_(rhs) { } - - CompareStub(Condition cc, - bool strict, - CompareFlags flags) : - cc_(cc), - strict_(strict), - never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0), - include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0), - include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0), - lhs_(no_reg), - rhs_(no_reg) { } - - void Generate(MacroAssembler* masm); - - private: - Condition cc_; - bool strict_; - // Only used for 'equal' comparisons. Tells the stub that we already know - // that at least one side of the comparison is not NaN. This allows the - // stub to use object identity in the positive case. We ignore it when - // generating the minor key for other comparisons to avoid creating more - // stubs. - bool never_nan_nan_; - // Do generate the number comparison code in the stub. Stubs without number - // comparison code is used when the number comparison has been inlined, and - // the stub will be called if one of the operands is not a number. - bool include_number_compare_; - - // Generate the comparison code for two smi operands in the stub. - bool include_smi_compare_; - - // Register holding the left hand side of the comparison if the stub gives - // a choice, no_reg otherwise. - - Register lhs_; - // Register holding the right hand side of the comparison if the stub gives - // a choice, no_reg otherwise. - Register rhs_; - - // Encoding of the minor key in 16 bits. - class StrictField: public BitField<bool, 0, 1> {}; - class NeverNanNanField: public BitField<bool, 1, 1> {}; - class IncludeNumberCompareField: public BitField<bool, 2, 1> {}; - class IncludeSmiCompareField: public BitField<bool, 3, 1> {}; - class RegisterField: public BitField<bool, 4, 1> {}; - class ConditionField: public BitField<int, 5, 11> {}; - - Major MajorKey() { return Compare; } - - int MinorKey(); - - virtual int GetCodeKind() { return Code::COMPARE_IC; } - virtual void FinishCode(Handle<Code> code) { - code->set_compare_state(CompareIC::GENERIC); - } - - // Branch to the label if the given object isn't a symbol. - void BranchIfNonSymbol(MacroAssembler* masm, - Label* label, - Register object, - Register scratch); - - // Unfortunately you have to run without snapshots to see most of these - // names in the profile since most compare stubs end up in the snapshot. - virtual void PrintName(StringStream* stream); -}; - - class CEntryStub : public CodeStub { public: explicit CEntryStub(int result_size, @@ -998,13 +1042,15 @@ class KeyedStoreElementStub : public CodeStub { KeyedAccessGrowMode grow_mode) : is_js_array_(is_js_array), elements_kind_(elements_kind), - grow_mode_(grow_mode) { } + grow_mode_(grow_mode), + fp_registers_(CanUseFPRegisters()) { } Major MajorKey() { return KeyedStoreElement; } int MinorKey() { return ElementsKindBits::encode(elements_kind_) | IsJSArrayBits::encode(is_js_array_) | - GrowModeBits::encode(grow_mode_); + GrowModeBits::encode(grow_mode_) | + FPRegisters::encode(fp_registers_); } void Generate(MacroAssembler* masm); @@ -1013,10 +1059,12 @@ class KeyedStoreElementStub : public CodeStub { class ElementsKindBits: public BitField<ElementsKind, 0, 8> {}; class GrowModeBits: public BitField<KeyedAccessGrowMode, 8, 1> {}; class IsJSArrayBits: public BitField<bool, 9, 1> {}; + class FPRegisters: public BitField<bool, 10, 1> {}; bool is_js_array_; ElementsKind elements_kind_; KeyedAccessGrowMode grow_mode_; + bool fp_registers_; DISALLOW_COPY_AND_ASSIGN(KeyedStoreElementStub); }; @@ -1046,6 +1094,9 @@ class ToBooleanStub: public CodeStub { bool IsEmpty() const { return set_.IsEmpty(); } bool Contains(Type type) const { return set_.Contains(type); } + bool ContainsAnyOf(Types types) const { + return set_.ContainsAnyOf(types.set_); + } void Add(Type type) { set_.Add(type); } byte ToByte() const { return set_.ToIntegral(); } void Print(StringStream* stream) const; @@ -1132,14 +1183,19 @@ class ElementsTransitionAndStoreStub : public CodeStub { class StoreArrayLiteralElementStub : public CodeStub { public: - explicit StoreArrayLiteralElementStub() {} + StoreArrayLiteralElementStub() + : fp_registers_(CanUseFPRegisters()) { } private: + class FPRegisters: public BitField<bool, 0, 1> {}; + Major MajorKey() { return StoreArrayLiteralElement; } - int MinorKey() { return 0; } + int MinorKey() { return FPRegisters::encode(fp_registers_); } void Generate(MacroAssembler* masm); + bool fp_registers_; + DISALLOW_COPY_AND_ASSIGN(StoreArrayLiteralElementStub); }; @@ -1159,6 +1215,8 @@ class ProfileEntryHookStub : public CodeStub { // non-NULL hook. static bool SetFunctionEntryHook(FunctionEntryHook entry_hook); + static bool HasEntryHook() { return entry_hook_ != NULL; } + private: static void EntryHookTrampoline(intptr_t function, intptr_t stack_pointer); diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc index 0163580e90..83ac854a07 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -107,6 +107,7 @@ Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm, if (!code.is_null()) { isolate->counters()->total_compiled_code_size()->Increment( code->instruction_size()); + code->set_prologue_offset(info->prologue_offset()); } return code; } diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h index 08a777f2ad..0ac68c2eac 100644 --- a/deps/v8/src/codegen.h +++ b/deps/v8/src/codegen.h @@ -90,6 +90,7 @@ namespace internal { typedef double (*UnaryMathFunction)(double x); UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type); +UnaryMathFunction CreateExpFunction(); UnaryMathFunction CreateSqrtFunction(); @@ -103,6 +104,19 @@ class ElementsTransitionGenerator : public AllStatic { DISALLOW_COPY_AND_ASSIGN(ElementsTransitionGenerator); }; + +class SeqStringSetCharGenerator : public AllStatic { + public: + static void Generate(MacroAssembler* masm, + String::Encoding encoding, + Register string, + Register index, + Register value); + private: + DISALLOW_COPY_AND_ASSIGN(SeqStringSetCharGenerator); +}; + + } } // namespace v8::internal #endif // V8_CODEGEN_H_ diff --git a/deps/v8/src/collection.js b/deps/v8/src/collection.js index d36fe18fa0..b3c2db72d7 100644 --- a/deps/v8/src/collection.js +++ b/deps/v8/src/collection.js @@ -88,6 +88,25 @@ function SetDelete(key) { } +function SetGetSize() { + if (!IS_SET(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Set.prototype.size', this]); + } + return %SetGetSize(this); +} + + +function SetClear() { + if (!IS_SET(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Set.prototype.clear', this]); + } + // Replace the internal table with a new empty table. + %SetInitialize(this); +} + + function MapConstructor() { if (%_IsConstructCall()) { %MapInitialize(this); @@ -145,6 +164,25 @@ function MapDelete(key) { } +function MapGetSize() { + if (!IS_MAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Map.prototype.size', this]); + } + return %MapGetSize(this); +} + + +function MapClear() { + if (!IS_MAP(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['Map.prototype.clear', this]); + } + // Replace the internal table with a new empty table. + %MapInitialize(this); +} + + function WeakMapConstructor() { if (%_IsConstructCall()) { %WeakMapInitialize(this); @@ -215,18 +253,22 @@ function WeakMapDelete(key) { %SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM); // Set up the non-enumerable functions on the Set prototype object. + InstallGetter($Set.prototype, "size", SetGetSize); InstallFunctions($Set.prototype, DONT_ENUM, $Array( "add", SetAdd, "has", SetHas, - "delete", SetDelete + "delete", SetDelete, + "clear", SetClear )); // Set up the non-enumerable functions on the Map prototype object. + InstallGetter($Map.prototype, "size", MapGetSize); InstallFunctions($Map.prototype, DONT_ENUM, $Array( "get", MapGet, "set", MapSet, "has", MapHas, - "delete", MapDelete + "delete", MapDelete, + "clear", MapClear )); // Set up the WeakMap constructor function. diff --git a/deps/v8/src/compilation-cache.cc b/deps/v8/src/compilation-cache.cc index c0645760b3..904e84fd6c 100644 --- a/deps/v8/src/compilation-cache.cc +++ b/deps/v8/src/compilation-cache.cc @@ -98,7 +98,7 @@ void CompilationSubCache::Age() { void CompilationSubCache::IterateFunctions(ObjectVisitor* v) { - Object* undefined = isolate()->heap()->raw_unchecked_undefined_value(); + Object* undefined = isolate()->heap()->undefined_value(); for (int i = 0; i < generations_; i++) { if (tables_[i] != undefined) { reinterpret_cast<CompilationCacheTable*>(tables_[i])->IterateElements(v); diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 86374371e9..5779aae81b 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -52,57 +52,53 @@ namespace internal { CompilationInfo::CompilationInfo(Handle<Script> script, Zone* zone) - : isolate_(script->GetIsolate()), - flags_(LanguageModeField::encode(CLASSIC_MODE)), - function_(NULL), - scope_(NULL), - global_scope_(NULL), + : flags_(LanguageModeField::encode(CLASSIC_MODE)), script_(script), - extension_(NULL), - pre_parse_data_(NULL), - osr_ast_id_(BailoutId::None()), - zone_(zone), - deferred_handles_(NULL) { - Initialize(BASE); + osr_ast_id_(BailoutId::None()) { + Initialize(zone); } CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info, Zone* zone) - : isolate_(shared_info->GetIsolate()), - flags_(LanguageModeField::encode(CLASSIC_MODE) | - IsLazy::encode(true)), - function_(NULL), - scope_(NULL), - global_scope_(NULL), + : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)), shared_info_(shared_info), script_(Handle<Script>(Script::cast(shared_info->script()))), - extension_(NULL), - pre_parse_data_(NULL), - osr_ast_id_(BailoutId::None()), - zone_(zone), - deferred_handles_(NULL) { - Initialize(BASE); + osr_ast_id_(BailoutId::None()) { + Initialize(zone); } CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone) - : isolate_(closure->GetIsolate()), - flags_(LanguageModeField::encode(CLASSIC_MODE) | - IsLazy::encode(true)), - function_(NULL), - scope_(NULL), - global_scope_(NULL), + : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)), closure_(closure), shared_info_(Handle<SharedFunctionInfo>(closure->shared())), script_(Handle<Script>(Script::cast(shared_info_->script()))), - extension_(NULL), - pre_parse_data_(NULL), context_(closure->context()), - osr_ast_id_(BailoutId::None()), - zone_(zone), - deferred_handles_(NULL) { - Initialize(BASE); + osr_ast_id_(BailoutId::None()) { + Initialize(zone); +} + + +void CompilationInfo::Initialize(Zone* zone) { + isolate_ = script_->GetIsolate(); + function_ = NULL; + scope_ = NULL; + global_scope_ = NULL; + extension_ = NULL; + pre_parse_data_ = NULL; + zone_ = zone; + deferred_handles_ = NULL; + prologue_offset_ = kPrologueOffsetNotSet; + mode_ = V8::UseCrankshaft() ? BASE : NONOPT; + if (script_->type()->value() == Script::TYPE_NATIVE) { + MarkAsNative(); + } + if (!shared_info_.is_null()) { + ASSERT(language_mode() == CLASSIC_MODE); + SetLanguageMode(shared_info_->language_mode()); + } + set_bailout_reason("unknown"); } @@ -194,6 +190,11 @@ void OptimizingCompiler::RecordOptimizationStats() { code_size, compilation_time); } + if (FLAG_hydrogen_stats) { + HStatistics::Instance()->IncrementSubtotals(time_taken_to_create_graph_, + time_taken_to_optimize_, + time_taken_to_codegen_); + } } @@ -284,7 +285,6 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() { // doesn't have deoptimization support. Alternatively, we may decide to // run the full code generator to get a baseline for the compile-time // performance of the hydrogen-based compiler. - Timer t(this, &time_taken_to_create_graph_); bool should_recompile = !info()->shared_info()->has_deoptimization_support(); if (should_recompile || FLAG_hydrogen_stats) { HPhase phase(HPhase::kFullCodeGen); @@ -324,7 +324,8 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() { oracle_ = new(info()->zone()) TypeFeedbackOracle( code, native_context, info()->isolate(), info()->zone()); graph_builder_ = new(info()->zone()) HGraphBuilder(info(), oracle_); - HPhase phase(HPhase::kTotal); + + Timer t(this, &time_taken_to_create_graph_); graph_ = graph_builder_->CreateGraph(); if (info()->isolate()->has_pending_exception()) { @@ -371,15 +372,17 @@ OptimizingCompiler::Status OptimizingCompiler::OptimizeGraph() { OptimizingCompiler::Status OptimizingCompiler::GenerateAndInstallCode() { ASSERT(last_status() == SUCCEEDED); - Timer timer(this, &time_taken_to_codegen_); - ASSERT(chunk_ != NULL); - ASSERT(graph_ != NULL); - Handle<Code> optimized_code = chunk_->Codegen(); - if (optimized_code.is_null()) { - info()->set_bailout_reason("code generation failed"); - return AbortOptimization(); + { // Scope for timer. + Timer timer(this, &time_taken_to_codegen_); + ASSERT(chunk_ != NULL); + ASSERT(graph_ != NULL); + Handle<Code> optimized_code = chunk_->Codegen(); + if (optimized_code.is_null()) { + info()->set_bailout_reason("code generation failed"); + return AbortOptimization(); + } + info()->SetCode(optimized_code); } - info()->SetCode(optimized_code); RecordOptimizationStats(); return SetLastStatus(SUCCEEDED); } @@ -390,6 +393,8 @@ static bool GenerateCode(CompilationInfo* info) { !info->IsCompilingForDebugging() && info->IsOptimizing(); if (is_optimizing) { + Logger::TimerEventScope timer( + info->isolate(), Logger::TimerEventScope::v8_recompile_synchronous); return MakeCrankshaftCode(info); } else { if (info->IsOptimizing()) { @@ -397,6 +402,8 @@ static bool GenerateCode(CompilationInfo* info) { // BASE or NONOPT. info->DisableOptimization(); } + Logger::TimerEventScope timer( + info->isolate(), Logger::TimerEventScope::v8_compile_full_code); return FullCodeGenerator::MakeCode(info); } } @@ -432,7 +439,9 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { ASSERT(!isolate->native_context().is_null()); Handle<Script> script = info->script(); - script->set_context_data((*isolate->native_context())->data()); + // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile? + FixedArray* array = isolate->native_context()->embedder_data(); + script->set_context_data(array->get(0)); #ifdef ENABLE_DEBUGGER_SUPPORT if (info->is_eval()) { @@ -841,6 +850,11 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) { ASSERT(closure->IsMarkedForParallelRecompilation()); Isolate* isolate = closure->GetIsolate(); + // Here we prepare compile data for the parallel recompilation thread, but + // this still happens synchronously and interrupts execution. + Logger::TimerEventScope timer( + isolate, Logger::TimerEventScope::v8_recompile_synchronous); + if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) { if (FLAG_trace_parallel_recompilation) { PrintF(" ** Compilation queue, will retry opting on next run.\n"); @@ -849,7 +863,7 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) { } SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(closure)); - VMState state(isolate, PARALLEL_COMPILER_PROLOGUE); + VMState state(isolate, PARALLEL_COMPILER); PostponeInterruptsScope postpone(isolate); Handle<SharedFunctionInfo> shared = info->shared_info(); @@ -860,7 +874,10 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) { { CompilationHandleScope handle_scope(*info); - if (InstallCodeFromOptimizedCodeMap(*info)) return; + if (!FLAG_manual_parallel_recompilation && + InstallCodeFromOptimizedCodeMap(*info)) { + return; + } if (ParserApi::Parse(*info, kNoParsingFlags)) { LanguageMode language_mode = info->function()->language_mode(); @@ -894,6 +911,10 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) { void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) { SmartPointer<CompilationInfo> info(optimizing_compiler->info()); + Isolate* isolate = info->isolate(); + VMState state(isolate, PARALLEL_COMPILER); + Logger::TimerEventScope timer( + isolate, Logger::TimerEventScope::v8_recompile_synchronous); // If crankshaft succeeded, install the optimized code else install // the unoptimized code. OptimizingCompiler::Status status = optimizing_compiler->last_status(); diff --git a/deps/v8/src/compiler.h b/deps/v8/src/compiler.h index af9459566d..653d5f124d 100644 --- a/deps/v8/src/compiler.h +++ b/deps/v8/src/compiler.h @@ -35,6 +35,8 @@ namespace v8 { namespace internal { +static const int kPrologueOffsetNotSet = -1; + class ScriptDataImpl; // CompilationInfo encapsulates some information known at compile time. It @@ -186,6 +188,16 @@ class CompilationInfo { const char* bailout_reason() const { return bailout_reason_; } void set_bailout_reason(const char* reason) { bailout_reason_ = reason; } + int prologue_offset() const { + ASSERT_NE(kPrologueOffsetNotSet, prologue_offset_); + return prologue_offset_; + } + + void set_prologue_offset(int prologue_offset) { + ASSERT_EQ(kPrologueOffsetNotSet, prologue_offset_); + prologue_offset_ = prologue_offset; + } + private: Isolate* isolate_; @@ -200,18 +212,7 @@ class CompilationInfo { NONOPT }; - void Initialize(Mode mode) { - mode_ = V8::UseCrankshaft() ? mode : NONOPT; - ASSERT(!script_.is_null()); - if (script_->type()->value() == Script::TYPE_NATIVE) { - MarkAsNative(); - } - if (!shared_info_.is_null()) { - ASSERT(language_mode() == CLASSIC_MODE); - SetLanguageMode(shared_info_->language_mode()); - } - set_bailout_reason("unknown"); - } + void Initialize(Zone* zone); void SetMode(Mode mode) { ASSERT(V8::UseCrankshaft()); @@ -285,6 +286,8 @@ class CompilationInfo { const char* bailout_reason_; + int prologue_offset_; + DISALLOW_COPY_AND_ASSIGN(CompilationInfo); }; @@ -293,6 +296,8 @@ class CompilationInfo { // Zone on construction and deallocates it on exit. class CompilationInfoWithZone: public CompilationInfo { public: + INLINE(void* operator new(size_t size)) { return Malloced::New(size); } + explicit CompilationInfoWithZone(Handle<Script> script) : CompilationInfo(script, &zone_), zone_(script->GetIsolate()), diff --git a/deps/v8/src/contexts.cc b/deps/v8/src/contexts.cc index 169d9a1223..4cb52d3a6c 100644 --- a/deps/v8/src/contexts.cc +++ b/deps/v8/src/contexts.cc @@ -55,6 +55,15 @@ JSBuiltinsObject* Context::builtins() { } +Context* Context::global_context() { + Context* current = this; + while (!current->IsGlobalContext()) { + current = current->previous(); + } + return current; +} + + Context* Context::native_context() { // Fast case: the global object for this context has been set. In // that case, the global object has a direct pointer to the global @@ -183,6 +192,10 @@ Handle<Object> Context::Lookup(Handle<String> name, ? IMMUTABLE_CHECK_INITIALIZED_HARMONY : IMMUTABLE_IS_INITIALIZED_HARMONY; break; + case MODULE: + *attributes = READ_ONLY; + *binding_flags = IMMUTABLE_IS_INITIALIZED_HARMONY; + break; case DYNAMIC: case DYNAMIC_GLOBAL: case DYNAMIC_LOCAL: @@ -251,8 +264,6 @@ void Context::AddOptimizedFunction(JSFunction* function) { } } - CHECK(function->next_function_link()->IsUndefined()); - // Check that the context belongs to the weak native contexts list. bool found = false; Object* context = GetHeap()->native_contexts_list(); @@ -265,6 +276,16 @@ void Context::AddOptimizedFunction(JSFunction* function) { } CHECK(found); #endif + + // If the function link field is already used then the function was + // enqueued as a code flushing candidate and we remove it now. + if (!function->next_function_link()->IsUndefined()) { + CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher(); + flusher->EvictCandidate(function); + } + + ASSERT(function->next_function_link()->IsUndefined()); + function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST)); set(OPTIMIZED_FUNCTIONS_LIST, function); } @@ -305,6 +326,18 @@ void Context::ClearOptimizedFunctions() { } +Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() { + Handle<Object> result(error_message_for_code_gen_from_strings()); + if (result->IsUndefined()) { + const char* error = + "Code generation from strings disallowed for this context"; + Isolate* isolate = Isolate::Current(); + result = isolate->factory()->NewStringFromAscii(i::CStrVector(error)); + } + return result; +} + + #ifdef DEBUG bool Context::IsBootstrappingOrValidParentContext( Object* object, Context* child) { diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h index cfc576cecb..745ba65347 100644 --- a/deps/v8/src/contexts.h +++ b/deps/v8/src/contexts.h @@ -152,14 +152,18 @@ enum BindingFlags { V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \ V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \ V(MAP_CACHE_INDEX, Object, map_cache) \ - V(CONTEXT_DATA_INDEX, Object, data) \ + V(EMBEDDER_DATA_INDEX, FixedArray, embedder_data) \ V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \ + V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \ + error_message_for_code_gen_from_strings) \ V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \ to_complete_property_descriptor) \ V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \ V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \ V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap) \ - V(PROXY_ENUMERATE, JSFunction, proxy_enumerate) \ + V(PROXY_ENUMERATE_INDEX, JSFunction, proxy_enumerate) \ + V(OBSERVERS_NOTIFY_CHANGE_INDEX, JSFunction, observers_notify_change) \ + V(OBSERVERS_DELIVER_CHANGES_INDEX, JSFunction, observers_deliver_changes) \ V(RANDOM_SEED_INDEX, ByteArray, random_seed) // JSFunctions are pairs (context, function code), sometimes also called @@ -279,13 +283,16 @@ class Context: public FixedArray { OPAQUE_REFERENCE_FUNCTION_INDEX, CONTEXT_EXTENSION_FUNCTION_INDEX, OUT_OF_MEMORY_INDEX, - CONTEXT_DATA_INDEX, + EMBEDDER_DATA_INDEX, ALLOW_CODE_GEN_FROM_STRINGS_INDEX, + ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, DERIVED_HAS_TRAP_INDEX, DERIVED_GET_TRAP_INDEX, DERIVED_SET_TRAP_INDEX, - PROXY_ENUMERATE, + PROXY_ENUMERATE_INDEX, + OBSERVERS_NOTIFY_CHANGE_INDEX, + OBSERVERS_DELIVER_CHANGES_INDEX, RANDOM_SEED_INDEX, // Properties from here are treated as weak references by the full GC. @@ -338,12 +345,19 @@ class Context: public FixedArray { // The builtins object. JSBuiltinsObject* builtins(); + // Get the innermost global context by traversing the context chain. + Context* global_context(); + // Compute the native context by traversing the context chain. Context* native_context(); - // Predicates for context types. IsNativeContext is defined on Object + // Predicates for context types. IsNativeContext is also defined on Object // because we frequently have to know if arbitrary objects are natives // contexts. + bool IsNativeContext() { + Map* map = this->map(); + return map == map->GetHeap()->native_context_map(); + } bool IsFunctionContext() { Map* map = this->map(); return map == map->GetHeap()->function_context_map(); @@ -381,6 +395,8 @@ class Context: public FixedArray { Object* OptimizedFunctionsListHead(); void ClearOptimizedFunctions(); + Handle<Object> ErrorMessageForCodeGenerationFromStrings(); + #define NATIVE_CONTEXT_FIELD_ACCESSORS(index, type, name) \ void set_##name(type* value) { \ ASSERT(IsNativeContext()); \ @@ -441,6 +457,9 @@ class Context: public FixedArray { static bool IsBootstrappingOrValidParentContext(Object* object, Context* kid); static bool IsBootstrappingOrGlobalObject(Object* object); #endif + + STATIC_CHECK(kHeaderSize == Internals::kContextHeaderSize); + STATIC_CHECK(EMBEDDER_DATA_INDEX == Internals::kContextEmbedderDataIndex); }; } } // namespace v8::internal diff --git a/deps/v8/src/counters.cc b/deps/v8/src/counters.cc index 811c0aa2e6..6d453d6aa3 100644 --- a/deps/v8/src/counters.cc +++ b/deps/v8/src/counters.cc @@ -77,7 +77,7 @@ void* Histogram::CreateHistogram() const { // Start the timer. void HistogramTimer::Start() { - if (histogram_.Enabled()) { + if (histogram_.Enabled() || FLAG_log_internal_timer_events) { stop_time_ = 0; start_time_ = OS::Ticks(); } @@ -87,11 +87,14 @@ void HistogramTimer::Start() { void HistogramTimer::Stop() { if (histogram_.Enabled()) { stop_time_ = OS::Ticks(); - // Compute the delta between start and stop, in milliseconds. int milliseconds = static_cast<int>(stop_time_ - start_time_) / 1000; histogram_.AddSample(milliseconds); } + if (FLAG_log_internal_timer_events) { + LOG(Isolate::Current(), + TimerEvent(histogram_.name_, start_time_, OS::Ticks())); + } } } } // namespace v8::internal diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index f20a41aa5f..8233f861ea 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -67,6 +67,62 @@ namespace v8 { + +static Handle<Value> Throw(const char* message) { + return ThrowException(String::New(message)); +} + + +// TODO(rossberg): should replace these by proper uses of HasInstance, +// once we figure out a good way to make the templates global. +const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; +const char kArrayMarkerPropName[] = "d8::_is_typed_array_"; + + +#define FOR_EACH_SYMBOL(V) \ + V(ArrayBuffer, "ArrayBuffer") \ + V(ArrayBufferMarkerPropName, kArrayBufferMarkerPropName) \ + V(ArrayMarkerPropName, kArrayMarkerPropName) \ + V(buffer, "buffer") \ + V(byteLength, "byteLength") \ + V(byteOffset, "byteOffset") \ + V(BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \ + V(length, "length") + + +class Symbols { + public: + explicit Symbols(Isolate* isolate) : isolate_(isolate) { + HandleScope scope; +#define INIT_SYMBOL(name, value) \ + name##_ = Persistent<String>::New(String::NewSymbol(value)); + FOR_EACH_SYMBOL(INIT_SYMBOL) +#undef INIT_SYMBOL + isolate->SetData(this); + } + + ~Symbols() { +#define DISPOSE_SYMBOL(name, value) name##_.Dispose(); + FOR_EACH_SYMBOL(DISPOSE_SYMBOL) +#undef DISPOSE_SYMBOL + isolate_->SetData(NULL); // Not really needed, just to be sure... + } + +#define DEFINE_SYMBOL_GETTER(name, value) \ + static Persistent<String> name(Isolate* isolate) { \ + return reinterpret_cast<Symbols*>(isolate->GetData())->name##_; \ + } + FOR_EACH_SYMBOL(DEFINE_SYMBOL_GETTER) +#undef DEFINE_SYMBOL_GETTER + + private: + Isolate* isolate_; +#define DEFINE_MEMBER(name, value) Persistent<String> name##_; + FOR_EACH_SYMBOL(DEFINE_MEMBER) +#undef DEFINE_MEMBER +}; + + LineEditor *LineEditor::first_ = NULL; @@ -92,17 +148,17 @@ LineEditor* LineEditor::Get() { class DumbLineEditor: public LineEditor { public: - DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { } + explicit DumbLineEditor(Isolate* isolate) + : LineEditor(LineEditor::DUMB, "dumb"), isolate_(isolate) { } virtual Handle<String> Prompt(const char* prompt); + private: + Isolate* isolate_; }; -static DumbLineEditor dumb_line_editor; - - Handle<String> DumbLineEditor::Prompt(const char* prompt) { printf("%s", prompt); - return Shell::ReadFromStdin(); + return Shell::ReadFromStdin(isolate_); } @@ -115,7 +171,6 @@ i::Mutex* Shell::context_mutex_(i::OS::CreateMutex()); Persistent<Context> Shell::utility_context_; #endif // V8_SHARED -LineEditor* Shell::console = NULL; Persistent<Context> Shell::evaluation_context_; ShellOptions Shell::options; const char* Shell::kPrompt = "d8> "; @@ -200,7 +255,13 @@ Handle<Value> Shell::Write(const Arguments& args) { if (i != 0) { printf(" "); } - v8::String::Utf8Value str(args[i]); + + // Explicitly catch potential exceptions in toString(). + v8::TryCatch try_catch; + Handle<String> str_obj = args[i]->ToString(); + if (try_catch.HasCaught()) return try_catch.ReThrow(); + + v8::String::Utf8Value str(str_obj); int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout)); if (n != str.length()) { printf("Error in fwrite\n"); @@ -226,17 +287,17 @@ Handle<Value> Shell::DisableProfiler(const Arguments& args) { Handle<Value> Shell::Read(const Arguments& args) { String::Utf8Value file(args[0]); if (*file == NULL) { - return ThrowException(String::New("Error loading file")); + return Throw("Error loading file"); } - Handle<String> source = ReadFile(*file); + Handle<String> source = ReadFile(args.GetIsolate(), *file); if (source.IsEmpty()) { - return ThrowException(String::New("Error loading file")); + return Throw("Error loading file"); } return source; } -Handle<String> Shell::ReadFromStdin() { +Handle<String> Shell::ReadFromStdin(Isolate* isolate) { static const int kBufferSize = 256; char buffer[kBufferSize]; Handle<String> accumulator = String::New(""); @@ -247,7 +308,7 @@ Handle<String> Shell::ReadFromStdin() { // If fgets gets an error, just give up. char* input = NULL; { // Release lock for blocking input. - Unlocker unlock(Isolate::GetCurrent()); + Unlocker unlock(isolate); input = fgets(buffer, kBufferSize, stdin); } if (input == NULL) return Handle<String>(); @@ -271,14 +332,14 @@ Handle<Value> Shell::Load(const Arguments& args) { HandleScope handle_scope; String::Utf8Value file(args[i]); if (*file == NULL) { - return ThrowException(String::New("Error loading file")); + return Throw("Error loading file"); } - Handle<String> source = ReadFile(*file); + Handle<String> source = ReadFile(args.GetIsolate(), *file); if (source.IsEmpty()) { - return ThrowException(String::New("Error loading file")); + return Throw("Error loading file"); } if (!ExecuteString(source, String::New(*file), false, true)) { - return ThrowException(String::New("Error executing file")); + return Throw("Error executing file"); } } return Undefined(); @@ -308,7 +369,7 @@ static int32_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { if (try_catch->HasCaught()) return 0; if (raw_value < 0) { - ThrowException(String::New("Array length must not be negative.")); + Throw("Array length must not be negative."); return 0; } @@ -317,33 +378,27 @@ static int32_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { ASSERT(kMaxLength == i::ExternalArray::kMaxLength); #endif // V8_SHARED if (raw_value > static_cast<int32_t>(kMaxLength)) { - ThrowException( - String::New("Array length exceeds maximum length.")); + Throw("Array length exceeds maximum length."); } return raw_value; } -// TODO(rossberg): should replace these by proper uses of HasInstance, -// once we figure out a good way to make the templates global. -const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; -const char kArrayMarkerPropName[] = "d8::_is_typed_array_"; - - -Handle<Value> Shell::CreateExternalArrayBuffer(Handle<Object> buffer, +Handle<Value> Shell::CreateExternalArrayBuffer(Isolate* isolate, + Handle<Object> buffer, int32_t length) { static const int32_t kMaxSize = 0x7fffffff; // Make sure the total size fits into a (signed) int. if (length < 0 || length > kMaxSize) { - return ThrowException(String::New("ArrayBuffer exceeds maximum size (2G)")); + return Throw("ArrayBuffer exceeds maximum size (2G)"); } uint8_t* data = new uint8_t[length]; if (data == NULL) { - return ThrowException(String::New("Memory allocation failed")); + return Throw("Memory allocation failed"); } memset(data, 0, length); - buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); + buffer->SetHiddenValue(Symbols::ArrayBufferMarkerPropName(isolate), True()); Persistent<Object> persistent_array = Persistent<Object>::New(buffer); persistent_array.MakeWeak(data, ExternalArrayWeakCallback); persistent_array.MarkIndependent(); @@ -351,7 +406,7 @@ Handle<Value> Shell::CreateExternalArrayBuffer(Handle<Object> buffer, buffer->SetIndexedPropertiesToExternalArrayData( data, v8::kExternalByteArray, length); - buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly); + buffer->Set(Symbols::byteLength(isolate), Int32::New(length), ReadOnly); return buffer; } @@ -367,18 +422,18 @@ Handle<Value> Shell::ArrayBuffer(const Arguments& args) { } if (args.Length() == 0) { - return ThrowException( - String::New("ArrayBuffer constructor must have one argument")); + return Throw("ArrayBuffer constructor must have one argument"); } TryCatch try_catch; int32_t length = convertToUint(args[0], &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); - return CreateExternalArrayBuffer(args.This(), length); + return CreateExternalArrayBuffer(args.GetIsolate(), args.This(), length); } -Handle<Object> Shell::CreateExternalArray(Handle<Object> array, +Handle<Object> Shell::CreateExternalArray(Isolate* isolate, + Handle<Object> array, Handle<Object> buffer, ExternalArrayType type, int32_t length, @@ -394,12 +449,13 @@ Handle<Object> Shell::CreateExternalArray(Handle<Object> array, array->SetIndexedPropertiesToExternalArrayData( static_cast<uint8_t*>(data) + byteOffset, type, length); - array->SetHiddenValue(String::New(kArrayMarkerPropName), Int32::New(type)); - array->Set(String::New("byteLength"), Int32::New(byteLength), ReadOnly); - array->Set(String::New("byteOffset"), Int32::New(byteOffset), ReadOnly); - array->Set(String::New("length"), Int32::New(length), ReadOnly); - array->Set(String::New("BYTES_PER_ELEMENT"), Int32::New(element_size)); - array->Set(String::New("buffer"), buffer, ReadOnly); + array->SetHiddenValue(Symbols::ArrayMarkerPropName(isolate), + Int32::New(type)); + array->Set(Symbols::byteLength(isolate), Int32::New(byteLength), ReadOnly); + array->Set(Symbols::byteOffset(isolate), Int32::New(byteOffset), ReadOnly); + array->Set(Symbols::length(isolate), Int32::New(length), ReadOnly); + array->Set(Symbols::BYTES_PER_ELEMENT(isolate), Int32::New(element_size)); + array->Set(Symbols::buffer(isolate), buffer, ReadOnly); return array; } @@ -408,6 +464,7 @@ Handle<Object> Shell::CreateExternalArray(Handle<Object> array, Handle<Value> Shell::CreateExternalArray(const Arguments& args, ExternalArrayType type, int32_t element_size) { + Isolate* isolate = args.GetIsolate(); if (!args.IsConstructCall()) { Handle<Value>* rec_args = new Handle<Value>[args.Length()]; for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; @@ -433,16 +490,15 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, int32_t byteOffset; bool init_from_array = false; if (args.Length() == 0) { - return ThrowException( - String::New("Array constructor must have at least one argument")); + return Throw("Array constructor must have at least one argument"); } if (args[0]->IsObject() && !args[0]->ToObject()->GetHiddenValue( - String::New(kArrayBufferMarkerPropName)).IsEmpty()) { + Symbols::ArrayBufferMarkerPropName(isolate)).IsEmpty()) { // Construct from ArrayBuffer. buffer = args[0]->ToObject(); int32_t bufferLength = - convertToUint(buffer->Get(String::New("byteLength")), &try_catch); + convertToUint(buffer->Get(Symbols::byteLength(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); if (args.Length() < 2 || args[1]->IsUndefined()) { @@ -451,11 +507,10 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, byteOffset = convertToUint(args[1], &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); if (byteOffset > bufferLength) { - return ThrowException(String::New("byteOffset out of bounds")); + return Throw("byteOffset out of bounds"); } if (byteOffset % element_size != 0) { - return ThrowException( - String::New("byteOffset must be multiple of element size")); + return Throw("byteOffset must be multiple of element size"); } } @@ -463,23 +518,22 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, byteLength = bufferLength - byteOffset; length = byteLength / element_size; if (byteLength % element_size != 0) { - return ThrowException( - String::New("buffer size must be multiple of element size")); + return Throw("buffer size must be multiple of element size"); } } else { length = convertToUint(args[2], &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); byteLength = length * element_size; if (byteOffset + byteLength > bufferLength) { - return ThrowException(String::New("length out of bounds")); + return Throw("length out of bounds"); } } } else { if (args[0]->IsObject() && - args[0]->ToObject()->Has(String::New("length"))) { + args[0]->ToObject()->Has(Symbols::length(isolate))) { // Construct from array. length = convertToUint( - args[0]->ToObject()->Get(String::New("length")), &try_catch); + args[0]->ToObject()->Get(Symbols::length(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); init_from_array = true; } else { @@ -491,7 +545,7 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, byteOffset = 0; Handle<Object> global = Context::GetCurrent()->Global(); - Handle<Value> array_buffer = global->Get(String::New("ArrayBuffer")); + Handle<Value> array_buffer = global->Get(Symbols::ArrayBuffer(isolate)); ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction()); Handle<Value> buffer_args[] = { Uint32::New(byteLength) }; Handle<Value> result = Handle<Function>::Cast(array_buffer)->NewInstance( @@ -500,8 +554,9 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, buffer = result->ToObject(); } - Handle<Object> array = CreateExternalArray( - args.This(), buffer, type, length, byteLength, byteOffset, element_size); + Handle<Object> array = + CreateExternalArray(isolate, args.This(), buffer, type, length, + byteLength, byteOffset, element_size); if (init_from_array) { Handle<Object> init = args[0]->ToObject(); @@ -516,25 +571,23 @@ Handle<Value> Shell::ArrayBufferSlice(const Arguments& args) { TryCatch try_catch; if (!args.This()->IsObject()) { - return ThrowException( - String::New("'slice' invoked on non-object receiver")); + return Throw("'slice' invoked on non-object receiver"); } + Isolate* isolate = args.GetIsolate(); Local<Object> self = args.This(); Local<Value> marker = - self->GetHiddenValue(String::New(kArrayBufferMarkerPropName)); + self->GetHiddenValue(Symbols::ArrayBufferMarkerPropName(isolate)); if (marker.IsEmpty()) { - return ThrowException( - String::New("'slice' invoked on wrong receiver type")); + return Throw("'slice' invoked on wrong receiver type"); } int32_t length = - convertToUint(self->Get(String::New("byteLength")), &try_catch); + convertToUint(self->Get(Symbols::byteLength(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); if (args.Length() == 0) { - return ThrowException( - String::New("'slice' must have at least one argument")); + return Throw("'slice' must have at least one argument"); } int32_t begin = convertToInt(args[0], &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); @@ -573,32 +626,31 @@ Handle<Value> Shell::ArraySubArray(const Arguments& args) { TryCatch try_catch; if (!args.This()->IsObject()) { - return ThrowException( - String::New("'subarray' invoked on non-object receiver")); + return Throw("'subarray' invoked on non-object receiver"); } + Isolate* isolate = args.GetIsolate(); Local<Object> self = args.This(); - Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); + Local<Value> marker = + self->GetHiddenValue(Symbols::ArrayMarkerPropName(isolate)); if (marker.IsEmpty()) { - return ThrowException( - String::New("'subarray' invoked on wrong receiver type")); + return Throw("'subarray' invoked on wrong receiver type"); } - Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); + Handle<Object> buffer = self->Get(Symbols::buffer(isolate))->ToObject(); if (try_catch.HasCaught()) return try_catch.ReThrow(); int32_t length = - convertToUint(self->Get(String::New("length")), &try_catch); + convertToUint(self->Get(Symbols::length(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); int32_t byteOffset = - convertToUint(self->Get(String::New("byteOffset")), &try_catch); + convertToUint(self->Get(Symbols::byteOffset(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); int32_t element_size = - convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); + convertToUint(self->Get(Symbols::BYTES_PER_ELEMENT(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); if (args.Length() == 0) { - return ThrowException( - String::New("'subarray' must have at least one argument")); + return Throw("'subarray' must have at least one argument"); } int32_t begin = convertToInt(args[0], &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); @@ -633,35 +685,33 @@ Handle<Value> Shell::ArraySet(const Arguments& args) { TryCatch try_catch; if (!args.This()->IsObject()) { - return ThrowException( - String::New("'set' invoked on non-object receiver")); + return Throw("'set' invoked on non-object receiver"); } + Isolate* isolate = args.GetIsolate(); Local<Object> self = args.This(); - Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); + Local<Value> marker = + self->GetHiddenValue(Symbols::ArrayMarkerPropName(isolate)); if (marker.IsEmpty()) { - return ThrowException( - String::New("'set' invoked on wrong receiver type")); + return Throw("'set' invoked on wrong receiver type"); } int32_t length = - convertToUint(self->Get(String::New("length")), &try_catch); + convertToUint(self->Get(Symbols::length(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); int32_t element_size = - convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); + convertToUint(self->Get(Symbols::BYTES_PER_ELEMENT(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); if (args.Length() == 0) { - return ThrowException( - String::New("'set' must have at least one argument")); + return Throw("'set' must have at least one argument"); } if (!args[0]->IsObject() || - !args[0]->ToObject()->Has(String::New("length"))) { - return ThrowException( - String::New("'set' invoked with non-array argument")); + !args[0]->ToObject()->Has(Symbols::length(isolate))) { + return Throw("'set' invoked with non-array argument"); } Handle<Object> source = args[0]->ToObject(); int32_t source_length = - convertToUint(source->Get(String::New("length")), &try_catch); + convertToUint(source->Get(Symbols::length(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); int32_t offset; @@ -672,31 +722,32 @@ Handle<Value> Shell::ArraySet(const Arguments& args) { if (try_catch.HasCaught()) return try_catch.ReThrow(); } if (offset + source_length > length) { - return ThrowException(String::New("offset or source length out of bounds")); + return Throw("offset or source length out of bounds"); } int32_t source_element_size; - if (source->GetHiddenValue(String::New(kArrayMarkerPropName)).IsEmpty()) { + if (source->GetHiddenValue(Symbols::ArrayMarkerPropName(isolate)).IsEmpty()) { source_element_size = 0; } else { source_element_size = - convertToUint(source->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); + convertToUint(source->Get(Symbols::BYTES_PER_ELEMENT(isolate)), + &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); } if (element_size == source_element_size && self->GetConstructor()->StrictEquals(source->GetConstructor())) { // Use memmove on the array buffers. - Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); + Handle<Object> buffer = self->Get(Symbols::buffer(isolate))->ToObject(); if (try_catch.HasCaught()) return try_catch.ReThrow(); Handle<Object> source_buffer = - source->Get(String::New("buffer"))->ToObject(); + source->Get(Symbols::buffer(isolate))->ToObject(); if (try_catch.HasCaught()) return try_catch.ReThrow(); int32_t byteOffset = - convertToUint(self->Get(String::New("byteOffset")), &try_catch); + convertToUint(self->Get(Symbols::byteOffset(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); int32_t source_byteOffset = - convertToUint(source->Get(String::New("byteOffset")), &try_catch); + convertToUint(source->Get(Symbols::byteOffset(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); uint8_t* dest = byteOffset + offset * element_size + static_cast<uint8_t*>( @@ -712,10 +763,10 @@ Handle<Value> Shell::ArraySet(const Arguments& args) { } } else { // Need to copy element-wise to make the right conversions. - Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); + Handle<Object> buffer = self->Get(Symbols::buffer(isolate))->ToObject(); if (try_catch.HasCaught()) return try_catch.ReThrow(); Handle<Object> source_buffer = - source->Get(String::New("buffer"))->ToObject(); + source->Get(Symbols::buffer(isolate))->ToObject(); if (try_catch.HasCaught()) return try_catch.ReThrow(); if (buffer->StrictEquals(source_buffer)) { @@ -723,10 +774,10 @@ Handle<Value> Shell::ArraySet(const Arguments& args) { // This gets a bit tricky in the case of different element sizes // (which, of course, is extremely unlikely to ever occur in practice). int32_t byteOffset = - convertToUint(self->Get(String::New("byteOffset")), &try_catch); + convertToUint(self->Get(Symbols::byteOffset(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); int32_t source_byteOffset = - convertToUint(source->Get(String::New("byteOffset")), &try_catch); + convertToUint(source->Get(Symbols::byteOffset(isolate)), &try_catch); if (try_catch.HasCaught()) return try_catch.ReThrow(); // Copy as much as we can from left to right. @@ -772,8 +823,9 @@ Handle<Value> Shell::ArraySet(const Arguments& args) { void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { HandleScope scope; + Isolate* isolate = Isolate::GetCurrent(); int32_t length = - object->ToObject()->Get(String::New("byteLength"))->Uint32Value(); + object->ToObject()->Get(Symbols::byteLength(isolate))->Uint32Value(); V8::AdjustAmountOfExternalAllocatedMemory(-length); delete[] static_cast<uint8_t*>(data); object.Dispose(); @@ -1139,7 +1191,7 @@ Handle<FunctionTemplate> Shell::CreateArrayTemplate(InvocationCallback fun) { } -Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { +Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) { Handle<ObjectTemplate> global_template = ObjectTemplate::New(); global_template->Set(String::New("print"), FunctionTemplate::New(Print)); global_template->Set(String::New("write"), FunctionTemplate::New(Write)); @@ -1159,7 +1211,7 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { // Bind the handlers for external arrays. PropertyAttribute attr = static_cast<PropertyAttribute>(ReadOnly | DontDelete); - global_template->Set(String::New("ArrayBuffer"), + global_template->Set(Symbols::ArrayBuffer(isolate), CreateArrayBufferTemplate(ArrayBuffer), attr); global_template->Set(String::New("Int8Array"), CreateArrayTemplate(Int8Array), attr); @@ -1196,7 +1248,7 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { } -void Shell::Initialize() { +void Shell::Initialize(Isolate* isolate) { #ifdef COMPRESS_STARTUP_DATA_BZ2 BZip2Decompressor startup_data_decompressor; int bz2_result = startup_data_decompressor.Decompress(); @@ -1217,12 +1269,15 @@ void Shell::Initialize() { V8::SetAddHistogramSampleFunction(AddHistogramSample); } #endif // V8_SHARED - if (options.test_shell) return; +} + +void Shell::InitializeDebugger(Isolate* isolate) { + if (options.test_shell) return; #ifndef V8_SHARED Locker lock; HandleScope scope; - Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); + Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate); utility_context_ = Context::New(NULL, global_template); #ifdef ENABLE_DEBUGGER_SUPPORT @@ -1236,13 +1291,13 @@ void Shell::Initialize() { } -Persistent<Context> Shell::CreateEvaluationContext() { +Persistent<Context> Shell::CreateEvaluationContext(Isolate* isolate) { #ifndef V8_SHARED // This needs to be a critical section since this is not thread-safe i::ScopedLock lock(context_mutex_); #endif // V8_SHARED // Initialize the global objects - Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); + Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate); Persistent<Context> context = Context::New(NULL, global_template); ASSERT(!context.IsEmpty()); Context::Scope scope(context); @@ -1288,7 +1343,6 @@ int CompareKeys(const void* a, const void* b) { void Shell::OnExit() { - if (console != NULL) console->Close(); if (i::FLAG_dump_counters) { int number_of_counters = 0; for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) { @@ -1348,9 +1402,9 @@ static FILE* FOpen(const char* path, const char* mode) { } -static char* ReadChars(const char* name, int* size_out) { +static char* ReadChars(Isolate* isolate, const char* name, int* size_out) { // Release the V8 lock while reading files. - v8::Unlocker unlocker(Isolate::GetCurrent()); + v8::Unlocker unlocker(isolate); FILE* file = FOpen(name, "rb"); if (file == NULL) return NULL; @@ -1375,15 +1429,17 @@ Handle<Value> Shell::ReadBuffer(const Arguments& args) { String::Utf8Value filename(args[0]); int length; if (*filename == NULL) { - return ThrowException(String::New("Error loading file")); + return Throw("Error loading file"); } - uint8_t* data = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length)); + uint8_t* data = reinterpret_cast<uint8_t*>( + ReadChars(args.GetIsolate(), *filename, &length)); if (data == NULL) { - return ThrowException(String::New("Error reading file")); + return Throw("Error reading file"); } + Isolate* isolate = args.GetIsolate(); Handle<Object> buffer = Object::New(); - buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); + buffer->SetHiddenValue(Symbols::ArrayBufferMarkerPropName(isolate), True()); Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer); persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback); persistent_buffer.MarkIndependent(); @@ -1391,7 +1447,7 @@ Handle<Value> Shell::ReadBuffer(const Arguments& args) { buffer->SetIndexedPropertiesToExternalArrayData( data, kExternalUnsignedByteArray, length); - buffer->Set(String::New("byteLength"), + buffer->Set(Symbols::byteLength(isolate), Int32::New(static_cast<int32_t>(length)), ReadOnly); return buffer; } @@ -1421,9 +1477,9 @@ static char* ReadWord(char* data) { // Reads a file into a v8 string. -Handle<String> Shell::ReadFile(const char* name) { +Handle<String> Shell::ReadFile(Isolate* isolate, const char* name) { int size = 0; - char* chars = ReadChars(name, &size); + char* chars = ReadChars(isolate, name, &size); if (chars == NULL) return Handle<String>(); Handle<String> result = String::New(chars); delete[] chars; @@ -1431,12 +1487,13 @@ Handle<String> Shell::ReadFile(const char* name) { } -void Shell::RunShell() { +void Shell::RunShell(Isolate* isolate) { Locker locker; Context::Scope context_scope(evaluation_context_); HandleScope outer_scope; Handle<String> name = String::New("(d8)"); - console = LineEditor::Get(); + DumbLineEditor dumb_line_editor(isolate); + LineEditor* console = LineEditor::Get(); printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name()); console->Open(); while (true) { @@ -1446,6 +1503,7 @@ void Shell::RunShell() { ExecuteString(input, name, true, true); } printf("\n"); + console->Close(); } @@ -1453,9 +1511,9 @@ void Shell::RunShell() { class ShellThread : public i::Thread { public: // Takes ownership of the underlying char array of |files|. - ShellThread(int no, char* files) + ShellThread(Isolate* isolate, char* files) : Thread("d8:ShellThread"), - no_(no), files_(files) { } + isolate_(isolate), files_(files) { } ~ShellThread() { delete[] files_; @@ -1463,7 +1521,7 @@ class ShellThread : public i::Thread { virtual void Run(); private: - int no_; + Isolate* isolate_; char* files_; }; @@ -1483,7 +1541,8 @@ void ShellThread::Run() { // Prepare the context for this thread. Locker locker; HandleScope outer_scope; - Persistent<Context> thread_context = Shell::CreateEvaluationContext(); + Persistent<Context> thread_context = + Shell::CreateEvaluationContext(isolate_); Context::Scope context_scope(thread_context); while ((ptr != NULL) && (*ptr != '\0')) { @@ -1496,7 +1555,7 @@ void ShellThread::Run() { continue; } - Handle<String> str = Shell::ReadFile(filename); + Handle<String> str = Shell::ReadFile(isolate_, filename); if (str.IsEmpty()) { printf("File '%s' not found\n", filename); Shell::Exit(1); @@ -1524,7 +1583,7 @@ SourceGroup::~SourceGroup() { } -void SourceGroup::Execute() { +void SourceGroup::Execute(Isolate* isolate) { for (int i = begin_offset_; i < end_offset_; ++i) { const char* arg = argv_[i]; if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) { @@ -1542,7 +1601,7 @@ void SourceGroup::Execute() { // Use all other arguments as names of files to load and run. HandleScope handle_scope; Handle<String> file_name = String::New(arg); - Handle<String> source = ReadFile(arg); + Handle<String> source = ReadFile(isolate, arg); if (source.IsEmpty()) { printf("Error reading '%s'\n", arg); Shell::Exit(1); @@ -1555,9 +1614,9 @@ void SourceGroup::Execute() { } -Handle<String> SourceGroup::ReadFile(const char* name) { +Handle<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) { int size; - char* chars = ReadChars(name, &size); + char* chars = ReadChars(isolate, name, &size); if (chars == NULL) return Handle<String>(); Handle<String> result = String::New(chars, size); delete[] chars; @@ -1583,10 +1642,11 @@ void SourceGroup::ExecuteInThread() { Isolate::Scope iscope(isolate); Locker lock(isolate); HandleScope scope; - Persistent<Context> context = Shell::CreateEvaluationContext(); + Symbols symbols(isolate); + Persistent<Context> context = Shell::CreateEvaluationContext(isolate); { Context::Scope cscope(context); - Execute(); + Execute(isolate); } context.Dispose(); if (Shell::options.send_idle_notification) { @@ -1754,21 +1814,21 @@ bool Shell::SetOptions(int argc, char* argv[]) { } -int Shell::RunMain(int argc, char* argv[]) { +int Shell::RunMain(Isolate* isolate, int argc, char* argv[]) { #ifndef V8_SHARED i::List<i::Thread*> threads(1); if (options.parallel_files != NULL) { for (int i = 0; i < options.num_parallel_files; i++) { char* files = NULL; - { Locker lock(Isolate::GetCurrent()); + { Locker lock(isolate); int size = 0; - files = ReadChars(options.parallel_files[i], &size); + files = ReadChars(isolate, options.parallel_files[i], &size); } if (files == NULL) { printf("File list '%s' not found\n", options.parallel_files[i]); Exit(1); } - ShellThread* thread = new ShellThread(threads.length(), files); + ShellThread* thread = new ShellThread(isolate, files); thread->Start(); threads.Add(thread); } @@ -1780,7 +1840,7 @@ int Shell::RunMain(int argc, char* argv[]) { { // NOLINT Locker lock; HandleScope scope; - Persistent<Context> context = CreateEvaluationContext(); + Persistent<Context> context = CreateEvaluationContext(isolate); if (options.last_run) { // Keep using the same context in the interactive shell. evaluation_context_ = context; @@ -1794,7 +1854,7 @@ int Shell::RunMain(int argc, char* argv[]) { } { Context::Scope cscope(context); - options.isolate_sources[0].Execute(); + options.isolate_sources[0].Execute(isolate); } if (!options.last_run) { context.Dispose(); @@ -1836,59 +1896,62 @@ int Shell::RunMain(int argc, char* argv[]) { int Shell::Main(int argc, char* argv[]) { if (!SetOptions(argc, argv)) return 1; - Initialize(); - int result = 0; - if (options.stress_opt || options.stress_deopt) { - Testing::SetStressRunType( - options.stress_opt ? Testing::kStressTypeOpt - : Testing::kStressTypeDeopt); - int stress_runs = Testing::GetStressRuns(); - for (int i = 0; i < stress_runs && result == 0; i++) { - printf("============ Stress %d/%d ============\n", i + 1, stress_runs); - Testing::PrepareStressRun(i); - options.last_run = (i == stress_runs - 1); - result = RunMain(argc, argv); - } - printf("======== Full Deoptimization =======\n"); - Testing::DeoptimizeAll(); + Isolate* isolate = Isolate::GetCurrent(); + { + Initialize(isolate); + Symbols symbols(isolate); + InitializeDebugger(isolate); + + if (options.stress_opt || options.stress_deopt) { + Testing::SetStressRunType(options.stress_opt + ? Testing::kStressTypeOpt + : Testing::kStressTypeDeopt); + int stress_runs = Testing::GetStressRuns(); + for (int i = 0; i < stress_runs && result == 0; i++) { + printf("============ Stress %d/%d ============\n", i + 1, stress_runs); + Testing::PrepareStressRun(i); + options.last_run = (i == stress_runs - 1); + result = RunMain(isolate, argc, argv); + } + printf("======== Full Deoptimization =======\n"); + Testing::DeoptimizeAll(); #if !defined(V8_SHARED) - } else if (i::FLAG_stress_runs > 0) { - int stress_runs = i::FLAG_stress_runs; - for (int i = 0; i < stress_runs && result == 0; i++) { - printf("============ Run %d/%d ============\n", i + 1, stress_runs); - options.last_run = (i == stress_runs - 1); - result = RunMain(argc, argv); - } + } else if (i::FLAG_stress_runs > 0) { + int stress_runs = i::FLAG_stress_runs; + for (int i = 0; i < stress_runs && result == 0; i++) { + printf("============ Run %d/%d ============\n", i + 1, stress_runs); + options.last_run = (i == stress_runs - 1); + result = RunMain(isolate, argc, argv); + } #endif - } else { - result = RunMain(argc, argv); - } + } else { + result = RunMain(isolate, argc, argv); + } #if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) - // Run remote debugger if requested, but never on --test - if (i::FLAG_remote_debugger && !options.test_shell) { - InstallUtilityScript(); - RunRemoteDebugger(i::FLAG_debugger_port); - return 0; - } + // Run remote debugger if requested, but never on --test + if (i::FLAG_remote_debugger && !options.test_shell) { + InstallUtilityScript(); + RunRemoteDebugger(i::FLAG_debugger_port); + return 0; + } #endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT - // Run interactive shell if explicitly requested or if no script has been - // executed, but never on --test + // Run interactive shell if explicitly requested or if no script has been + // executed, but never on --test - if (( options.interactive_shell - || !options.script_executed ) - && !options.test_shell ) { + if (( options.interactive_shell || !options.script_executed ) + && !options.test_shell ) { #if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) - if (!i::FLAG_debugger) { - InstallUtilityScript(); - } + if (!i::FLAG_debugger) { + InstallUtilityScript(); + } #endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT - RunShell(); + RunShell(isolate); + } } - V8::Dispose(); #ifndef V8_SHARED diff --git a/deps/v8/src/d8.gyp b/deps/v8/src/d8.gyp index 051b0922b7..a8361e6b4e 100644 --- a/deps/v8/src/d8.gyp +++ b/deps/v8/src/d8.gyp @@ -61,7 +61,8 @@ 'libraries': [ '-lreadline', ], 'sources': [ 'd8-readline.cc' ], }], - [ 'OS!="win"', { + ['(OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="netbsd" \ + or OS=="openbsd" or OS=="solaris" or OS=="android")', { 'sources': [ 'd8-posix.cc', ] }], [ 'OS=="win"', { @@ -98,7 +99,7 @@ '<(SHARED_INTERMEDIATE_DIR)/d8-js.cc', ], 'action': [ - '<(python)', + 'python', '../tools/js2c.py', '<@(_outputs)', 'D8', diff --git a/deps/v8/src/d8.h b/deps/v8/src/d8.h index a62a81fd9c..161c6533e7 100644 --- a/deps/v8/src/d8.h +++ b/deps/v8/src/d8.h @@ -158,7 +158,7 @@ class SourceGroup { void End(int offset) { end_offset_ = offset; } - void Execute(); + void Execute(Isolate* isolate); #ifndef V8_SHARED void StartExecuteInThread(); @@ -187,7 +187,7 @@ class SourceGroup { #endif // V8_SHARED void ExitShell(int exit_code); - Handle<String> ReadFile(const char* name); + Handle<String> ReadFile(Isolate* isolate, const char* name); const char** argv_; int begin_offset_; @@ -272,9 +272,9 @@ class Shell : public i::AllStatic { bool report_exceptions); static const char* ToCString(const v8::String::Utf8Value& value); static void ReportException(TryCatch* try_catch); - static Handle<String> ReadFile(const char* name); - static Persistent<Context> CreateEvaluationContext(); - static int RunMain(int argc, char* argv[]); + static Handle<String> ReadFile(Isolate* isolate, const char* name); + static Persistent<Context> CreateEvaluationContext(Isolate* isolate); + static int RunMain(Isolate* isolate, int argc, char* argv[]); static int Main(int argc, char* argv[]); static void Exit(int exit_code); @@ -310,9 +310,9 @@ class Shell : public i::AllStatic { static Handle<Value> DisableProfiler(const Arguments& args); static Handle<Value> Read(const Arguments& args); static Handle<Value> ReadBuffer(const Arguments& args); - static Handle<String> ReadFromStdin(); + static Handle<String> ReadFromStdin(Isolate* isolate); static Handle<Value> ReadLine(const Arguments& args) { - return ReadFromStdin(); + return ReadFromStdin(args.GetIsolate()); } static Handle<Value> Load(const Arguments& args); static Handle<Value> ArrayBuffer(const Arguments& args); @@ -365,7 +365,6 @@ class Shell : public i::AllStatic { static void AddOSMethods(Handle<ObjectTemplate> os_template); - static LineEditor* console; static const char* kPrompt; static ShellOptions options; @@ -384,15 +383,18 @@ class Shell : public i::AllStatic { static Counter* GetCounter(const char* name, bool is_histogram); static void InstallUtilityScript(); #endif // V8_SHARED - static void Initialize(); - static void RunShell(); + static void Initialize(Isolate* isolate); + static void InitializeDebugger(Isolate* isolate); + static void RunShell(Isolate* isolate); static bool SetOptions(int argc, char* argv[]); - static Handle<ObjectTemplate> CreateGlobalTemplate(); + static Handle<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate); static Handle<FunctionTemplate> CreateArrayBufferTemplate(InvocationCallback); static Handle<FunctionTemplate> CreateArrayTemplate(InvocationCallback); - static Handle<Value> CreateExternalArrayBuffer(Handle<Object> buffer, + static Handle<Value> CreateExternalArrayBuffer(Isolate* isolate, + Handle<Object> buffer, int32_t size); - static Handle<Object> CreateExternalArray(Handle<Object> array, + static Handle<Object> CreateExternalArray(Isolate* isolate, + Handle<Object> array, Handle<Object> buffer, ExternalArrayType type, int32_t length, diff --git a/deps/v8/src/date.js b/deps/v8/src/date.js index a54cb238c5..c75d12c651 100644 --- a/deps/v8/src/date.js +++ b/deps/v8/src/date.js @@ -107,7 +107,7 @@ function MakeDay(year, month, date) { } // Now we rely on year and month being SMIs. - return %DateMakeDay(year, month) + date - 1; + return %DateMakeDay(year | 0, month | 0) + date - 1; } diff --git a/deps/v8/src/dateparser-inl.h b/deps/v8/src/dateparser-inl.h index a5c7143bdd..3cb36fa433 100644 --- a/deps/v8/src/dateparser-inl.h +++ b/deps/v8/src/dateparser-inl.h @@ -62,7 +62,8 @@ bool DateParser::Parse(Vector<Char> str, // sss is in the range 000..999, // hh is in the range 00..23, // mm, ss, and sss default to 00 if missing, and - // timezone defaults to Z if missing. + // timezone defaults to Z if missing + // (following Safari, ISO actually demands local time). // Extensions: // We also allow sss to have more or less than three digits (but at // least one). diff --git a/deps/v8/src/debug-debugger.js b/deps/v8/src/debug-debugger.js index 163a0bd829..ea1a17d04b 100644 --- a/deps/v8/src/debug-debugger.js +++ b/deps/v8/src/debug-debugger.js @@ -1306,9 +1306,12 @@ ProtocolMessage.prototype.setOption = function(name, value) { }; -ProtocolMessage.prototype.failed = function(message) { +ProtocolMessage.prototype.failed = function(message, opt_details) { this.success = false; this.message = message; + if (IS_OBJECT(opt_details)) { + this.error_details = opt_details; + } }; @@ -1355,6 +1358,9 @@ ProtocolMessage.prototype.toJSONProtocol = function() { if (this.message) { json.message = this.message; } + if (this.error_details) { + json.error_details = this.error_details; + } json.running = this.running; return JSON.stringify(json); }; @@ -1427,6 +1433,8 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function( this.scopesRequest_(request, response); } else if (request.command == 'scope') { this.scopeRequest_(request, response); + } else if (request.command == 'setVariableValue') { + this.setVariableValueRequest_(request, response); } else if (request.command == 'evaluate') { this.evaluateRequest_(request, response); } else if (lol_is_enabled && request.command == 'getobj') { @@ -1953,11 +1961,12 @@ DebugCommandProcessor.prototype.frameRequest_ = function(request, response) { }; -DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) { +DebugCommandProcessor.prototype.resolveFrameFromScopeDescription_ = + function(scope_description) { // Get the frame for which the scope or scopes are requested. // With no frameNumber argument use the currently selected frame. - if (request.arguments && !IS_UNDEFINED(request.arguments.frameNumber)) { - frame_index = request.arguments.frameNumber; + if (scope_description && !IS_UNDEFINED(scope_description.frameNumber)) { + frame_index = scope_description.frameNumber; if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) { throw new Error('Invalid frame number'); } @@ -1971,13 +1980,13 @@ DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) { // 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)) { +DebugCommandProcessor.prototype.resolveScopeHolder_ = + function(scope_description) { + if (scope_description && "functionHandle" in scope_description) { + if (!IS_NUMBER(scope_description.functionHandle)) { throw new Error('Function handle must be a number'); } - var function_mirror = LookupMirror(request.arguments.functionHandle); + var function_mirror = LookupMirror(scope_description.functionHandle); if (!function_mirror) { throw new Error('Failed to find function object by handle'); } @@ -1992,14 +2001,14 @@ DebugCommandProcessor.prototype.scopeHolderForScopeRequest_ = } // Get the frame for which the scopes are requested. - var frame = this.frameForScopeRequest_(request); + var frame = this.resolveFrameFromScopeDescription_(scope_description); return frame; } } DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) { - var scope_holder = this.scopeHolderForScopeRequest_(request); + var scope_holder = this.resolveScopeHolder_(request.arguments); // Fill all scopes for this frame or function. var total_scopes = scope_holder.scopeCount(); @@ -2018,7 +2027,7 @@ DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) { DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) { // Get the frame or function for which the scope is requested. - var scope_holder = this.scopeHolderForScopeRequest_(request); + var scope_holder = this.resolveScopeHolder_(request.arguments); // With no scope argument just return top scope. var scope_index = 0; @@ -2033,6 +2042,77 @@ DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) { }; +// Reads value from protocol description. Description may be in form of type +// (for singletons), raw value (primitive types supported in JSON), +// string value description plus type (for primitive values) or handle id. +// Returns raw value or throws exception. +DebugCommandProcessor.resolveValue_ = function(value_description) { + if ("handle" in value_description) { + var value_mirror = LookupMirror(value_description.handle); + if (!value_mirror) { + throw new Error("Failed to resolve value by handle, ' #" + + mapping.handle + "# not found"); + } + return value_mirror.value(); + } else if ("stringDescription" in value_description) { + if (value_description.type == BOOLEAN_TYPE) { + return Boolean(value_description.stringDescription); + } else if (value_description.type == NUMBER_TYPE) { + return Number(value_description.stringDescription); + } if (value_description.type == STRING_TYPE) { + return String(value_description.stringDescription); + } else { + throw new Error("Unknown type"); + } + } else if ("value" in value_description) { + return value_description.value; + } else if (value_description.type == UNDEFINED_TYPE) { + return void 0; + } else if (value_description.type == NULL_TYPE) { + return null; + } else { + throw new Error("Failed to parse value description"); + } +}; + + +DebugCommandProcessor.prototype.setVariableValueRequest_ = + function(request, response) { + if (!request.arguments) { + response.failed('Missing arguments'); + return; + } + + if (IS_UNDEFINED(request.arguments.name)) { + response.failed('Missing variable name'); + } + var variable_name = request.arguments.name; + + var scope_description = request.arguments.scope; + + // Get the frame or function for which the scope is requested. + var scope_holder = this.resolveScopeHolder_(scope_description); + + if (IS_UNDEFINED(scope_description.number)) { + response.failed('Missing scope number'); + } + var scope_index = %ToNumber(scope_description.number); + + var scope = scope_holder.scope(scope_index); + + var new_value = + DebugCommandProcessor.resolveValue_(request.arguments.newValue); + + scope.setVariableValue(variable_name, new_value); + + var new_value_mirror = MakeMirror(new_value); + + response.body = { + newValue: new_value_mirror + }; +}; + + DebugCommandProcessor.prototype.evaluateRequest_ = function(request, response) { if (!request.arguments) { return response.failed('Missing arguments'); @@ -2387,8 +2467,17 @@ DebugCommandProcessor.prototype.changeLiveRequest_ = function( var new_source = request.arguments.new_source; - var result_description = Debug.LiveEdit.SetScriptSource(the_script, - new_source, preview_only, change_log); + var result_description; + try { + result_description = Debug.LiveEdit.SetScriptSource(the_script, + new_source, preview_only, change_log); + } catch (e) { + if (e instanceof Debug.LiveEdit.Failure && "details" in e) { + response.failed(e.message, e.details); + return; + } + throw e; + } response.body = {change_log: change_log, result: result_description}; if (!preview_only && !this.running_ && result_description.stack_modified) { @@ -2663,3 +2752,7 @@ function ValueToProtocolValue_(value, mirror_serializer) { } return json; } + +Debug.TestApi = { + CommandProcessorResolveValue: DebugCommandProcessor.resolveValue_ +}; diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index 6358d35317..ea1c0842b9 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -261,8 +261,12 @@ void BreakLocationIterator::Reset() { // Create relocation iterators for the two code objects. if (reloc_iterator_ != NULL) delete reloc_iterator_; if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_; - reloc_iterator_ = new RelocIterator(debug_info_->code()); - reloc_iterator_original_ = new RelocIterator(debug_info_->original_code()); + reloc_iterator_ = new RelocIterator( + debug_info_->code(), + ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)); + reloc_iterator_original_ = new RelocIterator( + debug_info_->original_code(), + ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)); // Position at the first break point. break_point_ = -1; @@ -782,9 +786,11 @@ bool Debug::CompileDebuggerScript(int index) { "error_loading_debugger", &computed_location, Vector<Handle<Object> >::empty(), Handle<String>(), Handle<JSArray>()); ASSERT(!isolate->has_pending_exception()); - isolate->set_pending_exception(*exception); - MessageHandler::ReportMessage(Isolate::Current(), NULL, message); - isolate->clear_pending_exception(); + if (!exception.is_null()) { + isolate->set_pending_exception(*exception); + MessageHandler::ReportMessage(Isolate::Current(), NULL, message); + isolate->clear_pending_exception(); + } return false; } @@ -2285,7 +2291,7 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { // Find the call address in the running code. This address holds the call to // either a DebugBreakXXX or to the debug break return entry code if the // break point is still active after processing the break point. - Address addr = frame->pc() - Assembler::kCallTargetAddressOffset; + Address addr = frame->pc() - Assembler::kPatchDebugBreakSlotReturnOffset; // Check if the location is at JS exit or debug break slot. bool at_js_return = false; @@ -2374,7 +2380,7 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { #endif // Find the call address in the running code. - Address addr = frame->pc() - Assembler::kCallTargetAddressOffset; + Address addr = frame->pc() - Assembler::kPatchDebugBreakSlotReturnOffset; // Check if the location is at JS return. RelocIterator it(debug_info->code()); @@ -2826,6 +2832,7 @@ void Debugger::OnScriptCollected(int id) { HandleScope scope(isolate_); // No more to do if not debugging. + if (isolate_->debug()->InDebugger()) return; if (!IsDebuggerActive()) return; if (!Debugger::EventActive(v8::ScriptCollected)) return; diff --git a/deps/v8/src/debug.h b/deps/v8/src/debug.h index 9e33f4b184..150e29e308 100644 --- a/deps/v8/src/debug.h +++ b/deps/v8/src/debug.h @@ -793,7 +793,6 @@ class Debugger { }; void OnAfterCompile(Handle<Script> script, AfterCompileFlags after_compile_flags); - void OnNewFunction(Handle<JSFunction> fun); void OnScriptCollected(int id); void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data, diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc index d1b00f8bde..8f1711144e 100644 --- a/deps/v8/src/deoptimizer.cc +++ b/deps/v8/src/deoptimizer.cc @@ -27,6 +27,7 @@ #include "v8.h" +#include "accessors.h" #include "codegen.h" #include "deoptimizer.h" #include "disasm.h" @@ -40,8 +41,11 @@ namespace v8 { namespace internal { DeoptimizerData::DeoptimizerData() { - eager_deoptimization_entry_code_ = NULL; - lazy_deoptimization_entry_code_ = NULL; + eager_deoptimization_entry_code_entries_ = -1; + lazy_deoptimization_entry_code_entries_ = -1; + size_t deopt_table_size = Deoptimizer::GetMaxDeoptTableSize(); + eager_deoptimization_entry_code_ = new VirtualMemory(deopt_table_size); + lazy_deoptimization_entry_code_ = new VirtualMemory(deopt_table_size); current_ = NULL; deoptimizing_code_list_ = NULL; #ifdef ENABLE_DEBUGGER_SUPPORT @@ -51,16 +55,18 @@ DeoptimizerData::DeoptimizerData() { DeoptimizerData::~DeoptimizerData() { - if (eager_deoptimization_entry_code_ != NULL) { - Isolate::Current()->memory_allocator()->Free( - eager_deoptimization_entry_code_); - eager_deoptimization_entry_code_ = NULL; - } - if (lazy_deoptimization_entry_code_ != NULL) { - Isolate::Current()->memory_allocator()->Free( - lazy_deoptimization_entry_code_); - lazy_deoptimization_entry_code_ = NULL; + delete eager_deoptimization_entry_code_; + eager_deoptimization_entry_code_ = NULL; + delete lazy_deoptimization_entry_code_; + lazy_deoptimization_entry_code_ = NULL; + + DeoptimizingCodeListNode* current = deoptimizing_code_list_; + while (current != NULL) { + DeoptimizingCodeListNode* prev = current; + current = current->next(); + delete prev; } + deoptimizing_code_list_ = NULL; } @@ -95,6 +101,20 @@ Deoptimizer* Deoptimizer::New(JSFunction* function, } +// No larger than 2K on all platforms +static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB; + + +size_t Deoptimizer::GetMaxDeoptTableSize() { + int entries_size = + Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_; + int commit_page_size = static_cast<int>(OS::CommitPageSize()); + int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) / + commit_page_size) + 1; + return static_cast<size_t>(commit_page_size * page_count); +} + + Deoptimizer* Deoptimizer::Grab(Isolate* isolate) { ASSERT(isolate == Isolate::Current()); Deoptimizer* result = isolate->deoptimizer_data()->current_; @@ -368,6 +388,8 @@ Deoptimizer::Deoptimizer(Isolate* isolate, output_count_(0), jsframe_count_(0), output_(NULL), + deferred_arguments_objects_values_(0), + deferred_arguments_objects_(0), deferred_heap_numbers_(0) { if (FLAG_trace_deopt && type != OSR) { if (type == DEBUGGER) { @@ -451,44 +473,45 @@ void Deoptimizer::DeleteFrameDescriptions() { } -Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) { +Address Deoptimizer::GetDeoptimizationEntry(int id, + BailoutType type, + GetEntryMode mode) { ASSERT(id >= 0); - if (id >= kNumberOfEntries) return NULL; - MemoryChunk* base = NULL; + if (id >= kMaxNumberOfEntries) return NULL; + VirtualMemory* base = NULL; + if (mode == ENSURE_ENTRY_CODE) { + EnsureCodeForDeoptimizationEntry(type, id); + } else { + ASSERT(mode == CALCULATE_ENTRY_ADDRESS); + } DeoptimizerData* data = Isolate::Current()->deoptimizer_data(); if (type == EAGER) { - if (data->eager_deoptimization_entry_code_ == NULL) { - data->eager_deoptimization_entry_code_ = CreateCode(type); - } base = data->eager_deoptimization_entry_code_; } else { - if (data->lazy_deoptimization_entry_code_ == NULL) { - data->lazy_deoptimization_entry_code_ = CreateCode(type); - } base = data->lazy_deoptimization_entry_code_; } return - static_cast<Address>(base->area_start()) + (id * table_entry_size_); + static_cast<Address>(base->address()) + (id * table_entry_size_); } int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) { - MemoryChunk* base = NULL; + VirtualMemory* base = NULL; DeoptimizerData* data = Isolate::Current()->deoptimizer_data(); if (type == EAGER) { base = data->eager_deoptimization_entry_code_; } else { base = data->lazy_deoptimization_entry_code_; } + Address base_casted = reinterpret_cast<Address>(base->address()); if (base == NULL || - addr < base->area_start() || - addr >= base->area_start() + - (kNumberOfEntries * table_entry_size_)) { + addr < base->address() || + addr >= base_casted + (kMaxNumberOfEntries * table_entry_size_)) { return kNotDeoptimizationEntry; } ASSERT_EQ(0, - static_cast<int>(addr - base->area_start()) % table_entry_size_); - return static_cast<int>(addr - base->area_start()) / table_entry_size_; + static_cast<int>(addr - base_casted) % table_entry_size_); + return static_cast<int>(addr - base_casted) / table_entry_size_; } @@ -512,7 +535,7 @@ int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data, shared->SourceCodePrint(&stream, -1); PrintF("[source:\n%s\n]", *stream.ToCString()); - UNREACHABLE(); + FATAL("unable to find pc offset during deoptimization"); return -1; } @@ -633,8 +656,21 @@ void Deoptimizer::DoComputeOutputFrames() { } -void Deoptimizer::MaterializeHeapNumbers() { +void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) { ASSERT_NE(DEBUGGER, bailout_type_); + + // Handlify all argument object values before triggering any allocation. + List<Handle<Object> > values(deferred_arguments_objects_values_.length()); + for (int i = 0; i < deferred_arguments_objects_values_.length(); ++i) { + values.Add(Handle<Object>(deferred_arguments_objects_values_[i])); + } + + // Play it safe and clear all unhandlified values before we continue. + deferred_arguments_objects_values_.Clear(); + + // Materialize all heap numbers before looking at arguments because when the + // output frames are used to materialize arguments objects later on they need + // to already contain valid heap numbers. for (int i = 0; i < deferred_heap_numbers_.length(); i++) { HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i]; Handle<Object> num = isolate_->factory()->NewNumber(d.value()); @@ -644,9 +680,55 @@ void Deoptimizer::MaterializeHeapNumbers() { d.value(), d.slot_address()); } - Memory::Object_at(d.slot_address()) = *num; } + + // Materialize arguments objects one frame at a time. + for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) { + if (frame_index != 0) it->Advance(); + JavaScriptFrame* frame = it->frame(); + Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate_); + Handle<JSObject> arguments; + for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) { + if (frame->GetExpression(i) == isolate_->heap()->arguments_marker()) { + ArgumentsObjectMaterializationDescriptor descriptor = + deferred_arguments_objects_.RemoveLast(); + const int length = descriptor.arguments_length(); + if (arguments.is_null()) { + if (frame->has_adapted_arguments()) { + // Use the arguments adapter frame we just built to materialize the + // arguments object. FunctionGetArguments can't throw an exception, + // so cast away the doubt with an assert. + arguments = Handle<JSObject>(JSObject::cast( + Accessors::FunctionGetArguments(*function, + NULL)->ToObjectUnchecked())); + values.RewindBy(length); + } else { + // Construct an arguments object and copy the parameters to a newly + // allocated arguments object backing store. + arguments = + isolate_->factory()->NewArgumentsObject(function, length); + Handle<FixedArray> array = + isolate_->factory()->NewFixedArray(length); + ASSERT(array->length() == length); + for (int i = length - 1; i >= 0 ; --i) { + array->set(i, *values.RemoveLast()); + } + arguments->set_elements(*array); + } + } + frame->SetExpression(i, *arguments); + ASSERT_EQ(Memory::Object_at(descriptor.slot_address()), *arguments); + if (FLAG_trace_deopt) { + PrintF("Materializing %sarguments object for %p: ", + frame->has_adapted_arguments() ? "(adapted) " : "", + reinterpret_cast<void*>(descriptor.slot_address())); + arguments->ShortPrint(); + PrintF("\n"); + } + } + } + } } @@ -932,8 +1014,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, } case Translation::ARGUMENTS_OBJECT: { - // Use the arguments marker value as a sentinel and fill in the arguments - // object after the deoptimized frame is built. + int args_index = iterator->Next() + 1; // Skip receiver. + int args_length = iterator->Next() - 1; // Skip receiver. if (FLAG_trace_deopt) { PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ", output_[frame_index]->GetTop() + output_offset, @@ -941,9 +1023,20 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, isolate_->heap()->arguments_marker()->ShortPrint(); PrintF(" ; arguments object\n"); } + // Use the arguments marker value as a sentinel and fill in the arguments + // object after the deoptimized frame is built. intptr_t value = reinterpret_cast<intptr_t>( isolate_->heap()->arguments_marker()); + AddArgumentsObject( + output_[frame_index]->GetTop() + output_offset, args_length); output_[frame_index]->SetFrameSlot(output_offset, value); + // We save the tagged argument values on the side and materialize the + // actual arguments object after the deoptimized frame is built. + for (int i = 0; i < args_length; i++) { + unsigned input_offset = input_->GetOffsetFromSlotIndex(args_index + i); + intptr_t input_value = input_->GetFrameSlot(input_offset); + AddArgumentsObjectValue(input_value); + } return; } } @@ -1285,39 +1378,63 @@ Object* Deoptimizer::ComputeLiteral(int index) const { } -void Deoptimizer::AddDoubleValue(intptr_t slot_address, - double value) { +void Deoptimizer::AddArgumentsObject(intptr_t slot_address, int argc) { + ArgumentsObjectMaterializationDescriptor object_desc( + reinterpret_cast<Address>(slot_address), argc); + deferred_arguments_objects_.Add(object_desc); +} + + +void Deoptimizer::AddArgumentsObjectValue(intptr_t value) { + deferred_arguments_objects_values_.Add(reinterpret_cast<Object*>(value)); +} + + +void Deoptimizer::AddDoubleValue(intptr_t slot_address, double value) { HeapNumberMaterializationDescriptor value_desc( reinterpret_cast<Address>(slot_address), value); deferred_heap_numbers_.Add(value_desc); } -MemoryChunk* Deoptimizer::CreateCode(BailoutType type) { +void Deoptimizer::EnsureCodeForDeoptimizationEntry(BailoutType type, + int max_entry_id) { // We cannot run this if the serializer is enabled because this will // cause us to emit relocation information for the external // references. This is fine because the deoptimizer's code section // isn't meant to be serialized at all. ASSERT(!Serializer::enabled()); + ASSERT(type == EAGER || type == LAZY); + DeoptimizerData* data = Isolate::Current()->deoptimizer_data(); + int entry_count = (type == EAGER) + ? data->eager_deoptimization_entry_code_entries_ + : data->lazy_deoptimization_entry_code_entries_; + if (max_entry_id < entry_count) return; + entry_count = Min(Max(entry_count * 2, Deoptimizer::kMinNumberOfEntries), + Deoptimizer::kMaxNumberOfEntries); + MacroAssembler masm(Isolate::Current(), NULL, 16 * KB); masm.set_emit_debug_code(false); - GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type); + GenerateDeoptimizationEntries(&masm, entry_count, type); CodeDesc desc; masm.GetCode(&desc); ASSERT(desc.reloc_size == 0); - MemoryChunk* chunk = - Isolate::Current()->memory_allocator()->AllocateChunk(desc.instr_size, - EXECUTABLE, - NULL); - ASSERT(chunk->area_size() >= desc.instr_size); - if (chunk == NULL) { - V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table"); + VirtualMemory* memory = type == EAGER + ? data->eager_deoptimization_entry_code_ + : data->lazy_deoptimization_entry_code_; + size_t table_size = Deoptimizer::GetMaxDeoptTableSize(); + ASSERT(static_cast<int>(table_size) >= desc.instr_size); + memory->Commit(memory->address(), table_size, true); + memcpy(memory->address(), desc.buffer, desc.instr_size); + CPU::FlushICache(memory->address(), desc.instr_size); + + if (type == EAGER) { + data->eager_deoptimization_entry_code_entries_ = entry_count; + } else { + data->lazy_deoptimization_entry_code_entries_ = entry_count; } - memcpy(chunk->area_start(), desc.buffer, desc.instr_size); - CPU::FlushICache(chunk->area_start(), desc.instr_size); - return chunk; } @@ -1359,6 +1476,54 @@ void Deoptimizer::RemoveDeoptimizingCode(Code* code) { } +static Object* CutOutRelatedFunctionsList(Context* context, + Code* code, + Object* undefined) { + Object* result_list_head = undefined; + Object* head; + Object* current; + current = head = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); + JSFunction* prev = NULL; + while (current != undefined) { + JSFunction* func = JSFunction::cast(current); + current = func->next_function_link(); + if (func->code() == code) { + func->set_next_function_link(result_list_head); + result_list_head = func; + if (prev) { + prev->set_next_function_link(current); + } else { + head = current; + } + } else { + prev = func; + } + } + if (head != context->get(Context::OPTIMIZED_FUNCTIONS_LIST)) { + context->set(Context::OPTIMIZED_FUNCTIONS_LIST, head); + } + return result_list_head; +} + + +void Deoptimizer::ReplaceCodeForRelatedFunctions(JSFunction* function, + Code* code) { + Context* context = function->context()->native_context(); + + SharedFunctionInfo* shared = function->shared(); + + Object* undefined = Isolate::Current()->heap()->undefined_value(); + Object* current = CutOutRelatedFunctionsList(context, code, undefined); + + while (current != undefined) { + JSFunction* func = JSFunction::cast(current); + current = func->next_function_link(); + func->set_code(shared->code()); + func->set_next_function_link(undefined); + } +} + + FrameDescription::FrameDescription(uint32_t frame_size, JSFunction* function) : frame_size_(frame_size), @@ -1570,8 +1735,10 @@ void Translation::StoreLiteral(int literal_id) { } -void Translation::StoreArgumentsObject() { +void Translation::StoreArgumentsObject(int args_index, int args_length) { buffer_->Add(ARGUMENTS_OBJECT, zone()); + buffer_->Add(args_index, zone()); + buffer_->Add(args_length, zone()); } @@ -1582,7 +1749,6 @@ void Translation::MarkDuplicate() { int Translation::NumberOfOperandsFor(Opcode opcode) { switch (opcode) { - case ARGUMENTS_OBJECT: case DUPLICATE: return 0; case GETTER_STUB_FRAME: @@ -1600,6 +1766,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) { case BEGIN: case ARGUMENTS_ADAPTOR_FRAME: case CONSTRUCT_STUB_FRAME: + case ARGUMENTS_OBJECT: return 2; case JS_FRAME: return 3; diff --git a/deps/v8/src/deoptimizer.h b/deps/v8/src/deoptimizer.h index cd33477e26..89955b38bd 100644 --- a/deps/v8/src/deoptimizer.h +++ b/deps/v8/src/deoptimizer.h @@ -57,6 +57,20 @@ class HeapNumberMaterializationDescriptor BASE_EMBEDDED { }; +class ArgumentsObjectMaterializationDescriptor BASE_EMBEDDED { + public: + ArgumentsObjectMaterializationDescriptor(Address slot_address, int argc) + : slot_address_(slot_address), arguments_length_(argc) { } + + Address slot_address() const { return slot_address_; } + int arguments_length() const { return arguments_length_; } + + private: + Address slot_address_; + int arguments_length_; +}; + + class OptimizedFunctionVisitor BASE_EMBEDDED { public: virtual ~OptimizedFunctionVisitor() {} @@ -86,8 +100,10 @@ class DeoptimizerData { #endif private: - MemoryChunk* eager_deoptimization_entry_code_; - MemoryChunk* lazy_deoptimization_entry_code_; + int eager_deoptimization_entry_code_entries_; + int lazy_deoptimization_entry_code_entries_; + VirtualMemory* eager_deoptimization_entry_code_; + VirtualMemory* lazy_deoptimization_entry_code_; Deoptimizer* current_; #ifdef ENABLE_DEBUGGER_SUPPORT @@ -152,6 +168,10 @@ class Deoptimizer : public Malloced { // execution returns. static void DeoptimizeFunction(JSFunction* function); + // Iterate over all the functions which share the same code object + // and make them use unoptimized version. + static void ReplaceCodeForRelatedFunctions(JSFunction* function, Code* code); + // Deoptimize all functions in the heap. static void DeoptimizeAll(); @@ -196,7 +216,7 @@ class Deoptimizer : public Malloced { ~Deoptimizer(); - void MaterializeHeapNumbers(); + void MaterializeHeapObjects(JavaScriptFrameIterator* it); #ifdef ENABLE_DEBUGGER_SUPPORT void MaterializeHeapNumbersForDebuggerInspectableFrame( Address parameters_top, @@ -208,7 +228,17 @@ class Deoptimizer : public Malloced { static void ComputeOutputFrames(Deoptimizer* deoptimizer); - static Address GetDeoptimizationEntry(int id, BailoutType type); + + enum GetEntryMode { + CALCULATE_ENTRY_ADDRESS, + ENSURE_ENTRY_CODE + }; + + + static Address GetDeoptimizationEntry( + int id, + BailoutType type, + GetEntryMode mode = ENSURE_ENTRY_CODE); static int GetDeoptimizationId(Address addr, BailoutType type); static int GetOutputInfo(DeoptimizationOutputData* data, BailoutId node_id, @@ -265,8 +295,11 @@ class Deoptimizer : public Malloced { int ConvertJSFrameIndexToFrameIndex(int jsframe_index); + static size_t GetMaxDeoptTableSize(); + private: - static const int kNumberOfEntries = 16384; + static const int kMinNumberOfEntries = 64; + static const int kMaxNumberOfEntries = 16384; Deoptimizer(Isolate* isolate, JSFunction* function, @@ -305,9 +338,12 @@ class Deoptimizer : public Malloced { Object* ComputeLiteral(int index) const; + void AddArgumentsObject(intptr_t slot_address, int argc); + void AddArgumentsObjectValue(intptr_t value); void AddDoubleValue(intptr_t slot_address, double value); - static MemoryChunk* CreateCode(BailoutType type); + static void EnsureCodeForDeoptimizationEntry(BailoutType type, + int max_entry_id); static void GenerateDeoptimizationEntries( MacroAssembler* masm, int count, BailoutType type); @@ -340,6 +376,8 @@ class Deoptimizer : public Malloced { // Array of output frame descriptions. FrameDescription** output_; + List<Object*> deferred_arguments_objects_values_; + List<ArgumentsObjectMaterializationDescriptor> deferred_arguments_objects_; List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_; static const int table_entry_size_; @@ -499,9 +537,6 @@ class FrameDescription { intptr_t context_; StackFrame::Type type_; Smi* state_; -#ifdef DEBUG - Code::Kind kind_; -#endif // Continuation is the PC where the execution continues after // deoptimizing. @@ -608,7 +643,7 @@ class Translation BASE_EMBEDDED { void StoreUint32StackSlot(int index); void StoreDoubleStackSlot(int index); void StoreLiteral(int literal_id); - void StoreArgumentsObject(); + void StoreArgumentsObject(int args_index, int args_length); void MarkDuplicate(); Zone* zone() const { return zone_; } diff --git a/deps/v8/src/elements-kind.cc b/deps/v8/src/elements-kind.cc index 655a23bf1e..7b1651a953 100644 --- a/deps/v8/src/elements-kind.cc +++ b/deps/v8/src/elements-kind.cc @@ -35,9 +35,14 @@ namespace v8 { namespace internal { -void PrintElementsKind(FILE* out, ElementsKind kind) { +const char* ElementsKindToString(ElementsKind kind) { ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); - PrintF(out, "%s", accessor->name()); + return accessor->name(); +} + + +void PrintElementsKind(FILE* out, ElementsKind kind) { + PrintF(out, "%s", ElementsKindToString(kind)); } diff --git a/deps/v8/src/elements-kind.h b/deps/v8/src/elements-kind.h index 3be7711a35..cb3bb9c9e9 100644 --- a/deps/v8/src/elements-kind.h +++ b/deps/v8/src/elements-kind.h @@ -77,6 +77,7 @@ const int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1; const int kFastElementsKindCount = LAST_FAST_ELEMENTS_KIND - FIRST_FAST_ELEMENTS_KIND + 1; +const char* ElementsKindToString(ElementsKind kind); void PrintElementsKind(FILE* out, ElementsKind kind); ElementsKind GetInitialFastElementsKind(); @@ -109,6 +110,13 @@ inline bool IsFastDoubleElementsKind(ElementsKind kind) { } +inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) { + return IsFastDoubleElementsKind(kind) || + kind == EXTERNAL_DOUBLE_ELEMENTS || + kind == EXTERNAL_FLOAT_ELEMENTS; +} + + inline bool IsFastSmiOrObjectElementsKind(ElementsKind kind) { return kind == FAST_SMI_ELEMENTS || kind == FAST_HOLEY_SMI_ELEMENTS || diff --git a/deps/v8/src/elements.cc b/deps/v8/src/elements.cc index 4cb50a461d..8e1bf3ec89 100644 --- a/deps/v8/src/elements.cc +++ b/deps/v8/src/elements.cc @@ -146,33 +146,36 @@ static Failure* ThrowArrayLengthRangeError(Heap* heap) { } -void CopyObjectToObjectElements(FixedArray* from, - ElementsKind from_kind, - uint32_t from_start, - FixedArray* to, - ElementsKind to_kind, - uint32_t to_start, - int raw_copy_size) { - ASSERT(to->map() != HEAP->fixed_cow_array_map()); +static void CopyObjectToObjectElements(FixedArrayBase* from_base, + ElementsKind from_kind, + uint32_t from_start, + FixedArrayBase* to_base, + ElementsKind to_kind, + uint32_t to_start, + int raw_copy_size) { + ASSERT(to_base->map() != HEAP->fixed_cow_array_map()); + AssertNoAllocation no_allocation; int copy_size = raw_copy_size; if (raw_copy_size < 0) { ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); - copy_size = Min(from->length() - from_start, - to->length() - to_start); -#ifdef DEBUG - // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already - // marked with the hole. + copy_size = Min(from_base->length() - from_start, + to_base->length() - to_start); if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to->length(); ++i) { - ASSERT(to->get(i)->IsTheHole()); + int start = to_start + copy_size; + int length = to_base->length() - start; + if (length > 0) { + Heap* heap = from_base->GetHeap(); + MemsetPointer(FixedArray::cast(to_base)->data_start() + start, + heap->the_hole_value(), length); } } -#endif } - ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && - (copy_size + static_cast<int>(from_start)) <= from->length()); + ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && + (copy_size + static_cast<int>(from_start)) <= from_base->length()); if (copy_size == 0) return; + FixedArray* from = FixedArray::cast(from_base); + FixedArray* to = FixedArray::cast(to_base); ASSERT(IsFastSmiOrObjectElementsKind(from_kind)); ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); Address to_address = to->address() + FixedArray::kHeaderSize; @@ -193,31 +196,34 @@ void CopyObjectToObjectElements(FixedArray* from, } -static void CopyDictionaryToObjectElements(SeededNumberDictionary* from, +static void CopyDictionaryToObjectElements(FixedArrayBase* from_base, uint32_t from_start, - FixedArray* to, + FixedArrayBase* to_base, ElementsKind to_kind, uint32_t to_start, int raw_copy_size) { + SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base); + AssertNoAllocation no_allocation; int copy_size = raw_copy_size; Heap* heap = from->GetHeap(); if (raw_copy_size < 0) { ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); copy_size = from->max_number_key() + 1 - from_start; -#ifdef DEBUG - // Fast object arrays cannot be uninitialized. Ensure they are already - // marked with the hole. if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to->length(); ++i) { - ASSERT(to->get(i)->IsTheHole()); + int start = to_start + copy_size; + int length = to_base->length() - start; + if (length > 0) { + Heap* heap = from->GetHeap(); + MemsetPointer(FixedArray::cast(to_base)->data_start() + start, + heap->the_hole_value(), length); } } -#endif } - ASSERT(to != from); + ASSERT(to_base != from_base); ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); if (copy_size == 0) return; + FixedArray* to = FixedArray::cast(to_base); uint32_t to_length = to->length(); if (to_start + copy_size > to_length) { copy_size = to_length - to_start; @@ -244,9 +250,9 @@ static void CopyDictionaryToObjectElements(SeededNumberDictionary* from, MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements( - FixedDoubleArray* from, + FixedArrayBase* from_base, uint32_t from_start, - FixedArray* to, + FixedArrayBase* to_base, ElementsKind to_kind, uint32_t to_start, int raw_copy_size) { @@ -255,21 +261,26 @@ MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements( if (raw_copy_size < 0) { ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); - copy_size = Min(from->length() - from_start, - to->length() - to_start); -#ifdef DEBUG - // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already - // marked with the hole. + copy_size = Min(from_base->length() - from_start, + to_base->length() - to_start); if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to->length(); ++i) { - ASSERT(to->get(i)->IsTheHole()); + // Also initialize the area that will be copied over since HeapNumber + // allocation below can cause an incremental marking step, requiring all + // existing heap objects to be propertly initialized. + int start = to_start; + int length = to_base->length() - start; + if (length > 0) { + Heap* heap = from_base->GetHeap(); + MemsetPointer(FixedArray::cast(to_base)->data_start() + start, + heap->the_hole_value(), length); } } -#endif } - ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && - (copy_size + static_cast<int>(from_start)) <= from->length()); - if (copy_size == 0) return from; + ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && + (copy_size + static_cast<int>(from_start)) <= from_base->length()); + if (copy_size == 0) return from_base; + FixedDoubleArray* from = FixedDoubleArray::cast(from_base); + FixedArray* to = FixedArray::cast(to_base); for (int i = 0; i < copy_size; ++i) { if (IsFastSmiElementsKind(to_kind)) { UNIMPLEMENTED(); @@ -298,26 +309,28 @@ MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements( } -static void CopyDoubleToDoubleElements(FixedDoubleArray* from, +static void CopyDoubleToDoubleElements(FixedArrayBase* from_base, uint32_t from_start, - FixedDoubleArray* to, + FixedArrayBase* to_base, uint32_t to_start, int raw_copy_size) { int copy_size = raw_copy_size; if (raw_copy_size < 0) { ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); - copy_size = Min(from->length() - from_start, - to->length() - to_start); + copy_size = Min(from_base->length() - from_start, + to_base->length() - to_start); if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to->length(); ++i) { - to->set_the_hole(i); + for (int i = to_start + copy_size; i < to_base->length(); ++i) { + FixedDoubleArray::cast(to_base)->set_the_hole(i); } } } - ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && - (copy_size + static_cast<int>(from_start)) <= from->length()); + ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && + (copy_size + static_cast<int>(from_start)) <= from_base->length()); if (copy_size == 0) return; + FixedDoubleArray* from = FixedDoubleArray::cast(from_base); + FixedDoubleArray* to = FixedDoubleArray::cast(to_base); Address to_address = to->address() + FixedDoubleArray::kHeaderSize; Address from_address = from->address() + FixedDoubleArray::kHeaderSize; to_address += kDoubleSize * to_start; @@ -329,25 +342,27 @@ static void CopyDoubleToDoubleElements(FixedDoubleArray* from, } -static void CopySmiToDoubleElements(FixedArray* from, +static void CopySmiToDoubleElements(FixedArrayBase* from_base, uint32_t from_start, - FixedDoubleArray* to, + FixedArrayBase* to_base, uint32_t to_start, int raw_copy_size) { int copy_size = raw_copy_size; if (raw_copy_size < 0) { ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); - copy_size = from->length() - from_start; + copy_size = from_base->length() - from_start; if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to->length(); ++i) { - to->set_the_hole(i); + for (int i = to_start + copy_size; i < to_base->length(); ++i) { + FixedDoubleArray::cast(to_base)->set_the_hole(i); } } } - ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && - (copy_size + static_cast<int>(from_start)) <= from->length()); + ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && + (copy_size + static_cast<int>(from_start)) <= from_base->length()); if (copy_size == 0) return; + FixedArray* from = FixedArray::cast(from_base); + FixedDoubleArray* to = FixedDoubleArray::cast(to_base); Object* the_hole = from->GetHeap()->the_hole_value(); for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size); from_start < from_end; from_start++, to_start++) { @@ -361,9 +376,9 @@ static void CopySmiToDoubleElements(FixedArray* from, } -static void CopyPackedSmiToDoubleElements(FixedArray* from, +static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base, uint32_t from_start, - FixedDoubleArray* to, + FixedArrayBase* to_base, uint32_t to_start, int packed_size, int raw_copy_size) { @@ -372,52 +387,55 @@ static void CopyPackedSmiToDoubleElements(FixedArray* from, if (raw_copy_size < 0) { ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); - copy_size = from->length() - from_start; + copy_size = packed_size - from_start; if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - to_end = to->length(); + to_end = to_base->length(); + for (uint32_t i = to_start + copy_size; i < to_end; ++i) { + FixedDoubleArray::cast(to_base)->set_the_hole(i); + } } else { to_end = to_start + static_cast<uint32_t>(copy_size); } } else { to_end = to_start + static_cast<uint32_t>(copy_size); } - ASSERT(static_cast<int>(to_end) <= to->length()); + ASSERT(static_cast<int>(to_end) <= to_base->length()); ASSERT(packed_size >= 0 && packed_size <= copy_size); - ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && - (copy_size + static_cast<int>(from_start)) <= from->length()); + ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && + (copy_size + static_cast<int>(from_start)) <= from_base->length()); if (copy_size == 0) return; + FixedArray* from = FixedArray::cast(from_base); + FixedDoubleArray* to = FixedDoubleArray::cast(to_base); for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size); from_start < from_end; from_start++, to_start++) { Object* smi = from->get(from_start); ASSERT(!smi->IsTheHole()); to->set(to_start, Smi::cast(smi)->value()); } - - while (to_start < to_end) { - to->set_the_hole(to_start++); - } } -static void CopyObjectToDoubleElements(FixedArray* from, +static void CopyObjectToDoubleElements(FixedArrayBase* from_base, uint32_t from_start, - FixedDoubleArray* to, + FixedArrayBase* to_base, uint32_t to_start, int raw_copy_size) { int copy_size = raw_copy_size; if (raw_copy_size < 0) { ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); - copy_size = from->length() - from_start; + copy_size = from_base->length() - from_start; if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to->length(); ++i) { - to->set_the_hole(i); + for (int i = to_start + copy_size; i < to_base->length(); ++i) { + FixedDoubleArray::cast(to_base)->set_the_hole(i); } } } - ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && - (copy_size + static_cast<int>(from_start)) <= from->length()); + ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && + (copy_size + static_cast<int>(from_start)) <= from_base->length()); if (copy_size == 0) return; + FixedArray* from = FixedArray::cast(from_base); + FixedDoubleArray* to = FixedDoubleArray::cast(to_base); Object* the_hole = from->GetHeap()->the_hole_value(); for (uint32_t from_end = from_start + copy_size; from_start < from_end; from_start++, to_start++) { @@ -431,23 +449,25 @@ static void CopyObjectToDoubleElements(FixedArray* from, } -static void CopyDictionaryToDoubleElements(SeededNumberDictionary* from, +static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base, uint32_t from_start, - FixedDoubleArray* to, + FixedArrayBase* to_base, uint32_t to_start, int raw_copy_size) { + SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base); int copy_size = raw_copy_size; if (copy_size < 0) { ASSERT(copy_size == ElementsAccessor::kCopyToEnd || copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); copy_size = from->max_number_key() + 1 - from_start; if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to->length(); ++i) { - to->set_the_hole(i); + for (int i = to_start + copy_size; i < to_base->length(); ++i) { + FixedDoubleArray::cast(to_base)->set_the_hole(i); } } } if (copy_size == 0) return; + FixedDoubleArray* to = FixedDoubleArray::cast(to_base); uint32_t to_length = to->length(); if (to_start + copy_size > to_length) { copy_size = to_length - to_start; @@ -503,8 +523,8 @@ class ElementsAccessorBase : public ElementsAccessor { Map* map = fixed_array_base->map(); // Arrays that have been shifted in place can't be verified. Heap* heap = holder->GetHeap(); - if (map == heap->raw_unchecked_one_pointer_filler_map() || - map == heap->raw_unchecked_two_pointer_filler_map() || + if (map == heap->one_pointer_filler_map() || + map == heap->two_pointer_filler_map() || map == heap->free_space_map()) { return; } @@ -527,10 +547,9 @@ class ElementsAccessorBase : public ElementsAccessor { static bool HasElementImpl(Object* receiver, JSObject* holder, uint32_t key, - BackingStore* backing_store) { - MaybeObject* element = - ElementsAccessorSubclass::GetImpl(receiver, holder, key, backing_store); - return !element->IsTheHole(); + FixedArrayBase* backing_store) { + return ElementsAccessorSubclass::GetAttributesImpl( + receiver, holder, key, backing_store) != ABSENT; } virtual bool HasElement(Object* receiver, @@ -541,7 +560,7 @@ class ElementsAccessorBase : public ElementsAccessor { backing_store = holder->elements(); } return ElementsAccessorSubclass::HasElementImpl( - receiver, holder, key, BackingStore::cast(backing_store)); + receiver, holder, key, backing_store); } MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver, @@ -552,28 +571,95 @@ class ElementsAccessorBase : public ElementsAccessor { backing_store = holder->elements(); } return ElementsAccessorSubclass::GetImpl( - receiver, holder, key, BackingStore::cast(backing_store)); + receiver, holder, key, backing_store); } MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver, JSObject* obj, uint32_t key, - BackingStore* backing_store) { + FixedArrayBase* backing_store) { return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store)) - ? backing_store->get(key) + ? BackingStore::cast(backing_store)->get(key) : backing_store->GetHeap()->the_hole_value(); } + MUST_USE_RESULT virtual PropertyAttributes GetAttributes( + Object* receiver, + JSObject* holder, + uint32_t key, + FixedArrayBase* backing_store) { + if (backing_store == NULL) { + backing_store = holder->elements(); + } + return ElementsAccessorSubclass::GetAttributesImpl( + receiver, holder, key, backing_store); + } + + MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* backing_store) { + if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) { + return ABSENT; + } + return BackingStore::cast(backing_store)->is_the_hole(key) ? ABSENT : NONE; + } + + MUST_USE_RESULT virtual PropertyType GetType( + Object* receiver, + JSObject* holder, + uint32_t key, + FixedArrayBase* backing_store) { + if (backing_store == NULL) { + backing_store = holder->elements(); + } + return ElementsAccessorSubclass::GetTypeImpl( + receiver, holder, key, backing_store); + } + + MUST_USE_RESULT static PropertyType GetTypeImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* backing_store) { + if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) { + return NONEXISTENT; + } + return BackingStore::cast(backing_store)->is_the_hole(key) + ? NONEXISTENT : FIELD; + } + + MUST_USE_RESULT virtual AccessorPair* GetAccessorPair( + Object* receiver, + JSObject* holder, + uint32_t key, + FixedArrayBase* backing_store) { + if (backing_store == NULL) { + backing_store = holder->elements(); + } + return ElementsAccessorSubclass::GetAccessorPairImpl( + receiver, holder, key, backing_store); + } + + MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* backing_store) { + return NULL; + } + MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array, Object* length) { return ElementsAccessorSubclass::SetLengthImpl( - array, length, BackingStore::cast(array->elements())); + array, length, array->elements()); } MUST_USE_RESULT static MaybeObject* SetLengthImpl( JSObject* obj, Object* length, - BackingStore* backing_store); + FixedArrayBase* backing_store); MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength( JSArray* array, @@ -631,9 +717,6 @@ class ElementsAccessorBase : public ElementsAccessor { } } } - if (from->length() == 0) { - return from; - } return ElementsAccessorSubclass::CopyElementsImpl( from, from_start, to, to_kind, to_start, packed_size, copy_size); } @@ -654,25 +737,22 @@ class ElementsAccessorBase : public ElementsAccessor { if (from == NULL) { from = holder->elements(); } - BackingStore* backing_store = BackingStore::cast(from); - uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(backing_store); // Optimize if 'other' is empty. // We cannot optimize if 'this' is empty, as other may have holes. + uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from); if (len1 == 0) return to; // Compute how many elements are not in other. uint32_t extra = 0; for (uint32_t y = 0; y < len1; y++) { - uint32_t key = - ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y); + uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y); if (ElementsAccessorSubclass::HasElementImpl( - receiver, holder, key, backing_store)) { + receiver, holder, key, from)) { MaybeObject* maybe_value = - ElementsAccessorSubclass::GetImpl(receiver, holder, - key, backing_store); + ElementsAccessorSubclass::GetImpl(receiver, holder, key, from); Object* value; - if (!maybe_value->ToObject(&value)) return maybe_value; + if (!maybe_value->To(&value)) return maybe_value; ASSERT(!value->IsTheHole()); if (!HasKey(to, value)) { extra++; @@ -684,9 +764,8 @@ class ElementsAccessorBase : public ElementsAccessor { // Allocate the result FixedArray* result; - MaybeObject* maybe_obj = - backing_store->GetHeap()->AllocateFixedArray(len0 + extra); - if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj; + MaybeObject* maybe_obj = from->GetHeap()->AllocateFixedArray(len0 + extra); + if (!maybe_obj->To(&result)) return maybe_obj; // Fill in the content { @@ -702,14 +781,13 @@ class ElementsAccessorBase : public ElementsAccessor { uint32_t index = 0; for (uint32_t y = 0; y < len1; y++) { uint32_t key = - ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y); + ElementsAccessorSubclass::GetKeyForIndexImpl(from, y); if (ElementsAccessorSubclass::HasElementImpl( - receiver, holder, key, backing_store)) { + receiver, holder, key, from)) { MaybeObject* maybe_value = - ElementsAccessorSubclass::GetImpl(receiver, holder, - key, backing_store); + ElementsAccessorSubclass::GetImpl(receiver, holder, key, from); Object* value; - if (!maybe_value->ToObject(&value)) return maybe_value; + if (!maybe_value->To(&value)) return maybe_value; if (!value->IsTheHole() && !HasKey(to, value)) { result->set(len0 + index, value); index++; @@ -721,24 +799,22 @@ class ElementsAccessorBase : public ElementsAccessor { } protected: - static uint32_t GetCapacityImpl(BackingStore* backing_store) { + static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) { return backing_store->length(); } virtual uint32_t GetCapacity(FixedArrayBase* backing_store) { - return ElementsAccessorSubclass::GetCapacityImpl( - BackingStore::cast(backing_store)); + return ElementsAccessorSubclass::GetCapacityImpl(backing_store); } - static uint32_t GetKeyForIndexImpl(BackingStore* backing_store, + static uint32_t GetKeyForIndexImpl(FixedArrayBase* backing_store, uint32_t index) { return index; } virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store, uint32_t index) { - return ElementsAccessorSubclass::GetKeyForIndexImpl( - BackingStore::cast(backing_store), index); + return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index); } private: @@ -764,17 +840,17 @@ class FastElementsAccessor // Adjusts the length of the fast backing store or returns the new length or // undefined in case conversion to a slow backing store should be performed. - static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store, + static MaybeObject* SetLengthWithoutNormalize(FixedArrayBase* backing_store, JSArray* array, Object* length_object, uint32_t length) { uint32_t old_capacity = backing_store->length(); Object* old_length = array->length(); - bool same_size = old_length->IsSmi() && - static_cast<uint32_t>(Smi::cast(old_length)->value()) == length; + bool same_or_smaller_size = old_length->IsSmi() && + static_cast<uint32_t>(Smi::cast(old_length)->value()) >= length; ElementsKind kind = array->GetElementsKind(); - if (!same_size && IsFastElementsKind(kind) && + if (!same_or_smaller_size && IsFastElementsKind(kind) && !IsFastHoleyElementsKind(kind)) { kind = GetHoleyElementsKind(kind); MaybeObject* maybe_obj = array->TransitionElementsKind(kind); @@ -802,7 +878,7 @@ class FastElementsAccessor // Otherwise, fill the unused tail with holes. int old_length = FastD2IChecked(array->length()->Number()); for (int i = length; i < old_length; i++) { - backing_store->set_the_hole(i); + BackingStore::cast(backing_store)->set_the_hole(i); } } return length_object; @@ -829,32 +905,38 @@ class FastElementsAccessor ASSERT(obj->HasFastSmiOrObjectElements() || obj->HasFastDoubleElements() || obj->HasFastArgumentsElements()); - typename KindTraits::BackingStore* backing_store = - KindTraits::BackingStore::cast(obj->elements()); Heap* heap = obj->GetHeap(); - if (backing_store->map() == heap->non_strict_arguments_elements_map()) { - backing_store = - KindTraits::BackingStore::cast( - FixedArray::cast(backing_store)->get(1)); - } else { - ElementsKind kind = KindTraits::Kind; - if (IsFastPackedElementsKind(kind)) { - MaybeObject* transitioned = - obj->TransitionElementsKind(GetHoleyElementsKind(kind)); - if (transitioned->IsFailure()) return transitioned; - } - if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) { - Object* writable; - MaybeObject* maybe = obj->EnsureWritableFastElements(); - if (!maybe->ToObject(&writable)) return maybe; - backing_store = KindTraits::BackingStore::cast(writable); - } + Object* elements = obj->elements(); + if (elements == heap->empty_fixed_array()) { + return heap->true_value(); + } + typename KindTraits::BackingStore* backing_store = + KindTraits::BackingStore::cast(elements); + bool is_non_strict_arguments_elements_map = + backing_store->map() == heap->non_strict_arguments_elements_map(); + if (is_non_strict_arguments_elements_map) { + backing_store = KindTraits::BackingStore::cast( + FixedArray::cast(backing_store)->get(1)); } uint32_t length = static_cast<uint32_t>( obj->IsJSArray() ? Smi::cast(JSArray::cast(obj)->length())->value() : backing_store->length()); if (key < length) { + if (!is_non_strict_arguments_elements_map) { + ElementsKind kind = KindTraits::Kind; + if (IsFastPackedElementsKind(kind)) { + MaybeObject* transitioned = + obj->TransitionElementsKind(GetHoleyElementsKind(kind)); + if (transitioned->IsFailure()) return transitioned; + } + if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) { + Object* writable; + MaybeObject* maybe = obj->EnsureWritableFastElements(); + if (!maybe->ToObject(&writable)) return maybe; + backing_store = KindTraits::BackingStore::cast(writable); + } + } backing_store->set_the_hole(key); // If an old space backing store is larger than a certain size and // has too few used values, normalize it. @@ -890,11 +972,11 @@ class FastElementsAccessor Object* receiver, JSObject* holder, uint32_t key, - typename KindTraits::BackingStore* backing_store) { + FixedArrayBase* backing_store) { if (key >= static_cast<uint32_t>(backing_store->length())) { return false; } - return !backing_store->is_the_hole(key); + return !BackingStore::cast(backing_store)->is_the_hole(key); } static void ValidateContents(JSObject* holder, int length) { @@ -942,25 +1024,18 @@ class FastSmiOrObjectElementsAccessor int copy_size) { if (IsFastSmiOrObjectElementsKind(to_kind)) { CopyObjectToObjectElements( - FixedArray::cast(from), KindTraits::Kind, from_start, - FixedArray::cast(to), to_kind, to_start, copy_size); + from, KindTraits::Kind, from_start, to, to_kind, to_start, copy_size); } else if (IsFastDoubleElementsKind(to_kind)) { if (IsFastSmiElementsKind(KindTraits::Kind)) { if (IsFastPackedElementsKind(KindTraits::Kind) && packed_size != kPackedSizeNotKnown) { CopyPackedSmiToDoubleElements( - FixedArray::cast(from), from_start, - FixedDoubleArray::cast(to), to_start, - packed_size, copy_size); + from, from_start, to, to_start, packed_size, copy_size); } else { - CopySmiToDoubleElements( - FixedArray::cast(from), from_start, - FixedDoubleArray::cast(to), to_start, copy_size); + CopySmiToDoubleElements(from, from_start, to, to_start, copy_size); } } else { - CopyObjectToDoubleElements( - FixedArray::cast(from), from_start, - FixedDoubleArray::cast(to), to_start, copy_size); + CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size); } } else { UNREACHABLE(); @@ -1064,13 +1139,10 @@ class FastDoubleElementsAccessor case FAST_HOLEY_SMI_ELEMENTS: case FAST_HOLEY_ELEMENTS: return CopyDoubleToObjectElements( - FixedDoubleArray::cast(from), from_start, FixedArray::cast(to), - to_kind, to_start, copy_size); + from, from_start, to, to_kind, to_start, copy_size); case FAST_DOUBLE_ELEMENTS: case FAST_HOLEY_DOUBLE_ELEMENTS: - CopyDoubleToDoubleElements(FixedDoubleArray::cast(from), from_start, - FixedDoubleArray::cast(to), - to_start, copy_size); + CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size); return from; default: UNREACHABLE(); @@ -1129,17 +1201,37 @@ class ExternalElementsAccessor MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver, JSObject* obj, uint32_t key, - BackingStore* backing_store) { + FixedArrayBase* backing_store) { return key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) - ? backing_store->get(key) + ? BackingStore::cast(backing_store)->get(key) : backing_store->GetHeap()->undefined_value(); } + MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* backing_store) { + return + key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) + ? NONE : ABSENT; + } + + MUST_USE_RESULT static PropertyType GetTypeImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* backing_store) { + return + key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) + ? FIELD : NONEXISTENT; + } + MUST_USE_RESULT static MaybeObject* SetLengthImpl( JSObject* obj, Object* length, - BackingStore* backing_store) { + FixedArrayBase* backing_store) { // External arrays do not support changing their length. UNREACHABLE(); return obj; @@ -1155,7 +1247,7 @@ class ExternalElementsAccessor static bool HasElementImpl(Object* receiver, JSObject* holder, uint32_t key, - BackingStore* backing_store) { + FixedArrayBase* backing_store) { uint32_t capacity = ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store); return key < capacity; @@ -1264,11 +1356,35 @@ class DictionaryElementsAccessor // Adjusts the length of the dictionary backing store and returns the new // length according to ES5 section 15.4.5.2 behavior. MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize( - SeededNumberDictionary* dict, + FixedArrayBase* store, JSArray* array, Object* length_object, uint32_t length) { - if (length == 0) { + SeededNumberDictionary* dict = SeededNumberDictionary::cast(store); + Heap* heap = array->GetHeap(); + int capacity = dict->Capacity(); + uint32_t new_length = length; + uint32_t old_length = static_cast<uint32_t>(array->length()->Number()); + if (new_length < old_length) { + // Find last non-deletable element in range of elements to be + // deleted and adjust range accordingly. + for (int i = 0; i < capacity; i++) { + Object* key = dict->KeyAt(i); + if (key->IsNumber()) { + uint32_t number = static_cast<uint32_t>(key->Number()); + if (new_length <= number && number < old_length) { + PropertyDetails details = dict->DetailsAt(i); + if (details.IsDontDelete()) new_length = number + 1; + } + } + } + if (new_length != length) { + MaybeObject* maybe_object = heap->NumberFromUint32(new_length); + if (!maybe_object->To(&length_object)) return maybe_object; + } + } + + if (new_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 // benefit that the array returns to fast mode. @@ -1276,45 +1392,22 @@ class DictionaryElementsAccessor MaybeObject* maybe_obj = array->ResetElements(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } else { - uint32_t new_length = length; - uint32_t old_length = static_cast<uint32_t>(array->length()->Number()); - if (new_length < old_length) { - // Find last non-deletable element in range of elements to be - // deleted and adjust range accordingly. - Heap* heap = array->GetHeap(); - int capacity = dict->Capacity(); - for (int i = 0; i < capacity; i++) { - Object* key = dict->KeyAt(i); - if (key->IsNumber()) { - uint32_t number = static_cast<uint32_t>(key->Number()); - if (new_length <= number && number < old_length) { - PropertyDetails details = dict->DetailsAt(i); - if (details.IsDontDelete()) new_length = number + 1; - } - } - } - if (new_length != length) { - MaybeObject* maybe_object = heap->NumberFromUint32(new_length); - if (!maybe_object->To(&length_object)) return maybe_object; - } - - // Remove elements that should be deleted. - int removed_entries = 0; - Object* the_hole_value = heap->the_hole_value(); - for (int i = 0; i < capacity; i++) { - Object* key = dict->KeyAt(i); - if (key->IsNumber()) { - uint32_t number = static_cast<uint32_t>(key->Number()); - if (new_length <= number && number < old_length) { - dict->SetEntry(i, the_hole_value, the_hole_value); - removed_entries++; - } + // Remove elements that should be deleted. + int removed_entries = 0; + Object* the_hole_value = heap->the_hole_value(); + for (int i = 0; i < capacity; i++) { + Object* key = dict->KeyAt(i); + if (key->IsNumber()) { + uint32_t number = static_cast<uint32_t>(key->Number()); + if (new_length <= number && number < old_length) { + dict->SetEntry(i, the_hole_value, the_hole_value); + removed_entries++; } } - - // Update the number of elements. - dict->ElementsRemoved(removed_entries); } + + // Update the number of elements. + dict->ElementsRemoved(removed_entries); } return length_object; } @@ -1336,30 +1429,29 @@ class DictionaryElementsAccessor int entry = dictionary->FindEntry(key); if (entry != SeededNumberDictionary::kNotFound) { Object* result = dictionary->DeleteProperty(entry, mode); - if (result == heap->true_value()) { - MaybeObject* maybe_elements = dictionary->Shrink(key); - FixedArray* new_elements = NULL; - if (!maybe_elements->To(&new_elements)) { - return maybe_elements; - } - if (is_arguments) { - FixedArray::cast(obj->elements())->set(1, new_elements); - } else { - obj->set_elements(new_elements); + if (result == heap->false_value()) { + if (mode == JSObject::STRICT_DELETION) { + // Deleting a non-configurable property in strict mode. + HandleScope scope(isolate); + Handle<Object> holder(obj); + Handle<Object> name = isolate->factory()->NewNumberFromUint(key); + Handle<Object> args[2] = { name, holder }; + Handle<Object> error = + isolate->factory()->NewTypeError("strict_delete_property", + HandleVector(args, 2)); + return isolate->Throw(*error); } + return heap->false_value(); + } + MaybeObject* maybe_elements = dictionary->Shrink(key); + FixedArray* new_elements = NULL; + if (!maybe_elements->To(&new_elements)) { + return maybe_elements; } - if (mode == JSObject::STRICT_DELETION && - result == heap->false_value()) { - // In strict mode, attempting to delete a non-configurable property - // throws an exception. - HandleScope scope(isolate); - Handle<Object> holder(obj); - Handle<Object> name = isolate->factory()->NewNumberFromUint(key); - Handle<Object> args[2] = { name, holder }; - Handle<Object> error = - isolate->factory()->NewTypeError("strict_delete_property", - HandleVector(args, 2)); - return isolate->Throw(*error); + if (is_arguments) { + FixedArray::cast(obj->elements())->set(1, new_elements); + } else { + obj->set_elements(new_elements); } } return heap->true_value(); @@ -1378,14 +1470,12 @@ class DictionaryElementsAccessor case FAST_HOLEY_SMI_ELEMENTS: case FAST_HOLEY_ELEMENTS: CopyDictionaryToObjectElements( - SeededNumberDictionary::cast(from), from_start, - FixedArray::cast(to), to_kind, to_start, copy_size); + from, from_start, to, to_kind, to_start, copy_size); return from; case FAST_DOUBLE_ELEMENTS: case FAST_HOLEY_DOUBLE_ELEMENTS: CopyDictionaryToDoubleElements( - SeededNumberDictionary::cast(from), from_start, - FixedDoubleArray::cast(to), to_start, copy_size); + from, from_start, to, to_start, copy_size); return from; default: UNREACHABLE(); @@ -1408,7 +1498,8 @@ class DictionaryElementsAccessor Object* receiver, JSObject* obj, uint32_t key, - SeededNumberDictionary* backing_store) { + FixedArrayBase* store) { + SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); int entry = backing_store->FindEntry(key); if (entry != SeededNumberDictionary::kNotFound) { Object* element = backing_store->ValueAt(entry); @@ -1425,16 +1516,59 @@ class DictionaryElementsAccessor return obj->GetHeap()->the_hole_value(); } + MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* backing_store) { + SeededNumberDictionary* dictionary = + SeededNumberDictionary::cast(backing_store); + int entry = dictionary->FindEntry(key); + if (entry != SeededNumberDictionary::kNotFound) { + return dictionary->DetailsAt(entry).attributes(); + } + return ABSENT; + } + + MUST_USE_RESULT static PropertyType GetTypeImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* store) { + SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); + int entry = backing_store->FindEntry(key); + if (entry != SeededNumberDictionary::kNotFound) { + return backing_store->DetailsAt(entry).type(); + } + return NONEXISTENT; + } + + MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* store) { + SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); + int entry = backing_store->FindEntry(key); + if (entry != SeededNumberDictionary::kNotFound && + backing_store->DetailsAt(entry).type() == CALLBACKS && + backing_store->ValueAt(entry)->IsAccessorPair()) { + return AccessorPair::cast(backing_store->ValueAt(entry)); + } + return NULL; + } + static bool HasElementImpl(Object* receiver, JSObject* holder, uint32_t key, - SeededNumberDictionary* backing_store) { - return backing_store->FindEntry(key) != + FixedArrayBase* backing_store) { + return SeededNumberDictionary::cast(backing_store)->FindEntry(key) != SeededNumberDictionary::kNotFound; } - static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict, + static uint32_t GetKeyForIndexImpl(FixedArrayBase* store, uint32_t index) { + SeededNumberDictionary* dict = SeededNumberDictionary::cast(store); Object* key = dict->KeyAt(index); return Smi::cast(key)->value(); } @@ -1457,7 +1591,8 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver, JSObject* obj, uint32_t key, - FixedArray* parameter_map) { + FixedArrayBase* parameters) { + FixedArray* parameter_map = FixedArray::cast(parameters); Object* probe = GetParameterMapArg(obj, parameter_map, key); if (!probe->IsTheHole()) { Context* context = Context::cast(parameter_map->get(0)); @@ -1484,10 +1619,61 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< } } + MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* backing_store) { + FixedArray* parameter_map = FixedArray::cast(backing_store); + Object* probe = GetParameterMapArg(obj, parameter_map, key); + if (!probe->IsTheHole()) { + return NONE; + } else { + // If not aliased, check the arguments. + FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); + return ElementsAccessor::ForArray(arguments)->GetAttributes( + receiver, obj, key, arguments); + } + } + + MUST_USE_RESULT static PropertyType GetTypeImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* parameters) { + FixedArray* parameter_map = FixedArray::cast(parameters); + Object* probe = GetParameterMapArg(obj, parameter_map, key); + if (!probe->IsTheHole()) { + return FIELD; + } else { + // If not aliased, check the arguments. + FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); + return ElementsAccessor::ForArray(arguments)->GetType( + receiver, obj, key, arguments); + } + } + + MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArrayBase* parameters) { + FixedArray* parameter_map = FixedArray::cast(parameters); + Object* probe = GetParameterMapArg(obj, parameter_map, key); + if (!probe->IsTheHole()) { + return NULL; + } else { + // If not aliased, check the arguments. + FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); + return ElementsAccessor::ForArray(arguments)->GetAccessorPair( + receiver, obj, key, arguments); + } + } + MUST_USE_RESULT static MaybeObject* SetLengthImpl( JSObject* obj, Object* length, - FixedArray* parameter_map) { + FixedArrayBase* parameter_map) { // TODO(mstarzinger): This was never implemented but will be used once we // correctly implement [[DefineOwnProperty]] on arrays. UNIMPLEMENTED(); @@ -1526,19 +1712,20 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< int packed_size, int copy_size) { FixedArray* parameter_map = FixedArray::cast(from); - FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); + FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments); return accessor->CopyElements(NULL, from_start, to, to_kind, to_start, copy_size, arguments); } - static uint32_t GetCapacityImpl(FixedArray* parameter_map) { + static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) { + FixedArray* parameter_map = FixedArray::cast(backing_store); FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); return Max(static_cast<uint32_t>(parameter_map->length() - 2), ForArray(arguments)->GetCapacity(arguments)); } - static uint32_t GetKeyForIndexImpl(FixedArray* dict, + static uint32_t GetKeyForIndexImpl(FixedArrayBase* dict, uint32_t index) { return index; } @@ -1546,12 +1733,14 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< static bool HasElementImpl(Object* receiver, JSObject* holder, uint32_t key, - FixedArray* parameter_map) { + FixedArrayBase* parameters) { + FixedArray* parameter_map = FixedArray::cast(parameters); Object* probe = GetParameterMapArg(holder, parameter_map, key); if (!probe->IsTheHole()) { return true; } else { - FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); + FixedArrayBase* arguments = + FixedArrayBase::cast(FixedArray::cast(parameter_map)->get(1)); ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments); return !accessor->Get(receiver, holder, key, arguments)->IsTheHole(); } @@ -1564,7 +1753,7 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< uint32_t length = holder->IsJSArray() ? Smi::cast(JSArray::cast(holder)->length())->value() : parameter_map->length(); - return key < (length - 2 ) + return key < (length - 2) ? parameter_map->get(key + 2) : parameter_map->GetHeap()->the_hole_value(); } @@ -1631,7 +1820,7 @@ MUST_USE_RESULT MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, ElementsKindTraits>:: SetLengthImpl(JSObject* obj, Object* length, - typename ElementsKindTraits::BackingStore* backing_store) { + FixedArrayBase* backing_store) { JSArray* array = JSArray::cast(obj); // Fast case: The new length fits into a Smi. diff --git a/deps/v8/src/elements.h b/deps/v8/src/elements.h index 822fca50ee..ffd6428ce9 100644 --- a/deps/v8/src/elements.h +++ b/deps/v8/src/elements.h @@ -71,6 +71,39 @@ class ElementsAccessor { uint32_t key, FixedArrayBase* backing_store = NULL) = 0; + // Returns an element's attributes, or ABSENT if there is no such + // element. This method doesn't iterate up the prototype chain. The caller + // 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. + MUST_USE_RESULT virtual PropertyAttributes GetAttributes( + Object* receiver, + JSObject* holder, + uint32_t key, + FixedArrayBase* backing_store = NULL) = 0; + + // Returns an element's type, or NONEXISTENT if there is no such + // element. This method doesn't iterate up the prototype chain. The caller + // 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. + MUST_USE_RESULT virtual PropertyType GetType( + Object* receiver, + JSObject* holder, + uint32_t key, + FixedArrayBase* backing_store = NULL) = 0; + + // Returns an element's accessors, or NULL if the element does not exist or + // is plain. This method doesn't iterate up the prototype chain. The caller + // 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. + MUST_USE_RESULT virtual AccessorPair* GetAccessorPair( + 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 @@ -164,16 +197,6 @@ class ElementsAccessor { DISALLOW_COPY_AND_ASSIGN(ElementsAccessor); }; - -void CopyObjectToObjectElements(FixedArray* from_obj, - ElementsKind from_kind, - uint32_t from_start, - FixedArray* to_obj, - ElementsKind to_kind, - uint32_t to_start, - int copy_size); - - } } // namespace v8::internal #endif // V8_ELEMENTS_H_ diff --git a/deps/v8/src/execution.cc b/deps/v8/src/execution.cc index 330e41fbc9..e43ea65fc6 100644 --- a/deps/v8/src/execution.cc +++ b/deps/v8/src/execution.cc @@ -118,7 +118,7 @@ static Handle<Object> Invoke(bool is_construct, CALL_GENERATED_CODE(stub_entry, function_entry, func, recv, argc, argv); } -#ifdef DEBUG +#ifdef VERIFY_HEAP value->Verify(); #endif @@ -211,6 +211,9 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func, Isolate* isolate = Isolate::Current(); ASSERT(isolate->has_pending_exception()); ASSERT(isolate->external_caught_exception()); + if (isolate->is_out_of_memory() && !isolate->ignore_out_of_memory()) { + V8::FatalProcessOutOfMemory("OOM during Execution::TryCall"); + } if (isolate->pending_exception() == isolate->heap()->termination_exception()) { result = isolate->factory()->termination_exception(); @@ -427,25 +430,6 @@ void StackGuard::TerminateExecution() { } -bool StackGuard::IsRuntimeProfilerTick() { - ExecutionAccess access(isolate_); - return (thread_local_.interrupt_flags_ & RUNTIME_PROFILER_TICK) != 0; -} - - -void StackGuard::RequestRuntimeProfilerTick() { - // Ignore calls if we're not optimizing or if we can't get the lock. - if (FLAG_opt && ExecutionAccess::TryLock(isolate_)) { - thread_local_.interrupt_flags_ |= RUNTIME_PROFILER_TICK; - if (thread_local_.postpone_interrupts_nesting_ == 0) { - thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit; - isolate_->heap()->SetStackLimits(); - } - ExecutionAccess::Unlock(isolate_); - } -} - - void StackGuard::RequestCodeReadyEvent() { ASSERT(FLAG_parallel_recompilation); if (ExecutionAccess::TryLock(isolate_)) { @@ -937,18 +921,14 @@ MaybeObject* Execution::HandleStackGuardInterrupt(Isolate* isolate) { } stack_guard->Continue(CODE_READY); } - if (!stack_guard->IsTerminateExecution()) { + if (!stack_guard->IsTerminateExecution() && + !FLAG_manual_parallel_recompilation) { isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); } isolate->counters()->stack_interrupts()->Increment(); - // If FLAG_count_based_interrupts, every interrupt is a profiler interrupt. - if (FLAG_count_based_interrupts || - stack_guard->IsRuntimeProfilerTick()) { - isolate->counters()->runtime_profiler_ticks()->Increment(); - stack_guard->Continue(RUNTIME_PROFILER_TICK); - isolate->runtime_profiler()->OptimizeNow(); - } + isolate->counters()->runtime_profiler_ticks()->Increment(); + isolate->runtime_profiler()->OptimizeNow(); #ifdef ENABLE_DEBUGGER_SUPPORT if (stack_guard->IsDebugBreak() || stack_guard->IsDebugCommand()) { DebugBreakHelper(); diff --git a/deps/v8/src/execution.h b/deps/v8/src/execution.h index 9f5d9ff2cd..448b8d68ac 100644 --- a/deps/v8/src/execution.h +++ b/deps/v8/src/execution.h @@ -41,9 +41,8 @@ enum InterruptFlag { DEBUGCOMMAND = 1 << 2, PREEMPT = 1 << 3, TERMINATE = 1 << 4, - RUNTIME_PROFILER_TICK = 1 << 5, - GC_REQUEST = 1 << 6, - CODE_READY = 1 << 7 + GC_REQUEST = 1 << 5, + CODE_READY = 1 << 6 }; @@ -194,8 +193,6 @@ class StackGuard { void Interrupt(); bool IsTerminateExecution(); void TerminateExecution(); - bool IsRuntimeProfilerTick(); - void RequestRuntimeProfilerTick(); bool IsCodeReadyEvent(); void RequestCodeReadyEvent(); #ifdef ENABLE_DEBUGGER_SUPPORT diff --git a/deps/v8/src/extensions/externalize-string-extension.cc b/deps/v8/src/extensions/externalize-string-extension.cc index 50d876136f..a126a5a569 100644 --- a/deps/v8/src/extensions/externalize-string-extension.cc +++ b/deps/v8/src/extensions/externalize-string-extension.cc @@ -93,7 +93,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize( return v8::ThrowException(v8::String::New( "externalizeString() can't externalize twice.")); } - if (string->IsAsciiRepresentation() && !force_two_byte) { + if (string->IsOneByteRepresentation() && !force_two_byte) { char* data = new char[string->length()]; String::WriteToFlat(*string, data, 0, string->length()); SimpleAsciiStringResource* resource = new SimpleAsciiStringResource( @@ -127,7 +127,8 @@ v8::Handle<v8::Value> ExternalizeStringExtension::IsAscii( return v8::ThrowException(v8::String::New( "isAsciiString() requires a single string argument.")); } - return Utils::OpenHandle(*args[0].As<v8::String>())->IsAsciiRepresentation() ? + return + Utils::OpenHandle(*args[0].As<v8::String>())->IsOneByteRepresentation() ? v8::True() : v8::False(); } diff --git a/deps/v8/src/extensions/gc-extension.cc b/deps/v8/src/extensions/gc-extension.cc index f921552aaa..813b9219bf 100644 --- a/deps/v8/src/extensions/gc-extension.cc +++ b/deps/v8/src/extensions/gc-extension.cc @@ -40,7 +40,11 @@ v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction( v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) { - HEAP->CollectAllGarbage(Heap::kNoGCFlags, "gc extension"); + if (args[0]->BooleanValue()) { + HEAP->CollectGarbage(NEW_SPACE, "gc extension"); + } else { + HEAP->CollectAllGarbage(Heap::kNoGCFlags, "gc extension"); + } return v8::Undefined(); } diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index 462af590d2..556f2b01b7 100644 --- a/deps/v8/src/factory.cc +++ b/deps/v8/src/factory.cc @@ -112,10 +112,11 @@ Handle<ObjectHashTable> Factory::NewObjectHashTable(int at_least_space_for) { } -Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors) { +Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors, + int slack) { ASSERT(0 <= number_of_descriptors); CALL_HEAP_FUNCTION(isolate(), - DescriptorArray::Allocate(number_of_descriptors), + DescriptorArray::Allocate(number_of_descriptors, slack), DescriptorArray); } @@ -177,7 +178,7 @@ Handle<String> Factory::LookupAsciiSymbol(Vector<const char> string) { } -Handle<String> Factory::LookupAsciiSymbol(Handle<SeqAsciiString> string, +Handle<String> Factory::LookupAsciiSymbol(Handle<SeqOneByteString> string, int from, int length) { CALL_HEAP_FUNCTION(isolate(), @@ -199,7 +200,7 @@ Handle<String> Factory::NewStringFromAscii(Vector<const char> string, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), - isolate()->heap()->AllocateStringFromAscii(string, pretenure), + isolate()->heap()->AllocateStringFromOneByte(string, pretenure), String); } @@ -221,12 +222,12 @@ Handle<String> Factory::NewStringFromTwoByte(Vector<const uc16> string, } -Handle<SeqAsciiString> Factory::NewRawAsciiString(int length, +Handle<SeqOneByteString> Factory::NewRawOneByteString(int length, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), - isolate()->heap()->AllocateRawAsciiString(length, pretenure), - SeqAsciiString); + isolate()->heap()->AllocateRawOneByteString(length, pretenure), + SeqOneByteString); } @@ -524,6 +525,12 @@ Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) { } +Handle<FixedArray> Factory::CopySizeFixedArray(Handle<FixedArray> array, + int new_length) { + CALL_HEAP_FUNCTION(isolate(), array->CopySize(new_length), FixedArray); +} + + Handle<FixedDoubleArray> Factory::CopyFixedDoubleArray( Handle<FixedDoubleArray> array) { CALL_HEAP_FUNCTION(isolate(), array->Copy(), FixedDoubleArray); @@ -869,6 +876,13 @@ Handle<ScopeInfo> Factory::NewScopeInfo(int length) { } +Handle<JSObject> Factory::NewExternal(void* value) { + CALL_HEAP_FUNCTION(isolate(), + isolate()->heap()->AllocateExternal(value), + JSObject); +} + + Handle<Code> Factory::NewCode(const CodeDesc& desc, Code::Flags flags, Handle<Object> self_ref, @@ -936,6 +950,9 @@ Handle<JSObject> Factory::NewJSObjectFromMap(Handle<Map> map) { Handle<JSArray> Factory::NewJSArray(int capacity, ElementsKind elements_kind, PretenureFlag pretenure) { + if (capacity != 0) { + elements_kind = GetHoleyElementsKind(elements_kind); + } CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateJSArrayAndStorage( elements_kind, @@ -954,6 +971,7 @@ Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArrayBase> elements, isolate(), isolate()->heap()->AllocateJSArrayWithElements(*elements, elements_kind, + elements->length(), pretenure), JSArray); } @@ -1284,10 +1302,26 @@ Handle<JSFunction> Factory::CreateApiFunction( result->shared()->DontAdaptArguments(); // Recursively copy parent templates' accessors, 'data' may be modified. + int max_number_of_additional_properties = 0; + FunctionTemplateInfo* info = *obj; + while (true) { + Object* props = info->property_accessors(); + if (!props->IsUndefined()) { + Handle<Object> props_handle(props); + NeanderArray props_array(props_handle); + max_number_of_additional_properties += props_array.length(); + } + Object* parent = info->parent_template(); + if (parent->IsUndefined()) break; + info = FunctionTemplateInfo::cast(parent); + } + + Map::EnsureDescriptorSlack(map, max_number_of_additional_properties); + while (true) { Handle<Object> props = Handle<Object>(obj->property_accessors()); if (!props->IsUndefined()) { - Map::CopyAppendCallbackDescriptors(map, props); + Map::AppendCallbackDescriptors(map, props); } Handle<Object> parent = Handle<Object>(obj->parent_template()); if (parent->IsUndefined()) break; @@ -1336,7 +1370,7 @@ Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<Context> context, // Check to see whether there is a matching element in the cache. Handle<MapCache> cache = Handle<MapCache>(MapCache::cast(context->map_cache())); - Handle<Object> result = Handle<Object>(cache->Lookup(*keys)); + Handle<Object> result = Handle<Object>(cache->Lookup(*keys), isolate()); if (result->IsMap()) return Handle<Map>::cast(result); // Create a new map and add it to the cache. Handle<Map> map = @@ -1388,7 +1422,7 @@ void Factory::ConfigureInstance(Handle<FunctionTemplateInfo> desc, bool* pending_exception) { // Configure the instance by adding the properties specified by the // instance template. - Handle<Object> instance_template = Handle<Object>(desc->instance_template()); + Handle<Object> instance_template(desc->instance_template(), isolate()); if (!instance_template->IsUndefined()) { Execution::ConfigureInstance(instance, instance_template, diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index e617abb6d1..dd613b71e4 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -66,7 +66,8 @@ class Factory { Handle<ObjectHashTable> NewObjectHashTable(int at_least_space_for); - Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors); + Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors, + int slack = 0); Handle<DeoptimizationInputData> NewDeoptimizationInputData( int deopt_entry_count, PretenureFlag pretenure); @@ -81,7 +82,7 @@ class Factory { Handle<String> LookupSymbol(Vector<const char> str); Handle<String> LookupSymbol(Handle<String> str); Handle<String> LookupAsciiSymbol(Vector<const char> str); - Handle<String> LookupAsciiSymbol(Handle<SeqAsciiString>, + Handle<String> LookupAsciiSymbol(Handle<SeqOneByteString>, int from, int length); Handle<String> LookupTwoByteSymbol(Vector<const uc16> str); @@ -129,7 +130,7 @@ class Factory { // Allocates and partially initializes an ASCII or TwoByte String. The // characters of the string are uninitialized. Currently used in regexp code // only, where they are pretenured. - Handle<SeqAsciiString> NewRawAsciiString( + Handle<SeqOneByteString> NewRawOneByteString( int length, PretenureFlag pretenure = NOT_TENURED); Handle<SeqTwoByteString> NewRawTwoByteString( @@ -238,6 +239,9 @@ class Factory { Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array); + Handle<FixedArray> CopySizeFixedArray(Handle<FixedArray> array, + int new_length); + Handle<FixedDoubleArray> CopyFixedDoubleArray( Handle<FixedDoubleArray> array); @@ -324,6 +328,8 @@ class Factory { Handle<ScopeInfo> NewScopeInfo(int length); + Handle<JSObject> NewExternal(void* value); + Handle<Code> NewCode(const CodeDesc& desc, Code::Flags flags, Handle<Object> self_reference, diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index d3ea89bdb7..338060f3fc 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -144,12 +144,16 @@ DEFINE_bool(harmony_modules, false, DEFINE_bool(harmony_proxies, false, "enable harmony proxies") DEFINE_bool(harmony_collections, false, "enable harmony collections (sets, maps, and weak maps)") +DEFINE_bool(harmony_observation, false, + "enable harmony object observation (implies harmony collections") DEFINE_bool(harmony, false, "enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) DEFINE_implication(harmony, harmony_proxies) DEFINE_implication(harmony, harmony_collections) +DEFINE_implication(harmony, harmony_observation) DEFINE_implication(harmony_modules, harmony_scoping) +DEFINE_implication(harmony_observation, harmony_collections) // Flags for experimental implementation features. DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes") @@ -177,6 +181,7 @@ DEFINE_int(max_inlined_nodes, 196, 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(fast_math, true, "faster (but maybe less accurate) math functions") DEFINE_bool(collect_megamorphic_maps_from_stub_cache, true, "crankshaft harvests type feedback from stub cache") @@ -198,10 +203,12 @@ 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, false, +DEFINE_bool(array_bounds_checks_elimination, true, "perform array bounds checks elimination") -DEFINE_bool(array_index_dehoisting, false, +DEFINE_bool(array_index_dehoisting, true, "perform array index dehoisting") +DEFINE_bool(dead_code_elimination, true, "use dead code elimination") +DEFINE_bool(trace_dead_code_elimination, false, "trace dead code elimination") DEFINE_bool(trace_osr, false, "trace on-stack replacement") DEFINE_int(stress_runs, 0, "number of stress runs") @@ -219,7 +226,7 @@ DEFINE_int(loop_weight, 1, "loop weight for representation inference") DEFINE_bool(optimize_for_in, true, "optimize functions containing for-in loops") DEFINE_bool(opt_safe_uint32_operations, true, - "allow uint32 values on optimize frames if they are used only in" + "allow uint32 values on optimize frames if they are used only in " "safe operations") DEFINE_bool(parallel_recompilation, false, @@ -227,6 +234,9 @@ DEFINE_bool(parallel_recompilation, false, DEFINE_bool(trace_parallel_recompilation, false, "track parallel recompilation") DEFINE_int(parallel_recompilation_queue_length, 2, "the length of the parallel compilation queue") +DEFINE_bool(manual_parallel_recompilation, false, + "disable automatic optimization") +DEFINE_implication(manual_parallel_recompilation, parallel_recompilation) // Experimental profiler changes. DEFINE_bool(experimental_profiler, true, "enable all profiler experiments") @@ -237,8 +247,6 @@ DEFINE_bool(self_optimization, false, DEFINE_bool(direct_self_opt, false, "call recompile stub directly when self-optimizing") DEFINE_bool(retry_self_opt, false, "re-try self-optimization if it failed") -DEFINE_bool(count_based_interrupts, false, - "trigger profiler ticks based on counting instead of timing") DEFINE_bool(interrupt_at_exit, false, "insert an interrupt check at function exit") DEFINE_bool(weighted_back_edges, false, @@ -254,7 +262,6 @@ DEFINE_implication(experimental_profiler, watch_ic_patching) DEFINE_implication(experimental_profiler, self_optimization) // Not implying direct_self_opt here because it seems to be a bad idea. DEFINE_implication(experimental_profiler, retry_self_opt) -DEFINE_implication(experimental_profiler, count_based_interrupts) DEFINE_implication(experimental_profiler, interrupt_at_exit) DEFINE_implication(experimental_profiler, weighted_back_edges) @@ -284,6 +291,13 @@ DEFINE_bool(enable_vfp2, true, "enable use of VFP2 instructions if available") DEFINE_bool(enable_armv7, true, "enable use of ARMv7 instructions if available (ARM only)") +DEFINE_bool(enable_sudiv, true, + "enable use of SDIV and UDIV instructions if available (ARM only)") +DEFINE_bool(enable_movw_movt, false, + "enable loading 32-bit constant by means of movw/movt " + "instruction pairs (ARM only)") +DEFINE_bool(enable_unaligned_accesses, true, + "enable unaligned accesses for ARMv7 (ARM only)") DEFINE_bool(enable_fpu, true, "enable use of MIPS FPU instructions if available (MIPS only)") @@ -380,13 +394,21 @@ DEFINE_bool(trace_external_memory, false, DEFINE_bool(collect_maps, true, "garbage collect maps from which no objects can be reached") DEFINE_bool(flush_code, true, - "flush code that we expect not to use again before full gc") + "flush code that we expect not to use again (during full gc)") +DEFINE_bool(flush_code_incrementally, true, + "flush code that we expect not to use again (incrementally)") +DEFINE_bool(age_code, true, + "track un-executed functions to age code and flush only " + "old code") DEFINE_bool(incremental_marking, true, "use incremental marking") DEFINE_bool(incremental_marking_steps, true, "do incremental marking steps") DEFINE_bool(trace_incremental_marking, false, "trace progress of the incremental marking") DEFINE_bool(track_gc_object_stats, false, "track object counts and memory usage") +#ifdef VERIFY_HEAP +DEFINE_bool(verify_heap, false, "verify heap pointers before and after GC") +#endif // v8.cc DEFINE_bool(use_idle_notification, true, @@ -412,9 +434,14 @@ DEFINE_bool(never_compact, false, "Never perform compaction on full GC - testing only") DEFINE_bool(compact_code_space, true, "Compact code space on full non-incremental collections") +DEFINE_bool(incremental_code_compaction, true, + "Compact code space on full incremental collections") DEFINE_bool(cleanup_code_caches_at_gc, true, "Flush inline caches prior to mark compact collection and " "flush code caches in maps during mark compact cycle.") +DEFINE_bool(use_marking_progress_bar, true, + "Use a progress bar to scan large objects in increments when " + "incremental marking is active.") DEFINE_int(random_seed, 0, "Default seed for initializing random generator " "(0, the default, means to use system random).") @@ -558,7 +585,6 @@ DEFINE_bool(gc_greedy, false, "perform GC prior to some allocations") DEFINE_bool(gc_verbose, false, "print stuff during garbage collection") DEFINE_bool(heap_stats, false, "report heap statistics before and after GC") DEFINE_bool(code_stats, false, "report code statistics after GC") -DEFINE_bool(verify_heap, false, "verify heap pointers before and after GC") DEFINE_bool(verify_native_context_separation, false, "verify that code holds on to at most one native context after GC") DEFINE_bool(print_handles, false, "report handles after GC") @@ -629,12 +655,14 @@ DEFINE_bool(prof_lazy, false, DEFINE_bool(prof_browser_mode, true, "Used with --prof, turns on browser-compatible mode for profiling.") DEFINE_bool(log_regexp, false, "Log regular expression execution.") -DEFINE_bool(sliding_state_window, false, - "Update sliding state window counters.") DEFINE_string(logfile, "v8.log", "Specify the name of the log file.") DEFINE_bool(ll_prof, false, "Enable low-level linux profiler.") DEFINE_string(gc_fake_mmap, "/tmp/__v8_gc__", "Specify the name of the file for fake gc mmap used in ll_prof") +DEFINE_bool(log_internal_timer_events, false, "Time internal events.") +DEFINE_bool(log_timer_events, false, + "Time events including external callbacks.") +DEFINE_implication(log_timer_events, log_internal_timer_events) // // Disassembler only flags diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index 18dc54164a..3b60fb59fa 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -484,7 +484,7 @@ Address StackFrame::UnpaddedFP() const { Code* EntryFrame::unchecked_code() const { - return HEAP->raw_unchecked_js_entry_code(); + return HEAP->js_entry_code(); } @@ -507,7 +507,7 @@ StackFrame::Type EntryFrame::GetCallerState(State* state) const { Code* EntryConstructFrame::unchecked_code() const { - return HEAP->raw_unchecked_js_construct_entry_code(); + return HEAP->js_construct_entry_code(); } diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index 9592e0afa2..928da4a764 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -86,6 +86,10 @@ void BreakableStatementChecker::VisitModuleUrl(ModuleUrl* module) { } +void BreakableStatementChecker::VisitModuleStatement(ModuleStatement* stmt) { +} + + void BreakableStatementChecker::VisitBlock(Block* stmt) { } @@ -466,9 +470,8 @@ void FullCodeGenerator::RecordTypeFeedbackCell( } -void FullCodeGenerator::RecordStackCheck(BailoutId ast_id) { - // The pc offset does not need to be encoded and packed together with a - // state. +void FullCodeGenerator::RecordBackEdge(BailoutId ast_id) { + // The pc offset does not need to be encoded and packed together with a state. ASSERT(masm_->pc_offset() > 0); BailoutEntry entry = { ast_id, static_cast<unsigned>(masm_->pc_offset()) }; stack_checks_.Add(entry, zone()); @@ -582,16 +585,137 @@ void FullCodeGenerator::DoTest(const TestContext* context) { } +void FullCodeGenerator::AllocateModules(ZoneList<Declaration*>* declarations) { + ASSERT(scope_->is_global_scope()); + + for (int i = 0; i < declarations->length(); i++) { + ModuleDeclaration* declaration = declarations->at(i)->AsModuleDeclaration(); + if (declaration != NULL) { + ModuleLiteral* module = declaration->module()->AsModuleLiteral(); + if (module != NULL) { + Comment cmnt(masm_, "[ Link nested modules"); + Scope* scope = module->body()->scope(); + Interface* interface = scope->interface(); + ASSERT(interface->IsModule() && interface->IsFrozen()); + + interface->Allocate(scope->module_var()->index()); + + // Set up module context. + ASSERT(scope->interface()->Index() >= 0); + __ Push(Smi::FromInt(scope->interface()->Index())); + __ Push(scope->GetScopeInfo()); + __ CallRuntime(Runtime::kPushModuleContext, 2); + StoreToFrameField(StandardFrameConstants::kContextOffset, + context_register()); + + AllocateModules(scope->declarations()); + + // Pop module context. + LoadContextField(context_register(), Context::PREVIOUS_INDEX); + // Update local stack frame context field. + StoreToFrameField(StandardFrameConstants::kContextOffset, + context_register()); + } + } + } +} + + +// Modules have their own local scope, represented by their own context. +// Module instance objects have an accessor for every export that forwards +// access to the respective slot from the module's context. (Exports that are +// modules themselves, however, are simple data properties.) +// +// All modules have a _hosting_ scope/context, which (currently) is the +// (innermost) enclosing global scope. To deal with recursion, nested modules +// are hosted by the same scope as global ones. +// +// For every (global or nested) module literal, the hosting context has an +// internal slot that points directly to the respective module context. This +// enables quick access to (statically resolved) module members by 2-dimensional +// access through the hosting context. For example, +// +// module A { +// let x; +// module B { let y; } +// } +// module C { let z; } +// +// allocates contexts as follows: +// +// [header| .A | .B | .C | A | C ] (global) +// | | | +// | | +-- [header| z ] (module) +// | | +// | +------- [header| y ] (module) +// | +// +------------ [header| x | B ] (module) +// +// Here, .A, .B, .C are the internal slots pointing to the hosted module +// contexts, whereas A, B, C hold the actual instance objects (note that every +// module context also points to the respective instance object through its +// extension slot in the header). +// +// To deal with arbitrary recursion and aliases between modules, +// they are created and initialized in several stages. Each stage applies to +// all modules in the hosting global scope, including nested ones. +// +// 1. Allocate: for each module _literal_, allocate the module contexts and +// respective instance object and wire them up. This happens in the +// PushModuleContext runtime function, as generated by AllocateModules +// (invoked by VisitDeclarations in the hosting scope). +// +// 2. Bind: for each module _declaration_ (i.e. literals as well as aliases), +// assign the respective instance object to respective local variables. This +// happens in VisitModuleDeclaration, and uses the instance objects created +// in the previous stage. +// For each module _literal_, this phase also constructs a module descriptor +// for the next stage. This happens in VisitModuleLiteral. +// +// 3. Populate: invoke the DeclareModules runtime function to populate each +// _instance_ object with accessors for it exports. This is generated by +// DeclareModules (invoked by VisitDeclarations in the hosting scope again), +// and uses the descriptors generated in the previous stage. +// +// 4. Initialize: execute the module bodies (and other code) in sequence. This +// happens by the separate statements generated for module bodies. To reenter +// the module scopes properly, the parser inserted ModuleStatements. + void FullCodeGenerator::VisitDeclarations( ZoneList<Declaration*>* declarations) { + Handle<FixedArray> saved_modules = modules_; + int saved_module_index = module_index_; ZoneList<Handle<Object> >* saved_globals = globals_; ZoneList<Handle<Object> > inner_globals(10, zone()); globals_ = &inner_globals; + if (scope_->num_modules() != 0) { + // This is a scope hosting modules. Allocate a descriptor array to pass + // to the runtime for initialization. + Comment cmnt(masm_, "[ Allocate modules"); + ASSERT(scope_->is_global_scope()); + modules_ = + isolate()->factory()->NewFixedArray(scope_->num_modules(), TENURED); + module_index_ = 0; + + // Generate code for allocating all modules, including nested ones. + // The allocated contexts are stored in internal variables in this scope. + AllocateModules(declarations); + } + AstVisitor::VisitDeclarations(declarations); + + if (scope_->num_modules() != 0) { + // Initialize modules from descriptor array. + ASSERT(module_index_ == modules_->length()); + DeclareModules(modules_); + modules_ = saved_modules; + module_index_ = saved_module_index; + } + if (!globals_->is_empty()) { // Invoke the platform-dependent code generator to do the actual - // declaration the global functions and variables. + // declaration of the global functions and variables. Handle<FixedArray> array = isolate()->factory()->NewFixedArray(globals_->length(), TENURED); for (int i = 0; i < globals_->length(); ++i) @@ -604,19 +728,23 @@ void FullCodeGenerator::VisitDeclarations( void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) { - // Allocate a module context statically. Block* block = module->body(); Scope* saved_scope = scope(); scope_ = block->scope(); - Interface* interface = module->interface(); - Handle<JSModule> instance = interface->Instance(); + Interface* interface = scope_->interface(); Comment cmnt(masm_, "[ ModuleLiteral"); SetStatementPosition(block); + ASSERT(!modules_.is_null()); + ASSERT(module_index_ < modules_->length()); + int index = module_index_++; + // Set up module context. - __ Push(instance); - __ CallRuntime(Runtime::kPushModuleContext, 1); + ASSERT(interface->Index() >= 0); + __ Push(Smi::FromInt(interface->Index())); + __ Push(Smi::FromInt(0)); + __ CallRuntime(Runtime::kPushModuleContext, 2); StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); { @@ -624,6 +752,11 @@ void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) { VisitDeclarations(scope_->declarations()); } + // Populate the module description. + Handle<ModuleInfo> description = + ModuleInfo::Create(isolate(), interface, scope_); + modules_->set(index, *description); + scope_ = saved_scope; // Pop module context. LoadContextField(context_register(), Context::PREVIOUS_INDEX); @@ -644,8 +777,20 @@ void FullCodeGenerator::VisitModulePath(ModulePath* module) { } -void FullCodeGenerator::VisitModuleUrl(ModuleUrl* decl) { - // TODO(rossberg) +void FullCodeGenerator::VisitModuleUrl(ModuleUrl* module) { + // TODO(rossberg): dummy allocation for now. + Scope* scope = module->body()->scope(); + Interface* interface = scope_->interface(); + + ASSERT(interface->IsModule() && interface->IsFrozen()); + ASSERT(!modules_.is_null()); + ASSERT(module_index_ < modules_->length()); + interface->Allocate(scope->module_var()->index()); + int index = module_index_++; + + Handle<ModuleInfo> description = + ModuleInfo::Create(isolate(), interface, scope_); + modules_->set(index, *description); } @@ -904,37 +1049,28 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { // Push a block context when entering a block with block scoped variables. if (stmt->scope() != NULL) { scope_ = stmt->scope(); - if (scope_->is_module_scope()) { - // If this block is a module body, then we have already allocated and - // initialized the declarations earlier. Just push the context. - ASSERT(!scope_->interface()->Instance().is_null()); - __ Push(scope_->interface()->Instance()); - __ CallRuntime(Runtime::kPushModuleContext, 1); - StoreToFrameField( - StandardFrameConstants::kContextOffset, context_register()); - } else { - { Comment cmnt(masm_, "[ Extend block context"); - Handle<ScopeInfo> scope_info = scope_->GetScopeInfo(); - int heap_slots = - scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS; - __ Push(scope_info); - PushFunctionArgumentForContextAllocation(); - if (heap_slots <= FastNewBlockContextStub::kMaximumSlots) { - FastNewBlockContextStub stub(heap_slots); - __ CallStub(&stub); - } else { - __ CallRuntime(Runtime::kPushBlockContext, 2); - } - - // Replace the context stored in the frame. - StoreToFrameField(StandardFrameConstants::kContextOffset, - context_register()); - } - { Comment cmnt(masm_, "[ Declarations"); - VisitDeclarations(scope_->declarations()); + ASSERT(!scope_->is_module_scope()); + { Comment cmnt(masm_, "[ Extend block context"); + Handle<ScopeInfo> scope_info = scope_->GetScopeInfo(); + int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS; + __ Push(scope_info); + PushFunctionArgumentForContextAllocation(); + if (heap_slots <= FastNewBlockContextStub::kMaximumSlots) { + FastNewBlockContextStub stub(heap_slots); + __ CallStub(&stub); + } else { + __ CallRuntime(Runtime::kPushBlockContext, 2); } + + // Replace the context stored in the frame. + StoreToFrameField(StandardFrameConstants::kContextOffset, + context_register()); + } + { Comment cmnt(masm_, "[ Declarations"); + VisitDeclarations(scope_->declarations()); } } + PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); VisitStatements(stmt->statements()); scope_ = saved_scope; @@ -951,6 +1087,26 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { } +void FullCodeGenerator::VisitModuleStatement(ModuleStatement* stmt) { + Comment cmnt(masm_, "[ Module context"); + + __ Push(Smi::FromInt(stmt->proxy()->interface()->Index())); + __ Push(Smi::FromInt(0)); + __ CallRuntime(Runtime::kPushModuleContext, 2); + StoreToFrameField( + StandardFrameConstants::kContextOffset, context_register()); + + Scope* saved_scope = scope_; + scope_ = stmt->body()->scope(); + VisitStatements(stmt->body()->statements()); + scope_ = saved_scope; + LoadContextField(context_register(), Context::PREVIOUS_INDEX); + // Update local stack frame context field. + StoreToFrameField(StandardFrameConstants::kContextOffset, + context_register()); +} + + void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { Comment cmnt(masm_, "[ ExpressionStatement"); SetStatementPosition(stmt); @@ -1111,7 +1267,7 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { // Check stack before looping. PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); __ bind(&stack_check); - EmitStackCheck(stmt, &body); + EmitBackEdgeBookkeeping(stmt, &body); __ jmp(&body); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); @@ -1140,7 +1296,7 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { SetStatementPosition(stmt); // Check stack before looping. - EmitStackCheck(stmt, &body); + EmitBackEdgeBookkeeping(stmt, &body); __ bind(&test); VisitForControl(stmt->cond(), @@ -1186,7 +1342,7 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { SetStatementPosition(stmt); // Check stack before looping. - EmitStackCheck(stmt, &body); + EmitBackEdgeBookkeeping(stmt, &body); __ bind(&test); if (stmt->cond() != NULL) { diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index 89b51f9582..2f88184806 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -396,9 +396,15 @@ class FullCodeGenerator: public AstVisitor { void VisitInDuplicateContext(Expression* expr); void VisitDeclarations(ZoneList<Declaration*>* declarations); + void DeclareModules(Handle<FixedArray> descriptions); void DeclareGlobals(Handle<FixedArray> pairs); int DeclareGlobalsFlags(); + // Generate code to allocate all (including nested) modules and contexts. + // Because of recursive linking and the presence of module alias declarations, + // this has to be a separate pass _before_ populating or executing any module. + void AllocateModules(ZoneList<Declaration*>* declarations); + // Try to perform a comparison as a fast inlined literal compare if // the operands allow it. Returns true if the compare operations // has been matched and all code generated; false otherwise. @@ -442,14 +448,13 @@ class FullCodeGenerator: public AstVisitor { // 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. // This is meant to be called at loop back edges, |back_edge_target| is // the jump target of the back edge and is used to approximate the amount // of code inside the loop. - void EmitStackCheck(IterationStatement* stmt, Label* back_edge_target); - // Record the OSR AST id corresponding to a stack check in the code. - void RecordStackCheck(BailoutId osr_ast_id); + void EmitBackEdgeBookkeeping(IterationStatement* stmt, + Label* back_edge_target); + // Record the OSR AST id corresponding to a back edge in the code. + void RecordBackEdge(BailoutId osr_ast_id); // Emit a table of stack check ids and pcs into the code stream. Return // the offset of the start of the table. unsigned EmitStackCheckTable(); @@ -804,8 +809,12 @@ class FullCodeGenerator: public AstVisitor { NestedStatement* nesting_stack_; int loop_depth_; ZoneList<Handle<Object> >* globals_; + Handle<FixedArray> modules_; + int module_index_; const ExpressionContext* context_; ZoneList<BailoutEntry> bailout_entries_; + // TODO(svenpanne) Rename this to something like back_edges_ and rename + // related functions accordingly. ZoneList<BailoutEntry> stack_checks_; ZoneList<TypeFeedbackCellEntry> type_feedback_cells_; int ic_total_count_; diff --git a/deps/v8/src/global-handles.cc b/deps/v8/src/global-handles.cc index 9c0ad45179..392a1810be 100644 --- a/deps/v8/src/global-handles.cc +++ b/deps/v8/src/global-handles.cc @@ -69,6 +69,7 @@ class GlobalHandles::Node { class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; index_ = 0; independent_ = false; + partially_dependent_ = false; in_new_space_list_ = false; parameter_or_next_free_.next_free = NULL; callback_ = NULL; @@ -89,6 +90,7 @@ class GlobalHandles::Node { object_ = object; class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; independent_ = false; + partially_dependent_ = false; state_ = NORMAL; parameter_or_next_free_.parameter = NULL; callback_ = NULL; @@ -154,6 +156,15 @@ class GlobalHandles::Node { } bool is_independent() const { return independent_; } + void MarkPartiallyDependent(GlobalHandles* global_handles) { + ASSERT(state_ != FREE); + if (global_handles->isolate()->heap()->InNewSpace(object_)) { + partially_dependent_ = true; + } + } + bool is_partially_dependent() const { return partially_dependent_; } + void clear_partially_dependent() { partially_dependent_ = false; } + // In-new-space-list flag accessors. void set_in_new_space_list(bool v) { in_new_space_list_ = v; } bool is_in_new_space_list() const { return in_new_space_list_; } @@ -260,6 +271,7 @@ class GlobalHandles::Node { State state_ : 4; bool independent_ : 1; + bool partially_dependent_ : 1; bool in_new_space_list_ : 1; // Handle specific callback. @@ -448,6 +460,16 @@ void GlobalHandles::MarkIndependent(Object** location) { } +void GlobalHandles::MarkPartiallyDependent(Object** location) { + Node::FromLocation(location)->MarkPartiallyDependent(this); +} + + +bool GlobalHandles::IsIndependent(Object** location) { + return Node::FromLocation(location)->is_independent(); +} + + bool GlobalHandles::IsNearDeath(Object** location) { return Node::FromLocation(location)->IsNearDeath(); } @@ -462,6 +484,9 @@ void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) { Node::FromLocation(location)->set_wrapper_class_id(class_id); } +uint16_t GlobalHandles::GetWrapperClassId(Object** location) { + return Node::FromLocation(location)->wrapper_class_id(); +} void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) { for (NodeIterator it(this); !it.done(); it.Advance()) { @@ -493,8 +518,9 @@ void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) { for (int i = 0; i < new_space_nodes_.length(); ++i) { Node* node = new_space_nodes_[i]; if (node->IsStrongRetainer() || - (node->IsWeakRetainer() && !node->is_independent())) { - v->VisitPointer(node->location()); + (node->IsWeakRetainer() && !node->is_independent() && + !node->is_partially_dependent())) { + v->VisitPointer(node->location()); } } } @@ -505,8 +531,8 @@ void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles( for (int i = 0; i < new_space_nodes_.length(); ++i) { Node* node = new_space_nodes_[i]; ASSERT(node->is_in_new_space_list()); - if (node->is_independent() && node->IsWeak() && - f(isolate_->heap(), node->location())) { + if ((node->is_independent() || node->is_partially_dependent()) && + node->IsWeak() && f(isolate_->heap(), node->location())) { node->MarkPending(); } } @@ -517,15 +543,61 @@ void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) { for (int i = 0; i < new_space_nodes_.length(); ++i) { Node* node = new_space_nodes_[i]; ASSERT(node->is_in_new_space_list()); - if (node->is_independent() && node->IsWeakRetainer()) { + if ((node->is_independent() || node->is_partially_dependent()) && + node->IsWeakRetainer()) { v->VisitPointer(node->location()); } } } +bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v, + WeakSlotCallbackWithHeap can_skip) { + int last = 0; + bool any_group_was_visited = false; + for (int i = 0; i < object_groups_.length(); i++) { + ObjectGroup* entry = object_groups_.at(i); + ASSERT(entry != NULL); + + Object*** objects = entry->objects_; + bool group_should_be_visited = false; + for (size_t j = 0; j < entry->length_; j++) { + Object* object = *objects[j]; + if (object->IsHeapObject()) { + if (!can_skip(isolate_->heap(), &object)) { + group_should_be_visited = true; + break; + } + } + } + + if (!group_should_be_visited) { + object_groups_[last++] = entry; + continue; + } + + // An object in the group requires visiting, so iterate over all + // objects in the group. + for (size_t j = 0; j < entry->length_; ++j) { + Object* object = *objects[j]; + if (object->IsHeapObject()) { + v->VisitPointer(&object); + any_group_was_visited = true; + } + } + + // Once the entire group has been iterated over, set the object + // group to NULL so it won't be processed again. + entry->Dispose(); + object_groups_.at(i) = NULL; + } + object_groups_.Rewind(last); + return any_group_was_visited; +} + + bool GlobalHandles::PostGarbageCollectionProcessing( - GarbageCollector collector) { + GarbageCollector collector, GCTracer* tracer) { // Process weak global handle callbacks. This must be done after the // GC is completely done, because the callbacks may invoke arbitrary // API functions. @@ -539,7 +611,10 @@ bool GlobalHandles::PostGarbageCollectionProcessing( // Skip dependent handles. Their weak callbacks might expect to be // called between two global garbage collection callbacks which // are not called for minor collections. - if (!node->is_independent()) continue; + if (!node->is_independent() && !node->is_partially_dependent()) { + continue; + } + node->clear_partially_dependent(); if (node->PostGarbageCollectionProcessing(isolate_, this)) { if (initial_post_gc_processing_count != post_gc_processing_count_) { // Weak callback triggered another GC and another round of @@ -555,6 +630,7 @@ bool GlobalHandles::PostGarbageCollectionProcessing( } } else { for (NodeIterator it(this); !it.done(); it.Advance()) { + it.node()->clear_partially_dependent(); if (it.node()->PostGarbageCollectionProcessing(isolate_, this)) { if (initial_post_gc_processing_count != post_gc_processing_count_) { // See the comment above. @@ -571,10 +647,17 @@ bool GlobalHandles::PostGarbageCollectionProcessing( for (int i = 0; i < new_space_nodes_.length(); ++i) { Node* node = new_space_nodes_[i]; ASSERT(node->is_in_new_space_list()); - if (node->IsRetainer() && isolate_->heap()->InNewSpace(node->object())) { - new_space_nodes_[last++] = node; + if (node->IsRetainer()) { + if (isolate_->heap()->InNewSpace(node->object())) { + new_space_nodes_[last++] = node; + tracer->increment_nodes_copied_in_new_space(); + } else { + node->set_in_new_space_list(false); + tracer->increment_nodes_promoted(); + } } else { node->set_in_new_space_list(false); + tracer->increment_nodes_died_in_new_space(); } } new_space_nodes_.Rewind(last); @@ -602,7 +685,7 @@ void GlobalHandles::IterateAllRoots(ObjectVisitor* v) { void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) { for (NodeIterator it(this); !it.done(); it.Advance()) { - if (it.node()->has_wrapper_class_id() && it.node()->IsRetainer()) { + if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) { v->VisitEmbedderReference(it.node()->location(), it.node()->wrapper_class_id()); } diff --git a/deps/v8/src/global-handles.h b/deps/v8/src/global-handles.h index ddf5fe29c3..7808d16a03 100644 --- a/deps/v8/src/global-handles.h +++ b/deps/v8/src/global-handles.h @@ -131,6 +131,7 @@ class GlobalHandles { WeakReferenceCallback callback); static void SetWrapperClassId(Object** location, uint16_t class_id); + static uint16_t GetWrapperClassId(Object** location); // Returns the current number of weak handles. int NumberOfWeakHandles() { return number_of_weak_handles_; } @@ -154,6 +155,11 @@ class GlobalHandles { // Clear the weakness of a global handle. void MarkIndependent(Object** location); + // Mark the reference to this object externaly unreachable. + void MarkPartiallyDependent(Object** location); + + static bool IsIndependent(Object** location); + // Tells whether global handle is near death. static bool IsNearDeath(Object** location); @@ -162,7 +168,8 @@ class GlobalHandles { // Process pending weak handles. // Returns true if next major GC is likely to collect more garbage. - bool PostGarbageCollectionProcessing(GarbageCollector collector); + bool PostGarbageCollectionProcessing(GarbageCollector collector, + GCTracer* tracer); // Iterates over all strong handles. void IterateStrongRoots(ObjectVisitor* v); @@ -192,16 +199,22 @@ class GlobalHandles { // Iterates over strong and dependent handles. See the node above. void IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v); - // Finds weak independent handles satisfying the callback predicate - // and marks them as pending. See the note above. + // Finds weak independent or partially independent handles satisfying + // the callback predicate and marks them as pending. See the note above. void IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f); - // Iterates over weak independent handles. See the note above. + // Iterates over weak independent or partially independent handles. + // See the note above. void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v); + // Iterate over objects in object groups that have at least one object + // which requires visiting. The callback has to return true if objects + // can be skipped and false otherwise. + bool IterateObjectGroups(ObjectVisitor* v, WeakSlotCallbackWithHeap can_skip); + // Add an object group. // Should be only used in GC callback function before a collection. - // All groups are destroyed after a mark-compact collection. + // All groups are destroyed after a garbage collection. void AddObjectGroup(Object*** handles, size_t length, v8::RetainedObjectInfo* info); diff --git a/deps/v8/src/globals.h b/deps/v8/src/globals.h index 00ecd63d2a..babffbf659 100644 --- a/deps/v8/src/globals.h +++ b/deps/v8/src/globals.h @@ -136,21 +136,6 @@ namespace internal { #endif #endif -// Define unaligned read for the target architectures supporting it. -#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_IA32) -#define V8_TARGET_CAN_READ_UNALIGNED 1 -#elif V8_TARGET_ARCH_ARM -// Some CPU-OS combinations allow unaligned access on ARM. We assume -// that unaligned accesses are not allowed unless the build system -// defines the CAN_USE_UNALIGNED_ACCESSES macro to be non-zero. -#if CAN_USE_UNALIGNED_ACCESSES -#define V8_TARGET_CAN_READ_UNALIGNED 1 -#endif -#elif V8_TARGET_ARCH_MIPS -#else -#error Target architecture is not supported by v8 -#endif - // Support for alternative bool type. This is only enabled if the code is // compiled with USE_MYBOOL defined. This catches some nasty type bugs. // For instance, 'bool b = "false";' results in b == true! This is a hidden diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc index 6aa7a6a876..7397cc00be 100644 --- a/deps/v8/src/handles.cc +++ b/deps/v8/src/handles.cc @@ -229,12 +229,12 @@ Handle<Object> SetPrototype(Handle<JSFunction> function, } -Handle<Object> SetProperty(Handle<Object> object, +Handle<Object> SetProperty(Isolate* isolate, + Handle<Object> object, Handle<Object> key, Handle<Object> value, PropertyAttributes attributes, StrictModeFlag strict_mode) { - Isolate* isolate = Isolate::Current(); CALL_HEAP_FUNCTION( isolate, Runtime::SetObjectProperty( @@ -593,6 +593,25 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver, } +Handle<Object> GetScriptNameOrSourceURL(Handle<Script> script) { + Isolate* isolate = script->GetIsolate(); + Handle<String> name_or_source_url_key = + isolate->factory()->LookupAsciiSymbol("nameOrSourceURL"); + Handle<JSValue> script_wrapper = GetScriptWrapper(script); + Handle<Object> property = GetProperty(script_wrapper, + name_or_source_url_key); + ASSERT(property->IsJSFunction()); + Handle<JSFunction> method = Handle<JSFunction>::cast(property); + bool caught_exception; + Handle<Object> result = Execution::TryCall(method, script_wrapper, 0, + NULL, &caught_exception); + if (caught_exception) { + result = isolate->factory()->undefined_value(); + } + return result; +} + + static bool ContainsOnlyValidKeys(Handle<FixedArray> array) { int len = array->length(); for (int i = 0; i < len; i++) { @@ -705,24 +724,46 @@ Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw) { } +Handle<FixedArray> ReduceFixedArrayTo(Handle<FixedArray> array, int length) { + ASSERT(array->length() >= length); + if (array->length() == length) return array; + + Handle<FixedArray> new_array = + array->GetIsolate()->factory()->NewFixedArray(length); + for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); + return new_array; +} + + Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, bool cache_result) { Isolate* isolate = object->GetIsolate(); if (object->HasFastProperties()) { if (object->map()->instance_descriptors()->HasEnumCache()) { int own_property_count = object->map()->EnumLength(); - - // Mark that we have an enum cache if we are allowed to cache it. - if (cache_result && own_property_count == Map::kInvalidEnumCache) { - int num_enum = object->map()->NumberOfDescribedProperties(DONT_ENUM); - object->map()->SetEnumLength(num_enum); + // If we have an enum cache, but the enum length of the given map is set + // to kInvalidEnumCache, this means that the map itself has never used the + // present enum cache. The first step to using the cache is to set the + // enum length of the map by counting the number of own descriptors that + // are not DONT_ENUM. + if (own_property_count == Map::kInvalidEnumCache) { + own_property_count = object->map()->NumberOfDescribedProperties( + OWN_DESCRIPTORS, DONT_ENUM); + + if (cache_result) object->map()->SetEnumLength(own_property_count); } DescriptorArray* desc = object->map()->instance_descriptors(); - Handle<FixedArray> keys(FixedArray::cast(desc->GetEnumCache()), isolate); - - isolate->counters()->enum_cache_hits()->Increment(); - return keys; + Handle<FixedArray> keys(desc->GetEnumCache(), isolate); + + // In case the number of properties required in the enum are actually + // present, we can reuse the enum cache. Otherwise, this means that the + // enum cache was generated for a previous (smaller) version of the + // Descriptor Array. In that case we regenerate the enum cache. + if (own_property_count <= keys->length()) { + isolate->counters()->enum_cache_hits()->Increment(); + return ReduceFixedArrayTo(keys, own_property_count); + } } Handle<Map> map(object->map()); @@ -734,8 +775,7 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, } isolate->counters()->enum_cache_misses()->Increment(); - - int num_enum = map->NumberOfDescribedProperties(DONT_ENUM); + int num_enum = map->NumberOfDescribedProperties(ALL_DESCRIPTORS, DONT_ENUM); Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum); Handle<FixedArray> indices = isolate->factory()->NewFixedArray(num_enum); @@ -743,10 +783,14 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, Handle<DescriptorArray> descs = Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); + int real_size = map->NumberOfOwnDescriptors(); + int enum_size = 0; int index = 0; + for (int i = 0; i < descs->number_of_descriptors(); i++) { PropertyDetails details = descs->GetDetails(i); if (!details.IsDontEnum()) { + if (i < real_size) ++enum_size; storage->set(index, descs->GetKey(i)); if (!indices.is_null()) { if (details.type() != FIELD) { @@ -773,9 +817,10 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, indices.is_null() ? Object::cast(Smi::FromInt(0)) : Object::cast(*indices)); if (cache_result) { - object->map()->SetEnumLength(index); + object->map()->SetEnumLength(enum_size); } - return storage; + + return ReduceFixedArrayTo(storage, enum_size); } else { Handle<StringDictionary> dictionary(object->property_dictionary()); @@ -870,7 +915,7 @@ int Utf8LengthHelper(String* input, int total = 0; bool dummy; while (true) { - if (input->IsAsciiRepresentation()) { + if (input->IsOneByteRepresentation()) { *starts_with_surrogate = false; return total + to - from; } @@ -903,14 +948,14 @@ int Utf8LengthHelper(String* input, } else { if (first_length > from) { // Left hand side is shorter. - if (first->IsAsciiRepresentation()) { + if (first->IsOneByteRepresentation()) { total += first_length - from; *starts_with_surrogate = false; starts_with_surrogate = &dummy; input = second; from = 0; to -= first_length; - } else if (second->IsAsciiRepresentation()) { + } else if (second->IsOneByteRepresentation()) { followed_by_surrogate = false; total += to - first_length; input = first; diff --git a/deps/v8/src/handles.h b/deps/v8/src/handles.h index b35693e95f..032fbe4815 100644 --- a/deps/v8/src/handles.h +++ b/deps/v8/src/handles.h @@ -95,6 +95,13 @@ class Handle { }; +// Convenience wrapper. +template<class T> +inline Handle<T> handle(T* t, Isolate* isolate) { + return Handle<T>(t, isolate); +} + + class DeferredHandles; class HandleScopeImplementer; @@ -209,7 +216,8 @@ Handle<String> FlattenGetString(Handle<String> str); int Utf8Length(Handle<String> str); -Handle<Object> SetProperty(Handle<Object> object, +Handle<Object> SetProperty(Isolate* isolate, + Handle<Object> object, Handle<Object> key, Handle<Object> value, PropertyAttributes attributes, @@ -260,6 +268,7 @@ int GetScriptLineNumber(Handle<Script> script, int code_position); // The safe version does not make heap allocations but may work much slower. int GetScriptLineNumberSafe(Handle<Script> script, int code_position); int GetScriptColumnNumber(Handle<Script> script, int code_position); +Handle<Object> GetScriptNameOrSourceURL(Handle<Script> script); // Computes the enumerable keys from interceptors. Used for debug mirrors and // by GetKeysInFixedArrayFor below. @@ -276,6 +285,7 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSReceiver> object, KeyCollectionType type, bool* threw); Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw); +Handle<FixedArray> ReduceFixedArrayTo(Handle<FixedArray> array, int length); Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, bool cache_result); diff --git a/deps/v8/src/heap-inl.h b/deps/v8/src/heap-inl.h index 4a827fef17..de47c94a8a 100644 --- a/deps/v8/src/heap-inl.h +++ b/deps/v8/src/heap-inl.h @@ -85,13 +85,16 @@ void PromotionQueue::ActivateGuardIfOnTheSamePage() { MaybeObject* Heap::AllocateStringFromUtf8(Vector<const char> str, PretenureFlag pretenure) { // Check for ASCII first since this is the common case. - if (String::IsAscii(str.start(), str.length())) { + const char* start = str.start(); + int length = str.length(); + int non_ascii_start = String::NonAsciiStart(start, length); + if (non_ascii_start >= length) { // If the string is ASCII, we do not need to convert the characters // since UTF8 is backwards compatible with ASCII. - return AllocateStringFromAscii(str, pretenure); + return AllocateStringFromOneByte(str, pretenure); } // Non-ASCII and we need to decode. - return AllocateStringFromUtf8Slow(str, pretenure); + return AllocateStringFromUtf8Slow(str, non_ascii_start, pretenure); } @@ -106,12 +109,12 @@ MaybeObject* Heap::AllocateSymbol(Vector<const char> str, MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str, uint32_t hash_field) { - if (str.length() > SeqAsciiString::kMaxLength) { + if (str.length() > SeqOneByteString::kMaxLength) { return Failure::OutOfMemoryException(); } // Compute map and object size. Map* map = ascii_symbol_map(); - int size = SeqAsciiString::SizeFor(str.length()); + int size = SeqOneByteString::SizeFor(str.length()); // Allocate string. Object* result; @@ -131,7 +134,7 @@ MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str, ASSERT_EQ(size, answer->Size()); // Fill in the characters. - memcpy(answer->address() + SeqAsciiString::kHeaderSize, + memcpy(answer->address() + SeqOneByteString::kHeaderSize, str.start(), str.length()); return answer; @@ -267,13 +270,6 @@ MaybeObject* Heap::AllocateRawMap() { #endif MaybeObject* result = map_space_->AllocateRaw(Map::kSize); if (result->IsFailure()) old_gen_exhausted_ = true; -#ifdef DEBUG - if (!result->IsFailure()) { - // Maps have their own alignment. - CHECK((reinterpret_cast<intptr_t>(result) & kMapAlignmentMask) == - static_cast<intptr_t>(kHeapObjectTag)); - } -#endif return result; } @@ -464,7 +460,7 @@ intptr_t Heap::AdjustAmountOfExternalAllocatedMemory( intptr_t change_in_bytes) { ASSERT(HasBeenSetUp()); intptr_t amount = amount_of_external_allocated_memory_ + change_in_bytes; - if (change_in_bytes >= 0) { + if (change_in_bytes > 0) { // Avoid overflow. if (amount > amount_of_external_allocated_memory_) { amount_of_external_allocated_memory_ = amount; @@ -611,7 +607,7 @@ void ExternalStringTable::Verify() { Object* obj = Object::cast(new_space_strings_[i]); // TODO(yangguo): check that the object is indeed an external string. ASSERT(heap_->InNewSpace(obj)); - ASSERT(obj != HEAP->raw_unchecked_the_hole_value()); + ASSERT(obj != HEAP->the_hole_value()); if (obj->IsExternalAsciiString()) { ExternalAsciiString* string = ExternalAsciiString::cast(obj); ASSERT(String::IsAscii(string->GetChars(), string->length())); @@ -621,7 +617,7 @@ void ExternalStringTable::Verify() { Object* obj = Object::cast(old_space_strings_[i]); // TODO(yangguo): check that the object is indeed an external string. ASSERT(!heap_->InNewSpace(obj)); - ASSERT(obj != HEAP->raw_unchecked_the_hole_value()); + ASSERT(obj != HEAP->the_hole_value()); if (obj->IsExternalAsciiString()) { ExternalAsciiString* string = ExternalAsciiString::cast(obj); ASSERT(String::IsAscii(string->GetChars(), string->length())); @@ -640,9 +636,11 @@ void ExternalStringTable::AddOldString(String* string) { void ExternalStringTable::ShrinkNewStrings(int position) { new_space_strings_.Rewind(position); +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { Verify(); } +#endif } @@ -741,28 +739,15 @@ AlwaysAllocateScope::~AlwaysAllocateScope() { } -LinearAllocationScope::LinearAllocationScope() { - HEAP->linear_allocation_scope_depth_++; -} - - -LinearAllocationScope::~LinearAllocationScope() { - HEAP->linear_allocation_scope_depth_--; - ASSERT(HEAP->linear_allocation_scope_depth_ >= 0); -} - - -#ifdef DEBUG void VerifyPointersVisitor::VisitPointers(Object** start, Object** end) { for (Object** current = start; current < end; current++) { if ((*current)->IsHeapObject()) { HeapObject* object = HeapObject::cast(*current); - ASSERT(HEAP->Contains(object)); - ASSERT(object->map()->IsMap()); + CHECK(HEAP->Contains(object)); + CHECK(object->map()->IsMap()); } } } -#endif double GCTracer::SizeOfHeapObjects() { diff --git a/deps/v8/src/heap-profiler.cc b/deps/v8/src/heap-profiler.cc index 301b09993e..45a93f9e14 100644 --- a/deps/v8/src/heap-profiler.cc +++ b/deps/v8/src/heap-profiler.cc @@ -65,23 +65,29 @@ void HeapProfiler::TearDown() { } -HeapSnapshot* HeapProfiler::TakeSnapshot(const char* name, - int type, - v8::ActivityControl* control) { +HeapSnapshot* HeapProfiler::TakeSnapshot( + const char* name, + int type, + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver) { ASSERT(Isolate::Current()->heap_profiler() != NULL); return Isolate::Current()->heap_profiler()->TakeSnapshotImpl(name, type, - control); + control, + resolver); } -HeapSnapshot* HeapProfiler::TakeSnapshot(String* name, - int type, - v8::ActivityControl* control) { +HeapSnapshot* HeapProfiler::TakeSnapshot( + String* name, + int type, + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver) { ASSERT(Isolate::Current()->heap_profiler() != NULL); return Isolate::Current()->heap_profiler()->TakeSnapshotImpl(name, type, - control); + control, + resolver); } @@ -122,16 +128,18 @@ v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback( } -HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, - int type, - v8::ActivityControl* control) { +HeapSnapshot* HeapProfiler::TakeSnapshotImpl( + const char* name, + int type, + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver) { HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type); HeapSnapshot* result = snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++); bool generation_completed = true; switch (s_type) { case HeapSnapshot::kFull: { - HeapSnapshotGenerator generator(result, control); + HeapSnapshotGenerator generator(result, control, resolver); generation_completed = generator.GenerateSnapshot(); break; } @@ -147,10 +155,13 @@ HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, } -HeapSnapshot* HeapProfiler::TakeSnapshotImpl(String* name, - int type, - v8::ActivityControl* control) { - return TakeSnapshotImpl(snapshots_->names()->GetName(name), type, control); +HeapSnapshot* HeapProfiler::TakeSnapshotImpl( + String* name, + int type, + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver) { + return TakeSnapshotImpl(snapshots_->names()->GetName(name), type, control, + resolver); } void HeapProfiler::StartHeapObjectsTrackingImpl() { diff --git a/deps/v8/src/heap-profiler.h b/deps/v8/src/heap-profiler.h index 346177b8ba..9d3ba6f111 100644 --- a/deps/v8/src/heap-profiler.h +++ b/deps/v8/src/heap-profiler.h @@ -51,12 +51,16 @@ class HeapProfiler { static size_t GetMemorySizeUsedByProfiler(); - static HeapSnapshot* TakeSnapshot(const char* name, - int type, - v8::ActivityControl* control); - static HeapSnapshot* TakeSnapshot(String* name, - int type, - v8::ActivityControl* control); + static HeapSnapshot* TakeSnapshot( + const char* name, + int type, + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver); + static HeapSnapshot* TakeSnapshot( + String* name, + int type, + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver); static void StartHeapObjectsTracking(); static void StopHeapObjectsTracking(); @@ -81,12 +85,16 @@ class HeapProfiler { private: HeapProfiler(); ~HeapProfiler(); - HeapSnapshot* TakeSnapshotImpl(const char* name, - int type, - v8::ActivityControl* control); - HeapSnapshot* TakeSnapshotImpl(String* name, - int type, - v8::ActivityControl* control); + HeapSnapshot* TakeSnapshotImpl( + const char* name, + int type, + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver); + HeapSnapshot* TakeSnapshotImpl( + String* name, + int type, + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver); void ResetSnapshots(); void StartHeapObjectsTrackingImpl(); diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 9ba769212d..746c9b6d6f 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -48,6 +48,7 @@ #include "snapshot.h" #include "store-buffer.h" #include "v8threads.h" +#include "v8utils.h" #include "vm-state-inl.h" #if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP #include "regexp-macro-assembler.h" @@ -97,6 +98,7 @@ Heap::Heap() linear_allocation_scope_depth_(0), contexts_disposed_(0), global_ic_age_(0), + flush_monomorphic_ics_(false), scan_on_scavenge_pages_(0), new_space_(this), old_pointer_space_(NULL), @@ -115,7 +117,6 @@ Heap::Heap() allocation_allowed_(true), allocation_timeout_(0), disallow_allocation_failure_(false), - debug_utils_(NULL), #endif // DEBUG new_space_high_promotion_mode_active_(false), old_gen_promotion_limit_(kMinimumPromotionLimit), @@ -135,6 +136,7 @@ Heap::Heap() tracer_(NULL), young_survivors_after_last_gc_(0), high_survival_rate_period_length_(0), + low_survival_rate_period_length_(0), survival_rate_(0), previous_survival_rate_trend_(Heap::STABLE), survival_rate_trend_(Heap::STABLE), @@ -210,6 +212,20 @@ intptr_t Heap::CommittedMemory() { lo_space_->Size(); } + +size_t Heap::CommittedPhysicalMemory() { + if (!HasBeenSetUp()) return 0; + + return new_space_.CommittedPhysicalMemory() + + old_pointer_space_->CommittedPhysicalMemory() + + old_data_space_->CommittedPhysicalMemory() + + code_space_->CommittedPhysicalMemory() + + map_space_->CommittedPhysicalMemory() + + cell_space_->CommittedPhysicalMemory() + + lo_space_->CommittedPhysicalMemory(); +} + + intptr_t Heap::CommittedMemoryExecutable() { if (!HasBeenSetUp()) return 0; @@ -370,6 +386,12 @@ void Heap::PrintShortHeapStatistics() { lo_space_->SizeOfObjects() / KB, lo_space_->Available() / KB, lo_space_->CommittedMemory() / KB); + PrintPID("All spaces, used: %6" V8_PTR_PREFIX "d KB" + ", available: %6" V8_PTR_PREFIX "d KB" + ", committed: %6" V8_PTR_PREFIX "d KB\n", + this->SizeOfObjects() / KB, + this->Available() / KB, + this->CommittedMemory() / KB); PrintPID("Total time spent in GC : %d ms\n", total_gc_time_ms_); } @@ -397,18 +419,23 @@ void Heap::GarbageCollectionPrologue() { ClearJSFunctionResultCaches(); gc_count_++; unflattened_strings_length_ = 0; -#ifdef DEBUG - ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC); - allow_allocation(false); + if (FLAG_flush_code && FLAG_flush_code_incrementally) { + mark_compact_collector()->EnableCodeFlushing(true); + } + +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { Verify(); } +#endif + +#ifdef DEBUG + ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC); + allow_allocation(false); if (FLAG_gc_verbose) Print(); -#endif // DEBUG -#if defined(DEBUG) ReportStatisticsBeforeGC(); #endif // DEBUG @@ -416,6 +443,7 @@ void Heap::GarbageCollectionPrologue() { store_buffer()->GCPrologue(); } + intptr_t Heap::SizeOfObjects() { intptr_t total = 0; AllSpaces spaces; @@ -425,17 +453,34 @@ intptr_t Heap::SizeOfObjects() { return total; } + +void Heap::RepairFreeListsAfterBoot() { + PagedSpaces spaces; + for (PagedSpace* space = spaces.next(); + space != NULL; + space = spaces.next()) { + space->RepairFreeListsAfterBoot(); + } +} + + void Heap::GarbageCollectionEpilogue() { store_buffer()->GCEpilogue(); LiveObjectList::GCEpilogue(); -#ifdef DEBUG - allow_allocation(true); - ZapFromSpace(); + // In release mode, we only zap the from space under heap verification. + if (Heap::ShouldZapGarbage()) { + ZapFromSpace(); + } + +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { Verify(); } +#endif +#ifdef DEBUG + allow_allocation(true); if (FLAG_print_global_handles) isolate_->global_handles()->Print(); if (FLAG_print_handles) PrintHandles(); if (FLAG_gc_verbose) Print(); @@ -570,7 +615,7 @@ bool Heap::CollectGarbage(AllocationSpace space, } if (collector == MARK_COMPACTOR && - !mark_compact_collector()->abort_incremental_marking_ && + !mark_compact_collector()->abort_incremental_marking() && !incremental_marking()->IsStopped() && !incremental_marking()->should_hurry() && FLAG_incremental_marking_steps) { @@ -598,22 +643,24 @@ bool Heap::CollectGarbage(AllocationSpace space, // Tell the tracer which collector we've selected. tracer.set_collector(collector); - HistogramTimer* rate = (collector == SCAVENGER) - ? isolate_->counters()->gc_scavenger() - : isolate_->counters()->gc_compactor(); - rate->Start(); - next_gc_likely_to_collect_more = - PerformGarbageCollection(collector, &tracer); - rate->Stop(); + { + HistogramTimerScope histogram_timer_scope( + (collector == SCAVENGER) ? isolate_->counters()->gc_scavenger() + : isolate_->counters()->gc_compactor()); + next_gc_likely_to_collect_more = + PerformGarbageCollection(collector, &tracer); + } GarbageCollectionEpilogue(); } - ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped()); - if (incremental_marking()->IsStopped()) { - if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) { - incremental_marking()->Start(); - } + // Start incremental marking for the next cycle. The heap snapshot + // generator needs incremental marking to stay off after it aborted. + if (!mark_compact_collector()->abort_incremental_marking() && + incremental_marking()->IsStopped() && + incremental_marking()->WorthActivating() && + NextGCIsLikelyToBeFull()) { + incremental_marking()->Start(); } return next_gc_likely_to_collect_more; @@ -630,7 +677,7 @@ void Heap::PerformScavenge() { } -#ifdef DEBUG +#ifdef VERIFY_HEAP // Helper class for verifying the symbol table. class SymbolTableVerifier : public ObjectVisitor { public: @@ -639,20 +686,18 @@ class SymbolTableVerifier : public ObjectVisitor { for (Object** p = start; p < end; p++) { if ((*p)->IsHeapObject()) { // Check that the symbol is actually a symbol. - ASSERT((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol()); + CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol()); } } } }; -#endif // DEBUG static void VerifySymbolTable() { -#ifdef DEBUG SymbolTableVerifier verifier; HEAP->symbol_table()->IterateElements(&verifier); -#endif // DEBUG } +#endif // VERIFY_HEAP static bool AbortIncrementalMarkingAndCollectGarbage( @@ -667,67 +712,42 @@ static bool AbortIncrementalMarkingAndCollectGarbage( void Heap::ReserveSpace( - int new_space_size, - int pointer_space_size, - int data_space_size, - int code_space_size, - int map_space_size, - int cell_space_size, - int large_object_size) { - NewSpace* new_space = Heap::new_space(); - PagedSpace* old_pointer_space = Heap::old_pointer_space(); - PagedSpace* old_data_space = Heap::old_data_space(); - PagedSpace* code_space = Heap::code_space(); - PagedSpace* map_space = Heap::map_space(); - PagedSpace* cell_space = Heap::cell_space(); - LargeObjectSpace* lo_space = Heap::lo_space(); + int *sizes, + Address *locations_out) { bool gc_performed = true; int counter = 0; static const int kThreshold = 20; while (gc_performed && counter++ < kThreshold) { gc_performed = false; - if (!new_space->ReserveSpace(new_space_size)) { - Heap::CollectGarbage(NEW_SPACE, - "failed to reserve space in the new space"); - gc_performed = true; - } - if (!old_pointer_space->ReserveSpace(pointer_space_size)) { - AbortIncrementalMarkingAndCollectGarbage(this, OLD_POINTER_SPACE, - "failed to reserve space in the old pointer space"); - gc_performed = true; - } - if (!(old_data_space->ReserveSpace(data_space_size))) { - AbortIncrementalMarkingAndCollectGarbage(this, OLD_DATA_SPACE, - "failed to reserve space in the old data space"); - gc_performed = true; - } - if (!(code_space->ReserveSpace(code_space_size))) { - AbortIncrementalMarkingAndCollectGarbage(this, CODE_SPACE, - "failed to reserve space in the code space"); - gc_performed = true; - } - if (!(map_space->ReserveSpace(map_space_size))) { - AbortIncrementalMarkingAndCollectGarbage(this, MAP_SPACE, - "failed to reserve space in the map space"); - gc_performed = true; - } - if (!(cell_space->ReserveSpace(cell_space_size))) { - AbortIncrementalMarkingAndCollectGarbage(this, CELL_SPACE, - "failed to reserve space in the cell space"); - gc_performed = true; - } - // We add a slack-factor of 2 in order to have space for a series of - // large-object allocations that are only just larger than the page size. - large_object_size *= 2; - // The ReserveSpace method on the large object space checks how much - // we can expand the old generation. This includes expansion caused by - // allocation in the other spaces. - large_object_size += cell_space_size + map_space_size + code_space_size + - data_space_size + pointer_space_size; - if (!(lo_space->ReserveSpace(large_object_size))) { - AbortIncrementalMarkingAndCollectGarbage(this, LO_SPACE, - "failed to reserve space in the large object space"); - gc_performed = true; + ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1); + for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) { + if (sizes[space] != 0) { + MaybeObject* allocation; + if (space == NEW_SPACE) { + allocation = new_space()->AllocateRaw(sizes[space]); + } else { + allocation = paged_space(space)->AllocateRaw(sizes[space]); + } + FreeListNode* node; + if (!allocation->To<FreeListNode>(&node)) { + if (space == NEW_SPACE) { + Heap::CollectGarbage(NEW_SPACE, + "failed to reserve space in the new space"); + } else { + AbortIncrementalMarkingAndCollectGarbage( + this, + static_cast<AllocationSpace>(space), + "failed to reserve space in paged space"); + } + gc_performed = true; + break; + } else { + // Mark with a free list node, in case we have a GC before + // deserializing. + node->set_size(this, sizes[space]); + locations_out[space] = node->address(); + } + } } } @@ -834,9 +854,12 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector, PROFILE(isolate_, CodeMovingGCEvent()); } +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { VerifySymbolTable(); } +#endif + if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) { ASSERT(!allocation_allowed_); GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); @@ -934,11 +957,16 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector, isolate_->counters()->objs_since_last_young()->Set(0); + // Callbacks that fire after this point might trigger nested GCs and + // restart incremental marking, the assertion can't be moved down. + ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped()); + gc_post_processing_depth_++; { DisableAssertNoAllocation allow_allocation; GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); next_gc_likely_to_collect_more = - isolate_->global_handles()->PostGarbageCollectionProcessing(collector); + isolate_->global_handles()->PostGarbageCollectionProcessing( + collector, tracer); } gc_post_processing_depth_--; @@ -963,9 +991,12 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector, GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); global_gc_epilogue_callback_(); } + +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { VerifySymbolTable(); } +#endif return next_gc_likely_to_collect_more; } @@ -992,7 +1023,7 @@ void Heap::MarkCompact(GCTracer* tracer) { contexts_disposed_ = 0; - isolate_->set_context_exit_happened(false); + flush_monomorphic_ics_ = false; } @@ -1048,7 +1079,7 @@ class ScavengeVisitor: public ObjectVisitor { }; -#ifdef DEBUG +#ifdef VERIFY_HEAP // Visitor class to verify pointers in code or data space do not point into // new space. class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor { @@ -1056,7 +1087,7 @@ class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor { void VisitPointers(Object** start, Object**end) { for (Object** current = start; current < end; current++) { if ((*current)->IsHeapObject()) { - ASSERT(!HEAP->InNewSpace(HeapObject::cast(*current))); + CHECK(!HEAP->InNewSpace(HeapObject::cast(*current))); } } } @@ -1081,7 +1112,7 @@ static void VerifyNonPointerSpacePointers() { object->Iterate(&v); } } -#endif +#endif // VERIFY_HEAP void Heap::CheckNewSpaceExpansionCriteria() { @@ -1220,7 +1251,8 @@ class ScavengeWeakObjectRetainer : public WeakObjectRetainer { void Heap::Scavenge() { RelocationLock relocation_lock(this); -#ifdef DEBUG + +#ifdef VERIFY_HEAP if (FLAG_verify_heap) VerifyNonPointerSpacePointers(); #endif @@ -1296,10 +1328,23 @@ void Heap::Scavenge() { } } + // Copy objects reachable from the code flushing candidates list. + MarkCompactCollector* collector = mark_compact_collector(); + if (collector->is_code_flushing_enabled()) { + collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor); + } + // Scavenge object reachable from the native contexts list directly. scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_)); new_space_front = DoScavenge(&scavenge_visitor, new_space_front); + + while (isolate()->global_handles()->IterateObjectGroups( + &scavenge_visitor, &IsUnscavengedHeapObject)) { + new_space_front = DoScavenge(&scavenge_visitor, new_space_front); + } + isolate()->global_handles()->RemoveObjectGroups(); + isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles( &IsUnscavengedHeapObject); isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots( @@ -1357,9 +1402,11 @@ String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, void Heap::UpdateNewSpaceReferencesInExternalStringTable( ExternalStringTableUpdaterCallback updater_func) { +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { external_string_table_.Verify(); } +#endif if (external_string_table_.new_space_strings_.is_empty()) return; @@ -1537,13 +1584,40 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) { AssertNoAllocation no_allocation; - class VisitorAdapter : public ObjectVisitor { + // Both the external string table and the symbol table may contain + // external strings, but neither lists them exhaustively, nor is the + // intersection set empty. Therefore we iterate over the external string + // table first, ignoring symbols, and then over the symbol table. + + class ExternalStringTableVisitorAdapter : public ObjectVisitor { + public: + explicit ExternalStringTableVisitorAdapter( + v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {} + virtual void VisitPointers(Object** start, Object** end) { + for (Object** p = start; p < end; p++) { + // Visit non-symbol external strings, + // since symbols are listed in the symbol table. + if (!(*p)->IsSymbol()) { + ASSERT((*p)->IsExternalString()); + visitor_->VisitExternalString(Utils::ToLocal( + Handle<String>(String::cast(*p)))); + } + } + } + private: + v8::ExternalResourceVisitor* visitor_; + } external_string_table_visitor(visitor); + + external_string_table_.Iterate(&external_string_table_visitor); + + class SymbolTableVisitorAdapter : public ObjectVisitor { public: - explicit VisitorAdapter(v8::ExternalResourceVisitor* visitor) - : visitor_(visitor) {} + explicit SymbolTableVisitorAdapter( + v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {} virtual void VisitPointers(Object** start, Object** end) { for (Object** p = start; p < end; p++) { if ((*p)->IsExternalString()) { + ASSERT((*p)->IsSymbol()); visitor_->VisitExternalString(Utils::ToLocal( Handle<String>(String::cast(*p)))); } @@ -1551,8 +1625,9 @@ void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) { } private: v8::ExternalResourceVisitor* visitor_; - } visitor_adapter(visitor); - external_string_table_.Iterate(&visitor_adapter); + } symbol_table_visitor(visitor); + + symbol_table()->IterateElements(&symbol_table_visitor); } @@ -1649,7 +1724,7 @@ template<MarksHandling marks_handling, class ScavengingVisitor : public StaticVisitorBase { public: static void Initialize() { - table_.Register(kVisitSeqAsciiString, &EvacuateSeqAsciiString); + table_.Register(kVisitSeqOneByteString, &EvacuateSeqOneByteString); table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString); table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); table_.Register(kVisitByteArray, &EvacuateByteArray); @@ -1893,11 +1968,11 @@ class ScavengingVisitor : public StaticVisitorBase { } - static inline void EvacuateSeqAsciiString(Map* map, + static inline void EvacuateSeqOneByteString(Map* map, HeapObject** slot, HeapObject* object) { - int object_size = SeqAsciiString::cast(object)-> - SeqAsciiStringSize(map->instance_type()); + int object_size = SeqOneByteString::cast(object)-> + SeqOneByteStringSize(map->instance_type()); EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>( map, slot, object, object_size); } @@ -2064,7 +2139,9 @@ MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, reinterpret_cast<Map*>(result)->set_unused_property_fields(0); reinterpret_cast<Map*>(result)->set_bit_field(0); reinterpret_cast<Map*>(result)->set_bit_field2(0); - reinterpret_cast<Map*>(result)->set_bit_field3(0); + int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) | + Map::OwnsDescriptors::encode(true); + reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3); return result; } @@ -2089,18 +2166,14 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER); map->init_back_pointer(undefined_value()); map->set_unused_property_fields(0); + map->set_instance_descriptors(empty_descriptor_array()); map->set_bit_field(0); map->set_bit_field2(1 << Map::kIsExtensible); - int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache); + int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) | + Map::OwnsDescriptors::encode(true); map->set_bit_field3(bit_field3); map->set_elements_kind(elements_kind); - // If the map object is aligned fill the padding area with Smi 0 objects. - if (Map::kPadStart < Map::kSize) { - memset(reinterpret_cast<byte*>(map) + Map::kPadStart - kHeapObjectTag, - 0, - Map::kSize - Map::kPadStart); - } return map; } @@ -2227,12 +2300,15 @@ bool Heap::CreateInitialMaps() { // Fix the instance_descriptors for the existing maps. meta_map()->set_code_cache(empty_fixed_array()); meta_map()->init_back_pointer(undefined_value()); + meta_map()->set_instance_descriptors(empty_descriptor_array()); fixed_array_map()->set_code_cache(empty_fixed_array()); fixed_array_map()->init_back_pointer(undefined_value()); + fixed_array_map()->set_instance_descriptors(empty_descriptor_array()); oddball_map()->set_code_cache(empty_fixed_array()); oddball_map()->init_back_pointer(undefined_value()); + oddball_map()->set_instance_descriptors(empty_descriptor_array()); // Fix prototype object for existing maps. meta_map()->set_prototype(null_value()); @@ -2463,6 +2539,14 @@ bool Heap::CreateInitialMaps() { } set_message_object_map(Map::cast(obj)); + Map* external_map; + { MaybeObject* maybe_obj = + AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize); + if (!maybe_obj->To(&external_map)) return false; + } + external_map->set_is_extensible(false); + set_external_map(external_map); + ASSERT(!InNewSpace(empty_fixed_array())); return true; } @@ -2681,7 +2765,7 @@ bool Heap::CreateInitialObjects() { set_termination_exception(obj); // Allocate the empty string. - { MaybeObject* maybe_obj = AllocateRawAsciiString(0, TENURED); + { MaybeObject* maybe_obj = AllocateRawOneByteString(0, TENURED); if (!maybe_obj->ToObject(&obj)) return false; } set_empty_string(String::cast(obj)); @@ -2701,7 +2785,7 @@ bool Heap::CreateInitialObjects() { // hash code in place. The hash code for the hidden_symbol is zero to ensure // that it will always be at the first entry in property descriptors. { MaybeObject* maybe_obj = - AllocateSymbol(CStrVector(""), 0, String::kZeroHash); + AllocateSymbol(CStrVector(""), 0, String::kEmptyStringHash); if (!maybe_obj->ToObject(&obj)) return false; } hidden_symbol_ = String::cast(obj); @@ -2780,6 +2864,15 @@ bool Heap::CreateInitialObjects() { } set_natives_source_cache(FixedArray::cast(obj)); + // Allocate object to hold object observation state. + { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); + if (!maybe_obj->ToObject(&obj)) return false; + } + { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj)); + if (!maybe_obj->ToObject(&obj)) return false; + } + set_observation_state(JSObject::cast(obj)); + // Handling of script id generation is in FACTORY->NewScript. set_last_script_id(undefined_value()); @@ -2799,6 +2892,34 @@ bool Heap::CreateInitialObjects() { } +bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) { + RootListIndex writable_roots[] = { + kStoreBufferTopRootIndex, + kStackLimitRootIndex, + kInstanceofCacheFunctionRootIndex, + kInstanceofCacheMapRootIndex, + kInstanceofCacheAnswerRootIndex, + kCodeStubsRootIndex, + kNonMonomorphicCacheRootIndex, + kPolymorphicCodeCacheRootIndex, + kLastScriptIdRootIndex, + kEmptyScriptRootIndex, + kRealStackLimitRootIndex, + kArgumentsAdaptorDeoptPCOffsetRootIndex, + kConstructStubDeoptPCOffsetRootIndex, + kGetterStubDeoptPCOffsetRootIndex, + kSetterStubDeoptPCOffsetRootIndex, + kSymbolTableRootIndex, + }; + + for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) { + if (root_index == writable_roots[i]) + return true; + } + return false; +} + + Object* RegExpResultsCache::Lookup(Heap* heap, String* key_string, Object* key_pattern, @@ -3016,7 +3137,7 @@ MaybeObject* Heap::NumberToString(Object* number, } Object* js_string; - MaybeObject* maybe_js_string = AllocateStringFromAscii(CStrVector(str)); + MaybeObject* maybe_js_string = AllocateStringFromOneByte(CStrVector(str)); if (maybe_js_string->ToObject(&js_string)) { SetNumberStringCache(number, String::cast(js_string)); } @@ -3190,10 +3311,10 @@ MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString( } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this. Object* result; - { MaybeObject* maybe_result = heap->AllocateRawAsciiString(2); + { MaybeObject* maybe_result = heap->AllocateRawOneByteString(2); if (!maybe_result->ToObject(&result)) return maybe_result; } - char* dest = SeqAsciiString::cast(result)->GetChars(); + char* dest = SeqOneByteString::cast(result)->GetChars(); dest[0] = c1; dest[1] = c2; return result; @@ -3232,8 +3353,8 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) { return MakeOrFindTwoCharacterString(this, c1, c2); } - bool first_is_ascii = first->IsAsciiRepresentation(); - bool second_is_ascii = second->IsAsciiRepresentation(); + bool first_is_ascii = first->IsOneByteRepresentation(); + bool second_is_ascii = second->IsOneByteRepresentation(); bool is_ascii = first_is_ascii && second_is_ascii; // Make sure that an out of memory exception is thrown if the length @@ -3263,35 +3384,35 @@ MaybeObject* Heap::AllocateConsString(String* first, String* second) { ASSERT(second->IsFlat()); if (is_ascii) { Object* result; - { MaybeObject* maybe_result = AllocateRawAsciiString(length); + { MaybeObject* maybe_result = AllocateRawOneByteString(length); if (!maybe_result->ToObject(&result)) return maybe_result; } // Copy the characters into the new object. - char* dest = SeqAsciiString::cast(result)->GetChars(); + char* dest = SeqOneByteString::cast(result)->GetChars(); // Copy first part. const char* src; if (first->IsExternalString()) { src = ExternalAsciiString::cast(first)->GetChars(); } else { - src = SeqAsciiString::cast(first)->GetChars(); + src = SeqOneByteString::cast(first)->GetChars(); } for (int i = 0; i < first_length; i++) *dest++ = src[i]; // Copy second part. if (second->IsExternalString()) { src = ExternalAsciiString::cast(second)->GetChars(); } else { - src = SeqAsciiString::cast(second)->GetChars(); + src = SeqOneByteString::cast(second)->GetChars(); } for (int i = 0; i < second_length; i++) *dest++ = src[i]; return result; } else { if (is_ascii_data_in_two_byte_string) { Object* result; - { MaybeObject* maybe_result = AllocateRawAsciiString(length); + { MaybeObject* maybe_result = AllocateRawOneByteString(length); if (!maybe_result->ToObject(&result)) return maybe_result; } // Copy the characters into the new object. - char* dest = SeqAsciiString::cast(result)->GetChars(); + char* dest = SeqOneByteString::cast(result)->GetChars(); String::WriteToFlat(first, dest, 0, first_length); String::WriteToFlat(second, dest + first_length, 0, second_length); isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment(); @@ -3358,17 +3479,17 @@ MaybeObject* Heap::AllocateSubString(String* buffer, // WriteToFlat takes care of the case when an indirect string has a // different encoding from its underlying string. These encodings may // differ because of externalization. - bool is_ascii = buffer->IsAsciiRepresentation(); + bool is_ascii = buffer->IsOneByteRepresentation(); { MaybeObject* maybe_result = is_ascii - ? AllocateRawAsciiString(length, pretenure) + ? AllocateRawOneByteString(length, pretenure) : AllocateRawTwoByteString(length, pretenure); if (!maybe_result->ToObject(&result)) return maybe_result; } String* string_result = String::cast(result); // Copy the characters into the new object. if (is_ascii) { - ASSERT(string_result->IsAsciiRepresentation()); - char* dest = SeqAsciiString::cast(string_result)->GetChars(); + ASSERT(string_result->IsOneByteRepresentation()); + char* dest = SeqOneByteString::cast(string_result)->GetChars(); String::WriteToFlat(buffer, dest, start, end); } else { ASSERT(string_result->IsTwoByteRepresentation()); @@ -3379,7 +3500,7 @@ MaybeObject* Heap::AllocateSubString(String* buffer, } ASSERT(buffer->IsFlat()); -#if DEBUG +#if VERIFY_HEAP if (FLAG_verify_heap) { buffer->StringVerify(); } @@ -3392,7 +3513,7 @@ MaybeObject* Heap::AllocateSubString(String* buffer, // indirect ASCII string is pointing to a two-byte string, the two-byte char // codes of the underlying string must still fit into ASCII (because // externalization must not change char codes). - { Map* map = buffer->IsAsciiRepresentation() + { Map* map = buffer->IsOneByteRepresentation() ? sliced_ascii_string_map() : sliced_string_map(); MaybeObject* maybe_result = Allocate(map, NEW_SPACE); @@ -3596,17 +3717,27 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc, MaybeObject* maybe_result; // Large code objects and code objects which should stay at a fixed address // are allocated in large object space. - if (obj_size > code_space()->AreaSize() || immovable) { + HeapObject* result; + bool force_lo_space = obj_size > code_space()->AreaSize(); + if (force_lo_space) { maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); } else { maybe_result = code_space_->AllocateRaw(obj_size); } + if (!maybe_result->To<HeapObject>(&result)) return maybe_result; - Object* result; - if (!maybe_result->ToObject(&result)) return maybe_result; + if (immovable && !force_lo_space && + // Objects on the first page of each space are never moved. + !code_space_->FirstPage()->Contains(result->address())) { + // Discard the first code allocation, which was on a page where it could be + // moved. + CreateFillerObjectAt(result->address(), obj_size); + maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); + if (!maybe_result->To<HeapObject>(&result)) return maybe_result; + } // Initialize the object - HeapObject::cast(result)->set_map_no_write_barrier(code_map()); + result->set_map_no_write_barrier(code_map()); Code* code = Code::cast(result); ASSERT(!isolate_->code_range()->exists() || isolate_->code_range()->contains(code->address())); @@ -3617,10 +3748,11 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc, code->set_check_type(RECEIVER_MAP_CHECK); } code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER); - code->set_type_feedback_info(undefined_value(), SKIP_WRITE_BARRIER); + code->InitializeTypeFeedbackInfoNoWriteBarrier(undefined_value()); code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER); code->set_gc_metadata(Smi::FromInt(0)); code->set_ic_age(global_ic_age_); + code->set_prologue_offset(kPrologueOffsetNotSet); // Allow self references to created code object by patching the handle to // point to the newly allocated Code object. if (!self_reference.is_null()) { @@ -3633,7 +3765,7 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc, // through the self_reference parameter. code->CopyFrom(desc); -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { code->Verify(); } @@ -3715,7 +3847,7 @@ MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) { isolate_->code_range()->contains(code->address())); new_code->Relocate(new_addr - old_addr); -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { code->Verify(); } @@ -3932,8 +4064,7 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) { if (HasDuplicates(descriptors)) { fun->shared()->ForbidInlineConstructor(); } else { - MaybeObject* maybe_failure = map->InitializeDescriptors(descriptors); - if (maybe_failure->IsFailure()) return maybe_failure; + map->InitializeDescriptors(descriptors); map->set_pre_allocated_property_fields(count); map->set_unused_property_fields(in_object_properties - count); } @@ -4012,7 +4143,7 @@ MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) { InitializeJSObjectFromMap(JSObject::cast(obj), FixedArray::cast(properties), map); - ASSERT(JSObject::cast(obj)->HasFastSmiOrObjectElements()); + ASSERT(JSObject::cast(obj)->HasFastElements()); return obj; } @@ -4062,9 +4193,6 @@ MaybeObject* Heap::AllocateJSArrayAndStorage( ArrayStorageAllocationMode mode, PretenureFlag pretenure) { ASSERT(capacity >= length); - if (length != 0 && mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE) { - elements_kind = GetHoleyElementsKind(elements_kind); - } MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure); JSArray* array; if (!maybe_array->To(&array)) return maybe_array; @@ -4077,7 +4205,7 @@ MaybeObject* Heap::AllocateJSArrayAndStorage( FixedArrayBase* elms; MaybeObject* maybe_elms = NULL; - if (elements_kind == FAST_DOUBLE_ELEMENTS) { + if (IsFastDoubleElementsKind(elements_kind)) { if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) { maybe_elms = AllocateUninitializedFixedDoubleArray(capacity); } else { @@ -4104,13 +4232,14 @@ MaybeObject* Heap::AllocateJSArrayAndStorage( MaybeObject* Heap::AllocateJSArrayWithElements( FixedArrayBase* elements, ElementsKind elements_kind, + int length, PretenureFlag pretenure) { MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure); JSArray* array; if (!maybe_array->To(&array)) return maybe_array; array->set_elements(elements); - array->set_length(Smi::FromInt(elements->length())); + array->set_length(Smi::FromInt(length)); array->ValidateElements(); return array; } @@ -4186,7 +4315,7 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) { StringDictionary* dictionary; MaybeObject* maybe_dictionary = StringDictionary::Allocate( - map->NumberOfDescribedProperties() * 2 + initial_size); + map->NumberOfOwnDescriptors() * 2 + initial_size); if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; // The global object might be created from an object template with accessors. @@ -4388,34 +4517,33 @@ MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor, } -MaybeObject* Heap::AllocateStringFromAscii(Vector<const char> string, +MaybeObject* Heap::AllocateStringFromOneByte(Vector<const char> string, PretenureFlag pretenure) { - if (string.length() == 1) { + int length = string.length(); + if (length == 1) { return Heap::LookupSingleCharacterStringFromCode(string[0]); } Object* result; { MaybeObject* maybe_result = - AllocateRawAsciiString(string.length(), pretenure); + AllocateRawOneByteString(string.length(), pretenure); if (!maybe_result->ToObject(&result)) return maybe_result; } // Copy the characters into the new object. - SeqAsciiString* string_result = SeqAsciiString::cast(result); - for (int i = 0; i < string.length(); i++) { - string_result->SeqAsciiStringSet(i, string[i]); - } + CopyChars(SeqOneByteString::cast(result)->GetChars(), string.start(), length); return result; } MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string, + int non_ascii_start, PretenureFlag pretenure) { - // Count the number of characters in the UTF-8 string and check if - // it is an ASCII string. + // Continue counting the number of characters in the UTF-8 string, starting + // from the first non-ascii character or word. + int chars = non_ascii_start; Access<UnicodeCache::Utf8Decoder> decoder(isolate_->unicode_cache()->utf8_decoder()); - decoder->Reset(string.start(), string.length()); - int chars = 0; + decoder->Reset(string.start() + non_ascii_start, string.length() - chars); while (decoder->has_more()) { uint32_t r = decoder->GetNext(); if (r <= unibrow::Utf16::kMaxNonSurrogateCharCode) { @@ -4431,16 +4559,16 @@ MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string, } // Convert and copy the characters into the new object. - String* string_result = String::cast(result); + SeqTwoByteString* twobyte = SeqTwoByteString::cast(result); decoder->Reset(string.start(), string.length()); int i = 0; while (i < chars) { uint32_t r = decoder->GetNext(); if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) { - string_result->Set(i++, unibrow::Utf16::LeadSurrogate(r)); - string_result->Set(i++, unibrow::Utf16::TrailSurrogate(r)); + twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::LeadSurrogate(r)); + twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::TrailSurrogate(r)); } else { - string_result->Set(i++, r); + twobyte->SeqTwoByteStringSet(i++, r); } } return result; @@ -4450,20 +4578,18 @@ MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string, MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string, PretenureFlag pretenure) { // Check if the string is an ASCII string. - MaybeObject* maybe_result; - if (String::IsAscii(string.start(), string.length())) { - maybe_result = AllocateRawAsciiString(string.length(), pretenure); - } else { // It's not an ASCII string. - maybe_result = AllocateRawTwoByteString(string.length(), pretenure); - } Object* result; - if (!maybe_result->ToObject(&result)) return maybe_result; + int length = string.length(); + const uc16* start = string.start(); - // Copy the characters into the new object, which may be either ASCII or - // UTF-16. - String* string_result = String::cast(result); - for (int i = 0; i < string.length(); i++) { - string_result->Set(i, string[i]); + if (String::IsAscii(start, length)) { + MaybeObject* maybe_result = AllocateRawOneByteString(length, pretenure); + if (!maybe_result->ToObject(&result)) return maybe_result; + CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length); + } else { // It's not an ASCII string. + MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure); + if (!maybe_result->ToObject(&result)) return maybe_result; + CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length); } return result; } @@ -4514,11 +4640,11 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, Map* map; if (is_ascii) { - if (chars > SeqAsciiString::kMaxLength) { + if (chars > SeqOneByteString::kMaxLength) { return Failure::OutOfMemoryException(); } map = ascii_symbol_map(); - size = SeqAsciiString::SizeFor(chars); + size = SeqOneByteString::SizeFor(chars); } else { if (chars > SeqTwoByteString::kMaxLength) { return Failure::OutOfMemoryException(); @@ -4558,13 +4684,14 @@ MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, } -MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { - if (length < 0 || length > SeqAsciiString::kMaxLength) { +MaybeObject* Heap::AllocateRawOneByteString(int length, + PretenureFlag pretenure) { + if (length < 0 || length > SeqOneByteString::kMaxLength) { return Failure::OutOfMemoryException(); } - int size = SeqAsciiString::SizeFor(length); - ASSERT(size <= SeqAsciiString::kMaxSize); + int size = SeqOneByteString::SizeFor(length); + ASSERT(size <= SeqOneByteString::kMaxSize); AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; AllocationSpace retry_space = OLD_DATA_SPACE; @@ -4592,14 +4719,14 @@ MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { String::cast(result)->set_hash_field(String::kEmptyHashField); ASSERT_EQ(size, HeapObject::cast(result)->Size()); -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { // Initialize string's content to ensure ASCII-ness (character range 0-127) // as required when verifying the heap. - char* dest = SeqAsciiString::cast(result)->GetChars(); + char* dest = SeqOneByteString::cast(result)->GetChars(); memset(dest, 0x0F, length * kCharSize); } -#endif // DEBUG +#endif return result; } @@ -4972,7 +5099,7 @@ MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) { } Context* context = reinterpret_cast<Context*>(result); context->set_map_no_write_barrier(module_context_map()); - // Context links will be set later. + // Instance link will be set later. context->set_extension(Smi::FromInt(0)); return context; } @@ -5059,6 +5186,20 @@ MaybeObject* Heap::AllocateScopeInfo(int length) { } +MaybeObject* Heap::AllocateExternal(void* value) { + Foreign* foreign; + { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value)); + if (!maybe_result->To(&foreign)) return maybe_result; + } + JSObject* external; + { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map()); + if (!maybe_result->To(&external)) return maybe_result; + } + external->SetInternalField(0, foreign); + return external; +} + + MaybeObject* Heap::AllocateStruct(InstanceType type) { Map* map; switch (type) { @@ -5128,7 +5269,8 @@ bool Heap::IdleNotification(int hint) { // 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; + intptr_t step_size = + size_factor * IncrementalMarking::kAllocatedThreshold; if (contexts_disposed_ > 0) { if (hint >= kMaxHint) { @@ -5147,10 +5289,6 @@ bool Heap::IdleNotification(int hint) { AdvanceIdleIncrementalMarking(step_size); contexts_disposed_ = 0; } - // Make sure that we have no pending context disposals. - // 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. @@ -5388,9 +5526,9 @@ bool Heap::InSpace(Address addr, AllocationSpace space) { } -#ifdef DEBUG +#ifdef VERIFY_HEAP void Heap::Verify() { - ASSERT(HasBeenSetUp()); + CHECK(HasBeenSetUp()); store_buffer()->Verify(); @@ -5409,9 +5547,7 @@ void Heap::Verify() { lo_space_->Verify(); } - - -#endif // DEBUG +#endif MaybeObject* Heap::LookupSymbol(Vector<const char> string) { @@ -5444,7 +5580,7 @@ MaybeObject* Heap::LookupAsciiSymbol(Vector<const char> string) { } -MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqAsciiString> string, +MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqOneByteString> string, int from, int length) { Object* symbol = NULL; @@ -5504,7 +5640,6 @@ bool Heap::LookupSymbolIfExists(String* string, String** symbol) { } -#ifdef DEBUG void Heap::ZapFromSpace() { NewSpacePageIterator it(new_space_.FromSpaceStart(), new_space_.FromSpaceEnd()); @@ -5517,7 +5652,6 @@ void Heap::ZapFromSpace() { } } } -#endif // DEBUG void Heap::IterateAndMarkPointersToFromSpace(Address start, @@ -5947,172 +6081,6 @@ intptr_t Heap::PromotedExternalMemorySize() { - amount_of_external_allocated_memory_at_last_global_gc_; } -#ifdef DEBUG - -// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject. -static const int kMarkTag = 2; - - -class HeapDebugUtils { - public: - explicit HeapDebugUtils(Heap* heap) - : search_for_any_global_(false), - search_target_(NULL), - found_target_(false), - object_stack_(20), - heap_(heap) { - } - - class MarkObjectVisitor : public ObjectVisitor { - public: - explicit MarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { } - - void VisitPointers(Object** start, Object** end) { - // Copy all HeapObject pointers in [start, end) - for (Object** p = start; p < end; p++) { - if ((*p)->IsHeapObject()) - utils_->MarkObjectRecursively(p); - } - } - - HeapDebugUtils* utils_; - }; - - void MarkObjectRecursively(Object** p) { - if (!(*p)->IsHeapObject()) return; - - HeapObject* obj = HeapObject::cast(*p); - - Object* map = obj->map(); - - if (!map->IsHeapObject()) return; // visited before - - if (found_target_) return; // stop if target found - object_stack_.Add(obj); - if ((search_for_any_global_ && obj->IsJSGlobalObject()) || - (!search_for_any_global_ && (obj == search_target_))) { - found_target_ = true; - return; - } - - // not visited yet - Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); - - Address map_addr = map_p->address(); - - obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag)); - - MarkObjectRecursively(&map); - - MarkObjectVisitor mark_visitor(this); - - obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p), - &mark_visitor); - - if (!found_target_) // don't pop if found the target - object_stack_.RemoveLast(); - } - - - class UnmarkObjectVisitor : public ObjectVisitor { - public: - explicit UnmarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { } - - void VisitPointers(Object** start, Object** end) { - // Copy all HeapObject pointers in [start, end) - for (Object** p = start; p < end; p++) { - if ((*p)->IsHeapObject()) - utils_->UnmarkObjectRecursively(p); - } - } - - HeapDebugUtils* utils_; - }; - - - void UnmarkObjectRecursively(Object** p) { - if (!(*p)->IsHeapObject()) return; - - HeapObject* obj = HeapObject::cast(*p); - - Object* map = obj->map(); - - if (map->IsHeapObject()) return; // unmarked already - - Address map_addr = reinterpret_cast<Address>(map); - - map_addr -= kMarkTag; - - ASSERT_TAG_ALIGNED(map_addr); - - HeapObject* map_p = HeapObject::FromAddress(map_addr); - - obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p)); - - UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p)); - - UnmarkObjectVisitor unmark_visitor(this); - - obj->IterateBody(Map::cast(map_p)->instance_type(), - obj->SizeFromMap(Map::cast(map_p)), - &unmark_visitor); - } - - - void MarkRootObjectRecursively(Object** root) { - if (search_for_any_global_) { - ASSERT(search_target_ == NULL); - } else { - ASSERT(search_target_->IsHeapObject()); - } - found_target_ = false; - object_stack_.Clear(); - - MarkObjectRecursively(root); - UnmarkObjectRecursively(root); - - if (found_target_) { - PrintF("=====================================\n"); - PrintF("==== Path to object ====\n"); - PrintF("=====================================\n\n"); - - ASSERT(!object_stack_.is_empty()); - for (int i = 0; i < object_stack_.length(); i++) { - if (i > 0) PrintF("\n |\n |\n V\n\n"); - Object* obj = object_stack_[i]; - obj->Print(); - } - PrintF("=====================================\n"); - } - } - - // Helper class for visiting HeapObjects recursively. - class MarkRootVisitor: public ObjectVisitor { - public: - explicit MarkRootVisitor(HeapDebugUtils* utils) : utils_(utils) { } - - void VisitPointers(Object** start, Object** end) { - // Visit all HeapObject pointers in [start, end) - for (Object** p = start; p < end; p++) { - if ((*p)->IsHeapObject()) - utils_->MarkRootObjectRecursively(p); - } - } - - HeapDebugUtils* utils_; - }; - - bool search_for_any_global_; - Object* search_target_; - bool found_target_; - List<Object*> object_stack_; - Heap* heap_; - - friend class Heap; -}; - -#endif - V8_DECLARE_ONCE(initialize_gc_once); @@ -6125,7 +6093,6 @@ static void InitializeGCOnce() { bool Heap::SetUp(bool create_heap_objects) { #ifdef DEBUG allocation_timeout_ = FLAG_gc_interval; - debug_utils_ = new HeapDebugUtils(this); #endif // Initialize heap spaces and initial maps and objects. Whenever something @@ -6254,11 +6221,12 @@ void Heap::SetStackLimits() { void Heap::TearDown() { -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { Verify(); } #endif + if (FLAG_print_cumulative_gc_stat) { PrintF("\n\n"); PrintF("gc_count=%d ", gc_count_); @@ -6319,11 +6287,6 @@ void Heap::TearDown() { isolate_->memory_allocator()->TearDown(); delete relocation_mutex_; - -#ifdef DEBUG - delete debug_utils_; - debug_utils_ = NULL; -#endif } @@ -6902,6 +6865,9 @@ GCTracer::GCTracer(Heap* heap, allocated_since_last_gc_(0), spent_in_mutator_(0), promoted_objects_size_(0), + nodes_died_in_new_space_(0), + nodes_copied_in_new_space_(0), + nodes_promoted_(0), heap_(heap), gc_reason_(gc_reason), collector_reason_(collector_reason) { @@ -7042,6 +7008,9 @@ GCTracer::~GCTracer() { PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_); + PrintF("nodes_died_in_new=%d ", nodes_died_in_new_space_); + PrintF("nodes_copied_in_new=%d ", nodes_copied_in_new_space_); + PrintF("nodes_promoted=%d ", nodes_promoted_); if (collector_ == SCAVENGER) { PrintF("stepscount=%d ", steps_count_since_last_gc_); @@ -7049,6 +7018,7 @@ GCTracer::~GCTracer() { } else { PrintF("stepscount=%d ", steps_count_); PrintF("stepstook=%d ", static_cast<int>(steps_took_)); + PrintF("longeststep=%.f ", longest_step_); } PrintF("\n"); @@ -7129,7 +7099,7 @@ void KeyedLookupCache::Clear() { void DescriptorLookupCache::Clear() { - for (int index = 0; index < kLength; index++) keys_[index].array = NULL; + for (int index = 0; index < kLength; index++) keys_[index].source = NULL; } @@ -7169,7 +7139,7 @@ void TranscendentalCache::Clear() { void ExternalStringTable::CleanUp() { int last = 0; for (int i = 0; i < new_space_strings_.length(); ++i) { - if (new_space_strings_[i] == heap_->raw_unchecked_the_hole_value()) { + if (new_space_strings_[i] == heap_->the_hole_value()) { continue; } if (heap_->InNewSpace(new_space_strings_[i])) { @@ -7181,16 +7151,18 @@ void ExternalStringTable::CleanUp() { new_space_strings_.Rewind(last); last = 0; for (int i = 0; i < old_space_strings_.length(); ++i) { - if (old_space_strings_[i] == heap_->raw_unchecked_the_hole_value()) { + if (old_space_strings_[i] == heap_->the_hole_value()) { continue; } ASSERT(!heap_->InNewSpace(old_space_strings_[i])); old_space_strings_[last++] = old_space_strings_[i]; } old_space_strings_.Rewind(last); +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { Verify(); } +#endif } diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index cb167d30aa..72035cadcf 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -154,7 +154,9 @@ namespace internal { V(Smi, arguments_adaptor_deopt_pc_offset, ArgumentsAdaptorDeoptPCOffset) \ V(Smi, construct_stub_deopt_pc_offset, ConstructStubDeoptPCOffset) \ V(Smi, getter_stub_deopt_pc_offset, GetterStubDeoptPCOffset) \ - V(Smi, setter_stub_deopt_pc_offset, SetterStubDeoptPCOffset) + V(Smi, setter_stub_deopt_pc_offset, SetterStubDeoptPCOffset) \ + V(JSObject, observation_state, ObservationState) \ + V(Map, external_map, ExternalMap) #define ROOT_LIST(V) \ STRONG_ROOT_LIST(V) \ @@ -176,6 +178,7 @@ namespace internal { V(constructor_symbol, "constructor") \ V(code_symbol, ".code") \ V(result_symbol, ".result") \ + V(dot_for_symbol, ".for.") \ V(catch_var_symbol, ".catch-var") \ V(empty_symbol, "") \ V(eval_symbol, "eval") \ @@ -283,14 +286,6 @@ class StoreBufferRebuilder { -// The all static Heap captures the interface to the global object heap. -// All JavaScript contexts by this process share the same object heap. - -#ifdef DEBUG -class HeapDebugUtils; -#endif - - // A queue of objects promoted during scavenge. Each object is accompanied // by it's size to avoid dereferencing a map pointer for scanning. class PromotionQueue { @@ -486,6 +481,9 @@ class Heap { // Returns the amount of executable memory currently committed for the heap. intptr_t CommittedMemoryExecutable(); + // Returns the amount of phyical memory currently committed for the heap. + size_t CommittedPhysicalMemory(); + // Returns the available bytes in space w/o growing. // Heap doesn't guarantee that it can allocate an object that requires // all available bytes. Check MaxHeapObjectSize() instead. @@ -508,6 +506,24 @@ class Heap { MapSpace* map_space() { return map_space_; } CellSpace* cell_space() { return cell_space_; } LargeObjectSpace* lo_space() { return lo_space_; } + PagedSpace* paged_space(int idx) { + switch (idx) { + case OLD_POINTER_SPACE: + return old_pointer_space(); + case OLD_DATA_SPACE: + return old_data_space(); + case MAP_SPACE: + return map_space(); + case CELL_SPACE: + return cell_space(); + case CODE_SPACE: + return code_space(); + case NEW_SPACE: + case LO_SPACE: + UNREACHABLE(); + } + return NULL; + } bool always_allocate() { return always_allocate_scope_depth_ != 0; } Address always_allocate_scope_depth_address() { @@ -560,6 +576,7 @@ class Heap { MUST_USE_RESULT MaybeObject* AllocateJSArrayWithElements( FixedArrayBase* array_base, ElementsKind elements_kind, + int length, PretenureFlag pretenure = NOT_TENURED); // Allocates and initializes a new global object based on a constructor. @@ -642,6 +659,9 @@ class Heap { // Allocates a serialized scope info. MUST_USE_RESULT MaybeObject* AllocateScopeInfo(int length); + // Allocates an External object for v8's external API. + MUST_USE_RESULT MaybeObject* AllocateExternal(void* value); + // Allocates an empty PolymorphicCodeCache. MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache(); @@ -657,6 +677,9 @@ class Heap { // Clear the Instanceof cache (used when a prototype changes). inline void ClearInstanceofCache(); + // For use during bootup. + void RepairFreeListsAfterBoot(); + // Allocates and fully initializes a String. There are two String // encodings: ASCII and two byte. One should choose between the three string // allocation functions based on the encoding of the string buffer used to @@ -675,7 +698,7 @@ class Heap { // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // failed. // Please note this does not perform a garbage collection. - MUST_USE_RESULT MaybeObject* AllocateStringFromAscii( + MUST_USE_RESULT MaybeObject* AllocateStringFromOneByte( Vector<const char> str, PretenureFlag pretenure = NOT_TENURED); MUST_USE_RESULT inline MaybeObject* AllocateStringFromUtf8( @@ -683,6 +706,7 @@ class Heap { PretenureFlag pretenure = NOT_TENURED); MUST_USE_RESULT MaybeObject* AllocateStringFromUtf8Slow( Vector<const char> str, + int non_ascii_start, PretenureFlag pretenure = NOT_TENURED); MUST_USE_RESULT MaybeObject* AllocateStringFromTwoByte( Vector<const uc16> str, @@ -718,7 +742,7 @@ class Heap { // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // failed. // Please note this does not perform a garbage collection. - MUST_USE_RESULT MaybeObject* AllocateRawAsciiString( + MUST_USE_RESULT MaybeObject* AllocateRawOneByteString( int length, PretenureFlag pretenure = NOT_TENURED); MUST_USE_RESULT MaybeObject* AllocateRawTwoByteString( @@ -1013,9 +1037,8 @@ class Heap { return LookupSymbol(CStrVector(str)); } MUST_USE_RESULT MaybeObject* LookupSymbol(String* str); - MUST_USE_RESULT MaybeObject* LookupAsciiSymbol(Handle<SeqAsciiString> string, - int from, - int length); + MUST_USE_RESULT MaybeObject* LookupAsciiSymbol( + Handle<SeqOneByteString> string, int from, int length); bool LookupSymbolIfExists(String* str, String** symbol); bool LookupTwoCharsSymbolIfExists(String* str, String** symbol); @@ -1081,7 +1104,10 @@ class Heap { void EnsureHeapIsIterable(); // Notify the heap that a context has been disposed. - int NotifyContextDisposed() { return ++contexts_disposed_; } + int NotifyContextDisposed() { + flush_monomorphic_ics_ = true; + return ++contexts_disposed_; + } // Utility to invoke the scavenger. This is needed in test code to // ensure correct callback for weak global handles. @@ -1239,13 +1265,15 @@ class Heap { return &native_contexts_list_; } +#ifdef VERIFY_HEAP + // Verify the heap is in its normal state before or after a GC. + void Verify(); +#endif + #ifdef DEBUG void Print(); void PrintHandles(); - // Verify the heap is in its normal state before or after a GC. - void Verify(); - void OldPointerSpaceCheckStoreBuffer(); void MapSpaceCheckStoreBuffer(); void LargeObjectSpaceCheckStoreBuffer(); @@ -1253,10 +1281,23 @@ class Heap { // Report heap statistics. void ReportHeapStatistics(const char* title); void ReportCodeStatistics(const char* title); +#endif + + // Zapping is needed for verify heap, and always done in debug builds. + static inline bool ShouldZapGarbage() { +#ifdef DEBUG + return true; +#else +#ifdef VERIFY_HEAP + return FLAG_verify_heap; +#else + return false; +#endif +#endif + } // Fill in bogus values in from space void ZapFromSpace(); -#endif // Print short heap statistics. void PrintShortHeapStatistics(); @@ -1309,20 +1350,9 @@ class Heap { // Commits from space if it is uncommitted. void EnsureFromSpaceIsCommitted(); - // Support for partial snapshots. After calling this we can allocate a - // certain number of bytes using only linear allocation (with a - // LinearAllocationScope and an AlwaysAllocateScope) without using freelists - // or causing a GC. It returns true of space was reserved or false if a GC is - // needed. For paged spaces the space requested must include the space wasted - // at the end of each page when allocating linearly. - void ReserveSpace( - int new_space_size, - int pointer_space_size, - int data_space_size, - int code_space_size, - int map_space_size, - int cell_space_size, - int large_object_size); + // Support for partial snapshots. After calling this we have a linear + // space to write objects in each space. + void ReserveSpace(int *sizes, Address* addresses); // // Support for the API. @@ -1418,6 +1448,10 @@ class Heap { STATIC_CHECK(kFalseValueRootIndex == Internals::kFalseValueRootIndex); STATIC_CHECK(kempty_symbolRootIndex == Internals::kEmptySymbolRootIndex); + // Generated code can embed direct references to non-writable roots if + // they are in new space. + static bool RootCanBeWrittenAfterInitialization(RootListIndex root_index); + MUST_USE_RESULT MaybeObject* NumberToString( Object* number, bool check_number_string_cache = true); MUST_USE_RESULT MaybeObject* Uint32ToString( @@ -1489,13 +1523,6 @@ class Heap { void ClearNormalizedMapCaches(); - // Clears the cache of ICs related to this map. - void ClearCacheOnMap(Map* map) { - if (FLAG_cleanup_code_caches_at_gc) { - map->ClearCodeCache(this); - } - } - GCTracer* tracer() { return tracer_; } // Returns the size of objects residing in non new spaces. @@ -1616,6 +1643,8 @@ class Heap { global_ic_age_ = (global_ic_age_ + 1) & SharedFunctionInfo::ICAgeBits::kMax; } + bool flush_monomorphic_ics() { return flush_monomorphic_ics_; } + intptr_t amount_of_external_allocated_memory() { return amount_of_external_allocated_memory_; } @@ -1701,6 +1730,8 @@ class Heap { int global_ic_age_; + bool flush_monomorphic_ics_; + int scan_on_scavenge_pages_; #if defined(V8_TARGET_ARCH_X64) @@ -1754,8 +1785,6 @@ class Heap { // Do we expect to be able to handle allocation failure at this // time? bool disallow_allocation_failure_; - - HeapDebugUtils* debug_utils_; #endif // DEBUG // Indicates that the new space should be kept small due to high promotion @@ -1872,7 +1901,6 @@ class Heap { bool PerformGarbageCollection(GarbageCollector collector, GCTracer* tracer); - inline void UpdateOldSpaceLimits(); // Allocate an uninitialized object in map space. The behavior is identical @@ -1899,9 +1927,9 @@ class Heap { void CreateFixedStubs(); - MaybeObject* CreateOddball(const char* to_string, - Object* to_number, - byte kind); + MUST_USE_RESULT MaybeObject* CreateOddball(const char* to_string, + Object* to_number, + byte kind); // Allocate a JSArray with no elements MUST_USE_RESULT MaybeObject* AllocateJSArray( @@ -2131,7 +2159,6 @@ class Heap { friend class GCTracer; friend class DisallowAllocationFailure; friend class AlwaysAllocateScope; - friend class LinearAllocationScope; friend class Page; friend class Isolate; friend class MarkCompactCollector; @@ -2198,14 +2225,6 @@ class AlwaysAllocateScope { }; -class LinearAllocationScope { - public: - inline LinearAllocationScope(); - inline ~LinearAllocationScope(); -}; - - -#ifdef DEBUG // Visitor class to verify interior pointers in spaces that do not contain // or care about intergenerational references. All heap object pointers have to // point into the heap to a location that has a map pointer at its first word. @@ -2215,7 +2234,6 @@ class VerifyPointersVisitor: public ObjectVisitor { public: inline void VisitPointers(Object** start, Object** end); }; -#endif // Space iterator for iterating over all spaces of the heap. @@ -2374,7 +2392,7 @@ class KeyedLookupCache { }; -// Cache for mapping (array, property name) into descriptor index. +// Cache for mapping (map, property name) into descriptor index. // The cache contains both positive and negative results. // Descriptor index equals kNotFound means the property is absent. // Cleared at startup and prior to any gc. @@ -2382,21 +2400,21 @@ class DescriptorLookupCache { public: // Lookup descriptor index for (map, name). // If absent, kAbsent is returned. - int Lookup(DescriptorArray* array, String* name) { + int Lookup(Map* source, String* name) { if (!StringShape(name).IsSymbol()) return kAbsent; - int index = Hash(array, name); + int index = Hash(source, name); Key& key = keys_[index]; - if ((key.array == array) && (key.name == name)) return results_[index]; + if ((key.source == source) && (key.name == name)) return results_[index]; return kAbsent; } // Update an element in the cache. - void Update(DescriptorArray* array, String* name, int result) { + void Update(Map* source, String* name, int result) { ASSERT(result != kAbsent); if (StringShape(name).IsSymbol()) { - int index = Hash(array, name); + int index = Hash(source, name); Key& key = keys_[index]; - key.array = array; + key.source = source; key.name = name; results_[index] = result; } @@ -2410,26 +2428,26 @@ class DescriptorLookupCache { private: DescriptorLookupCache() { for (int i = 0; i < kLength; ++i) { - keys_[i].array = NULL; + keys_[i].source = NULL; keys_[i].name = NULL; results_[i] = kAbsent; } } - static int Hash(DescriptorArray* array, String* name) { + static int Hash(Object* source, String* name) { // Uses only lower 32 bits if pointers are larger. - uint32_t array_hash = - static_cast<uint32_t>(reinterpret_cast<uintptr_t>(array)) + uint32_t source_hash = + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(source)) >> kPointerSizeLog2; uint32_t name_hash = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)) >> kPointerSizeLog2; - return (array_hash ^ name_hash) % kLength; + return (source_hash ^ name_hash) % kLength; } static const int kLength = 64; struct Key { - DescriptorArray* array; + Map* source; String* name; }; @@ -2531,6 +2549,18 @@ class GCTracer BASE_EMBEDDED { promoted_objects_size_ += object_size; } + void increment_nodes_died_in_new_space() { + nodes_died_in_new_space_++; + } + + void increment_nodes_copied_in_new_space() { + nodes_copied_in_new_space_++; + } + + void increment_nodes_promoted() { + nodes_promoted_++; + } + private: // Returns a string matching the collector. const char* CollectorString(); @@ -2575,6 +2605,15 @@ class GCTracer BASE_EMBEDDED { // Size of objects promoted during the current collection. intptr_t promoted_objects_size_; + // Number of died nodes in the new space. + int nodes_died_in_new_space_; + + // Number of copied nodes to the new space. + int nodes_copied_in_new_space_; + + // Number of promoted nodes to the old space. + int nodes_promoted_; + // Incremental marking steps counters. int steps_count_; double steps_took_; diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index 0192a763f0..0e6ea00058 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/deps/v8/src/hydrogen-instructions.cc @@ -85,6 +85,81 @@ void HValue::AssumeRepresentation(Representation r) { } +void HValue::InferRepresentation(HInferRepresentation* h_infer) { + ASSERT(CheckFlag(kFlexibleRepresentation)); + Representation new_rep = RepresentationFromInputs(); + UpdateRepresentation(new_rep, h_infer, "inputs"); + new_rep = RepresentationFromUses(); + UpdateRepresentation(new_rep, h_infer, "uses"); +} + + +Representation HValue::RepresentationFromUses() { + if (HasNoUses()) return Representation::None(); + + // Array of use counts for each representation. + int use_count[Representation::kNumRepresentations] = { 0 }; + + for (HUseIterator it(uses()); !it.Done(); it.Advance()) { + HValue* use = it.value(); + Representation rep = use->observed_input_representation(it.index()); + if (rep.IsNone()) continue; + if (FLAG_trace_representation) { + PrintF("#%d %s is used by #%d %s as %s%s\n", + id(), Mnemonic(), use->id(), use->Mnemonic(), rep.Mnemonic(), + (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : "")); + } + use_count[rep.kind()] += use->LoopWeight(); + } + if (IsPhi()) HPhi::cast(this)->AddIndirectUsesTo(&use_count[0]); + int tagged_count = use_count[Representation::kTagged]; + int double_count = use_count[Representation::kDouble]; + int int32_count = use_count[Representation::kInteger32]; + + if (tagged_count > 0) return Representation::Tagged(); + if (double_count > 0) return Representation::Double(); + if (int32_count > 0) return Representation::Integer32(); + + return Representation::None(); +} + + +void HValue::UpdateRepresentation(Representation new_rep, + HInferRepresentation* h_infer, + const char* reason) { + Representation r = representation(); + if (new_rep.is_more_general_than(r)) { + // When an HConstant is marked "not convertible to integer", then + // never try to represent it as an integer. + if (new_rep.IsInteger32() && !IsConvertibleToInteger()) { + new_rep = Representation::Tagged(); + if (FLAG_trace_representation) { + PrintF("Changing #%d %s representation %s -> %s because it's NCTI" + " (%s want i)\n", + id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason); + } + } else { + if (FLAG_trace_representation) { + PrintF("Changing #%d %s representation %s -> %s based on %s\n", + id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason); + } + } + ChangeRepresentation(new_rep); + AddDependantsToWorklist(h_infer); + } +} + + +void HValue::AddDependantsToWorklist(HInferRepresentation* h_infer) { + for (HUseIterator it(uses()); !it.Done(); it.Advance()) { + h_infer->AddToWorklist(it.value()); + } + for (int i = 0; i < OperandCount(); ++i) { + h_infer->AddToWorklist(OperandAt(i)); + } +} + + static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) { if (result > kMaxInt) { *overflow = true; @@ -301,6 +376,7 @@ HUseListNode* HUseListNode::tail() { bool HValue::CheckUsesForFlag(Flag f) { for (HUseIterator it(uses()); !it.Done(); it.Advance()) { + if (it.value()->IsSimulate()) continue; if (!it.value()->CheckFlag(f)) return false; } return true; @@ -707,7 +783,7 @@ void HCallGlobal::PrintDataTo(StringStream* stream) { void HCallKnownGlobal::PrintDataTo(StringStream* stream) { - stream->Add("o ", target()->shared()->DebugName()); + stream->Add("%o ", target()->shared()->DebugName()); stream->Add("#%d", argument_count()); } @@ -764,6 +840,24 @@ void HReturn::PrintDataTo(StringStream* stream) { } +Representation HBranch::observed_input_representation(int index) { + static const ToBooleanStub::Types tagged_types( + ToBooleanStub::UNDEFINED | + ToBooleanStub::NULL_TYPE | + ToBooleanStub::SPEC_OBJECT | + ToBooleanStub::STRING); + if (expected_input_types_.ContainsAnyOf(tagged_types)) { + return Representation::Tagged(); + } else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) { + return Representation::Double(); + } else if (expected_input_types_.Contains(ToBooleanStub::SMI)) { + return Representation::Integer32(); + } else { + return Representation::None(); + } +} + + void HCompareMap::PrintDataTo(StringStream* stream) { value()->PrintNameTo(stream); stream->Add(" (%p)", *map()); @@ -859,16 +953,6 @@ void HLoadFieldByIndex::PrintDataTo(StringStream* stream) { } -HValue* HConstant::Canonicalize() { - return HasNoUses() ? NULL : this; -} - - -HValue* HTypeof::Canonicalize() { - return HasNoUses() ? NULL : this; -} - - HValue* HBitwise::Canonicalize() { if (!representation().IsInteger32()) return this; // If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x. @@ -1058,6 +1142,13 @@ void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) { } +void HLoadElements::PrintDataTo(StringStream* stream) { + value()->PrintNameTo(stream); + stream->Add(" "); + typecheck()->PrintNameTo(stream); +} + + void HCheckMaps::PrintDataTo(StringStream* stream) { value()->PrintNameTo(stream); stream->Add(" [%p", *map_set()->first()); @@ -1342,15 +1433,11 @@ void HPhi::InitRealUses(int phi_id) { for (HUseIterator it(uses()); !it.Done(); it.Advance()) { HValue* value = it.value(); if (!value->IsPhi()) { - Representation rep = value->ObservedInputRepresentation(it.index()); + Representation rep = value->observed_input_representation(it.index()); non_phi_uses_[rep.kind()] += value->LoopWeight(); if (FLAG_trace_representation) { - PrintF("%d %s is used by %d %s as %s\n", - this->id(), - this->Mnemonic(), - value->id(), - value->Mnemonic(), - rep.Mnemonic()); + PrintF("#%d Phi is used by real #%d %s as %s\n", + id(), value->id(), value->Mnemonic(), rep.Mnemonic()); } } } @@ -1359,11 +1446,8 @@ void HPhi::InitRealUses(int phi_id) { void HPhi::AddNonPhiUsesFrom(HPhi* other) { if (FLAG_trace_representation) { - PrintF("adding to %d %s uses of %d %s: i%d d%d t%d\n", - this->id(), - this->Mnemonic(), - other->id(), - other->Mnemonic(), + PrintF("adding to #%d Phi uses of #%d Phi: i%d d%d t%d\n", + id(), other->id(), other->non_phi_uses_[Representation::kInteger32], other->non_phi_uses_[Representation::kDouble], other->non_phi_uses_[Representation::kTagged]); @@ -1382,9 +1466,20 @@ void HPhi::AddIndirectUsesTo(int* dest) { } -void HPhi::ResetInteger32Uses() { - non_phi_uses_[Representation::kInteger32] = 0; - indirect_uses_[Representation::kInteger32] = 0; +void HSimulate::MergeInto(HSimulate* other) { + for (int i = 0; i < values_.length(); ++i) { + HValue* value = values_[i]; + if (HasAssignedIndexAt(i)) { + other->AddAssignedValue(GetAssignedIndexAt(i), value); + } else { + if (other->pop_count_ > 0) { + other->pop_count_--; + } else { + other->AddPushedValue(value); + } + } + } + other->pop_count_ += pop_count(); } @@ -1393,7 +1488,7 @@ void HSimulate::PrintDataTo(StringStream* stream) { if (pop_count_ > 0) stream->Add(" pop %d", pop_count_); if (values_.length() > 0) { if (pop_count_ > 0) stream->Add(" /"); - for (int i = 0; i < values_.length(); ++i) { + for (int i = values_.length() - 1; i >= 0; --i) { if (i > 0) stream->Add(","); if (HasAssignedIndexAt(i)) { stream->Add(" var[%d] = ", GetAssignedIndexAt(i)); @@ -1432,7 +1527,6 @@ HConstant::HConstant(Handle<Object> handle, Representation r) : handle_(handle), has_int32_value_(false), has_double_value_(false) { - set_representation(r); SetFlag(kUseGVN); if (handle_->IsNumber()) { double n = handle_->Number(); @@ -1441,6 +1535,16 @@ HConstant::HConstant(Handle<Object> handle, Representation r) double_value_ = n; has_double_value_ = true; } + if (r.IsNone()) { + if (has_int32_value_) { + r = Representation::Integer32(); + } else if (has_double_value_) { + r = Representation::Double(); + } else { + r = Representation::Tagged(); + } + } + set_representation(r); } @@ -1539,6 +1643,60 @@ void HBinaryOperation::PrintDataTo(StringStream* stream) { } +void HBinaryOperation::InferRepresentation(HInferRepresentation* h_infer) { + ASSERT(CheckFlag(kFlexibleRepresentation)); + Representation new_rep = RepresentationFromInputs(); + UpdateRepresentation(new_rep, h_infer, "inputs"); + // When the operation has information about its own output type, don't look + // at uses. + if (!observed_output_representation_.IsNone()) return; + new_rep = RepresentationFromUses(); + UpdateRepresentation(new_rep, h_infer, "uses"); +} + + +Representation HBinaryOperation::RepresentationFromInputs() { + // Determine the worst case of observed input representations and + // the currently assumed output representation. + Representation rep = representation(); + if (observed_output_representation_.is_more_general_than(rep)) { + rep = observed_output_representation_; + } + for (int i = 1; i <= 2; ++i) { + Representation input_rep = observed_input_representation(i); + if (input_rep.is_more_general_than(rep)) rep = input_rep; + } + // If any of the actual input representation is more general than what we + // have so far but not Tagged, use that representation instead. + Representation left_rep = left()->representation(); + Representation right_rep = right()->representation(); + + if (left_rep.is_more_general_than(rep) && + left()->CheckFlag(kFlexibleRepresentation)) { + rep = left_rep; + } + if (right_rep.is_more_general_than(rep) && + right()->CheckFlag(kFlexibleRepresentation)) { + rep = right_rep; + } + return rep; +} + + +void HBinaryOperation::AssumeRepresentation(Representation r) { + set_observed_input_representation(r, r); + HValue::AssumeRepresentation(r); +} + + +void HMathMinMax::InferRepresentation(HInferRepresentation* h_infer) { + ASSERT(CheckFlag(kFlexibleRepresentation)); + Representation new_rep = RepresentationFromInputs(); + UpdateRepresentation(new_rep, h_infer, "inputs"); + // Do not care about uses. +} + + Range* HBitwise::InferRange(Zone* zone) { if (op() == Token::BIT_XOR) return HValue::InferRange(zone); const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff); @@ -1615,7 +1773,7 @@ Range* HShl::InferRange(Zone* zone) { } -Range* HLoadKeyedSpecializedArrayElement::InferRange(Zone* zone) { +Range* HLoadKeyed::InferRange(Zone* zone) { switch (elements_kind()) { case EXTERNAL_PIXEL_ELEMENTS: return new(zone) Range(0, 255); @@ -1670,9 +1828,19 @@ void HGoto::PrintDataTo(StringStream* stream) { } -void HCompareIDAndBranch::SetInputRepresentation(Representation r) { - input_representation_ = r; - if (r.IsDouble()) { +void HCompareIDAndBranch::InferRepresentation(HInferRepresentation* h_infer) { + Representation rep = Representation::None(); + Representation left_rep = left()->representation(); + Representation right_rep = right()->representation(); + bool observed_integers = + observed_input_representation(0).IsInteger32() && + observed_input_representation(1).IsInteger32(); + bool inputs_are_not_doubles = + !left_rep.IsDouble() && !right_rep.IsDouble(); + if (observed_integers && inputs_are_not_doubles) { + rep = Representation::Integer32(); + } else { + rep = Representation::Double(); // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, === // and !=) have special handling of undefined, e.g. undefined == undefined // is 'true'. Relational comparisons have a different semantic, first @@ -1689,9 +1857,8 @@ void HCompareIDAndBranch::SetInputRepresentation(Representation r) { if (!Token::IsOrderedRelationalCompareOp(token_)) { SetFlag(kDeoptimizeOnUndefined); } - } else { - ASSERT(r.IsInteger32()); } + ChangeRepresentation(rep); } @@ -1842,11 +2009,25 @@ void HLoadNamedGeneric::PrintDataTo(StringStream* stream) { } -void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) { - object()->PrintNameTo(stream); +void HLoadKeyed::PrintDataTo(StringStream* stream) { + if (!is_external()) { + elements()->PrintNameTo(stream); + } else { + ASSERT(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND && + elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND); + elements()->PrintNameTo(stream); + stream->Add("."); + stream->Add(ElementsKindToString(elements_kind())); + } + stream->Add("["); key()->PrintNameTo(stream); - stream->Add("] "); + if (IsDehoisted()) { + stream->Add(" + %d] ", index_offset()); + } else { + stream->Add("] "); + } + dependency()->PrintNameTo(stream); if (RequiresHoleCheck()) { stream->Add(" check_hole"); @@ -1854,29 +2035,26 @@ void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) { } -bool HLoadKeyedFastElement::RequiresHoleCheck() { +bool HLoadKeyed::RequiresHoleCheck() const { if (IsFastPackedElementsKind(elements_kind())) { return false; } + if (IsFastDoubleElementsKind(elements_kind())) { + return true; + } + for (HUseIterator it(uses()); !it.Done(); it.Advance()) { HValue* use = it.value(); - if (!use->IsChange()) return true; + if (!use->IsChange()) { + return true; + } } return false; } -void HLoadKeyedFastDoubleElement::PrintDataTo(StringStream* stream) { - elements()->PrintNameTo(stream); - stream->Add("["); - key()->PrintNameTo(stream); - stream->Add("] "); - dependency()->PrintNameTo(stream); -} - - void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) { object()->PrintNameTo(stream); stream->Add("["); @@ -1889,21 +2067,22 @@ HValue* HLoadKeyedGeneric::Canonicalize() { // Recognize generic keyed loads that use property name generated // by for-in statement as a key and rewrite them into fast property load // by index. - if (key()->IsLoadKeyedFastElement()) { - HLoadKeyedFastElement* key_load = HLoadKeyedFastElement::cast(key()); - if (key_load->object()->IsForInCacheArray()) { + if (key()->IsLoadKeyed()) { + HLoadKeyed* key_load = HLoadKeyed::cast(key()); + if (key_load->elements()->IsForInCacheArray()) { HForInCacheArray* names_cache = - HForInCacheArray::cast(key_load->object()); + HForInCacheArray::cast(key_load->elements()); if (names_cache->enumerable() == object()) { HForInCacheArray* index_cache = names_cache->index_cache(); HCheckMapValue* map_check = new(block()->zone()) HCheckMapValue(object(), names_cache->map()); - HInstruction* index = new(block()->zone()) HLoadKeyedFastElement( + HInstruction* index = new(block()->zone()) HLoadKeyed( index_cache, key_load->key(), - key_load->key()); + key_load->key(), + key_load->elements_kind()); map_check->InsertBefore(this); index->InsertBefore(this); HLoadFieldByIndex* load = new(block()->zone()) HLoadFieldByIndex( @@ -1918,56 +2097,6 @@ HValue* HLoadKeyedGeneric::Canonicalize() { } -void HLoadKeyedSpecializedArrayElement::PrintDataTo( - StringStream* stream) { - external_pointer()->PrintNameTo(stream); - stream->Add("."); - switch (elements_kind()) { - case EXTERNAL_BYTE_ELEMENTS: - stream->Add("byte"); - break; - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - stream->Add("u_byte"); - break; - case EXTERNAL_SHORT_ELEMENTS: - stream->Add("short"); - break; - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - stream->Add("u_short"); - break; - case EXTERNAL_INT_ELEMENTS: - stream->Add("int"); - break; - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - stream->Add("u_int"); - break; - case EXTERNAL_FLOAT_ELEMENTS: - stream->Add("float"); - break; - case EXTERNAL_DOUBLE_ELEMENTS: - stream->Add("double"); - break; - case EXTERNAL_PIXEL_ELEMENTS: - stream->Add("pixel"); - break; - case FAST_ELEMENTS: - case FAST_SMI_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - case DICTIONARY_ELEMENTS: - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNREACHABLE(); - break; - } - stream->Add("["); - key()->PrintNameTo(stream); - stream->Add("] "); - dependency()->PrintNameTo(stream); -} - - void HStoreNamedGeneric::PrintDataTo(StringStream* stream) { object()->PrintNameTo(stream); stream->Add("."); @@ -1994,20 +2123,25 @@ void HStoreNamedField::PrintDataTo(StringStream* stream) { } -void HStoreKeyedFastElement::PrintDataTo(StringStream* stream) { - object()->PrintNameTo(stream); - stream->Add("["); - key()->PrintNameTo(stream); - stream->Add("] = "); - value()->PrintNameTo(stream); -} - +void HStoreKeyed::PrintDataTo(StringStream* stream) { + if (!is_external()) { + elements()->PrintNameTo(stream); + } else { + elements()->PrintNameTo(stream); + stream->Add("."); + stream->Add(ElementsKindToString(elements_kind())); + ASSERT(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND && + elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND); + } -void HStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) { - elements()->PrintNameTo(stream); stream->Add("["); key()->PrintNameTo(stream); - stream->Add("] = "); + if (IsDehoisted()) { + stream->Add(" + %d] = ", index_offset()); + } else { + stream->Add("] = "); + } + value()->PrintNameTo(stream); } @@ -2021,56 +2155,6 @@ void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) { } -void HStoreKeyedSpecializedArrayElement::PrintDataTo( - StringStream* stream) { - external_pointer()->PrintNameTo(stream); - stream->Add("."); - switch (elements_kind()) { - case EXTERNAL_BYTE_ELEMENTS: - stream->Add("byte"); - break; - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - stream->Add("u_byte"); - break; - case EXTERNAL_SHORT_ELEMENTS: - stream->Add("short"); - break; - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - stream->Add("u_short"); - break; - case EXTERNAL_INT_ELEMENTS: - stream->Add("int"); - break; - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - stream->Add("u_int"); - break; - case EXTERNAL_FLOAT_ELEMENTS: - stream->Add("float"); - break; - case EXTERNAL_DOUBLE_ELEMENTS: - stream->Add("double"); - break; - case EXTERNAL_PIXEL_ELEMENTS: - stream->Add("pixel"); - break; - case FAST_SMI_ELEMENTS: - case FAST_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_HOLEY_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - case DICTIONARY_ELEMENTS: - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNREACHABLE(); - break; - } - stream->Add("["); - key()->PrintNameTo(stream); - stream->Add("] = "); - value()->PrintNameTo(stream); -} - - void HTransitionElementsKind::PrintDataTo(StringStream* stream) { object()->PrintNameTo(stream); ElementsKind from_kind = original_map()->elements_kind(); @@ -2090,7 +2174,7 @@ void HLoadGlobalCell::PrintDataTo(StringStream* stream) { } -bool HLoadGlobalCell::RequiresHoleCheck() { +bool HLoadGlobalCell::RequiresHoleCheck() const { if (details_.IsDontDelete() && !details_.IsReadOnly()) return false; for (HUseIterator it(uses()); !it.Done(); it.Advance()) { HValue* use = it.value(); @@ -2361,10 +2445,10 @@ 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() || +bool HStoreKeyed::NeedsCanonicalization() { + // If value is an integer or comes from the result of a keyed load + // then it will be a non-hole value: no need for canonicalization. + if (value()->IsLoadKeyed() || (value()->IsChange() && HChange::cast(value())->from().IsInteger32())) { return false; } @@ -2547,7 +2631,41 @@ void HBitwise::PrintDataTo(StringStream* stream) { } -Representation HPhi::InferredRepresentation() { +void HPhi::InferRepresentation(HInferRepresentation* h_infer) { + ASSERT(CheckFlag(kFlexibleRepresentation)); + // If there are non-Phi uses, and all of them have observed the same + // representation, than that's what this Phi is going to use. + Representation new_rep = RepresentationObservedByAllNonPhiUses(); + if (!new_rep.IsNone()) { + UpdateRepresentation(new_rep, h_infer, "unanimous use observations"); + return; + } + new_rep = RepresentationFromInputs(); + UpdateRepresentation(new_rep, h_infer, "inputs"); + new_rep = RepresentationFromUses(); + UpdateRepresentation(new_rep, h_infer, "uses"); + new_rep = RepresentationFromUseRequirements(); + UpdateRepresentation(new_rep, h_infer, "use requirements"); +} + + +Representation HPhi::RepresentationObservedByAllNonPhiUses() { + int non_phi_use_count = 0; + for (int i = Representation::kInteger32; + i < Representation::kNumRepresentations; ++i) { + non_phi_use_count += non_phi_uses_[i]; + } + if (non_phi_use_count <= 1) return Representation::None(); + for (int i = 0; i < Representation::kNumRepresentations; ++i) { + if (non_phi_uses_[i] == non_phi_use_count) { + return Representation::FromKind(static_cast<Representation::Kind>(i)); + } + } + return Representation::None(); +} + + +Representation HPhi::RepresentationFromInputs() { bool double_occurred = false; bool int32_occurred = false; for (int i = 0; i < OperandCount(); ++i) { @@ -2556,6 +2674,7 @@ Representation HPhi::InferredRepresentation() { HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value(); if (hint_value != NULL) { Representation hint = hint_value->representation(); + if (hint.IsTagged()) return hint; if (hint.IsDouble()) double_occurred = true; if (hint.IsInteger32()) int32_occurred = true; } @@ -2574,7 +2693,9 @@ Representation HPhi::InferredRepresentation() { return Representation::Tagged(); } } else { - return Representation::Tagged(); + if (value->IsPhi() && !IsConvertibleToInteger()) { + return Representation::Tagged(); + } } } } @@ -2587,6 +2708,37 @@ Representation HPhi::InferredRepresentation() { } +Representation HPhi::RepresentationFromUseRequirements() { + Representation all_uses_require = Representation::None(); + bool all_uses_require_the_same = true; + for (HUseIterator it(uses()); !it.Done(); it.Advance()) { + // We check for observed_input_representation elsewhere. + Representation use_rep = + it.value()->RequiredInputRepresentation(it.index()); + // No useful info from this use -> look at the next one. + if (use_rep.IsNone()) { + continue; + } + if (use_rep.Equals(all_uses_require)) { + continue; + } + // This use's representation contradicts what we've seen so far. + if (!all_uses_require.IsNone()) { + ASSERT(!use_rep.Equals(all_uses_require)); + all_uses_require_the_same = false; + break; + } + // Otherwise, initialize observed representation. + all_uses_require = use_rep; + } + if (all_uses_require_the_same) { + return all_uses_require; + } + + return Representation::None(); +} + + // Node-specific verification code is only included in debug mode. #ifdef DEBUG @@ -2625,12 +2777,6 @@ void HCheckFunction::Verify() { ASSERT(HasNoUses()); } - -void HCheckPrototypeMaps::Verify() { - HInstruction::Verify(); - ASSERT(HasNoUses()); -} - #endif } } // namespace v8::internal diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index 6c938cd4bf..161e6542d9 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -45,6 +45,7 @@ namespace internal { // Forward declarations. class HBasicBlock; class HEnvironment; +class HInferRepresentation; class HInstruction; class HLoopInformation; class HValue; @@ -53,6 +54,7 @@ class LChunkBuilder; #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \ + V(BinaryOperation) \ V(BitwiseBinaryOperation) \ V(ControlInstruction) \ V(Instruction) \ @@ -132,10 +134,8 @@ class LChunkBuilder; V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ - V(LoadKeyedFastDoubleElement) \ - V(LoadKeyedFastElement) \ + V(LoadKeyed) \ V(LoadKeyedGeneric) \ - V(LoadKeyedSpecializedArrayElement) \ V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ @@ -153,7 +153,9 @@ class LChunkBuilder; V(Random) \ V(RegExpLiteral) \ V(Return) \ + V(Ror) \ V(Sar) \ + V(SeqStringSetChar) \ V(Shl) \ V(Shr) \ V(Simulate) \ @@ -162,10 +164,8 @@ class LChunkBuilder; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ - V(StoreKeyedFastDoubleElement) \ - V(StoreKeyedFastElement) \ + V(StoreKeyed) \ V(StoreKeyedGeneric) \ - V(StoreKeyedSpecializedArrayElement) \ V(StoreNamedField) \ V(StoreNamedGeneric) \ V(StringAdd) \ @@ -310,9 +310,9 @@ class Representation { public: enum Kind { kNone, - kTagged, - kDouble, kInteger32, + kDouble, + kTagged, kExternal, kNumRepresentations }; @@ -325,10 +325,18 @@ class Representation { static Representation Double() { return Representation(kDouble); } static Representation External() { return Representation(kExternal); } + static Representation FromKind(Kind kind) { return Representation(kind); } + bool Equals(const Representation& other) { return kind_ == other.kind_; } + bool is_more_general_than(const Representation& other) { + ASSERT(kind_ != kExternal); + ASSERT(other.kind_ != kExternal); + return kind_ > other.kind_; + } + Kind kind() const { return static_cast<Kind>(kind_); } bool IsNone() const { return kind_ == kNone; } bool IsTagged() const { return kind_ == kTagged; } @@ -631,13 +639,15 @@ class HValue: public ZoneObject { virtual bool EmitAtUses() { return false; } Representation representation() const { return representation_; } void ChangeRepresentation(Representation r) { - // Representation was already set and is allowed to be changed. - ASSERT(!r.IsNone()); ASSERT(CheckFlag(kFlexibleRepresentation)); RepresentationChanged(r); representation_ = r; + if (r.IsTagged()) { + // Tagged is the bottom of the lattice, don't go any further. + ClearFlag(kFlexibleRepresentation); + } } - void AssumeRepresentation(Representation r); + virtual void AssumeRepresentation(Representation r); virtual bool IsConvertibleToInteger() const { return true; } @@ -666,7 +676,7 @@ class HValue: public ZoneObject { // Operands. virtual int OperandCount() = 0; - virtual HValue* OperandAt(int index) = 0; + virtual HValue* OperandAt(int index) const = 0; void SetOperandAt(int index, HValue* value); void DeleteAndReplaceWith(HValue* other); @@ -735,16 +745,11 @@ class HValue: public ZoneObject { void ComputeInitialRange(Zone* zone); // Representation helpers. - virtual Representation RequiredInputRepresentation(int index) = 0; - - virtual Representation InferredRepresentation() { - return representation(); - } - - // Type feedback access. - virtual Representation ObservedInputRepresentation(int index) { - return RequiredInputRepresentation(index); + virtual Representation observed_input_representation(int index) { + return Representation::None(); } + virtual Representation RequiredInputRepresentation(int index) = 0; + virtual void InferRepresentation(HInferRepresentation* h_infer); // This gives the instruction an opportunity to replace itself with an // instruction that does the same in some better way. To replace an @@ -777,6 +782,10 @@ class HValue: public ZoneObject { UNREACHABLE(); } + bool IsDead() const { + return HasNoUses() && !HasObservableSideEffects() && IsDeletable(); + } + #ifdef DEBUG virtual void Verify() = 0; #endif @@ -788,7 +797,18 @@ class HValue: public ZoneObject { UNREACHABLE(); return false; } + + virtual Representation RepresentationFromInputs() { + return representation(); + } + Representation RepresentationFromUses(); + virtual void UpdateRepresentation(Representation new_rep, + HInferRepresentation* h_infer, + const char* reason); + void AddDependantsToWorklist(HInferRepresentation* h_infer); + virtual void RepresentationChanged(Representation to) { } + virtual Range* InferRange(Zone* zone); virtual void DeleteFromGraph() = 0; virtual void InternalSetOperandAt(int index, HValue* value) = 0; @@ -798,7 +818,6 @@ class HValue: public ZoneObject { } void set_representation(Representation r) { - // Representation is set-once. ASSERT(representation_.IsNone() && !r.IsNone()); representation_ = r; } @@ -861,6 +880,8 @@ class HValue: public ZoneObject { GVNFlagSet gvn_flags_; private: + virtual bool IsDeletable() const { return false; } + DISALLOW_COPY_AND_ASSIGN(HValue); }; @@ -929,7 +950,7 @@ template<int V> class HTemplateInstruction : public HInstruction { public: int OperandCount() { return V; } - HValue* OperandAt(int i) { return inputs_[i]; } + HValue* OperandAt(int i) const { return inputs_[i]; } protected: void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; } @@ -981,7 +1002,7 @@ class HTemplateControlInstruction: public HControlInstruction { void SetSuccessorAt(int i, HBasicBlock* block) { successors_[i] = block; } int OperandCount() { return V; } - HValue* OperandAt(int i) { return inputs_[i]; } + HValue* OperandAt(int i) const { return inputs_[i]; } protected: @@ -1026,7 +1047,7 @@ class HDeoptimize: public HControlInstruction { } virtual int OperandCount() { return values_.length(); } - virtual HValue* OperandAt(int index) { return values_[index]; } + virtual HValue* OperandAt(int index) const { return values_[index]; } virtual void PrintDataTo(StringStream* stream); virtual int SuccessorCount() { return 0; } @@ -1109,6 +1130,7 @@ class HBranch: public HUnaryControlInstruction { virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); } + virtual Representation observed_input_representation(int index); ToBooleanStub::Types expected_input_types() const { return expected_input_types_; @@ -1187,7 +1209,7 @@ class HUnaryOperation: public HTemplateInstruction<1> { return reinterpret_cast<HUnaryOperation*>(value); } - HValue* value() { return OperandAt(0); } + HValue* value() const { return OperandAt(0); } virtual void PrintDataTo(StringStream* stream); }; @@ -1263,8 +1285,8 @@ class HChange: public HUnaryOperation { virtual HType CalculateInferredType(); virtual HValue* Canonicalize(); - Representation from() { return value()->representation(); } - Representation to() { return representation(); } + Representation from() const { return value()->representation(); } + Representation to() const { return representation(); } bool deoptimize_on_undefined() const { return CheckFlag(kDeoptimizeOnUndefined); } @@ -1283,6 +1305,11 @@ class HChange: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { + return !from().IsTagged() || value()->type().IsSmi(); + } }; @@ -1302,17 +1329,30 @@ class HClampToUint8: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } +}; + + +enum RemovableSimulate { + REMOVABLE_SIMULATE, + FIXED_SIMULATE }; class HSimulate: public HInstruction { public: - HSimulate(BailoutId ast_id, int pop_count, Zone* zone) + HSimulate(BailoutId ast_id, + int pop_count, + Zone* zone, + RemovableSimulate removable) : ast_id_(ast_id), pop_count_(pop_count), values_(2, zone), assigned_indexes_(2, zone), - zone_(zone) {} + zone_(zone), + removable_(removable) {} virtual ~HSimulate() {} virtual void PrintDataTo(StringStream* stream); @@ -1340,12 +1380,15 @@ class HSimulate: public HInstruction { AddValue(kNoIndex, value); } virtual int OperandCount() { return values_.length(); } - virtual HValue* OperandAt(int index) { return values_[index]; } + virtual HValue* OperandAt(int index) const { return values_[index]; } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); } + void MergeInto(HSimulate* other); + bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; } + DECLARE_CONCRETE_INSTRUCTION(Simulate) #ifdef DEBUG @@ -1372,6 +1415,7 @@ class HSimulate: public HInstruction { ZoneList<HValue*> values_; ZoneList<int> assigned_indexes_; Zone* zone_; + RemovableSimulate removable_; }; @@ -1431,6 +1475,7 @@ class HEnterInlined: public HTemplateInstruction<0> { ZoneList<HValue*>* arguments_values) : closure_(closure), arguments_count_(arguments_count), + arguments_pushed_(false), function_(function), call_kind_(call_kind), inlining_kind_(inlining_kind), @@ -1442,6 +1487,8 @@ class HEnterInlined: public HTemplateInstruction<0> { Handle<JSFunction> closure() const { return closure_; } int arguments_count() const { return arguments_count_; } + bool arguments_pushed() const { return arguments_pushed_; } + void set_arguments_pushed() { arguments_pushed_ = true; } FunctionLiteral* function() const { return function_; } CallKind call_kind() const { return call_kind_; } InliningKind inlining_kind() const { return inlining_kind_; } @@ -1458,6 +1505,7 @@ class HEnterInlined: public HTemplateInstruction<0> { private: Handle<JSFunction> closure_; int arguments_count_; + bool arguments_pushed_; FunctionLiteral* function_; CallKind call_kind_; InliningKind inlining_kind_; @@ -1468,21 +1516,13 @@ class HEnterInlined: public HTemplateInstruction<0> { class HLeaveInlined: public HTemplateInstruction<0> { public: - explicit HLeaveInlined(bool arguments_pushed) - : arguments_pushed_(arguments_pushed) { } + HLeaveInlined() { } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); } - bool arguments_pushed() { - return arguments_pushed_; - } - DECLARE_CONCRETE_INSTRUCTION(LeaveInlined) - - private: - bool arguments_pushed_; }; @@ -1517,6 +1557,9 @@ class HThisFunction: public HTemplateInstruction<0> { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1535,6 +1578,9 @@ class HContext: public HTemplateInstruction<0> { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1553,6 +1599,9 @@ class HOuterContext: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1598,6 +1647,9 @@ class HGlobalObject: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1617,6 +1669,9 @@ class HGlobalReceiver: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1902,6 +1957,9 @@ class HJSArrayLength: public HTemplateInstruction<2> { protected: virtual bool DataEquals(HValue* other_raw) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1922,6 +1980,9 @@ class HFixedArrayBaseLength: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1942,6 +2003,9 @@ class HMapEnumLength: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1961,6 +2025,9 @@ class HElementsKind: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1975,6 +2042,9 @@ class HBitNot: public HUnaryOperation { virtual Representation RequiredInputRepresentation(int index) { return Representation::Integer32(); } + virtual Representation observed_input_representation(int index) { + return Representation::Integer32(); + } virtual HType CalculateInferredType(); virtual HValue* Canonicalize(); @@ -1983,6 +2053,9 @@ class HBitNot: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1999,7 +2072,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { set_representation(Representation::Integer32()); break; case kMathAbs: - set_representation(Representation::Tagged()); + // Not setting representation here: it is None intentionally. SetFlag(kFlexibleRepresentation); SetGVNFlag(kChangesNewSpacePromotion); break; @@ -2012,6 +2085,9 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { set_representation(Representation::Double()); SetGVNFlag(kChangesNewSpacePromotion); break; + case kMathExp: + set_representation(Representation::Double()); + break; default: UNREACHABLE(); } @@ -2038,6 +2114,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { case kMathSqrt: case kMathPowHalf: case kMathLog: + case kMathExp: case kMathSin: case kMathCos: case kMathTan: @@ -2065,6 +2142,8 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { } private: + virtual bool IsDeletable() const { return true; } + BuiltinFunctionId op_; }; @@ -2080,6 +2159,9 @@ class HLoadElements: public HTemplateInstruction<2> { } HValue* value() { return OperandAt(0); } + HValue* typecheck() { return OperandAt(1); } + + virtual void PrintDataTo(StringStream* stream); virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); @@ -2089,6 +2171,9 @@ class HLoadElements: public HTemplateInstruction<2> { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -2112,6 +2197,9 @@ class HLoadExternalArrayPointer: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -2168,6 +2256,7 @@ class HCheckMaps: public HTemplateInstruction<2> { virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); } + virtual void PrintDataTo(StringStream* stream); virtual HType CalculateInferredType(); @@ -2328,10 +2417,6 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { SetGVNFlag(kDependsOnMaps); } -#ifdef DEBUG - virtual void Verify(); -#endif - Handle<JSObject> prototype() const { return prototype_; } Handle<JSObject> holder() const { return holder_; } @@ -2399,19 +2484,21 @@ class HPhi: public HValue { indirect_uses_[i] = 0; } ASSERT(merged_index >= 0); - set_representation(Representation::Tagged()); SetFlag(kFlexibleRepresentation); } - virtual Representation InferredRepresentation(); + virtual Representation RepresentationFromInputs(); virtual Range* InferRange(Zone* zone); + virtual void InferRepresentation(HInferRepresentation* h_infer); + Representation RepresentationObservedByAllNonPhiUses(); + Representation RepresentationFromUseRequirements(); virtual Representation RequiredInputRepresentation(int index) { return representation(); } virtual HType CalculateInferredType(); virtual int OperandCount() { return inputs_.length(); } - virtual HValue* OperandAt(int index) { return inputs_[index]; } + virtual HValue* OperandAt(int index) const { return inputs_[index]; } HValue* GetRedundantReplacement(); void AddInput(HValue* value); bool HasRealUses(); @@ -2469,14 +2556,17 @@ class HPhi: public HValue { bool AllOperandsConvertibleToInteger() { for (int i = 0; i < OperandCount(); ++i) { if (!OperandAt(i)->IsConvertibleToInteger()) { + if (FLAG_trace_representation) { + HValue* input = OperandAt(i); + PrintF("#%d %s: Input #%d %s at %d is NCTI\n", + id(), Mnemonic(), input->id(), input->Mnemonic(), i); + } return false; } } return true; } - void ResetInteger32Uses(); - protected: virtual void DeleteFromGraph(); virtual void InternalSetOperandAt(int index, HValue* value) { @@ -2507,6 +2597,9 @@ class HArgumentsObject: public HTemplateInstruction<0> { } DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) + + private: + virtual bool IsDeletable() const { return true; } }; @@ -2562,7 +2655,6 @@ class HConstant: public HTemplateInstruction<0> { } virtual bool EmitAtUses() { return !representation().IsDouble(); } - virtual HValue* Canonicalize(); virtual void PrintDataTo(StringStream* stream); virtual HType CalculateInferredType(); bool IsInteger() { return handle()->IsSmi(); } @@ -2635,6 +2727,8 @@ class HConstant: public HTemplateInstruction<0> { } private: + virtual bool IsDeletable() const { return true; } + // If this is a numerical constant, handle_ either points to to the // HeapObject the constant originated from or is null. If the // constant is non-numeric, handle_ always points to a valid @@ -2655,11 +2749,14 @@ class HConstant: public HTemplateInstruction<0> { class HBinaryOperation: public HTemplateInstruction<3> { public: - HBinaryOperation(HValue* context, HValue* left, HValue* right) { + HBinaryOperation(HValue* context, HValue* left, HValue* right) + : observed_output_representation_(Representation::None()) { ASSERT(left != NULL && right != NULL); SetOperandAt(0, context); SetOperandAt(1, left); SetOperandAt(2, right); + observed_input_representation_[0] = Representation::None(); + observed_input_representation_[1] = Representation::None(); } HValue* context() { return OperandAt(0); } @@ -2678,9 +2775,34 @@ class HBinaryOperation: public HTemplateInstruction<3> { return right(); } + void set_observed_input_representation(Representation left, + Representation right) { + observed_input_representation_[0] = left; + observed_input_representation_[1] = right; + } + + virtual void initialize_output_representation(Representation observed) { + observed_output_representation_ = observed; + } + + virtual Representation observed_input_representation(int index) { + if (index == 0) return Representation::Tagged(); + return observed_input_representation_[index - 1]; + } + + virtual void InferRepresentation(HInferRepresentation* h_infer); + virtual Representation RepresentationFromInputs(); + virtual void AssumeRepresentation(Representation r); + virtual bool IsCommutative() const { return false; } virtual void PrintDataTo(StringStream* stream); + + DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation) + + private: + Representation observed_input_representation_[2]; + Representation observed_output_representation_; }; @@ -2755,6 +2877,9 @@ class HArgumentsElements: public HTemplateInstruction<0> { protected: virtual bool DataEquals(HValue* other) { return true; } + private: + virtual bool IsDeletable() const { return true; } + bool from_inlined_; }; @@ -2774,6 +2899,9 @@ class HArgumentsLength: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -2844,6 +2972,9 @@ class HBoundsCheck: public HTemplateInstruction<2> { } return Representation::Integer32(); } + virtual Representation observed_input_representation(int index) { + return Representation::Integer32(); + } virtual void PrintDataTo(StringStream* stream); @@ -2862,12 +2993,9 @@ class HBitwiseBinaryOperation: public HBinaryOperation { public: HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right) : HBinaryOperation(context, left, right) { - set_representation(Representation::Tagged()); SetFlag(kFlexibleRepresentation); + SetFlag(kTruncatingToInt32); SetAllSideEffects(); - observed_input_representation_[0] = Representation::Tagged(); - observed_input_representation_[1] = Representation::None(); - observed_input_representation_[2] = Representation::None(); } virtual Representation RequiredInputRepresentation(int index) { @@ -2880,26 +3008,32 @@ class HBitwiseBinaryOperation: public HBinaryOperation { if (!to.IsTagged()) { ASSERT(to.IsInteger32()); ClearAllSideEffects(); - SetFlag(kTruncatingToInt32); SetFlag(kUseGVN); + } else { + SetAllSideEffects(); + ClearFlag(kUseGVN); } } - virtual HType CalculateInferredType(); - - virtual Representation ObservedInputRepresentation(int index) { - return observed_input_representation_[index]; + virtual void UpdateRepresentation(Representation new_rep, + HInferRepresentation* h_infer, + const char* reason) { + // We only generate either int32 or generic tagged bitwise operations. + if (new_rep.IsDouble()) new_rep = Representation::Integer32(); + HValue::UpdateRepresentation(new_rep, h_infer, reason); } - void InitializeObservedInputRepresentation(Representation r) { - observed_input_representation_[1] = r; - observed_input_representation_[2] = r; + virtual void initialize_output_representation(Representation observed) { + if (observed.IsDouble()) observed = Representation::Integer32(); + HBinaryOperation::initialize_output_representation(observed); } + virtual HType CalculateInferredType(); + DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation) private: - Representation observed_input_representation_[3]; + virtual bool IsDeletable() const { return true; } }; @@ -2922,6 +3056,9 @@ class HMathFloorOfDiv: public HBinaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -2929,13 +3066,15 @@ class HArithmeticBinaryOperation: public HBinaryOperation { public: HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right) : HBinaryOperation(context, left, right) { - set_representation(Representation::Tagged()); - SetFlag(kFlexibleRepresentation); SetAllSideEffects(); + SetFlag(kFlexibleRepresentation); } virtual void RepresentationChanged(Representation to) { - if (!to.IsTagged()) { + if (to.IsTagged()) { + SetAllSideEffects(); + ClearFlag(kUseGVN); + } else { ClearAllSideEffects(); SetFlag(kUseGVN); } @@ -2948,12 +3087,8 @@ class HArithmeticBinaryOperation: public HBinaryOperation { : representation(); } - virtual Representation InferredRepresentation() { - if (left()->representation().Equals(right()->representation())) { - return left()->representation(); - } - return HValue::InferredRepresentation(); - } + private: + virtual bool IsDeletable() const { return true; } }; @@ -2970,11 +3105,9 @@ class HCompareGeneric: public HBinaryOperation { } virtual Representation RequiredInputRepresentation(int index) { - return Representation::Tagged(); - } - - Representation GetInputRepresentation() const { - return Representation::Tagged(); + return index == 0 + ? Representation::Tagged() + : representation(); } Token::Value token() const { return token_; } @@ -2993,6 +3126,7 @@ class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> { public: HCompareIDAndBranch(HValue* left, HValue* right, Token::Value token) : token_(token) { + SetFlag(kFlexibleRepresentation); ASSERT(Token::IsCompareOp(token)); SetOperandAt(0, left); SetOperandAt(1, right); @@ -3002,20 +3136,26 @@ class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> { HValue* right() { return OperandAt(1); } Token::Value token() const { return token_; } - void SetInputRepresentation(Representation r); - Representation GetInputRepresentation() const { - return input_representation_; + void set_observed_input_representation(Representation left, + Representation right) { + observed_input_representation_[0] = left; + observed_input_representation_[1] = right; } + virtual void InferRepresentation(HInferRepresentation* h_infer); + virtual Representation RequiredInputRepresentation(int index) { - return input_representation_; + return representation(); + } + virtual Representation observed_input_representation(int index) { + return observed_input_representation_[index]; } virtual void PrintDataTo(StringStream* stream); DECLARE_CONCRETE_INSTRUCTION(CompareIDAndBranch) private: - Representation input_representation_; + Representation observed_input_representation_[2]; Token::Value token_; }; @@ -3076,6 +3216,9 @@ class HIsNilAndBranch: public HUnaryControlInstruction { virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); } + virtual Representation observed_input_representation(int index) { + return Representation::Tagged(); + } DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch) @@ -3239,6 +3382,9 @@ class HGetCachedArrayIndex: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -3343,18 +3489,26 @@ class HPower: public HTemplateInstruction<2> { } HValue* left() { return OperandAt(0); } - HValue* right() { return OperandAt(1); } + HValue* right() const { return OperandAt(1); } virtual Representation RequiredInputRepresentation(int index) { return index == 0 ? Representation::Double() : Representation::None(); } + virtual Representation observed_input_representation(int index) { + return RequiredInputRepresentation(index); + } DECLARE_CONCRETE_INSTRUCTION(Power) protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { + return !right()->representation().IsTagged(); + } }; @@ -3372,6 +3526,9 @@ class HRandom: public HTemplateInstruction<1> { } DECLARE_CONCRETE_INSTRUCTION(Random) + + private: + virtual bool IsDeletable() const { return true; } }; @@ -3502,6 +3659,16 @@ class HDiv: public HArithmeticBinaryOperation { SetFlag(kCanOverflow); } + bool HasPowerOf2Divisor() { + if (right()->IsConstant() && + HConstant::cast(right())->HasInteger32Value()) { + int32_t value = HConstant::cast(right())->Integer32Value(); + return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value)); + } + + return false; + } + virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); static HInstruction* NewHDiv(Zone* zone, @@ -3527,14 +3694,21 @@ class HMathMinMax: public HArithmeticBinaryOperation { operation_(op) { } virtual Representation RequiredInputRepresentation(int index) { - return index == 0 - ? Representation::Tagged() - : representation(); - } + return index == 0 ? Representation::Tagged() + : representation(); + } + + virtual Representation observed_input_representation(int index) { + return RequiredInputRepresentation(index); + } - virtual Representation InferredRepresentation() { - if (left()->representation().IsInteger32() && - right()->representation().IsInteger32()) { + virtual void InferRepresentation(HInferRepresentation* h_infer); + + virtual Representation RepresentationFromInputs() { + Representation left_rep = left()->representation(); + Representation right_rep = right()->representation(); + if ((left_rep.IsNone() || left_rep.IsInteger32()) && + (right_rep.IsNone() || right_rep.IsInteger32())) { return Representation::Integer32(); } return Representation::Double(); @@ -3653,6 +3827,25 @@ class HSar: public HBitwiseBinaryOperation { }; +class HRor: public HBitwiseBinaryOperation { + public: + HRor(HValue* context, HValue* left, HValue* right) + : HBitwiseBinaryOperation(context, left, right) { + ChangeRepresentation(Representation::Integer32()); + } + + static HInstruction* NewHRor(Zone* zone, + HValue* context, + HValue* left, + HValue* right); + + DECLARE_CONCRETE_INSTRUCTION(Ror) + + protected: + virtual bool DataEquals(HValue* other) { return true; } +}; + + class HOsrEntry: public HTemplateInstruction<0> { public: explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) { @@ -3762,7 +3955,7 @@ class HLoadGlobalCell: public HTemplateInstruction<0> { } Handle<JSGlobalPropertyCell> cell() const { return cell_; } - bool RequiresHoleCheck(); + bool RequiresHoleCheck() const; virtual void PrintDataTo(StringStream* stream); @@ -3784,6 +3977,8 @@ class HLoadGlobalCell: public HTemplateInstruction<0> { } private: + virtual bool IsDeletable() const { return !RequiresHoleCheck(); } + Handle<JSGlobalPropertyCell> cell_; PropertyDetails details_; }; @@ -3831,7 +4026,8 @@ inline bool StoringValueNeedsWriteBarrier(HValue* value) { inline bool ReceiverObjectNeedsWriteBarrier(HValue* object, HValue* new_space_dominator) { - return !object->IsAllocateObject() || (object != new_space_dominator); + return (!object->IsAllocateObject() && !object->IsFastLiteral()) || + (object != new_space_dominator); } @@ -3944,7 +4140,7 @@ class HLoadContextSlot: public HUnaryOperation { return mode_ == kCheckDeoptimize; } - bool RequiresHoleCheck() { + bool RequiresHoleCheck() const { return mode_ != kNoCheck; } @@ -3963,6 +4159,8 @@ class HLoadContextSlot: public HUnaryOperation { } private: + virtual bool IsDeletable() const { return !RequiresHoleCheck(); } + int slot_index_; Mode mode_; }; @@ -4055,6 +4253,8 @@ class HLoadNamedField: public HUnaryOperation { } private: + virtual bool IsDeletable() const { return true; } + bool is_in_object_; int offset_; }; @@ -4153,29 +4353,59 @@ class ArrayInstructionInterface { virtual ~ArrayInstructionInterface() { }; }; -class HLoadKeyedFastElement + +class HLoadKeyed : public HTemplateInstruction<3>, public ArrayInstructionInterface { public: - HLoadKeyedFastElement(HValue* obj, - HValue* key, - HValue* dependency, - ElementsKind elements_kind = FAST_ELEMENTS) + HLoadKeyed(HValue* obj, + HValue* key, + HValue* dependency, + ElementsKind elements_kind) : bit_field_(0) { - ASSERT(IsFastSmiOrObjectElementsKind(elements_kind)); bit_field_ = ElementsKindField::encode(elements_kind); - if (IsFastSmiElementsKind(elements_kind) && - IsFastPackedElementsKind(elements_kind)) { - set_type(HType::Smi()); - } + SetOperandAt(0, obj); SetOperandAt(1, key); SetOperandAt(2, dependency); - set_representation(Representation::Tagged()); - SetGVNFlag(kDependsOnArrayElements); + + if (!is_external()) { + // I can detect the case between storing double (holey and fast) and + // smi/object by looking at elements_kind_. + ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || + IsFastDoubleElementsKind(elements_kind)); + + if (IsFastSmiOrObjectElementsKind(elements_kind)) { + if (IsFastSmiElementsKind(elements_kind) && + IsFastPackedElementsKind(elements_kind)) { + set_type(HType::Smi()); + } + + set_representation(Representation::Tagged()); + SetGVNFlag(kDependsOnArrayElements); + } else { + set_representation(Representation::Double()); + SetGVNFlag(kDependsOnDoubleArrayElements); + } + } else { + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || + elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { + set_representation(Representation::Double()); + } else { + set_representation(Representation::Integer32()); + } + + SetGVNFlag(kDependsOnSpecializedArrayElements); + // Native code could change the specialized array. + SetGVNFlag(kDependsOnCalls); + } + SetFlag(kUseGVN); } - HValue* object() { return OperandAt(0); } + bool is_external() const { + return IsExternalArrayElementsKind(elements_kind()); + } + HValue* elements() { return OperandAt(0); } HValue* key() { return OperandAt(1); } HValue* dependency() { return OperandAt(2); } uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); } @@ -4193,158 +4423,68 @@ class HLoadKeyedFastElement } virtual Representation RequiredInputRepresentation(int index) { - // The key is supposed to be Integer32. - if (index == 0) return Representation::Tagged(); + // kind_fast: tagged[int32] (none) + // kind_double: tagged[int32] (none) + // kind_external: external[int32] (none) + if (index == 0) { + return is_external() ? Representation::External() + : Representation::Tagged(); + } if (index == 1) return Representation::Integer32(); return Representation::None(); } + virtual Representation observed_input_representation(int index) { + return RequiredInputRepresentation(index); + } + virtual void PrintDataTo(StringStream* stream); - bool RequiresHoleCheck(); + bool RequiresHoleCheck() const; + + virtual Range* InferRange(Zone* zone); - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement) + DECLARE_CONCRETE_INSTRUCTION(LoadKeyed) protected: virtual bool DataEquals(HValue* other) { - if (!other->IsLoadKeyedFastElement()) return false; - HLoadKeyedFastElement* other_load = HLoadKeyedFastElement::cast(other); + if (!other->IsLoadKeyed()) return false; + HLoadKeyed* other_load = HLoadKeyed::cast(other); + if (IsDehoisted() && index_offset() != other_load->index_offset()) return false; return elements_kind() == other_load->elements_kind(); } private: - class ElementsKindField: public BitField<ElementsKind, 0, 4> {}; - class IndexOffsetField: public BitField<uint32_t, 4, 27> {}; - class IsDehoistedField: public BitField<bool, 31, 1> {}; - uint32_t bit_field_; -}; - - -enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK }; - - -class HLoadKeyedFastDoubleElement - : public HTemplateInstruction<3>, public ArrayInstructionInterface { - public: - HLoadKeyedFastDoubleElement( - HValue* elements, - HValue* key, - HValue* dependency, - HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK) - : index_offset_(0), - is_dehoisted_(false), - hole_check_mode_(hole_check_mode) { - SetOperandAt(0, elements); - SetOperandAt(1, key); - SetOperandAt(2, dependency); - set_representation(Representation::Double()); - SetGVNFlag(kDependsOnDoubleArrayElements); - SetFlag(kUseGVN); - } - - HValue* elements() { return OperandAt(0); } - HValue* key() { return OperandAt(1); } - HValue* dependency() { return OperandAt(2); } - uint32_t index_offset() { return index_offset_; } - void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } - HValue* GetKey() { return key(); } - void SetKey(HValue* key) { SetOperandAt(1, key); } - bool IsDehoisted() { return is_dehoisted_; } - void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } - - virtual Representation RequiredInputRepresentation(int index) { - // The key is supposed to be Integer32. - if (index == 0) return Representation::Tagged(); - if (index == 1) return Representation::Integer32(); - return Representation::None(); - } - - bool RequiresHoleCheck() { - return hole_check_mode_ == PERFORM_HOLE_CHECK; - } - - virtual void PrintDataTo(StringStream* stream); - - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement) - - protected: - virtual bool DataEquals(HValue* other) { - if (!other->IsLoadKeyedFastDoubleElement()) return false; - HLoadKeyedFastDoubleElement* other_load = - HLoadKeyedFastDoubleElement::cast(other); - return hole_check_mode_ == other_load->hole_check_mode_; - } - - private: - uint32_t index_offset_; - bool is_dehoisted_; - HoleCheckMode hole_check_mode_; -}; - - -class HLoadKeyedSpecializedArrayElement - : public HTemplateInstruction<3>, public ArrayInstructionInterface { - public: - HLoadKeyedSpecializedArrayElement(HValue* external_elements, - HValue* key, - HValue* dependency, - ElementsKind elements_kind) - : elements_kind_(elements_kind), - index_offset_(0), - is_dehoisted_(false) { - SetOperandAt(0, external_elements); - SetOperandAt(1, key); - SetOperandAt(2, dependency); - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || - elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { - set_representation(Representation::Double()); - } else { - set_representation(Representation::Integer32()); - } - SetGVNFlag(kDependsOnSpecializedArrayElements); - // Native code could change the specialized array. - SetGVNFlag(kDependsOnCalls); - SetFlag(kUseGVN); + virtual bool IsDeletable() const { + return !RequiresHoleCheck(); } - virtual void PrintDataTo(StringStream* stream); - - virtual Representation RequiredInputRepresentation(int index) { - // The key is supposed to be Integer32. - if (index == 0) return Representation::External(); - if (index == 1) return Representation::Integer32(); - return Representation::None(); - } + // Establish some checks around our packed fields + enum LoadKeyedBits { + kBitsForElementsKind = 5, + kBitsForIndexOffset = 26, + kBitsForIsDehoisted = 1, - HValue* external_pointer() { return OperandAt(0); } - HValue* key() { return OperandAt(1); } - HValue* dependency() { return OperandAt(2); } - ElementsKind elements_kind() const { return elements_kind_; } - uint32_t index_offset() { return index_offset_; } - void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } - HValue* GetKey() { return key(); } - void SetKey(HValue* key) { SetOperandAt(1, key); } - bool IsDehoisted() { return is_dehoisted_; } - void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } - - virtual Range* InferRange(Zone* zone); - - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement) - - protected: - virtual bool DataEquals(HValue* other) { - if (!other->IsLoadKeyedSpecializedArrayElement()) return false; - HLoadKeyedSpecializedArrayElement* cast_other = - HLoadKeyedSpecializedArrayElement::cast(other); - return elements_kind_ == cast_other->elements_kind(); - } + kStartElementsKind = 0, + kStartIndexOffset = kStartElementsKind + kBitsForElementsKind, + kStartIsDehoisted = kStartIndexOffset + kBitsForIndexOffset + }; - private: - ElementsKind elements_kind_; - uint32_t index_offset_; - bool is_dehoisted_; + STATIC_ASSERT((kBitsForElementsKind + kBitsForIndexOffset + + kBitsForIsDehoisted) <= sizeof(uint32_t)*8); + STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind)); + class ElementsKindField: + public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind> + {}; // NOLINT + class IndexOffsetField: + public BitField<uint32_t, kStartIndexOffset, kBitsForIndexOffset> + {}; // NOLINT + class IsDehoistedField: + public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted> + {}; // NOLINT + uint32_t bit_field_; }; @@ -4365,6 +4505,7 @@ class HLoadKeyedGeneric: public HTemplateInstruction<3> { virtual void PrintDataTo(StringStream* stream); virtual Representation RequiredInputRepresentation(int index) { + // tagged[tagged] return Representation::Tagged(); } @@ -4470,83 +4611,75 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> { }; -class HStoreKeyedFastElement +class HStoreKeyed : public HTemplateInstruction<3>, public ArrayInstructionInterface { public: - HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val, - ElementsKind elements_kind = FAST_ELEMENTS) + HStoreKeyed(HValue* obj, HValue* key, HValue* val, + ElementsKind elements_kind) : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) { SetOperandAt(0, obj); SetOperandAt(1, key); SetOperandAt(2, val); - SetGVNFlag(kChangesArrayElements); - } - - virtual Representation RequiredInputRepresentation(int index) { - // The key is supposed to be Integer32. - return index == 1 - ? Representation::Integer32() - : Representation::Tagged(); - } - - HValue* object() { return OperandAt(0); } - HValue* key() { return OperandAt(1); } - HValue* value() { return OperandAt(2); } - bool value_is_smi() { - return IsFastSmiElementsKind(elements_kind_); - } - uint32_t index_offset() { return index_offset_; } - void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } - HValue* GetKey() { return key(); } - void SetKey(HValue* key) { SetOperandAt(1, key); } - bool IsDehoisted() { return is_dehoisted_; } - void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } - bool NeedsWriteBarrier() { - if (value_is_smi()) { - return false; + if (is_external()) { + SetGVNFlag(kChangesSpecializedArrayElements); + } else if (IsFastDoubleElementsKind(elements_kind)) { + SetGVNFlag(kChangesDoubleArrayElements); + SetFlag(kDeoptimizeOnUndefined); } else { - return StoringValueNeedsWriteBarrier(value()); + SetGVNFlag(kChangesArrayElements); } - } - virtual void PrintDataTo(StringStream* stream); + // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating. + if (elements_kind >= EXTERNAL_BYTE_ELEMENTS && + elements_kind <= EXTERNAL_UNSIGNED_INT_ELEMENTS) { + SetFlag(kTruncatingToInt32); + } + } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement) + virtual Representation RequiredInputRepresentation(int index) { + // kind_fast: tagged[int32] = tagged + // kind_double: tagged[int32] = double + // kind_external: external[int32] = (double | int32) + if (index == 0) { + return is_external() ? Representation::External() + : Representation::Tagged(); + } else if (index == 1) { + return Representation::Integer32(); + } - private: - ElementsKind elements_kind_; - uint32_t index_offset_; - bool is_dehoisted_; -}; + ASSERT_EQ(index, 2); + if (IsDoubleOrFloatElementsKind(elements_kind())) { + return Representation::Double(); + } + return is_external() ? Representation::Integer32() + : Representation::Tagged(); + } -class HStoreKeyedFastDoubleElement - : public HTemplateInstruction<3>, public ArrayInstructionInterface { - public: - HStoreKeyedFastDoubleElement(HValue* elements, - HValue* key, - HValue* val) - : index_offset_(0), is_dehoisted_(false) { - SetOperandAt(0, elements); - SetOperandAt(1, key); - SetOperandAt(2, val); - SetGVNFlag(kChangesDoubleArrayElements); + bool is_external() const { + return IsExternalArrayElementsKind(elements_kind()); } - virtual Representation RequiredInputRepresentation(int index) { - if (index == 1) { - return Representation::Integer32(); - } else if (index == 2) { + virtual Representation observed_input_representation(int index) { + if (index < 2) return RequiredInputRepresentation(index); + if (IsDoubleOrFloatElementsKind(elements_kind())) { return Representation::Double(); - } else { - return Representation::Tagged(); } + if (is_external()) { + return Representation::Integer32(); + } + // For fast object elements kinds, don't assume anything. + return Representation::None(); } HValue* elements() { return OperandAt(0); } HValue* key() { return OperandAt(1); } HValue* value() { return OperandAt(2); } + bool value_is_smi() const { + return IsFastSmiElementsKind(elements_kind_); + } + ElementsKind elements_kind() const { return elements_kind_; } uint32_t index_offset() { return index_offset_; } void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } HValue* GetKey() { return key(); } @@ -4555,64 +4688,18 @@ class HStoreKeyedFastDoubleElement void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } bool NeedsWriteBarrier() { - return StoringValueNeedsWriteBarrier(value()); + if (value_is_smi()) { + return false; + } else { + return StoringValueNeedsWriteBarrier(value()); + } } bool NeedsCanonicalization(); virtual void PrintDataTo(StringStream* stream); - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement) - - private: - uint32_t index_offset_; - bool is_dehoisted_; -}; - - -class HStoreKeyedSpecializedArrayElement - : public HTemplateInstruction<3>, public ArrayInstructionInterface { - public: - HStoreKeyedSpecializedArrayElement(HValue* external_elements, - HValue* key, - HValue* val, - ElementsKind elements_kind) - : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) { - SetGVNFlag(kChangesSpecializedArrayElements); - SetOperandAt(0, external_elements); - SetOperandAt(1, key); - SetOperandAt(2, val); - } - - virtual void PrintDataTo(StringStream* stream); - - virtual Representation RequiredInputRepresentation(int index) { - if (index == 0) { - return Representation::External(); - } else { - bool float_or_double_elements = - elements_kind() == EXTERNAL_FLOAT_ELEMENTS || - elements_kind() == EXTERNAL_DOUBLE_ELEMENTS; - if (index == 2 && float_or_double_elements) { - return Representation::Double(); - } else { - return Representation::Integer32(); - } - } - } - - HValue* external_pointer() { return OperandAt(0); } - HValue* key() { return OperandAt(1); } - HValue* value() { return OperandAt(2); } - ElementsKind elements_kind() const { return elements_kind_; } - uint32_t index_offset() { return index_offset_; } - void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } - HValue* GetKey() { return key(); } - void SetKey(HValue* key) { SetOperandAt(1, key); } - bool IsDehoisted() { return is_dehoisted_; } - void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } - - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement) + DECLARE_CONCRETE_INSTRUCTION(StoreKeyed) private: ElementsKind elements_kind_; @@ -4643,6 +4730,7 @@ class HStoreKeyedGeneric: public HTemplateInstruction<4> { StrictModeFlag strict_mode_flag() { return strict_mode_flag_; } virtual Representation RequiredInputRepresentation(int index) { + // tagged[tagged] = tagged return Representation::Tagged(); } @@ -4664,10 +4752,6 @@ class HTransitionElementsKind: public HTemplateInstruction<1> { transitioned_map_(transitioned_map) { SetOperandAt(0, object); SetFlag(kUseGVN); - // Don't set GVN DependOn flags here. That would defeat GVN's detection of - // congruent HTransitionElementsKind instructions. Instruction hoisting - // handles HTransitionElementsKind instruction specially, explicitly adding - // DependsOn flags during its dependency calculations. SetGVNFlag(kChangesElementsKind); if (original_map->has_fast_double_elements()) { SetGVNFlag(kChangesElementsPointer); @@ -4712,6 +4796,7 @@ class HStringAdd: public HBinaryOperation { set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetGVNFlag(kDependsOnMaps); + SetGVNFlag(kChangesNewSpacePromotion); } virtual Representation RequiredInputRepresentation(int index) { @@ -4726,6 +4811,10 @@ class HStringAdd: public HBinaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. + // private: + // virtual bool IsDeletable() const { return true; } }; @@ -4760,6 +4849,10 @@ class HStringCharCodeAt: public HTemplateInstruction<3> { virtual Range* InferRange(Zone* zone) { return new(zone) Range(0, String::kMaxUtf16CodeUnit); } + + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. + // private: + // virtual bool IsDeletable() const { return true; } }; @@ -4786,6 +4879,10 @@ class HStringCharFromCode: public HTemplateInstruction<2> { virtual bool DataEquals(HValue* other) { return true; } DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode) + + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. + // private: + // virtual bool IsDeletable() const { return true; } }; @@ -4814,6 +4911,9 @@ class HStringLength: public HUnaryOperation { virtual Range* InferRange(Zone* zone) { return new(zone) Range(0, String::kMaxLength); } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -4840,6 +4940,9 @@ class HAllocateObject: public HTemplateInstruction<1> { DECLARE_CONCRETE_INSTRUCTION(AllocateObject) private: + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. + // virtual bool IsDeletable() const { return true; } + Handle<JSFunction> constructor_; }; @@ -4856,6 +4959,8 @@ class HMaterializedLiteral: public HTemplateInstruction<V> { int depth() const { return depth_; } private: + virtual bool IsDeletable() const { return true; } + int literal_index_; int depth_; }; @@ -5031,6 +5136,8 @@ class HFunctionLiteral: public HTemplateInstruction<1> { bool pretenure() const { return pretenure_; } private: + virtual bool IsDeletable() const { return true; } + Handle<SharedFunctionInfo> shared_info_; bool pretenure_; }; @@ -5047,7 +5154,6 @@ class HTypeof: public HTemplateInstruction<2> { HValue* context() { return OperandAt(0); } HValue* value() { return OperandAt(1); } - virtual HValue* Canonicalize(); virtual void PrintDataTo(StringStream* stream); virtual Representation RequiredInputRepresentation(int index) { @@ -5055,6 +5161,9 @@ class HTypeof: public HTemplateInstruction<2> { } DECLARE_CONCRETE_INSTRUCTION(Typeof) + + private: + virtual bool IsDeletable() const { return true; } }; @@ -5073,6 +5182,9 @@ class HToFastProperties: public HUnaryOperation { } DECLARE_CONCRETE_INSTRUCTION(ToFastProperties) + + private: + virtual bool IsDeletable() const { return true; } }; @@ -5087,6 +5199,9 @@ class HValueOf: public HUnaryOperation { } DECLARE_CONCRETE_INSTRUCTION(ValueOf) + + private: + virtual bool IsDeletable() const { return true; } }; @@ -5110,6 +5225,33 @@ class HDateField: public HUnaryOperation { }; +class HSeqStringSetChar: public HTemplateInstruction<3> { + public: + HSeqStringSetChar(String::Encoding encoding, + HValue* string, + HValue* index, + HValue* value) : encoding_(encoding) { + SetOperandAt(0, string); + SetOperandAt(1, index); + SetOperandAt(2, value); + } + + String::Encoding encoding() { return encoding_; } + HValue* string() { return OperandAt(0); } + HValue* index() { return OperandAt(1); } + HValue* value() { return OperandAt(2); } + + virtual Representation RequiredInputRepresentation(int index) { + return Representation::Tagged(); + } + + DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar) + + private: + String::Encoding encoding_; +}; + + class HDeleteProperty: public HBinaryOperation { public: HDeleteProperty(HValue* context, HValue* obj, HValue* key) @@ -5283,6 +5425,9 @@ class HLoadFieldByIndex : public HTemplateInstruction<2> { } DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex); + + private: + virtual bool IsDeletable() const { return true; } }; diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 75344bb513..d1e5b51a5e 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -133,7 +133,8 @@ HDeoptimize* HBasicBlock::CreateDeoptimize( } -HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id) { +HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id, + RemovableSimulate removable) { ASSERT(HasEnvironment()); HEnvironment* environment = last_environment(); ASSERT(ast_id.IsNone() || @@ -142,8 +143,12 @@ HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id) { int push_count = environment->push_count(); int pop_count = environment->pop_count(); - HSimulate* instr = new(zone()) HSimulate(ast_id, pop_count, zone()); - for (int i = push_count - 1; i >= 0; --i) { + HSimulate* instr = + new(zone()) HSimulate(ast_id, pop_count, zone(), removable); + // Order of pushed values: newest (top of stack) first. This allows + // HSimulate::MergeInto() to easily append additional pushed values + // that are older (from further down the stack). + for (int i = 0; i < push_count; ++i) { instr->AddPushedValue(environment->ExpressionStackAt(i)); } for (int i = 0; i < environment->assigned_variables()->length(); ++i) { @@ -168,10 +173,9 @@ void HBasicBlock::Finish(HControlInstruction* end) { void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) { bool drop_extra = state != NULL && state->inlining_kind() == DROP_EXTRA_ON_RETURN; - bool arguments_pushed = state != NULL && state->arguments_pushed(); if (block->IsInlineReturnTarget()) { - AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); + AddInstruction(new(zone()) HLeaveInlined()); last_environment_ = last_environment()->DiscardInlined(drop_extra); } @@ -185,11 +189,10 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value, FunctionState* state) { HBasicBlock* target = state->function_return(); bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; - bool arguments_pushed = state->arguments_pushed(); ASSERT(target->IsInlineReturnTarget()); ASSERT(return_value != NULL); - AddInstruction(new(zone()) HLeaveInlined(arguments_pushed)); + AddInstruction(new(zone()) HLeaveInlined()); last_environment_ = last_environment()->DiscardInlined(drop_extra); last_environment()->Push(return_value); AddSimulate(BailoutId::None()); @@ -1293,7 +1296,7 @@ void HRangeAnalysis::Analyze(HBasicBlock* block) { void HRangeAnalysis::InferControlFlowRange(HCompareIDAndBranch* test, HBasicBlock* dest) { ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); - if (test->GetInputRepresentation().IsInteger32()) { + if (test->representation().IsInteger32()) { Token::Value op = test->token(); if (test->SecondSuccessor() == dest) { op = Token::NegateCompareOp(op); @@ -1950,52 +1953,6 @@ void HGlobalValueNumberer::ProcessLoopBlock( if (can_hoist && !graph()->use_optimistic_licm()) { can_hoist = block->IsLoopSuccessorDominator(); } - if (instr->IsTransitionElementsKind()) { - // It's possible to hoist transitions out of a loop as long as the - // hoisting wouldn't move the transition past an instruction that has a - // DependsOn flag for anything it changes. - GVNFlagSet hoist_depends_blockers = - HValue::ConvertChangesToDependsFlags(instr->ChangesFlags()); - - // In addition, the transition must not be hoisted above elements kind - // changes, or if the transition is destructive to the elements buffer, - // changes to array pointer or array contents. - GVNFlagSet hoist_change_blockers; - hoist_change_blockers.Add(kChangesElementsKind); - HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr); - if (trans->original_map()->has_fast_double_elements()) { - hoist_change_blockers.Add(kChangesElementsPointer); - hoist_change_blockers.Add(kChangesDoubleArrayElements); - } - if (trans->transitioned_map()->has_fast_double_elements()) { - hoist_change_blockers.Add(kChangesElementsPointer); - hoist_change_blockers.Add(kChangesArrayElements); - } - 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 - // between it and the beginning of the loop header. - bool in_nested_loop = block != loop_header && - ((block->parent_loop_header() != loop_header) || - block->IsLoopHeader()); - can_hoist = !in_nested_loop && - block->IsLoopSuccessorDominator() && - !first_time_depends->ContainsAnyOf(hoist_depends_blockers) && - !first_time_changes->ContainsAnyOf(hoist_change_blockers); - } if (can_hoist) { bool inputs_loop_invariant = true; @@ -2287,32 +2244,8 @@ void HGlobalValueNumberer::AnalyzeGraph() { } -class HInferRepresentation BASE_EMBEDDED { - public: - explicit HInferRepresentation(HGraph* graph) - : graph_(graph), - worklist_(8, graph->zone()), - in_worklist_(graph->GetMaximumValueID(), graph->zone()) { } - - void Analyze(); - - private: - Representation TryChange(HValue* current); - void AddToWorklist(HValue* current); - void InferBasedOnInputs(HValue* current); - void AddDependantsToWorklist(HValue* current); - void InferBasedOnUses(HValue* current); - - Zone* zone() const { return graph_->zone(); } - - HGraph* graph_; - ZoneList<HValue*> worklist_; - BitVector in_worklist_; -}; - - void HInferRepresentation::AddToWorklist(HValue* current) { - if (current->representation().IsSpecialization()) return; + if (current->representation().IsTagged()) return; if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return; if (in_worklist_.Contains(current->id())) return; worklist_.Add(current, zone()); @@ -2320,105 +2253,6 @@ void HInferRepresentation::AddToWorklist(HValue* current) { } -// This method tries to specialize the representation type of the value -// given as a parameter. The value is asked to infer its representation type -// based on its inputs. If the inferred type is more specialized, then this -// becomes the new representation type of the node. -void HInferRepresentation::InferBasedOnInputs(HValue* current) { - Representation r = current->representation(); - if (r.IsSpecialization()) return; - ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation)); - Representation inferred = current->InferredRepresentation(); - if (inferred.IsSpecialization()) { - if (FLAG_trace_representation) { - PrintF("Changing #%d representation %s -> %s based on inputs\n", - current->id(), - r.Mnemonic(), - inferred.Mnemonic()); - } - current->ChangeRepresentation(inferred); - AddDependantsToWorklist(current); - } -} - - -void HInferRepresentation::AddDependantsToWorklist(HValue* value) { - for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) { - AddToWorklist(it.value()); - } - for (int i = 0; i < value->OperandCount(); ++i) { - AddToWorklist(value->OperandAt(i)); - } -} - - -// This method calculates whether specializing the representation of the value -// given as the parameter has a benefit in terms of less necessary type -// conversions. If there is a benefit, then the representation of the value is -// specialized. -void HInferRepresentation::InferBasedOnUses(HValue* value) { - Representation r = value->representation(); - if (r.IsSpecialization() || value->HasNoUses()) return; - ASSERT(value->CheckFlag(HValue::kFlexibleRepresentation)); - Representation new_rep = TryChange(value); - if (!new_rep.IsNone()) { - if (!value->representation().Equals(new_rep)) { - if (FLAG_trace_representation) { - PrintF("Changing #%d representation %s -> %s based on uses\n", - value->id(), - r.Mnemonic(), - new_rep.Mnemonic()); - } - value->ChangeRepresentation(new_rep); - AddDependantsToWorklist(value); - } - } -} - - -Representation HInferRepresentation::TryChange(HValue* value) { - // Array of use counts for each representation. - int use_count[Representation::kNumRepresentations] = { 0 }; - - for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) { - HValue* use = it.value(); - Representation rep = use->ObservedInputRepresentation(it.index()); - if (rep.IsNone()) continue; - if (FLAG_trace_representation) { - PrintF("%d %s is used by %d %s as %s\n", - value->id(), - value->Mnemonic(), - use->id(), - use->Mnemonic(), - rep.Mnemonic()); - } - if (use->IsPhi()) HPhi::cast(use)->AddIndirectUsesTo(&use_count[0]); - use_count[rep.kind()] += use->LoopWeight(); - } - int tagged_count = use_count[Representation::kTagged]; - int double_count = use_count[Representation::kDouble]; - int int32_count = use_count[Representation::kInteger32]; - int non_tagged_count = double_count + int32_count; - - // If a non-loop phi has tagged uses, don't convert it to untagged. - if (value->IsPhi() && !value->block()->IsLoopHeader() && tagged_count > 0) { - return Representation::None(); - } - - // Prefer unboxing over boxing, the latter is more expensive. - if (tagged_count > non_tagged_count) return Representation::None(); - - // Prefer Integer32 over Double, if possible. - if (int32_count > 0 && value->IsConvertibleToInteger()) { - return Representation::Integer32(); - } - - if (double_count > 0) return Representation::Double(); - - return Representation::None(); -} - - void HInferRepresentation::Analyze() { HPhase phase("H_Infer representations", graph_); @@ -2469,7 +2303,6 @@ void HInferRepresentation::Analyze() { it.Advance()) { HPhi* phi = phi_list->at(it.Current()); phi->set_is_convertible_to_integer(false); - phi->ResetInteger32Uses(); } } @@ -2505,8 +2338,74 @@ void HInferRepresentation::Analyze() { while (!worklist_.is_empty()) { HValue* current = worklist_.RemoveLast(); in_worklist_.Remove(current->id()); - InferBasedOnInputs(current); - InferBasedOnUses(current); + current->InferRepresentation(this); + } + + // Lastly: any instruction that we don't have representation information + // for defaults to Tagged. + for (int i = 0; i < graph_->blocks()->length(); ++i) { + HBasicBlock* block = graph_->blocks()->at(i); + const ZoneList<HPhi*>* phis = block->phis(); + for (int j = 0; j < phis->length(); ++j) { + HPhi* phi = phis->at(j); + if (phi->representation().IsNone()) { + phi->ChangeRepresentation(Representation::Tagged()); + } + } + for (HInstruction* current = block->first(); + current != NULL; current = current->next()) { + if (current->representation().IsNone() && + current->CheckFlag(HInstruction::kFlexibleRepresentation)) { + current->ChangeRepresentation(Representation::Tagged()); + } + } + } +} + + +void HGraph::MergeRemovableSimulates() { + for (int i = 0; i < blocks()->length(); ++i) { + HBasicBlock* block = blocks()->at(i); + // Always reset the folding candidate at the start of a block. + HSimulate* folding_candidate = NULL; + // Nasty heuristic: Never remove the first simulate in a block. This + // just so happens to have a beneficial effect on register allocation. + bool first = true; + for (HInstruction* current = block->first(); + current != NULL; current = current->next()) { + if (current->IsLeaveInlined()) { + // Never fold simulates from inlined environments into simulates + // in the outer environment. + // (Before each HEnterInlined, there is a non-foldable HSimulate + // anyway, so we get the barrier in the other direction for free.) + if (folding_candidate != NULL) { + folding_candidate->DeleteAndReplaceWith(NULL); + } + folding_candidate = NULL; + continue; + } + // If we have an HSimulate and a candidate, perform the folding. + if (!current->IsSimulate()) continue; + if (first) { + first = false; + continue; + } + HSimulate* current_simulate = HSimulate::cast(current); + if (folding_candidate != NULL) { + folding_candidate->MergeInto(current_simulate); + folding_candidate->DeleteAndReplaceWith(NULL); + folding_candidate = NULL; + } + // Check if the current simulate is a candidate for folding. + if (current_simulate->previous()->HasObservableSideEffects() && + !current_simulate->next()->IsSimulate()) { + continue; + } + if (!current_simulate->is_candidate_for_removal()) { + continue; + } + folding_candidate = current_simulate; + } } } @@ -2601,7 +2500,6 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value, } else { next = HInstruction::cast(use_value); } - // For constants we try to make the representation change at compile // time. When a representation change is not possible without loss of // information we treat constants like normal instructions and insert the @@ -2613,7 +2511,7 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value, if (value->IsConstant()) { HConstant* constant = HConstant::cast(value); // Try to create a new copy of the constant with the new representation. - new_value = is_truncating + new_value = (is_truncating && to.IsInteger32()) ? constant->CopyToTruncatedInt32(zone()) : constant->CopyToRepresentation(to, zone()); } @@ -2673,9 +2571,23 @@ void HGraph::InsertRepresentationChanges() { for (int i = 0; i < phi_list()->length(); i++) { HPhi* phi = phi_list()->at(i); if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue; - if (!phi->CheckUsesForFlag(HValue::kTruncatingToInt32)) { - phi->ClearFlag(HValue::kTruncatingToInt32); - change = true; + for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) { + // If a Phi is used as a non-truncating int32 or as a double, + // clear its "truncating" flag. + HValue* use = it.value(); + Representation input_representation = + use->RequiredInputRepresentation(it.index()); + if ((input_representation.IsInteger32() && + !use->CheckFlag(HValue::kTruncatingToInt32)) || + input_representation.IsDouble()) { + if (FLAG_trace_representation) { + PrintF("#%d Phi is not truncating because of #%d %s\n", + phi->id(), it.value()->id(), it.value()->Mnemonic()); + } + phi->ClearFlag(HValue::kTruncatingToInt32); + change = true; + break; + } } } } @@ -2690,8 +2602,9 @@ void HGraph::InsertRepresentationChanges() { // Process normal instructions. HInstruction* current = blocks_[i]->first(); while (current != NULL) { + HInstruction* next = current->next(); InsertRepresentationChangesForValue(current); - current = current->next(); + current = next; } } } @@ -2763,17 +2676,18 @@ bool Uint32Analysis::IsSafeUint32Use(HValue* val, HValue* use) { } else if (use->IsChange() || use->IsSimulate()) { // Conversions and deoptimization have special support for unt32. return true; - } else if (use->IsStoreKeyedSpecializedArrayElement()) { - // Storing a value into an external integer array is a bit level operation. - HStoreKeyedSpecializedArrayElement* store = - HStoreKeyedSpecializedArrayElement::cast(use); - - if (store->value() == val) { - // Clamping or a conversion to double should have beed inserted. - ASSERT(store->elements_kind() != EXTERNAL_PIXEL_ELEMENTS); - ASSERT(store->elements_kind() != EXTERNAL_FLOAT_ELEMENTS); - ASSERT(store->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS); - return true; + } else if (use->IsStoreKeyed()) { + HStoreKeyed* store = HStoreKeyed::cast(use); + if (store->is_external()) { + // Storing a value into an external integer array is a bit level + // operation. + if (store->value() == val) { + // Clamping or a conversion to double should have beed inserted. + ASSERT(store->elements_kind() != EXTERNAL_PIXEL_ELEMENTS); + ASSERT(store->elements_kind() != EXTERNAL_FLOAT_ELEMENTS); + ASSERT(store->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS); + return true; + } } } @@ -3085,7 +2999,9 @@ void TestContext::ReturnValue(HValue* value) { void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { ASSERT(!instr->IsControlInstruction()); owner()->AddInstruction(instr); - if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id); + if (instr->HasObservableSideEffects()) { + owner()->AddSimulate(ast_id, REMOVABLE_SIMULATE); + } } @@ -3109,7 +3025,9 @@ void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { } owner()->AddInstruction(instr); owner()->Push(instr); - if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id); + if (instr->HasObservableSideEffects()) { + owner()->AddSimulate(ast_id, REMOVABLE_SIMULATE); + } } @@ -3141,7 +3059,7 @@ void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { // this one isn't actually needed (and wouldn't work if it were targeted). if (instr->HasObservableSideEffects()) { builder->Push(instr); - builder->AddSimulate(ast_id); + builder->AddSimulate(ast_id, REMOVABLE_SIMULATE); builder->Pop(); } BuildBranch(instr); @@ -3319,9 +3237,8 @@ HGraph* HGraphBuilder::CreateGraph() { // optimization. Disable optimistic LICM in that case. Handle<Code> unoptimized_code(info()->shared_info()->code()); ASSERT(unoptimized_code->kind() == Code::FUNCTION); - Handle<Object> maybe_type_info(unoptimized_code->type_feedback_info()); Handle<TypeFeedbackInfo> type_info( - Handle<TypeFeedbackInfo>::cast(maybe_type_info)); + TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); int checksum = type_info->own_type_change_checksum(); int composite_checksum = graph()->update_type_change_checksum(checksum); graph()->set_use_optimistic_licm( @@ -3368,6 +3285,11 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { HInferRepresentation rep(this); rep.Analyze(); + // Remove HSimulate instructions that have turned out not to be needed + // after all by folding them into the following HSimulate. + // This must happen after inferring representations. + MergeRemovableSimulates(); + MarkDeoptimizeOnUndefined(); InsertRepresentationChanges(); @@ -3406,6 +3328,7 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { EliminateRedundantBoundsChecks(); DehoistSimpleArrayIndexComputations(); + if (FLAG_dead_code_elimination) DeadCodeElimination(); return true; } @@ -3432,6 +3355,8 @@ class BoundsCheckKey : public ZoneObject { static BoundsCheckKey* Create(Zone* zone, HBoundsCheck* check, int32_t* offset) { + if (!check->index()->representation().IsInteger32()) return NULL; + HValue* index_base = NULL; HConstant* constant = NULL; bool is_sub = false; @@ -3613,7 +3538,10 @@ class BoundsCheckBbData: public ZoneObject { HConstant(new_offset, Representation::Integer32()); if (*add == NULL) { new_constant->InsertBefore(check); - *add = new(BasicBlock()->zone()) HAdd(NULL, + // Because of the bounds checks elimination algorithm, the index is always + // an HAdd or an HSub here, so we can safely cast to an HBinaryOperation. + HValue* context = HBinaryOperation::cast(check->index())->context(); + *add = new(BasicBlock()->zone()) HAdd(context, original_value, new_constant); (*add)->AssumeRepresentation(representation); @@ -3682,6 +3610,7 @@ void HGraph::EliminateRedundantBoundsChecks(HBasicBlock* bb, int32_t offset; BoundsCheckKey* key = BoundsCheckKey::Create(zone(), check, &offset); + if (key == NULL) continue; BoundsCheckBbData** data_p = table->LookupOrInsert(key, zone()); BoundsCheckBbData* data = *data_p; if (data == NULL) { @@ -3743,6 +3672,7 @@ void HGraph::EliminateRedundantBoundsChecks() { static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { HValue* index = array_operation->GetKey(); + if (!index->representation().IsInteger32()) return; HConstant* constant; HValue* subexpression; @@ -3797,27 +3727,11 @@ void HGraph::DehoistSimpleArrayIndexComputations() { instr != NULL; instr = instr->next()) { ArrayInstructionInterface* array_instruction = NULL; - if (instr->IsLoadKeyedFastElement()) { - HLoadKeyedFastElement* op = HLoadKeyedFastElement::cast(instr); - array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsLoadKeyedFastDoubleElement()) { - HLoadKeyedFastDoubleElement* op = - HLoadKeyedFastDoubleElement::cast(instr); + if (instr->IsLoadKeyed()) { + HLoadKeyed* op = HLoadKeyed::cast(instr); array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsLoadKeyedSpecializedArrayElement()) { - HLoadKeyedSpecializedArrayElement* op = - HLoadKeyedSpecializedArrayElement::cast(instr); - array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsStoreKeyedFastElement()) { - HStoreKeyedFastElement* op = HStoreKeyedFastElement::cast(instr); - array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsStoreKeyedFastDoubleElement()) { - HStoreKeyedFastDoubleElement* op = - HStoreKeyedFastDoubleElement::cast(instr); - array_instruction = static_cast<ArrayInstructionInterface*>(op); - } else if (instr->IsStoreKeyedSpecializedArrayElement()) { - HStoreKeyedSpecializedArrayElement* op = - HStoreKeyedSpecializedArrayElement::cast(instr); + } else if (instr->IsStoreKeyed()) { + HStoreKeyed* op = HStoreKeyed::cast(instr); array_instruction = static_cast<ArrayInstructionInterface*>(op); } else { continue; @@ -3828,6 +3742,36 @@ void HGraph::DehoistSimpleArrayIndexComputations() { } +void HGraph::DeadCodeElimination() { + HPhase phase("H_Dead code elimination", this); + ZoneList<HInstruction*> worklist(blocks_.length(), zone()); + for (int i = 0; i < blocks()->length(); ++i) { + for (HInstruction* instr = blocks()->at(i)->first(); + instr != NULL; + instr = instr->next()) { + if (instr->IsDead()) worklist.Add(instr, zone()); + } + } + + while (!worklist.is_empty()) { + HInstruction* instr = worklist.RemoveLast(); + if (FLAG_trace_dead_code_elimination) { + HeapStringAllocator allocator; + StringStream stream(&allocator); + instr->PrintNameTo(&stream); + stream.Add(" = "); + instr->PrintTo(&stream); + PrintF("[removing dead instruction %s]\n", *stream.ToCString()); + } + instr->DeleteAndReplaceWith(NULL); + for (int i = 0; i < instr->OperandCount(); ++i) { + HValue* operand = instr->OperandAt(i); + if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone()); + } + } +} + + HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { ASSERT(current_block() != NULL); current_block()->AddInstruction(instr); @@ -3835,9 +3779,9 @@ HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { } -void HGraphBuilder::AddSimulate(BailoutId ast_id) { +void HGraphBuilder::AddSimulate(BailoutId ast_id, RemovableSimulate removable) { ASSERT(current_block() != NULL); - current_block()->AddSimulate(ast_id); + current_block()->AddSimulate(ast_id, removable); } @@ -4194,7 +4138,7 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { !clause->label()->IsStringLiteral()) || (switch_type == SMI_SWITCH && !clause->label()->IsSmiLiteral())) { - return Bailout("SwitchStatemnt: mixed label types are not supported"); + return Bailout("SwitchStatement: mixed label types are not supported"); } } @@ -4248,12 +4192,13 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { new(zone()) HCompareIDAndBranch(tag_value, label_value, Token::EQ_STRICT); - compare_->SetInputRepresentation(Representation::Integer32()); + compare_->set_observed_input_representation( + Representation::Integer32(), Representation::Integer32()); compare = compare_; } else { compare = new(zone()) HStringCompareAndBranch(context, tag_value, - label_value, - Token::EQ_STRICT); + label_value, + Token::EQ_STRICT); } compare->SetSuccessorAt(0, body_block); @@ -4612,7 +4557,8 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { // Check that we still have more keys. HCompareIDAndBranch* compare_index = new(zone()) HCompareIDAndBranch(index, limit, Token::LT); - compare_index->SetInputRepresentation(Representation::Integer32()); + compare_index->set_observed_input_representation( + Representation::Integer32(), Representation::Integer32()); HBasicBlock* loop_body = graph()->CreateBasicBlock(); HBasicBlock* loop_successor = graph()->CreateBasicBlock(); @@ -4627,10 +4573,11 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { set_current_block(loop_body); HValue* key = AddInstruction( - new(zone()) HLoadKeyedFastElement( + new(zone()) HLoadKeyed( environment()->ExpressionStackAt(2), // Enum cache. environment()->ExpressionStackAt(0), // Iteration index. - environment()->ExpressionStackAt(0))); + environment()->ExpressionStackAt(0), + FAST_ELEMENTS)); // Check if the expected map still matches that of the enumerable. // If not just deoptimize. @@ -4886,7 +4833,7 @@ void HGraphBuilder::VisitLiteral(Literal* expr) { ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); HConstant* instr = - new(zone()) HConstant(expr->handle(), Representation::Tagged()); + new(zone()) HConstant(expr->handle(), Representation::None()); return ast_context()->ReturnInstruction(instr, expr->id()); } @@ -5123,7 +5070,9 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { map)); } AddInstruction(store); - if (store->HasObservableSideEffects()) AddSimulate(key->id()); + if (store->HasObservableSideEffects()) { + AddSimulate(key->id(), REMOVABLE_SIMULATE); + } } else { CHECK_ALIVE(VisitForEffect(value)); } @@ -5235,18 +5184,14 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { // Fall through. case FAST_ELEMENTS: case FAST_HOLEY_ELEMENTS: - AddInstruction(new(zone()) HStoreKeyedFastElement( + case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + AddInstruction(new(zone()) HStoreKeyed( elements, key, value, boilerplate_elements_kind)); break; - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, - key, - value)); - break; default: UNREACHABLE(); break; @@ -5291,18 +5236,19 @@ static int ComputeLoadStoreFieldIndex(Handle<Map> type, } +void HGraphBuilder::AddCheckMapsWithTransitions(HValue* object, + Handle<Map> map) { + AddInstruction(new(zone()) HCheckNonSmi(object)); + AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); +} + + HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object, Handle<String> name, HValue* value, Handle<Map> map, - LookupResult* lookup, - bool smi_and_map_check) { + LookupResult* lookup) { ASSERT(lookup->IsFound()); - if (smi_and_map_check) { - AddInstruction(new(zone()) HCheckNonSmi(object)); - AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); - } - // If the property does not exist yet, we have to check that it wasn't made // readonly or turned into a setter by some meanwhile modifications on the // prototype chain. @@ -5371,7 +5317,7 @@ HInstruction* HGraphBuilder::BuildCallSetter(HValue* object, Handle<Map> map, Handle<JSFunction> setter, Handle<JSObject> holder) { - AddCheckConstantFunction(holder, object, map, true); + AddCheckConstantFunction(holder, object, map); AddInstruction(new(zone()) HPushArgument(object)); AddInstruction(new(zone()) HPushArgument(value)); return new(zone()) HCallConstantFunction(setter, 2); @@ -5385,8 +5331,8 @@ HInstruction* HGraphBuilder::BuildStoreNamedMonomorphic(HValue* object, // Handle a store to a known field. LookupResult lookup(isolate()); if (ComputeLoadStoreField(map, name, &lookup, true)) { - // true = needs smi and map check. - return BuildStoreNamedField(object, name, value, map, &lookup, true); + AddCheckMapsWithTransitions(object, map); + return BuildStoreNamedField(object, name, value, map, &lookup); } // No luck, do a generic store. @@ -5434,7 +5380,7 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, HInstruction* instr; if (count == types->length() && is_monomorphic_field) { AddInstruction(new(zone()) HCheckMaps(object, types, zone())); - instr = BuildLoadNamedField(object, map, &lookup, false); + instr = BuildLoadNamedField(object, map, &lookup); } else { HValue* context = environment()->LookupContext(); instr = new(zone()) HLoadNamedFieldPolymorphic(context, @@ -5477,7 +5423,7 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, set_current_block(if_true); HInstruction* instr; CHECK_ALIVE(instr = - BuildStoreNamedField(object, name, value, map, &lookup, false)); + BuildStoreNamedField(object, name, value, map, &lookup)); instr->set_position(expr->position()); // Goto will add the HSimulate for the store. AddInstruction(instr); @@ -5507,10 +5453,10 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, // unoptimized code). if (instr->HasObservableSideEffects()) { if (ast_context()->IsEffect()) { - AddSimulate(expr->id()); + AddSimulate(expr->id(), REMOVABLE_SIMULATE); } else { Push(value); - AddSimulate(expr->id()); + AddSimulate(expr->id(), REMOVABLE_SIMULATE); Drop(1); } } @@ -5553,7 +5499,7 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { Handle<JSFunction> setter; Handle<JSObject> holder; if (LookupSetter(map, name, &setter, &holder)) { - AddCheckConstantFunction(holder, object, map, true); + AddCheckConstantFunction(holder, object, map); if (FLAG_inline_accessors && TryInlineSetter(setter, expr, value)) { return; } @@ -5580,7 +5526,9 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { Push(value); instr->set_position(expr->position()); AddInstruction(instr); - if (instr->HasObservableSideEffects()) AddSimulate(expr->AssignmentId()); + if (instr->HasObservableSideEffects()) { + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); + } return ast_context()->ReturnValue(Pop()); } else { @@ -5597,7 +5545,7 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { &has_side_effects); Push(value); ASSERT(has_side_effects); // Stores always have side effects. - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); return ast_context()->ReturnValue(Pop()); } } @@ -5619,7 +5567,9 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails()); instr->set_position(position); AddInstruction(instr); - if (instr->HasObservableSideEffects()) AddSimulate(ast_id); + if (instr->HasObservableSideEffects()) { + AddSimulate(ast_id, REMOVABLE_SIMULATE); + } } else { HValue* context = environment()->LookupContext(); HGlobalObject* global_object = new(zone()) HGlobalObject(context); @@ -5633,7 +5583,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, instr->set_position(position); AddInstruction(instr); ASSERT(instr->HasObservableSideEffects()); - if (instr->HasObservableSideEffects()) AddSimulate(ast_id); + AddSimulate(ast_id, REMOVABLE_SIMULATE); } } @@ -5710,7 +5660,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { new(zone()) HStoreContextSlot(context, var->index(), mode, Top()); AddInstruction(instr); if (instr->HasObservableSideEffects()) { - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); } break; } @@ -5750,7 +5700,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { load = BuildLoadNamedGeneric(object, name, prop); } PushAndAdd(load); - if (load->HasObservableSideEffects()) AddSimulate(prop->LoadId()); + if (load->HasObservableSideEffects()) { + AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); + } CHECK_ALIVE(VisitForValue(expr->value())); HValue* right = Pop(); @@ -5758,7 +5710,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { HInstruction* instr = BuildBinaryOperation(operation, left, right); PushAndAdd(instr); - if (instr->HasObservableSideEffects()) AddSimulate(operation->id()); + if (instr->HasObservableSideEffects()) { + AddSimulate(operation->id(), REMOVABLE_SIMULATE); + } HInstruction* store; if (!monomorphic) { @@ -5780,7 +5734,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { // Drop the simulated receiver and value. Return the value. Drop(2); Push(instr); - if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId()); + if (store->HasObservableSideEffects()) { + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); + } return ast_context()->ReturnValue(Pop()); } else { @@ -5796,7 +5752,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { false, // is_store &has_side_effects); Push(load); - if (has_side_effects) AddSimulate(prop->LoadId()); + if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); CHECK_ALIVE(VisitForValue(expr->value())); @@ -5805,7 +5761,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { HInstruction* instr = BuildBinaryOperation(operation, left, right); PushAndAdd(instr); - if (instr->HasObservableSideEffects()) AddSimulate(operation->id()); + if (instr->HasObservableSideEffects()) { + AddSimulate(operation->id(), REMOVABLE_SIMULATE); + } expr->RecordTypeFeedback(oracle(), zone()); HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(), @@ -5817,7 +5775,7 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { Drop(3); Push(instr); ASSERT(has_side_effects); // Stores always have side effects. - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); return ast_context()->ReturnValue(Pop()); } @@ -5940,7 +5898,7 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { context, var->index(), mode, Top()); AddInstruction(instr); if (instr->HasObservableSideEffects()) { - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); } return ast_context()->ReturnValue(Pop()); } @@ -5977,13 +5935,7 @@ void HGraphBuilder::VisitThrow(Throw* expr) { HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, Handle<Map> map, - LookupResult* lookup, - bool smi_and_map_check) { - if (smi_and_map_check) { - AddInstruction(new(zone()) HCheckNonSmi(object)); - AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); - } - + LookupResult* lookup) { int index = lookup->GetLocalFieldIndexFromMap(*map); if (index < 0) { // Negative property indices are in-object properties, indexed @@ -6014,7 +5966,7 @@ HInstruction* HGraphBuilder::BuildCallGetter(HValue* object, Handle<Map> map, Handle<JSFunction> getter, Handle<JSObject> holder) { - AddCheckConstantFunction(holder, object, map, true); + AddCheckConstantFunction(holder, object, map); AddInstruction(new(zone()) HPushArgument(object)); return new(zone()) HCallConstantFunction(getter, 1); } @@ -6029,17 +5981,29 @@ HInstruction* HGraphBuilder::BuildLoadNamedMonomorphic(HValue* object, LookupResult lookup(isolate()); map->LookupDescriptor(NULL, *name, &lookup); if (lookup.IsField()) { - return BuildLoadNamedField(object, map, &lookup, true); + AddCheckMapsWithTransitions(object, map); + return BuildLoadNamedField(object, map, &lookup); } // Handle a load of a constant known function. if (lookup.IsConstantFunction()) { - AddInstruction(new(zone()) HCheckNonSmi(object)); - AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); + AddCheckMapsWithTransitions(object, map); Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); return new(zone()) HConstant(function, Representation::Tagged()); } + // Handle a load from a known field somewhere in the protoype chain. + LookupInPrototypes(map, name, &lookup); + if (lookup.IsField()) { + Handle<JSObject> prototype(JSObject::cast(map->prototype())); + Handle<JSObject> holder(lookup.holder()); + Handle<Map> holder_map(holder->map()); + AddCheckMapsWithTransitions(object, map); + HInstruction* holder_value = + AddInstruction(new(zone()) HCheckPrototypeMaps(prototype, holder)); + return BuildLoadNamedField(holder_value, holder_map, &lookup); + } + // No luck, do a generic load. return BuildLoadNamedGeneric(object, name, expr); } @@ -6072,13 +6036,6 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: case EXTERNAL_UNSIGNED_INT_ELEMENTS: { - if (!val->representation().IsInteger32()) { - val = AddInstruction(new(zone()) HChange( - val, - Representation::Integer32(), - true, // Truncate to int32. - false)); // Don't deoptimize undefined (irrelevant here). - } break; } case EXTERNAL_FLOAT_ELEMENTS: @@ -6095,13 +6052,15 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( UNREACHABLE(); break; } - return new(zone()) HStoreKeyedSpecializedArrayElement( - external_elements, checked_key, val, elements_kind); + return new(zone()) HStoreKeyed(external_elements, + checked_key, + val, + elements_kind); } else { ASSERT(val == NULL); - HLoadKeyedSpecializedArrayElement* load = - new(zone()) HLoadKeyedSpecializedArrayElement( - external_elements, checked_key, dependency, elements_kind); + HLoadKeyed* load = + new(zone()) HLoadKeyed( + external_elements, checked_key, dependency, elements_kind); if (FLAG_opt_safe_uint32_operations && elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { graph()->RecordUint32Instruction(load); @@ -6120,10 +6079,6 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, if (is_store) { ASSERT(val != NULL); switch (elements_kind) { - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - return new(zone()) HStoreKeyedFastDoubleElement( - elements, checked_key, val); case FAST_SMI_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: // Smi-only arrays need a smi check. @@ -6131,7 +6086,9 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, // Fall through. case FAST_ELEMENTS: case FAST_HOLEY_ELEMENTS: - return new(zone()) HStoreKeyedFastElement( + case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + return new(zone()) HStoreKeyed( elements, checked_key, val, elements_kind); default: UNREACHABLE(); @@ -6139,16 +6096,10 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, } } // It's an element load (!is_store). - HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ? - OMIT_HOLE_CHECK : - PERFORM_HOLE_CHECK; - if (IsFastDoubleElementsKind(elements_kind)) { - return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key, - load_dependency, mode); - } else { // Smi or Object elements. - return new(zone()) HLoadKeyedFastElement(elements, checked_key, - load_dependency, elements_kind); - } + return new(zone()) HLoadKeyed(elements, + checked_key, + load_dependency, + elements_kind); } @@ -6375,7 +6326,6 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, HInstruction* elements_kind_instr = AddInstruction(new(zone()) HElementsKind(object)); - HCompareConstantEqAndBranch* elements_kind_branch = NULL; HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object, checkspec)); HLoadExternalArrayPointer* external_elements = NULL; @@ -6406,8 +6356,9 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, if (type_todo[elements_kind]) { HBasicBlock* if_true = graph()->CreateBasicBlock(); HBasicBlock* if_false = graph()->CreateBasicBlock(); - elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( - elements_kind_instr, elements_kind, Token::EQ_STRICT); + HCompareConstantEqAndBranch* elements_kind_branch = + new(zone()) HCompareConstantEqAndBranch( + elements_kind_instr, elements_kind, Token::EQ_STRICT); elements_kind_branch->SetSuccessorAt(0, if_true); elements_kind_branch->SetSuccessorAt(1, if_false); current_block()->Finish(elements_kind_branch); @@ -6549,6 +6500,7 @@ void HGraphBuilder::EnsureArgumentsArePushedForAccess() { // Push arguments when entering inlined function. HEnterInlined* entry = function_state()->entry(); + entry->set_arguments_pushed(); ZoneList<HValue*>* arguments_values = entry->arguments_values(); @@ -6678,7 +6630,7 @@ void HGraphBuilder::VisitProperty(Property* expr) { Handle<JSFunction> getter; Handle<JSObject> holder; if (LookupGetter(map, name, &getter, &holder)) { - AddCheckConstantFunction(holder, Top(), map, true); + AddCheckConstantFunction(holder, Top(), map); if (FLAG_inline_accessors && TryInlineGetter(getter, expr)) return; AddInstruction(new(zone()) HPushArgument(Pop())); instr = new(zone()) HCallConstantFunction(getter, 1); @@ -6704,10 +6656,10 @@ void HGraphBuilder::VisitProperty(Property* expr) { &has_side_effects); if (has_side_effects) { if (ast_context()->IsEffect()) { - AddSimulate(expr->id()); + AddSimulate(expr->id(), REMOVABLE_SIMULATE); } else { Push(load); - AddSimulate(expr->id()); + AddSimulate(expr->id(), REMOVABLE_SIMULATE); Drop(1); } } @@ -6718,22 +6670,23 @@ void HGraphBuilder::VisitProperty(Property* expr) { } +void HGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, + Handle<Map> receiver_map) { + if (!holder.is_null()) { + AddInstruction(new(zone()) HCheckPrototypeMaps( + Handle<JSObject>(JSObject::cast(receiver_map->prototype())), holder)); + } +} + + void HGraphBuilder::AddCheckConstantFunction(Handle<JSObject> holder, HValue* receiver, - Handle<Map> receiver_map, - bool smi_and_map_check) { + Handle<Map> receiver_map) { // Constant functions have the nice property that the map will change if they // are overwritten. Therefore it is enough to check the map of the holder and // its prototypes. - if (smi_and_map_check) { - AddInstruction(new(zone()) HCheckNonSmi(receiver)); - AddInstruction(HCheckMaps::NewWithTransitions(receiver, receiver_map, - zone())); - } - if (!holder.is_null()) { - AddInstruction(new(zone()) HCheckPrototypeMaps( - Handle<JSObject>(JSObject::cast(receiver_map->prototype())), holder)); - } + AddCheckMapsWithTransitions(receiver, receiver_map); + AddCheckPrototypeMaps(holder, receiver_map); } @@ -6815,7 +6768,7 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, set_current_block(if_true); expr->ComputeTarget(map, name); - AddCheckConstantFunction(expr->holder(), receiver, map, false); + AddCheckPrototypeMaps(expr->holder(), map); if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { Handle<JSFunction> caller = info()->closure(); SmartArrayPointer<char> caller_name = @@ -7161,9 +7114,8 @@ bool HGraphBuilder::TryInline(CallKind call_kind, inlined_count_ += nodes_added; ASSERT(unoptimized_code->kind() == Code::FUNCTION); - Handle<Object> maybe_type_info(unoptimized_code->type_feedback_info()); Handle<TypeFeedbackInfo> type_info( - Handle<TypeFeedbackInfo>::cast(maybe_type_info)); + TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); graph()->update_type_change_checksum(type_info->own_type_change_checksum()); TraceInline(target, caller, NULL); @@ -7301,6 +7253,9 @@ bool HGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra) { if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); switch (id) { + case kMathExp: + if (!FLAG_fast_math) break; + // Fall through if FLAG_fast_math. case kMathRound: case kMathAbs: case kMathSqrt: @@ -7361,6 +7316,9 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, return true; } break; + case kMathExp: + if (!FLAG_fast_math) break; + // Fall through if FLAG_fast_math. case kMathRound: case kMathFloor: case kMathAbs: @@ -7370,7 +7328,7 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, case kMathCos: case kMathTan: if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); HValue* argument = Pop(); HValue* context = environment()->LookupContext(); Drop(1); // Receiver. @@ -7383,7 +7341,7 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, break; case kMathPow: if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); HValue* right = Pop(); HValue* left = Pop(); Pop(); // Pop receiver. @@ -7425,7 +7383,7 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, break; case kMathRandom: if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); Drop(1); // Receiver. HValue* context = environment()->LookupContext(); HGlobalObject* global_object = new(zone()) HGlobalObject(context); @@ -7438,7 +7396,7 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr, case kMathMax: case kMathMin: if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); HValue* right = Pop(); HValue* left = Pop(); Drop(1); // Receiver. @@ -7487,7 +7445,7 @@ bool HGraphBuilder::TryCallApply(Call* expr) { VisitForValue(prop->obj()); if (HasStackOverflow() || current_block() == NULL) return true; HValue* function = Top(); - AddCheckConstantFunction(expr->holder(), function, function_map, true); + AddCheckConstantFunction(expr->holder(), function, function_map); Drop(1); VisitForValue(args->at(0)); @@ -7537,6 +7495,55 @@ bool HGraphBuilder::TryCallApply(Call* expr) { } +// Checks if all maps in |types| are from the same family, i.e., are elements +// transitions of each other. Returns either NULL if they are not from the same +// family, or a Map* indicating the map with the first elements kind of the +// family that is in the list. +static Map* CheckSameElementsFamily(SmallMapList* types) { + if (types->length() <= 1) return NULL; + // Check if all maps belong to the same transition family. + Map* kinds[kFastElementsKindCount]; + Map* first_map = *types->first(); + ElementsKind first_kind = first_map->elements_kind(); + if (!IsFastElementsKind(first_kind)) return NULL; + int first_index = GetSequenceIndexFromFastElementsKind(first_kind); + int last_index = first_index; + + for (int i = 0; i < kFastElementsKindCount; i++) kinds[i] = NULL; + + kinds[first_index] = first_map; + + for (int i = 1; i < types->length(); ++i) { + Map* map = *types->at(i); + ElementsKind elements_kind = map->elements_kind(); + if (!IsFastElementsKind(elements_kind)) return NULL; + int index = GetSequenceIndexFromFastElementsKind(elements_kind); + if (index < first_index) { + first_index = index; + } else if (index > last_index) { + last_index = index; + } else if (kinds[index] != map) { + return NULL; + } + kinds[index] = map; + } + + Map* current = kinds[first_index]; + for (int i = first_index + 1; i <= last_index; i++) { + Map* next = kinds[i]; + if (next != NULL) { + ElementsKind current_kind = next->elements_kind(); + if (next != current->LookupElementsTransitionMap(current_kind)) { + return NULL; + } + current = next; + } + } + + return kinds[first_index]; +} + + void HGraphBuilder::VisitCall(Call* expr) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); @@ -7576,15 +7583,25 @@ void HGraphBuilder::VisitCall(Call* expr) { CHECK_ALIVE(VisitExpressions(expr->arguments())); Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); - SmallMapList* types = expr->GetReceiverTypes(); - HValue* receiver = - environment()->ExpressionStackAt(expr->arguments()->length()); - if (expr->IsMonomorphic()) { - Handle<Map> receiver_map = (types == NULL || types->is_empty()) + bool monomorphic = expr->IsMonomorphic(); + Handle<Map> receiver_map; + if (monomorphic) { + receiver_map = (types == NULL || types->is_empty()) ? Handle<Map>::null() : types->first(); + } else { + Map* family_map = CheckSameElementsFamily(types); + if (family_map != NULL) { + receiver_map = Handle<Map>(family_map); + monomorphic = expr->ComputeTarget(receiver_map, name); + } + } + + HValue* receiver = + environment()->ExpressionStackAt(expr->arguments()->length()); + if (monomorphic) { if (TryInlineBuiltinMethodCall(expr, receiver, receiver_map, @@ -7606,7 +7623,7 @@ void HGraphBuilder::VisitCall(Call* expr) { call = PreProcessCall( new(zone()) HCallNamed(context, name, argument_count)); } else { - AddCheckConstantFunction(expr->holder(), receiver, receiver_map, true); + AddCheckConstantFunction(expr->holder(), receiver, receiver_map); if (TryInlineCall(expr)) return; call = PreProcessCall( @@ -7629,7 +7646,7 @@ void HGraphBuilder::VisitCall(Call* expr) { VariableProxy* proxy = expr->expression()->AsVariableProxy(); bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); - if (proxy != NULL && proxy->var()->is_possibly_eval()) { + if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { return Bailout("possible direct call to eval"); } @@ -7955,14 +7972,13 @@ void HGraphBuilder::VisitSub(UnaryOperation* expr) { HInstruction* instr = new(zone()) HMul(context, value, graph_->GetConstantMinus1()); TypeInfo info = oracle()->UnaryType(expr); + Representation rep = ToRepresentation(info); if (info.IsUninitialized()) { AddInstruction(new(zone()) HSoftDeoptimize); current_block()->MarkAsDeoptimizing(); info = TypeInfo::Unknown(); } - Representation rep = ToRepresentation(info); - TraceRepresentation(expr->op(), info, instr, rep); - instr->AssumeRepresentation(rep); + HBinaryOperation::cast(instr)->set_observed_input_representation(rep, rep); return ast_context()->ReturnInstruction(instr, expr->id()); } @@ -8051,8 +8067,11 @@ HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input, : graph_->GetConstantMinus1(); HValue* context = environment()->LookupContext(); HInstruction* instr = new(zone()) HAdd(context, Top(), delta); - TraceRepresentation(expr->op(), info, instr, rep); + // We can't insert a simulate here, because it would break deoptimization, + // so the HAdd must not have side effects, so we must freeze its + // representation. instr->AssumeRepresentation(rep); + instr->ClearAllSideEffects(); AddInstruction(instr); return instr; } @@ -8126,7 +8145,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { new(zone()) HStoreContextSlot(context, var->index(), mode, after); AddInstruction(instr); if (instr->HasObservableSideEffects()) { - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); } break; } @@ -8167,7 +8186,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { load = BuildLoadNamedGeneric(object, name, prop); } PushAndAdd(load); - if (load->HasObservableSideEffects()) AddSimulate(prop->LoadId()); + if (load->HasObservableSideEffects()) { + AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); + } after = BuildIncrement(returns_original_input, expr); input = Pop(); @@ -8195,7 +8216,9 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { // necessary. environment()->SetExpressionStackAt(0, after); if (returns_original_input) environment()->SetExpressionStackAt(1, input); - if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId()); + if (store->HasObservableSideEffects()) { + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); + } } else { // Keyed property. @@ -8212,7 +8235,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { false, // is_store &has_side_effects); Push(load); - if (has_side_effects) AddSimulate(prop->LoadId()); + if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); after = BuildIncrement(returns_original_input, expr); input = Pop(); @@ -8230,7 +8253,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { environment()->SetExpressionStackAt(0, after); if (returns_original_input) environment()->SetExpressionStackAt(1, input); ASSERT(has_side_effects); // Stores always have side effects. - AddSimulate(expr->AssignmentId()); + AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); } } @@ -8251,21 +8274,82 @@ HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* context, return new(zone()) HStringCharCodeAt(context, string, checked_index); } +// Checks if the given shift amounts have form: (sa) and (32 - sa). +static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, + HValue* const32_minus_sa) { + if (!const32_minus_sa->IsSub()) return false; + HSub* sub = HSub::cast(const32_minus_sa); + HValue* const32 = sub->left(); + if (!const32->IsConstant() || + HConstant::cast(const32)->Integer32Value() != 32) { + return false; + } + return (sub->right() == sa); +} + + +// Checks if the left and the right are shift instructions with the oposite +// directions that can be replaced by one rotate right instruction or not. +// Returns the operand and the shift amount for the rotate instruction in the +// former case. +bool HGraphBuilder::MatchRotateRight(HValue* left, + HValue* right, + HValue** operand, + HValue** shift_amount) { + HShl* shl; + HShr* shr; + if (left->IsShl() && right->IsShr()) { + shl = HShl::cast(left); + shr = HShr::cast(right); + } else if (left->IsShr() && right->IsShl()) { + shl = HShl::cast(right); + shr = HShr::cast(left); + } else { + return false; + } + + if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) && + !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) { + return false; + } + *operand= shr->left(); + *shift_amount = shr->right(); + return true; +} + + +bool CanBeZero(HValue *right) { + if (right->IsConstant()) { + HConstant* right_const = HConstant::cast(right); + if (right_const->HasInteger32Value() && + (right_const->Integer32Value() & 0x1f) != 0) { + return false; + } + } + return true; +} + HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, HValue* left, HValue* right) { HValue* context = environment()->LookupContext(); - TypeInfo info = oracle()->BinaryType(expr); - if (info.IsUninitialized()) { + TypeInfo left_info, right_info, result_info, combined_info; + oracle()->BinaryType(expr, &left_info, &right_info, &result_info); + Representation left_rep = ToRepresentation(left_info); + Representation right_rep = ToRepresentation(right_info); + Representation result_rep = ToRepresentation(result_info); + if (left_info.IsUninitialized()) { + // Can't have initialized one but not the other. + ASSERT(right_info.IsUninitialized()); AddInstruction(new(zone()) HSoftDeoptimize); current_block()->MarkAsDeoptimizing(); - info = TypeInfo::Unknown(); + left_info = right_info = TypeInfo::Unknown(); } HInstruction* instr = NULL; switch (expr->op()) { case Token::ADD: - if (info.IsString()) { + if (left_info.IsString() && right_info.IsString()) { AddInstruction(new(zone()) HCheckNonSmi(left)); AddInstruction(HCheckInstanceType::NewIsString(left, zone())); AddInstruction(new(zone()) HCheckNonSmi(right)); @@ -8289,25 +8373,26 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, break; case Token::BIT_XOR: case Token::BIT_AND: - case Token::BIT_OR: instr = HBitwise::NewHBitwise(zone(), expr->op(), context, left, right); break; + case Token::BIT_OR: { + HValue* operand, *shift_amount; + if (left_info.IsInteger32() && right_info.IsInteger32() && + MatchRotateRight(left, right, &operand, &shift_amount)) { + instr = new(zone()) HRor(context, operand, shift_amount); + } else { + instr = HBitwise::NewHBitwise(zone(), expr->op(), context, left, right); + } + break; + } case Token::SAR: instr = HSar::NewHSar(zone(), context, left, right); break; case Token::SHR: instr = HShr::NewHShr(zone(), context, left, right); - if (FLAG_opt_safe_uint32_operations && instr->IsShr()) { - bool can_be_shift_by_zero = true; - if (right->IsConstant()) { - HConstant* right_const = HConstant::cast(right); - if (right_const->HasInteger32Value() && - (right_const->Integer32Value() & 0x1f) != 0) { - can_be_shift_by_zero = false; - } - } - - if (can_be_shift_by_zero) graph()->RecordUint32Instruction(instr); + if (FLAG_opt_safe_uint32_operations && instr->IsShr() && + CanBeZero(right)) { + graph()->RecordUint32Instruction(instr); } break; case Token::SHL: @@ -8317,23 +8402,11 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, UNREACHABLE(); } - // If we hit an uninitialized binary op stub we will get type info - // for a smi operation. If one of the operands is a constant string - // do not generate code assuming it is a smi operation. - if (info.IsSmi() && - ((left->IsConstant() && HConstant::cast(left)->handle()->IsString()) || - (right->IsConstant() && HConstant::cast(right)->handle()->IsString()))) { - return instr; - } - Representation rep = ToRepresentation(info); - // We only generate either int32 or generic tagged bitwise operations. - if (instr->IsBitwiseBinaryOperation()) { - HBitwiseBinaryOperation::cast(instr)-> - InitializeObservedInputRepresentation(rep); - if (rep.IsDouble()) rep = Representation::Integer32(); + if (instr->IsBinaryOperation()) { + HBinaryOperation* binop = HBinaryOperation::cast(instr); + binop->set_observed_input_representation(left_rep, right_rep); + binop->initialize_output_representation(result_rep); } - TraceRepresentation(expr->op(), info, instr, rep); - instr->AssumeRepresentation(rep); return instr; } @@ -8477,27 +8550,8 @@ void HGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { } -void HGraphBuilder::TraceRepresentation(Token::Value op, - TypeInfo info, - HValue* value, - Representation rep) { - if (!FLAG_trace_representation) return; - // TODO(svenpanne) Under which circumstances are we actually not flexible? - // At first glance, this looks a bit weird... - bool flexible = value->CheckFlag(HValue::kFlexibleRepresentation); - PrintF("Operation %s has type info %s, %schange representation assumption " - "for %s (ID %d) from %s to %s\n", - Token::Name(op), - info.ToString(), - flexible ? "" : " DO NOT ", - value->Mnemonic(), - graph_->GetMaximumValueID(), - value->representation().Mnemonic(), - rep.Mnemonic()); -} - - Representation HGraphBuilder::ToRepresentation(TypeInfo info) { + if (info.IsUninitialized()) return Representation::None(); if (info.IsSmi()) return Representation::Integer32(); if (info.IsInteger32()) return Representation::Integer32(); if (info.IsDouble()) return Representation::Double(); @@ -8595,13 +8649,17 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { return ast_context()->ReturnControl(instr, expr->id()); } - TypeInfo type_info = oracle()->CompareType(expr); + TypeInfo left_type, right_type, overall_type_info; + oracle()->CompareType(expr, &left_type, &right_type, &overall_type_info); + Representation combined_rep = ToRepresentation(overall_type_info); + Representation left_rep = ToRepresentation(left_type); + Representation right_rep = ToRepresentation(right_type); // Check if this expression was ever executed according to type feedback. // Note that for the special typeof/null/undefined cases we get unknown here. - if (type_info.IsUninitialized()) { + if (overall_type_info.IsUninitialized()) { AddInstruction(new(zone()) HSoftDeoptimize); current_block()->MarkAsDeoptimizing(); - type_info = TypeInfo::Unknown(); + overall_type_info = left_type = right_type = TypeInfo::Unknown(); } CHECK_ALIVE(VisitForValue(expr->left())); @@ -8673,17 +8731,15 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { HIn* result = new(zone()) HIn(context, left, right); result->set_position(expr->position()); return ast_context()->ReturnInstruction(result, expr->id()); - } else if (type_info.IsNonPrimitive()) { + } else if (overall_type_info.IsNonPrimitive()) { switch (op) { case Token::EQ: case Token::EQ_STRICT: { // Can we get away with map check and not instance type check? Handle<Map> map = oracle()->GetCompareMap(expr); if (!map.is_null()) { - AddInstruction(new(zone()) HCheckNonSmi(left)); - AddInstruction(HCheckMaps::NewWithTransitions(left, map, zone())); - AddInstruction(new(zone()) HCheckNonSmi(right)); - AddInstruction(HCheckMaps::NewWithTransitions(right, map, zone())); + AddCheckMapsWithTransitions(left, map); + AddCheckMapsWithTransitions(right, map); HCompareObjectEqAndBranch* result = new(zone()) HCompareObjectEqAndBranch(left, right); result->set_position(expr->position()); @@ -8702,8 +8758,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { default: return Bailout("Unsupported non-primitive compare"); } - } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) && - (op == Token::EQ || op == Token::EQ_STRICT)) { + } else if (overall_type_info.IsSymbol() && Token::IsEqualityOp(op)) { AddInstruction(new(zone()) HCheckNonSmi(left)); AddInstruction(HCheckInstanceType::NewIsSymbol(left, zone())); AddInstruction(new(zone()) HCheckNonSmi(right)); @@ -8713,17 +8768,17 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { result->set_position(expr->position()); return ast_context()->ReturnControl(result, expr->id()); } else { - Representation r = ToRepresentation(type_info); - if (r.IsTagged()) { + if (combined_rep.IsTagged() || combined_rep.IsNone()) { HCompareGeneric* result = new(zone()) HCompareGeneric(context, left, right, op); + result->set_observed_input_representation(left_rep, right_rep); result->set_position(expr->position()); return ast_context()->ReturnInstruction(result, expr->id()); } else { HCompareIDAndBranch* result = new(zone()) HCompareIDAndBranch(left, right, op); + result->set_observed_input_representation(left_rep, right_rep); result->set_position(expr->position()); - result->SetInputRepresentation(r); return ast_context()->ReturnControl(result, expr->id()); } } @@ -8810,7 +8865,9 @@ void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* declaration) { HStoreContextSlot* store = new(zone()) HStoreContextSlot( context, variable->index(), HStoreContextSlot::kNoCheck, value); AddInstruction(store); - if (store->HasObservableSideEffects()) AddSimulate(proxy->id()); + if (store->HasObservableSideEffects()) { + AddSimulate(proxy->id(), REMOVABLE_SIMULATE); + } } break; case Variable::LOOKUP: @@ -8846,7 +8903,9 @@ void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* declaration) { HStoreContextSlot* store = new(zone()) HStoreContextSlot( context, variable->index(), HStoreContextSlot::kNoCheck, value); AddInstruction(store); - if (store->HasObservableSideEffects()) AddSimulate(proxy->id()); + if (store->HasObservableSideEffects()) { + AddSimulate(proxy->id(), REMOVABLE_SIMULATE); + } break; } case Variable::LOOKUP: @@ -8890,6 +8949,11 @@ void HGraphBuilder::VisitModuleUrl(ModuleUrl* module) { } +void HGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) { + UNREACHABLE(); +} + + // Generators for inline runtime functions. // Support for types. void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { @@ -9025,8 +9089,10 @@ void HGraphBuilder::GenerateArguments(CallRuntime* call) { HInstruction* elements = AddInstruction( new(zone()) HArgumentsElements(false)); HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); + HInstruction* checked_index = + AddInstruction(new(zone()) HBoundsCheck(index, length)); HAccessArgumentsAt* result = - new(zone()) HAccessArgumentsAt(elements, length, index); + new(zone()) HAccessArgumentsAt(elements, length, checked_index); return ast_context()->ReturnInstruction(result, call->id()); } @@ -9059,6 +9125,39 @@ void HGraphBuilder::GenerateDateField(CallRuntime* call) { } +void HGraphBuilder::GenerateOneByteSeqStringSetChar( + CallRuntime* call) { + ASSERT(call->arguments()->length() == 3); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); + CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); + HValue* value = Pop(); + HValue* index = Pop(); + HValue* string = Pop(); + HSeqStringSetChar* result = new(zone()) HSeqStringSetChar( + String::ONE_BYTE_ENCODING, string, index, value); + return ast_context()->ReturnInstruction(result, call->id()); +} + + +void HGraphBuilder::GenerateTwoByteSeqStringSetChar( + CallRuntime* call) { + ASSERT(call->arguments()->length() == 3); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); + CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); + HValue* value = Pop(); + HValue* index = Pop(); + HValue* string = Pop(); + HValue* context = environment()->LookupContext(); + HStringCharCodeAt* char_code = BuildStringCharCodeAt(context, string, index); + AddInstruction(char_code); + HSeqStringSetChar* result = new(zone()) HSeqStringSetChar( + String::TWO_BYTE_ENCODING, string, index, value); + return ast_context()->ReturnInstruction(result, call->id()); +} + + void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) { ASSERT(call->arguments()->length() == 2); CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); @@ -9391,6 +9490,7 @@ HEnvironment::HEnvironment(HEnvironment* outer, specials_count_(1), local_count_(0), outer_(outer), + entry_(NULL), pop_count_(0), push_count_(0), ast_id_(BailoutId::None()), @@ -9407,6 +9507,7 @@ HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone) specials_count_(1), local_count_(0), outer_(NULL), + entry_(NULL), pop_count_(0), push_count_(0), ast_id_(other->ast_id()), @@ -9427,6 +9528,7 @@ HEnvironment::HEnvironment(HEnvironment* outer, parameter_count_(arguments), local_count_(0), outer_(outer), + entry_(NULL), pop_count_(0), push_count_(0), ast_id_(BailoutId::None()), @@ -9455,6 +9557,7 @@ void HEnvironment::Initialize(const HEnvironment* other) { parameter_count_ = other->parameter_count_; local_count_ = other->local_count_; if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. + entry_ = other->entry_; pop_count_ = other->pop_count_; push_count_ = other->push_count_; ast_id_ = other->ast_id_; @@ -9900,28 +10003,43 @@ void HStatistics::Print() { double size_percent = static_cast<double>(size) * 100 / total_size_; PrintF(" %8u bytes / %4.1f %%\n", size, size_percent); } + + PrintF("---------------------------------------------------------------\n"); + int64_t total = create_graph_ + optimize_graph_ + generate_code_; + PrintF("%30s - %7.3f ms / %4.1f %% \n", + "Create graph", + static_cast<double>(create_graph_) / 1000, + static_cast<double>(create_graph_) * 100 / total); + PrintF("%30s - %7.3f ms / %4.1f %% \n", + "Optimize graph", + static_cast<double>(optimize_graph_) / 1000, + static_cast<double>(optimize_graph_) * 100 / total); + PrintF("%30s - %7.3f ms / %4.1f %% \n", + "Generate and install code", + static_cast<double>(generate_code_) / 1000, + static_cast<double>(generate_code_) * 100 / total); + PrintF("---------------------------------------------------------------\n"); + PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n", + "Total", + static_cast<double>(total) / 1000, + static_cast<double>(total) / full_code_gen_); + double source_size_in_kb = static_cast<double>(source_size_) / 1024; double normalized_time = source_size_in_kb > 0 - ? (static_cast<double>(sum) / 1000) / source_size_in_kb + ? (static_cast<double>(total) / 1000) / source_size_in_kb : 0; - double normalized_bytes = source_size_in_kb > 0 - ? total_size_ / source_size_in_kb + double normalized_size_in_kb = source_size_in_kb > 0 + ? total_size_ / 1024 / source_size_in_kb : 0; - PrintF("%30s - %7.3f ms %7.3f bytes\n", "Sum", - normalized_time, normalized_bytes); - PrintF("---------------------------------------------------------------\n"); - PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n", - "Total", - static_cast<double>(total_) / 1000, - static_cast<double>(total_) / full_code_gen_); + PrintF("%30s - %7.3f ms %7.3f kB allocated\n", + "Average per kB source", + normalized_time, normalized_size_in_kb); } void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { if (name == HPhase::kFullCodeGen) { full_code_gen_ += ticks; - } else if (name == HPhase::kTotal) { - total_ += ticks; } else { total_size_ += size; for (int i = 0; i < names_.length(); ++i) { @@ -9939,8 +10057,6 @@ void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { const char* const HPhase::kFullCodeGen = "Full code generator"; -const char* const HPhase::kTotal = "Total"; - void HPhase::Begin(const char* name, HGraph* graph, diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index 7d23ac7306..98b05d147a 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -125,7 +125,10 @@ class HBasicBlock: public ZoneObject { void Goto(HBasicBlock* block, FunctionState* state = NULL); int PredecessorIndexOf(HBasicBlock* predecessor) const; - void AddSimulate(BailoutId ast_id) { AddInstruction(CreateSimulate(ast_id)); } + void AddSimulate(BailoutId ast_id, + RemovableSimulate removable = FIXED_SIMULATE) { + AddInstruction(CreateSimulate(ast_id, removable)); + } void AssignCommonDominator(HBasicBlock* other); void AssignLoopSuccessorDominators(); @@ -166,7 +169,7 @@ class HBasicBlock: public ZoneObject { void RegisterPredecessor(HBasicBlock* pred); void AddDominatedBlock(HBasicBlock* block); - HSimulate* CreateSimulate(BailoutId ast_id); + HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable); HDeoptimize* CreateDeoptimize(HDeoptimize::UseEnvironment has_uses); int block_id_; @@ -255,6 +258,7 @@ class HGraph: public ZoneObject { void InitializeInferredTypes(); void InsertTypeConversions(); + void MergeRemovableSimulates(); void InsertRepresentationChanges(); void MarkDeoptimizeOnUndefined(); void ComputeMinusZeroChecks(); @@ -268,7 +272,9 @@ class HGraph: public ZoneObject { void ReplaceCheckedValues(); void EliminateRedundantBoundsChecks(); void DehoistSimpleArrayIndexComputations(); + void DeadCodeElimination(); void PropagateDeoptimizingMark(); + void EliminateUnusedInstructions(); // Returns false if there are phi-uses of the arguments-object // which are not supported by the optimizing compiler. @@ -434,13 +440,6 @@ class HEnvironment: public ZoneObject { Handle<JSFunction> closure, Zone* zone); - HEnvironment* DiscardInlined(bool drop_extra) { - HEnvironment* outer = outer_; - while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_; - if (drop_extra) outer->Drop(1); - return outer; - } - HEnvironment* arguments_environment() { return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this; } @@ -462,6 +461,9 @@ class HEnvironment: public ZoneObject { BailoutId ast_id() const { return ast_id_; } void set_ast_id(BailoutId id) { ast_id_ = id; } + HEnterInlined* entry() const { return entry_; } + void set_entry(HEnterInlined* entry) { entry_ = entry; } + int length() const { return values_.length(); } bool is_special_index(int i) const { return i >= parameter_count() && i < parameter_count() + specials_count(); @@ -540,6 +542,13 @@ class HEnvironment: public ZoneObject { CallKind call_kind, InliningKind inlining_kind) const; + HEnvironment* DiscardInlined(bool drop_extra) { + HEnvironment* outer = outer_; + while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_; + if (drop_extra) outer->Drop(1); + return outer; + } + void AddIncomingEdge(HBasicBlock* block, HEnvironment* other); void ClearHistory() { @@ -600,6 +609,7 @@ class HEnvironment: public ZoneObject { int specials_count_; int local_count_; HEnvironment* outer_; + HEnterInlined* entry_; int pop_count_; int push_count_; BailoutId ast_id_; @@ -607,6 +617,25 @@ class HEnvironment: public ZoneObject { }; +class HInferRepresentation BASE_EMBEDDED { + public: + explicit HInferRepresentation(HGraph* graph) + : graph_(graph), + worklist_(8, graph->zone()), + in_worklist_(graph->GetMaximumValueID(), graph->zone()) { } + + void Analyze(); + void AddToWorklist(HValue* current); + + private: + Zone* zone() const { return graph_->zone(); } + + HGraph* graph_; + ZoneList<HValue*> worklist_; + BitVector in_worklist_; +}; + + class HGraphBuilder; enum ArgumentsAllowedFlag { @@ -874,7 +903,8 @@ class HGraphBuilder: public AstVisitor { // Adding instructions. HInstruction* AddInstruction(HInstruction* instr); - void AddSimulate(BailoutId ast_id); + void AddSimulate(BailoutId ast_id, + RemovableSimulate removable = FIXED_SIMULATE); // Bailout environment manipulation. void Push(HValue* value) { environment()->Push(value); } @@ -1019,10 +1049,6 @@ class HGraphBuilder: public AstVisitor { // to push them as outgoing parameters. template <class Instruction> HInstruction* PreProcessCall(Instruction* call); - void TraceRepresentation(Token::Value op, - TypeInfo info, - HValue* value, - Representation rep); static Representation ToRepresentation(TypeInfo info); void SetUpScope(Scope* scope); @@ -1159,8 +1185,7 @@ class HGraphBuilder: public AstVisitor { HLoadNamedField* BuildLoadNamedField(HValue* object, Handle<Map> map, - LookupResult* result, - bool smi_and_map_check); + LookupResult* result); HInstruction* BuildLoadNamedGeneric(HValue* object, Handle<String> name, Property* expr); @@ -1181,12 +1206,14 @@ class HGraphBuilder: public AstVisitor { ElementsKind elements_kind, bool is_store); + void AddCheckMapsWithTransitions(HValue* object, + Handle<Map> map); + HInstruction* BuildStoreNamedField(HValue* object, Handle<String> name, HValue* value, Handle<Map> map, - LookupResult* lookup, - bool smi_and_map_check); + LookupResult* lookup); HInstruction* BuildStoreNamedGeneric(HValue* object, Handle<String> name, HValue* value); @@ -1207,10 +1234,17 @@ class HGraphBuilder: public AstVisitor { HInstruction* BuildThisFunction(); + void AddCheckPrototypeMaps(Handle<JSObject> holder, + Handle<Map> receiver_map); + void AddCheckConstantFunction(Handle<JSObject> holder, HValue* receiver, - Handle<Map> receiver_map, - bool smi_and_map_check); + Handle<Map> receiver_map); + + bool MatchRotateRight(HValue* left, + HValue* right, + HValue** operand, + HValue** shift_amount); Zone* zone() const { return zone_; } @@ -1344,12 +1378,22 @@ class HStatistics: public Malloced { return instance.get(); } + void IncrementSubtotals(int64_t create_graph, + int64_t optimize_graph, + int64_t generate_code) { + create_graph_ += create_graph; + optimize_graph_ += optimize_graph; + generate_code_ += generate_code; + } + private: HStatistics() : timing_(5), names_(5), sizes_(5), - total_(0), + create_graph_(0), + optimize_graph_(0), + generate_code_(0), total_size_(0), full_code_gen_(0), source_size_(0) { } @@ -1357,7 +1401,9 @@ class HStatistics: public Malloced { List<int64_t> timing_; List<const char*> names_; List<unsigned> sizes_; - int64_t total_; + int64_t create_graph_; + int64_t optimize_graph_; + int64_t generate_code_; unsigned total_size_; int64_t full_code_gen_; double source_size_; @@ -1367,7 +1413,6 @@ class HStatistics: public Malloced { class HPhase BASE_EMBEDDED { public: static const char* const kFullCodeGen; - static const char* const kTotal; explicit HPhase(const char* name) { Begin(name, NULL, NULL, NULL); } HPhase(const char* name, HGraph* graph) { diff --git a/deps/v8/src/ia32/assembler-ia32-inl.h b/deps/v8/src/ia32/assembler-ia32-inl.h index 0b47748d6b..114f878421 100644 --- a/deps/v8/src/ia32/assembler-ia32-inl.h +++ b/deps/v8/src/ia32/assembler-ia32-inl.h @@ -46,12 +46,21 @@ namespace v8 { namespace internal { +static const byte kCallOpcode = 0xE8; + + // The modes possibly affected by apply must be in kApplyMask. void RelocInfo::apply(intptr_t delta) { if (rmode_ == RUNTIME_ENTRY || IsCodeTarget(rmode_)) { int32_t* p = reinterpret_cast<int32_t*>(pc_); *p -= delta; // Relocate entry. CPU::FlushICache(p, sizeof(uint32_t)); + } else if (rmode_ == CODE_AGE_SEQUENCE) { + if (*pc_ == kCallOpcode) { + int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1); + *p -= delta; // Relocate entry. + CPU::FlushICache(p, sizeof(uint32_t)); + } } else if (rmode_ == JS_RETURN && IsPatchedReturnSequence()) { // Special handling of js_return when a break point is set (call // instruction has been inserted). @@ -169,6 +178,21 @@ void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell, } +Code* RelocInfo::code_age_stub() { + ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); + ASSERT(*pc_ == kCallOpcode); + return Code::GetCodeFromTargetAddress( + Assembler::target_address_at(pc_ + 1)); +} + + +void RelocInfo::set_code_age_stub(Code* stub) { + ASSERT(*pc_ == kCallOpcode); + ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); + Assembler::set_target_address_at(pc_ + 1, stub->instruction_start()); +} + + Address RelocInfo::call_address() { ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence())); @@ -206,7 +230,7 @@ Object** RelocInfo::call_object_address() { bool RelocInfo::IsPatchedReturnSequence() { - return *pc_ == 0xE8; + return *pc_ == kCallOpcode; } @@ -227,7 +251,9 @@ void RelocInfo::Visit(ObjectVisitor* visitor) { } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { visitor->VisitExternalReference(this); CPU::FlushICache(pc_, sizeof(Address)); -#ifdef ENABLE_DEBUGGER_SUPPORT + } else if (RelocInfo::IsCodeAgeSequence(mode)) { + visitor->VisitCodeAgeSequence(this); + #ifdef ENABLE_DEBUGGER_SUPPORT // TODO(isolates): Get a cached isolate below. } else if (((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) || @@ -255,6 +281,8 @@ void RelocInfo::Visit(Heap* heap) { } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { StaticVisitor::VisitExternalReference(this); CPU::FlushICache(pc_, sizeof(Address)); + } else if (RelocInfo::IsCodeAgeSequence(mode)) { + StaticVisitor::VisitCodeAgeSequence(heap, this); #ifdef ENABLE_DEBUGGER_SUPPORT } else if (heap->isolate()->debug()->has_break_points() && ((RelocInfo::IsJSReturn(mode) && @@ -387,6 +415,11 @@ void Assembler::set_target_address_at(Address pc, Address target) { } +Address Assembler::target_address_from_return_address(Address pc) { + return pc - kCallTargetAddressOffset; +} + + Displacement Assembler::disp_at(Label* L) { return Displacement(long_at(L->pos())); } diff --git a/deps/v8/src/ia32/assembler-ia32.cc b/deps/v8/src/ia32/assembler-ia32.cc index ea68c5090f..8cccaa5a74 100644 --- a/deps/v8/src/ia32/assembler-ia32.cc +++ b/deps/v8/src/ia32/assembler-ia32.cc @@ -169,7 +169,7 @@ void Displacement::init(Label* L, Type type) { const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY | 1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE | - 1 << RelocInfo::DEBUG_BREAK_SLOT; + 1 << RelocInfo::DEBUG_BREAK_SLOT | 1 << RelocInfo::CODE_AGE_SEQUENCE; bool RelocInfo::IsCodedSpecially() { @@ -312,48 +312,19 @@ Register Operand::reg() const { static void InitCoverageLog(); #endif -Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size) - : AssemblerBase(arg_isolate), - positions_recorder_(this), - emit_debug_code_(FLAG_debug_code) { - if (buffer == NULL) { - // Do our own buffer management. - if (buffer_size <= kMinimalBufferSize) { - buffer_size = kMinimalBufferSize; - - if (isolate()->assembler_spare_buffer() != NULL) { - buffer = isolate()->assembler_spare_buffer(); - isolate()->set_assembler_spare_buffer(NULL); - } - } - if (buffer == NULL) { - buffer_ = NewArray<byte>(buffer_size); - } else { - buffer_ = static_cast<byte*>(buffer); - } - buffer_size_ = buffer_size; - own_buffer_ = true; - } else { - // Use externally provided buffer instead. - ASSERT(buffer_size > 0); - buffer_ = static_cast<byte*>(buffer); - buffer_size_ = buffer_size; - own_buffer_ = false; - } - +Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) + : AssemblerBase(isolate, buffer, buffer_size), + positions_recorder_(this) { // Clear the buffer in debug mode unless it was provided by the // caller in which case we can't be sure it's okay to overwrite // existing code in it; see CodePatcher::CodePatcher(...). #ifdef DEBUG if (own_buffer_) { - memset(buffer_, 0xCC, buffer_size); // int3 + memset(buffer_, 0xCC, buffer_size_); // int3 } #endif - // Set up buffer pointers. - ASSERT(buffer_ != NULL); - pc_ = buffer_; - reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); + reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); #ifdef GENERATED_CODE_COVERAGE InitCoverageLog(); @@ -361,18 +332,6 @@ Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size) } -Assembler::~Assembler() { - if (own_buffer_) { - if (isolate()->assembler_spare_buffer() == NULL && - buffer_size_ == kMinimalBufferSize) { - isolate()->set_assembler_spare_buffer(buffer_); - } else { - DeleteArray(buffer_); - } - } -} - - void Assembler::GetCode(CodeDesc* desc) { // Finalize code (at this point overflow() may be true, but the gap ensures // that we are still not overlapping instructions and relocation info). @@ -1064,6 +1023,25 @@ void Assembler::rcr(Register dst, uint8_t imm8) { } } +void Assembler::ror(Register dst, uint8_t imm8) { + EnsureSpace ensure_space(this); + ASSERT(is_uint5(imm8)); // illegal shift count + if (imm8 == 1) { + EMIT(0xD1); + EMIT(0xC8 | dst.code()); + } else { + EMIT(0xC1); + EMIT(0xC8 | dst.code()); + EMIT(imm8); + } +} + +void Assembler::ror_cl(Register dst) { + EnsureSpace ensure_space(this); + EMIT(0xD3); + EMIT(0xC8 | dst.code()); +} + void Assembler::sar(Register dst, uint8_t imm8) { EnsureSpace ensure_space(this); @@ -1501,7 +1479,7 @@ void Assembler::jmp(Handle<Code> code, RelocInfo::Mode rmode) { void Assembler::j(Condition cc, Label* L, Label::Distance distance) { EnsureSpace ensure_space(this); - ASSERT(0 <= cc && cc < 16); + ASSERT(0 <= cc && static_cast<int>(cc) < 16); if (L->is_bound()) { const int short_size = 2; const int long_size = 6; @@ -1533,7 +1511,7 @@ void Assembler::j(Condition cc, Label* L, Label::Distance distance) { void Assembler::j(Condition cc, byte* entry, RelocInfo::Mode rmode) { EnsureSpace ensure_space(this); - ASSERT((0 <= cc) && (cc < 16)); + ASSERT((0 <= cc) && (static_cast<int>(cc) < 16)); // 0000 1111 1000 tttn #32-bit disp. EMIT(0x0F); EMIT(0x80 | cc); @@ -1988,6 +1966,16 @@ void Assembler::addsd(XMMRegister dst, XMMRegister src) { } +void Assembler::addsd(XMMRegister dst, const Operand& src) { + ASSERT(CpuFeatures::IsEnabled(SSE2)); + EnsureSpace ensure_space(this); + EMIT(0xF2); + EMIT(0x0F); + EMIT(0x58); + emit_sse_operand(dst, src); +} + + void Assembler::mulsd(XMMRegister dst, XMMRegister src) { ASSERT(CpuFeatures::IsEnabled(SSE2)); EnsureSpace ensure_space(this); @@ -1998,6 +1986,16 @@ void Assembler::mulsd(XMMRegister dst, XMMRegister src) { } +void Assembler::mulsd(XMMRegister dst, const Operand& src) { + ASSERT(CpuFeatures::IsEnabled(SSE2)); + EnsureSpace ensure_space(this); + EMIT(0xF2); + EMIT(0x0F); + EMIT(0x59); + emit_sse_operand(dst, src); +} + + void Assembler::subsd(XMMRegister dst, XMMRegister src) { ASSERT(CpuFeatures::IsEnabled(SSE2)); EnsureSpace ensure_space(this); @@ -2105,6 +2103,16 @@ void Assembler::movmskpd(Register dst, XMMRegister src) { } +void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) { + ASSERT(CpuFeatures::IsEnabled(SSE2)); + EnsureSpace ensure_space(this); + EMIT(0x66); + EMIT(0x0F); + EMIT(0x76); + emit_sse_operand(dst, src); +} + + void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) { ASSERT(CpuFeatures::IsEnabled(SSE2)); EnsureSpace ensure_space(this); @@ -2384,7 +2392,7 @@ void Assembler::psrlq(XMMRegister dst, XMMRegister src) { } -void Assembler::pshufd(XMMRegister dst, XMMRegister src, int8_t shuffle) { +void Assembler::pshufd(XMMRegister dst, XMMRegister src, uint8_t shuffle) { ASSERT(CpuFeatures::IsEnabled(SSE2)); EnsureSpace ensure_space(this); EMIT(0x66); diff --git a/deps/v8/src/ia32/assembler-ia32.h b/deps/v8/src/ia32/assembler-ia32.h index f95e7b797c..b1f421ec86 100644 --- a/deps/v8/src/ia32/assembler-ia32.h +++ b/deps/v8/src/ia32/assembler-ia32.h @@ -582,15 +582,7 @@ class Assembler : public AssemblerBase { // upon destruction of the assembler. // TODO(vitalyr): the assembler does not need an isolate. Assembler(Isolate* isolate, void* buffer, int buffer_size); - ~Assembler(); - - // Overrides the default provided by FLAG_debug_code. - void set_emit_debug_code(bool value) { emit_debug_code_ = value; } - - // Avoids using instructions that vary in size in unpredictable ways between - // the snapshot and the running VM. This is needed by the full compiler so - // that it can recompile code with debug support and fix the PC. - void set_predictable_code_size(bool value) { predictable_code_size_ = value; } + virtual ~Assembler() { } // GetCode emits any pending (non-emitted) code and fills the descriptor // desc. GetCode() is idempotent; it returns the same result if no other @@ -601,6 +593,10 @@ class Assembler : public AssemblerBase { inline static Address target_address_at(Address pc); inline static void set_target_address_at(Address pc, Address target); + // Return the code target address at a call site from the return address + // of that call in the instruction stream. + inline static Address target_address_from_return_address(Address pc); + // This sets the branch destination (which is in the instruction on x86). // This is for calls and branches within generated code. inline static void deserialization_set_special_target_at( @@ -629,6 +625,7 @@ class Assembler : public AssemblerBase { static const int kPatchDebugBreakSlotAddressOffset = 1; // JMP imm32. static const int kCallInstructionLength = 5; + static const int kPatchDebugBreakSlotReturnOffset = kPointerSize; static const int kJSReturnSequenceLength = 6; // The debug break slot must be able to contain a call instruction. @@ -812,6 +809,8 @@ class Assembler : public AssemblerBase { void rcl(Register dst, uint8_t imm8); void rcr(Register dst, uint8_t imm8); + void ror(Register dst, uint8_t imm8); + void ror_cl(Register dst); void sar(Register dst, uint8_t imm8); void sar_cl(Register dst); @@ -991,8 +990,10 @@ class Assembler : public AssemblerBase { void cvtsd2ss(XMMRegister dst, XMMRegister src); void addsd(XMMRegister dst, XMMRegister src); + void addsd(XMMRegister dst, const Operand& src); void subsd(XMMRegister dst, XMMRegister src); void mulsd(XMMRegister dst, XMMRegister src); + void mulsd(XMMRegister dst, const Operand& src); void divsd(XMMRegister dst, XMMRegister src); void xorpd(XMMRegister dst, XMMRegister src); void xorps(XMMRegister dst, XMMRegister src); @@ -1016,6 +1017,7 @@ class Assembler : public AssemblerBase { void movmskpd(Register dst, XMMRegister src); void cmpltsd(XMMRegister dst, XMMRegister src); + void pcmpeqd(XMMRegister dst, XMMRegister src); void movaps(XMMRegister dst, XMMRegister src); @@ -1048,7 +1050,7 @@ class Assembler : public AssemblerBase { void psllq(XMMRegister dst, XMMRegister src); void psrlq(XMMRegister reg, int8_t shift); void psrlq(XMMRegister dst, XMMRegister src); - void pshufd(XMMRegister dst, XMMRegister src, int8_t shuffle); + void pshufd(XMMRegister dst, XMMRegister src, uint8_t shuffle); void pextrd(Register dst, XMMRegister src, int8_t offset) { pextrd(Operand(dst), src, offset); } @@ -1091,8 +1093,6 @@ class Assembler : public AssemblerBase { void db(uint8_t data); void dd(uint32_t data); - int pc_offset() const { return pc_ - buffer_; } - // Check if there is less than kGap bytes available in the buffer. // If this is the case, we need to grow the buffer before emitting // an instruction or relocation information. @@ -1111,15 +1111,11 @@ class Assembler : public AssemblerBase { // Avoid overflows for displacements etc. static const int kMaximalBufferSize = 512*MB; - static const int kMinimalBufferSize = 4*KB; byte byte_at(int pos) { return buffer_[pos]; } void set_byte_at(int pos, byte value) { buffer_[pos] = value; } protected: - bool emit_debug_code() const { return emit_debug_code_; } - bool predictable_code_size() const { return predictable_code_size_ ; } - void movsd(XMMRegister dst, const Operand& src); void movsd(const Operand& dst, XMMRegister src); @@ -1180,22 +1176,10 @@ class Assembler : public AssemblerBase { friend class CodePatcher; friend class EnsureSpace; - // Code buffer: - // The buffer into which code and relocation info are generated. - byte* buffer_; - int buffer_size_; - // True if the assembler owns the buffer, false if buffer is external. - bool own_buffer_; - // code generation - byte* pc_; // the program counter; moves forward RelocInfoWriter reloc_info_writer; PositionsRecorder positions_recorder_; - - bool emit_debug_code_; - bool predictable_code_size_; - friend class PositionsRecorder; }; diff --git a/deps/v8/src/ia32/builtins-ia32.cc b/deps/v8/src/ia32/builtins-ia32.cc index 9bc15e9098..01785bb53e 100644 --- a/deps/v8/src/ia32/builtins-ia32.cc +++ b/deps/v8/src/ia32/builtins-ia32.cc @@ -538,6 +538,42 @@ void Builtins::Generate_LazyRecompile(MacroAssembler* masm) { } +static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) { + // For now, we are relying on the fact that make_code_young doesn't do any + // garbage collection which allows us to save/restore the registers without + // worrying about which of them contain pointers. We also don't build an + // internal frame to make the code faster, since we shouldn't have to do stack + // crawls in MakeCodeYoung. This seems a bit fragile. + + // Re-execute the code that was patched back to the young age when + // the stub returns. + __ sub(Operand(esp, 0), Immediate(5)); + __ pushad(); + __ mov(eax, Operand(esp, 8 * kPointerSize)); + { + FrameScope scope(masm, StackFrame::MANUAL); + __ PrepareCallCFunction(1, ebx); + __ mov(Operand(esp, 0), eax); + __ CallCFunction( + ExternalReference::get_make_code_young_function(masm->isolate()), 1); + } + __ popad(); + __ ret(0); +} + +#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \ +void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \ + MacroAssembler* masm) { \ + GenerateMakeCodeYoungAgainCommon(masm); \ +} \ +void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \ + MacroAssembler* masm) { \ + GenerateMakeCodeYoungAgainCommon(masm); \ +} +CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR) +#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR + + static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, Deoptimizer::BailoutType type) { { diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index 140db8a718..da8e2ae457 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -735,6 +735,12 @@ class FloatingPointHelper : public AllStatic { static void CheckSSE2OperandsAreInt32(MacroAssembler* masm, Label* non_int32, Register scratch); + + static void CheckSSE2OperandIsInt32(MacroAssembler* masm, + Label* non_int32, + XMMRegister operand, + Register scratch, + XMMRegister xmm_scratch); }; @@ -755,11 +761,20 @@ static void IntegerConvert(MacroAssembler* masm, // Get exponent alone in scratch2. __ mov(scratch2, scratch); __ and_(scratch2, HeapNumber::kExponentMask); + __ shr(scratch2, HeapNumber::kExponentShift); + __ sub(scratch2, Immediate(HeapNumber::kExponentBias)); + // Load ecx with zero. We use this either for the final shift or + // for the answer. + __ xor_(ecx, ecx); + // If the exponent is above 83, the number contains no significant + // bits in the range 0..2^31, so the result is zero. + static const uint32_t kResultIsZeroExponent = 83; + __ cmp(scratch2, Immediate(kResultIsZeroExponent)); + __ j(above, &done); if (use_sse3) { CpuFeatures::Scope scope(SSE3); // Check whether the exponent is too big for a 64 bit signed integer. - static const uint32_t kTooBigExponent = - (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; + static const uint32_t kTooBigExponent = 63; __ cmp(scratch2, Immediate(kTooBigExponent)); __ j(greater_equal, conversion_failure); // Load x87 register with heap number. @@ -771,15 +786,11 @@ static void IntegerConvert(MacroAssembler* masm, __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. __ add(esp, Immediate(sizeof(uint64_t))); // Nolint. } else { - // Load ecx with zero. We use this either for the final shift or - // for the answer. - __ xor_(ecx, ecx); // Check whether the exponent matches a 32 bit signed int that cannot be // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the // exponent is 30 (biased). This is the exponent that we are fastest at and // also the highest exponent we can handle here. - const uint32_t non_smi_exponent = - (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; + const uint32_t non_smi_exponent = 30; __ cmp(scratch2, Immediate(non_smi_exponent)); // If we have a match of the int32-but-not-Smi exponent then skip some // logic. @@ -791,8 +802,7 @@ static void IntegerConvert(MacroAssembler* masm, { // Handle a big exponent. The only reason we have this code is that the // >>> operator has a tendency to generate numbers with an exponent of 31. - const uint32_t big_non_smi_exponent = - (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; + const uint32_t big_non_smi_exponent = 31; __ cmp(scratch2, Immediate(big_non_smi_exponent)); __ j(not_equal, conversion_failure); // We have the big exponent, typically from >>>. This means the number is @@ -821,19 +831,8 @@ static void IntegerConvert(MacroAssembler* masm, } __ bind(&normal_exponent); - // Exponent word in scratch, exponent part of exponent word in scratch2. - // Zero in ecx. - // We know the exponent is smaller than 30 (biased). If it is less than - // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e. - // it rounds to zero. - const uint32_t zero_exponent = - (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; - __ sub(scratch2, Immediate(zero_exponent)); - // ecx already has a Smi zero. - __ j(less, &done, Label::kNear); - - // We have a shifted exponent between 0 and 30 in scratch2. - __ shr(scratch2, HeapNumber::kExponentShift); + // Exponent word in scratch, exponent in scratch2. Zero in ecx. + // We know that 0 <= exponent < 30. __ mov(ecx, Immediate(30)); __ sub(ecx, scratch2); @@ -868,8 +867,8 @@ static void IntegerConvert(MacroAssembler* masm, __ jmp(&done, Label::kNear); __ bind(&negative); __ sub(ecx, scratch2); - __ bind(&done); } + __ bind(&done); } @@ -1192,16 +1191,17 @@ void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { } +void BinaryOpStub::Initialize() { + platform_specific_bit_ = CpuFeatures::IsSupported(SSE3); +} + + void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { __ pop(ecx); // Save return address. __ push(edx); __ push(eax); // Left and right arguments are now on top. - // Push this stub's key. Although the operation and the type info are - // encoded into the key, the encoding is opaque, so push them too. __ push(Immediate(Smi::FromInt(MinorKey()))); - __ push(Immediate(Smi::FromInt(op_))); - __ push(Immediate(Smi::FromInt(operands_type_))); __ push(ecx); // Push return address. @@ -1210,7 +1210,7 @@ void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { __ TailCallExternalReference( ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()), - 5, + 3, 1); } @@ -1220,11 +1220,7 @@ void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { __ pop(ecx); // Save return address. // Left and right arguments are already on top of the stack. - // Push this stub's key. Although the operation and the type info are - // encoded into the key, the encoding is opaque, so push them too. __ push(Immediate(Smi::FromInt(MinorKey()))); - __ push(Immediate(Smi::FromInt(op_))); - __ push(Immediate(Smi::FromInt(operands_type_))); __ push(ecx); // Push return address. @@ -1233,73 +1229,22 @@ void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { __ TailCallExternalReference( ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()), - 5, + 3, 1); } -void BinaryOpStub::Generate(MacroAssembler* masm) { - // Explicitly allow generation of nested stubs. It is safe here because - // generation code does not use any raw pointers. - AllowStubCallsScope allow_stub_calls(masm, true); - - switch (operands_type_) { - case BinaryOpIC::UNINITIALIZED: - GenerateTypeTransition(masm); - break; - case BinaryOpIC::SMI: - GenerateSmiStub(masm); - break; - case BinaryOpIC::INT32: - GenerateInt32Stub(masm); - break; - case BinaryOpIC::HEAP_NUMBER: - GenerateHeapNumberStub(masm); - break; - case BinaryOpIC::ODDBALL: - GenerateOddballStub(masm); - break; - case BinaryOpIC::BOTH_STRING: - GenerateBothStringStub(masm); - break; - case BinaryOpIC::STRING: - GenerateStringStub(masm); - break; - case BinaryOpIC::GENERIC: - GenerateGeneric(masm); - break; - default: - UNREACHABLE(); - } -} - - -void BinaryOpStub::PrintName(StringStream* stream) { - const char* op_name = Token::Name(op_); - const char* overwrite_name; - switch (mode_) { - case NO_OVERWRITE: overwrite_name = "Alloc"; break; - case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; - case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; - default: overwrite_name = "UnknownOverwrite"; break; - } - stream->Add("BinaryOpStub_%s_%s_%s", - op_name, - overwrite_name, - BinaryOpIC::GetName(operands_type_)); -} - - -void BinaryOpStub::GenerateSmiCode( +static void BinaryOpStub_GenerateSmiCode( MacroAssembler* masm, Label* slow, - SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { + BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results, + Token::Value op) { // 1. Move arguments into edx, eax except for DIV and MOD, which need the // dividend in eax and edx free for the division. Use eax, ebx for those. Comment load_comment(masm, "-- Load arguments"); Register left = edx; Register right = eax; - if (op_ == Token::DIV || op_ == Token::MOD) { + if (op == Token::DIV || op == Token::MOD) { left = eax; right = ebx; __ mov(ebx, eax); @@ -1312,7 +1257,7 @@ void BinaryOpStub::GenerateSmiCode( Label not_smis; Register combined = ecx; ASSERT(!left.is(combined) && !right.is(combined)); - switch (op_) { + switch (op) { case Token::BIT_OR: // Perform the operation into eax and smi check the result. Preserve // eax in case the result is not a smi. @@ -1356,7 +1301,7 @@ void BinaryOpStub::GenerateSmiCode( // eax and check the result if necessary. Comment perform_smi(masm, "-- Perform smi operation"); Label use_fp_on_smis; - switch (op_) { + switch (op) { case Token::BIT_OR: // Nothing to do. break; @@ -1490,7 +1435,7 @@ void BinaryOpStub::GenerateSmiCode( } // 5. Emit return of result in eax. Some operations have registers pushed. - switch (op_) { + switch (op) { case Token::ADD: case Token::SUB: case Token::MUL: @@ -1513,9 +1458,9 @@ void BinaryOpStub::GenerateSmiCode( // 6. For some operations emit inline code to perform floating point // operations on known smis (e.g., if the result of the operation // overflowed the smi range). - if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) { + if (allow_heapnumber_results == BinaryOpStub::NO_HEAPNUMBER_RESULTS) { __ bind(&use_fp_on_smis); - switch (op_) { + switch (op) { // Undo the effects of some operations, and some register moves. case Token::SHL: // The arguments are saved on the stack, and only used from there. @@ -1543,8 +1488,8 @@ void BinaryOpStub::GenerateSmiCode( } __ jmp(¬_smis); } else { - ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS); - switch (op_) { + ASSERT(allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS); + switch (op) { case Token::SHL: case Token::SHR: { Comment perform_float(masm, "-- Perform float operation on smis"); @@ -1555,13 +1500,13 @@ void BinaryOpStub::GenerateSmiCode( // Store the result in the HeapNumber and return. // It's OK to overwrite the arguments on the stack because we // are about to return. - if (op_ == Token::SHR) { + if (op == Token::SHR) { __ mov(Operand(esp, 1 * kPointerSize), left); __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); __ fild_d(Operand(esp, 1 * kPointerSize)); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); } else { - ASSERT_EQ(Token::SHL, op_); + ASSERT_EQ(Token::SHL, op); if (CpuFeatures::IsSupported(SSE2)) { CpuFeatures::Scope use_sse2(SSE2); __ cvtsi2sd(xmm0, left); @@ -1583,7 +1528,7 @@ void BinaryOpStub::GenerateSmiCode( Comment perform_float(masm, "-- Perform float operation on smis"); __ bind(&use_fp_on_smis); // Restore arguments to edx, eax. - switch (op_) { + switch (op) { case Token::ADD: // Revert right = right + left. __ sub(right, left); @@ -1609,7 +1554,7 @@ void BinaryOpStub::GenerateSmiCode( if (CpuFeatures::IsSupported(SSE2)) { CpuFeatures::Scope use_sse2(SSE2); FloatingPointHelper::LoadSSE2Smis(masm, ebx); - switch (op_) { + switch (op) { case Token::ADD: __ addsd(xmm0, xmm1); break; case Token::SUB: __ subsd(xmm0, xmm1); break; case Token::MUL: __ mulsd(xmm0, xmm1); break; @@ -1619,7 +1564,7 @@ void BinaryOpStub::GenerateSmiCode( __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); } else { // SSE2 not available, use FPU. FloatingPointHelper::LoadFloatSmis(masm, ebx); - switch (op_) { + switch (op) { case Token::ADD: __ faddp(1); break; case Token::SUB: __ fsubp(1); break; case Token::MUL: __ fmulp(1); break; @@ -1642,7 +1587,7 @@ void BinaryOpStub::GenerateSmiCode( // edx and eax. Comment done_comment(masm, "-- Enter non-smi code"); __ bind(¬_smis); - switch (op_) { + switch (op) { case Token::BIT_OR: case Token::SHL: case Token::SAR: @@ -1689,9 +1634,11 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { if (result_type_ == BinaryOpIC::UNINITIALIZED || result_type_ == BinaryOpIC::SMI) { - GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, NO_HEAPNUMBER_RESULTS, op_); } else { - GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); } __ bind(&call_runtime); switch (op_) { @@ -1716,19 +1663,9 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { } -void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { - ASSERT(operands_type_ == BinaryOpIC::STRING); - ASSERT(op_ == Token::ADD); - // Try to add arguments as strings, otherwise, transition to the generic - // BinaryOpIC type. - GenerateAddStrings(masm); - GenerateTypeTransition(masm); -} - - void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { Label call_runtime; - ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); + ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING); ASSERT(op_ == Token::ADD); // If both arguments are strings, call the string add stub. // Otherwise, do a transition. @@ -1756,6 +1693,11 @@ void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { } +static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, + Label* alloc_failure, + OverwriteMode mode); + + // Input: // edx: left operand (tagged) // eax: right operand (tagged) @@ -1763,7 +1705,7 @@ void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { // eax: result (tagged) void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Label call_runtime; - ASSERT(operands_type_ == BinaryOpIC::INT32); + ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); // Floating point case. switch (op_) { @@ -1776,6 +1718,18 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Label not_int32; if (CpuFeatures::IsSupported(SSE2)) { CpuFeatures::Scope use_sse2(SSE2); + // It could be that only SMIs have been seen at either the left + // or the right operand. For precise type feedback, patch the IC + // again if this changes. + // In theory, we would need the same check in the non-SSE2 case, + // but since we don't support Crankshaft on such hardware we can + // afford not to care about precise type feedback. + if (left_type_ == BinaryOpIC::SMI) { + __ JumpIfNotSmi(edx, ¬_int32); + } + if (right_type_ == BinaryOpIC::SMI) { + __ JumpIfNotSmi(eax, ¬_int32); + } FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); if (op_ == Token::MOD) { @@ -1793,11 +1747,12 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { if (result_type_ <= BinaryOpIC::INT32) { __ cvttsd2si(ecx, Operand(xmm0)); __ cvtsi2sd(xmm2, ecx); - __ ucomisd(xmm0, xmm2); - __ j(not_zero, ¬_int32); - __ j(carry, ¬_int32); + __ pcmpeqd(xmm2, xmm0); + __ movmskpd(ecx, xmm2); + __ test(ecx, Immediate(1)); + __ j(zero, ¬_int32); } - GenerateHeapResultAllocation(masm, &call_runtime); + BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_); __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); __ ret(0); } @@ -1823,7 +1778,8 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { default: UNREACHABLE(); } Label after_alloc_failure; - GenerateHeapResultAllocation(masm, &after_alloc_failure); + BinaryOpStub_GenerateHeapResultAllocation( + masm, &after_alloc_failure, mode_); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ ret(0); __ bind(&after_alloc_failure); @@ -1848,10 +1804,14 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Label not_floats; Label not_int32; Label non_smi_result; + // We do not check the input arguments here, as any value is + // unconditionally truncated to an int32 anyway. To get the + // right optimized code, int32 type feedback is just right. + bool use_sse3 = platform_specific_bit_; FloatingPointHelper::LoadUnknownsAsIntegers(masm, - use_sse3_, + use_sse3, ¬_floats); - FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, + FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3, ¬_int32); switch (op_) { case Token::BIT_OR: __ or_(eax, ecx); break; @@ -1924,44 +1884,24 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { switch (op_) { case Token::ADD: - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); - break; case Token::SUB: - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); - break; case Token::MUL: - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); - break; case Token::DIV: GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); break; case Token::MOD: - break; + return; // Handled above. case Token::BIT_OR: - __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); - break; case Token::BIT_AND: - __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); - break; case Token::BIT_XOR: - __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); - break; case Token::SAR: - __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); - break; case Token::SHL: - __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); - break; case Token::SHR: - __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); break; default: UNREACHABLE(); } + GenerateCallRuntime(masm); } @@ -2010,7 +1950,28 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { Label not_floats; if (CpuFeatures::IsSupported(SSE2)) { CpuFeatures::Scope use_sse2(SSE2); + + // It could be that only SMIs have been seen at either the left + // or the right operand. For precise type feedback, patch the IC + // again if this changes. + // In theory, we would need the same check in the non-SSE2 case, + // but since we don't support Crankshaft on such hardware we can + // afford not to care about precise type feedback. + if (left_type_ == BinaryOpIC::SMI) { + __ JumpIfNotSmi(edx, ¬_floats); + } + if (right_type_ == BinaryOpIC::SMI) { + __ JumpIfNotSmi(eax, ¬_floats); + } FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); + if (left_type_ == BinaryOpIC::INT32) { + FloatingPointHelper::CheckSSE2OperandIsInt32( + masm, ¬_floats, xmm0, ecx, xmm2); + } + if (right_type_ == BinaryOpIC::INT32) { + FloatingPointHelper::CheckSSE2OperandIsInt32( + masm, ¬_floats, xmm1, ecx, xmm2); + } switch (op_) { case Token::ADD: __ addsd(xmm0, xmm1); break; @@ -2019,7 +1980,7 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { case Token::DIV: __ divsd(xmm0, xmm1); break; default: UNREACHABLE(); } - GenerateHeapResultAllocation(masm, &call_runtime); + BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_); __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); __ ret(0); } else { // SSE2 not available, use FPU. @@ -2036,7 +1997,8 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { default: UNREACHABLE(); } Label after_alloc_failure; - GenerateHeapResultAllocation(masm, &after_alloc_failure); + BinaryOpStub_GenerateHeapResultAllocation( + masm, &after_alloc_failure, mode_); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ ret(0); __ bind(&after_alloc_failure); @@ -2062,8 +2024,12 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { GenerateRegisterArgsPush(masm); Label not_floats; Label non_smi_result; + // We do not check the input arguments here, as any value is + // unconditionally truncated to an int32 anyway. To get the + // right optimized code, int32 type feedback is just right. + bool use_sse3 = platform_specific_bit_; FloatingPointHelper::LoadUnknownsAsIntegers(masm, - use_sse3_, + use_sse3, ¬_floats); switch (op_) { case Token::BIT_OR: __ or_(eax, ecx); break; @@ -2135,46 +2101,23 @@ void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { switch (op_) { case Token::ADD: - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); - break; case Token::SUB: - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); - break; case Token::MUL: - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); - break; case Token::DIV: - GenerateRegisterArgsPush(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); - break; case Token::BIT_AND: - __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); - break; case Token::BIT_XOR: - __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); - break; case Token::SAR: - __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); - break; case Token::SHL: - __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); - break; case Token::SHR: - __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); break; default: UNREACHABLE(); } + GenerateCallRuntime(masm); } @@ -2203,7 +2146,8 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { UNREACHABLE(); } - GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); // Floating point case. switch (op_) { @@ -2223,7 +2167,7 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { case Token::DIV: __ divsd(xmm0, xmm1); break; default: UNREACHABLE(); } - GenerateHeapResultAllocation(masm, &call_runtime); + BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_); __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); __ ret(0); } else { // SSE2 not available, use FPU. @@ -2240,7 +2184,8 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { default: UNREACHABLE(); } Label after_alloc_failure; - GenerateHeapResultAllocation(masm, &after_alloc_failure); + BinaryOpStub_GenerateHeapResultAllocation( + masm, &after_alloc_failure, mode_); __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); __ ret(0); __ bind(&after_alloc_failure); @@ -2261,8 +2206,9 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { case Token::SHL: case Token::SHR: { Label non_smi_result; + bool use_sse3 = platform_specific_bit_; FloatingPointHelper::LoadUnknownsAsIntegers(masm, - use_sse3_, + use_sse3, &call_runtime); switch (op_) { case Token::BIT_OR: __ or_(eax, ecx); break; @@ -2329,48 +2275,26 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { // result. __ bind(&call_runtime); switch (op_) { - case Token::ADD: { + case Token::ADD: GenerateAddStrings(masm); - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); - break; - } + // Fall through. case Token::SUB: - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); - break; case Token::MUL: - GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); - break; case Token::DIV: GenerateRegisterArgsPush(masm); - __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); break; case Token::MOD: - __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); - break; case Token::BIT_OR: - __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); - break; case Token::BIT_AND: - __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); - break; case Token::BIT_XOR: - __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); - break; case Token::SAR: - __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); - break; case Token::SHL: - __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); - break; case Token::SHR: - __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); break; default: UNREACHABLE(); } + GenerateCallRuntime(masm); } @@ -2406,11 +2330,10 @@ void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { } -void BinaryOpStub::GenerateHeapResultAllocation( - MacroAssembler* masm, - Label* alloc_failure) { +static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, + Label* alloc_failure, + OverwriteMode mode) { Label skip_allocation; - OverwriteMode mode = mode_; switch (mode) { case OVERWRITE_LEFT: { // If the argument in edx is already an object, we skip the @@ -2922,16 +2845,22 @@ void FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm, void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, Label* non_int32, Register scratch) { - __ cvttsd2si(scratch, Operand(xmm0)); - __ cvtsi2sd(xmm2, scratch); - __ ucomisd(xmm0, xmm2); - __ j(not_zero, non_int32); - __ j(carry, non_int32); - __ cvttsd2si(scratch, Operand(xmm1)); - __ cvtsi2sd(xmm2, scratch); - __ ucomisd(xmm1, xmm2); - __ j(not_zero, non_int32); - __ j(carry, non_int32); + CheckSSE2OperandIsInt32(masm, non_int32, xmm0, scratch, xmm2); + CheckSSE2OperandIsInt32(masm, non_int32, xmm1, scratch, xmm2); +} + + +void FloatingPointHelper::CheckSSE2OperandIsInt32(MacroAssembler* masm, + Label* non_int32, + XMMRegister operand, + Register scratch, + XMMRegister xmm_scratch) { + __ cvttsd2si(scratch, Operand(operand)); + __ cvtsi2sd(xmm_scratch, scratch); + __ pcmpeqd(xmm_scratch, operand); + __ movmskpd(scratch, xmm_scratch); + __ test(scratch, Immediate(1)); + __ j(zero, non_int32); } @@ -3186,10 +3115,10 @@ void MathPowStub::Generate(MacroAssembler* masm) { // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X) __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X) - __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X) + __ faddp(1); // 2^(X-rnd(X)), rnd(X) // FSCALE calculates st(0) * 2^st(1) __ fscale(); // 2^X, rnd(X) - __ fstp(1); + __ fstp(1); // 2^X // Bail out to runtime in case of exceptions in the status word. __ fnstsw_ax(); __ test_b(eax, 0x5F); // We check for all but precision exception. @@ -3213,21 +3142,28 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ movsd(double_scratch2, double_result); // Load double_exponent with 1. // Get absolute value of exponent. - Label no_neg, while_true, no_multiply; + Label no_neg, while_true, while_false; __ test(scratch, scratch); __ j(positive, &no_neg, Label::kNear); __ neg(scratch); __ bind(&no_neg); - __ bind(&while_true); + __ j(zero, &while_false, Label::kNear); __ shr(scratch, 1); - __ j(not_carry, &no_multiply, Label::kNear); - __ mulsd(double_result, double_scratch); - __ bind(&no_multiply); + // Above condition means CF==0 && ZF==0. This means that the + // bit that has been shifted out is 0 and the result is not 0. + __ j(above, &while_true, Label::kNear); + __ movsd(double_result, double_scratch); + __ j(zero, &while_false, Label::kNear); + __ bind(&while_true); + __ shr(scratch, 1); __ mulsd(double_scratch, double_scratch); + __ j(above, &while_true, Label::kNear); + __ mulsd(double_result, double_scratch); __ j(not_zero, &while_true); + __ bind(&while_false); // scratch has the original value of the exponent - if the exponent is // negative, return 1/result. __ test(exponent, exponent); @@ -3585,7 +3521,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { __ bind(&runtime); __ pop(eax); // Remove saved parameter count. __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count. - __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); + __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); } @@ -3952,9 +3888,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ test(ecx, ecx); __ j(zero, &setup_two_byte, Label::kNear); __ SmiUntag(esi); - __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize)); + __ lea(ecx, FieldOperand(eax, esi, times_1, SeqOneByteString::kHeaderSize)); __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. - __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); + __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqOneByteString::kHeaderSize)); __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. __ jmp(&setup_rest, Label::kNear); @@ -4100,7 +4036,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { } __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); STATIC_ASSERT(kTwoByteStringTag == 0); __ test_b(ebx, kStringEncodingMask); @@ -4170,15 +4106,15 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { Immediate(factory->fixed_array_map())); // Set length. __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx); - // Fill contents of fixed-array with the-hole. + // Fill contents of fixed-array with undefined. __ SmiUntag(ecx); - __ mov(edx, Immediate(factory->the_hole_value())); + __ mov(edx, Immediate(factory->undefined_value())); __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); - // Fill fixed array elements with hole. + // Fill fixed array elements with undefined. // eax: JSArray. // ecx: Number of elements to fill. // ebx: Start of elements in FixedArray. - // edx: the hole. + // edx: undefined. Label loop; __ test(ecx, ecx); __ bind(&loop); @@ -4313,30 +4249,59 @@ static int NegativeComparisonResult(Condition cc) { return (cc == greater || cc == greater_equal) ? LESS : GREATER; } -void CompareStub::Generate(MacroAssembler* masm) { - ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); +static void CheckInputType(MacroAssembler* masm, + Register input, + CompareIC::State expected, + Label* fail) { + Label ok; + if (expected == CompareIC::SMI) { + __ JumpIfNotSmi(input, fail); + } else if (expected == CompareIC::HEAP_NUMBER) { + __ JumpIfSmi(input, &ok); + __ cmp(FieldOperand(input, HeapObject::kMapOffset), + Immediate(masm->isolate()->factory()->heap_number_map())); + __ j(not_equal, fail); + } + // We could be strict about symbol/string here, but as long as + // hydrogen doesn't care, the stub doesn't have to care either. + __ bind(&ok); +} + + +static void BranchIfNonSymbol(MacroAssembler* masm, + Label* label, + Register object, + Register scratch) { + __ JumpIfSmi(object, label); + __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); + __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); + __ and_(scratch, kIsSymbolMask | kIsNotStringMask); + __ cmp(scratch, kSymbolTag | kStringTag); + __ j(not_equal, label); +} + + +void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { Label check_unequal_objects; + Condition cc = GetCondition(); - // Compare two smis if required. - if (include_smi_compare_) { - Label non_smi, smi_done; - __ mov(ecx, edx); - __ or_(ecx, eax); - __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); - __ sub(edx, eax); // Return on the result of the subtraction. - __ j(no_overflow, &smi_done, Label::kNear); - __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. - __ bind(&smi_done); - __ mov(eax, edx); - __ ret(0); - __ bind(&non_smi); - } else if (FLAG_debug_code) { - __ mov(ecx, edx); - __ or_(ecx, eax); - __ test(ecx, Immediate(kSmiTagMask)); - __ Assert(not_zero, "Unexpected smi operands."); - } + Label miss; + CheckInputType(masm, edx, left_, &miss); + CheckInputType(masm, eax, right_, &miss); + + // Compare two smis. + Label non_smi, smi_done; + __ mov(ecx, edx); + __ or_(ecx, eax); + __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); + __ sub(edx, eax); // Return on the result of the subtraction. + __ j(no_overflow, &smi_done, Label::kNear); + __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. + __ bind(&smi_done); + __ mov(eax, edx); + __ ret(0); + __ bind(&non_smi); // NOTICE! This code is only reached after a smi-fast-case check, so // it is certain that at least one operand isn't a smi. @@ -4348,67 +4313,61 @@ void CompareStub::Generate(MacroAssembler* masm) { __ cmp(eax, edx); __ j(not_equal, ¬_identical); - if (cc_ != equal) { + if (cc != equal) { // Check for undefined. undefined OP undefined is false even though // undefined == undefined. Label check_for_nan; __ cmp(edx, masm->isolate()->factory()->undefined_value()); __ j(not_equal, &check_for_nan, Label::kNear); - __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); + __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); __ ret(0); __ bind(&check_for_nan); } // Test for NaN. Sadly, we can't just compare to factory->nan_value(), // so we do the second best thing - test it ourselves. - // Note: if cc_ != equal, never_nan_nan_ is not used. - if (never_nan_nan_ && (cc_ == equal)) { - __ Set(eax, Immediate(Smi::FromInt(EQUAL))); + Label heap_number; + __ cmp(FieldOperand(edx, HeapObject::kMapOffset), + Immediate(masm->isolate()->factory()->heap_number_map())); + __ j(equal, &heap_number, Label::kNear); + if (cc != equal) { + // Call runtime on identical JSObjects. Otherwise return equal. + __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); + __ j(above_equal, ¬_identical); + } + __ Set(eax, Immediate(Smi::FromInt(EQUAL))); + __ ret(0); + + __ bind(&heap_number); + // It is a heap number, so return non-equal if it's NaN and equal if + // it's not NaN. + // The representation of NaN values has all exponent bits (52..62) set, + // and not all mantissa bits (0..51) clear. + // We only accept QNaNs, which have bit 51 set. + // Read top bits of double representation (second word of value). + + // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., + // all bits in the mask are set. We only need to check the word + // that contains the exponent and high bit of the mantissa. + STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); + __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); + __ Set(eax, Immediate(0)); + // Shift value and mask so kQuietNaNHighBitsMask applies to topmost + // bits. + __ add(edx, edx); + __ cmp(edx, kQuietNaNHighBitsMask << 1); + if (cc == equal) { + STATIC_ASSERT(EQUAL != 1); + __ setcc(above_equal, eax); __ ret(0); } else { - Label heap_number; - __ cmp(FieldOperand(edx, HeapObject::kMapOffset), - Immediate(masm->isolate()->factory()->heap_number_map())); - __ j(equal, &heap_number, Label::kNear); - if (cc_ != equal) { - // Call runtime on identical JSObjects. Otherwise return equal. - __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); - __ j(above_equal, ¬_identical); - } + Label nan; + __ j(above_equal, &nan, Label::kNear); __ Set(eax, Immediate(Smi::FromInt(EQUAL))); __ ret(0); - - __ bind(&heap_number); - // It is a heap number, so return non-equal if it's NaN and equal if - // it's not NaN. - // The representation of NaN values has all exponent bits (52..62) set, - // and not all mantissa bits (0..51) clear. - // We only accept QNaNs, which have bit 51 set. - // Read top bits of double representation (second word of value). - - // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., - // all bits in the mask are set. We only need to check the word - // that contains the exponent and high bit of the mantissa. - STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); - __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); - __ Set(eax, Immediate(0)); - // Shift value and mask so kQuietNaNHighBitsMask applies to topmost - // bits. - __ add(edx, edx); - __ cmp(edx, kQuietNaNHighBitsMask << 1); - if (cc_ == equal) { - STATIC_ASSERT(EQUAL != 1); - __ setcc(above_equal, eax); - __ ret(0); - } else { - Label nan; - __ j(above_equal, &nan, Label::kNear); - __ Set(eax, Immediate(Smi::FromInt(EQUAL))); - __ ret(0); - __ bind(&nan); - __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); - __ ret(0); - } + __ bind(&nan); + __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); + __ ret(0); } __ bind(¬_identical); @@ -4416,7 +4375,7 @@ void CompareStub::Generate(MacroAssembler* masm) { // Strict equality can quickly decide whether objects are equal. // Non-strict object equality is slower, so it is handled later in the stub. - if (cc_ == equal && strict_) { + if (cc == equal && strict()) { Label slow; // Fallthrough label. Label not_smis; // If we're doing a strict equality comparison, we don't have to do @@ -4487,70 +4446,68 @@ void CompareStub::Generate(MacroAssembler* masm) { } // Generate the number comparison code. - if (include_number_compare_) { - Label non_number_comparison; - Label unordered; - if (CpuFeatures::IsSupported(SSE2)) { - CpuFeatures::Scope use_sse2(SSE2); - CpuFeatures::Scope use_cmov(CMOV); - - FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); - __ ucomisd(xmm0, xmm1); + Label non_number_comparison; + Label unordered; + if (CpuFeatures::IsSupported(SSE2)) { + CpuFeatures::Scope use_sse2(SSE2); + CpuFeatures::Scope use_cmov(CMOV); - // Don't base result on EFLAGS when a NaN is involved. - __ j(parity_even, &unordered, Label::kNear); - // Return a result of -1, 0, or 1, based on EFLAGS. - __ mov(eax, 0); // equal - __ mov(ecx, Immediate(Smi::FromInt(1))); - __ cmov(above, eax, ecx); - __ mov(ecx, Immediate(Smi::FromInt(-1))); - __ cmov(below, eax, ecx); - __ ret(0); - } else { - FloatingPointHelper::CheckFloatOperands( - masm, &non_number_comparison, ebx); - FloatingPointHelper::LoadFloatOperand(masm, eax); - FloatingPointHelper::LoadFloatOperand(masm, edx); - __ FCmp(); + FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); + __ ucomisd(xmm0, xmm1); - // Don't base result on EFLAGS when a NaN is involved. - __ j(parity_even, &unordered, Label::kNear); + // Don't base result on EFLAGS when a NaN is involved. + __ j(parity_even, &unordered, Label::kNear); + // Return a result of -1, 0, or 1, based on EFLAGS. + __ mov(eax, 0); // equal + __ mov(ecx, Immediate(Smi::FromInt(1))); + __ cmov(above, eax, ecx); + __ mov(ecx, Immediate(Smi::FromInt(-1))); + __ cmov(below, eax, ecx); + __ ret(0); + } else { + FloatingPointHelper::CheckFloatOperands( + masm, &non_number_comparison, ebx); + FloatingPointHelper::LoadFloatOperand(masm, eax); + FloatingPointHelper::LoadFloatOperand(masm, edx); + __ FCmp(); - Label below_label, above_label; - // Return a result of -1, 0, or 1, based on EFLAGS. - __ j(below, &below_label, Label::kNear); - __ j(above, &above_label, Label::kNear); + // Don't base result on EFLAGS when a NaN is involved. + __ j(parity_even, &unordered, Label::kNear); - __ Set(eax, Immediate(0)); - __ ret(0); + Label below_label, above_label; + // Return a result of -1, 0, or 1, based on EFLAGS. + __ j(below, &below_label, Label::kNear); + __ j(above, &above_label, Label::kNear); - __ bind(&below_label); - __ mov(eax, Immediate(Smi::FromInt(-1))); - __ ret(0); + __ Set(eax, Immediate(0)); + __ ret(0); - __ bind(&above_label); - __ mov(eax, Immediate(Smi::FromInt(1))); - __ ret(0); - } + __ bind(&below_label); + __ mov(eax, Immediate(Smi::FromInt(-1))); + __ ret(0); - // If one of the numbers was NaN, then the result is always false. - // The cc is never not-equal. - __ bind(&unordered); - ASSERT(cc_ != not_equal); - if (cc_ == less || cc_ == less_equal) { - __ mov(eax, Immediate(Smi::FromInt(1))); - } else { - __ mov(eax, Immediate(Smi::FromInt(-1))); - } + __ bind(&above_label); + __ mov(eax, Immediate(Smi::FromInt(1))); __ ret(0); + } - // The number comparison code did not provide a valid result. - __ bind(&non_number_comparison); + // If one of the numbers was NaN, then the result is always false. + // The cc is never not-equal. + __ bind(&unordered); + ASSERT(cc != not_equal); + if (cc == less || cc == less_equal) { + __ mov(eax, Immediate(Smi::FromInt(1))); + } else { + __ mov(eax, Immediate(Smi::FromInt(-1))); } + __ ret(0); + + // The number comparison code did not provide a valid result. + __ bind(&non_number_comparison); // Fast negative check for symbol-to-symbol equality. Label check_for_strings; - if (cc_ == equal) { + if (cc == equal) { BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); @@ -4566,7 +4523,7 @@ void CompareStub::Generate(MacroAssembler* masm) { &check_unequal_objects); // Inline comparison of ASCII strings. - if (cc_ == equal) { + if (cc == equal) { StringCompareStub::GenerateFlatAsciiStringEquals(masm, edx, eax, @@ -4585,7 +4542,7 @@ void CompareStub::Generate(MacroAssembler* masm) { #endif __ bind(&check_unequal_objects); - if (cc_ == equal && !strict_) { + if (cc == equal && !strict()) { // Non-strict equality. Objects are unequal if // they are both JSObjects and not undetectable, // and their pointers are different. @@ -4629,11 +4586,11 @@ void CompareStub::Generate(MacroAssembler* masm) { // Figure out which native to call and setup the arguments. Builtins::JavaScript builtin; - if (cc_ == equal) { - builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; + if (cc == equal) { + builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; } else { builtin = Builtins::COMPARE; - __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); + __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); } // Restore return address on the stack. @@ -4642,19 +4599,9 @@ void CompareStub::Generate(MacroAssembler* masm) { // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) // tagged as a small integer. __ InvokeBuiltin(builtin, JUMP_FUNCTION); -} - -void CompareStub::BranchIfNonSymbol(MacroAssembler* masm, - Label* label, - Register object, - Register scratch) { - __ JumpIfSmi(object, label); - __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); - __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); - __ and_(scratch, kIsSymbolMask | kIsNotStringMask); - __ cmp(scratch, kSymbolTag | kStringTag); - __ j(not_equal, label); + __ bind(&miss); + GenerateMiss(masm); } @@ -5399,44 +5346,6 @@ Register InstanceofStub::left() { return eax; } Register InstanceofStub::right() { return edx; } -int CompareStub::MinorKey() { - // Encode the three parameters in a unique 16 bit value. To avoid duplicate - // stubs the never NaN NaN condition is only taken into account if the - // condition is equals. - ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); - ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); - return ConditionField::encode(static_cast<unsigned>(cc_)) - | RegisterField::encode(false) // lhs_ and rhs_ are not used - | StrictField::encode(strict_) - | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) - | IncludeNumberCompareField::encode(include_number_compare_) - | IncludeSmiCompareField::encode(include_smi_compare_); -} - - -// Unfortunately you have to run without snapshots to see most of these -// names in the profile since most compare stubs end up in the snapshot. -void CompareStub::PrintName(StringStream* stream) { - ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); - const char* cc_name; - switch (cc_) { - case less: cc_name = "LT"; break; - case greater: cc_name = "GT"; break; - case less_equal: cc_name = "LE"; break; - case greater_equal: cc_name = "GE"; break; - case equal: cc_name = "EQ"; break; - case not_equal: cc_name = "NE"; break; - default: cc_name = "UnknownCondition"; break; - } - bool is_equality = cc_ == equal || cc_ == not_equal; - stream->Add("CompareStub_%s", cc_name); - if (strict_ && is_equality) stream->Add("_STRICT"); - if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); - if (!include_number_compare_) stream->Add("_NO_NUMBER"); - if (!include_smi_compare_) stream->Add("_NO_SMI"); -} - - // ------------------------------------------------------------------------- // StringCharCodeAtGenerator @@ -5671,8 +5580,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime); // Get the two characters forming the new string. - __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); - __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); + __ movzx_b(ebx, FieldOperand(eax, SeqOneByteString::kHeaderSize)); + __ movzx_b(ecx, FieldOperand(edx, SeqOneByteString::kHeaderSize)); // Try to lookup two character string in symbol table. If it is not found // just allocate a new one. @@ -5689,8 +5598,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. // Get the two characters forming the new string. - __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); - __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); + __ movzx_b(ebx, FieldOperand(eax, SeqOneByteString::kHeaderSize)); + __ movzx_b(ecx, FieldOperand(edx, SeqOneByteString::kHeaderSize)); __ bind(&make_two_character_string_no_reload); __ IncrementCounter(counters->string_add_make_two_char(), 1); __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime); @@ -5698,7 +5607,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ shl(ecx, kBitsPerByte); __ or_(ebx, ecx); // Set the characters in the new string. - __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); + __ mov_w(FieldOperand(eax, SeqOneByteString::kHeaderSize), ebx); __ IncrementCounter(counters->string_add_native(), 1); __ ret(2 * kPointerSize); @@ -5715,7 +5624,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); __ and_(ecx, edi); - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ test(ecx, Immediate(kStringEncodingMask)); __ j(zero, &non_ascii); @@ -5724,7 +5633,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime); __ bind(&allocated); // Fill the fields of the cons string. - if (FLAG_debug_code) __ AbortIfNotSmi(ebx); + __ AssertSmi(ebx); __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), Immediate(String::kEmptyHashField)); @@ -5740,13 +5649,6 @@ void StringAddStub::Generate(MacroAssembler* masm) { // edi: second instance type. __ test(ecx, Immediate(kAsciiDataHintMask)); __ j(not_zero, &ascii_data); - __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); - __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); - __ xor_(edi, ecx); - STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); - __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); - __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); - __ j(equal, &ascii_data); // Allocate a two byte cons string. __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime); __ jmp(&allocated); @@ -5772,10 +5674,10 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ test_b(ecx, kShortExternalStringMask); __ j(not_zero, &call_runtime); __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); __ jmp(&first_prepared, Label::kNear); __ bind(&first_is_sequential); - __ add(eax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(eax, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ bind(&first_prepared); __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); @@ -5793,10 +5695,10 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ test_b(edi, kShortExternalStringMask); __ j(not_zero, &call_runtime); __ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset)); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); __ jmp(&second_prepared, Label::kNear); __ bind(&second_is_sequential); - __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(edx, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ bind(&second_prepared); // Push the addresses of both strings' first characters onto the stack. @@ -5817,7 +5719,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { // eax: result string __ mov(ecx, eax); // Locate first character of result. - __ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(ecx, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); // Load first argument's length and first character location. Account for // values currently on the stack when fetching arguments from it. __ mov(edx, Operand(esp, 4 * kPointerSize)); @@ -6127,7 +6029,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, temp, temp, &next_probe_pop_mask[i]); // Check if the two characters match. - __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); + __ mov(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize)); __ and_(temp, 0x0000ffff); __ cmp(chars, temp); __ j(equal, &found_in_symbol_table); @@ -6316,7 +6218,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { // string's encoding is wrong because we always have to recheck encoding of // the newly created string's parent anyways due to externalized strings. Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ test(ebx, Immediate(kStringEncodingMask)); __ j(zero, &two_byte_slice, Label::kNear); @@ -6355,7 +6257,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ j(not_zero, &runtime); __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); __ bind(&sequential_string); @@ -6363,7 +6265,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ push(edx); __ push(edi); __ SmiUntag(ecx); - STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); + STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); __ test_b(ebx, kStringEncodingMask); __ j(zero, &two_byte_sequential); @@ -6375,12 +6277,12 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ mov(edx, esi); // esi used by following code. // Locate first character of result. __ mov(edi, eax); - __ add(edi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(edi, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); // Load string argument and locate character of sub string start. __ pop(esi); __ pop(ebx); __ SmiUntag(ebx); - __ lea(esi, FieldOperand(esi, ebx, times_1, SeqAsciiString::kHeaderSize)); + __ lea(esi, FieldOperand(esi, ebx, times_1, SeqOneByteString::kHeaderSize)); // eax: result string // ecx: result length @@ -6541,9 +6443,9 @@ void StringCompareStub::GenerateAsciiCharsCompareLoop( // doesn't need an additional compare. __ SmiUntag(length); __ lea(left, - FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); + FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize)); __ lea(right, - FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); + FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize)); __ neg(length); Register index = length; // index = -length; @@ -6598,7 +6500,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) { void ICCompareStub::GenerateSmis(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::SMIS); + ASSERT(state_ == CompareIC::SMI); Label miss; __ mov(ecx, edx); __ or_(ecx, eax); @@ -6624,31 +6526,52 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) { void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::HEAP_NUMBERS); + ASSERT(state_ == CompareIC::HEAP_NUMBER); Label generic_stub; Label unordered, maybe_undefined1, maybe_undefined2; Label miss; - __ mov(ecx, edx); - __ and_(ecx, eax); - __ JumpIfSmi(ecx, &generic_stub, Label::kNear); - __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); - __ j(not_equal, &maybe_undefined1, Label::kNear); - __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); - __ j(not_equal, &maybe_undefined2, Label::kNear); + if (left_ == CompareIC::SMI) { + __ JumpIfNotSmi(edx, &miss); + } + if (right_ == CompareIC::SMI) { + __ JumpIfNotSmi(eax, &miss); + } // Inlining the double comparison and falling back to the general compare - // stub if NaN is involved or SS2 or CMOV is unsupported. + // stub if NaN is involved or SSE2 or CMOV is unsupported. if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { CpuFeatures::Scope scope1(SSE2); CpuFeatures::Scope scope2(CMOV); - // Load left and right operand - __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); + // Load left and right operand. + Label done, left, left_smi, right_smi; + __ JumpIfSmi(eax, &right_smi, Label::kNear); + __ cmp(FieldOperand(eax, HeapObject::kMapOffset), + masm->isolate()->factory()->heap_number_map()); + __ j(not_equal, &maybe_undefined1, Label::kNear); __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); + __ jmp(&left, Label::kNear); + __ bind(&right_smi); + __ mov(ecx, eax); // Can't clobber eax because we can still jump away. + __ SmiUntag(ecx); + __ cvtsi2sd(xmm1, ecx); + + __ bind(&left); + __ JumpIfSmi(edx, &left_smi, Label::kNear); + __ cmp(FieldOperand(edx, HeapObject::kMapOffset), + masm->isolate()->factory()->heap_number_map()); + __ j(not_equal, &maybe_undefined2, Label::kNear); + __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); + __ jmp(&done); + __ bind(&left_smi); + __ mov(ecx, edx); // Can't clobber edx because we can still jump away. + __ SmiUntag(ecx); + __ cvtsi2sd(xmm0, ecx); - // Compare operands + __ bind(&done); + // Compare operands. __ ucomisd(xmm0, xmm1); // Don't base result on EFLAGS when a NaN is involved. @@ -6662,17 +6585,30 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { __ mov(ecx, Immediate(Smi::FromInt(-1))); __ cmov(below, eax, ecx); __ ret(0); + } else { + __ mov(ecx, edx); + __ and_(ecx, eax); + __ JumpIfSmi(ecx, &generic_stub, Label::kNear); + + __ cmp(FieldOperand(eax, HeapObject::kMapOffset), + masm->isolate()->factory()->heap_number_map()); + __ j(not_equal, &maybe_undefined1, Label::kNear); + __ cmp(FieldOperand(edx, HeapObject::kMapOffset), + masm->isolate()->factory()->heap_number_map()); + __ j(not_equal, &maybe_undefined2, Label::kNear); } __ bind(&unordered); - CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); __ bind(&generic_stub); + ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC, + CompareIC::GENERIC); __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); __ bind(&maybe_undefined1); if (Token::IsOrderedRelationalCompareOp(op_)) { __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value())); __ j(not_equal, &miss); + __ JumpIfSmi(edx, &unordered); __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); __ j(not_equal, &maybe_undefined2, Label::kNear); __ jmp(&unordered); @@ -6690,7 +6626,7 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::SYMBOLS); + ASSERT(state_ == CompareIC::SYMBOL); ASSERT(GetCondition() == equal); // Registers containing left and right operands respectively. @@ -6735,7 +6671,7 @@ void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { void ICCompareStub::GenerateStrings(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::STRINGS); + ASSERT(state_ == CompareIC::STRING); Label miss; bool equality = Token::IsEqualityOp(op_); @@ -6824,7 +6760,7 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) { void ICCompareStub::GenerateObjects(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::OBJECTS); + ASSERT(state_ == CompareIC::OBJECT); Label miss; __ mov(ecx, edx); __ and_(ecx, eax); @@ -6973,8 +6909,7 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, ASSERT(!name.is(r0)); ASSERT(!name.is(r1)); - // Assert that name contains a string. - if (FLAG_debug_code) __ AbortIfNotString(name); + __ AssertString(name); __ mov(r1, FieldOperand(elements, kCapacityOffset)); __ shr(r1, kSmiTagSize); // convert smi to int @@ -7198,6 +7133,11 @@ void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { } +bool CodeStub::CanUseFPRegisters() { + return CpuFeatures::IsSupported(SSE2); +} + + // Takes the input in 3 registers: address_ value_ and object_. A pointer to // the value has just been written into the object, now this stub makes sure // we keep the GC informed. The word in the object where the value has been @@ -7285,13 +7225,7 @@ void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { int argument_count = 3; __ PrepareCallCFunction(argument_count, regs_.scratch0()); __ mov(Operand(esp, 0 * kPointerSize), regs_.object()); - if (mode == INCREMENTAL_COMPACTION) { - __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot. - } else { - ASSERT(mode == INCREMENTAL); - __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); - __ mov(Operand(esp, 1 * kPointerSize), regs_.scratch0()); // Value. - } + __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot. __ mov(Operand(esp, 2 * kPointerSize), Immediate(ExternalReference::isolate_address())); @@ -7318,6 +7252,17 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker( Mode mode) { Label object_is_black, need_incremental, need_incremental_pop_object; + __ mov(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask)); + __ and_(regs_.scratch0(), regs_.object()); + __ mov(regs_.scratch1(), + Operand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset)); + __ sub(regs_.scratch1(), Immediate(1)); + __ mov(Operand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset), + regs_.scratch1()); + __ j(negative, &need_incremental); + // Let's look at the color of the object: If it is not black we don't have // to inform the incremental marker. __ JumpIfBlack(regs_.object(), diff --git a/deps/v8/src/ia32/code-stubs-ia32.h b/deps/v8/src/ia32/code-stubs-ia32.h index 803a711de9..29c16e1304 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.h +++ b/deps/v8/src/ia32/code-stubs-ia32.h @@ -154,96 +154,6 @@ class UnaryOpStub: public CodeStub { }; -class BinaryOpStub: public CodeStub { - public: - BinaryOpStub(Token::Value op, OverwriteMode mode) - : op_(op), - mode_(mode), - operands_type_(BinaryOpIC::UNINITIALIZED), - result_type_(BinaryOpIC::UNINITIALIZED) { - use_sse3_ = CpuFeatures::IsSupported(SSE3); - ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); - } - - BinaryOpStub( - int key, - BinaryOpIC::TypeInfo operands_type, - BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED) - : op_(OpBits::decode(key)), - mode_(ModeBits::decode(key)), - use_sse3_(SSE3Bits::decode(key)), - operands_type_(operands_type), - result_type_(result_type) { } - - private: - enum SmiCodeGenerateHeapNumberResults { - ALLOW_HEAPNUMBER_RESULTS, - NO_HEAPNUMBER_RESULTS - }; - - Token::Value op_; - OverwriteMode mode_; - bool use_sse3_; - - // Operand type information determined at runtime. - BinaryOpIC::TypeInfo operands_type_; - BinaryOpIC::TypeInfo result_type_; - - virtual void PrintName(StringStream* stream); - - // Minor key encoding in 16 bits RRRTTTSOOOOOOOMM. - class ModeBits: public BitField<OverwriteMode, 0, 2> {}; - class OpBits: public BitField<Token::Value, 2, 7> {}; - class SSE3Bits: public BitField<bool, 9, 1> {}; - class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {}; - class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {}; - - Major MajorKey() { return BinaryOp; } - int MinorKey() { - return OpBits::encode(op_) - | ModeBits::encode(mode_) - | SSE3Bits::encode(use_sse3_) - | OperandTypeInfoBits::encode(operands_type_) - | ResultTypeInfoBits::encode(result_type_); - } - - void Generate(MacroAssembler* masm); - void GenerateGeneric(MacroAssembler* masm); - void GenerateSmiCode(MacroAssembler* masm, - Label* slow, - SmiCodeGenerateHeapNumberResults heapnumber_results); - void GenerateLoadArguments(MacroAssembler* masm); - void GenerateReturn(MacroAssembler* masm); - void GenerateUninitializedStub(MacroAssembler* masm); - void GenerateSmiStub(MacroAssembler* masm); - void GenerateInt32Stub(MacroAssembler* masm); - void GenerateHeapNumberStub(MacroAssembler* masm); - void GenerateOddballStub(MacroAssembler* masm); - void GenerateStringStub(MacroAssembler* masm); - void GenerateBothStringStub(MacroAssembler* masm); - void GenerateGenericStub(MacroAssembler* masm); - void GenerateAddStrings(MacroAssembler* masm); - - void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure); - void GenerateRegisterArgsPush(MacroAssembler* masm); - void GenerateTypeTransition(MacroAssembler* masm); - void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); - - virtual int GetCodeKind() { return Code::BINARY_OP_IC; } - - virtual InlineCacheState GetICState() { - return BinaryOpIC::ToState(operands_type_); - } - - virtual void FinishCode(Handle<Code> code) { - code->set_binary_op_type(operands_type_); - code->set_binary_op_result_type(result_type_); - } - - friend class CodeGenerator; -}; - - class StringHelper : public AllStatic { public: // Generate code for copying characters using a simple loop. This should only diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index eb6868729b..9477bf149a 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -102,6 +102,43 @@ UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { } +UnaryMathFunction CreateExpFunction() { + if (!CpuFeatures::IsSupported(SSE2)) return &exp; + if (!FLAG_fast_math) return &exp; + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == NULL) return &exp; + ExternalReference::InitializeMathExpData(); + + MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); + // esp[1 * kPointerSize]: raw double input + // esp[0 * kPointerSize]: return address + { + CpuFeatures::Scope use_sse2(SSE2); + XMMRegister input = xmm1; + XMMRegister result = xmm2; + __ movdbl(input, Operand(esp, 1 * kPointerSize)); + __ push(eax); + __ push(ebx); + + MathExpGenerator::EmitMathExp(&masm, input, result, xmm0, eax, ebx); + + __ pop(ebx); + __ pop(eax); + __ movdbl(Operand(esp, 1 * kPointerSize), result); + __ fld_d(Operand(esp, 1 * kPointerSize)); + __ Ret(); + } + + CodeDesc desc; + masm.GetCode(&desc); + + CPU::FlushICache(buffer, actual_size); + OS::ProtectCode(buffer, actual_size); + return FUNCTION_CAST<UnaryMathFunction>(buffer); +} + + UnaryMathFunction CreateSqrtFunction() { size_t actual_size; // Allocate buffer in executable space. @@ -732,7 +769,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, // Dispatch on the encoding: ASCII or two-byte. Label ascii; __ bind(&seq_string); - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ test(result, Immediate(kStringEncodingMask)); __ j(not_zero, &ascii, Label::kNear); @@ -751,12 +788,174 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, __ movzx_b(result, FieldOperand(string, index, times_1, - SeqAsciiString::kHeaderSize)); + SeqOneByteString::kHeaderSize)); + __ bind(&done); +} + + +void SeqStringSetCharGenerator::Generate(MacroAssembler* masm, + String::Encoding encoding, + Register string, + Register index, + Register value) { + if (FLAG_debug_code) { + __ test(index, Immediate(kSmiTagMask)); + __ Check(zero, "Non-smi index"); + __ test(value, Immediate(kSmiTagMask)); + __ Check(zero, "Non-smi value"); + + __ cmp(index, FieldOperand(string, String::kLengthOffset)); + __ Check(less, "Index is too large"); + + __ cmp(index, Immediate(Smi::FromInt(0))); + __ Check(greater_equal, "Index is negative"); + + __ push(value); + __ mov(value, FieldOperand(string, HeapObject::kMapOffset)); + __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset)); + + __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask)); + static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; + static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; + __ cmp(value, Immediate(encoding == String::ONE_BYTE_ENCODING + ? one_byte_seq_type : two_byte_seq_type)); + __ Check(equal, "Unexpected string type"); + __ pop(value); + } + + __ SmiUntag(value); + STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); + if (encoding == String::ONE_BYTE_ENCODING) { + __ SmiUntag(index); + __ mov_b(FieldOperand(string, index, times_1, SeqString::kHeaderSize), + value); + } else { + // No need to untag a smi for two-byte addressing. + __ mov_w(FieldOperand(string, index, times_1, SeqString::kHeaderSize), + value); + } +} + + +static Operand ExpConstant(int index) { + return Operand::StaticVariable(ExternalReference::math_exp_constants(index)); +} + + +void MathExpGenerator::EmitMathExp(MacroAssembler* masm, + XMMRegister input, + XMMRegister result, + XMMRegister double_scratch, + Register temp1, + Register temp2) { + ASSERT(!input.is(double_scratch)); + ASSERT(!input.is(result)); + ASSERT(!result.is(double_scratch)); + ASSERT(!temp1.is(temp2)); + ASSERT(ExternalReference::math_exp_constants(0).address() != NULL); + + Label done; + + __ movdbl(double_scratch, ExpConstant(0)); + __ xorpd(result, result); + __ ucomisd(double_scratch, input); + __ j(above_equal, &done); + __ ucomisd(input, ExpConstant(1)); + __ movdbl(result, ExpConstant(2)); + __ j(above_equal, &done); + __ movdbl(double_scratch, ExpConstant(3)); + __ movdbl(result, ExpConstant(4)); + __ mulsd(double_scratch, input); + __ addsd(double_scratch, result); + __ movd(temp2, double_scratch); + __ subsd(double_scratch, result); + __ movdbl(result, ExpConstant(6)); + __ mulsd(double_scratch, ExpConstant(5)); + __ subsd(double_scratch, input); + __ subsd(result, double_scratch); + __ movsd(input, double_scratch); + __ mulsd(input, double_scratch); + __ mulsd(result, input); + __ mov(temp1, temp2); + __ mulsd(result, ExpConstant(7)); + __ subsd(result, double_scratch); + __ add(temp1, Immediate(0x1ff800)); + __ addsd(result, ExpConstant(8)); + __ and_(temp2, Immediate(0x7ff)); + __ shr(temp1, 11); + __ shl(temp1, 20); + __ movd(input, temp1); + __ pshufd(input, input, static_cast<uint8_t>(0xe1)); // Order: 11 10 00 01 + __ movdbl(double_scratch, Operand::StaticArray( + temp2, times_8, ExternalReference::math_exp_log_table())); + __ por(input, double_scratch); + __ mulsd(result, input); __ bind(&done); } #undef __ +static const int kNoCodeAgeSequenceLength = 5; + +static byte* GetNoCodeAgeSequence(uint32_t* length) { + static bool initialized = false; + static byte sequence[kNoCodeAgeSequenceLength]; + *length = kNoCodeAgeSequenceLength; + if (!initialized) { + // The sequence of instructions that is patched out for aging code is the + // following boilerplate stack-building prologue that is found both in + // FUNCTION and OPTIMIZED_FUNCTION code: + CodePatcher patcher(sequence, kNoCodeAgeSequenceLength); + patcher.masm()->push(ebp); + patcher.masm()->mov(ebp, esp); + patcher.masm()->push(esi); + patcher.masm()->push(edi); + initialized = true; + } + return sequence; +} + + +bool Code::IsYoungSequence(byte* sequence) { + uint32_t young_length; + byte* young_sequence = GetNoCodeAgeSequence(&young_length); + bool result = (!memcmp(sequence, young_sequence, young_length)); + ASSERT(result || *sequence == kCallOpcode); + return result; +} + + +void Code::GetCodeAgeAndParity(byte* sequence, Age* age, + MarkingParity* parity) { + if (IsYoungSequence(sequence)) { + *age = kNoAge; + *parity = NO_MARKING_PARITY; + } else { + sequence++; // Skip the kCallOpcode byte + Address target_address = sequence + *reinterpret_cast<int*>(sequence) + + Assembler::kCallTargetAddressOffset; + Code* stub = GetCodeFromTargetAddress(target_address); + GetCodeAgeAndParity(stub, age, parity); + } +} + + +void Code::PatchPlatformCodeAge(byte* sequence, + Code::Age age, + MarkingParity parity) { + uint32_t young_length; + byte* young_sequence = GetNoCodeAgeSequence(&young_length); + if (age == kNoAge) { + memcpy(sequence, young_sequence, young_length); + CPU::FlushICache(sequence, young_length); + } else { + Code* stub = GetCodeAgeStub(age, parity); + CodePatcher patcher(sequence, young_length); + patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE); + } +} + + } } // namespace v8::internal #endif // V8_TARGET_ARCH_IA32 diff --git a/deps/v8/src/ia32/codegen-ia32.h b/deps/v8/src/ia32/codegen-ia32.h index f4ab0b50f6..5137274145 100644 --- a/deps/v8/src/ia32/codegen-ia32.h +++ b/deps/v8/src/ia32/codegen-ia32.h @@ -88,6 +88,20 @@ class StringCharLoadGenerator : public AllStatic { DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator); }; + +class MathExpGenerator : public AllStatic { + public: + static void EmitMathExp(MacroAssembler* masm, + XMMRegister input, + XMMRegister result, + XMMRegister double_scratch, + Register temp1, + Register temp2); + + private: + DISALLOW_COPY_AND_ASSIGN(MathExpGenerator); +}; + } } // namespace v8::internal #endif // V8_IA32_CODEGEN_IA32_H_ diff --git a/deps/v8/src/ia32/deoptimizer-ia32.cc b/deps/v8/src/ia32/deoptimizer-ia32.cc index f50010b9d9..c9ecaccd2d 100644 --- a/deps/v8/src/ia32/deoptimizer-ia32.cc +++ b/deps/v8/src/ia32/deoptimizer-ia32.cc @@ -198,19 +198,7 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { // ignore all slots that might have been recorded on it. isolate->heap()->mark_compact_collector()->InvalidateCode(code); - // Iterate over all the functions which share the same code object - // and make them use unoptimized version. - Context* context = function->context()->native_context(); - Object* element = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); - SharedFunctionInfo* shared = function->shared(); - while (!element->IsUndefined()) { - JSFunction* func = JSFunction::cast(element); - // Grab element before code replacement as ReplaceCode alters the list. - element = func->next_function_link(); - if (func->code() == code) { - func->ReplaceCode(shared->code()); - } - } + ReplaceCodeForRelatedFunctions(function, code); if (FLAG_trace_deopt) { PrintF("[forced deoptimization: "); @@ -222,8 +210,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { static const byte kJnsInstruction = 0x79; static const byte kJnsOffset = 0x13; -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; @@ -236,31 +222,26 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, Address call_target_address = pc_after - kIntSize; ASSERT_EQ(check_code->entry(), Assembler::target_address_at(call_target_address)); - // The stack check code matches the pattern: + // The back edge bookkeeping code matches the pattern: // - // cmp esp, <limit> - // jae ok + // sub <profiling_counter>, <delta> + // jns ok // call <stack guard> // test eax, <loop nesting depth> // ok: ... // // We will patch away the branch so the code is: // - // cmp esp, <limit> ;; Not changed + // sub <profiling_counter>, <delta> ;; Not changed // nop // nop // call <on-stack replacment> // test eax, <loop nesting depth> // ok: - 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)); + ASSERT_EQ(kJnsInstruction, *(call_target_address - 3)); + ASSERT_EQ(kJnsOffset, *(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, @@ -284,13 +265,8 @@ void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code, 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; - } + *(call_target_address - 3) = kJnsInstruction; + *(call_target_address - 2) = kJnsOffset; Assembler::set_target_address_at(call_target_address, check_code->entry()); diff --git a/deps/v8/src/ia32/disasm-ia32.cc b/deps/v8/src/ia32/disasm-ia32.cc index 008fdde7ea..1ac3b2eb23 100644 --- a/deps/v8/src/ia32/disasm-ia32.cc +++ b/deps/v8/src/ia32/disasm-ia32.cc @@ -869,6 +869,7 @@ static const char* F0Mnem(byte f0byte) { case 0xAF: return "imul"; case 0xA5: return "shld"; case 0xAD: return "shrd"; + case 0xAC: return "shrd"; // 3-operand version. case 0xAB: return "bts"; default: return NULL; } @@ -1305,6 +1306,14 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, NameOfXMMRegister(rm), static_cast<int>(imm8)); data += 2; + } else if (*data == 0x76) { + data++; + int mod, regop, rm; + get_modrm(*data, &mod, ®op, &rm); + AppendToBuffer("pcmpeqd %s,%s", + NameOfXMMRegister(regop), + NameOfXMMRegister(rm)); + data++; } else if (*data == 0x90) { data++; AppendToBuffer("nop"); // 2 byte nop. diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index 7fb7cc3215..50713b5c14 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -119,7 +119,7 @@ void FullCodeGenerator::Generate() { handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell( - Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget))); + Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); @@ -156,6 +156,7 @@ void FullCodeGenerator::Generate() { // the frame (that is done below). FrameScope frame_scope(masm_, StackFrame::MANUAL); + info->set_prologue_offset(masm_->pc_offset()); __ push(ebp); // Caller's frame pointer. __ mov(ebp, esp); __ push(esi); // Callee's context. @@ -328,39 +329,27 @@ void FullCodeGenerator::EmitProfilingCounterReset() { } -void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, - Label* back_edge_target) { - Comment cmnt(masm_, "[ Stack check"); +void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, + Label* back_edge_target) { + Comment cmnt(masm_, "[ Back edge bookkeeping"); Label ok; - 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 / kBackEdgeDistanceUnit)); - } - EmitProfilingCounterDecrement(weight); - __ j(positive, &ok, Label::kNear); - InterruptStub stub; - __ CallStub(&stub); - } else { - // Count based interrupts happen often enough when they are enabled - // that the additional stack checks are not necessary (they would - // only check for interrupts). - ExternalReference stack_limit = - ExternalReference::address_of_stack_limit(isolate()); - __ cmp(esp, Operand::StaticVariable(stack_limit)); - __ j(above_equal, &ok, Label::kNear); - StackCheckStub stub; - __ CallStub(&stub); + 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 / kBackEdgeDistanceUnit)); } + EmitProfilingCounterDecrement(weight); + __ j(positive, &ok, Label::kNear); + InterruptStub 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. - RecordStackCheck(stmt->OsrEntryId()); + RecordBackEdge(stmt->OsrEntryId()); // Loop stack checks can be patched to perform on-stack replacement. In // order to decide whether or not to perform OSR we embed the loop depth @@ -369,9 +358,7 @@ void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, ASSERT(loop_depth() > 0); __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker))); - if (FLAG_count_based_interrupts) { - EmitProfilingCounterReset(); - } + EmitProfilingCounterReset(); __ bind(&ok); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); @@ -754,8 +741,7 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { - // The variable in the declaration always resides in the current function - // context. + // The variable in the declaration always resides in the current context. ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); if (generate_debug_code_) { // Check that we're not inside a with or catch context. @@ -884,33 +870,32 @@ void FullCodeGenerator::VisitFunctionDeclaration( void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { - VariableProxy* proxy = declaration->proxy(); - Variable* variable = proxy->var(); - Handle<JSModule> instance = declaration->module()->interface()->Instance(); - ASSERT(!instance.is_null()); + Variable* variable = declaration->proxy()->var(); + ASSERT(variable->location() == Variable::CONTEXT); + ASSERT(variable->interface()->IsFrozen()); - switch (variable->location()) { - case Variable::UNALLOCATED: { - Comment cmnt(masm_, "[ ModuleDeclaration"); - globals_->Add(variable->name(), zone()); - globals_->Add(instance, zone()); - Visit(declaration->module()); - break; - } + Comment cmnt(masm_, "[ ModuleDeclaration"); + EmitDebugCheckDeclarationContext(variable); - case Variable::CONTEXT: { - Comment cmnt(masm_, "[ ModuleDeclaration"); - EmitDebugCheckDeclarationContext(variable); - __ mov(ContextOperand(esi, variable->index()), Immediate(instance)); - Visit(declaration->module()); - break; - } + // Load instance object. + __ LoadContext(eax, scope_->ContextChainLength(scope_->GlobalScope())); + __ mov(eax, ContextOperand(eax, variable->interface()->Index())); + __ mov(eax, ContextOperand(eax, Context::EXTENSION_INDEX)); - case Variable::PARAMETER: - case Variable::LOCAL: - case Variable::LOOKUP: - UNREACHABLE(); - } + // Assign it. + __ mov(ContextOperand(esi, variable->index()), eax); + // We know that we have written a module, which is not a smi. + __ RecordWriteContextSlot(esi, + Context::SlotOffset(variable->index()), + eax, + ecx, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS); + + // Traverse into body. + Visit(declaration->module()); } @@ -945,13 +930,21 @@ void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { // Call the runtime to declare the globals. __ push(esi); // The context is the first argument. - __ push(Immediate(pairs)); - __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags()))); + __ Push(pairs); + __ Push(Smi::FromInt(DeclareGlobalsFlags())); __ CallRuntime(Runtime::kDeclareGlobals, 3); // Return value is ignored. } +void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) { + // Call the runtime to declare the modules. + __ Push(descriptions); + __ CallRuntime(Runtime::kDeclareModules, 1); + // Return value is ignored. +} + + void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { Comment cmnt(masm_, "[ SwitchStatement"); Breakable nested_statement(this, stmt); @@ -1193,7 +1186,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ bind(loop_statement.continue_label()); __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); - EmitStackCheck(stmt, &loop); + EmitBackEdgeBookkeeping(stmt, &loop); __ jmp(&loop); // Remove the pointers stored on the stack. @@ -1346,9 +1339,9 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, } else if (var->mode() == DYNAMIC_LOCAL) { Variable* local = var->local_if_not_shadowed(); __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); - if (local->mode() == CONST || - local->mode() == CONST_HARMONY || - local->mode() == LET) { + if (local->mode() == LET || + local->mode() == CONST || + local->mode() == CONST_HARMONY) { __ cmp(eax, isolate()->factory()->the_hole_value()); __ j(not_equal, done); if (local->mode() == CONST) { @@ -2139,37 +2132,15 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { ASSERT(prop != NULL); ASSERT(prop->key()->AsLiteral() != NULL); - // If the assignment starts a block of assignments to the same object, - // change to slow case to avoid the quadratic behavior of repeatedly - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - __ push(Operand(esp, kPointerSize)); // Receiver is now under value. - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - // Record source code position before IC call. SetSourcePosition(expr->position()); __ mov(ecx, prop->key()->AsLiteral()->handle()); - if (expr->ends_initialization_block()) { - __ mov(edx, Operand(esp, 0)); - } else { - __ pop(edx); - } + __ pop(edx); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ push(eax); // Result of assignment, saved even if not needed. - __ push(Operand(esp, kPointerSize)); // Receiver is under value. - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(eax); - __ Drop(1); - } PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(eax); } @@ -2181,23 +2152,8 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { // 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 - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - // Receiver is now under the key and value. - __ push(Operand(esp, 2 * kPointerSize)); - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - __ pop(ecx); // Key. - if (expr->ends_initialization_block()) { - __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. - } else { - __ pop(edx); - } + __ pop(edx); // Record source code position before IC call. SetSourcePosition(expr->position()); Handle<Code> ic = is_classic_mode() @@ -2205,15 +2161,6 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ pop(edx); - __ push(eax); // Result of assignment, saved even if not needed. - __ push(edx); - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(eax); - } - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(eax); } @@ -2371,7 +2318,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { VariableProxy* proxy = callee->AsVariableProxy(); Property* property = callee->AsProperty(); - if (proxy != NULL && proxy->var()->is_possibly_eval()) { + if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { // In a call to eval, we first call %ResolvePossiblyDirectEval to // resolve the function we need to call and the receiver of the call. // Then we call the resolved function using the given arguments. @@ -2653,7 +2600,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - if (generate_debug_code_) __ AbortIfSmi(eax); + __ AssertNotSmi(eax); // Check whether this map has already been checked to be safe for default // valueOf. @@ -2669,22 +2616,28 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ j(equal, if_false); // Look for valueOf symbol in the descriptor array, and indicate false if - // found. The type is not checked, so if it is a transition it is a false - // negative. + // found. Since we omit an enumeration index check, if it is added via a + // transition that shares its descriptor array, this is a false positive. + Label entry, loop, done; + + // Skip loop if no descriptors are valid. + __ NumberOfOwnDescriptors(ecx, ebx); + __ cmp(ecx, 0); + __ j(equal, &done); + __ LoadInstanceDescriptors(ebx, ebx); - __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); - // ebx: descriptor array - // ecx: length of descriptor array + // ebx: descriptor array. + // ecx: valid entries in the descriptor array. // Calculate the end of the descriptor array. STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); STATIC_ASSERT(kPointerSize == 4); - __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); + __ imul(ecx, ecx, DescriptorArray::kDescriptorSize); + __ lea(ecx, Operand(ebx, ecx, times_2, DescriptorArray::kFirstOffset)); // Calculate location of the first key name. __ add(ebx, Immediate(DescriptorArray::kFirstOffset)); // Loop through all the keys in the descriptor array. If one of these is the // symbol valueOf the result is false. - Label entry, loop; __ jmp(&entry); __ bind(&loop); __ mov(edx, FieldOperand(ebx, 0)); @@ -2695,10 +2648,12 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ cmp(ebx, ecx); __ j(not_equal, &loop); + __ bind(&done); + // Reload map as register ebx was used as temporary above. __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); - // If a valueOf property is not found on the object check that it's + // If a valueOf property is not found on the object check that its // prototype is the un-modified String prototype. If not result is false. __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); __ JumpIfSmi(ecx, if_false); @@ -2876,7 +2831,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); __ bind(&exit); - if (generate_debug_code_) __ AbortIfNotSmi(eax); + __ AssertSmi(eax); context()->Plug(eax); } @@ -3105,6 +3060,38 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) { } +void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { + ZoneList<Expression*>* args = expr->arguments(); + ASSERT_EQ(3, args->length()); + + VisitForStackValue(args->at(1)); // index + VisitForStackValue(args->at(2)); // value + __ pop(ecx); + __ pop(ebx); + VisitForAccumulatorValue(args->at(0)); // string + + static const String::Encoding encoding = String::ONE_BYTE_ENCODING; + SeqStringSetCharGenerator::Generate(masm_, encoding, eax, ebx, ecx); + context()->Plug(eax); +} + + +void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { + ZoneList<Expression*>* args = expr->arguments(); + ASSERT_EQ(3, args->length()); + + VisitForStackValue(args->at(1)); // index + VisitForStackValue(args->at(2)); // value + __ pop(ecx); + __ pop(ebx); + VisitForAccumulatorValue(args->at(0)); // string + + static const String::Encoding encoding = String::TWO_BYTE_ENCODING; + SeqStringSetCharGenerator::Generate(masm_, encoding, eax, ebx, ecx); + context()->Plug(eax); +} + + void FullCodeGenerator::EmitMathPow(CallRuntime* expr) { // Load the arguments on the stack and call the runtime function. ZoneList<Expression*>* args = expr->arguments(); @@ -3500,9 +3487,7 @@ void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { VisitForAccumulatorValue(args->at(0)); - if (generate_debug_code_) { - __ AbortIfNotString(eax); - } + __ AssertString(eax); Label materialize_true, materialize_false; Label* if_true = NULL; @@ -3525,7 +3510,7 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) { ASSERT(args->length() == 1); VisitForAccumulatorValue(args->at(0)); - __ AbortIfNotString(eax); + __ AssertString(eax); __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); __ IndexFromHash(eax, eax); @@ -3613,10 +3598,10 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); __ and_(scratch, Immediate( kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); - __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); + __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag); __ j(not_equal, &bailout); __ add(string_length, - FieldOperand(string, SeqAsciiString::kLengthOffset)); + FieldOperand(string, SeqOneByteString::kLengthOffset)); __ j(overflow, &bailout); __ add(index, Immediate(1)); __ cmp(index, array_length); @@ -3645,14 +3630,15 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); __ and_(scratch, Immediate( - kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); + kIsNotStringMask | kStringEncodingMask | kAsciiDataHintMask | + kStringRepresentationMask)); __ cmp(scratch, ASCII_STRING_TYPE); __ j(not_equal, &bailout); // Add (separator length times array_length) - separator length // to string_length. __ mov(scratch, separator_operand); - __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); + __ mov(scratch, FieldOperand(scratch, SeqOneByteString::kLengthOffset)); __ sub(string_length, scratch); // May be negative, temporarily. __ imul(scratch, array_length_operand); __ j(overflow, &bailout); @@ -3666,11 +3652,11 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ AllocateAsciiString(result_pos, string_length, scratch, index, string, &bailout); __ mov(result_operand, result_pos); - __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize)); + __ lea(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize)); __ mov(string, separator_operand); - __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset), + __ cmp(FieldOperand(string, SeqOneByteString::kLengthOffset), Immediate(Smi::FromInt(1))); __ j(equal, &one_char_separator); __ j(greater, &long_separator); @@ -3695,7 +3681,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { FieldOperand(string, String::kLengthOffset)); __ shr(string_length, 1); __ lea(string, - FieldOperand(string, SeqAsciiString::kHeaderSize)); + FieldOperand(string, SeqOneByteString::kHeaderSize)); __ CopyBytes(string, result_pos, string_length, scratch); __ add(index, Immediate(1)); __ bind(&loop_1_condition); @@ -3708,7 +3694,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // One-character separator case __ bind(&one_char_separator); // Replace separator with its ASCII character value. - __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize)); + __ mov_b(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize)); __ mov_b(separator_operand, scratch); __ Set(index, Immediate(0)); @@ -3736,7 +3722,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { FieldOperand(string, String::kLengthOffset)); __ shr(string_length, 1); __ lea(string, - FieldOperand(string, SeqAsciiString::kHeaderSize)); + FieldOperand(string, SeqOneByteString::kHeaderSize)); __ CopyBytes(string, result_pos, string_length, scratch); __ add(index, Immediate(1)); @@ -3765,7 +3751,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { FieldOperand(string, String::kLengthOffset)); __ shr(string_length, 1); __ lea(string, - FieldOperand(string, SeqAsciiString::kHeaderSize)); + FieldOperand(string, SeqOneByteString::kHeaderSize)); __ CopyBytes(string, result_pos, string_length, scratch); __ bind(&loop_3_entry); @@ -3777,7 +3763,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { FieldOperand(string, String::kLengthOffset)); __ shr(string_length, 1); __ lea(string, - FieldOperand(string, SeqAsciiString::kHeaderSize)); + FieldOperand(string, SeqOneByteString::kHeaderSize)); __ CopyBytes(string, result_pos, string_length, scratch); __ add(index, Immediate(1)); @@ -4326,29 +4312,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { default: { VisitForAccumulatorValue(expr->right()); - Condition cc = no_condition; - switch (op) { - case Token::EQ_STRICT: - case Token::EQ: - cc = equal; - break; - case Token::LT: - cc = less; - break; - case Token::GT: - cc = greater; - break; - case Token::LTE: - cc = less_equal; - break; - case Token::GTE: - cc = greater_equal; - break; - case Token::IN: - case Token::INSTANCEOF: - default: - UNREACHABLE(); - } + Condition cc = CompareIC::ComputeCondition(op); __ pop(edx); bool inline_smi_code = ShouldInlineSmiCase(op); diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc index 52d8fa1452..ac5af2bf66 100644 --- a/deps/v8/src/ia32/ic-ia32.cc +++ b/deps/v8/src/ia32/ic-ia32.cc @@ -747,6 +747,125 @@ void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) { } +static void KeyedStoreGenerateGenericHelper( + MacroAssembler* masm, + Label* fast_object, + Label* fast_double, + Label* slow, + KeyedStoreCheckMap check_map, + KeyedStoreIncrementLength increment_length) { + Label transition_smi_elements; + Label finish_object_store, non_double_value, transition_double_elements; + Label fast_double_without_map_check; + // eax: value + // ecx: key (a smi) + // edx: receiver + // ebx: FixedArray receiver->elements + // edi: receiver map + // Fast case: Do the store, could either Object or double. + __ bind(fast_object); + if (check_map == kCheckMap) { + __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset)); + __ cmp(edi, masm->isolate()->factory()->fixed_array_map()); + __ j(not_equal, fast_double); + } + // Smi stores don't require further checks. + Label non_smi_value; + __ JumpIfNotSmi(eax, &non_smi_value); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ add(FieldOperand(edx, JSArray::kLengthOffset), + Immediate(Smi::FromInt(1))); + } + // It's irrelevant whether array is smi-only or not when writing a smi. + __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax); + __ ret(0); + + __ bind(&non_smi_value); + // Escape to elements kind transition case. + __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); + __ CheckFastObjectElements(edi, &transition_smi_elements); + + // Fast elements array, store the value to the elements backing store. + __ bind(&finish_object_store); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ add(FieldOperand(edx, JSArray::kLengthOffset), + Immediate(Smi::FromInt(1))); + } + __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax); + // Update write barrier for the elements array address. + __ mov(edx, eax); // Preserve the value which is returned. + __ RecordWriteArray( + ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); + __ ret(0); + + __ bind(fast_double); + if (check_map == kCheckMap) { + // Check for fast double array case. If this fails, call through to the + // runtime. + __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map()); + __ j(not_equal, slow); + // If the value is a number, store it as a double in the FastDoubleElements + // array. + } + __ bind(&fast_double_without_map_check); + __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0, + &transition_double_elements, false); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ add(FieldOperand(edx, JSArray::kLengthOffset), + Immediate(Smi::FromInt(1))); + } + __ ret(0); + + __ bind(&transition_smi_elements); + __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); + + // Transition the array appropriately depending on the value type. + __ CheckMap(eax, + masm->isolate()->factory()->heap_number_map(), + &non_double_value, + DONT_DO_SMI_CHECK); + + // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS + // and complete the store. + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_DOUBLE_ELEMENTS, + ebx, + edi, + slow); + ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow); + __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); + __ jmp(&fast_double_without_map_check); + + __ bind(&non_double_value); + // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_ELEMENTS, + ebx, + edi, + slow); + ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); + __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); + + __ bind(&transition_double_elements); + // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a + // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and + // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS + __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); + __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, + FAST_ELEMENTS, + ebx, + edi, + slow); + ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow); + __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); +} + + void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode) { // ----------- S t a t e ------------- @@ -755,10 +874,9 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // -- edx : receiver // -- esp[0] : return address // ----------------------------------- - Label slow, fast_object_with_map_check, fast_object_without_map_check; - Label fast_double_with_map_check, fast_double_without_map_check; - Label check_if_double_array, array, extra, transition_smi_elements; - Label finish_object_store, non_double_value, transition_double_elements; + Label slow, fast_object, fast_object_grow; + Label fast_double, fast_double_grow; + Label array, extra, check_if_double_array; // Check that the object isn't a smi. __ JumpIfSmi(edx, &slow); @@ -785,7 +903,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); // Check array bounds. Both the key and the length of FixedArray are smis. __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); - __ j(below, &fast_object_with_map_check); + __ j(below, &fast_object); // Slow case: call runtime. __ bind(&slow); @@ -808,18 +926,12 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset)); __ cmp(edi, masm->isolate()->factory()->fixed_array_map()); __ j(not_equal, &check_if_double_array); - // Add 1 to receiver->length, and go to common element store code for Objects. - __ add(FieldOperand(edx, JSArray::kLengthOffset), - Immediate(Smi::FromInt(1))); - __ jmp(&fast_object_without_map_check); + __ jmp(&fast_object_grow); __ bind(&check_if_double_array); __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map()); __ j(not_equal, &slow); - // Add 1 to receiver->length, and go to common element store code for doubles. - __ add(FieldOperand(edx, JSArray::kLengthOffset), - Immediate(Smi::FromInt(1))); - __ jmp(&fast_double_without_map_check); + __ jmp(&fast_double_grow); // Array case: Get the length and the elements array from the JS // array. Check that the array is in fast mode (and writable); if it @@ -836,94 +948,10 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. __ j(above_equal, &extra); - // Fast case: Do the store, could either Object or double. - __ bind(&fast_object_with_map_check); - // eax: value - // ecx: key (a smi) - // edx: receiver - // ebx: FixedArray receiver->elements - // edi: receiver map - __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset)); - __ cmp(edi, masm->isolate()->factory()->fixed_array_map()); - __ j(not_equal, &fast_double_with_map_check); - __ bind(&fast_object_without_map_check); - // Smi stores don't require further checks. - Label non_smi_value; - __ JumpIfNotSmi(eax, &non_smi_value); - // It's irrelevant whether array is smi-only or not when writing a smi. - __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax); - __ ret(0); - - __ bind(&non_smi_value); - // Escape to elements kind transition case. - __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); - __ CheckFastObjectElements(edi, &transition_smi_elements); - - // Fast elements array, store the value to the elements backing store. - __ bind(&finish_object_store); - __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax); - // Update write barrier for the elements array address. - __ mov(edx, eax); // Preserve the value which is returned. - __ RecordWriteArray( - ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); - __ ret(0); - - __ bind(&fast_double_with_map_check); - // Check for fast double array case. If this fails, call through to the - // runtime. - __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map()); - __ j(not_equal, &slow); - __ bind(&fast_double_without_map_check); - // If the value is a number, store it as a double in the FastDoubleElements - // array. - __ StoreNumberToDoubleElements(eax, ebx, ecx, edx, xmm0, - &transition_double_elements, false); - __ ret(0); - - __ bind(&transition_smi_elements); - __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); - - // Transition the array appropriately depending on the value type. - __ CheckMap(eax, - masm->isolate()->factory()->heap_number_map(), - &non_double_value, - DONT_DO_SMI_CHECK); - - // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS - // and complete the store. - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS, - ebx, - edi, - &slow); - ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow); - __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); - __ jmp(&fast_double_without_map_check); - - __ bind(&non_double_value); - // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_ELEMENTS, - ebx, - edi, - &slow); - ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); - __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); - - __ bind(&transition_double_elements); - // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a - // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and - // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS - __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); - __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, - FAST_ELEMENTS, - ebx, - edi, - &slow); - ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow); - __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); + KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, + &slow, kCheckMap, kDontIncrementLength); + KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, + &slow, kDontCheckMap, kIncrementLength); } @@ -1687,7 +1715,7 @@ Condition CompareIC::ComputeCondition(Token::Value op) { } -static bool HasInlinedSmiCode(Address address) { +bool CompareIC::HasInlinedSmiCode(Address address) { // The address of the instruction following the call. Address test_instruction_address = address + Assembler::kCallTargetAddressOffset; @@ -1698,40 +1726,6 @@ static bool HasInlinedSmiCode(Address address) { } -void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { - HandleScope scope; - Handle<Code> rewritten; - State previous_state = GetState(); - - State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y); - if (state == GENERIC) { - CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); - rewritten = stub.GetCode(); - } else { - ICCompareStub stub(op_, state); - if (state == KNOWN_OBJECTS) { - stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map())); - } - rewritten = stub.GetCode(); - } - set_target(*rewritten); - -#ifdef DEBUG - if (FLAG_trace_ic) { - PrintF("[CompareIC (%s->%s)#%s]\n", - GetStateName(previous_state), - GetStateName(state), - Token::Name(op_)); - } -#endif - - // Activate inlined smi code. - if (previous_state == UNINITIALIZED) { - PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); - } -} - - void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { // The address of the instruction following the call. Address test_instruction_address = diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 2b42b13a1a..e03f73323d 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -176,6 +176,7 @@ bool LCodeGen::GeneratePrologue() { __ bind(&do_not_pad); } + info()->set_prologue_offset(masm_->pc_offset()); __ push(ebp); // Caller's frame pointer. __ mov(ebp, esp); __ push(esi); // Callee's context. @@ -293,7 +294,30 @@ bool LCodeGen::GenerateBody() { } if (emit_instructions) { - Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); + if (FLAG_code_comments) { + HValue* hydrogen = instr->hydrogen_value(); + if (hydrogen != NULL) { + if (hydrogen->IsChange()) { + HValue* changed_value = HChange::cast(hydrogen)->value(); + int use_id = 0; + const char* use_mnemo = "dead"; + if (hydrogen->UseCount() >= 1) { + HValue* use_value = hydrogen->uses().value(); + use_id = use_value->id(); + use_mnemo = use_value->Mnemonic(); + } + Comment(";;; @%d: %s. <of #%d %s for #%d %s>", + current_instruction_, instr->Mnemonic(), + changed_value->id(), changed_value->Mnemonic(), + use_id, use_mnemo); + } else { + Comment(";;; @%d: %s. <#%d>", current_instruction_, + instr->Mnemonic(), hydrogen->id()); + } + } else { + Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); + } + } instr->CompileToNative(this); } } @@ -404,7 +428,9 @@ Operand LCodeGen::HighOperand(LOperand* op) { void LCodeGen::WriteTranslation(LEnvironment* environment, - Translation* translation) { + Translation* translation, + int* arguments_index, + int* arguments_count) { if (environment == NULL) return; // The translation includes one command per value in the environment. @@ -412,7 +438,17 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, // The output frame height does not include the parameters. int height = translation_size - environment->parameter_count(); - WriteTranslation(environment->outer(), translation); + // Function parameters are arguments to the outermost environment. The + // arguments index points to the first element of a sequence of tagged + // values on the stack that represent the arguments. This needs to be + // kept in sync with the LArgumentsElements implementation. + *arguments_index = -environment->parameter_count(); + *arguments_count = environment->parameter_count(); + + WriteTranslation(environment->outer(), + translation, + arguments_index, + arguments_count); int closure_id = *info()->closure() != *environment->closure() ? DefineDeoptimizationLiteral(environment->closure()) : Translation::kSelfLiteralId; @@ -437,6 +473,17 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); break; } + + // Inlined frames which push their arguments cause the index to be + // bumped and another stack area to be used for materialization. + if (environment->entry() != NULL && + environment->entry()->arguments_pushed()) { + *arguments_index = *arguments_index < 0 + ? GetStackSlotCount() + : *arguments_index + *arguments_count; + *arguments_count = environment->entry()->arguments_count() + 1; + } + for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); // spilled_registers_ and spilled_double_registers_ are either @@ -448,7 +495,9 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, AddToTranslation(translation, environment->spilled_registers()[value->index()], environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } else if ( value->IsDoubleRegister() && environment->spilled_double_registers()[value->index()] != NULL) { @@ -457,14 +506,18 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation, environment->spilled_double_registers()[value->index()], false, - false); + false, + *arguments_index, + *arguments_count); } } AddToTranslation(translation, value, environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } } @@ -472,12 +525,14 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, void LCodeGen::AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32) { + bool is_uint32, + int arguments_index, + int arguments_count) { if (op == NULL) { // TODO(twuerthinger): Introduce marker operands to indicate that this value // is not present and must be reconstructed from the deoptimizer. Currently // this is only used for the arguments object. - translation->StoreArgumentsObject(); + translation->StoreArgumentsObject(arguments_index, arguments_count); } else if (op->IsStackSlot()) { if (is_tagged) { translation->StoreStackSlot(op->index()); @@ -596,15 +651,16 @@ void LCodeGen::RegisterEnvironmentForDeoptimization( int frame_count = 0; int jsframe_count = 0; + int args_index = 0; + int args_count = 0; for (LEnvironment* e = environment; e != NULL; e = e->outer()) { ++frame_count; if (e->frame_type() == JS_FUNCTION) { ++jsframe_count; } } - Translation translation(&translations_, frame_count, jsframe_count, - zone()); - WriteTranslation(environment, &translation); + Translation translation(&translations_, frame_count, jsframe_count, zone()); + WriteTranslation(environment, &translation, &args_index, &args_count); int deoptimization_index = deoptimizations_.length(); int pc_offset = masm()->pc_offset(); environment->Register(deoptimization_index, @@ -877,7 +933,7 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { void LCodeGen::DoModI(LModI* instr) { if (instr->hydrogen()->HasPowerOf2Divisor()) { - Register dividend = ToRegister(instr->InputAt(0)); + Register dividend = ToRegister(instr->left()); int32_t divisor = HConstant::cast(instr->hydrogen()->right())->Integer32Value(); @@ -901,8 +957,8 @@ void LCodeGen::DoModI(LModI* instr) { __ bind(&done); } else { Label done, remainder_eq_dividend, slow, do_subtraction, both_positive; - Register left_reg = ToRegister(instr->InputAt(0)); - Register right_reg = ToRegister(instr->InputAt(1)); + Register left_reg = ToRegister(instr->left()); + Register right_reg = ToRegister(instr->right()); Register result_reg = ToRegister(instr->result()); ASSERT(left_reg.is(eax)); @@ -932,7 +988,7 @@ void LCodeGen::DoModI(LModI* instr) { __ j(less, &remainder_eq_dividend, Label::kNear); // Check if the divisor is a PowerOfTwo integer. - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); __ mov(scratch, right_reg); __ sub(Operand(scratch), Immediate(1)); __ test(scratch, Operand(right_reg)); @@ -988,11 +1044,48 @@ void LCodeGen::DoModI(LModI* instr) { void LCodeGen::DoDivI(LDivI* instr) { - LOperand* right = instr->InputAt(1); + if (instr->hydrogen()->HasPowerOf2Divisor()) { + Register dividend = ToRegister(instr->left()); + int32_t divisor = + HConstant::cast(instr->hydrogen()->right())->Integer32Value(); + int32_t test_value = 0; + int32_t power = 0; + + if (divisor > 0) { + test_value = divisor - 1; + power = WhichPowerOf2(divisor); + } else { + // Check for (0 / -x) that will produce negative zero. + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { + __ test(dividend, Operand(dividend)); + DeoptimizeIf(zero, instr->environment()); + } + // Check for (kMinInt / -1). + if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { + __ cmp(dividend, kMinInt); + DeoptimizeIf(zero, instr->environment()); + } + test_value = - divisor - 1; + power = WhichPowerOf2(-divisor); + } + + if (test_value != 0) { + // Deoptimize if remainder is not 0. + __ test(dividend, Immediate(test_value)); + DeoptimizeIf(not_zero, instr->environment()); + __ sar(dividend, power); + } + + if (divisor < 0) __ neg(dividend); + + return; + } + + LOperand* right = instr->right(); ASSERT(ToRegister(instr->result()).is(eax)); - ASSERT(ToRegister(instr->InputAt(0)).is(eax)); - ASSERT(!ToRegister(instr->InputAt(1)).is(eax)); - ASSERT(!ToRegister(instr->InputAt(1)).is(edx)); + ASSERT(ToRegister(instr->left()).is(eax)); + ASSERT(!ToRegister(instr->right()).is(eax)); + ASSERT(!ToRegister(instr->right()).is(edx)); Register left_reg = eax; @@ -1013,7 +1106,7 @@ void LCodeGen::DoDivI(LDivI* instr) { __ bind(&left_not_zero); } - // Check for (-kMinInt / -1). + // Check for (kMinInt / -1). if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { Label left_not_min_int; __ cmp(left_reg, kMinInt); @@ -1034,10 +1127,10 @@ void LCodeGen::DoDivI(LDivI* instr) { void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { - ASSERT(instr->InputAt(1)->IsConstantOperand()); + ASSERT(instr->right()->IsConstantOperand()); - Register dividend = ToRegister(instr->InputAt(0)); - int32_t divisor = ToInteger32(LConstantOperand::cast(instr->InputAt(1))); + Register dividend = ToRegister(instr->left()); + int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); Register result = ToRegister(instr->result()); switch (divisor) { @@ -1083,9 +1176,9 @@ void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { __ sar(result, power); } } else { - ASSERT(ToRegister(instr->InputAt(0)).is(eax)); + ASSERT(ToRegister(instr->left()).is(eax)); ASSERT(ToRegister(instr->result()).is(edx)); - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); // Find b which: 2^b < divisor_abs < 2^(b+1). unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs); @@ -1137,11 +1230,11 @@ void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { void LCodeGen::DoMulI(LMulI* instr) { - Register left = ToRegister(instr->InputAt(0)); - LOperand* right = instr->InputAt(1); + Register left = ToRegister(instr->left()); + LOperand* right = instr->right(); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { - __ mov(ToRegister(instr->TempAt(0)), left); + __ mov(ToRegister(instr->temp()), left); } if (right->IsConstantOperand()) { @@ -1202,12 +1295,15 @@ void LCodeGen::DoMulI(LMulI* instr) { __ test(left, Operand(left)); __ j(not_zero, &done, Label::kNear); if (right->IsConstantOperand()) { - if (ToInteger32(LConstantOperand::cast(right)) <= 0) { + if (ToInteger32(LConstantOperand::cast(right)) < 0) { DeoptimizeIf(no_condition, instr->environment()); + } else if (ToInteger32(LConstantOperand::cast(right)) == 0) { + __ cmp(ToRegister(instr->temp()), Immediate(0)); + DeoptimizeIf(less, instr->environment()); } } else { // Test the non-zero operand for negative sign. - __ or_(ToRegister(instr->TempAt(0)), ToOperand(right)); + __ or_(ToRegister(instr->temp()), ToOperand(right)); DeoptimizeIf(sign, instr->environment()); } __ bind(&done); @@ -1216,8 +1312,8 @@ void LCodeGen::DoMulI(LMulI* instr) { void LCodeGen::DoBitI(LBitI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); ASSERT(left->IsRegister()); @@ -1257,14 +1353,21 @@ void LCodeGen::DoBitI(LBitI* instr) { void LCodeGen::DoShiftI(LShiftI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); ASSERT(left->IsRegister()); if (right->IsRegister()) { ASSERT(ToRegister(right).is(ecx)); switch (instr->op()) { + case Token::ROR: + __ ror_cl(ToRegister(left)); + if (instr->can_deopt()) { + __ test(ToRegister(left), Immediate(0x80000000)); + DeoptimizeIf(not_zero, instr->environment()); + } + break; case Token::SAR: __ sar_cl(ToRegister(left)); break; @@ -1286,6 +1389,14 @@ void LCodeGen::DoShiftI(LShiftI* instr) { int value = ToInteger32(LConstantOperand::cast(right)); uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); switch (instr->op()) { + case Token::ROR: + if (shift_count == 0 && instr->can_deopt()) { + __ test(ToRegister(left), Immediate(0x80000000)); + DeoptimizeIf(not_zero, instr->environment()); + } else { + __ ror(ToRegister(left), shift_count); + } + break; case Token::SAR: if (shift_count != 0) { __ sar(ToRegister(left), shift_count); @@ -1313,8 +1424,8 @@ void LCodeGen::DoShiftI(LShiftI* instr) { void LCodeGen::DoSubI(LSubI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); if (right->IsConstantOperand()) { @@ -1343,7 +1454,7 @@ void LCodeGen::DoConstantD(LConstantD* instr) { if (BitCast<uint64_t, double>(v) == 0) { __ xorps(res, res); } else { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); uint64_t int_val = BitCast<uint64_t, double>(v); int32_t lower = static_cast<int32_t>(int_val); int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt)); @@ -1386,7 +1497,7 @@ void LCodeGen::DoConstantT(LConstantT* instr) { void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ mov(result, FieldOperand(array, JSArray::kLengthOffset)); } @@ -1394,21 +1505,21 @@ void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { void LCodeGen::DoFixedArrayBaseLength( LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset)); } void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) { Register result = ToRegister(instr->result()); - Register map = ToRegister(instr->InputAt(0)); + Register map = ToRegister(instr->value()); __ EnumLength(result, map); } void LCodeGen::DoElementsKind(LElementsKind* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); // Load map into |result|. __ mov(result, FieldOperand(input, HeapObject::kMapOffset)); @@ -1422,9 +1533,9 @@ void LCodeGen::DoElementsKind(LElementsKind* instr) { void LCodeGen::DoValueOf(LValueOf* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); - Register map = ToRegister(instr->TempAt(0)); + Register map = ToRegister(instr->temp()); ASSERT(input.is(result)); Label done; @@ -1441,9 +1552,9 @@ void LCodeGen::DoValueOf(LValueOf* instr) { void LCodeGen::DoDateField(LDateField* instr) { - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->date()); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); Smi* index = instr->index(); Label runtime, done; ASSERT(object.is(result)); @@ -1476,8 +1587,17 @@ void LCodeGen::DoDateField(LDateField* instr) { } +void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { + SeqStringSetCharGenerator::Generate(masm(), + instr->encoding(), + ToRegister(instr->string()), + ToRegister(instr->index()), + ToRegister(instr->value())); +} + + void LCodeGen::DoBitNotI(LBitNotI* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->Equals(instr->result())); __ not_(ToRegister(input)); } @@ -1496,8 +1616,8 @@ void LCodeGen::DoThrow(LThrow* instr) { void LCodeGen::DoAddI(LAddI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); if (right->IsConstantOperand()) { @@ -1513,8 +1633,8 @@ void LCodeGen::DoAddI(LAddI* instr) { void LCodeGen::DoMathMinMax(LMathMinMax* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); HMathMinMax::Operation operation = instr->hydrogen()->operation(); if (instr->hydrogen()->representation().IsInteger32()) { @@ -1574,8 +1694,8 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { void LCodeGen::DoArithmeticD(LArithmeticD* instr) { - XMMRegister left = ToDoubleRegister(instr->InputAt(0)); - XMMRegister right = ToDoubleRegister(instr->InputAt(1)); + XMMRegister left = ToDoubleRegister(instr->left()); + XMMRegister right = ToDoubleRegister(instr->right()); XMMRegister result = ToDoubleRegister(instr->result()); // Modulo uses a fixed result register. ASSERT(instr->op() == Token::MOD || left.is(result)); @@ -1661,17 +1781,17 @@ void LCodeGen::DoBranch(LBranch* instr) { Representation r = instr->hydrogen()->value()->representation(); if (r.IsInteger32()) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); __ test(reg, Operand(reg)); EmitBranch(true_block, false_block, not_zero); } else if (r.IsDouble()) { - XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); + XMMRegister reg = ToDoubleRegister(instr->value()); __ xorps(xmm0, xmm0); __ ucomisd(reg, xmm0); EmitBranch(true_block, false_block, not_equal); } else { ASSERT(r.IsTagged()); - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); HType type = instr->hydrogen()->value()->type(); if (type.IsBoolean()) { __ cmp(reg, factory()->true_value()); @@ -1719,7 +1839,7 @@ void LCodeGen::DoBranch(LBranch* instr) { Register map = no_reg; // Keep the compiler happy. if (expected.NeedsMap()) { - map = ToRegister(instr->TempAt(0)); + map = ToRegister(instr->temp()); ASSERT(!map.is(reg)); __ mov(map, FieldOperand(reg, HeapObject::kMapOffset)); @@ -1812,8 +1932,8 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); Condition cc = TokenToCondition(instr->op(), instr->is_double()); @@ -1849,8 +1969,8 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); - Operand right = ToOperand(instr->InputAt(1)); + Register left = ToRegister(instr->left()); + Operand right = ToOperand(instr->right()); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -1860,7 +1980,7 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); + Register left = ToRegister(instr->left()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1870,7 +1990,7 @@ void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); int false_block = chunk_->LookupDestination(instr->false_block_id()); // If the expression is known to be untagged or a smi, then it's definitely @@ -1900,7 +2020,7 @@ void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { __ JumpIfSmi(reg, false_label); // Check for undetectable objects by looking in the bit field in // the map. The object has already been smi checked. - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset)); __ test(scratch, Immediate(1 << Map::kIsUndetectable)); @@ -1933,8 +2053,8 @@ Condition LCodeGen::EmitIsObject(Register input, void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1959,8 +2079,8 @@ Condition LCodeGen::EmitIsString(Register input, void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1973,7 +2093,7 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { - Operand input = ToOperand(instr->InputAt(0)); + Operand input = ToOperand(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1984,8 +2104,8 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register input = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2055,8 +2175,8 @@ static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register input = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2071,10 +2191,10 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); - __ AbortIfNotString(input); + __ AssertString(input); __ mov(result, FieldOperand(input, String::kHashFieldOffset)); __ IndexFromHash(result, result); @@ -2083,7 +2203,7 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { void LCodeGen::DoHasCachedArrayIndexAndBranch( LHasCachedArrayIndexAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2160,9 +2280,9 @@ void LCodeGen::EmitClassOfTest(Label* is_true, void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); - Register temp2 = ToRegister(instr->TempAt(1)); + Register input = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); + Register temp2 = ToRegister(instr->temp2()); Handle<String> class_name = instr->hydrogen()->class_name(); @@ -2179,7 +2299,7 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); int true_block = instr->true_block_id(); int false_block = instr->false_block_id(); @@ -2225,8 +2345,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr); Label done, false_result; - Register object = ToRegister(instr->InputAt(1)); - Register temp = ToRegister(instr->TempAt(0)); + Register object = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); // A Smi is not an instance of anything. __ JumpIfSmi(object, &false_result); @@ -2235,7 +2355,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { // hole value will be patched to the last map/result pair generated by the // instanceof stub. Label cache_miss; - Register map = ToRegister(instr->TempAt(0)); + Register map = ToRegister(instr->temp()); __ mov(map, FieldOperand(object, HeapObject::kMapOffset)); __ bind(deferred->map_check()); // Label for calculating code patching. Handle<JSGlobalPropertyCell> cache_cell = @@ -2286,7 +2406,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, // register which is pushed last by PushSafepointRegisters as top of the // stack is used to pass the offset to the location of the map check to // the stub. - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0); __ LoadHeapObject(InstanceofStub::right(), instr->function()); static const int kAdditionalDelta = 13; @@ -2453,7 +2573,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { HType type = instr->hydrogen()->value()->type(); SmiCheck check_needed = type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); int offset = Context::SlotOffset(instr->slot_index()); __ RecordWriteContextSlot(context, offset, @@ -2618,7 +2738,7 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { Register function = ToRegister(instr->function()); - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); Register result = ToRegister(instr->result()); // Check that the function really is a function. @@ -2660,7 +2780,7 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->object()); __ mov(result, FieldOperand(input, JSObject::kElementsOffset)); if (FLAG_debug_code) { Label done, ok, fail; @@ -2696,7 +2816,7 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) { void LCodeGen::DoLoadExternalArrayPointer( LLoadExternalArrayPointer* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->object()); __ mov(result, FieldOperand(input, ExternalArray::kExternalPointerOffset)); } @@ -2707,43 +2827,78 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { Register length = ToRegister(instr->length()); Operand index = ToOperand(instr->index()); Register result = ToRegister(instr->result()); - - __ sub(length, index); - DeoptimizeIf(below_equal, instr->environment()); - // There are two words between the frame pointer and the last argument. // Subtracting from length accounts for one of them add one more. + __ sub(length, index); __ mov(result, Operand(arguments, length, times_4, kPointerSize)); } -void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { - Register result = ToRegister(instr->result()); - - // Load the result. - __ mov(result, - BuildFastArrayOperand(instr->elements(), - instr->key(), - instr->hydrogen()->key()->representation(), - FAST_ELEMENTS, - FixedArray::kHeaderSize - kHeapObjectTag, - instr->additional_index())); - - // Check for the hole value. - if (instr->hydrogen()->RequiresHoleCheck()) { - if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { - __ test(result, Immediate(kSmiTagMask)); - DeoptimizeIf(not_equal, instr->environment()); - } else { - __ cmp(result, factory()->the_hole_value()); - DeoptimizeIf(equal, instr->environment()); +void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { + ElementsKind elements_kind = instr->elements_kind(); + LOperand* key = instr->key(); + if (!key->IsConstantOperand() && + ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), + elements_kind)) { + __ SmiUntag(ToRegister(key)); + } + Operand operand(BuildFastArrayOperand( + instr->elements(), + key, + instr->hydrogen()->key()->representation(), + elements_kind, + 0, + instr->additional_index())); + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { + XMMRegister result(ToDoubleRegister(instr->result())); + __ movss(result, operand); + __ cvtss2sd(result, result); + } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { + __ movdbl(ToDoubleRegister(instr->result()), operand); + } else { + Register result(ToRegister(instr->result())); + switch (elements_kind) { + case EXTERNAL_BYTE_ELEMENTS: + __ movsx_b(result, operand); + break; + case EXTERNAL_PIXEL_ELEMENTS: + case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: + __ movzx_b(result, operand); + break; + case EXTERNAL_SHORT_ELEMENTS: + __ movsx_w(result, operand); + break; + case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: + __ movzx_w(result, operand); + break; + case EXTERNAL_INT_ELEMENTS: + __ mov(result, operand); + break; + case EXTERNAL_UNSIGNED_INT_ELEMENTS: + __ mov(result, operand); + if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { + __ test(result, Operand(result)); + DeoptimizeIf(negative, instr->environment()); + } + break; + case EXTERNAL_FLOAT_ELEMENTS: + case EXTERNAL_DOUBLE_ELEMENTS: + case FAST_SMI_ELEMENTS: + case FAST_ELEMENTS: + case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + case DICTIONARY_ELEMENTS: + case NON_STRICT_ARGUMENTS_ELEMENTS: + UNREACHABLE(); + break; } } } -void LCodeGen::DoLoadKeyedFastDoubleElement( - LLoadKeyedFastDoubleElement* instr) { +void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { XMMRegister result = ToDoubleRegister(instr->result()); if (instr->hydrogen()->RequiresHoleCheck()) { @@ -2770,6 +2925,42 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( } +void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { + Register result = ToRegister(instr->result()); + + // Load the result. + __ mov(result, + BuildFastArrayOperand(instr->elements(), + instr->key(), + instr->hydrogen()->key()->representation(), + FAST_ELEMENTS, + FixedArray::kHeaderSize - kHeapObjectTag, + instr->additional_index())); + + // Check for the hole value. + if (instr->hydrogen()->RequiresHoleCheck()) { + if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { + __ test(result, Immediate(kSmiTagMask)); + DeoptimizeIf(not_equal, instr->environment()); + } else { + __ cmp(result, factory()->the_hole_value()); + DeoptimizeIf(equal, instr->environment()); + } + } +} + + +void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { + if (instr->is_external()) { + DoLoadKeyedExternalArray(instr); + } else if (instr->hydrogen()->representation().IsDouble()) { + DoLoadKeyedFixedDoubleArray(instr); + } else { + DoLoadKeyedFixedArray(instr); + } +} + + Operand LCodeGen::BuildFastArrayOperand( LOperand* elements_pointer, LOperand* key, @@ -2779,7 +2970,7 @@ Operand LCodeGen::BuildFastArrayOperand( uint32_t additional_index) { Register elements_pointer_reg = ToRegister(elements_pointer); int shift_size = ElementsKindToShiftSize(elements_kind); - // Even though the HLoad/StoreKeyedFastElement instructions force the input + // Even though the HLoad/StoreKeyed instructions force the input // representation for the key to be an integer, the input gets replaced during // bound check elimination with the index argument to the bounds check, which // can be tagged, so that case must be handled here, too. @@ -2804,71 +2995,6 @@ Operand LCodeGen::BuildFastArrayOperand( } -void LCodeGen::DoLoadKeyedSpecializedArrayElement( - LLoadKeyedSpecializedArrayElement* instr) { - ElementsKind elements_kind = instr->elements_kind(); - LOperand* key = instr->key(); - if (!key->IsConstantOperand() && - ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), - elements_kind)) { - __ SmiUntag(ToRegister(key)); - } - Operand operand(BuildFastArrayOperand( - instr->external_pointer(), - key, - instr->hydrogen()->key()->representation(), - elements_kind, - 0, - instr->additional_index())); - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { - XMMRegister result(ToDoubleRegister(instr->result())); - __ movss(result, operand); - __ cvtss2sd(result, result); - } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { - __ movdbl(ToDoubleRegister(instr->result()), operand); - } else { - Register result(ToRegister(instr->result())); - switch (elements_kind) { - case EXTERNAL_BYTE_ELEMENTS: - __ movsx_b(result, operand); - break; - case EXTERNAL_PIXEL_ELEMENTS: - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ movzx_b(result, operand); - break; - case EXTERNAL_SHORT_ELEMENTS: - __ movsx_w(result, operand); - break; - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ movzx_w(result, operand); - break; - case EXTERNAL_INT_ELEMENTS: - __ mov(result, operand); - break; - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ mov(result, operand); - if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { - __ test(result, Operand(result)); - DeoptimizeIf(negative, instr->environment()); - } - break; - case EXTERNAL_FLOAT_ELEMENTS: - case EXTERNAL_DOUBLE_ELEMENTS: - case FAST_SMI_ELEMENTS: - case FAST_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_HOLEY_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - case DICTIONARY_ELEMENTS: - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNREACHABLE(); - break; - } - } -} - - void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->object()).is(edx)); @@ -2909,7 +3035,7 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { - Operand elem = ToOperand(instr->InputAt(0)); + Operand elem = ToOperand(instr->elements()); Register result = ToRegister(instr->result()); Label done; @@ -2933,7 +3059,7 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { Register receiver = ToRegister(instr->receiver()); Register function = ToRegister(instr->function()); - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); // If the receiver is null or undefined, we have to pass the global // object as a receiver to normal functions. Values have to be @@ -3021,7 +3147,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { - LOperand* argument = instr->InputAt(0); + LOperand* argument = instr->value(); EmitPushTaggedOperand(argument); } @@ -3052,7 +3178,7 @@ void LCodeGen::DoOuterContext(LOuterContext* instr) { void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(esi)); + ASSERT(ToRegister(instr->context()).is(esi)); __ push(esi); // The context is the first argument. __ push(Immediate(instr->hydrogen()->pairs())); __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags()))); @@ -3385,11 +3511,11 @@ void LCodeGen::DoPower(LPower* instr) { Representation exponent_type = instr->hydrogen()->right()->representation(); // Having marked this as a call, we can use any registers. // Just make sure that the input/output registers are the expected ones. - ASSERT(!instr->InputAt(1)->IsDoubleRegister() || - ToDoubleRegister(instr->InputAt(1)).is(xmm1)); - ASSERT(!instr->InputAt(1)->IsRegister() || - ToRegister(instr->InputAt(1)).is(eax)); - ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2)); + ASSERT(!instr->right()->IsDoubleRegister() || + ToDoubleRegister(instr->right()).is(xmm1)); + ASSERT(!instr->right()->IsRegister() || + ToRegister(instr->right()).is(eax)); + ASSERT(ToDoubleRegister(instr->left()).is(xmm2)); ASSERT(ToDoubleRegister(instr->result()).is(xmm3)); if (exponent_type.IsTagged()) { @@ -3427,7 +3553,7 @@ void LCodeGen::DoRandom(LRandom* instr) { // Having marked this instruction as a call we can use any // registers. ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); - ASSERT(ToRegister(instr->InputAt(0)).is(eax)); + ASSERT(ToRegister(instr->global_object()).is(eax)); // Assert that the register size is indeed the size of each seed. static const int kSeedSize = sizeof(uint32_t); STATIC_ASSERT(kPointerSize == kSeedSize); @@ -3521,6 +3647,16 @@ void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { } +void LCodeGen::DoMathExp(LMathExp* instr) { + XMMRegister input = ToDoubleRegister(instr->value()); + XMMRegister result = ToDoubleRegister(instr->result()); + Register temp1 = ToRegister(instr->temp1()); + Register temp2 = ToRegister(instr->temp2()); + + MathExpGenerator::EmitMathExp(masm(), input, result, xmm0, temp1, temp2); +} + + void LCodeGen::DoMathTan(LUnaryMathOperation* instr) { ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); TranscendentalCacheStub stub(TranscendentalCache::TAN, @@ -3684,8 +3820,8 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { if (!instr->hydrogen()->NeedsWriteBarrierForMap()) { __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); } else { - Register temp = ToRegister(instr->TempAt(0)); - Register temp_map = ToRegister(instr->TempAt(1)); + Register temp = ToRegister(instr->temp()); + Register temp_map = ToRegister(instr->temp_map()); __ mov(temp_map, instr->transition()); __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map); // Update the write barrier for the map field. @@ -3706,7 +3842,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { if (instr->is_in_object()) { __ mov(FieldOperand(object, offset), value); if (instr->hydrogen()->NeedsWriteBarrier()) { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); // Update the write barrier for the object for in-object properties. __ RecordWriteField(object, offset, @@ -3717,7 +3853,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { check_needed); } } else { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset)); __ mov(FieldOperand(temp, offset), value); if (instr->hydrogen()->NeedsWriteBarrier()) { @@ -3786,8 +3922,7 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { } -void LCodeGen::DoStoreKeyedSpecializedArrayElement( - LStoreKeyedSpecializedArrayElement* instr) { +void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { ElementsKind elements_kind = instr->elements_kind(); LOperand* key = instr->key(); if (!key->IsConstantOperand() && @@ -3796,7 +3931,7 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( __ SmiUntag(ToRegister(key)); } Operand operand(BuildFastArrayOperand( - instr->external_pointer(), + instr->elements(), key, instr->hydrogen()->key()->representation(), elements_kind, @@ -3840,13 +3975,39 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( } -void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { +void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { + XMMRegister value = ToDoubleRegister(instr->value()); + + if (instr->NeedsCanonicalization()) { + Label 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(), + instr->hydrogen()->key()->representation(), + FAST_DOUBLE_ELEMENTS, + FixedDoubleArray::kHeaderSize - kHeapObjectTag, + instr->additional_index()); + __ movdbl(double_store_operand, value); +} + + +void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { Register value = ToRegister(instr->value()); - Register elements = ToRegister(instr->object()); + Register elements = ToRegister(instr->elements()); Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; Operand operand = BuildFastArrayOperand( - instr->object(), + instr->elements(), instr->key(), instr->hydrogen()->key()->representation(), FAST_ELEMENTS, @@ -3871,30 +4032,15 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { } -void LCodeGen::DoStoreKeyedFastDoubleElement( - LStoreKeyedFastDoubleElement* instr) { - XMMRegister value = ToDoubleRegister(instr->value()); - - if (instr->NeedsCanonicalization()) { - Label 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); +void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { + // By cases...external, fast-double, fast + if (instr->is_external()) { + DoStoreKeyedExternalArray(instr); + } else if (instr->hydrogen()->value()->representation().IsDouble()) { + DoStoreKeyedFixedDoubleArray(instr); + } else { + DoStoreKeyedFixedArray(instr); } - - Operand double_store_operand = BuildFastArrayOperand( - instr->elements(), - instr->key(), - instr->hydrogen()->key()->representation(), - FAST_DOUBLE_ELEMENTS, - FixedDoubleArray::kHeaderSize - kHeapObjectTag, - instr->additional_index()); - __ movdbl(double_store_operand, value); } @@ -3913,7 +4059,7 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { Register object_reg = ToRegister(instr->object()); - Register new_map_reg = ToRegister(instr->new_map_reg()); + Register new_map_reg = ToRegister(instr->new_map_temp()); Handle<Map> from_map = instr->original_map(); Handle<Map> to_map = instr->transitioned_map(); @@ -3933,14 +4079,14 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), Immediate(map)); // Write barrier. - ASSERT_NE(instr->temp_reg(), NULL); + ASSERT_NE(instr->temp(), NULL); __ RecordWriteForMap(object_reg, to_map, new_map_reg, - ToRegister(instr->temp_reg()), + ToRegister(instr->temp()), kDontSaveFPRegs); } else if (IsFastSmiElementsKind(from_kind) && IsFastDoubleElementsKind(to_kind)) { __ mov(new_map_reg, to_map); - Register fixed_object_reg = ToRegister(instr->temp_reg()); + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(edx)); ASSERT(new_map_reg.is(ebx)); __ mov(fixed_object_reg, object_reg); @@ -3949,7 +4095,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { } else if (IsFastDoubleElementsKind(from_kind) && IsFastObjectElementsKind(to_kind)) { __ mov(new_map_reg, to_map); - Register fixed_object_reg = ToRegister(instr->temp_reg()); + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(edx)); ASSERT(new_map_reg.is(ebx)); __ mov(fixed_object_reg, object_reg); @@ -4010,9 +4156,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { } CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr, instr->context()); - if (FLAG_debug_code) { - __ AbortIfNotSmi(eax); - } + __ AssertSmi(eax); __ SmiUntag(eax); __ StoreToSafepointRegisterSlot(result, eax); } @@ -4082,7 +4226,7 @@ void LCodeGen::DoStringAdd(LStringAdd* instr) { void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() || input->IsStackSlot()); LOperand* output = instr->result(); ASSERT(output->IsDoubleRegister()); @@ -4091,9 +4235,9 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); LOperand* output = instr->result(); - LOperand* temp = instr->TempAt(0); + LOperand* temp = instr->temp(); __ LoadUint32(ToDoubleRegister(output), ToRegister(input), @@ -4107,16 +4251,14 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { - codegen()->DoDeferredNumberTagI(instr_, - instr_->InputAt(0), - SIGNED_INT32); + codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32); } virtual LInstruction* instr() { return instr_; } private: LNumberTagI* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() && input->Equals(instr->result())); Register reg = ToRegister(input); @@ -4133,16 +4275,14 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr) : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { - codegen()->DoDeferredNumberTagI(instr_, - instr_->InputAt(0), - UNSIGNED_INT32); + codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32); } virtual LInstruction* instr() { return instr_; } private: LNumberTagU* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() && input->Equals(instr->result())); Register reg = ToRegister(input); @@ -4219,9 +4359,9 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { LNumberTagD* instr_; }; - XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + XMMRegister input_reg = ToDoubleRegister(instr->value()); Register reg = ToRegister(instr->result()); - Register tmp = ToRegister(instr->TempAt(0)); + Register tmp = ToRegister(instr->temp()); DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); if (FLAG_inline_new) { @@ -4256,7 +4396,7 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { void LCodeGen::DoSmiTag(LSmiTag* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() && input->Equals(instr->result())); ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); __ SmiTag(ToRegister(input)); @@ -4264,15 +4404,13 @@ void LCodeGen::DoSmiTag(LSmiTag* instr) { void LCodeGen::DoSmiUntag(LSmiUntag* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() && input->Equals(instr->result())); if (instr->needs_check()) { __ test(ToRegister(input), Immediate(kSmiTagMask)); DeoptimizeIf(not_zero, instr->environment()); } else { - if (FLAG_debug_code) { - __ AbortIfNotSmi(ToRegister(input)); - } + __ AssertSmi(ToRegister(input)); } __ SmiUntag(ToRegister(input)); } @@ -4333,7 +4471,7 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { Label done, heap_number; - Register input_reg = ToRegister(instr->InputAt(0)); + Register input_reg = ToRegister(instr->value()); // Heap number map check. __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), @@ -4344,6 +4482,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { // Check for undefined. Undefined is converted to zero for truncating // conversions. __ cmp(input_reg, factory()->undefined_value()); + __ RecordComment("Deferred TaggedToI: cannot truncate"); DeoptimizeIf(not_equal, instr->environment()); __ mov(input_reg, 0); __ jmp(&done, Label::kNear); @@ -4364,6 +4503,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { __ j(less, &convert, Label::kNear); // Pop FPU stack before deoptimizing. __ fstp(0); + __ RecordComment("Deferred TaggedToI: exponent too big"); DeoptimizeIf(no_condition, instr->environment()); // Reserve space for 64 bit answer. @@ -4374,7 +4514,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result. __ add(Operand(esp), Immediate(kDoubleSize)); } else { - XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0)); + XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); __ cvttsd2si(input_reg, Operand(xmm0)); __ cmp(input_reg, 0x80000000u); @@ -4389,20 +4529,24 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { } } else { // Deoptimize if we don't have a heap number. + __ RecordComment("Deferred TaggedToI: not a heap number"); DeoptimizeIf(not_equal, instr->environment()); - XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0)); + XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); __ cvttsd2si(input_reg, Operand(xmm0)); __ cvtsi2sd(xmm_temp, Operand(input_reg)); __ ucomisd(xmm0, xmm_temp); + __ RecordComment("Deferred TaggedToI: lost precision"); DeoptimizeIf(not_equal, instr->environment()); + __ RecordComment("Deferred TaggedToI: NaN"); DeoptimizeIf(parity_even, instr->environment()); // NaN. if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { __ test(input_reg, Operand(input_reg)); __ j(not_zero, &done); __ movmskpd(input_reg, xmm0); __ and_(input_reg, 1); + __ RecordComment("Deferred TaggedToI: minus zero"); DeoptimizeIf(not_zero, instr->environment()); } } @@ -4421,7 +4565,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { LTaggedToI* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); ASSERT(input->Equals(instr->result())); @@ -4440,9 +4584,9 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); - LOperand* temp = instr->TempAt(0); + LOperand* temp = instr->temp(); ASSERT(temp == NULL || temp->IsRegister()); LOperand* result = instr->result(); ASSERT(result->IsDoubleRegister()); @@ -4464,7 +4608,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { void LCodeGen::DoDoubleToI(LDoubleToI* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsDoubleRegister()); LOperand* result = instr->result(); ASSERT(result->IsRegister()); @@ -4502,7 +4646,7 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { __ bind(&done); } else { Label done; - Register temp_reg = ToRegister(instr->TempAt(0)); + Register temp_reg = ToRegister(instr->temp()); XMMRegister xmm_scratch = xmm0; // If cvttsd2si succeeded, we're done. Otherwise, we attempt @@ -4581,22 +4725,22 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { void LCodeGen::DoCheckSmi(LCheckSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); __ test(ToOperand(input), Immediate(kSmiTagMask)); DeoptimizeIf(not_zero, instr->environment()); } void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); __ test(ToOperand(input), Immediate(kSmiTagMask)); DeoptimizeIf(zero, instr->environment()); } void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { - Register input = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register input = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); @@ -4666,7 +4810,7 @@ void LCodeGen::DoCheckMapCommon(Register reg, void LCodeGen::DoCheckMaps(LCheckMaps* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); Register reg = ToRegister(input); @@ -4732,7 +4876,8 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { - Register reg = ToRegister(instr->TempAt(0)); + ASSERT(instr->temp()->Equals(instr->result())); + Register reg = ToRegister(instr->temp()); Handle<JSObject> holder = instr->holder(); Handle<JSObject> current_prototype = instr->prototype(); @@ -4772,7 +4917,7 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { new(zone()) DeferredAllocateObject(this, instr); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); Handle<JSFunction> constructor = instr->hydrogen()->constructor(); Handle<Map> initial_map(constructor->initial_map()); int instance_size = initial_map->instance_size(); @@ -4805,7 +4950,7 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset)); if (FLAG_debug_code) { - __ AbortIfSmi(map); + __ AssertNotSmi(map); __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset), instance_size >> kPointerSizeLog2); __ Assert(equal, "Unexpected instance size"); @@ -5091,7 +5236,7 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { void LCodeGen::DoToFastProperties(LToFastProperties* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(eax)); + ASSERT(ToRegister(instr->value()).is(eax)); __ push(eax); CallRuntime(Runtime::kToFastProperties, 1, instr); } @@ -5171,14 +5316,14 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { - LOperand* input = instr->InputAt(1); + LOperand* input = instr->value(); EmitPushTaggedOperand(input); CallRuntime(Runtime::kTypeof, 1, instr); } void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); Label* true_label = chunk_->GetAssemblyLabel(true_block); @@ -5262,7 +5407,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index 9058ede0eb..44ddaffcd4 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -129,7 +129,10 @@ class LCodeGen BASE_EMBEDDED { void DoGap(LGap* instr); // Emit frame translation commands for an environment. - void WriteTranslation(LEnvironment* environment, Translation* translation); + void WriteTranslation(LEnvironment* environment, + Translation* translation, + int* arguments_index, + int* arguments_count); void EnsureRelocSpaceForDeoptimization(); @@ -239,7 +242,9 @@ class LCodeGen BASE_EMBEDDED { void AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32); + bool is_uint32, + int arguments_index, + int arguments_count); void PopulateDeoptimizationData(Handle<Code> code); int DefineDeoptimizationLiteral(Handle<Object> literal); @@ -335,6 +340,12 @@ class LCodeGen BASE_EMBEDDED { int* offset); void EnsureSpaceForLazyDeopt(); + void DoLoadKeyedExternalArray(LLoadKeyed* instr); + void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); + void DoLoadKeyedFixedArray(LLoadKeyed* instr); + void DoStoreKeyedExternalArray(LStoreKeyed* instr); + void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); + void DoStoreKeyedFixedArray(LStoreKeyed* instr); // Emits code for pushing either a tagged constant, a (non-double) // register, or a stack slot operand. diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index f576e37e4f..d7ac7a8b14 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/deps/v8/src/ia32/lithium-ia32.cc @@ -179,6 +179,7 @@ const char* LArithmeticT::Mnemonic() const { case Token::BIT_AND: return "bit-and-t"; case Token::BIT_OR: return "bit-or-t"; case Token::BIT_XOR: return "bit-xor-t"; + case Token::ROR: return "ror-t"; case Token::SHL: return "sal-t"; case Token::SAR: return "sar-t"; case Token::SHR: return "shr-t"; @@ -196,22 +197,22 @@ void LGoto::PrintDataTo(StringStream* stream) { void LBranch::PrintDataTo(StringStream* stream) { stream->Add("B%d | B%d on ", true_block_id(), false_block_id()); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); } void LCmpIDAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - InputAt(0)->PrintTo(stream); + left()->PrintTo(stream); stream->Add(" %s ", Token::String(op())); - InputAt(1)->PrintTo(stream); + right()->PrintTo(stream); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); } void LIsNilAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(kind() == kStrictEquality ? " === " : " == "); stream->Add(nil() == kNullValue ? "null" : "undefined"); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); @@ -220,57 +221,57 @@ void LIsNilAndBranch::PrintDataTo(StringStream* stream) { void LIsObjectAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_object("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsStringAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_string("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_smi("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_undetectable("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LStringCompareAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if string_compare("); - InputAt(1)->PrintTo(stream); - InputAt(2)->PrintTo(stream); + left()->PrintTo(stream); + right()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_instance_type("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_cached_array_index("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if class_of_test("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(), true_block_id(), @@ -280,7 +281,7 @@ void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(" == \"%s\" then B%d else B%d", *hydrogen()->type_literal()->ToCString(), true_block_id(), false_block_id()); @@ -294,34 +295,39 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) { void LUnaryMathOperation::PrintDataTo(StringStream* stream) { stream->Add("/%s ", hydrogen()->OpName()); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); +} + + +void LMathExp::PrintDataTo(StringStream* stream) { + value()->PrintTo(stream); } void LMathPowHalf::PrintDataTo(StringStream* stream) { stream->Add("/pow_half "); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); } void LLoadContextSlot::PrintDataTo(StringStream* stream) { - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); stream->Add("[%d]", slot_index()); } void LStoreContextSlot::PrintDataTo(StringStream* stream) { - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); stream->Add("[%d] <- ", slot_index()); - InputAt(1)->PrintTo(stream); + value()->PrintTo(stream); } void LInvokeFunction::PrintDataTo(StringStream* stream) { stream->Add("= "); - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); stream->Add(" "); - InputAt(1)->PrintTo(stream); + function()->PrintTo(stream); stream->Add(" #%d / ", arity()); } @@ -350,7 +356,9 @@ void LCallKnownGlobal::PrintDataTo(StringStream* stream) { void LCallNew::PrintDataTo(StringStream* stream) { stream->Add("= "); - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); + stream->Add(" "); + constructor()->PrintTo(stream); stream->Add(" #%d / ", arity()); } @@ -405,20 +413,27 @@ void LStoreNamedGeneric::PrintDataTo(StringStream* stream) { } -void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) { - object()->PrintTo(stream); +void LLoadKeyed::PrintDataTo(StringStream* stream) { + elements()->PrintTo(stream); stream->Add("["); key()->PrintTo(stream); - stream->Add("] <- "); - value()->PrintTo(stream); + if (hydrogen()->IsDehoisted()) { + stream->Add(" + %d]", additional_index()); + } else { + stream->Add("]"); + } } -void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) { +void LStoreKeyed::PrintDataTo(StringStream* stream) { elements()->PrintTo(stream); stream->Add("["); key()->PrintTo(stream); - stream->Add("] <- "); + if (hydrogen()->IsDehoisted()) { + stream->Add(" + %d] <-", additional_index()); + } else { + stream->Add("] <- "); + } value()->PrintTo(stream); } @@ -886,6 +901,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment( argument_count_, value_count, outer, + hydrogen_env->entry(), zone()); int argument_index = *argument_index_accumulator; for (int i = 0; i < value_count; ++i) { @@ -1076,6 +1092,14 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context, input); return DefineSameAsFirst(result); + } else if (op == kMathExp) { + ASSERT(instr->representation().IsDouble()); + ASSERT(instr->value()->representation().IsDouble()); + LOperand* value = UseTempRegister(instr->value()); + LOperand* temp1 = TempRegister(); + LOperand* temp2 = TempRegister(); + LMathExp* result = new(zone()) LMathExp(value, temp1, temp2); + return DefineAsRegister(result); } else if (op == kMathSin || op == kMathCos || op == kMathTan) { LOperand* context = UseFixed(instr->context(), esi); LOperand* input = UseFixedDouble(instr->value(), xmm1); @@ -1166,6 +1190,11 @@ LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) { } +LInstruction* LChunkBuilder::DoRor(HRor* instr) { + return DoShift(Token::ROR, instr); +} + + LInstruction* LChunkBuilder::DoShr(HShr* instr) { return DoShift(Token::SHR, instr); } @@ -1218,6 +1247,13 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { if (instr->representation().IsDouble()) { return DoArithmeticD(Token::DIV, instr); } else if (instr->representation().IsInteger32()) { + if (instr->HasPowerOf2Divisor()) { + ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero)); + LOperand* value = UseRegisterAtStart(instr->left()); + LDivI* div = + new(zone()) LDivI(value, UseOrConstant(instr->right()), NULL); + return AssignEnvironment(DefineSameAsFirst(div)); + } // The temporary operand is necessary to ensure that right is not allocated // into edx. LOperand* temp = FixedTemp(edx); @@ -1449,7 +1485,7 @@ LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) { LInstruction* LChunkBuilder::DoCompareIDAndBranch( HCompareIDAndBranch* instr) { - Representation r = instr->GetInputRepresentation(); + Representation r = instr->representation(); if (r.IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); @@ -1614,6 +1650,17 @@ LInstruction* LChunkBuilder::DoDateField(HDateField* instr) { } +LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { + LOperand* string = UseRegister(instr->string()); + LOperand* index = UseRegister(instr->index()); + ASSERT(ecx.is_byte_register()); + LOperand* value = UseFixed(instr->value(), ecx); + LSeqStringSetChar* result = + new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value); + return DefineSameAsFirst(result); +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { return AssignEnvironment(new(zone()) LBoundsCheck( UseRegisterOrConstantAtStart(instr->index()), @@ -1740,9 +1787,9 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { - LOperand* temp = TempRegister(); + LUnallocated* temp = TempRegister(); LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp); - return AssignEnvironment(result); + return AssignEnvironment(Define(result, temp)); } @@ -1776,7 +1823,7 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { Representation input_rep = value->representation(); if (input_rep.IsDouble()) { LOperand* reg = UseRegister(value); - return DefineAsRegister(new(zone()) LClampDToUint8(reg)); + return DefineFixed(new(zone()) LClampDToUint8(reg), eax); } else if (input_rep.IsInteger32()) { LOperand* reg = UseFixed(value, eax); return DefineFixed(new(zone()) LClampIToUint8(reg), eax); @@ -1929,59 +1976,38 @@ LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( } -LInstruction* LChunkBuilder::DoLoadKeyedFastElement( - HLoadKeyedFastElement* instr) { - ASSERT(instr->representation().IsTagged()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - LOperand* obj = UseRegisterAtStart(instr->object()); - LOperand* key = UseRegisterOrConstantAtStart(instr->key()); - LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key); - if (instr->RequiresHoleCheck()) AssignEnvironment(result); - return DefineAsRegister(result); -} - - -LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement( - HLoadKeyedFastDoubleElement* instr) { - ASSERT(instr->representation().IsDouble()); +LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { ASSERT(instr->key()->representation().IsInteger32() || instr->key()->representation().IsTagged()); - LOperand* elements = UseRegisterAtStart(instr->elements()); - LOperand* key = UseRegisterOrConstantAtStart(instr->key()); - LLoadKeyedFastDoubleElement* result = - new(zone()) LLoadKeyedFastDoubleElement(elements, key); - return AssignEnvironment(DefineAsRegister(result)); -} - - -LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( - HLoadKeyedSpecializedArrayElement* instr) { ElementsKind elements_kind = instr->elements_kind(); - ASSERT( - (instr->representation().IsInteger32() && - (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && - (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || - (instr->representation().IsDouble() && - ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || - (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - LOperand* external_pointer = UseRegister(instr->external_pointer()); bool clobbers_key = ExternalArrayOpRequiresTemp( instr->key()->representation(), elements_kind); LOperand* key = clobbers_key ? UseTempRegister(instr->key()) - : UseRegisterOrConstant(instr->key()); + : UseRegisterOrConstantAtStart(instr->key()); + LLoadKeyed* result = NULL; + + if (!instr->is_external()) { + LOperand* obj = UseRegisterAtStart(instr->elements()); + result = new(zone()) LLoadKeyed(obj, key); + } else { + ASSERT( + (instr->representation().IsInteger32() && + (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && + (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || + (instr->representation().IsDouble() && + ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || + (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); + LOperand* external_pointer = UseRegister(instr->elements()); + result = new(zone()) LLoadKeyed(external_pointer, key); + } - LLoadKeyedSpecializedArrayElement* result = - new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key); - LInstruction* load_instr = DefineAsRegister(result); + DefineAsRegister(result); + bool can_deoptimize = instr->RequiresHoleCheck() || + (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS); // An unsigned int array load might overflow and cause a deopt, make sure it // has an environment. - return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) - ? AssignEnvironment(load_instr) - : load_instr; + return can_deoptimize ? AssignEnvironment(result) : result; } @@ -1996,72 +2022,61 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { } -LInstruction* LChunkBuilder::DoStoreKeyedFastElement( - HStoreKeyedFastElement* instr) { - bool needs_write_barrier = instr->NeedsWriteBarrier(); - ASSERT(instr->value()->representation().IsTagged()); - ASSERT(instr->object()->representation().IsTagged()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); +LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { + if (!instr->is_external()) { + ASSERT(instr->elements()->representation().IsTagged()); + ASSERT(instr->key()->representation().IsInteger32() || + instr->key()->representation().IsTagged()); - LOperand* obj = UseRegister(instr->object()); - LOperand* val = needs_write_barrier - ? UseTempRegister(instr->value()) - : UseRegisterAtStart(instr->value()); - LOperand* key = needs_write_barrier - ? UseTempRegister(instr->key()) - : UseRegisterOrConstantAtStart(instr->key()); - return new(zone()) LStoreKeyedFastElement(obj, key, val); -} - - -LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement( - HStoreKeyedFastDoubleElement* instr) { - ASSERT(instr->value()->representation().IsDouble()); - ASSERT(instr->elements()->representation().IsTagged()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* elements = UseRegisterAtStart(instr->elements()); - LOperand* val = UseTempRegister(instr->value()); - LOperand* key = UseRegisterOrConstantAtStart(instr->key()); - - return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val); -} + if (instr->value()->representation().IsDouble()) { + LOperand* object = UseRegisterAtStart(instr->elements()); + LOperand* val = UseTempRegister(instr->value()); + LOperand* key = UseRegisterOrConstantAtStart(instr->key()); + return new(zone()) LStoreKeyed(object, key, val); + } else { + ASSERT(instr->value()->representation().IsTagged()); + bool needs_write_barrier = instr->NeedsWriteBarrier(); + + LOperand* obj = UseRegister(instr->elements()); + LOperand* val = needs_write_barrier + ? UseTempRegister(instr->value()) + : UseRegisterAtStart(instr->value()); + LOperand* key = needs_write_barrier + ? UseTempRegister(instr->key()) + : UseRegisterOrConstantAtStart(instr->key()); + return new(zone()) LStoreKeyed(obj, key, val); + } + } -LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( - HStoreKeyedSpecializedArrayElement* instr) { ElementsKind elements_kind = instr->elements_kind(); - ASSERT( + ASSERT( (instr->value()->representation().IsInteger32() && (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || (instr->value()->representation().IsDouble() && ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || - (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); - ASSERT(instr->external_pointer()->representation().IsExternal()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); + (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); + ASSERT(instr->elements()->representation().IsExternal()); - LOperand* external_pointer = UseRegister(instr->external_pointer()); - LOperand* val = NULL; - if (elements_kind == EXTERNAL_BYTE_ELEMENTS || + LOperand* external_pointer = UseRegister(instr->elements()); + // Determine if we need a byte register in this case for the value. + bool val_is_fixed_register = + elements_kind == EXTERNAL_BYTE_ELEMENTS || elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS || - elements_kind == EXTERNAL_PIXEL_ELEMENTS) { - // We need a byte register in this case for the value. - val = UseFixed(instr->value(), eax); - } else { - val = UseRegister(instr->value()); - } + elements_kind == EXTERNAL_PIXEL_ELEMENTS; + + LOperand* val = val_is_fixed_register + ? UseFixed(instr->value(), eax) + : UseRegister(instr->value()); bool clobbers_key = ExternalArrayOpRequiresTemp( instr->key()->representation(), elements_kind); LOperand* key = clobbers_key ? UseTempRegister(instr->key()) - : UseRegisterOrConstant(instr->key()); - return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer, - key, - val); + : UseRegisterOrConstantAtStart(instr->key()); + return new(zone()) LStoreKeyed(external_pointer, + key, + val); } @@ -2235,6 +2250,7 @@ LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) { LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) { + ASSERT(argument_count_ == 0); allocator_->MarkAsOsrEntry(); current_block_->last_environment()->set_ast_id(instr->ast_id()); return AssignEnvironment(new(zone()) LOsrEntry); @@ -2275,12 +2291,10 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { - LOperand* arguments = UseRegister(instr->arguments()); + LOperand* args = UseRegister(instr->arguments()); LOperand* length = UseTempRegister(instr->length()); LOperand* index = Use(instr->index()); - LAccessArgumentsAt* result = - new(zone()) LAccessArgumentsAt(arguments, length, index); - return AssignEnvironment(DefineAsRegister(result)); + return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index)); } @@ -2317,7 +2331,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { env->set_ast_id(instr->ast_id()); env->Drop(instr->pop_count()); - for (int i = 0; i < instr->values()->length(); ++i) { + for (int i = instr->values()->length() - 1; i >= 0; --i) { HValue* value = instr->values()->at(i); if (instr->HasAssignedIndexAt(i)) { env->Bind(instr->GetAssignedIndexAt(i), value); @@ -2370,6 +2384,7 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { if (instr->arguments_var() != NULL) { inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject()); } + inner->set_entry(instr); current_block_->UpdateEnvironment(inner); chunk_->AddInlinedClosure(instr->closure()); return NULL; @@ -2381,7 +2396,7 @@ LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { HEnvironment* env = current_block_->last_environment(); - if (instr->arguments_pushed()) { + if (env->entry()->arguments_pushed()) { int argument_count = env->arguments_environment()->parameter_count(); pop = new(zone()) LDrop(argument_count); argument_count_ -= argument_count; diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h index 83a6c6f32b..cf85374267 100644 --- a/deps/v8/src/ia32/lithium-ia32.h +++ b/deps/v8/src/ia32/lithium-ia32.h @@ -119,14 +119,13 @@ class LCodeGen; V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ - V(LoadKeyedFastElement) \ - V(LoadKeyedFastDoubleElement) \ + V(LoadKeyed) \ V(LoadKeyedGeneric) \ - V(LoadKeyedSpecializedArrayElement) \ V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ V(MapEnumLength) \ + V(MathExp) \ V(MathFloorOfDiv) \ V(MathMinMax) \ V(MathPowHalf) \ @@ -145,6 +144,7 @@ class LCodeGen; V(PushArgument) \ V(RegExpLiteral) \ V(Return) \ + V(SeqStringSetChar) \ V(ShiftI) \ V(SmiTag) \ V(SmiUntag) \ @@ -152,10 +152,8 @@ class LCodeGen; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ - V(StoreKeyedFastDoubleElement) \ - V(StoreKeyedFastElement) \ + V(StoreKeyed) \ V(StoreKeyedGeneric) \ - V(StoreKeyedSpecializedArrayElement) \ V(StoreNamedField) \ V(StoreNamedGeneric) \ V(StringAdd) \ @@ -257,9 +255,6 @@ class LInstruction: public ZoneObject { virtual bool HasResult() const = 0; virtual LOperand* result() = 0; - virtual int TempCount() = 0; - virtual LOperand* TempAt(int i) = 0; - LOperand* FirstInput() { return InputAt(0); } LOperand* Output() { return HasResult() ? result() : NULL; } @@ -273,6 +268,10 @@ class LInstruction: public ZoneObject { virtual int InputCount() = 0; virtual LOperand* InputAt(int i) = 0; + friend class TempIterator; + virtual int TempCount() = 0; + virtual LOperand* TempAt(int i) = 0; + LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; @@ -292,18 +291,18 @@ class LTemplateInstruction: public LInstruction { void set_result(LOperand* operand) { results_[0] = operand; } LOperand* result() { return results_[0]; } - LOperand* InputAt(int i) { return inputs_[i]; } - - int TempCount() { return T; } - LOperand* TempAt(int i) { return temps_[i]; } - protected: EmbeddedContainer<LOperand*, R> results_; EmbeddedContainer<LOperand*, I> inputs_; EmbeddedContainer<LOperand*, T> temps_; private: + // Iterator support. virtual int InputCount() { return I; } + virtual LOperand* InputAt(int i) { return inputs_[i]; } + + virtual int TempCount() { return T; } + virtual LOperand* TempAt(int i) { return temps_[i]; } }; @@ -423,11 +422,11 @@ class LCallStub: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } + LOperand* context() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallStub, "call-stub") DECLARE_HYDROGEN_ACCESSOR(CallStub) - LOperand* context() { return inputs_[0]; } - TranscendentalCache::Type transcendental_type() { return hydrogen()->transcendental_type(); } @@ -467,10 +466,11 @@ class LWrapReceiver: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } - DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver") - LOperand* receiver() { return inputs_[0]; } LOperand* function() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver") }; @@ -486,12 +486,12 @@ class LApplyArguments: public LTemplateInstruction<1, 4, 0> { inputs_[3] = elements; } - DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments") - LOperand* function() { return inputs_[0]; } LOperand* receiver() { return inputs_[1]; } LOperand* length() { return inputs_[2]; } LOperand* elements() { return inputs_[3]; } + + DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments") }; @@ -503,12 +503,12 @@ class LAccessArgumentsAt: public LTemplateInstruction<1, 3, 0> { inputs_[2] = index; } - DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at") - LOperand* arguments() { return inputs_[0]; } LOperand* length() { return inputs_[1]; } LOperand* index() { return inputs_[2]; } + DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at") + virtual void PrintDataTo(StringStream* stream); }; @@ -519,6 +519,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = elements; } + LOperand* elements() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length") }; @@ -538,6 +540,10 @@ class LModI: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i") DECLARE_HYDROGEN_ACCESSOR(Mod) }; @@ -551,6 +557,9 @@ class LDivI: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i") DECLARE_HYDROGEN_ACCESSOR(Div) }; @@ -566,6 +575,10 @@ class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div") DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv) }; @@ -579,6 +592,10 @@ class LMulI: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i") DECLARE_HYDROGEN_ACCESSOR(Mul) }; @@ -591,12 +608,15 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch) Token::Value op() const { return hydrogen()->token(); } bool is_double() const { - return hydrogen()->GetInputRepresentation().IsDouble(); + return hydrogen()->representation().IsDouble(); } virtual void PrintDataTo(StringStream* stream); @@ -621,6 +641,27 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 2, 0> { }; +class LMathExp: public LTemplateInstruction<1, 1, 2> { + public: + LMathExp(LOperand* value, + LOperand* temp1, + LOperand* temp2) { + inputs_[0] = value; + temps_[0] = temp1; + temps_[1] = temp2; + ExternalReference::InitializeMathExpData(); + } + + LOperand* value() { return inputs_[0]; } + LOperand* temp1() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp") + + virtual void PrintDataTo(StringStream* stream); +}; + + class LMathPowHalf: public LTemplateInstruction<1, 2, 1> { public: LMathPowHalf(LOperand* context, LOperand* value, LOperand* temp) { @@ -646,6 +687,9 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch") }; @@ -657,6 +701,8 @@ class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> { inputs_[0] = left; } + LOperand* left() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch, "cmp-constant-eq-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareConstantEqAndBranch) @@ -670,6 +716,9 @@ class LIsNilAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch) @@ -687,6 +736,9 @@ class LIsObjectAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") virtual void PrintDataTo(StringStream* stream); @@ -700,6 +752,9 @@ class LIsStringAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch") virtual void PrintDataTo(StringStream* stream); @@ -712,6 +767,8 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch) @@ -726,6 +783,9 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, "is-undetectable-and-branch") @@ -741,6 +801,9 @@ class LStringCompareAndBranch: public LControlInstruction<3, 0> { inputs_[2] = right; } + LOperand* left() { return inputs_[1]; } + LOperand* right() { return inputs_[2]; } + DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch, "string-compare-and-branch") DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch) @@ -758,6 +821,9 @@ class LHasInstanceTypeAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch, "has-instance-type-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch) @@ -772,6 +838,8 @@ class LGetCachedArrayIndex: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex, "get-cached-array-index") DECLARE_HYDROGEN_ACCESSOR(GetCachedArrayIndex) }; @@ -783,8 +851,11 @@ class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch, "has-cached-array-index-and-branch") + virtual void PrintDataTo(StringStream* stream); }; @@ -795,6 +866,8 @@ class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { temps_[0] = temp; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch, "is-construct-call-and-branch") }; @@ -808,6 +881,10 @@ class LClassOfTestAndBranch: public LControlInstruction<1, 2> { temps_[1] = temp2; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch") DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) @@ -839,9 +916,9 @@ class LInstanceOf: public LTemplateInstruction<1, 3, 0> { inputs_[2] = right; } - DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of") - LOperand* context() { return inputs_[0]; } + + DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of") }; @@ -853,6 +930,9 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal, "instance-of-known-global") DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) @@ -892,10 +972,13 @@ class LBitI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } - Token::Value op() const { return hydrogen()->op(); } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i") DECLARE_HYDROGEN_ACCESSOR(Bitwise) + + Token::Value op() const { return hydrogen()->op(); } }; @@ -907,12 +990,14 @@ class LShiftI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } - Token::Value op() const { return op_; } - - bool can_deopt() const { return can_deopt_; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i") + Token::Value op() const { return op_; } + bool can_deopt() const { return can_deopt_; } + private: Token::Value op_; bool can_deopt_; @@ -926,6 +1011,9 @@ class LSubI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i") DECLARE_HYDROGEN_ACCESSOR(Sub) }; @@ -946,6 +1034,8 @@ class LConstantD: public LTemplateInstruction<1, 0, 1> { temps_[0] = temp; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d") DECLARE_HYDROGEN_ACCESSOR(Constant) @@ -964,11 +1054,14 @@ class LConstantT: public LTemplateInstruction<1, 0, 0> { class LBranch: public LControlInstruction<1, 1> { public: - explicit LBranch(LOperand* value, LOperand* temp) { + LBranch(LOperand* value, LOperand* temp) { inputs_[0] = value; temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_HYDROGEN_ACCESSOR(Branch) @@ -982,6 +1075,8 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareMap) @@ -1003,6 +1098,8 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) }; @@ -1014,6 +1111,8 @@ class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength, "fixed-array-base-length") DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength) @@ -1026,6 +1125,8 @@ class LMapEnumLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MapEnumLength, "map-enum-length") }; @@ -1036,6 +1137,8 @@ class LElementsKind: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind") DECLARE_HYDROGEN_ACCESSOR(ElementsKind) }; @@ -1048,6 +1151,9 @@ class LValueOf: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value-of") DECLARE_HYDROGEN_ACCESSOR(ValueOf) }; @@ -1061,6 +1167,9 @@ class LDateField: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* date() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(DateField, "date-field") DECLARE_HYDROGEN_ACCESSOR(DateField) @@ -1071,6 +1180,30 @@ class LDateField: public LTemplateInstruction<1, 1, 1> { }; +class LSeqStringSetChar: public LTemplateInstruction<1, 3, 0> { + public: + LSeqStringSetChar(String::Encoding encoding, + LOperand* string, + LOperand* index, + LOperand* value) : encoding_(encoding) { + inputs_[0] = string; + inputs_[1] = index; + inputs_[2] = value; + } + + String::Encoding encoding() { return encoding_; } + LOperand* string() { return inputs_[0]; } + LOperand* index() { return inputs_[1]; } + LOperand* value() { return inputs_[2]; } + + DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char") + DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar) + + private: + String::Encoding encoding_; +}; + + class LThrow: public LTemplateInstruction<0, 2, 0> { public: LThrow(LOperand* context, LOperand* value) { @@ -1091,6 +1224,8 @@ class LBitNotI: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") }; @@ -1102,6 +1237,9 @@ class LAddI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i") DECLARE_HYDROGEN_ACCESSOR(Add) }; @@ -1114,6 +1252,9 @@ class LMathMinMax: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max") DECLARE_HYDROGEN_ACCESSOR(MathMinMax) }; @@ -1126,6 +1267,9 @@ class LPower: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(Power, "power") DECLARE_HYDROGEN_ACCESSOR(Power) }; @@ -1137,6 +1281,8 @@ class LRandom: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } + LOperand* global_object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Random, "random") DECLARE_HYDROGEN_ACCESSOR(Random) }; @@ -1150,6 +1296,9 @@ class LArithmeticD: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + Token::Value op() const { return op_; } virtual Opcode opcode() const { return LInstruction::kArithmeticD; } @@ -1173,14 +1322,15 @@ class LArithmeticT: public LTemplateInstruction<1, 3, 0> { inputs_[2] = right; } + LOperand* context() { return inputs_[0]; } + LOperand* left() { return inputs_[1]; } + LOperand* right() { return inputs_[2]; } + virtual Opcode opcode() const { return LInstruction::kArithmeticT; } virtual void CompileToNative(LCodeGen* generator); virtual const char* Mnemonic() const; Token::Value op() const { return op_; } - LOperand* context() { return inputs_[0]; } - LOperand* left() { return inputs_[1]; } - LOperand* right() { return inputs_[2]; } private: Token::Value op_; @@ -1203,10 +1353,10 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field") DECLARE_HYDROGEN_ACCESSOR(LoadNamedField) - - LOperand* object() { return inputs_[0]; } }; @@ -1217,11 +1367,11 @@ class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 2, 0> { inputs_[1] = object; } - DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic") - DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic) - LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic") + DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic) }; @@ -1232,11 +1382,12 @@ class LLoadNamedGeneric: public LTemplateInstruction<1, 2, 0> { inputs_[1] = object; } + LOperand* context() { return inputs_[0]; } + LOperand* object() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric) - LOperand* context() { return inputs_[0]; } - LOperand* object() { return inputs_[1]; } Handle<Object> name() const { return hydrogen()->name(); } }; @@ -1248,10 +1399,11 @@ class LLoadFunctionPrototype: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* function() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype") DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype) - - LOperand* function() { return inputs_[0]; } }; @@ -1261,6 +1413,8 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements") }; @@ -1271,40 +1425,33 @@ class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer, "load-external-array-pointer") }; -class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { +class LLoadKeyed: public LTemplateInstruction<1, 2, 0> { public: - LLoadKeyedFastElement(LOperand* elements, LOperand* key) { + LLoadKeyed(LOperand* elements, LOperand* key) { inputs_[0] = elements; inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement) - LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - -class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> { - public: - LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) { - inputs_[0] = elements; - inputs_[1] = key; + ElementsKind elements_kind() const { + return hydrogen()->elements_kind(); + } + bool is_external() const { + return hydrogen()->is_external(); } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement, - "load-keyed-fast-double-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement) + DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") + DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) - LOperand* elements() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } + virtual void PrintDataTo(StringStream* stream); uint32_t additional_index() const { return hydrogen()->index_offset(); } }; @@ -1322,26 +1469,6 @@ inline static bool ExternalArrayOpRequiresTemp( } -class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> { - public: - LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) { - inputs_[0] = external_pointer; - inputs_[1] = key; - } - - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement, - "load-keyed-specialized-array-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement) - - LOperand* external_pointer() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - ElementsKind elements_kind() const { - return hydrogen()->elements_kind(); - } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - class LLoadKeyedGeneric: public LTemplateInstruction<1, 3, 0> { public: LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) { @@ -1350,11 +1477,11 @@ class LLoadKeyedGeneric: public LTemplateInstruction<1, 3, 0> { inputs_[2] = key; } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") - LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } LOperand* key() { return inputs_[2]; } + + DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") }; @@ -1372,11 +1499,12 @@ class LLoadGlobalGeneric: public LTemplateInstruction<1, 2, 0> { inputs_[1] = global_object; } + LOperand* context() { return inputs_[0]; } + LOperand* global_object() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic") DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric) - LOperand* context() { return inputs_[0]; } - LOperand* global_object() { return inputs_[1]; } Handle<Object> name() const { return hydrogen()->name(); } bool for_typeof() const { return hydrogen()->for_typeof(); } }; @@ -1388,10 +1516,10 @@ class LStoreGlobalCell: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell, "store-global-cell") DECLARE_HYDROGEN_ACCESSOR(StoreGlobalCell) - - LOperand* value() { return inputs_[0]; } }; @@ -1405,13 +1533,14 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 3, 0> { inputs_[2] = value; } + LOperand* context() { return inputs_[0]; } + LOperand* global_object() { return inputs_[1]; } + LOperand* value() { return inputs_[2]; } + DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic") DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric) - LOperand* context() { return InputAt(0); } - LOperand* global_object() { return InputAt(1); } Handle<Object> name() const { return hydrogen()->name(); } - LOperand* value() { return InputAt(2); } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; @@ -1422,10 +1551,11 @@ class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } + LOperand* context() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot") DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot) - LOperand* context() { return InputAt(0); } int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); @@ -1440,11 +1570,13 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 1> { temps_[0] = temp; } + LOperand* context() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot") DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot) - LOperand* context() { return InputAt(0); } - LOperand* value() { return InputAt(1); } int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); @@ -1457,6 +1589,8 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument") }; @@ -1493,9 +1627,9 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } - DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context") + LOperand* context() { return inputs_[0]; } - LOperand* context() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context") }; @@ -1505,6 +1639,8 @@ class LDeclareGlobals: public LTemplateInstruction<0, 1, 0> { inputs_[0] = context; } + LOperand* context() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals, "declare-globals") DECLARE_HYDROGEN_ACCESSOR(DeclareGlobals) }; @@ -1516,9 +1652,9 @@ class LGlobalObject: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } - DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") + LOperand* context() { return inputs_[0]; } - LOperand* context() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") }; @@ -1528,9 +1664,9 @@ class LGlobalReceiver: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } - DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver") + LOperand* global() { return inputs_[0]; } - LOperand* global() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver") }; @@ -1553,12 +1689,12 @@ class LInvokeFunction: public LTemplateInstruction<1, 2, 0> { inputs_[1] = function; } - DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function") - DECLARE_HYDROGEN_ACCESSOR(InvokeFunction) - LOperand* context() { return inputs_[0]; } LOperand* function() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function") + DECLARE_HYDROGEN_ACCESSOR(InvokeFunction) + virtual void PrintDataTo(StringStream* stream); int arity() const { return hydrogen()->argument_count() - 1; } @@ -1573,12 +1709,12 @@ class LCallKeyed: public LTemplateInstruction<1, 2, 0> { inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed") - DECLARE_HYDROGEN_ACCESSOR(CallKeyed) - LOperand* context() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed") + DECLARE_HYDROGEN_ACCESSOR(CallKeyed) + virtual void PrintDataTo(StringStream* stream); int arity() const { return hydrogen()->argument_count() - 1; } @@ -1591,12 +1727,13 @@ class LCallNamed: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } + LOperand* context() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call-named") DECLARE_HYDROGEN_ACCESSOR(CallNamed) virtual void PrintDataTo(StringStream* stream); - LOperand* context() { return inputs_[0]; } Handle<String> name() const { return hydrogen()->name(); } int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -1609,11 +1746,12 @@ class LCallFunction: public LTemplateInstruction<1, 2, 0> { inputs_[1] = function; } + LOperand* context() { return inputs_[0]; } + LOperand* function() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function") DECLARE_HYDROGEN_ACCESSOR(CallFunction) - LOperand* context() { return inputs_[0]; } - LOperand* function() { return inputs_[1]; } int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -1624,12 +1762,13 @@ class LCallGlobal: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } + LOperand* context() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global") DECLARE_HYDROGEN_ACCESSOR(CallGlobal) virtual void PrintDataTo(StringStream* stream); - LOperand* context() { return inputs_[0]; } Handle<String> name() const {return hydrogen()->name(); } int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -1654,13 +1793,14 @@ class LCallNew: public LTemplateInstruction<1, 2, 0> { inputs_[1] = constructor; } + LOperand* context() { return inputs_[0]; } + LOperand* constructor() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new") DECLARE_HYDROGEN_ACCESSOR(CallNew) virtual void PrintDataTo(StringStream* stream); - LOperand* context() { return inputs_[0]; } - LOperand* constructor() { return inputs_[1]; } int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -1670,10 +1810,12 @@ class LCallRuntime: public LTemplateInstruction<1, 1, 0> { explicit LCallRuntime(LOperand* context) { inputs_[0] = context; } + + LOperand* context() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime") DECLARE_HYDROGEN_ACCESSOR(CallRuntime) - LOperand* context() { return inputs_[0]; } const Runtime::Function* function() const { return hydrogen()->function(); } int arity() const { return hydrogen()->argument_count(); } }; @@ -1685,6 +1827,8 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double") }; @@ -1696,6 +1840,9 @@ class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double") }; @@ -1706,6 +1853,8 @@ class LNumberTagI: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i") }; @@ -1717,6 +1866,8 @@ class LNumberTagU: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u") }; @@ -1728,6 +1879,9 @@ class LNumberTagD: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d") }; @@ -1740,6 +1894,9 @@ class LDoubleToI: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -1755,6 +1912,9 @@ class LTaggedToI: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -1768,6 +1928,8 @@ class LSmiTag: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag") }; @@ -1779,6 +1941,9 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag") DECLARE_HYDROGEN_ACCESSOR(Change); }; @@ -1791,6 +1956,8 @@ class LSmiUntag: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag") bool needs_check() const { return needs_check_; } @@ -1812,14 +1979,16 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 2> { temps_[1] = temp_map; } + LOperand* object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp_map() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field") DECLARE_HYDROGEN_ACCESSOR(StoreNamedField) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* value() { return inputs_[1]; } - Handle<Object> name() const { return hydrogen()->name(); } bool is_in_object() { return hydrogen()->is_in_object(); } int offset() { return hydrogen()->offset(); } @@ -1835,89 +2004,44 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 3, 0> { inputs_[2] = value; } + LOperand* context() { return inputs_[0]; } + LOperand* object() { return inputs_[1]; } + LOperand* value() { return inputs_[2]; } + DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic") DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric) virtual void PrintDataTo(StringStream* stream); - - LOperand* context() { return inputs_[0]; } - LOperand* object() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } Handle<Object> name() const { return hydrogen()->name(); } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; -class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> { +class LStoreKeyed: public LTemplateInstruction<0, 3, 0> { public: - LStoreKeyedFastElement(LOperand* obj, LOperand* key, LOperand* val) { + LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val) { inputs_[0] = obj; inputs_[1] = key; inputs_[2] = val; } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement, - "store-keyed-fast-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement) - - virtual void PrintDataTo(StringStream* stream); - - LOperand* object() { return inputs_[0]; } + bool is_external() const { return hydrogen()->is_external(); } + LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - -class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> { - public: - LStoreKeyedFastDoubleElement(LOperand* elements, - LOperand* key, - LOperand* val) { - inputs_[0] = elements; - inputs_[1] = key; - inputs_[2] = val; + ElementsKind elements_kind() const { + return hydrogen()->elements_kind(); } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement, - "store-keyed-fast-double-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement) + DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed") + DECLARE_HYDROGEN_ACCESSOR(StoreKeyed) virtual void PrintDataTo(StringStream* stream); - - LOperand* elements() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } uint32_t additional_index() const { return hydrogen()->index_offset(); } - bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } }; -class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> { - public: - LStoreKeyedSpecializedArrayElement(LOperand* external_pointer, - LOperand* key, - LOperand* val) { - inputs_[0] = external_pointer; - inputs_[1] = key; - inputs_[2] = val; - } - - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement, - "store-keyed-specialized-array-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement) - - LOperand* external_pointer() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } - ElementsKind elements_kind() const { - return hydrogen()->elements_kind(); - } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - class LStoreKeyedGeneric: public LTemplateInstruction<0, 4, 0> { public: LStoreKeyedGeneric(LOperand* context, @@ -1930,15 +2054,16 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 4, 0> { inputs_[3] = value; } + LOperand* context() { return inputs_[0]; } + LOperand* object() { return inputs_[1]; } + LOperand* key() { return inputs_[2]; } + LOperand* value() { return inputs_[3]; } + DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic") DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric) virtual void PrintDataTo(StringStream* stream); - LOperand* context() { return inputs_[0]; } - LOperand* object() { return inputs_[1]; } - LOperand* key() { return inputs_[2]; } - LOperand* value() { return inputs_[3]; } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; @@ -1947,21 +2072,22 @@ class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> { public: LTransitionElementsKind(LOperand* object, LOperand* new_map_temp, - LOperand* temp_reg) { + LOperand* temp) { inputs_[0] = object; temps_[0] = new_map_temp; - temps_[1] = temp_reg; + temps_[1] = temp; } + LOperand* object() { return inputs_[0]; } + LOperand* new_map_temp() { return temps_[0]; } + LOperand* temp() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind, "transition-elements-kind") DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* new_map_reg() { return temps_[0]; } - LOperand* temp_reg() { return temps_[1]; } Handle<Map> original_map() { return hydrogen()->original_map(); } Handle<Map> transitioned_map() { return hydrogen()->transitioned_map(); } }; @@ -1975,12 +2101,12 @@ class LStringAdd: public LTemplateInstruction<1, 3, 0> { inputs_[2] = right; } - DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add") - DECLARE_HYDROGEN_ACCESSOR(StringAdd) - LOperand* context() { return inputs_[0]; } LOperand* left() { return inputs_[1]; } LOperand* right() { return inputs_[2]; } + + DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add") + DECLARE_HYDROGEN_ACCESSOR(StringAdd) }; @@ -1992,12 +2118,12 @@ class LStringCharCodeAt: public LTemplateInstruction<1, 3, 0> { inputs_[2] = index; } - DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at") - DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt) - LOperand* context() { return inputs_[0]; } LOperand* string() { return inputs_[1]; } LOperand* index() { return inputs_[2]; } + + DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at") + DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt) }; @@ -2008,11 +2134,11 @@ class LStringCharFromCode: public LTemplateInstruction<1, 2, 0> { inputs_[1] = char_code; } - DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code") - DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode) - LOperand* context() { return inputs_[0]; } LOperand* char_code() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code") + DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode) }; @@ -2022,10 +2148,10 @@ class LStringLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = string; } + LOperand* string() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length") DECLARE_HYDROGEN_ACCESSOR(StringLength) - - LOperand* string() { return inputs_[0]; } }; @@ -2049,6 +2175,9 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type") DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType) }; @@ -2060,17 +2189,21 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps") DECLARE_HYDROGEN_ACCESSOR(CheckMaps) }; -class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> { +class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> { public: explicit LCheckPrototypeMaps(LOperand* temp) { temps_[0] = temp; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) @@ -2085,6 +2218,8 @@ class LCheckSmi: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi") }; @@ -2132,6 +2267,8 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi") }; @@ -2143,10 +2280,11 @@ class LAllocateObject: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* context() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object") DECLARE_HYDROGEN_ACCESSOR(AllocateObject) - - LOperand* context() { return inputs_[0]; } }; @@ -2223,6 +2361,8 @@ class LToFastProperties: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties") DECLARE_HYDROGEN_ACCESSOR(ToFastProperties) }; @@ -2235,6 +2375,9 @@ class LTypeof: public LTemplateInstruction<1, 2, 0> { inputs_[1] = value; } + LOperand* context() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof") }; @@ -2245,6 +2388,8 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch") DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch) @@ -2262,11 +2407,11 @@ class LDeleteProperty: public LTemplateInstruction<1, 3, 0> { inputs_[2] = key; } - DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") - LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } LOperand* key() { return inputs_[2]; } + + DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") }; diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 9c5f31e2cf..14fb8ca852 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -129,14 +129,22 @@ void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg, XMMRegister scratch_reg, Register result_reg) { Label done; - ExternalReference zero_ref = ExternalReference::address_of_zero(); - movdbl(scratch_reg, Operand::StaticVariable(zero_ref)); - Set(result_reg, Immediate(0)); - ucomisd(input_reg, scratch_reg); - j(below, &done, Label::kNear); + Label conv_failure; + pxor(scratch_reg, scratch_reg); cvtsd2si(result_reg, input_reg); test(result_reg, Immediate(0xFFFFFF00)); j(zero, &done, Label::kNear); + cmp(result_reg, Immediate(0x80000000)); + j(equal, &conv_failure, Label::kNear); + mov(result_reg, Immediate(0)); + setcc(above, result_reg); + sub(result_reg, Immediate(1)); + and_(result_reg, Immediate(255)); + jmp(&done, Label::kNear); + bind(&conv_failure); + Set(result_reg, Immediate(0)); + ucomisd(input_reg, scratch_reg); + j(below, &done, Label::kNear); Set(result_reg, Immediate(255)); bind(&done); } @@ -274,9 +282,7 @@ void MacroAssembler::RecordWriteForMap( ASSERT(!object.is(value)); ASSERT(!object.is(address)); ASSERT(!value.is(address)); - if (emit_debug_code()) { - AbortIfSmi(object); - } + AssertNotSmi(object); if (!FLAG_incremental_marking) { return; @@ -323,9 +329,7 @@ void MacroAssembler::RecordWrite(Register object, ASSERT(!object.is(value)); ASSERT(!object.is(address)); ASSERT(!value.is(address)); - if (emit_debug_code()) { - AbortIfSmi(object); - } + AssertNotSmi(object); if (remembered_set_action == OMIT_REMEMBERED_SET && !FLAG_incremental_marking) { @@ -503,7 +507,8 @@ void MacroAssembler::StoreNumberToDoubleElements( Register scratch1, XMMRegister scratch2, Label* fail, - bool specialize_for_processor) { + bool specialize_for_processor, + int elements_offset) { Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value; JumpIfSmi(maybe_number, &smi_value, Label::kNear); @@ -525,12 +530,14 @@ void MacroAssembler::StoreNumberToDoubleElements( CpuFeatures::Scope use_sse2(SSE2); movdbl(scratch2, FieldOperand(maybe_number, HeapNumber::kValueOffset)); bind(&have_double_value); - movdbl(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize), + movdbl(FieldOperand(elements, key, times_4, + FixedDoubleArray::kHeaderSize - elements_offset), scratch2); } else { fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset)); bind(&have_double_value); - fstp_d(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize)); + fstp_d(FieldOperand(elements, key, times_4, + FixedDoubleArray::kHeaderSize - elements_offset)); } jmp(&done); @@ -557,13 +564,15 @@ void MacroAssembler::StoreNumberToDoubleElements( if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) { CpuFeatures::Scope fscope(SSE2); cvtsi2sd(scratch2, scratch1); - movdbl(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize), + movdbl(FieldOperand(elements, key, times_4, + FixedDoubleArray::kHeaderSize - elements_offset), scratch2); } else { push(scratch1); fild_s(Operand(esp, 0)); pop(scratch1); - fstp_d(FieldOperand(elements, key, times_4, FixedDoubleArray::kHeaderSize)); + fstp_d(FieldOperand(elements, key, times_4, + FixedDoubleArray::kHeaderSize - elements_offset)); } bind(&done); } @@ -668,36 +677,44 @@ void MacroAssembler::FCmp() { } -void MacroAssembler::AbortIfNotNumber(Register object) { - Label ok; - JumpIfSmi(object, &ok); - cmp(FieldOperand(object, HeapObject::kMapOffset), - isolate()->factory()->heap_number_map()); - Assert(equal, "Operand not a number"); - bind(&ok); +void MacroAssembler::AssertNumber(Register object) { + if (emit_debug_code()) { + Label ok; + JumpIfSmi(object, &ok); + cmp(FieldOperand(object, HeapObject::kMapOffset), + isolate()->factory()->heap_number_map()); + Check(equal, "Operand not a number"); + bind(&ok); + } } -void MacroAssembler::AbortIfNotSmi(Register object) { - test(object, Immediate(kSmiTagMask)); - Assert(equal, "Operand is not a smi"); +void MacroAssembler::AssertSmi(Register object) { + if (emit_debug_code()) { + test(object, Immediate(kSmiTagMask)); + Check(equal, "Operand is not a smi"); + } } -void MacroAssembler::AbortIfNotString(Register object) { - test(object, Immediate(kSmiTagMask)); - Assert(not_equal, "Operand is not a string"); - push(object); - mov(object, FieldOperand(object, HeapObject::kMapOffset)); - CmpInstanceType(object, FIRST_NONSTRING_TYPE); - pop(object); - Assert(below, "Operand is not a string"); +void MacroAssembler::AssertString(Register object) { + if (emit_debug_code()) { + test(object, Immediate(kSmiTagMask)); + Check(not_equal, "Operand is a smi and not a string"); + push(object); + mov(object, FieldOperand(object, HeapObject::kMapOffset)); + CmpInstanceType(object, FIRST_NONSTRING_TYPE); + pop(object); + Check(below, "Operand is not a string"); + } } -void MacroAssembler::AbortIfSmi(Register object) { - test(object, Immediate(kSmiTagMask)); - Assert(not_equal, "Operand is a smi"); +void MacroAssembler::AssertNotSmi(Register object) { + if (emit_debug_code()) { + test(object, Immediate(kSmiTagMask)); + Check(not_equal, "Operand is a smi"); + } } @@ -1441,14 +1458,14 @@ void MacroAssembler::AllocateAsciiString(Register result, Label* gc_required) { // Calculate the number of bytes needed for the characters in the string while // observing object alignment. - ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); + ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); mov(scratch1, length); ASSERT(kCharSize == 1); add(scratch1, Immediate(kObjectAlignmentMask)); and_(scratch1, Immediate(~kObjectAlignmentMask)); // Allocate ASCII string in new space. - AllocateInNewSpace(SeqAsciiString::kHeaderSize, + AllocateInNewSpace(SeqOneByteString::kHeaderSize, times_1, scratch1, result, @@ -1476,7 +1493,7 @@ void MacroAssembler::AllocateAsciiString(Register result, ASSERT(length > 0); // Allocate ASCII string in new space. - AllocateInNewSpace(SeqAsciiString::SizeFor(length), + AllocateInNewSpace(SeqOneByteString::SizeFor(length), result, scratch1, scratch2, @@ -1903,9 +1920,25 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, mov(edi, Operand::StaticVariable(limit_address)); add(Operand::StaticVariable(level_address), Immediate(1)); + if (FLAG_log_timer_events) { + FrameScope frame(this, StackFrame::MANUAL); + PushSafepointRegisters(); + PrepareCallCFunction(0, eax); + CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0); + PopSafepointRegisters(); + } + // Call the api function. call(function_address, RelocInfo::RUNTIME_ENTRY); + if (FLAG_log_timer_events) { + FrameScope frame(this, StackFrame::MANUAL); + PushSafepointRegisters(); + PrepareCallCFunction(0, eax); + CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0); + PopSafepointRegisters(); + } + if (!kReturnHandlesDirectly) { // PrepareCallApiFunction saved pointer to the output slot into // callee-save register esi. @@ -2573,19 +2606,13 @@ void MacroAssembler::Abort(const char* msg) { void MacroAssembler::LoadInstanceDescriptors(Register map, Register descriptors) { - Register temp = descriptors; - mov(temp, FieldOperand(map, Map::kTransitionsOrBackPointerOffset)); + mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); +} - Label ok, fail; - CheckMap(temp, - isolate()->factory()->fixed_array_map(), - &fail, - DONT_DO_SMI_CHECK); - mov(descriptors, FieldOperand(temp, TransitionArray::kDescriptorsOffset)); - jmp(&ok); - bind(&fail); - mov(descriptors, isolate()->factory()->empty_descriptor_array()); - bind(&ok); + +void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { + mov(dst, FieldOperand(map, Map::kBitField3Offset)); + DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); } @@ -2609,7 +2636,7 @@ void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii( } and_(scratch, kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); - cmp(scratch, kStringTag | kSeqStringTag | kAsciiStringTag); + cmp(scratch, kStringTag | kSeqStringTag | kOneByteStringTag); j(not_equal, failure); } @@ -2632,15 +2659,17 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1, movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); // Check that both are flat ASCII strings. - const int kFlatAsciiStringMask = - kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; + const int kFlatAsciiStringMask = kIsNotStringMask | kStringRepresentationMask + | kStringEncodingMask | kAsciiDataHintTag; const int kFlatAsciiStringTag = ASCII_STRING_TYPE; // Interleave bits from both instance types and compare them in one check. - ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3)); + ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 8)); + ASSERT_EQ(ASCII_STRING_TYPE, ASCII_STRING_TYPE & kFlatAsciiStringMask); and_(scratch1, kFlatAsciiStringMask); and_(scratch2, kFlatAsciiStringMask); - lea(scratch1, Operand(scratch1, scratch2, times_8, 0)); - cmp(scratch1, kFlatAsciiStringTag | (kFlatAsciiStringTag << 3)); + shl(scratch1, 8); + or_(scratch1, scratch2); + cmp(scratch1, kFlatAsciiStringTag | (kFlatAsciiStringTag << 8)); j(not_equal, failure); } @@ -2900,15 +2929,15 @@ void MacroAssembler::EnsureNotWhite( bind(¬_external); // Sequential string, either ASCII or UC16. - ASSERT(kAsciiStringTag == 0x04); + ASSERT(kOneByteStringTag == 0x04); and_(length, Immediate(kStringEncodingMask)); xor_(length, Immediate(kStringEncodingMask)); add(length, Immediate(0x04)); // Value now either 4 (if ASCII) or 8 (if UC16), i.e., char-size shifted // by 2. If we multiply the string length as smi by this, it still // won't overflow a 32-bit value. - ASSERT_EQ(SeqAsciiString::kMaxSize, SeqTwoByteString::kMaxSize); - ASSERT(SeqAsciiString::kMaxSize <= + ASSERT_EQ(SeqOneByteString::kMaxSize, SeqTwoByteString::kMaxSize); + ASSERT(SeqOneByteString::kMaxSize <= static_cast<int>(0xffffffffu >> (2 + kSmiTagSize))); imul(length, FieldOperand(value, String::kLengthOffset)); shr(length, 2 + kSmiTagSize + kSmiShiftSize); diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h index 7d475e7d7e..7abb29b10a 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -388,7 +388,8 @@ class MacroAssembler: public Assembler { Register scratch1, XMMRegister scratch2, Label* fail, - bool specialize_for_processor); + bool specialize_for_processor, + int offset = 0); // Compare an object's map with the specified map and its transitioned // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. FLAGS are set with @@ -493,27 +494,28 @@ class MacroAssembler: public Assembler { void LoadInstanceDescriptors(Register map, Register descriptors); void EnumLength(Register dst, Register map); + void NumberOfOwnDescriptors(Register dst, Register map); template<typename Field> void DecodeField(Register reg) { - static const int full_shift = Field::kShift + kSmiTagSize; - static const int low_mask = Field::kMask >> Field::kShift; - sar(reg, full_shift); - and_(reg, Immediate(low_mask)); + static const int shift = Field::kShift; + static const int mask = (Field::kMask >> Field::kShift) << kSmiTagSize; + sar(reg, shift); + and_(reg, Immediate(mask)); } void LoadPowerOf2(XMMRegister dst, Register scratch, int power); - // Abort execution if argument is not a number. Used in debug code. - void AbortIfNotNumber(Register object); + // Abort execution if argument is not a number, enabled via --debug-code. + void AssertNumber(Register object); - // Abort execution if argument is not a smi. Used in debug code. - void AbortIfNotSmi(Register object); + // Abort execution if argument is not a smi, enabled via --debug-code. + void AssertSmi(Register object); - // Abort execution if argument is a smi. Used in debug code. - void AbortIfSmi(Register object); + // Abort execution if argument is a smi, enabled via --debug-code. + void AssertNotSmi(Register object); - // Abort execution if argument is a string. Used in debug code. - void AbortIfNotString(Register object); + // Abort execution if argument is not a string, enabled via --debug-code. + void AssertString(Register object); // --------------------------------------------------------------------------- // Exception handling @@ -787,6 +789,7 @@ class MacroAssembler: public Assembler { // Push a handle value. void Push(Handle<Object> handle) { push(Immediate(handle)); } + void Push(Smi* smi) { Push(Handle<Smi>(smi)); } Handle<Object> CodeObject() { ASSERT(!code_object_.is_null()); diff --git a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc index 622dc4254d..af6a9e44ba 100644 --- a/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/regexp-macro-assembler-ia32.cc @@ -1197,7 +1197,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); // Current string. - bool is_ascii = subject->IsAsciiRepresentationUnderneath(); + bool is_ascii = subject->IsOneByteRepresentationUnderneath(); ASSERT(re_code->instruction_start() <= *return_address); ASSERT(*return_address <= @@ -1228,7 +1228,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, } // String might have changed. - if (subject_tmp->IsAsciiRepresentation() != is_ascii) { + if (subject_tmp->IsOneByteRepresentation() != is_ascii) { // If we changed between an ASCII and an UC16 string, the specialized // code cannot be used, and we need to restart regexp matching from // scratch (including, potentially, compiling a new version of the code). diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index f5e2d05892..c8695c572c 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -376,18 +376,23 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, Register dst, Register src, Handle<JSObject> holder, - int index) { - // Adjust for the number of properties stored in the holder. - index -= holder->map()->inobject_properties(); - if (index < 0) { - // Get the property straight out of the holder. - int offset = holder->map()->instance_size() + (index * kPointerSize); + PropertyIndex index) { + if (index.is_header_index()) { + int offset = index.header_index() * kPointerSize; __ mov(dst, FieldOperand(src, offset)); } else { - // Calculate the offset into the properties array. - int offset = index * kPointerSize + FixedArray::kHeaderSize; - __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset)); - __ mov(dst, FieldOperand(dst, offset)); + // Adjust for the number of properties stored in the holder. + int slot = index.field_index() - holder->map()->inobject_properties(); + if (slot < 0) { + // Get the property straight out of the holder. + int offset = holder->map()->instance_size() + (slot * kPointerSize); + __ mov(dst, FieldOperand(src, offset)); + } else { + // Calculate the offset into the properties array. + int offset = slot * kPointerSize + FixedArray::kHeaderSize; + __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset)); + __ mov(dst, FieldOperand(dst, offset)); + } } } @@ -1036,7 +1041,7 @@ void StubCompiler::GenerateLoadField(Handle<JSObject> object, Register scratch1, Register scratch2, Register scratch3, - int index, + PropertyIndex index, Handle<String> name, Label* miss) { // Check that the receiver isn't a smi. @@ -1423,7 +1428,7 @@ void CallStubCompiler::GenerateMissBranch() { Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name) { // ----------- S t a t e ------------- // -- ecx : name @@ -1518,7 +1523,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( Label call_builtin; if (argc == 1) { // Otherwise fall through to call builtin. - Label attempt_to_grow_elements, with_write_barrier; + Label attempt_to_grow_elements, with_write_barrier, check_double; // Get the elements array of the object. __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset)); @@ -1526,7 +1531,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( // Check that the elements are in fast mode and writable. __ cmp(FieldOperand(edi, HeapObject::kMapOffset), Immediate(factory()->fixed_array_map())); - __ j(not_equal, &call_builtin); + __ j(not_equal, &check_double); // Get the array's length into eax and calculate new length. __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); @@ -1557,17 +1562,49 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( __ ret((argc + 1) * kPointerSize); + __ bind(&check_double); + + + // Check that the elements are in double mode. + __ cmp(FieldOperand(edi, HeapObject::kMapOffset), + Immediate(factory()->fixed_double_array_map())); + __ j(not_equal, &call_builtin); + + // Get the array's length into eax and calculate new length. + __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); + STATIC_ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0); + __ add(eax, Immediate(Smi::FromInt(argc))); + + // Get the elements' length into ecx. + __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); + + // Check if we could survive without allocation. + __ cmp(eax, ecx); + __ j(greater, &call_builtin); + + __ mov(ecx, Operand(esp, argc * kPointerSize)); + __ StoreNumberToDoubleElements( + ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize); + + // Save new length. + __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); + __ ret((argc + 1) * kPointerSize); + __ bind(&with_write_barrier); __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); - if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) { + if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) { Label fast_object, not_fast_object; __ CheckFastObjectElements(ebx, ¬_fast_object, Label::kNear); __ jmp(&fast_object); // In case of fast smi-only, convert to fast object, otherwise bail out. __ bind(¬_fast_object); __ CheckFastSmiElements(ebx, &call_builtin); + __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), + Immediate(factory()->heap_number_map())); + __ j(equal, &call_builtin); // edi: elements array // edx: receiver // ebx: map @@ -2956,7 +2993,7 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name, Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name) { // ----------- S t a t e ------------- // -- ecx : name @@ -3156,7 +3193,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal( Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name, Handle<JSObject> receiver, Handle<JSObject> holder, - int index) { + PropertyIndex index) { // ----------- S t a t e ------------- // -- ecx : key // -- edx : receiver @@ -3421,6 +3458,7 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( #endif // Load the initial map and verify that it is in fact a map. + // edi: constructor __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. __ JumpIfSmi(ebx, &generic_stub_call); @@ -3429,19 +3467,23 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( #ifdef DEBUG // Cannot construct functions this way. - // edi: constructor // ebx: initial map __ CmpInstanceType(ebx, JS_FUNCTION_TYPE); - __ Assert(not_equal, "Function constructed by construct stub."); + __ Check(not_equal, "Function constructed by construct stub."); #endif // Now allocate the JSObject on the heap by moving the new space allocation // top forward. - // edi: constructor // ebx: initial map + ASSERT(function->has_initial_map()); + int instance_size = function->initial_map()->instance_size(); +#ifdef DEBUG __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); __ shl(ecx, kPointerSizeLog2); - __ AllocateInNewSpace(ecx, edx, ecx, no_reg, + __ cmp(ecx, Immediate(instance_size)); + __ Check(equal, "Instance size of initial map changed."); +#endif + __ AllocateInNewSpace(instance_size, edx, ecx, no_reg, &generic_stub_call, NO_ALLOCATION_FLAGS); // Allocated the JSObject, now initialize the fields and add the heap tag. @@ -3501,7 +3543,6 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( } // Fill the unused in-object property fields with undefined. - ASSERT(function->has_initial_map()); for (int i = shared->this_property_assignments_count(); i < function->initial_map()->inobject_properties(); i++) { @@ -4312,13 +4353,22 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // ecx: key // edx: receiver // edi: elements - // Initialize the new FixedDoubleArray. Leave elements unitialized for - // efficiency, they are guaranteed to be initialized before use. + // Initialize the new FixedDoubleArray. __ mov(FieldOperand(edi, JSObject::kMapOffset), Immediate(masm->isolate()->factory()->fixed_double_array_map())); __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset), Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements))); + __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0, + &transition_elements_kind, true); + + for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { + int offset = FixedDoubleArray::OffsetOfElementAt(i); + __ mov(FieldOperand(edi, offset), Immediate(kHoleNanLower32)); + __ mov(FieldOperand(edi, offset + kPointerSize), + Immediate(kHoleNanUpper32)); + } + // Install the new backing store in the JSArray. __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi); __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx, @@ -4328,7 +4378,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ add(FieldOperand(edx, JSArray::kLengthOffset), Immediate(Smi::FromInt(1))); __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); - __ jmp(&finish_store); + __ ret(0); __ bind(&check_capacity); // eax: value diff --git a/deps/v8/src/ic-inl.h b/deps/v8/src/ic-inl.h index 0e41093e5c..77f409a1ef 100644 --- a/deps/v8/src/ic-inl.h +++ b/deps/v8/src/ic-inl.h @@ -40,10 +40,11 @@ namespace internal { Address IC::address() const { // Get the address of the call. - Address result = pc() - Assembler::kCallTargetAddressOffset; + Address result = Assembler::target_address_from_return_address(pc()); #ifdef ENABLE_DEBUGGER_SUPPORT - Debug* debug = Isolate::Current()->debug(); + ASSERT(Isolate::Current() == isolate()); + Debug* debug = isolate()->debug(); // First check if any break points are active if not just return the address // of the call. if (!debug->has_break_points()) return result; diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index b902b5386d..bf2a649f7f 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -158,7 +158,7 @@ Address IC::OriginalCodeAddress() const { // Get the address of the call site in the active code. This is the // place where the call to DebugBreakXXX is and where the IC // normally would be. - Address addr = pc() - Assembler::kCallTargetAddressOffset; + Address addr = Assembler::target_address_from_return_address(pc()); // Return the address in the original code. This is the place where // the call which has been overwritten by the DebugBreakXXX resides // and the place where the inline cache system should look. @@ -310,7 +310,8 @@ void IC::PostPatching(Address address, Code* target, Code* old_target) { if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) { return; } - Code* host = target->GetHeap()->isolate()-> + Isolate* isolate = target->GetHeap()->isolate(); + Code* host = isolate-> inner_pointer_to_code_cache()->GetCacheEntry(address)->code; if (host->kind() != Code::FUNCTION) return; @@ -333,7 +334,7 @@ void IC::PostPatching(Address address, Code* target, Code* old_target) { } if (FLAG_watch_ic_patching) { host->set_profiler_ticks(0); - Isolate::Current()->runtime_profiler()->NotifyICChanged(); + isolate->runtime_profiler()->NotifyICChanged(); } // TODO(2029): When an optimized function is patched, it would // be nice to propagate the corresponding type information to its @@ -414,11 +415,13 @@ 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; + ASSERT(target->major_key() == CodeStub::CompareIC); + CompareIC::State handler_state; + Token::Value op; + ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, + &handler_state, &op); // Only clear CompareICs that can retain objects. - if (target->compare_state() != KNOWN_OBJECTS) return; - Token::Value op = CompareIC::ComputeOperation(target); + if (handler_state != KNOWN_OBJECTS) return; SetTargetAtAddress(address, GetRawUninitialized(op)); PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); } @@ -646,7 +649,7 @@ Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, Handle<JSObject> holder(lookup->holder()); switch (lookup->type()) { case FIELD: { - int index = lookup->GetFieldIndex(); + PropertyIndex index = lookup->GetFieldIndex(); return isolate()->stub_cache()->ComputeCallField( argc, kind_, extra_state, name, object, holder, index); } @@ -1377,6 +1380,11 @@ MaybeObject* StoreIC::Store(State state, return *value; } + // Observed objects are always modified through the runtime. + if (FLAG_harmony_observation && receiver->map()->is_observed()) { + return receiver->SetProperty(*name, *value, NONE, strict_mode); + } + // Use specialized code for setting the length of arrays with fast // properties. Slow properties might indicate redefinition of the // length property. @@ -1462,11 +1470,9 @@ void StoreIC::UpdateCaches(LookupResult* lookup, Handle<Code> code; switch (type) { case FIELD: - code = isolate()->stub_cache()->ComputeStoreField(name, - receiver, - lookup->GetFieldIndex(), - Handle<Map>::null(), - strict_mode); + code = isolate()->stub_cache()->ComputeStoreField( + name, receiver, lookup->GetFieldIndex().field_index(), + Handle<Map>::null(), strict_mode); break; case NORMAL: if (receiver->IsGlobalObject()) { @@ -1902,7 +1908,8 @@ MaybeObject* KeyedStoreIC::Store(State state, } // Update inline cache and stub cache. - if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { + if (FLAG_use_ic && !receiver->IsJSGlobalProxy() && + !(FLAG_harmony_observation && receiver->map()->is_observed())) { LookupResult lookup(isolate()); if (LookupForWrite(receiver, name, &lookup)) { UpdateCaches(&lookup, state, strict_mode, receiver, name, value); @@ -1914,8 +1921,10 @@ MaybeObject* KeyedStoreIC::Store(State state, } // Do not use ICs for objects that require access checks (including - // the global object). - bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); + // the global object), or are observed. + bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() && + !(FLAG_harmony_observation && object->IsJSObject() && + JSObject::cast(*object)->map()->is_observed()); ASSERT(!(use_ic && object->IsJSGlobalProxy())); if (use_ic) { @@ -1973,7 +1982,7 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup, switch (type) { case FIELD: code = isolate()->stub_cache()->ComputeKeyedStoreField( - name, receiver, lookup->GetFieldIndex(), + name, receiver, lookup->GetFieldIndex().field_index(), Handle<Map>::null(), strict_mode); break; case TRANSITION: { @@ -2307,11 +2316,10 @@ const char* BinaryOpIC::GetName(TypeInfo type_info) { switch (type_info) { case UNINITIALIZED: return "Uninitialized"; case SMI: return "SMI"; - case INT32: return "Int32s"; - case HEAP_NUMBER: return "HeapNumbers"; + case INT32: return "Int32"; + case HEAP_NUMBER: return "HeapNumber"; case ODDBALL: return "Oddball"; - case BOTH_STRING: return "BothStrings"; - case STRING: return "Strings"; + case STRING: return "String"; case GENERIC: return "Generic"; default: return "Invalid"; } @@ -2326,7 +2334,6 @@ BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { case INT32: case HEAP_NUMBER: case ODDBALL: - case BOTH_STRING: case STRING: return MONOMORPHIC; case GENERIC: @@ -2337,58 +2344,6 @@ BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { } -BinaryOpIC::TypeInfo BinaryOpIC::JoinTypes(BinaryOpIC::TypeInfo x, - BinaryOpIC::TypeInfo y) { - if (x == UNINITIALIZED) return y; - if (y == UNINITIALIZED) return x; - if (x == y) return x; - if (x == BOTH_STRING && y == STRING) return STRING; - if (x == STRING && y == BOTH_STRING) return STRING; - if (x == STRING || x == BOTH_STRING || y == STRING || y == BOTH_STRING) { - return GENERIC; - } - if (x > y) return x; - return y; -} - - -BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Handle<Object> left, - Handle<Object> right) { - ::v8::internal::TypeInfo left_type = - ::v8::internal::TypeInfo::TypeFromValue(left); - ::v8::internal::TypeInfo right_type = - ::v8::internal::TypeInfo::TypeFromValue(right); - - if (left_type.IsSmi() && right_type.IsSmi()) { - return SMI; - } - - if (left_type.IsInteger32() && right_type.IsInteger32()) { - // Platforms with 32-bit Smis have no distinct INT32 type. - if (kSmiValueSize == 32) return SMI; - return INT32; - } - - if (left_type.IsNumber() && right_type.IsNumber()) { - return HEAP_NUMBER; - } - - // Patching for fast string ADD makes sense even if only one of the - // arguments is a string. - if (left_type.IsString()) { - return right_type.IsString() ? BOTH_STRING : STRING; - } else if (right_type.IsString()) { - return STRING; - } - - // Check for oddball objects. - if (left->IsUndefined() && right->IsNumber()) return ODDBALL; - if (left->IsNumber() && right->IsUndefined()) return ODDBALL; - - return GENERIC; -} - - RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { ASSERT(args.length() == 4); @@ -2440,25 +2395,72 @@ RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { return *result; } + +static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, + Token::Value op) { + ::v8::internal::TypeInfo type = + ::v8::internal::TypeInfo::TypeFromValue(value); + if (type.IsSmi()) return BinaryOpIC::SMI; + if (type.IsInteger32()) { + if (kSmiValueSize == 32) return BinaryOpIC::SMI; + return BinaryOpIC::INT32; + } + if (type.IsNumber()) return BinaryOpIC::HEAP_NUMBER; + if (type.IsString()) return BinaryOpIC::STRING; + if (value->IsUndefined()) { + if (op == Token::BIT_AND || + op == Token::BIT_OR || + op == Token::BIT_XOR || + op == Token::SAR || + op == Token::SHL || + op == Token::SHR) { + if (kSmiValueSize == 32) return BinaryOpIC::SMI; + return BinaryOpIC::INT32; + } + return BinaryOpIC::ODDBALL; + } + return BinaryOpIC::GENERIC; +} + + +static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, + Handle<Object> value, + Token::Value op) { + BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); + if (old_type == BinaryOpIC::STRING) { + if (new_type == BinaryOpIC::STRING) return new_type; + return BinaryOpIC::GENERIC; + } + return Max(old_type, new_type); +} + + RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { - ASSERT(args.length() == 5); + ASSERT(args.length() == 3); HandleScope scope(isolate); Handle<Object> left = args.at<Object>(0); Handle<Object> right = args.at<Object>(1); int key = args.smi_at(2); - Token::Value op = static_cast<Token::Value>(args.smi_at(3)); - BinaryOpIC::TypeInfo previous_type = - static_cast<BinaryOpIC::TypeInfo>(args.smi_at(4)); + Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); + BinaryOpIC::TypeInfo previous_left, previous_right, unused_previous_result; + BinaryOpStub::decode_types_from_minor_key( + key, &previous_left, &previous_right, &unused_previous_result); - BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right); - type = BinaryOpIC::JoinTypes(type, previous_type); + BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); + BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; - if ((type == BinaryOpIC::STRING || type == BinaryOpIC::BOTH_STRING) && + + // STRING is only used for ADD operations. + if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && op != Token::ADD) { - type = BinaryOpIC::GENERIC; + new_left = new_right = BinaryOpIC::GENERIC; } - if (type == BinaryOpIC::SMI && previous_type == BinaryOpIC::SMI) { + + BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); + BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); + + if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { if (op == Token::DIV || op == Token::MUL || op == Token::SHR || @@ -2473,26 +2475,35 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { result_type = BinaryOpIC::INT32; } } - if (type == BinaryOpIC::INT32 && previous_type == BinaryOpIC::INT32) { - // We must be here because an operation on two INT32 types overflowed. - result_type = BinaryOpIC::HEAP_NUMBER; + if (new_overall == BinaryOpIC::INT32 && + previous_overall == BinaryOpIC::INT32) { + if (new_left == previous_left && new_right == previous_right) { + result_type = BinaryOpIC::HEAP_NUMBER; + } } - BinaryOpStub stub(key, type, result_type); + BinaryOpStub stub(key, new_left, new_right, result_type); Handle<Code> code = stub.GetCode(); if (!code.is_null()) { +#ifdef DEBUG if (FLAG_trace_ic) { - PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n", - BinaryOpIC::GetName(previous_type), - BinaryOpIC::GetName(type), + PrintF("[BinaryOpIC in "); + JavaScriptFrame::PrintTop(stdout, false, true); + PrintF(" ((%s+%s)->((%s+%s)->%s))#%s @ %p]\n", + BinaryOpIC::GetName(previous_left), + BinaryOpIC::GetName(previous_right), + BinaryOpIC::GetName(new_left), + BinaryOpIC::GetName(new_right), BinaryOpIC::GetName(result_type), - Token::Name(op)); + Token::Name(op), + static_cast<void*>(*code)); } +#endif BinaryOpIC ic(isolate); ic.patch(*code); // Activate inlined smi code. - if (previous_type == BinaryOpIC::UNINITIALIZED) { + if (previous_overall == BinaryOpIC::UNINITIALIZED) { PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); } } @@ -2555,43 +2566,28 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { Code* CompareIC::GetRawUninitialized(Token::Value op) { - ICCompareStub stub(op, UNINITIALIZED); + ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); Code* code = NULL; - CHECK(stub.FindCodeInCache(&code)); + CHECK(stub.FindCodeInCache(&code, Isolate::Current())); return code; } Handle<Code> CompareIC::GetUninitialized(Token::Value op) { - ICCompareStub stub(op, UNINITIALIZED); + ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); return stub.GetCode(); } -CompareIC::State CompareIC::ComputeState(Code* target) { - int key = target->major_key(); - if (key == CodeStub::Compare) return GENERIC; - ASSERT(key == CodeStub::CompareIC); - return static_cast<State>(target->compare_state()); -} - - -Token::Value CompareIC::ComputeOperation(Code* target) { - ASSERT(target->major_key() == CodeStub::CompareIC); - return static_cast<Token::Value>( - target->compare_operation() + Token::EQ); -} - - const char* CompareIC::GetStateName(State state) { switch (state) { case UNINITIALIZED: return "UNINITIALIZED"; - case SMIS: return "SMIS"; - case HEAP_NUMBERS: return "HEAP_NUMBERS"; - case OBJECTS: return "OBJECTS"; + case SMI: return "SMI"; + case HEAP_NUMBER: return "HEAP_NUMBER"; + case OBJECT: return "OBJECTS"; case KNOWN_OBJECTS: return "KNOWN_OBJECTS"; - case SYMBOLS: return "SYMBOLS"; - case STRINGS: return "STRINGS"; + case SYMBOL: return "SYMBOL"; + case STRING: return "STRING"; case GENERIC: return "GENERIC"; default: UNREACHABLE(); @@ -2600,28 +2596,67 @@ const char* CompareIC::GetStateName(State state) { } -CompareIC::State CompareIC::TargetState(State state, +static CompareIC::State InputState(CompareIC::State old_state, + Handle<Object> value) { + switch (old_state) { + case CompareIC::UNINITIALIZED: + if (value->IsSmi()) return CompareIC::SMI; + if (value->IsHeapNumber()) return CompareIC::HEAP_NUMBER; + if (value->IsSymbol()) return CompareIC::SYMBOL; + if (value->IsString()) return CompareIC::STRING; + if (value->IsJSObject()) return CompareIC::OBJECT; + break; + case CompareIC::SMI: + if (value->IsSmi()) return CompareIC::SMI; + if (value->IsHeapNumber()) return CompareIC::HEAP_NUMBER; + break; + case CompareIC::HEAP_NUMBER: + if (value->IsNumber()) return CompareIC::HEAP_NUMBER; + break; + case CompareIC::SYMBOL: + if (value->IsSymbol()) return CompareIC::SYMBOL; + if (value->IsString()) return CompareIC::STRING; + break; + case CompareIC::STRING: + if (value->IsSymbol() || value->IsString()) return CompareIC::STRING; + break; + case CompareIC::OBJECT: + if (value->IsJSObject()) return CompareIC::OBJECT; + break; + case CompareIC::GENERIC: + break; + case CompareIC::KNOWN_OBJECTS: + UNREACHABLE(); + break; + } + return CompareIC::GENERIC; +} + + +CompareIC::State CompareIC::TargetState(State old_state, + State old_left, + State old_right, bool has_inlined_smi_code, Handle<Object> x, Handle<Object> y) { - switch (state) { + switch (old_state) { case UNINITIALIZED: - if (x->IsSmi() && y->IsSmi()) return SMIS; - if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS; + if (x->IsSmi() && y->IsSmi()) return SMI; + if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBER; if (Token::IsOrderedRelationalCompareOp(op_)) { // Ordered comparisons treat undefined as NaN, so the // HEAP_NUMBER stub will do the right thing. if ((x->IsNumber() && y->IsUndefined()) || (y->IsNumber() && x->IsUndefined())) { - return HEAP_NUMBERS; + return HEAP_NUMBER; } } if (x->IsSymbol() && y->IsSymbol()) { // We compare symbols as strings if we need to determine // the order in a non-equality compare. - return Token::IsEqualityOp(op_) ? SYMBOLS : STRINGS; + return Token::IsEqualityOp(op_) ? SYMBOL : STRING; } - if (x->IsString() && y->IsString()) return STRINGS; + if (x->IsString() && y->IsString()) return STRING; if (!Token::IsEqualityOp(op_)) return GENERIC; if (x->IsJSObject() && y->IsJSObject()) { if (Handle<JSObject>::cast(x)->map() == @@ -2629,30 +2664,70 @@ CompareIC::State CompareIC::TargetState(State state, Token::IsEqualityOp(op_)) { return KNOWN_OBJECTS; } else { - return OBJECTS; + return OBJECT; } } return GENERIC; - case SMIS: - return has_inlined_smi_code && x->IsNumber() && y->IsNumber() - ? HEAP_NUMBERS + case SMI: + return x->IsNumber() && y->IsNumber() + ? HEAP_NUMBER : GENERIC; - case SYMBOLS: + case SYMBOL: ASSERT(Token::IsEqualityOp(op_)); - return x->IsString() && y->IsString() ? STRINGS : GENERIC; - case HEAP_NUMBERS: - case STRINGS: - case OBJECTS: + return x->IsString() && y->IsString() ? STRING : GENERIC; + case HEAP_NUMBER: + if (old_left == SMI && x->IsHeapNumber()) return HEAP_NUMBER; + if (old_right == SMI && y->IsHeapNumber()) return HEAP_NUMBER; + case STRING: + case OBJECT: case KNOWN_OBJECTS: case GENERIC: return GENERIC; } UNREACHABLE(); - return GENERIC; + return GENERIC; // Make the compiler happy. +} + + +void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { + HandleScope scope; + State previous_left, previous_right, previous_state; + ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left, + &previous_right, &previous_state, NULL); + State new_left = InputState(previous_left, x); + State new_right = InputState(previous_right, y); + State state = TargetState(previous_state, previous_left, previous_right, + HasInlinedSmiCode(address()), x, y); + ICCompareStub stub(op_, new_left, new_right, state); + if (state == KNOWN_OBJECTS) { + stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map())); + } + set_target(*stub.GetCode()); + +#ifdef DEBUG + if (FLAG_trace_ic) { + PrintF("[CompareIC in "); + JavaScriptFrame::PrintTop(stdout, false, true); + PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", + GetStateName(previous_left), + GetStateName(previous_right), + GetStateName(previous_state), + GetStateName(new_left), + GetStateName(new_right), + GetStateName(state), + Token::Name(op_), + static_cast<void*>(*stub.GetCode())); + } +#endif + + // Activate inlined smi code. + if (previous_state == UNINITIALIZED) { + PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); + } } -// Used from ic_<arch>.cc. +// Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. RUNTIME_FUNCTION(Code*, CompareIC_Miss) { NoHandleAllocation na; ASSERT(args.length() == 3); diff --git a/deps/v8/src/ic.h b/deps/v8/src/ic.h index c86f316ef3..bfccd10a6a 100644 --- a/deps/v8/src/ic.h +++ b/deps/v8/src/ic.h @@ -631,6 +631,18 @@ class StoreIC: public IC { }; +enum KeyedStoreCheckMap { + kDontCheckMap, + kCheckMap +}; + + +enum KeyedStoreIncrementLength { + kDontIncrementLength, + kIncrementLength +}; + + class KeyedStoreIC: public KeyedIC { public: explicit KeyedStoreIC(Isolate* isolate) : KeyedIC(isolate) { @@ -638,7 +650,7 @@ class KeyedStoreIC: public KeyedIC { } MUST_USE_RESULT MaybeObject* Store(State state, - StrictModeFlag strict_mode, + StrictModeFlag strict_mode, Handle<Object> object, Handle<Object> name, Handle<Object> value, @@ -759,8 +771,7 @@ class BinaryOpIC: public IC { INT32, HEAP_NUMBER, ODDBALL, - BOTH_STRING, // Only used for addition operation. - STRING, // Only used for addition operation. At least one string operand. + STRING, // Only used for addition operation. GENERIC }; @@ -771,10 +782,6 @@ class BinaryOpIC: public IC { static const char* GetName(TypeInfo type_info); static State ToState(TypeInfo type_info); - - static TypeInfo GetTypeInfo(Handle<Object> left, Handle<Object> right); - - static TypeInfo JoinTypes(TypeInfo x, TypeInfo y); }; @@ -782,11 +789,11 @@ class CompareIC: public IC { public: enum State { UNINITIALIZED, - SMIS, - HEAP_NUMBERS, - SYMBOLS, - STRINGS, - OBJECTS, + SMI, + HEAP_NUMBER, + SYMBOL, + STRING, + OBJECT, KNOWN_OBJECTS, GENERIC }; @@ -797,27 +804,27 @@ class CompareIC: public IC { // Update the inline cache for the given operands. void UpdateCaches(Handle<Object> x, Handle<Object> y); + // Factory method for getting an uninitialized compare stub. static Handle<Code> GetUninitialized(Token::Value op); // Helper function for computing the condition for a compare operation. static Condition ComputeCondition(Token::Value op); - // 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: - State TargetState(State state, bool has_inlined_smi_code, - Handle<Object> x, Handle<Object> y); + static bool HasInlinedSmiCode(Address address); + + State TargetState(State old_state, + State old_left, + State old_right, + bool has_inlined_smi_code, + Handle<Object> x, + Handle<Object> y); bool strict() const { return op_ == Token::EQ_STRICT; } Condition GetCondition() const { return ComputeCondition(op_); } - State GetState() { return ComputeState(target()); } static Code* GetRawUninitialized(Token::Value op); diff --git a/deps/v8/src/incremental-marking-inl.h b/deps/v8/src/incremental-marking-inl.h index 5c2c8ab431..1c30383d52 100644 --- a/deps/v8/src/incremental-marking-inl.h +++ b/deps/v8/src/incremental-marking-inl.h @@ -37,18 +37,31 @@ namespace internal { bool IncrementalMarking::BaseRecordWrite(HeapObject* obj, Object** slot, Object* value) { - MarkBit value_bit = Marking::MarkBitFrom(HeapObject::cast(value)); + HeapObject* value_heap_obj = HeapObject::cast(value); + MarkBit value_bit = Marking::MarkBitFrom(value_heap_obj); if (Marking::IsWhite(value_bit)) { MarkBit obj_bit = Marking::MarkBitFrom(obj); if (Marking::IsBlack(obj_bit)) { - BlackToGreyAndUnshift(obj, obj_bit); - RestartIfNotMarking(); + MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); + if (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) { + if (chunk->IsLeftOfProgressBar(slot)) { + WhiteToGreyAndPush(value_heap_obj, value_bit); + RestartIfNotMarking(); + } else { + return false; + } + } else { + BlackToGreyAndUnshift(obj, obj_bit); + RestartIfNotMarking(); + return false; + } + } else { + return false; } - - // Object is either grey or white. It will be scanned if survives. - return false; } - return true; + if (!is_compacting_) return false; + MarkBit obj_bit = Marking::MarkBitFrom(obj); + return Marking::IsBlack(obj_bit); } @@ -81,6 +94,10 @@ void IncrementalMarking::RecordWrites(HeapObject* obj) { if (IsMarking()) { MarkBit obj_bit = Marking::MarkBitFrom(obj); if (Marking::IsBlack(obj_bit)) { + MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); + if (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) { + chunk->set_progress_bar(0); + } BlackToGreyAndUnshift(obj, obj_bit); RestartIfNotMarking(); } @@ -109,7 +126,7 @@ void IncrementalMarking::BlackToGreyAndUnshift(HeapObject* obj, if (FLAG_trace_gc) { PrintPID("Hurrying incremental marking because of lack of progress\n"); } - allocation_marking_factor_ = kMaxAllocationMarkingFactor; + marking_speed_ = kMaxMarkingSpeed; } } @@ -123,27 +140,6 @@ void IncrementalMarking::WhiteToGreyAndPush(HeapObject* obj, MarkBit mark_bit) { } -bool IncrementalMarking::MarkObjectAndPush(HeapObject* obj) { - MarkBit mark_bit = Marking::MarkBitFrom(obj); - if (!mark_bit.Get()) { - WhiteToGreyAndPush(obj, mark_bit); - return true; - } - return false; -} - - -bool IncrementalMarking::MarkObjectWithoutPush(HeapObject* obj) { - MarkBit mark_bit = Marking::MarkBitFrom(obj); - if (!mark_bit.Get()) { - mark_bit.Set(); - MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); - return true; - } - return false; -} - - } } // namespace v8::internal #endif // V8_INCREMENTAL_MARKING_INL_H_ diff --git a/deps/v8/src/incremental-marking.cc b/deps/v8/src/incremental-marking.cc index 57f18b2e75..ef7dbe05ff 100644 --- a/deps/v8/src/incremental-marking.cc +++ b/deps/v8/src/incremental-marking.cc @@ -44,7 +44,6 @@ IncrementalMarking::IncrementalMarking(Heap* heap) state_(STOPPED), marking_deque_memory_(NULL), marking_deque_memory_committed_(false), - marker_(this, heap->mark_compact_collector()), steps_count_(0), steps_took_(0), longest_step_(0.0), @@ -53,7 +52,7 @@ IncrementalMarking::IncrementalMarking(Heap* heap) steps_count_since_last_gc_(0), steps_took_since_last_gc_(0), should_hurry_(false), - allocation_marking_factor_(0), + marking_speed_(0), allocated_(0), no_marking_scope_depth_(0) { } @@ -67,7 +66,7 @@ void IncrementalMarking::TearDown() { void IncrementalMarking::RecordWriteSlow(HeapObject* obj, Object** slot, Object* value) { - if (BaseRecordWrite(obj, slot, value) && is_compacting_ && slot != NULL) { + if (BaseRecordWrite(obj, slot, value) && slot != NULL) { MarkBit obj_bit = Marking::MarkBitFrom(obj); if (Marking::IsBlack(obj_bit)) { // Object is not going to be rescanned we need to record the slot. @@ -79,29 +78,43 @@ void IncrementalMarking::RecordWriteSlow(HeapObject* obj, void IncrementalMarking::RecordWriteFromCode(HeapObject* obj, - Object* value, + Object** slot, Isolate* isolate) { ASSERT(obj->IsHeapObject()); - - // Fast cases should already be covered by RecordWriteStub. - ASSERT(value->IsHeapObject()); - ASSERT(!value->IsHeapNumber()); - ASSERT(!value->IsString() || - value->IsConsString() || - value->IsSlicedString()); - ASSERT(Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(value)))); - IncrementalMarking* marking = isolate->heap()->incremental_marking(); ASSERT(!marking->is_compacting_); - marking->RecordWrite(obj, NULL, value); + + MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); + int counter = chunk->write_barrier_counter(); + if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) { + marking->write_barriers_invoked_since_last_step_ += + MemoryChunk::kWriteBarrierCounterGranularity - + chunk->write_barrier_counter(); + chunk->set_write_barrier_counter( + MemoryChunk::kWriteBarrierCounterGranularity); + } + + marking->RecordWrite(obj, slot, *slot); } void IncrementalMarking::RecordWriteForEvacuationFromCode(HeapObject* obj, Object** slot, Isolate* isolate) { + ASSERT(obj->IsHeapObject()); IncrementalMarking* marking = isolate->heap()->incremental_marking(); ASSERT(marking->is_compacting_); + + MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); + int counter = chunk->write_barrier_counter(); + if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) { + marking->write_barriers_invoked_since_last_step_ += + MemoryChunk::kWriteBarrierCounterGranularity - + chunk->write_barrier_counter(); + chunk->set_write_barrier_counter( + MemoryChunk::kWriteBarrierCounterGranularity); + } + marking->RecordWrite(obj, slot, *slot); } @@ -127,9 +140,9 @@ void IncrementalMarking::RecordCodeTargetPatch(Address pc, HeapObject* value) { void IncrementalMarking::RecordWriteOfCodeEntrySlow(JSFunction* host, - Object** slot, - Code* value) { - if (BaseRecordWrite(host, slot, value) && is_compacting_) { + Object** slot, + Code* value) { + if (BaseRecordWrite(host, slot, value)) { ASSERT(slot != NULL); heap_->mark_compact_collector()-> RecordCodeEntrySlot(reinterpret_cast<Address>(slot), value); @@ -162,17 +175,98 @@ void IncrementalMarking::RecordWriteIntoCodeSlow(HeapObject* obj, } +static void MarkObjectGreyDoNotEnqueue(Object* obj) { + if (obj->IsHeapObject()) { + HeapObject* heap_obj = HeapObject::cast(obj); + MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::cast(obj)); + if (Marking::IsBlack(mark_bit)) { + MemoryChunk::IncrementLiveBytesFromGC(heap_obj->address(), + -heap_obj->Size()); + } + Marking::AnyToGrey(mark_bit); + } +} + + +static inline void MarkBlackOrKeepGrey(HeapObject* heap_object, + MarkBit mark_bit, + int size) { + ASSERT(!Marking::IsImpossible(mark_bit)); + if (mark_bit.Get()) return; + mark_bit.Set(); + MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), size); + ASSERT(Marking::IsBlack(mark_bit)); +} + + +static inline void MarkBlackOrKeepBlack(HeapObject* heap_object, + MarkBit mark_bit, + int size) { + ASSERT(!Marking::IsImpossible(mark_bit)); + if (Marking::IsBlack(mark_bit)) return; + Marking::MarkBlack(mark_bit); + MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), size); + ASSERT(Marking::IsBlack(mark_bit)); +} + + class IncrementalMarkingMarkingVisitor : public StaticMarkingVisitor<IncrementalMarkingMarkingVisitor> { public: static void Initialize() { StaticMarkingVisitor<IncrementalMarkingMarkingVisitor>::Initialize(); + table_.Register(kVisitFixedArray, &VisitFixedArrayIncremental); + table_.Register(kVisitNativeContext, &VisitNativeContextIncremental); + table_.Register(kVisitJSRegExp, &VisitJSRegExp); + } + + static const int kProgressBarScanningChunk = 32 * 1024; - table_.Register(kVisitSharedFunctionInfo, &VisitSharedFunctionInfo); + static void VisitFixedArrayIncremental(Map* map, HeapObject* object) { + MemoryChunk* chunk = MemoryChunk::FromAddress(object->address()); + // TODO(mstarzinger): Move setting of the flag to the allocation site of + // the array. The visitor should just check the flag. + if (FLAG_use_marking_progress_bar && + chunk->owner()->identity() == LO_SPACE) { + chunk->SetFlag(MemoryChunk::HAS_PROGRESS_BAR); + } + if (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) { + Heap* heap = map->GetHeap(); + // When using a progress bar for large fixed arrays, scan only a chunk of + // the array and try to push it onto the marking deque again until it is + // fully scanned. Fall back to scanning it through to the end in case this + // fails because of a full deque. + int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); + int start_offset = Max(FixedArray::BodyDescriptor::kStartOffset, + chunk->progress_bar()); + int end_offset = Min(object_size, + start_offset + kProgressBarScanningChunk); + bool scan_until_end = false; + do { + VisitPointersWithAnchor(heap, + HeapObject::RawField(object, 0), + HeapObject::RawField(object, start_offset), + HeapObject::RawField(object, end_offset)); + start_offset = end_offset; + end_offset = Min(object_size, end_offset + kProgressBarScanningChunk); + scan_until_end = heap->incremental_marking()->marking_deque()->IsFull(); + } while (scan_until_end && start_offset < object_size); + chunk->set_progress_bar(start_offset); + if (start_offset < object_size) { + heap->incremental_marking()->marking_deque()->UnshiftGrey(object); + } + } else { + FixedArrayVisitor::Visit(map, object); + } + } - table_.Register(kVisitJSFunction, &VisitJSFunction); + static void VisitNativeContextIncremental(Map* map, HeapObject* object) { + Context* context = Context::cast(object); - table_.Register(kVisitJSRegExp, &VisitJSRegExp); + // We will mark cache black with a separate pass + // when we finish marking. + MarkObjectGreyDoNotEnqueue(context->normalized_map_cache()); + VisitNativeContext(map, context); } static void VisitJSWeakMap(Map* map, HeapObject* object) { @@ -182,31 +276,7 @@ class IncrementalMarkingMarkingVisitor HeapObject::RawField(object, JSWeakMap::kSize)); } - static void VisitSharedFunctionInfo(Map* map, HeapObject* object) { - Heap* heap = map->GetHeap(); - SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); - if (shared->ic_age() != heap->global_ic_age()) { - shared->ResetForNewContext(heap->global_ic_age()); - } - FixedBodyVisitor<IncrementalMarkingMarkingVisitor, - SharedFunctionInfo::BodyDescriptor, - void>::Visit(map, object); - } - - static inline void VisitJSFunction(Map* map, HeapObject* object) { - Heap* heap = map->GetHeap(); - // Iterate over all fields in the body but take care in dealing with - // the code entry and skip weak fields. - VisitPointers(heap, - HeapObject::RawField(object, JSFunction::kPropertiesOffset), - HeapObject::RawField(object, JSFunction::kCodeEntryOffset)); - VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset); - VisitPointers(heap, - HeapObject::RawField(object, - JSFunction::kCodeEntryOffset + kPointerSize), - HeapObject::RawField(object, - JSFunction::kNonWeakFieldsEndOffset)); - } + static void BeforeVisitingSharedFunctionInfo(HeapObject* object) {} INLINE(static void VisitPointer(Heap* heap, Object** p)) { Object* obj = *p; @@ -226,27 +296,51 @@ class IncrementalMarkingMarkingVisitor } } + INLINE(static void VisitPointersWithAnchor(Heap* heap, + Object** anchor, + Object** start, + Object** end)) { + for (Object** p = start; p < end; p++) { + Object* obj = *p; + if (obj->NonFailureIsHeapObject()) { + heap->mark_compact_collector()->RecordSlot(anchor, p, obj); + MarkObject(heap, obj); + } + } + } + + // Marks the object grey and pushes it on the marking stack. INLINE(static void MarkObject(Heap* heap, Object* obj)) { HeapObject* heap_object = HeapObject::cast(obj); MarkBit mark_bit = Marking::MarkBitFrom(heap_object); if (mark_bit.data_only()) { - if (heap->incremental_marking()->MarkBlackOrKeepGrey(mark_bit)) { - MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), - heap_object->Size()); - } + MarkBlackOrKeepGrey(heap_object, mark_bit, heap_object->Size()); } else if (Marking::IsWhite(mark_bit)) { heap->incremental_marking()->WhiteToGreyAndPush(heap_object, mark_bit); } } + + // Marks the object black without pushing it on the marking stack. + // Returns true if object needed marking and false otherwise. + INLINE(static bool MarkObjectWithoutPush(Heap* heap, Object* obj)) { + HeapObject* heap_object = HeapObject::cast(obj); + MarkBit mark_bit = Marking::MarkBitFrom(heap_object); + if (Marking::IsWhite(mark_bit)) { + mark_bit.Set(); + MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), + heap_object->Size()); + return true; + } + return false; + } }; class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor { public: - IncrementalMarkingRootMarkingVisitor(Heap* heap, - IncrementalMarking* incremental_marking) - : heap_(heap), - incremental_marking_(incremental_marking) { + explicit IncrementalMarkingRootMarkingVisitor( + IncrementalMarking* incremental_marking) + : incremental_marking_(incremental_marking) { } void VisitPointer(Object** p) { @@ -265,10 +359,7 @@ class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor { HeapObject* heap_object = HeapObject::cast(obj); MarkBit mark_bit = Marking::MarkBitFrom(heap_object); if (mark_bit.data_only()) { - if (incremental_marking_->MarkBlackOrKeepGrey(mark_bit)) { - MemoryChunk::IncrementLiveBytesFromGC(heap_object->address(), - heap_object->Size()); - } + MarkBlackOrKeepGrey(heap_object, mark_bit, heap_object->Size()); } else { if (Marking::IsWhite(mark_bit)) { incremental_marking_->WhiteToGreyAndPush(heap_object, mark_bit); @@ -276,7 +367,6 @@ class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor { } } - Heap* heap_; IncrementalMarking* incremental_marking_; }; @@ -494,19 +584,6 @@ void IncrementalMarking::Start() { } -static void MarkObjectGreyDoNotEnqueue(Object* obj) { - if (obj->IsHeapObject()) { - HeapObject* heap_obj = HeapObject::cast(obj); - MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::cast(obj)); - if (Marking::IsBlack(mark_bit)) { - MemoryChunk::IncrementLiveBytesFromGC(heap_obj->address(), - -heap_obj->Size()); - } - Marking::AnyToGrey(mark_bit); - } -} - - void IncrementalMarking::StartMarking(CompactionFlag flag) { if (FLAG_trace_incremental_marking) { PrintF("[IncrementalMarking] Start marking\n"); @@ -533,8 +610,8 @@ void IncrementalMarking::StartMarking(CompactionFlag flag) { ActivateIncrementalWriteBarrier(); -#ifdef DEBUG // Marking bits are cleared by the sweeper. +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { heap_->mark_compact_collector()->VerifyMarkbitsAreClean(); } @@ -550,7 +627,7 @@ void IncrementalMarking::StartMarking(CompactionFlag flag) { } // Mark strong roots grey. - IncrementalMarkingRootMarkingVisitor visitor(heap_, this); + IncrementalMarkingRootMarkingVisitor visitor(this); heap_->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG); // Ready to start incremental marking. @@ -606,8 +683,11 @@ void IncrementalMarking::UpdateMarkingDequeAfterScavenge() { ASSERT(new_top != marking_deque_.bottom()); #ifdef DEBUG MarkBit mark_bit = Marking::MarkBitFrom(obj); + MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); ASSERT(Marking::IsGrey(mark_bit) || - (obj->IsFiller() && Marking::IsWhite(mark_bit))); + (obj->IsFiller() && Marking::IsWhite(mark_bit)) || + (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR) && + Marking::IsBlack(mark_bit))); #endif } } @@ -619,6 +699,58 @@ void IncrementalMarking::UpdateMarkingDequeAfterScavenge() { } +void IncrementalMarking::VisitObject(Map* map, HeapObject* obj, int size) { + MarkBit map_mark_bit = Marking::MarkBitFrom(map); + if (Marking::IsWhite(map_mark_bit)) { + WhiteToGreyAndPush(map, map_mark_bit); + } + + IncrementalMarkingMarkingVisitor::IterateBody(map, obj); + + MarkBit mark_bit = Marking::MarkBitFrom(obj); +#ifdef DEBUG + MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); + SLOW_ASSERT(Marking::IsGrey(mark_bit) || + (obj->IsFiller() && Marking::IsWhite(mark_bit)) || + (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR) && + Marking::IsBlack(mark_bit))); +#endif + MarkBlackOrKeepBlack(obj, mark_bit, size); +} + + +void IncrementalMarking::ProcessMarkingDeque(intptr_t bytes_to_process) { + Map* filler_map = heap_->one_pointer_filler_map(); + while (!marking_deque_.IsEmpty() && bytes_to_process > 0) { + HeapObject* obj = marking_deque_.Pop(); + + // Explicitly skip one word fillers. Incremental markbit patterns are + // correct only for objects that occupy at least two words. + Map* map = obj->map(); + if (map == filler_map) continue; + + int size = obj->SizeFromMap(map); + bytes_to_process -= size; + VisitObject(map, obj, size); + } +} + + +void IncrementalMarking::ProcessMarkingDeque() { + Map* filler_map = heap_->one_pointer_filler_map(); + while (!marking_deque_.IsEmpty()) { + HeapObject* obj = marking_deque_.Pop(); + + // Explicitly skip one word fillers. Incremental markbit patterns are + // correct only for objects that occupy at least two words. + Map* map = obj->map(); + if (map == filler_map) continue; + + VisitObject(map, obj, obj->SizeFromMap(map)); + } +} + + void IncrementalMarking::Hurry() { if (state() == MARKING) { double start = 0.0; @@ -628,49 +760,7 @@ void IncrementalMarking::Hurry() { } // TODO(gc) hurry can mark objects it encounters black as mutator // was stopped. - Map* filler_map = heap_->one_pointer_filler_map(); - Map* native_context_map = heap_->native_context_map(); - while (!marking_deque_.IsEmpty()) { - HeapObject* obj = marking_deque_.Pop(); - - // Explicitly skip one word fillers. Incremental markbit patterns are - // correct only for objects that occupy at least two words. - Map* map = obj->map(); - if (map == filler_map) { - continue; - } else if (map == native_context_map) { - // Native contexts have weak fields. - IncrementalMarkingMarkingVisitor::VisitNativeContext(map, obj); - } else if (map->instance_type() == MAP_TYPE) { - Map* map = Map::cast(obj); - heap_->ClearCacheOnMap(map); - - // When map collection is enabled we have to mark through map's - // transitions and back pointers in a special way to make these links - // weak. Only maps for subclasses of JSReceiver can have transitions. - STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); - if (FLAG_collect_maps && - map->instance_type() >= FIRST_JS_RECEIVER_TYPE) { - marker_.MarkMapContents(map); - } else { - IncrementalMarkingMarkingVisitor::VisitPointers( - heap_, - HeapObject::RawField(map, Map::kPointerFieldsBeginOffset), - HeapObject::RawField(map, Map::kPointerFieldsEndOffset)); - } - } else { - MarkBit map_mark_bit = Marking::MarkBitFrom(map); - if (Marking::IsWhite(map_mark_bit)) { - WhiteToGreyAndPush(map, map_mark_bit); - } - IncrementalMarkingMarkingVisitor::IterateBody(map, obj); - } - - MarkBit mark_bit = Marking::MarkBitFrom(obj); - ASSERT(!Marking::IsBlack(mark_bit)); - Marking::MarkBlack(mark_bit); - MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); - } + ProcessMarkingDeque(); state_ = COMPLETE; if (FLAG_trace_incremental_marking) { double end = OS::TimeCurrentMillis(); @@ -776,11 +866,25 @@ void IncrementalMarking::Step(intptr_t allocated_bytes, allocated_ += allocated_bytes; - if (allocated_ < kAllocatedThreshold) return; + if (allocated_ < kAllocatedThreshold && + write_barriers_invoked_since_last_step_ < + kWriteBarriersInvokedThreshold) { + return; + } if (state_ == MARKING && no_marking_scope_depth_ > 0) return; - intptr_t bytes_to_process = allocated_ * allocation_marking_factor_; + // The marking speed is driven either by the allocation rate or by the rate + // at which we are having to check the color of objects in the write barrier. + // It is possible for a tight non-allocating loop to run a lot of write + // barriers before we get here and check them (marking can only take place on + // allocation), so to reduce the lumpiness we don't use the write barriers + // invoked since last step directly to determine the amount of work to do. + intptr_t bytes_to_process = + marking_speed_ * Max(allocated_, write_barriers_invoked_since_last_step_); + allocated_ = 0; + write_barriers_invoked_since_last_step_ = 0; + bytes_scanned_ += bytes_to_process; double start = 0; @@ -795,74 +899,19 @@ void IncrementalMarking::Step(intptr_t allocated_bytes, StartMarking(PREVENT_COMPACTION); } } else if (state_ == MARKING) { - Map* filler_map = heap_->one_pointer_filler_map(); - Map* native_context_map = heap_->native_context_map(); - while (!marking_deque_.IsEmpty() && bytes_to_process > 0) { - HeapObject* obj = marking_deque_.Pop(); - - // Explicitly skip one word fillers. Incremental markbit patterns are - // correct only for objects that occupy at least two words. - Map* map = obj->map(); - if (map == filler_map) continue; - - int size = obj->SizeFromMap(map); - bytes_to_process -= size; - MarkBit map_mark_bit = Marking::MarkBitFrom(map); - if (Marking::IsWhite(map_mark_bit)) { - WhiteToGreyAndPush(map, map_mark_bit); - } - - // TODO(gc) switch to static visitor instead of normal visitor. - if (map == native_context_map) { - // Native contexts have weak fields. - Context* ctx = Context::cast(obj); - - // We will mark cache black with a separate pass - // when we finish marking. - MarkObjectGreyDoNotEnqueue(ctx->normalized_map_cache()); - - IncrementalMarkingMarkingVisitor::VisitNativeContext(map, ctx); - } else if (map->instance_type() == MAP_TYPE) { - Map* map = Map::cast(obj); - heap_->ClearCacheOnMap(map); - - // When map collection is enabled we have to mark through map's - // transitions and back pointers in a special way to make these links - // weak. Only maps for subclasses of JSReceiver can have transitions. - STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); - if (FLAG_collect_maps && - map->instance_type() >= FIRST_JS_RECEIVER_TYPE) { - marker_.MarkMapContents(map); - } else { - IncrementalMarkingMarkingVisitor::VisitPointers( - heap_, - HeapObject::RawField(map, Map::kPointerFieldsBeginOffset), - HeapObject::RawField(map, Map::kPointerFieldsEndOffset)); - } - } else { - IncrementalMarkingMarkingVisitor::IterateBody(map, obj); - } - - MarkBit obj_mark_bit = Marking::MarkBitFrom(obj); - SLOW_ASSERT(Marking::IsGrey(obj_mark_bit) || - (obj->IsFiller() && Marking::IsWhite(obj_mark_bit))); - Marking::MarkBlack(obj_mark_bit); - MemoryChunk::IncrementLiveBytesFromGC(obj->address(), size); - } + ProcessMarkingDeque(bytes_to_process); if (marking_deque_.IsEmpty()) MarkingComplete(action); } - allocated_ = 0; - steps_count_++; steps_count_since_last_gc_++; bool speed_up = false; - if ((steps_count_ % kAllocationMarkingFactorSpeedupInterval) == 0) { + if ((steps_count_ % kMarkingSpeedAccellerationInterval) == 0) { if (FLAG_trace_gc) { PrintPID("Speed up marking after %d steps\n", - static_cast<int>(kAllocationMarkingFactorSpeedupInterval)); + static_cast<int>(kMarkingSpeedAccellerationInterval)); } speed_up = true; } @@ -871,7 +920,7 @@ void IncrementalMarking::Step(intptr_t allocated_bytes, (old_generation_space_available_at_start_of_incremental_ < 10 * MB); bool only_1_nth_of_space_that_was_available_still_left = - (SpaceLeftInOldSpace() * (allocation_marking_factor_ + 1) < + (SpaceLeftInOldSpace() * (marking_speed_ + 1) < old_generation_space_available_at_start_of_incremental_); if (space_left_is_very_small || @@ -882,7 +931,7 @@ void IncrementalMarking::Step(intptr_t allocated_bytes, bool size_of_old_space_multiplied_by_n_during_marking = (heap_->PromotedTotalSize() > - (allocation_marking_factor_ + 1) * + (marking_speed_ + 1) * old_generation_space_used_at_start_of_incremental_); if (size_of_old_space_multiplied_by_n_during_marking) { speed_up = true; @@ -893,7 +942,7 @@ void IncrementalMarking::Step(intptr_t allocated_bytes, int64_t promoted_during_marking = heap_->PromotedTotalSize() - old_generation_space_used_at_start_of_incremental_; - intptr_t delay = allocation_marking_factor_ * MB; + intptr_t delay = marking_speed_ * MB; intptr_t scavenge_slack = heap_->MaxSemiSpaceSize(); // We try to scan at at least twice the speed that we are allocating. @@ -910,12 +959,12 @@ void IncrementalMarking::Step(intptr_t allocated_bytes, PrintPID("Postponing speeding up marking until marking starts\n"); } } else { - allocation_marking_factor_ += kAllocationMarkingFactorSpeedup; - allocation_marking_factor_ = static_cast<int>( - Min(kMaxAllocationMarkingFactor, - static_cast<intptr_t>(allocation_marking_factor_ * 1.3))); + marking_speed_ += kMarkingSpeedAccellerationInterval; + marking_speed_ = static_cast<int>( + Min(kMaxMarkingSpeed, + static_cast<intptr_t>(marking_speed_ * 1.3))); if (FLAG_trace_gc) { - PrintPID("Marking speed increased to %d\n", allocation_marking_factor_); + PrintPID("Marking speed increased to %d\n", marking_speed_); } } } @@ -941,8 +990,9 @@ void IncrementalMarking::ResetStepCounters() { steps_count_since_last_gc_ = 0; steps_took_since_last_gc_ = 0; bytes_rescanned_ = 0; - allocation_marking_factor_ = kInitialAllocationMarkingFactor; + marking_speed_ = kInitialMarkingSpeed; bytes_scanned_ = 0; + write_barriers_invoked_since_last_step_ = 0; } diff --git a/deps/v8/src/incremental-marking.h b/deps/v8/src/incremental-marking.h index 4cb356de8f..fc5a978cc4 100644 --- a/deps/v8/src/incremental-marking.h +++ b/deps/v8/src/incremental-marking.h @@ -95,21 +95,23 @@ class IncrementalMarking { // progress in the face of the mutator creating new work for it. We start // of at a moderate rate of work and gradually increase the speed of the // incremental marker until it completes. - // Do some marking every time this much memory has been allocated. + // Do some marking every time this much memory has been allocated or that many + // heavy (color-checking) write barriers have been invoked. static const intptr_t kAllocatedThreshold = 65536; + static const intptr_t kWriteBarriersInvokedThreshold = 65536; // Start off by marking this many times more memory than has been allocated. - static const intptr_t kInitialAllocationMarkingFactor = 1; + static const intptr_t kInitialMarkingSpeed = 1; // But if we are promoting a lot of data we need to mark faster to keep up // with the data that is entering the old space through promotion. static const intptr_t kFastMarking = 3; // After this many steps we increase the marking/allocating factor. - static const intptr_t kAllocationMarkingFactorSpeedupInterval = 1024; + static const intptr_t kMarkingSpeedAccellerationInterval = 1024; // This is how much we increase the marking/allocating factor by. - static const intptr_t kAllocationMarkingFactorSpeedup = 2; - static const intptr_t kMaxAllocationMarkingFactor = 1000; + static const intptr_t kMarkingSpeedAccelleration = 2; + static const intptr_t kMaxMarkingSpeed = 1000; void OldSpaceStep(intptr_t allocated) { - Step(allocated * kFastMarking / kInitialAllocationMarkingFactor, + Step(allocated * kFastMarking / kInitialMarkingSpeed, GC_VIA_STACK_GUARD); } @@ -125,13 +127,19 @@ class IncrementalMarking { } static void RecordWriteFromCode(HeapObject* obj, - Object* value, + Object** slot, Isolate* isolate); static void RecordWriteForEvacuationFromCode(HeapObject* obj, Object** slot, Isolate* isolate); + // Record a slot for compaction. Returns false for objects that are + // guaranteed to be rescanned or not guaranteed to survive. + // + // No slots in white objects should be recorded, as some slots are typed and + // cannot be interpreted correctly if the underlying object does not survive + // the incremental cycle (stays white). INLINE(bool BaseRecordWrite(HeapObject* obj, Object** slot, Object* value)); INLINE(void RecordWrite(HeapObject* obj, Object** slot, Object* value)); INLINE(void RecordWriteIntoCode(HeapObject* obj, @@ -156,29 +164,6 @@ class IncrementalMarking { inline void WhiteToGreyAndPush(HeapObject* obj, MarkBit mark_bit); - // Does white->black or keeps gray or black color. Returns true if converting - // white to black. - inline bool MarkBlackOrKeepGrey(MarkBit mark_bit) { - ASSERT(!Marking::IsImpossible(mark_bit)); - if (mark_bit.Get()) { - // Grey or black: Keep the color. - return false; - } - mark_bit.Set(); - ASSERT(Marking::IsBlack(mark_bit)); - return true; - } - - // Marks the object grey and pushes it on the marking stack. - // Returns true if object needed marking and false otherwise. - // This is for incremental marking only. - INLINE(bool MarkObjectAndPush(HeapObject* obj)); - - // Marks the object black without pushing it on the marking stack. - // Returns true if object needed marking and false otherwise. - // This is for incremental marking only. - INLINE(bool MarkObjectWithoutPush(HeapObject* obj)); - inline int steps_count() { return steps_count_; } @@ -215,13 +200,13 @@ class IncrementalMarking { void NotifyOfHighPromotionRate() { if (IsMarking()) { - if (allocation_marking_factor_ < kFastMarking) { + if (marking_speed_ < kFastMarking) { if (FLAG_trace_gc) { PrintPID("Increasing marking speed to %d " "due to high promotion rate\n", static_cast<int>(kFastMarking)); } - allocation_marking_factor_ = kFastMarking; + marking_speed_ = kFastMarking; } } } @@ -261,6 +246,12 @@ class IncrementalMarking { void EnsureMarkingDequeIsCommitted(); + INLINE(void ProcessMarkingDeque()); + + INLINE(void ProcessMarkingDeque(intptr_t bytes_to_process)); + + INLINE(void VisitObject(Map* map, HeapObject* obj, int size)); + Heap* heap_; State state_; @@ -269,7 +260,6 @@ class IncrementalMarking { VirtualMemory* marking_deque_memory_; bool marking_deque_memory_committed_; MarkingDeque marking_deque_; - Marker<IncrementalMarking> marker_; int steps_count_; double steps_took_; @@ -280,9 +270,10 @@ class IncrementalMarking { double steps_took_since_last_gc_; int64_t bytes_rescanned_; bool should_hurry_; - int allocation_marking_factor_; + int marking_speed_; intptr_t bytes_scanned_; intptr_t allocated_; + intptr_t write_barriers_invoked_since_last_step_; int no_marking_scope_depth_; diff --git a/deps/v8/src/interface.cc b/deps/v8/src/interface.cc index 336be82c60..1634a37113 100644 --- a/deps/v8/src/interface.cc +++ b/deps/v8/src/interface.cc @@ -170,6 +170,8 @@ void Interface::DoUnify(Interface* that, bool* ok, Zone* zone) { ASSERT(that->forward_ == NULL); ASSERT(!this->IsValue()); ASSERT(!that->IsValue()); + ASSERT(this->index_ == -1); + ASSERT(that->index_ == -1); ASSERT(*ok); #ifdef DEBUG @@ -194,15 +196,6 @@ void Interface::DoUnify(Interface* that, bool* ok, Zone* zone) { 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; @@ -227,7 +220,7 @@ void Interface::Print(int n) { } else if (IsValue()) { PrintF("value\n"); } else if (IsModule()) { - PrintF("module %s{", IsFrozen() ? "" : "(unresolved) "); + PrintF("module %d %s{", Index(), IsFrozen() ? "" : "(unresolved) "); ZoneHashMap* map = Chase()->exports_; if (map == NULL || map->occupancy() == 0) { PrintF("}\n"); diff --git a/deps/v8/src/interface.h b/deps/v8/src/interface.h index 94ef11ba5c..f824a9a874 100644 --- a/deps/v8/src/interface.h +++ b/deps/v8/src/interface.h @@ -108,18 +108,18 @@ 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(); if (*ok) Chase()->flags_ |= FROZEN; } + // Assign an index. + void Allocate(int index) { + ASSERT(IsModule() && IsFrozen() && Chase()->index_ == -1); + Chase()->index_ = index; + } + // --------------------------------------------------------------------------- // Accessors. @@ -138,7 +138,23 @@ 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_; } + bool IsUnified(Interface* that) { + return Chase() == that->Chase() + || (this->IsValue() == that->IsValue() && + this->IsConst() == that->IsConst()); + } + + int Length() { + ASSERT(IsModule() && IsFrozen()); + ZoneHashMap* exports = Chase()->exports_; + return exports ? exports->occupancy() : 0; + } + + // The context slot in the hosting global context pointing to this module. + int Index() { + ASSERT(IsModule() && IsFrozen()); + return Chase()->index_; + } // Look up an exported name. Returns NULL if not (yet) defined. Interface* Lookup(Handle<String> name, Zone* zone); @@ -194,12 +210,13 @@ class Interface : public ZoneObject { int flags_; Interface* forward_; // Unification link ZoneHashMap* exports_; // Module exports and their types (allocated lazily) - Handle<JSModule> instance_; + int index_; explicit Interface(int flags) : flags_(flags), forward_(NULL), - exports_(NULL) { + exports_(NULL), + index_(-1) { #ifdef DEBUG if (FLAG_print_interface_details) PrintF("# Creating %p\n", static_cast<void*>(this)); diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 75e15a4541..15d0bdd441 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -426,11 +426,6 @@ char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) { } -void Isolate::IterateThread(ThreadVisitor* v) { - v->VisitThread(this, thread_local_top()); -} - - void Isolate::IterateThread(ThreadVisitor* v, char* t) { ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t); v->VisitThread(this, thread); @@ -553,7 +548,97 @@ void Isolate::PushStackTraceAndDie(unsigned int magic, } -void Isolate::CaptureAndSetCurrentStackTraceFor(Handle<JSObject> error_object) { +// Determines whether the given stack frame should be displayed in +// a stack trace. The caller is the error constructor that asked +// for the stack trace to be collected. The first time a construct +// call to this function is encountered it is skipped. The seen_caller +// in/out parameter is used to remember if the caller has been seen +// yet. +static bool IsVisibleInStackTrace(StackFrame* raw_frame, + Object* caller, + bool* seen_caller) { + // Only display JS frames. + if (!raw_frame->is_java_script()) return false; + JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); + Object* raw_fun = frame->function(); + // Not sure when this can happen but skip it just in case. + if (!raw_fun->IsJSFunction()) return false; + if ((raw_fun == caller) && !(*seen_caller)) { + *seen_caller = true; + return false; + } + // Skip all frames until we've seen the caller. + if (!(*seen_caller)) return false; + // Also, skip non-visible built-in functions and any call with the builtins + // object as receiver, so as to not reveal either the builtins object or + // an internal function. + // The --builtins-in-stack-traces command line flag allows including + // internal call sites in the stack trace for debugging purposes. + if (!FLAG_builtins_in_stack_traces) { + JSFunction* fun = JSFunction::cast(raw_fun); + if (frame->receiver()->IsJSBuiltinsObject() || + (fun->IsBuiltin() && !fun->shared()->native())) { + return false; + } + } + return true; +} + + +Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, + Handle<Object> caller, + int limit) { + limit = Max(limit, 0); // Ensure that limit is not negative. + int initial_size = Min(limit, 10); + Handle<FixedArray> elements = + factory()->NewFixedArrayWithHoles(initial_size * 4); + + // If the caller parameter is a function we skip frames until we're + // under it before starting to collect. + bool seen_caller = !caller->IsJSFunction(); + int cursor = 0; + int frames_seen = 0; + for (StackFrameIterator iter(this); + !iter.done() && frames_seen < limit; + iter.Advance()) { + StackFrame* raw_frame = iter.frame(); + if (IsVisibleInStackTrace(raw_frame, *caller, &seen_caller)) { + frames_seen++; + JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); + // Set initial size to the maximum inlining level + 1 for the outermost + // function. + List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1); + frame->Summarize(&frames); + for (int i = frames.length() - 1; i >= 0; i--) { + if (cursor + 4 > elements->length()) { + int new_capacity = JSObject::NewElementsCapacity(elements->length()); + Handle<FixedArray> new_elements = + factory()->NewFixedArrayWithHoles(new_capacity); + for (int i = 0; i < cursor; i++) { + new_elements->set(i, elements->get(i)); + } + elements = new_elements; + } + ASSERT(cursor + 4 <= elements->length()); + + Handle<Object> recv = frames[i].receiver(); + Handle<JSFunction> fun = frames[i].function(); + Handle<Code> code = frames[i].code(); + Handle<Smi> offset(Smi::FromInt(frames[i].offset())); + elements->set(cursor++, *recv); + elements->set(cursor++, *fun); + elements->set(cursor++, *code); + elements->set(cursor++, *offset); + } + } + } + Handle<JSArray> result = factory()->NewJSArrayWithElements(elements); + result->set_length(Smi::FromInt(cursor)); + return result; +} + + +void Isolate::CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object) { if (capture_stack_trace_for_uncaught_exceptions_) { // Capture stack trace for a detailed exception message. Handle<String> key = factory()->hidden_stack_trace_symbol(); @@ -574,8 +659,6 @@ Handle<JSArray> Isolate::CaptureCurrentStackTrace( Handle<String> column_key = factory()->LookupAsciiSymbol("column"); Handle<String> line_key = factory()->LookupAsciiSymbol("lineNumber"); Handle<String> script_key = factory()->LookupAsciiSymbol("scriptName"); - Handle<String> name_or_source_url_key = - factory()->LookupAsciiSymbol("nameOrSourceURL"); Handle<String> script_name_or_source_url_key = factory()->LookupAsciiSymbol("scriptNameOrSourceURL"); Handle<String> function_key = factory()->LookupAsciiSymbol("functionName"); @@ -635,18 +718,7 @@ Handle<JSArray> Isolate::CaptureCurrentStackTrace( } if (options & StackTrace::kScriptNameOrSourceURL) { - Handle<Object> script_name(script->name(), this); - Handle<JSValue> script_wrapper = GetScriptWrapper(script); - Handle<Object> property = GetProperty(script_wrapper, - name_or_source_url_key); - ASSERT(property->IsJSFunction()); - Handle<JSFunction> method = Handle<JSFunction>::cast(property); - bool caught_exception; - Handle<Object> result = Execution::TryCall(method, script_wrapper, 0, - NULL, &caught_exception); - if (caught_exception) { - result = factory()->undefined_value(); - } + Handle<Object> result = GetScriptNameOrSourceURL(script); CHECK_NOT_EMPTY_HANDLE(this, JSObject::SetLocalPropertyIgnoreAttributes( stack_frame, script_name_or_source_url_key, @@ -923,15 +995,28 @@ const char* const Isolate::kStackOverflowMessage = Failure* Isolate::StackOverflow() { HandleScope scope; + // At this point we cannot create an Error object using its javascript + // constructor. Instead, we copy the pre-constructed boilerplate and + // attach the stack trace as a hidden property. Handle<String> key = factory()->stack_overflow_symbol(); Handle<JSObject> boilerplate = Handle<JSObject>::cast(GetProperty(js_builtins_object(), key)); - Handle<Object> exception = Copy(boilerplate); - // TODO(1240995): To avoid having to call JavaScript code to compute - // the message for stack overflow exceptions which is very likely to - // double fault with another stack overflow exception, we use a - // precomputed message. + Handle<JSObject> exception = Copy(boilerplate); DoThrow(*exception, NULL); + + // Get stack trace limit. + Handle<Object> error = GetProperty(js_builtins_object(), "$Error"); + if (!error->IsJSObject()) return Failure::Exception(); + Handle<Object> stack_trace_limit = + GetProperty(Handle<JSObject>::cast(error), "stackTraceLimit"); + if (!stack_trace_limit->IsNumber()) return Failure::Exception(); + int limit = static_cast<int>(stack_trace_limit->Number()); + + Handle<JSArray> stack_trace = CaptureSimpleStackTrace( + exception, factory()->undefined_value(), limit); + JSObject::SetHiddenProperty(exception, + factory()->hidden_stack_trace_symbol(), + stack_trace); return Failure::Exception(); } @@ -972,9 +1057,12 @@ void Isolate::ScheduleThrow(Object* exception) { // When scheduling a throw we first throw the exception to get the // error reporting if it is uncaught before rescheduling it. Throw(exception); - thread_local_top()->scheduled_exception_ = pending_exception(); - thread_local_top()->external_caught_exception_ = false; - clear_pending_exception(); + PropagatePendingExceptionToExternalTryCatch(); + if (has_pending_exception()) { + thread_local_top()->scheduled_exception_ = pending_exception(); + thread_local_top()->external_caught_exception_ = false; + clear_pending_exception(); + } } @@ -1138,10 +1226,22 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) { stack_trace_for_uncaught_exceptions_options_); } } + + Handle<Object> exception_arg = exception_handle; + // If the exception argument is a custom object, turn it into a string + // before throwing as uncaught exception. Note that the pending + // exception object to be set later must not be turned into a string. + if (exception_arg->IsJSObject() && !IsErrorObject(exception_arg)) { + bool failed = false; + exception_arg = Execution::ToDetailString(exception_arg, &failed); + if (failed) { + exception_arg = factory()->LookupAsciiSymbol("exception"); + } + } Handle<Object> message_obj = MessageHandler::MakeMessageObject( "uncaught_exception", location, - HandleVector<Object>(&exception_handle, 1), + HandleVector<Object>(&exception_arg, 1), stack_trace, stack_trace_object); thread_local_top()->pending_message_obj_ = *message_obj; @@ -1264,6 +1364,24 @@ void Isolate::ReportPendingMessages() { } +MessageLocation Isolate::GetMessageLocation() { + ASSERT(has_pending_exception()); + + if (thread_local_top_.pending_exception_ != Failure::OutOfMemoryException() && + thread_local_top_.pending_exception_ != heap()->termination_exception() && + thread_local_top_.has_pending_message_ && + !thread_local_top_.pending_message_obj_->IsTheHole() && + thread_local_top_.pending_message_script_ != NULL) { + Handle<Script> script(thread_local_top_.pending_message_script_); + int start_pos = thread_local_top_.pending_message_start_pos_; + int end_pos = thread_local_top_.pending_message_end_pos_; + return MessageLocation(script, start_pos, end_pos); + } + + return MessageLocation(); +} + + void Isolate::TraceException(bool flag) { FLAG_trace_exception = flag; // TODO(isolates): This is an unfortunate use. } @@ -1926,7 +2044,7 @@ bool Isolate::Init(Deserializer* des) { // If we are deserializing, log non-function code objects and compiled // functions found in the snapshot. - if (create_heap_objects && + if (!create_heap_objects && (FLAG_log_code || FLAG_ll_prof || logger_->is_logging_code_events())) { HandleScope scope; LOG(this, LogCodeObjects()); diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h index 1d7bc6fc6d..ac2e554f85 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -354,6 +354,7 @@ typedef List<HeapObject*, PreallocatedStorageAllocationPolicy> DebugObjectCache; V(uint64_t, enabled_cpu_features, 0) \ V(CpuProfiler*, cpu_profiler, NULL) \ V(HeapProfiler*, heap_profiler, NULL) \ + V(bool, observer_delivery_pending, false) \ ISOLATE_DEBUGGER_INIT_LIST(V) class Isolate { @@ -715,7 +716,10 @@ class Isolate { int frame_limit, StackTrace::StackTraceOptions options); - void CaptureAndSetCurrentStackTraceFor(Handle<JSObject> error_object); + Handle<JSArray> CaptureSimpleStackTrace(Handle<JSObject> error_object, + Handle<Object> caller, + int limit); + void CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object); // Returns if the top context may access the given global object. If // the result is false, the pending exception is guaranteed to be @@ -739,6 +743,8 @@ class Isolate { Failure* ReThrow(MaybeObject* exception); void ScheduleThrow(Object* exception); void ReportPendingMessages(); + // Return pending location if any or unfilled structure. + MessageLocation GetMessageLocation(); Failure* ThrowIllegalOperation(); // Promote a scheduled exception to pending. Asserts has_scheduled_exception. @@ -764,7 +770,6 @@ class Isolate { void Iterate(ObjectVisitor* v); void Iterate(ObjectVisitor* v, ThreadLocalTop* t); char* Iterate(ObjectVisitor* v, char* t); - void IterateThread(ThreadVisitor* v); void IterateThread(ThreadVisitor* v, char* t); @@ -917,10 +922,6 @@ class Isolate { bool fp_stubs_generated() { return fp_stubs_generated_; } - StaticResource<SafeStringInputBuffer>* compiler_safe_string_input_buffer() { - return &compiler_safe_string_input_buffer_; - } - Builtins* builtins() { return &builtins_; } void NotifyExtensionInstalled() { @@ -991,9 +992,6 @@ class Isolate { Factory* factory() { return reinterpret_cast<Factory*>(this); } - // SerializerDeserializer state. - static const int kPartialSnapshotCacheCapacity = 1400; - static const int kJSRegexpStaticOffsetsVectorSize = 128; Address external_callback() { @@ -1230,7 +1228,6 @@ class Isolate { ThreadManager* thread_manager_; RuntimeState runtime_state_; bool fp_stubs_generated_; - StaticResource<SafeStringInputBuffer> compiler_safe_string_input_buffer_; Builtins builtins_; bool has_installed_extensions_; StringTracker* string_tracker_; @@ -1397,12 +1394,7 @@ class StackLimitCheck BASE_EMBEDDED { bool HasOverflowed() const { StackGuard* stack_guard = isolate_->stack_guard(); - // Stack has overflowed in C++ code only if stack pointer exceeds the C++ - // stack guard and the limits are not set to interrupt values. - // TODO(214): Stack overflows are ignored if a interrupt is pending. This - // code should probably always use the initial C++ limit. - return (reinterpret_cast<uintptr_t>(this) < stack_guard->climit()) && - stack_guard->IsStackOverflow(); + return (reinterpret_cast<uintptr_t>(this) < stack_guard->real_climit()); } private: Isolate* isolate_; diff --git a/deps/v8/src/json-parser.h b/deps/v8/src/json-parser.h index a4db130e25..2f980cc05b 100644 --- a/deps/v8/src/json-parser.h +++ b/deps/v8/src/json-parser.h @@ -58,7 +58,7 @@ class JsonParser BASE_EMBEDDED { if (position_ >= source_length_) { c0_ = kEndOfString; } else if (seq_ascii) { - c0_ = seq_source_->SeqAsciiStringGet(position_); + c0_ = seq_source_->SeqOneByteStringGet(position_); } else { c0_ = source_->Get(position_); } @@ -71,11 +71,11 @@ class JsonParser BASE_EMBEDDED { inline void AdvanceSkipWhitespace() { do { Advance(); - } while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' '); + } while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r'); } inline void SkipWhitespace() { - while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' ') { + while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') { Advance(); } } @@ -149,17 +149,23 @@ class JsonParser BASE_EMBEDDED { } inline Isolate* isolate() { return isolate_; } + inline Factory* factory() { return factory_; } + inline Handle<JSFunction> object_constructor() { return object_constructor_; } inline Zone* zone() const { return zone_; } static const int kInitialSpecialStringLength = 1024; + static const int kPretenureTreshold = 100 * 1024; private: Handle<String> source_; int source_length_; - Handle<SeqAsciiString> seq_source_; + Handle<SeqOneByteString> seq_source_; + PretenureFlag pretenure_; Isolate* isolate_; + Factory* factory_; + Handle<JSFunction> object_constructor_; uc32 c0_; int position_; Zone* zone_; @@ -169,14 +175,18 @@ template <bool seq_ascii> Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> source, Zone* zone) { isolate_ = source->map()->GetHeap()->isolate(); + factory_ = isolate_->factory(); + object_constructor_ = Handle<JSFunction>( + isolate()->native_context()->object_function(), isolate()); zone_ = zone; FlattenString(source); source_ = source; source_length_ = source_->length(); + pretenure_ = (source_length_ >= kPretenureTreshold) ? TENURED : NOT_TENURED; // Optimized fast case where we only have ASCII characters. if (seq_ascii) { - seq_source_ = Handle<SeqAsciiString>::cast(source_); + seq_source_ = Handle<SeqOneByteString>::cast(source_); } // Set initial position right before the string. @@ -185,10 +195,12 @@ Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> source, AdvanceSkipWhitespace(); Handle<Object> result = ParseJsonValue(); if (result.is_null() || c0_ != kEndOfString) { - // Parse failed. Current character is the unexpected token. + // Some exception (for example stack overflow) is already pending. + if (isolate_->has_pending_exception()) return Handle<Object>::null(); + // Parse failed. Current character is the unexpected token. const char* message; - Factory* factory = isolate()->factory(); + Factory* factory = this->factory(); Handle<JSArray> array; switch (c0_) { @@ -237,87 +249,118 @@ Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> source, // Parse any JSON value. template <bool seq_ascii> Handle<Object> JsonParser<seq_ascii>::ParseJsonValue() { - switch (c0_) { - case '"': - return ParseJsonString(); - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return ParseJsonNumber(); - case 'f': - if (AdvanceGetChar() == 'a' && AdvanceGetChar() == 'l' && - AdvanceGetChar() == 's' && AdvanceGetChar() == 'e') { - AdvanceSkipWhitespace(); - return isolate()->factory()->false_value(); - } else { - return ReportUnexpectedCharacter(); - } - case 't': - if (AdvanceGetChar() == 'r' && AdvanceGetChar() == 'u' && - AdvanceGetChar() == 'e') { - AdvanceSkipWhitespace(); - return isolate()->factory()->true_value(); - } else { - return ReportUnexpectedCharacter(); - } - case 'n': - if (AdvanceGetChar() == 'u' && AdvanceGetChar() == 'l' && - AdvanceGetChar() == 'l') { - AdvanceSkipWhitespace(); - return isolate()->factory()->null_value(); - } else { - return ReportUnexpectedCharacter(); - } - case '{': - return ParseJsonObject(); - case '[': - return ParseJsonArray(); - default: - return ReportUnexpectedCharacter(); + StackLimitCheck stack_check(isolate_); + if (stack_check.HasOverflowed()) { + isolate_->StackOverflow(); + return Handle<Object>::null(); + } + + if (c0_ == '"') return ParseJsonString(); + if ((c0_ >= '0' && c0_ <= '9') || c0_ == '-') return ParseJsonNumber(); + if (c0_ == '{') return ParseJsonObject(); + if (c0_ == '[') return ParseJsonArray(); + if (c0_ == 'f') { + if (AdvanceGetChar() == 'a' && AdvanceGetChar() == 'l' && + AdvanceGetChar() == 's' && AdvanceGetChar() == 'e') { + AdvanceSkipWhitespace(); + return factory()->false_value(); + } + return ReportUnexpectedCharacter(); + } + if (c0_ == 't') { + if (AdvanceGetChar() == 'r' && AdvanceGetChar() == 'u' && + AdvanceGetChar() == 'e') { + AdvanceSkipWhitespace(); + return factory()->true_value(); + } + return ReportUnexpectedCharacter(); + } + if (c0_ == 'n') { + if (AdvanceGetChar() == 'u' && AdvanceGetChar() == 'l' && + AdvanceGetChar() == 'l') { + AdvanceSkipWhitespace(); + return factory()->null_value(); + } + return ReportUnexpectedCharacter(); } + return ReportUnexpectedCharacter(); } // Parse a JSON object. Position must be right at '{'. template <bool seq_ascii> Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() { - Handle<JSFunction> object_constructor( - isolate()->native_context()->object_function()); + Handle<Object> prototype; Handle<JSObject> json_object = - isolate()->factory()->NewJSObject(object_constructor); + factory()->NewJSObject(object_constructor(), pretenure_); ASSERT_EQ(c0_, '{'); AdvanceSkipWhitespace(); if (c0_ != '}') { do { if (c0_ != '"') return ReportUnexpectedCharacter(); + + int start_position = position_; + Advance(); + + uint32_t index = 0; + if (c0_ >= '0' && c0_ <= '9') { + // Maybe an array index, try to parse it. + if (c0_ == '0') { + // With a leading zero, the string has to be "0" only to be an index. + Advance(); + } else { + do { + int d = c0_ - '0'; + if (index > 429496729U - ((d > 5) ? 1 : 0)) break; + index = (index * 10) + d; + Advance(); + } while (c0_ >= '0' && c0_ <= '9'); + } + + if (c0_ == '"') { + // Successfully parsed index, parse and store element. + AdvanceSkipWhitespace(); + + if (c0_ != ':') return ReportUnexpectedCharacter(); + AdvanceSkipWhitespace(); + Handle<Object> value = ParseJsonValue(); + if (value.is_null()) return ReportUnexpectedCharacter(); + + JSObject::SetOwnElement(json_object, index, value, kNonStrictMode); + continue; + } + // Not an index, fallback to the slow path. + } + + position_ = start_position; +#ifdef DEBUG + c0_ = '"'; +#endif + Handle<String> key = ParseJsonSymbol(); if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); + AdvanceSkipWhitespace(); Handle<Object> value = ParseJsonValue(); if (value.is_null()) return ReportUnexpectedCharacter(); - uint32_t index; - if (key->AsArrayIndex(&index)) { - JSObject::SetOwnElement(json_object, index, value, kNonStrictMode); - } else if (key->Equals(isolate()->heap()->Proto_symbol())) { - SetPrototype(json_object, value); + if (key->Equals(isolate()->heap()->Proto_symbol())) { + prototype = value; } else { - JSObject::SetLocalPropertyIgnoreAttributes( - json_object, key, value, NONE); + if (JSObject::TryTransitionToField(json_object, key)) { + int index = json_object->LastAddedFieldIndex(); + json_object->FastPropertyAtPut(index, *value); + } else { + JSObject::SetLocalPropertyIgnoreAttributes( + json_object, key, value, NONE); + } } } while (MatchSkipWhiteSpace(',')); if (c0_ != '}') { return ReportUnexpectedCharacter(); } + if (!prototype.is_null()) SetPrototype(json_object, prototype); } AdvanceSkipWhitespace(); return json_object; @@ -344,11 +387,12 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonArray() { AdvanceSkipWhitespace(); // Allocate a fixed array with all the elements. Handle<FixedArray> fast_elements = - isolate()->factory()->NewFixedArray(elements.length()); + factory()->NewFixedArray(elements.length(), pretenure_); for (int i = 0, n = elements.length(); i < n; i++) { fast_elements->set(i, *elements[i]); } - return isolate()->factory()->NewJSArrayWithElements(fast_elements); + return factory()->NewJSArrayWithElements( + fast_elements, FAST_ELEMENTS, pretenure_); } @@ -415,7 +459,7 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonNumber() { buffer.Dispose(); } SkipWhitespace(); - return isolate()->factory()->NewNumber(number); + return factory()->NewNumber(number, pretenure_); } @@ -428,21 +472,27 @@ inline void SeqStringSet(Handle<SeqTwoByteString> seq_str, int i, uc32 c) { } template <> -inline void SeqStringSet(Handle<SeqAsciiString> seq_str, int i, uc32 c) { - seq_str->SeqAsciiStringSet(i, c); +inline void SeqStringSet(Handle<SeqOneByteString> seq_str, int i, uc32 c) { + seq_str->SeqOneByteStringSet(i, c); } template <typename StringType> -inline Handle<StringType> NewRawString(Factory* factory, int length); +inline Handle<StringType> NewRawString(Factory* factory, + int length, + PretenureFlag pretenure); template <> -inline Handle<SeqTwoByteString> NewRawString(Factory* factory, int length) { - return factory->NewRawTwoByteString(length, NOT_TENURED); +inline Handle<SeqTwoByteString> NewRawString(Factory* factory, + int length, + PretenureFlag pretenure) { + return factory->NewRawTwoByteString(length, pretenure); } template <> -inline Handle<SeqAsciiString> NewRawString(Factory* factory, int length) { - return factory->NewRawAsciiString(length, NOT_TENURED); +inline Handle<SeqOneByteString> NewRawString(Factory* factory, + int length, + PretenureFlag pretenure) { + return factory->NewRawOneByteString(length, pretenure); } @@ -456,8 +506,8 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( int count = end - start; int max_length = count + source_length_ - position_; int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count)); - Handle<StringType> seq_str = NewRawString<StringType>(isolate()->factory(), - length); + Handle<StringType> seq_str = + NewRawString<StringType>(factory(), length, pretenure_); // Copy prefix into seq_str. SinkChar* dest = seq_str->GetChars(); String::WriteToFlat(*prefix, dest, start, end); @@ -480,7 +530,7 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( SeqStringSet(seq_str, count++, c0_); Advance(); } else { - // StringType is SeqAsciiString and we just read a non-ASCII char. + // StringType is SeqOneByteString and we just read a non-ASCII char. return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str, 0, count); } } else { @@ -520,7 +570,7 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString( SeqStringSet(seq_str, count++, value); break; } else { - // StringType is SeqAsciiString and we just read a non-ASCII char. + // StringType is SeqOneByteString and we just read a non-ASCII char. position_ -= 6; // Rewind position_ to \ in \uxxxx. Advance(); return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str, @@ -561,8 +611,58 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() { Advance(); if (c0_ == '"') { AdvanceSkipWhitespace(); - return Handle<String>(isolate()->heap()->empty_string()); + return factory()->empty_string(); + } + + if (seq_ascii && is_symbol) { + // Fast path for existing symbols. If the the string being parsed is not + // a known symbol, contains backslashes or unexpectedly reaches the end of + // string, return with an empty handle. + uint32_t running_hash = isolate()->heap()->HashSeed(); + int position = position_; + uc32 c0 = c0_; + do { + if (c0 == '\\') { + c0_ = c0; + int beg_pos = position_; + position_ = position; + return SlowScanJsonString<SeqOneByteString, char>(source_, + beg_pos, + position_); + } + if (c0 < 0x20) return Handle<String>::null(); + running_hash = StringHasher::AddCharacterCore(running_hash, c0); + position++; + if (position >= source_length_) return Handle<String>::null(); + c0 = seq_source_->SeqOneByteStringGet(position); + } while (c0 != '"'); + int length = position - position_; + uint32_t hash = (length <= String::kMaxHashCalcLength) + ? StringHasher::GetHashCore(running_hash) : length; + Vector<const char> string_vector( + seq_source_->GetChars() + position_, length); + SymbolTable* symbol_table = isolate()->heap()->symbol_table(); + uint32_t capacity = symbol_table->Capacity(); + uint32_t entry = SymbolTable::FirstProbe(hash, capacity); + uint32_t count = 1; + while (true) { + Object* element = symbol_table->KeyAt(entry); + if (element == isolate()->heap()->undefined_value()) { + // Lookup failure. + break; + } + if (element != isolate()->heap()->the_hole_value() && + String::cast(element)->IsAsciiEqualTo(string_vector)) { + // Lookup success, update the current position. + position_ = position; + // Advance past the last '"'. + AdvanceSkipWhitespace(); + return Handle<String>(String::cast(element), isolate()); + } + entry = SymbolTable::NextProbe(entry, count++, capacity); + } } + int beg_pos = position_; // Fast case for ASCII only without escape characters. do { @@ -577,7 +677,7 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() { position_); } } else { - return SlowScanJsonString<SeqAsciiString, char>(source_, + return SlowScanJsonString<SeqOneByteString, char>(source_, beg_pos, position_); } @@ -585,12 +685,12 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() { int length = position_ - beg_pos; Handle<String> result; if (seq_ascii && is_symbol) { - result = isolate()->factory()->LookupAsciiSymbol(seq_source_, - beg_pos, - length); + result = factory()->LookupAsciiSymbol(seq_source_, + beg_pos, + length); } else { - result = isolate()->factory()->NewRawAsciiString(length); - char* dest = SeqAsciiString::cast(*result)->GetChars(); + result = factory()->NewRawOneByteString(length, pretenure_); + char* dest = SeqOneByteString::cast(*result)->GetChars(); String::WriteToFlat(*source_, dest, beg_pos, position_); } ASSERT_EQ('"', c0_); diff --git a/deps/v8/src/json-stringifier.h b/deps/v8/src/json-stringifier.h new file mode 100644 index 0000000000..7a8af30eb8 --- /dev/null +++ b/deps/v8/src/json-stringifier.h @@ -0,0 +1,748 @@ +// 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_JSON_STRINGIFIER_H_ +#define V8_JSON_STRINGIFIER_H_ + +#include "v8.h" +#include "v8utils.h" +#include "v8conversions.h" + +namespace v8 { +namespace internal { + +class BasicJsonStringifier BASE_EMBEDDED { + public: + explicit BasicJsonStringifier(Isolate* isolate); + + MaybeObject* Stringify(Handle<Object> object); + + private: + static const int kInitialPartLength = 32; + static const int kMaxPartLength = 16 * 1024; + static const int kPartLengthGrowthFactor = 2; + + enum Result { UNCHANGED, SUCCESS, EXCEPTION, CIRCULAR, STACK_OVERFLOW }; + + void Extend(); + + void ChangeEncoding(); + + void ShrinkCurrentPart(); + + template <bool is_ascii, typename Char> + INLINE(void Append_(Char c)); + + template <bool is_ascii, typename Char> + INLINE(void Append_(const Char* chars)); + + INLINE(void Append(char c)) { + if (is_ascii_) { + Append_<true>(c); + } else { + Append_<false>(c); + } + } + + INLINE(void Append(const char* chars)) { + if (is_ascii_) { + Append_<true>(chars); + } else { + Append_<false>(chars); + } + } + + Handle<Object> ApplyToJsonFunction(Handle<Object> object, + Handle<Object> key); + + Result SerializeGeneric(Handle<Object> object, + Handle<Object> key, + bool deferred_comma, + bool deferred_key); + + // Entry point to serialize the object. + INLINE(Result SerializeObject(Handle<Object> obj)) { + return Serialize_<false>(obj, false, factory_->empty_string()); + } + + // Serialize an array element. + // The index may serve as argument for the toJSON function. + INLINE(Result SerializeElement(Handle<Object> object, int i)) { + return Serialize_<false>(object, false, Handle<Object>(Smi::FromInt(i))); + } + + // Serialize a object property. + // The key may or may not be serialized depending on the property. + // The key may also serve as argument for the toJSON function. + INLINE(Result SerializeProperty(Handle<Object> object, + bool deferred_comma, + Handle<String> deferred_key)) { + ASSERT(!deferred_key.is_null()); + return Serialize_<true>(object, deferred_comma, deferred_key); + } + + template <bool deferred_string_key> + Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key); + + void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) { + if (deferred_comma) Append(','); + SerializeString(Handle<String>::cast(deferred_key)); + Append(':'); + } + + Result SerializeSmi(Smi* object); + + Result SerializeDouble(double number); + INLINE(Result SerializeHeapNumber(Handle<HeapNumber> object)) { + return SerializeDouble(object->value()); + } + + Result SerializeJSValue(Handle<JSValue> object); + + INLINE(Result SerializeJSArray(Handle<JSArray> object)); + INLINE(Result SerializeJSObject(Handle<JSObject> object)); + + Result SerializeJSArraySlow(Handle<JSArray> object, int length); + + void SerializeString(Handle<String> object); + + template <typename SrcChar, typename DestChar> + INLINE(void SerializeStringUnchecked_(const SrcChar* src, + DestChar* dest, + int length)); + + template <bool is_ascii, typename Char> + INLINE(void SerializeString_(Handle<String> string)); + + template <typename Char> + INLINE(bool DoNotEscape(Char c)); + + template <typename Char> + INLINE(Vector<const Char> GetCharVector(Handle<String> string)); + + Result StackPush(Handle<Object> object); + void StackPop(); + + INLINE(Handle<String> accumulator()) { + return Handle<String>(String::cast(accumulator_store_->value()), isolate_); + } + + INLINE(void set_accumulator(Handle<String> string)) { + return accumulator_store_->set_value(*string); + } + + Isolate* isolate_; + Factory* factory_; + // We use a value wrapper for the string accumulator to keep the + // (indirect) handle to it in the outermost handle scope. + Handle<JSValue> accumulator_store_; + Handle<String> current_part_; + Handle<String> tojson_symbol_; + Handle<JSArray> stack_; + int current_index_; + int part_length_; + bool is_ascii_; + + static const int kJsonEscapeTableEntrySize = 8; + static const char* const JsonEscapeTable; +}; + + +// Translation table to escape ASCII characters. +// Table entries start at a multiple of 8 and are null-terminated. +const char* const BasicJsonStringifier::JsonEscapeTable = + "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " + "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 " + "\\b\0 \\t\0 \\n\0 \\u000b\0 " + "\\f\0 \\r\0 \\u000e\0 \\u000f\0 " + "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 " + "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 " + "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 " + "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 " + " \0 !\0 \\\"\0 #\0 " + "$\0 %\0 &\0 '\0 " + "(\0 )\0 *\0 +\0 " + ",\0 -\0 .\0 /\0 " + "0\0 1\0 2\0 3\0 " + "4\0 5\0 6\0 7\0 " + "8\0 9\0 :\0 ;\0 " + "<\0 =\0 >\0 ?\0 " + "@\0 A\0 B\0 C\0 " + "D\0 E\0 F\0 G\0 " + "H\0 I\0 J\0 K\0 " + "L\0 M\0 N\0 O\0 " + "P\0 Q\0 R\0 S\0 " + "T\0 U\0 V\0 W\0 " + "X\0 Y\0 Z\0 [\0 " + "\\\\\0 ]\0 ^\0 _\0 " + "`\0 a\0 b\0 c\0 " + "d\0 e\0 f\0 g\0 " + "h\0 i\0 j\0 k\0 " + "l\0 m\0 n\0 o\0 " + "p\0 q\0 r\0 s\0 " + "t\0 u\0 v\0 w\0 " + "x\0 y\0 z\0 {\0 " + "|\0 }\0 ~\0 \177\0 "; + + +BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) + : isolate_(isolate), current_index_(0), is_ascii_(true) { + factory_ = isolate_->factory(); + accumulator_store_ = Handle<JSValue>::cast( + factory_->ToObject(factory_->empty_string())); + part_length_ = kInitialPartLength; + current_part_ = factory_->NewRawOneByteString(kInitialPartLength); + tojson_symbol_ = factory_->LookupAsciiSymbol("toJSON"); + stack_ = factory_->NewJSArray(8); +} + + +MaybeObject* BasicJsonStringifier::Stringify(Handle<Object> object) { + switch (SerializeObject(object)) { + case UNCHANGED: + return isolate_->heap()->undefined_value(); + case SUCCESS: + ShrinkCurrentPart(); + return *factory_->NewConsString(accumulator(), current_part_); + case CIRCULAR: + return isolate_->Throw(*factory_->NewTypeError( + "circular_structure", HandleVector<Object>(NULL, 0))); + case STACK_OVERFLOW: + return isolate_->StackOverflow(); + default: + return Failure::Exception(); + } +} + + +template <bool is_ascii, typename Char> +void BasicJsonStringifier::Append_(Char c) { + if (is_ascii) { + SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet( + current_index_++, c); + } else { + SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet( + current_index_++, c); + } + if (current_index_ == part_length_) Extend(); +} + + +template <bool is_ascii, typename Char> +void BasicJsonStringifier::Append_(const Char* chars) { + for ( ; *chars != '\0'; chars++) Append_<is_ascii, Char>(*chars); +} + + +Handle<Object> BasicJsonStringifier::ApplyToJsonFunction( + Handle<Object> object, Handle<Object> key) { + LookupResult lookup(isolate_); + JSObject::cast(*object)->LookupRealNamedProperty(*tojson_symbol_, &lookup); + if (!lookup.IsProperty()) return object; + PropertyAttributes attr; + Handle<Object> fun = + Object::GetProperty(object, object, &lookup, tojson_symbol_, &attr); + if (!fun->IsJSFunction()) return object; + + // Call toJSON function. + if (key->IsSmi()) key = factory_->NumberToString(key); + Handle<Object> argv[] = { key }; + bool has_exception = false; + HandleScope scope(isolate_); + object = Execution::Call(fun, object, 1, argv, &has_exception); + // Return empty handle to signal an exception. + if (has_exception) return Handle<Object>::null(); + return scope.CloseAndEscape(object); +} + + +BasicJsonStringifier::Result BasicJsonStringifier::StackPush( + Handle<Object> object) { + StackLimitCheck check(isolate_); + if (check.HasOverflowed()) return STACK_OVERFLOW; + + int length = Smi::cast(stack_->length())->value(); + FixedArray* elements = FixedArray::cast(stack_->elements()); + for (int i = 0; i < length; i++) { + if (elements->get(i) == *object) { + return CIRCULAR; + } + } + stack_->EnsureSize(length + 1); + FixedArray::cast(stack_->elements())->set(length, *object); + stack_->set_length(Smi::FromInt(length + 1)); + return SUCCESS; +} + + +void BasicJsonStringifier::StackPop() { + int length = Smi::cast(stack_->length())->value(); + stack_->set_length(Smi::FromInt(length - 1)); +} + + +template <bool deferred_string_key> +BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( + Handle<Object> object, bool comma, Handle<Object> key) { + if (object->IsJSObject()) { + object = ApplyToJsonFunction(object, key); + if (object.is_null()) return EXCEPTION; + } + + if (object->IsSmi()) { + if (deferred_string_key) SerializeDeferredKey(comma, key); + return SerializeSmi(Smi::cast(*object)); + } + + switch (HeapObject::cast(*object)->map()->instance_type()) { + case HEAP_NUMBER_TYPE: + if (deferred_string_key) SerializeDeferredKey(comma, key); + return SerializeHeapNumber(Handle<HeapNumber>::cast(object)); + case ODDBALL_TYPE: + switch (Oddball::cast(*object)->kind()) { + case Oddball::kFalse: + if (deferred_string_key) SerializeDeferredKey(comma, key); + Append("false"); + return SUCCESS; + case Oddball::kTrue: + if (deferred_string_key) SerializeDeferredKey(comma, key); + Append("true"); + return SUCCESS; + case Oddball::kNull: + if (deferred_string_key) SerializeDeferredKey(comma, key); + Append("null"); + return SUCCESS; + default: + return UNCHANGED; + } + case JS_ARRAY_TYPE: + if (deferred_string_key) SerializeDeferredKey(comma, key); + return SerializeJSArray(Handle<JSArray>::cast(object)); + case JS_VALUE_TYPE: + if (deferred_string_key) SerializeDeferredKey(comma, key); + return SerializeJSValue(Handle<JSValue>::cast(object)); + case JS_FUNCTION_TYPE: + return UNCHANGED; + default: + if (object->IsString()) { + if (deferred_string_key) SerializeDeferredKey(comma, key); + SerializeString(Handle<String>::cast(object)); + return SUCCESS; + } else if (object->IsJSObject()) { + if (deferred_string_key) SerializeDeferredKey(comma, key); + return SerializeJSObject(Handle<JSObject>::cast(object)); + } else { + return SerializeGeneric(object, key, comma, deferred_string_key); + } + } +} + + +BasicJsonStringifier::Result BasicJsonStringifier::SerializeGeneric( + Handle<Object> object, + Handle<Object> key, + bool deferred_comma, + bool deferred_key) { + Handle<JSObject> builtins(isolate_->native_context()->builtins()); + Handle<JSFunction> builtin = + Handle<JSFunction>::cast(GetProperty(builtins, "JSONSerializeAdapter")); + + Handle<Object> argv[] = { key, object }; + bool has_exception = false; + Handle<Object> result = + Execution::Call(builtin, object, 2, argv, &has_exception); + if (has_exception) return EXCEPTION; + if (result->IsUndefined()) return UNCHANGED; + if (deferred_key) { + if (key->IsSmi()) key = factory_->NumberToString(key); + SerializeDeferredKey(deferred_comma, key); + } + + Handle<String> result_string = Handle<String>::cast(result); + // Shrink current part, attach it to the accumulator, also attach the result + // string to the accumulator, and allocate a new part. + ShrinkCurrentPart(); // Shrink. + part_length_ = kInitialPartLength; // Allocate conservatively. + Extend(); // Attach current part and allocate new part. + // Attach result string to the accumulator. + set_accumulator(factory_->NewConsString(accumulator(), result_string)); + return SUCCESS; +} + + +BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue( + Handle<JSValue> object) { + bool has_exception = false; + String* class_name = object->class_name(); + if (class_name == isolate_->heap()->String_symbol()) { + Handle<Object> value = Execution::ToString(object, &has_exception); + if (has_exception) return EXCEPTION; + SerializeString(Handle<String>::cast(value)); + } else if (class_name == isolate_->heap()->Number_symbol()) { + Handle<Object> value = Execution::ToNumber(object, &has_exception); + if (has_exception) return EXCEPTION; + if (value->IsSmi()) return SerializeSmi(Smi::cast(*value)); + SerializeHeapNumber(Handle<HeapNumber>::cast(value)); + } else { + ASSERT(class_name == isolate_->heap()->Boolean_symbol()); + Object* value = JSValue::cast(*object)->value(); + ASSERT(value->IsBoolean()); + Append(value->IsTrue() ? "true" : "false"); + } + return SUCCESS; +} + + +BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { + static const int kBufferSize = 100; + char chars[kBufferSize]; + Vector<char> buffer(chars, kBufferSize); + Append(IntToCString(object->value(), buffer)); + return SUCCESS; +} + + +BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble( + double number) { + if (isinf(number) || isnan(number)) { + Append("null"); + return SUCCESS; + } + static const int kBufferSize = 100; + char chars[kBufferSize]; + Vector<char> buffer(chars, kBufferSize); + Append(DoubleToCString(number, buffer)); + return SUCCESS; +} + + +BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( + Handle<JSArray> object) { + HandleScope handle_scope(isolate_); + Result stack_push = StackPush(object); + if (stack_push != SUCCESS) return stack_push; + int length = Smi::cast(object->length())->value(); + Append('['); + switch (object->GetElementsKind()) { + case FAST_SMI_ELEMENTS: { + Handle<FixedArray> elements( + FixedArray::cast(object->elements()), isolate_); + for (int i = 0; i < length; i++) { + if (i > 0) Append(','); + SerializeSmi(Smi::cast(elements->get(i))); + } + break; + } + case FAST_DOUBLE_ELEMENTS: { + Handle<FixedDoubleArray> elements( + FixedDoubleArray::cast(object->elements()), isolate_); + for (int i = 0; i < length; i++) { + if (i > 0) Append(','); + SerializeDouble(elements->get_scalar(i)); + } + break; + } + case FAST_ELEMENTS: { + Handle<FixedArray> elements( + FixedArray::cast(object->elements()), isolate_); + for (int i = 0; i < length; i++) { + if (i > 0) Append(','); + Result result = + SerializeElement(Handle<Object>(elements->get(i), isolate_), i); + if (result == SUCCESS) continue; + if (result == UNCHANGED) { + Append("null"); + } else { + return result; + } + } + break; + } + // TODO(yangguo): The FAST_HOLEY_* cases could be handled in a faster way. + // They resemble the non-holey cases except that a prototype chain lookup + // is necessary for holes. + default: { + Result result = SerializeJSArraySlow(object, length); + if (result != SUCCESS) return result; + break; + } + } + Append(']'); + StackPop(); + current_part_ = handle_scope.CloseAndEscape(current_part_); + return SUCCESS; +} + + +BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow( + Handle<JSArray> object, int length) { + for (int i = 0; i < length; i++) { + if (i > 0) Append(','); + Handle<Object> element = Object::GetElement(object, i); + if (element->IsUndefined()) { + Append("null"); + } else { + Result result = SerializeElement(element, i); + if (result == SUCCESS) continue; + if (result == UNCHANGED) { + Append("null"); + } else { + return result; + } + } + } + return SUCCESS; +} + + +BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( + Handle<JSObject> object) { + HandleScope handle_scope(isolate_); + Result stack_push = StackPush(object); + if (stack_push != SUCCESS) return stack_push; + if (object->IsJSGlobalProxy()) { + object = Handle<JSObject>( + JSObject::cast(object->GetPrototype()), isolate_); + ASSERT(object->IsGlobalObject()); + } + + Append('{'); + bool comma = false; + + if (object->HasFastProperties() && + !object->HasIndexedInterceptor() && + !object->HasNamedInterceptor() && + object->elements()->length() == 0) { + Handle<Map> map(object->map()); + for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { + Handle<String> key(map->instance_descriptors()->GetKey(i), isolate_); + PropertyDetails details = map->instance_descriptors()->GetDetails(i); + if (details.IsDontEnum() || details.IsDeleted()) continue; + Handle<Object> property; + if (details.type() == FIELD && *map == object->map()) { + property = Handle<Object>( + object->FastPropertyAt( + map->instance_descriptors()->GetFieldIndex(i)), + isolate_); + } else { + property = GetProperty(object, key); + if (property.is_null()) return EXCEPTION; + } + Result result = SerializeProperty(property, comma, key); + if (!comma && result == SUCCESS) comma = true; + if (result >= EXCEPTION) return result; + } + } else { + bool has_exception = false; + Handle<FixedArray> contents = + GetKeysInFixedArrayFor(object, LOCAL_ONLY, &has_exception); + if (has_exception) return EXCEPTION; + + for (int i = 0; i < contents->length(); i++) { + Object* key = contents->get(i); + Handle<String> key_handle; + Handle<Object> property; + if (key->IsString()) { + key_handle = Handle<String>(String::cast(key), isolate_); + property = GetProperty(object, key_handle); + } else { + ASSERT(key->IsNumber()); + key_handle = factory_->NumberToString(Handle<Object>(key, isolate_)); + uint32_t index; + if (key->IsSmi()) { + property = Object::GetElement(object, Smi::cast(key)->value()); + } else if (key_handle->AsArrayIndex(&index)) { + property = Object::GetElement(object, index); + } else { + property = GetProperty(object, key_handle); + } + } + if (property.is_null()) return EXCEPTION; + Result result = SerializeProperty(property, comma, key_handle); + if (!comma && result == SUCCESS) comma = true; + if (result >= EXCEPTION) return result; + } + } + + Append('}'); + StackPop(); + current_part_ = handle_scope.CloseAndEscape(current_part_); + return SUCCESS; +} + + +void BasicJsonStringifier::ShrinkCurrentPart() { + ASSERT(current_index_ < part_length_); + current_part_ = Handle<String>( + SeqString::cast(*current_part_)->Truncate(current_index_), isolate_); +} + + +void BasicJsonStringifier::Extend() { + set_accumulator(factory_->NewConsString(accumulator(), current_part_)); + if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) { + part_length_ *= kPartLengthGrowthFactor; + } + if (is_ascii_) { + current_part_ = factory_->NewRawOneByteString(part_length_); + } else { + current_part_ = factory_->NewRawTwoByteString(part_length_); + } + current_index_ = 0; +} + + +void BasicJsonStringifier::ChangeEncoding() { + ShrinkCurrentPart(); + set_accumulator(factory_->NewConsString(accumulator(), current_part_)); + current_part_ = factory_->NewRawTwoByteString(part_length_); + current_index_ = 0; + is_ascii_ = false; +} + + +template <typename SrcChar, typename DestChar> +void BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src, + DestChar* dest, + int length) { + dest += current_index_; + DestChar* dest_start = dest; + + // Assert that uc16 character is not truncated down to 8 bit. + // The <uc16, char> version of this method must not be called. + ASSERT(sizeof(*dest) >= sizeof(*src)); + + for (int i = 0; i < length; i++) { + SrcChar c = src[i]; + if (DoNotEscape(c)) { + *(dest++) = static_cast<DestChar>(c); + } else { + const char* chars = &JsonEscapeTable[c * kJsonEscapeTableEntrySize]; + while (*chars != '\0') *(dest++) = *(chars++); + } + } + + current_index_ += static_cast<int>(dest - dest_start); +} + + +template <bool is_ascii, typename Char> +void BasicJsonStringifier::SerializeString_(Handle<String> string) { + int length = string->length(); + Append_<is_ascii, char>('"'); + // We make a rough estimate to find out if the current string can be + // serialized without allocating a new string part. The worst case length of + // an escaped character is 6. Shifting the remainin string length right by 3 + // is a more pessimistic estimate, but faster to calculate. + + if (((part_length_ - current_index_) >> 3) > length) { + AssertNoAllocation no_allocation; + Vector<const Char> vector = GetCharVector<Char>(string); + if (is_ascii) { + SerializeStringUnchecked_( + vector.start(), + SeqOneByteString::cast(*current_part_)->GetChars(), + length); + } else { + SerializeStringUnchecked_( + vector.start(), + SeqTwoByteString::cast(*current_part_)->GetChars(), + length); + } + } else { + String* string_location = *string; + Vector<const Char> vector = GetCharVector<Char>(string); + for (int i = 0; i < length; i++) { + Char c = vector[i]; + if (DoNotEscape(c)) { + Append_<is_ascii, Char>(c); + } else { + Append_<is_ascii, char>( + &JsonEscapeTable[c * kJsonEscapeTableEntrySize]); + } + // If GC moved the string, we need to refresh the vector. + if (*string != string_location) { + vector = GetCharVector<Char>(string); + string_location = *string; + } + } + } + + Append_<is_ascii, char>('"'); +} + + +template <> +bool BasicJsonStringifier::DoNotEscape(char c) { + return c >= '#' && c <= '~' && c != '\\'; +} + + +template <> +bool BasicJsonStringifier::DoNotEscape(uc16 c) { + return (c >= 0x80) || (c >= '#' && c <= '~' && c != '\\'); +} + + +template <> +Vector<const char> BasicJsonStringifier::GetCharVector(Handle<String> string) { + String::FlatContent flat = string->GetFlatContent(); + ASSERT(flat.IsAscii()); + return flat.ToAsciiVector(); +} + + +template <> +Vector<const uc16> BasicJsonStringifier::GetCharVector(Handle<String> string) { + String::FlatContent flat = string->GetFlatContent(); + ASSERT(flat.IsTwoByte()); + return flat.ToUC16Vector(); +} + + +void BasicJsonStringifier::SerializeString(Handle<String> object) { + FlattenString(object); + String::FlatContent flat = object->GetFlatContent(); + if (is_ascii_) { + if (flat.IsAscii()) { + SerializeString_<true, char>(object); + } else { + ChangeEncoding(); + SerializeString(object); + } + } else { + if (flat.IsAscii()) { + SerializeString_<false, char>(object); + } else { + SerializeString_<false, uc16>(object); + } + } +} + +} } // namespace v8::internal + +#endif // V8_JSON_STRINGIFIER_H_ diff --git a/deps/v8/src/json.js b/deps/v8/src/json.js index 85224b0f05..9ab1a31e59 100644 --- a/deps/v8/src/json.js +++ b/deps/v8/src/json.js @@ -178,141 +178,9 @@ function JSONSerialize(key, holder, replacer, stack, indent, gap) { } -function BasicSerializeArray(value, stack, builder) { - var len = value.length; - if (len == 0) { - builder.push("[]"); - return; - } - if (!%PushIfAbsent(stack, value)) { - throw MakeTypeError('circular_structure', $Array()); - } - builder.push("["); - var val = value[0]; - if (IS_STRING(val)) { - // First entry is a string. Remaining entries are likely to be strings too. - var array_string = %QuoteJSONStringArray(value); - if (!IS_UNDEFINED(array_string)) { - // array_string also includes bracket characters so we are done. - builder[builder.length - 1] = array_string; - stack.pop(); - return; - } else { - builder.push(%QuoteJSONString(val)); - for (var i = 1; i < len; i++) { - val = value[i]; - if (IS_STRING(val)) { - builder.push(%QuoteJSONStringComma(val)); - } else { - builder.push(","); - var before = builder.length; - BasicJSONSerialize(i, val, stack, builder); - if (before == builder.length) builder[before - 1] = ",null"; - } - } - } - } else if (IS_NUMBER(val)) { - // First entry is a number. Remaining entries are likely to be numbers too. - builder.push(JSON_NUMBER_TO_STRING(val)); - for (var i = 1; i < len; i++) { - builder.push(","); - val = value[i]; - if (IS_NUMBER(val)) { - builder.push(JSON_NUMBER_TO_STRING(val)); - } else { - var before = builder.length; - BasicJSONSerialize(i, val, stack, builder); - if (before == builder.length) builder[before - 1] = ",null"; - } - } - } else { - var before = builder.length; - BasicJSONSerialize(0, val, stack, builder); - if (before == builder.length) builder.push("null"); - for (var i = 1; i < len; i++) { - builder.push(","); - before = builder.length; - BasicJSONSerialize(i, value[i], stack, builder); - if (before == builder.length) builder[before - 1] = ",null"; - } - } - stack.pop(); - builder.push("]"); -} - - -function BasicSerializeObject(value, stack, builder) { - if (!%PushIfAbsent(stack, value)) { - throw MakeTypeError('circular_structure', $Array()); - } - builder.push("{"); - var first = true; - var keys = %ObjectKeys(value); - var len = keys.length; - for (var i = 0; i < len; i++) { - var p = keys[i]; - if (!first) { - builder.push(%QuoteJSONStringComma(p)); - } else { - builder.push(%QuoteJSONString(p)); - } - builder.push(":"); - var before = builder.length; - BasicJSONSerialize(p, value[p], stack, builder); - if (before == builder.length) { - builder.pop(); - builder.pop(); - } else { - first = false; - } - } - stack.pop(); - builder.push("}"); -} - - -function BasicJSONSerialize(key, value, stack, builder) { - if (IS_SPEC_OBJECT(value)) { - var toJSON = value.toJSON; - if (IS_SPEC_FUNCTION(toJSON)) { - value = %_CallFunction(value, ToString(key), toJSON); - } - } - if (IS_STRING(value)) { - builder.push(value !== "" ? %QuoteJSONString(value) : '""'); - } else if (IS_NUMBER(value)) { - builder.push(JSON_NUMBER_TO_STRING(value)); - } else if (IS_BOOLEAN(value)) { - builder.push(value ? "true" : "false"); - } else if (IS_NULL(value)) { - builder.push("null"); - } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) { - // Value is a non-callable object. - // Unwrap value if necessary - if (IS_NUMBER_WRAPPER(value)) { - value = ToNumber(value); - builder.push(JSON_NUMBER_TO_STRING(value)); - } else if (IS_STRING_WRAPPER(value)) { - builder.push(%QuoteJSONString(ToString(value))); - } else if (IS_BOOLEAN_WRAPPER(value)) { - builder.push(%_ValueOf(value) ? "true" : "false"); - } else if (IS_ARRAY(value)) { - BasicSerializeArray(value, stack, builder); - } else { - BasicSerializeObject(value, stack, builder); - } - } -} - - function JSONStringify(value, replacer, space) { if (%_ArgumentsLength() == 1) { - var builder = new InternalArray(); - BasicJSONSerialize('', value, new InternalArray(), builder); - if (builder.length == 0) return; - var result = %_FastAsciiArrayJoin(builder, ""); - if (!IS_UNDEFINED(result)) return result; - return %StringBuilderConcat(builder, builder.length, ""); + return %BasicJSONStringify(value); } if (IS_OBJECT(space)) { // Unwrap 'space' if it is wrapped @@ -338,6 +206,7 @@ function JSONStringify(value, replacer, space) { return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap); } + function SetUpJSON() { %CheckIsBootstrapping(); InstallFunctions($JSON, DONT_ENUM, $Array( @@ -346,4 +215,12 @@ function SetUpJSON() { )); } + +function JSONSerializeAdapter(key, object) { + var holder = {}; + holder[key] = object; + // No need to pass the actual holder since there is no replacer function. + return JSONSerialize(key, holder, void 0, new InternalArray(), "", ""); +} + SetUpJSON(); diff --git a/deps/v8/src/jsregexp.cc b/deps/v8/src/jsregexp.cc index e59170d5a3..813208c959 100644 --- a/deps/v8/src/jsregexp.cc +++ b/deps/v8/src/jsregexp.cc @@ -529,7 +529,7 @@ int RegExpImpl::IrregexpPrepare(Handle<JSRegExp> regexp, if (!subject->IsFlat()) FlattenString(subject); // Check the asciiness of the underlying storage. - bool is_ascii = subject->IsAsciiRepresentationUnderneath(); + bool is_ascii = subject->IsOneByteRepresentationUnderneath(); if (!EnsureCompiledIrregexp(regexp, subject, is_ascii)) return -1; #ifdef V8_INTERPRETED_REGEXP @@ -560,7 +560,7 @@ int RegExpImpl::IrregexpExecRaw(Handle<JSRegExp> regexp, ASSERT(index <= subject->length()); ASSERT(subject->IsFlat()); - bool is_ascii = subject->IsAsciiRepresentationUnderneath(); + bool is_ascii = subject->IsOneByteRepresentationUnderneath(); #ifndef V8_INTERPRETED_REGEXP ASSERT(output_size >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2); @@ -596,7 +596,7 @@ int RegExpImpl::IrregexpExecRaw(Handle<JSRegExp> regexp, // being internal and external, and even between being ASCII and UC16, // but the characters are always the same). IrregexpPrepare(regexp, subject); - is_ascii = subject->IsAsciiRepresentationUnderneath(); + is_ascii = subject->IsOneByteRepresentationUnderneath(); } while (true); UNREACHABLE(); return RE_EXCEPTION; diff --git a/deps/v8/src/lithium.h b/deps/v8/src/lithium.h index 923a1594c9..089926e71a 100644 --- a/deps/v8/src/lithium.h +++ b/deps/v8/src/lithium.h @@ -133,13 +133,15 @@ class LUnallocated: public LOperand { // index in the upper bits. static const int kPolicyWidth = 3; static const int kLifetimeWidth = 1; - static const int kVirtualRegisterWidth = 18; + static const int kVirtualRegisterWidth = 15; static const int kPolicyShift = kKindFieldWidth; static const int kLifetimeShift = kPolicyShift + kPolicyWidth; static const int kVirtualRegisterShift = kLifetimeShift + kLifetimeWidth; static const int kFixedIndexShift = kVirtualRegisterShift + kVirtualRegisterWidth; + static const int kFixedIndexWidth = 32 - kFixedIndexShift; + STATIC_ASSERT(kFixedIndexWidth > 5); class PolicyField : public BitField<Policy, kPolicyShift, kPolicyWidth> { }; @@ -154,8 +156,8 @@ class LUnallocated: public LOperand { }; static const int kMaxVirtualRegisters = 1 << kVirtualRegisterWidth; - static const int kMaxFixedIndex = 63; - static const int kMinFixedIndex = -64; + static const int kMaxFixedIndex = (1 << (kFixedIndexWidth - 1)) - 1; + static const int kMinFixedIndex = -(1 << (kFixedIndexWidth - 1)); bool HasAnyPolicy() const { return policy() == ANY; @@ -460,6 +462,7 @@ class LEnvironment: public ZoneObject { int argument_count, int value_count, LEnvironment* outer, + HEnterInlined* entry, Zone* zone) : closure_(closure), frame_type_(frame_type), @@ -475,6 +478,7 @@ class LEnvironment: public ZoneObject { spilled_registers_(NULL), spilled_double_registers_(NULL), outer_(outer), + entry_(entry), zone_(zone) { } Handle<JSFunction> closure() const { return closure_; } @@ -491,6 +495,7 @@ class LEnvironment: public ZoneObject { } const ZoneList<LOperand*>* values() const { return &values_; } LEnvironment* outer() const { return outer_; } + HEnterInlined* entry() { return entry_; } void AddValue(LOperand* operand, Representation representation, @@ -556,6 +561,7 @@ class LEnvironment: public ZoneObject { LOperand** spilled_double_registers_; LEnvironment* outer_; + HEnterInlined* entry_; Zone* zone_; }; diff --git a/deps/v8/src/liveedit-debugger.js b/deps/v8/src/liveedit-debugger.js index cfcdb818c9..451b146bde 100644 --- a/deps/v8/src/liveedit-debugger.js +++ b/deps/v8/src/liveedit-debugger.js @@ -76,7 +76,17 @@ Debug.LiveEdit = new function() { try { new_compile_info = GatherCompileInfo(new_source, script); } catch (e) { - throw new Failure("Failed to compile new version of script: " + e); + var failure = + new Failure("Failed to compile new version of script: " + e); + if (e instanceof SyntaxError) { + var details = { + type: "liveedit_compile_error", + syntaxErrorMessage: e.message + }; + CopyErrorPositionToDetails(e, details); + failure.details = details; + } + throw failure; } var root_new_node = BuildCodeInfoTree(new_compile_info); @@ -978,6 +988,31 @@ Debug.LiveEdit = new function() { return "LiveEdit Failure: " + this.message; }; + function CopyErrorPositionToDetails(e, details) { + function createPositionStruct(script, position) { + if (position == -1) return; + var location = script.locationFromPosition(position, true); + if (location == null) return; + return { + line: location.line + 1, + column: location.column + 1, + position: position + }; + } + + if (!("scriptObject" in e) || !("startPosition" in e)) { + return; + } + + var script = e.scriptObject; + + var position_struct = { + start: createPositionStruct(script, e.startPosition), + end: createPositionStruct(script, e.endPosition) + }; + details.position = position_struct; + } + // A testing entry. function GetPcFromSourcePos(func, source_pos) { return %GetFunctionCodePositionFromSource(func, source_pos); diff --git a/deps/v8/src/liveedit.cc b/deps/v8/src/liveedit.cc index f35315438d..f491e37204 100644 --- a/deps/v8/src/liveedit.cc +++ b/deps/v8/src/liveedit.cc @@ -36,6 +36,7 @@ #include "debug.h" #include "deoptimizer.h" #include "global-handles.h" +#include "messages.h" #include "parser.h" #include "scopeinfo.h" #include "scopes.h" @@ -635,6 +636,21 @@ static Handle<JSValue> WrapInJSValue(Handle<Object> object) { } +static Handle<SharedFunctionInfo> UnwrapSharedFunctionInfoFromJSValue( + Handle<JSValue> jsValue) { + Object* shared = jsValue->value(); + CHECK(shared->IsSharedFunctionInfo()); + return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(shared)); +} + + +static int GetArrayLength(Handle<JSArray> array) { + Object* length = array->length(); + CHECK(length->IsSmi()); + return Smi::cast(length)->value(); +} + + // Simple helper class that creates more or less typed structures over // JSArray object. This is an adhoc method of passing structures from C++ // to JavaScript. @@ -688,12 +704,14 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> { : JSArrayBasedStruct<FunctionInfoWrapper>(array) { } void SetInitialProperties(Handle<String> name, int start_position, - int end_position, int param_num, int parent_index) { + int end_position, int param_num, + int literal_count, int parent_index) { HandleScope scope; this->SetField(kFunctionNameOffset_, name); this->SetSmiValueField(kStartPositionOffset_, start_position); this->SetSmiValueField(kEndPositionOffset_, end_position); this->SetSmiValueField(kParamNumOffset_, param_num); + this->SetSmiValueField(kLiteralNumOffset_, literal_count); this->SetSmiValueField(kParentIndexOffset_, parent_index); } void SetFunctionCode(Handle<Code> function_code, @@ -711,6 +729,9 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> { Handle<JSValue> info_holder = WrapInJSValue(info); this->SetField(kSharedFunctionInfoOffset_, info_holder); } + int GetLiteralCount() { + return this->GetSmiValueField(kLiteralNumOffset_); + } int GetParentIndex() { return this->GetSmiValueField(kParentIndexOffset_); } @@ -744,7 +765,8 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> { static const int kOuterScopeInfoOffset_ = 6; static const int kParentIndexOffset_ = 7; static const int kSharedFunctionInfoOffset_ = 8; - static const int kSize_ = 9; + static const int kLiteralNumOffset_ = 9; + static const int kSize_ = 10; friend class JSArrayBasedStruct<FunctionInfoWrapper>; }; @@ -777,9 +799,7 @@ class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> { Object* element = this->GetField(kSharedInfoOffset_); CHECK(element->IsJSValue()); Handle<JSValue> value_wrapper(JSValue::cast(element)); - Handle<Object> raw_result = UnwrapJSValue(value_wrapper); - CHECK(raw_result->IsSharedFunctionInfo()); - return Handle<SharedFunctionInfo>::cast(raw_result); + return UnwrapSharedFunctionInfoFromJSValue(value_wrapper); } private: @@ -806,6 +826,7 @@ class FunctionInfoListener { FunctionInfoWrapper info = FunctionInfoWrapper::Create(); info.SetInitialProperties(fun->name(), fun->start_position(), fun->end_position(), fun->parameter_count(), + fun->materialized_literal_count(), current_parent_index_); current_parent_index_ = len_; SetElementNonStrict(result_, len_, info.GetJSArray()); @@ -905,17 +926,65 @@ JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script, Handle<Object> original_source = Handle<Object>(script->source()); script->set_source(*source); isolate->set_active_function_info_listener(&listener); - CompileScriptForTracker(isolate, script); + + { + // Creating verbose TryCatch from public API is currently the only way to + // force code save location. We do not use this the object directly. + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + + // A logical 'try' section. + CompileScriptForTracker(isolate, script); + } + + // A logical 'catch' section. + Handle<JSObject> rethrow_exception; + if (isolate->has_pending_exception()) { + Handle<Object> exception(isolate->pending_exception()->ToObjectChecked()); + MessageLocation message_location = isolate->GetMessageLocation(); + + isolate->clear_pending_message(); + isolate->clear_pending_exception(); + + // If possible, copy positions from message object to exception object. + if (exception->IsJSObject() && !message_location.script().is_null()) { + rethrow_exception = Handle<JSObject>::cast(exception); + + Factory* factory = isolate->factory(); + Handle<String> start_pos_key = + factory->LookupAsciiSymbol("startPosition"); + Handle<String> end_pos_key = + factory->LookupAsciiSymbol("endPosition"); + Handle<String> script_obj_key = + factory->LookupAsciiSymbol("scriptObject"); + Handle<Smi> start_pos(Smi::FromInt(message_location.start_pos())); + Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos())); + Handle<JSValue> script_obj = GetScriptWrapper(message_location.script()); + JSReceiver::SetProperty( + rethrow_exception, start_pos_key, start_pos, NONE, kNonStrictMode); + JSReceiver::SetProperty( + rethrow_exception, end_pos_key, end_pos, NONE, kNonStrictMode); + JSReceiver::SetProperty( + rethrow_exception, script_obj_key, script_obj, NONE, kNonStrictMode); + } + } + + // A logical 'finally' section. isolate->set_active_function_info_listener(NULL); script->set_source(*original_source); - return *(listener.GetResult()); + if (rethrow_exception.is_null()) { + return *(listener.GetResult()); + } else { + isolate->Throw(*rethrow_exception); + return 0; + } } void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) { HandleScope scope; - int len = Smi::cast(array->length())->value(); + int len = GetArrayLength(array); for (int i = 0; i < len; i++) { Handle<SharedFunctionInfo> info( SharedFunctionInfo::cast(array->GetElementNoExceptionThrown(i))); @@ -1001,6 +1070,129 @@ static void ReplaceCodeObject(Handle<Code> original, } +// Patch function literals. +// Name 'literals' is a misnomer. Rather it's a cache for complex object +// boilerplates and for a native context. We must clean cached values. +// Additionally we may need to allocate a new array if number of literals +// changed. +class LiteralFixer { + public: + static void PatchLiterals(FunctionInfoWrapper* compile_info_wrapper, + Handle<SharedFunctionInfo> shared_info, + Isolate* isolate) { + int new_literal_count = compile_info_wrapper->GetLiteralCount(); + if (new_literal_count > 0) { + new_literal_count += JSFunction::kLiteralsPrefixSize; + } + int old_literal_count = shared_info->num_literals(); + + if (old_literal_count == new_literal_count) { + // If literal count didn't change, simply go over all functions + // and clear literal arrays. + ClearValuesVisitor visitor; + IterateJSFunctions(*shared_info, &visitor); + } else { + // When literal count changes, we have to create new array instances. + // Since we cannot create instances when iterating heap, we should first + // collect all functions and fix their literal arrays. + Handle<FixedArray> function_instances = + CollectJSFunctions(shared_info, isolate); + for (int i = 0; i < function_instances->length(); i++) { + Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i))); + Handle<FixedArray> old_literals(fun->literals()); + Handle<FixedArray> new_literals = + isolate->factory()->NewFixedArray(new_literal_count); + if (new_literal_count > 0) { + Handle<Context> native_context; + if (old_literals->length() > + JSFunction::kLiteralNativeContextIndex) { + native_context = Handle<Context>( + JSFunction::NativeContextFromLiterals(fun->literals())); + } else { + native_context = Handle<Context>(fun->context()->native_context()); + } + new_literals->set(JSFunction::kLiteralNativeContextIndex, + *native_context); + } + fun->set_literals(*new_literals); + } + + shared_info->set_num_literals(new_literal_count); + } + } + + private: + // Iterates all function instances in the HEAP that refers to the + // provided shared_info. + template<typename Visitor> + static void IterateJSFunctions(SharedFunctionInfo* shared_info, + Visitor* visitor) { + AssertNoAllocation no_allocations_please; + + HeapIterator iterator; + for (HeapObject* obj = iterator.next(); obj != NULL; + obj = iterator.next()) { + if (obj->IsJSFunction()) { + JSFunction* function = JSFunction::cast(obj); + if (function->shared() == shared_info) { + visitor->visit(function); + } + } + } + } + + // Finds all instances of JSFunction that refers to the provided shared_info + // and returns array with them. + static Handle<FixedArray> CollectJSFunctions( + Handle<SharedFunctionInfo> shared_info, Isolate* isolate) { + CountVisitor count_visitor; + count_visitor.count = 0; + IterateJSFunctions(*shared_info, &count_visitor); + int size = count_visitor.count; + + Handle<FixedArray> result = isolate->factory()->NewFixedArray(size); + if (size > 0) { + CollectVisitor collect_visitor(result); + IterateJSFunctions(*shared_info, &collect_visitor); + } + return result; + } + + class ClearValuesVisitor { + public: + void visit(JSFunction* fun) { + FixedArray* literals = fun->literals(); + int len = literals->length(); + for (int j = JSFunction::kLiteralsPrefixSize; j < len; j++) { + literals->set_undefined(j); + } + } + }; + + class CountVisitor { + public: + void visit(JSFunction* fun) { + count++; + } + int count; + }; + + class CollectVisitor { + public: + explicit CollectVisitor(Handle<FixedArray> output) + : m_output(output), m_pos(0) {} + + void visit(JSFunction* fun) { + m_output->set(m_pos, fun); + m_pos++; + } + private: + Handle<FixedArray> m_output; + int m_pos; + }; +}; + + // Check whether the code is natural function code (not a lazy-compile stub // code). static bool IsJSFunctionCode(Code* code) { @@ -1067,9 +1259,10 @@ MaybeObject* LiveEdit::ReplaceFunctionCode( Handle<JSArray> new_compile_info_array, Handle<JSArray> shared_info_array) { HandleScope scope; + Isolate* isolate = Isolate::Current(); if (!SharedInfoWrapper::IsInstance(shared_info_array)) { - return Isolate::Current()->ThrowIllegalOperation(); + return isolate->ThrowIllegalOperation(); } FunctionInfoWrapper compile_info_wrapper(new_compile_info_array); @@ -1100,6 +1293,8 @@ MaybeObject* LiveEdit::ReplaceFunctionCode( shared_info->set_start_position(start_position); shared_info->set_end_position(end_position); + LiteralFixer::PatchLiterals(&compile_info_wrapper, shared_info, isolate); + shared_info->set_construct_stub( Isolate::Current()->builtins()->builtin( Builtins::kJSConstructStubGeneric)); @@ -1132,7 +1327,7 @@ MaybeObject* LiveEdit::FunctionSourceUpdated( void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper, Handle<Object> script_handle) { Handle<SharedFunctionInfo> shared_info = - Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper)); + UnwrapSharedFunctionInfoFromJSValue(function_wrapper); CHECK(script_handle->IsScript() || script_handle->IsUndefined()); shared_info->set_script(*script_handle); @@ -1152,19 +1347,22 @@ void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper, static int TranslatePosition(int original_position, Handle<JSArray> position_change_array) { int position_diff = 0; - int array_len = Smi::cast(position_change_array->length())->value(); + int array_len = GetArrayLength(position_change_array); // TODO(635): binary search may be used here for (int i = 0; i < array_len; i += 3) { Object* element = position_change_array->GetElementNoExceptionThrown(i); + CHECK(element->IsSmi()); int chunk_start = Smi::cast(element)->value(); if (original_position < chunk_start) { break; } element = position_change_array->GetElementNoExceptionThrown(i + 1); + CHECK(element->IsSmi()); int chunk_end = Smi::cast(element)->value(); // Position mustn't be inside a chunk. ASSERT(original_position >= chunk_end); element = position_change_array->GetElementNoExceptionThrown(i + 2); + CHECK(element->IsSmi()); int chunk_changed_end = Smi::cast(element)->value(); position_diff = chunk_changed_end - chunk_end; } @@ -1271,7 +1469,9 @@ static Handle<Code> PatchPositionsInCode( continue; } } - buffer_writer.Write(it.rinfo()); + if (RelocInfo::IsRealRelocMode(rinfo->rmode())) { + buffer_writer.Write(it.rinfo()); + } } } @@ -1293,7 +1493,6 @@ static Handle<Code> PatchPositionsInCode( MaybeObject* LiveEdit::PatchFunctionPositions( Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) { - if (!SharedInfoWrapper::IsInstance(shared_info_array)) { return Isolate::Current()->ThrowIllegalOperation(); } @@ -1383,11 +1582,11 @@ void LiveEdit::ReplaceRefToNestedFunction( Handle<JSValue> subst_function_wrapper) { Handle<SharedFunctionInfo> parent_shared = - Handle<SharedFunctionInfo>::cast(UnwrapJSValue(parent_function_wrapper)); + UnwrapSharedFunctionInfoFromJSValue(parent_function_wrapper); Handle<SharedFunctionInfo> orig_shared = - Handle<SharedFunctionInfo>::cast(UnwrapJSValue(orig_function_wrapper)); + UnwrapSharedFunctionInfoFromJSValue(orig_function_wrapper); Handle<SharedFunctionInfo> subst_shared = - Handle<SharedFunctionInfo>::cast(UnwrapJSValue(subst_function_wrapper)); + UnwrapSharedFunctionInfoFromJSValue(subst_function_wrapper); for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) { if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) { @@ -1410,12 +1609,13 @@ static bool CheckActivation(Handle<JSArray> shared_info_array, Handle<JSFunction> function( JSFunction::cast(JavaScriptFrame::cast(frame)->function())); - int len = Smi::cast(shared_info_array->length())->value(); + int len = GetArrayLength(shared_info_array); for (int i = 0; i < len; i++) { - JSValue* wrapper = - JSValue::cast(shared_info_array->GetElementNoExceptionThrown(i)); - Handle<SharedFunctionInfo> shared( - SharedFunctionInfo::cast(wrapper->value())); + Object* element = shared_info_array->GetElementNoExceptionThrown(i); + CHECK(element->IsJSValue()); + Handle<JSValue> jsvalue(JSValue::cast(element)); + Handle<SharedFunctionInfo> shared = + UnwrapSharedFunctionInfoFromJSValue(jsvalue); if (function->shared() == *shared || IsInlined(*function, *shared)) { SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status))); @@ -1723,7 +1923,7 @@ static const char* DropActivationsInActiveThread( return message; } - int array_len = Smi::cast(shared_info_array->length())->value(); + int array_len = GetArrayLength(shared_info_array); // Replace "blocked on active" with "replaced on active" status. for (int i = 0; i < array_len; i++) { @@ -1765,7 +1965,7 @@ class InactiveThreadActivationsChecker : public ThreadVisitor { Handle<JSArray> LiveEdit::CheckAndDropActivations( Handle<JSArray> shared_info_array, bool do_drop, Zone* zone) { - int len = Smi::cast(shared_info_array->length())->value(); + int len = GetArrayLength(shared_info_array); Handle<JSArray> result = FACTORY->NewJSArray(len); diff --git a/deps/v8/src/liveobjectlist.cc b/deps/v8/src/liveobjectlist.cc index 6b89cf6839..6dbe0a86e7 100644 --- a/deps/v8/src/liveobjectlist.cc +++ b/deps/v8/src/liveobjectlist.cc @@ -71,7 +71,7 @@ typedef int (*RawComparer)(const void*, const void*); v(ExternalAsciiString, "unexpected: ExternalAsciiString") \ v(ExternalString, "unexpected: ExternalString") \ v(SeqTwoByteString, "unexpected: SeqTwoByteString") \ - v(SeqAsciiString, "unexpected: SeqAsciiString") \ + v(SeqOneByteString, "unexpected: SeqOneByteString") \ v(SeqString, "unexpected: SeqString") \ v(JSFunctionResultCache, "unexpected: JSFunctionResultCache") \ v(NativeContext, "unexpected: NativeContext") \ diff --git a/deps/v8/src/log-utils.cc b/deps/v8/src/log-utils.cc index 7bd7baa2d8..d8d92cbe21 100644 --- a/deps/v8/src/log-utils.cc +++ b/deps/v8/src/log-utils.cc @@ -67,6 +67,7 @@ void Log::Initialize() { FLAG_log_suspect = true; FLAG_log_handles = true; FLAG_log_regexp = true; + FLAG_log_internal_timer_events = true; } // --prof implies --log-code. @@ -80,7 +81,8 @@ void Log::Initialize() { bool open_log_file = FLAG_log || FLAG_log_runtime || FLAG_log_api || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect - || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof; + || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof + || FLAG_log_internal_timer_events; // If we're logging anything, we need to open the log file. if (open_log_file) { @@ -257,7 +259,7 @@ void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) { if (len > 0x1000) len = 0x1000; if (show_impl_info) { - Append(str->IsAsciiRepresentation() ? 'a' : '2'); + Append(str->IsOneByteRepresentation() ? 'a' : '2'); if (StringShape(str).IsExternal()) Append('e'); if (StringShape(str).IsSymbol()) diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc index b049ffe4eb..d0dc76d4b8 100644 --- a/deps/v8/src/log.cc +++ b/deps/v8/src/log.cc @@ -44,37 +44,6 @@ namespace v8 { namespace internal { -// -// Sliding state window. Updates counters to keep track of the last -// window of kBufferSize states. This is useful to track where we -// spent our time. -// -class SlidingStateWindow { - public: - explicit SlidingStateWindow(Isolate* isolate); - ~SlidingStateWindow(); - void AddState(StateTag state); - - private: - static const int kBufferSize = 256; - Counters* counters_; - int current_index_; - bool is_full_; - byte buffer_[kBufferSize]; - - - void IncrementStateCounter(StateTag state) { - counters_->state_counters(state)->Increment(); - } - - - void DecrementStateCounter(StateTag state) { - counters_->state_counters(state)->Decrement(); - } -}; - - -// // The Profiler samples pc and sp values for the main thread. // Each sample is appended to a circular buffer. // An independent thread removes data and writes it to the log. @@ -189,24 +158,12 @@ class Ticker: public Sampler { public: Ticker(Isolate* isolate, int interval): Sampler(isolate, interval), - window_(NULL), profiler_(NULL) {} ~Ticker() { if (IsActive()) Stop(); } virtual void Tick(TickSample* sample) { if (profiler_) profiler_->Insert(sample); - if (window_) window_->AddState(sample->state); - } - - void SetWindow(SlidingStateWindow* window) { - window_ = window; - if (!IsActive()) Start(); - } - - void ClearWindow() { - window_ = NULL; - if (!profiler_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop(); } void SetProfiler(Profiler* profiler) { @@ -219,7 +176,7 @@ class Ticker: public Sampler { void ClearProfiler() { DecreaseProfilingDepth(); profiler_ = NULL; - if (!window_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop(); + if (IsActive()) Stop(); } protected: @@ -228,42 +185,11 @@ class Ticker: public Sampler { } private: - SlidingStateWindow* window_; Profiler* profiler_; }; // -// SlidingStateWindow implementation. -// -SlidingStateWindow::SlidingStateWindow(Isolate* isolate) - : counters_(isolate->counters()), current_index_(0), is_full_(false) { - for (int i = 0; i < kBufferSize; i++) { - buffer_[i] = static_cast<byte>(OTHER); - } - isolate->logger()->ticker_->SetWindow(this); -} - - -SlidingStateWindow::~SlidingStateWindow() { - LOGGER->ticker_->ClearWindow(); -} - - -void SlidingStateWindow::AddState(StateTag state) { - if (is_full_) { - DecrementStateCounter(static_cast<StateTag>(buffer_[current_index_])); - } else if (current_index_ == kBufferSize - 1) { - is_full_ = true; - } - buffer_[current_index_] = static_cast<byte>(state); - IncrementStateCounter(state); - ASSERT(IsPowerOf2(kBufferSize)); - current_index_ = (current_index_ + 1) & (kBufferSize - 1); -} - - -// // Profiler implementation. // Profiler::Profiler(Isolate* isolate) @@ -518,7 +444,6 @@ class Logger::NameBuffer { Logger::Logger() : ticker_(NULL), profiler_(NULL), - sliding_state_window_(NULL), log_events_(NULL), logging_nesting_(0), cpu_profiler_nesting_(0), @@ -531,7 +456,8 @@ Logger::Logger() prev_sp_(NULL), prev_function_(NULL), prev_to_(NULL), - prev_code_(NULL) { + prev_code_(NULL), + epoch_(0) { } @@ -704,6 +630,58 @@ void Logger::SharedLibraryEvent(const wchar_t* library_path, } +void Logger::TimerEvent(const char* name, int64_t start, int64_t end) { + if (!log_->IsEnabled()) return; + ASSERT(FLAG_log_internal_timer_events); + LogMessageBuilder msg(this); + int since_epoch = static_cast<int>(start - epoch_); + int pause_time = static_cast<int>(end - start); + msg.Append("timer-event,\"%s\",%ld,%ld\n", name, since_epoch, pause_time); + msg.WriteToLogFile(); +} + + +void Logger::ExternalSwitch(StateTag old_tag, StateTag new_tag) { + if (old_tag != EXTERNAL && new_tag == EXTERNAL) { + enter_external_ = OS::Ticks(); + } + if (old_tag == EXTERNAL && new_tag != EXTERNAL && enter_external_ != 0) { + TimerEvent("V8.External", enter_external_, OS::Ticks()); + enter_external_ = 0; + } +} + + +void Logger::EnterExternal() { + LOGGER->enter_external_ = OS::Ticks(); +} + + +void Logger::LeaveExternal() { + if (enter_external_ == 0) return; + Logger* logger = LOGGER; + logger->TimerEvent("V8.External", enter_external_, OS::Ticks()); + logger->enter_external_ = 0; +} + + +int64_t Logger::enter_external_ = 0; + + +void Logger::TimerEventScope::LogTimerEvent() { + LOG(isolate_, TimerEvent(name_, start_, OS::Ticks())); +} + + +const char* Logger::TimerEventScope::v8_recompile_synchronous = + "V8.RecompileSynchronous"; +const char* Logger::TimerEventScope::v8_recompile_parallel = + "V8.RecompileParallel"; +const char* Logger::TimerEventScope::v8_compile_full_code = + "V8.CompileFullCode"; +const char* Logger::TimerEventScope::v8_execute = "V8.Execute"; + + void Logger::LogRegExpSource(Handle<JSRegExp> regexp) { // Prints "/" + re.source + "/" + // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"") @@ -874,7 +852,7 @@ void Logger::CallbackEventInternal(const char* prefix, const char* name, Address entry_point) { if (!log_->IsEnabled() || !FLAG_log_code) return; LogMessageBuilder msg(this); - msg.Append("%s,%s,", + msg.Append("%s,%s,-3,", kLogEventsNames[CODE_CREATION_EVENT], kLogEventsNames[CALLBACK_TAG]); msg.AppendAddress(entry_point); @@ -930,9 +908,10 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, } if (!FLAG_log_code) return; LogMessageBuilder msg(this); - msg.Append("%s,%s,", + msg.Append("%s,%s,%d,", kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[tag]); + kLogEventsNames[tag], + code->kind()); msg.AppendAddress(code->address()); msg.Append(",%d,\"", code->ExecutableSize()); for (const char* p = comment; *p != '\0'; p++) { @@ -969,9 +948,10 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, } if (!FLAG_log_code) return; LogMessageBuilder msg(this); - msg.Append("%s,%s,", + msg.Append("%s,%s,%d,", kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[tag]); + kLogEventsNames[tag], + code->kind()); msg.AppendAddress(code->address()); msg.Append(",%d,\"", code->ExecutableSize()); msg.AppendDetailed(name, false); @@ -1021,9 +1001,10 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, LogMessageBuilder msg(this); SmartArrayPointer<char> str = name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); - msg.Append("%s,%s,", + msg.Append("%s,%s,%d,", kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[tag]); + kLogEventsNames[tag], + code->kind()); msg.AppendAddress(code->address()); msg.Append(",%d,\"%s\",", code->ExecutableSize(), *str); msg.AppendAddress(shared->address()); @@ -1068,9 +1049,10 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); SmartArrayPointer<char> sourcestr = source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); - msg.Append("%s,%s,", + msg.Append("%s,%s,%d,", kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[tag]); + kLogEventsNames[tag], + code->kind()); msg.AppendAddress(code->address()); msg.Append(",%d,\"%s %s:%d\",", code->ExecutableSize(), @@ -1104,9 +1086,10 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) { } if (!FLAG_log_code) return; LogMessageBuilder msg(this); - msg.Append("%s,%s,", + msg.Append("%s,%s,%d,", kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[tag]); + kLogEventsNames[tag], + code->kind()); msg.AppendAddress(code->address()); msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count); msg.Append('\n'); @@ -1141,7 +1124,7 @@ void Logger::RegExpCodeCreateEvent(Code* code, String* source) { } if (!FLAG_log_code) return; LogMessageBuilder msg(this); - msg.Append("%s,%s,", + msg.Append("%s,%s,-2,", kLogEventsNames[CODE_CREATION_EVENT], kLogEventsNames[REG_EXP_TAG]); msg.AppendAddress(code->address()); @@ -1321,6 +1304,7 @@ void Logger::TickEvent(TickSample* sample, bool overflow) { msg.AppendAddress(sample->pc); msg.Append(','); msg.AppendAddress(sample->sp); + msg.Append(",%ld", static_cast<int>(OS::Ticks() - epoch_)); if (sample->has_external_callback) { msg.Append(",1,"); msg.AppendAddress(sample->external_callback); @@ -1353,9 +1337,7 @@ void Logger::PauseProfiler() { if (--cpu_profiler_nesting_ == 0) { profiler_->pause(); if (FLAG_prof_lazy) { - if (!FLAG_sliding_state_window && !RuntimeProfiler::IsEnabled()) { - ticker_->Stop(); - } + ticker_->Stop(); FLAG_log_code = false; LOG(ISOLATE, UncheckedStringEvent("profiler", "pause")); } @@ -1376,9 +1358,7 @@ void Logger::ResumeProfiler() { FLAG_log_code = true; LogCompiledFunctions(); LogAccessorCallbacks(); - if (!FLAG_sliding_state_window && !ticker_->IsActive()) { - ticker_->Start(); - } + if (!ticker_->IsActive()) ticker_->Start(); } profiler_->resume(); } @@ -1721,13 +1701,10 @@ bool Logger::SetUp() { Isolate* isolate = Isolate::Current(); ticker_ = new Ticker(isolate, kSamplingIntervalMs); - if (FLAG_sliding_state_window && sliding_state_window_ == NULL) { - sliding_state_window_ = new SlidingStateWindow(isolate); - } - bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect - || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof; + || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof + || FLAG_log_internal_timer_events; if (start_logging) { logging_nesting_ = 1; @@ -1745,6 +1722,8 @@ bool Logger::SetUp() { } } + if (FLAG_log_internal_timer_events || FLAG_prof) epoch_ = OS::Ticks(); + return true; } @@ -1788,9 +1767,6 @@ FILE* Logger::TearDown() { profiler_ = NULL; } - delete sliding_state_window_; - sliding_state_window_ = NULL; - delete ticker_; ticker_ = NULL; @@ -1798,22 +1774,6 @@ FILE* Logger::TearDown() { } -void Logger::EnableSlidingStateWindow() { - // If the ticker is NULL, Logger::SetUp has not been called yet. In - // that case, we set the sliding_state_window flag so that the - // sliding window computation will be started when Logger::SetUp is - // called. - if (ticker_ == NULL) { - FLAG_sliding_state_window = true; - return; - } - // Otherwise, if the sliding state window computation has not been - // started we do it now. - if (sliding_state_window_ == NULL) { - sliding_state_window_ = new SlidingStateWindow(Isolate::Current()); - } -} - // Protects the state below. static Mutex* active_samplers_mutex = NULL; diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h index 33f359a7f9..eced6050a5 100644 --- a/deps/v8/src/log.h +++ b/deps/v8/src/log.h @@ -74,8 +74,8 @@ namespace internal { class LogMessageBuilder; class Profiler; class Semaphore; -class SlidingStateWindow; class Ticker; +class Isolate; #undef LOG #define LOG(isolate, Call) \ @@ -174,9 +174,6 @@ class Logger { // leaving the file open. FILE* TearDown(); - // Enable the computation of a sliding window of states. - void EnableSlidingStateWindow(); - // Emits an event with a string value -> (name, value). void StringEvent(const char* name, const char* value); @@ -275,6 +272,37 @@ class Logger { uintptr_t start, uintptr_t end); + // ==== Events logged by --log-timer-events. ==== + void TimerEvent(const char* name, int64_t start, int64_t end); + void ExternalSwitch(StateTag old_tag, StateTag new_tag); + + static void EnterExternal(); + static void LeaveExternal(); + + class TimerEventScope { + public: + TimerEventScope(Isolate* isolate, const char* name) + : isolate_(isolate), name_(name), start_(0) { + if (FLAG_log_internal_timer_events) start_ = OS::Ticks(); + } + + ~TimerEventScope() { + if (FLAG_log_internal_timer_events) LogTimerEvent(); + } + + void LogTimerEvent(); + + static const char* v8_recompile_synchronous; + static const char* v8_recompile_parallel; + static const char* v8_compile_full_code; + static const char* v8_execute; + + private: + Isolate* isolate_; + const char* name_; + int64_t start_; + }; + // ==== Events logged by --log-regexp ==== // Regexp compilation and execution events. @@ -401,10 +429,6 @@ class Logger { // of samples. Profiler* profiler_; - // SlidingStateWindow instance keeping a sliding window of the most - // recent VM states. - SlidingStateWindow* sliding_state_window_; - // An array of log events names. const char* const* log_events_; @@ -415,7 +439,6 @@ class Logger { friend class LogMessageBuilder; friend class TimeLog; friend class Profiler; - friend class SlidingStateWindow; friend class StackTracer; friend class VMState; @@ -449,6 +472,9 @@ class Logger { // Logger::FunctionCreateEvent(...) Address prev_code_; + int64_t epoch_; + static int64_t enter_external_; + friend class CpuProfiler; }; diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py index 08fa82e686..f871fc55c7 100644 --- a/deps/v8/src/macros.py +++ b/deps/v8/src/macros.py @@ -32,6 +32,8 @@ const NONE = 0; const READ_ONLY = 1; const DONT_ENUM = 2; const DONT_DELETE = 4; +const NEW_ONE_BYTE_STRING = true; +const NEW_TWO_BYTE_STRING = false; # Constants used for getter and setter operations. const GETTER = 0; diff --git a/deps/v8/src/mark-compact-inl.h b/deps/v8/src/mark-compact-inl.h index 2f7e31fea5..10773e7202 100644 --- a/deps/v8/src/mark-compact-inl.h +++ b/deps/v8/src/mark-compact-inl.h @@ -52,32 +52,15 @@ void MarkCompactCollector::SetFlags(int flags) { } -bool MarkCompactCollector::MarkObjectAndPush(HeapObject* obj) { - if (MarkObjectWithoutPush(obj)) { - marking_deque_.PushBlack(obj); - return true; - } - return false; -} - - void MarkCompactCollector::MarkObject(HeapObject* obj, MarkBit mark_bit) { ASSERT(Marking::MarkBitFrom(obj) == mark_bit); if (!mark_bit.Get()) { mark_bit.Set(); MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); - ProcessNewlyMarkedObject(obj); - } -} - - -bool MarkCompactCollector::MarkObjectWithoutPush(HeapObject* obj) { - MarkBit mark_bit = Marking::MarkBitFrom(obj); - if (!mark_bit.Get()) { - SetMark(obj, mark_bit); - return true; + ASSERT(IsMarked(obj)); + ASSERT(HEAP->Contains(obj)); + marking_deque_.PushBlack(obj); } - return false; } @@ -86,9 +69,6 @@ void MarkCompactCollector::SetMark(HeapObject* obj, MarkBit mark_bit) { ASSERT(Marking::MarkBitFrom(obj) == mark_bit); mark_bit.Set(); MemoryChunk::IncrementLiveBytesFromGC(obj->address(), obj->Size()); - if (obj->IsMap()) { - heap_->ClearCacheOnMap(Map::cast(obj)); - } } diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc index dcce8daddf..8ca14db506 100644 --- a/deps/v8/src/mark-compact.cc +++ b/deps/v8/src/mark-compact.cc @@ -62,24 +62,24 @@ MarkCompactCollector::MarkCompactCollector() : // NOLINT sweep_precisely_(false), reduce_memory_footprint_(false), abort_incremental_marking_(false), + marking_parity_(ODD_MARKING_PARITY), compacting_(false), was_marked_incrementally_(false), tracer_(NULL), migration_slots_buffer_(NULL), heap_(NULL), code_flusher_(NULL), - encountered_weak_maps_(NULL), - marker_(this, this) { } + encountered_weak_maps_(NULL) { } -#ifdef DEBUG +#ifdef VERIFY_HEAP class VerifyMarkingVisitor: public ObjectVisitor { public: void VisitPointers(Object** start, Object** end) { for (Object** current = start; current < end; current++) { if ((*current)->IsHeapObject()) { HeapObject* object = HeapObject::cast(*current); - ASSERT(HEAP->mark_compact_collector()->IsMarked(object)); + CHECK(HEAP->mark_compact_collector()->IsMarked(object)); } } } @@ -96,7 +96,7 @@ static void VerifyMarking(Address bottom, Address top) { current += kPointerSize) { object = HeapObject::FromAddress(current); if (MarkCompactCollector::IsMarked(object)) { - ASSERT(current >= next_object_must_be_here_or_later); + CHECK(current >= next_object_must_be_here_or_later); object->Iterate(&visitor); next_object_must_be_here_or_later = current + object->Size(); } @@ -109,12 +109,12 @@ static void VerifyMarking(NewSpace* space) { NewSpacePageIterator it(space->bottom(), end); // The bottom position is at the start of its page. Allows us to use // page->area_start() as start of range on all pages. - ASSERT_EQ(space->bottom(), + CHECK_EQ(space->bottom(), NewSpacePage::FromAddress(space->bottom())->area_start()); while (it.has_next()) { NewSpacePage* page = it.next(); Address limit = it.has_next() ? page->area_end() : end; - ASSERT(limit == end || !page->Contains(end)); + CHECK(limit == end || !page->Contains(end)); VerifyMarking(page->area_start(), limit); } } @@ -174,7 +174,7 @@ static void VerifyEvacuation(Address bottom, Address top) { current += kPointerSize) { object = HeapObject::FromAddress(current); if (MarkCompactCollector::IsMarked(object)) { - ASSERT(current >= next_object_must_be_here_or_later); + CHECK(current >= next_object_must_be_here_or_later); object->Iterate(&visitor); next_object_must_be_here_or_later = current + object->Size(); } @@ -190,7 +190,7 @@ static void VerifyEvacuation(NewSpace* space) { NewSpacePage* page = it.next(); Address current = page->area_start(); Address limit = it.has_next() ? page->area_end() : space->top(); - ASSERT(limit == space->top() || !page->Contains(space->top())); + CHECK(limit == space->top() || !page->Contains(space->top())); while (current < limit) { HeapObject* object = HeapObject::FromAddress(current); object->Iterate(&visitor); @@ -222,8 +222,10 @@ static void VerifyEvacuation(Heap* heap) { VerifyEvacuationVisitor visitor; heap->IterateStrongRoots(&visitor, VISIT_ALL); } +#endif // VERIFY_HEAP +#ifdef DEBUG class VerifyNativeContextSeparationVisitor: public ObjectVisitor { public: VerifyNativeContextSeparationVisitor() : current_native_context_(NULL) {} @@ -348,7 +350,9 @@ bool MarkCompactCollector::StartCompaction(CompactionMode mode) { CollectEvacuationCandidates(heap()->old_pointer_space()); CollectEvacuationCandidates(heap()->old_data_space()); - if (FLAG_compact_code_space && mode == NON_INCREMENTAL_COMPACTION) { + if (FLAG_compact_code_space && + (mode == NON_INCREMENTAL_COMPACTION || + FLAG_incremental_code_compaction)) { CollectEvacuationCandidates(heap()->code_space()); } else if (FLAG_trace_fragmentation) { TraceFragmentation(heap()->code_space()); @@ -383,7 +387,7 @@ void MarkCompactCollector::CollectGarbage() { ClearWeakMaps(); -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { VerifyMarking(heap_); } @@ -401,11 +405,18 @@ void MarkCompactCollector::CollectGarbage() { Finish(); + if (marking_parity_ == EVEN_MARKING_PARITY) { + marking_parity_ = ODD_MARKING_PARITY; + } else { + ASSERT(marking_parity_ == ODD_MARKING_PARITY); + marking_parity_ = EVEN_MARKING_PARITY; + } + tracer_ = NULL; } -#ifdef DEBUG +#ifdef VERIFY_HEAP void MarkCompactCollector::VerifyMarkbitsAreClean(PagedSpace* space) { PageIterator it(space); @@ -416,6 +427,7 @@ void MarkCompactCollector::VerifyMarkbitsAreClean(PagedSpace* space) { } } + void MarkCompactCollector::VerifyMarkbitsAreClean(NewSpace* space) { NewSpacePageIterator it(space->bottom(), space->top()); @@ -426,6 +438,7 @@ void MarkCompactCollector::VerifyMarkbitsAreClean(NewSpace* space) { } } + void MarkCompactCollector::VerifyMarkbitsAreClean() { VerifyMarkbitsAreClean(heap_->old_pointer_space()); VerifyMarkbitsAreClean(heap_->old_data_space()); @@ -437,11 +450,11 @@ void MarkCompactCollector::VerifyMarkbitsAreClean() { LargeObjectIterator it(heap_->lo_space()); 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()); + CHECK(Marking::IsWhite(mark_bit)); + CHECK_EQ(0, Page::FromAddress(obj->address())->LiveBytes()); } } -#endif +#endif // VERIFY_HEAP static void ClearMarkbitsInPagedSpace(PagedSpace* space) { @@ -475,6 +488,7 @@ void MarkCompactCollector::ClearMarkbits() { MarkBit mark_bit = Marking::MarkBitFrom(obj); mark_bit.Clear(); mark_bit.Next().Clear(); + Page::FromAddress(obj->address())->ResetProgressBar(); Page::FromAddress(obj->address())->ResetLiveBytes(); } } @@ -803,7 +817,7 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) { space->PrepareForMarkCompact(); } -#ifdef DEBUG +#ifdef VERIFY_HEAP if (!was_marked_incrementally_ && FLAG_verify_heap) { VerifyMarkbitsAreClean(); } @@ -854,133 +868,144 @@ void MarkCompactCollector::Finish() { // and continue with marking. This process repeats until all reachable // objects have been marked. -class CodeFlusher { - public: - explicit CodeFlusher(Isolate* isolate) - : isolate_(isolate), - jsfunction_candidates_head_(NULL), - shared_function_info_candidates_head_(NULL) {} +void CodeFlusher::ProcessJSFunctionCandidates() { + Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); + Object* undefined = isolate_->heap()->undefined_value(); - void AddCandidate(SharedFunctionInfo* shared_info) { - SetNextCandidate(shared_info, shared_function_info_candidates_head_); - shared_function_info_candidates_head_ = shared_info; - } + JSFunction* candidate = jsfunction_candidates_head_; + JSFunction* next_candidate; + while (candidate != NULL) { + next_candidate = GetNextCandidate(candidate); + ClearNextCandidate(candidate, undefined); - void AddCandidate(JSFunction* function) { - ASSERT(function->code() == function->shared()->code()); + SharedFunctionInfo* shared = candidate->shared(); - SetNextCandidate(function, jsfunction_candidates_head_); - jsfunction_candidates_head_ = function; - } + Code* code = shared->code(); + MarkBit code_mark = Marking::MarkBitFrom(code); + if (!code_mark.Get()) { + shared->set_code(lazy_compile); + candidate->set_code(lazy_compile); + } else if (code == lazy_compile) { + candidate->set_code(lazy_compile); + } - void ProcessCandidates() { - ProcessSharedFunctionInfoCandidates(); - ProcessJSFunctionCandidates(); - } + // We are in the middle of a GC cycle so the write barrier in the code + // setter did not record the slot update and we have to do that manually. + Address slot = candidate->address() + JSFunction::kCodeEntryOffset; + Code* target = Code::cast(Code::GetObjectFromEntryAddress(slot)); + isolate_->heap()->mark_compact_collector()-> + RecordCodeEntrySlot(slot, target); - private: - void ProcessJSFunctionCandidates() { - Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); + Object** shared_code_slot = + HeapObject::RawField(shared, SharedFunctionInfo::kCodeOffset); + isolate_->heap()->mark_compact_collector()-> + RecordSlot(shared_code_slot, shared_code_slot, *shared_code_slot); - JSFunction* candidate = jsfunction_candidates_head_; - JSFunction* next_candidate; - while (candidate != NULL) { - next_candidate = GetNextCandidate(candidate); + candidate = next_candidate; + } - SharedFunctionInfo* shared = candidate->shared(); + jsfunction_candidates_head_ = NULL; +} - Code* code = shared->code(); - MarkBit code_mark = Marking::MarkBitFrom(code); - if (!code_mark.Get()) { - shared->set_code(lazy_compile); - candidate->set_code(lazy_compile); - } else { - candidate->set_code(shared->code()); - } - // We are in the middle of a GC cycle so the write barrier in the code - // setter did not record the slot update and we have to do that manually. - Address slot = candidate->address() + JSFunction::kCodeEntryOffset; - Code* target = Code::cast(Code::GetObjectFromEntryAddress(slot)); - isolate_->heap()->mark_compact_collector()-> - RecordCodeEntrySlot(slot, target); +void CodeFlusher::ProcessSharedFunctionInfoCandidates() { + Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); - RecordSharedFunctionInfoCodeSlot(shared); + SharedFunctionInfo* candidate = shared_function_info_candidates_head_; + SharedFunctionInfo* next_candidate; + while (candidate != NULL) { + next_candidate = GetNextCandidate(candidate); + ClearNextCandidate(candidate); - candidate = next_candidate; + Code* code = candidate->code(); + MarkBit code_mark = Marking::MarkBitFrom(code); + if (!code_mark.Get()) { + candidate->set_code(lazy_compile); } - jsfunction_candidates_head_ = NULL; + Object** code_slot = + HeapObject::RawField(candidate, SharedFunctionInfo::kCodeOffset); + isolate_->heap()->mark_compact_collector()-> + RecordSlot(code_slot, code_slot, *code_slot); + + candidate = next_candidate; } + shared_function_info_candidates_head_ = NULL; +} - void ProcessSharedFunctionInfoCandidates() { - Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); - SharedFunctionInfo* candidate = shared_function_info_candidates_head_; - SharedFunctionInfo* next_candidate; +void CodeFlusher::EvictCandidate(JSFunction* function) { + ASSERT(!function->next_function_link()->IsUndefined()); + Object* undefined = isolate_->heap()->undefined_value(); + + // The function is no longer a candidate, make sure it gets visited + // again so that previous flushing decisions are revisited. + isolate_->heap()->incremental_marking()->RecordWrites(function); + + JSFunction* candidate = jsfunction_candidates_head_; + JSFunction* next_candidate; + if (candidate == function) { + next_candidate = GetNextCandidate(function); + jsfunction_candidates_head_ = next_candidate; + ClearNextCandidate(function, undefined); + } else { while (candidate != NULL) { next_candidate = GetNextCandidate(candidate); - SetNextCandidate(candidate, NULL); - Code* code = candidate->code(); - MarkBit code_mark = Marking::MarkBitFrom(code); - if (!code_mark.Get()) { - candidate->set_code(lazy_compile); + if (next_candidate == function) { + next_candidate = GetNextCandidate(function); + SetNextCandidate(candidate, next_candidate); + ClearNextCandidate(function, undefined); } - RecordSharedFunctionInfoCodeSlot(candidate); - candidate = next_candidate; } - - shared_function_info_candidates_head_ = NULL; } +} - void RecordSharedFunctionInfoCodeSlot(SharedFunctionInfo* shared) { - Object** slot = HeapObject::RawField(shared, - SharedFunctionInfo::kCodeOffset); - isolate_->heap()->mark_compact_collector()-> - RecordSlot(slot, slot, HeapObject::cast(*slot)); - } - static JSFunction** GetNextCandidateField(JSFunction* candidate) { - return reinterpret_cast<JSFunction**>( - candidate->address() + JSFunction::kCodeEntryOffset); - } +void CodeFlusher::EvictJSFunctionCandidates() { + Object* undefined = isolate_->heap()->undefined_value(); - static JSFunction* GetNextCandidate(JSFunction* candidate) { - return *GetNextCandidateField(candidate); + JSFunction* candidate = jsfunction_candidates_head_; + JSFunction* next_candidate; + while (candidate != NULL) { + next_candidate = GetNextCandidate(candidate); + ClearNextCandidate(candidate, undefined); + candidate = next_candidate; } - static void SetNextCandidate(JSFunction* candidate, - JSFunction* next_candidate) { - *GetNextCandidateField(candidate) = next_candidate; - } + jsfunction_candidates_head_ = NULL; +} - static SharedFunctionInfo** GetNextCandidateField( - SharedFunctionInfo* candidate) { - Code* code = candidate->code(); - return reinterpret_cast<SharedFunctionInfo**>( - code->address() + Code::kGCMetadataOffset); - } - static SharedFunctionInfo* GetNextCandidate(SharedFunctionInfo* candidate) { - return reinterpret_cast<SharedFunctionInfo*>( - candidate->code()->gc_metadata()); +void CodeFlusher::EvictSharedFunctionInfoCandidates() { + SharedFunctionInfo* candidate = shared_function_info_candidates_head_; + SharedFunctionInfo* next_candidate; + while (candidate != NULL) { + next_candidate = GetNextCandidate(candidate); + ClearNextCandidate(candidate); + candidate = next_candidate; } - static void SetNextCandidate(SharedFunctionInfo* candidate, - SharedFunctionInfo* next_candidate) { - candidate->code()->set_gc_metadata(next_candidate); - } + shared_function_info_candidates_head_ = NULL; +} - Isolate* isolate_; - JSFunction* jsfunction_candidates_head_; - SharedFunctionInfo* shared_function_info_candidates_head_; - DISALLOW_COPY_AND_ASSIGN(CodeFlusher); -}; +void CodeFlusher::IteratePointersToFromSpace(ObjectVisitor* v) { + Heap* heap = isolate_->heap(); + + JSFunction** slot = &jsfunction_candidates_head_; + JSFunction* candidate = jsfunction_candidates_head_; + while (candidate != NULL) { + if (heap->InFromSpace(candidate)) { + v->VisitPointer(reinterpret_cast<Object**>(slot)); + } + candidate = GetNextCandidate(*slot); + slot = GetNextCandidateSlot(*slot); + } +} MarkCompactCollector::~MarkCompactCollector() { @@ -1063,11 +1088,23 @@ class MarkCompactMarkingVisitor } } + // Marks the object black and pushes it on the marking stack. INLINE(static void MarkObject(Heap* heap, HeapObject* object)) { MarkBit mark = Marking::MarkBitFrom(object); heap->mark_compact_collector()->MarkObject(object, mark); } + // Marks the object black without pushing it on the marking stack. + // Returns true if object needed marking and false otherwise. + INLINE(static bool MarkObjectWithoutPush(Heap* heap, HeapObject* object)) { + MarkBit mark_bit = Marking::MarkBitFrom(object); + if (!mark_bit.Get()) { + heap->mark_compact_collector()->SetMark(object, mark_bit); + return true; + } + return false; + } + // Mark object pointed to by p. INLINE(static void MarkObjectByPointer(MarkCompactCollector* collector, Object** anchor_slot, @@ -1120,6 +1157,11 @@ class MarkCompactMarkingVisitor return true; } + INLINE(static void BeforeVisitingSharedFunctionInfo(HeapObject* object)) { + SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); + shared->BeforeVisitingPointers(); + } + static void VisitJSWeakMap(Map* map, HeapObject* object) { MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector(); JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(object); @@ -1163,123 +1205,8 @@ class MarkCompactMarkingVisitor // Code flushing support. - // How many collections newly compiled code object will survive before being - // flushed. - static const int kCodeAgeThreshold = 5; - static const int kRegExpCodeThreshold = 5; - inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { - Object* undefined = heap->undefined_value(); - return (info->script() != undefined) && - (reinterpret_cast<Script*>(info->script())->source() != undefined); - } - - - inline static bool IsCompiled(JSFunction* function) { - return function->code() != - function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); - } - - inline static bool IsCompiled(SharedFunctionInfo* function) { - return function->code() != - function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); - } - - inline static bool IsFlushable(Heap* heap, JSFunction* function) { - SharedFunctionInfo* shared_info = function->unchecked_shared(); - - // Code is either on stack, in compilation cache or referenced - // by optimized version of function. - MarkBit code_mark = Marking::MarkBitFrom(function->code()); - if (code_mark.Get()) { - if (!Marking::MarkBitFrom(shared_info).Get()) { - shared_info->set_code_age(0); - } - return false; - } - - // We do not flush code for optimized functions. - if (function->code() != shared_info->code()) { - return false; - } - - return IsFlushable(heap, shared_info); - } - - inline static bool IsFlushable(Heap* heap, SharedFunctionInfo* shared_info) { - // Code is either on stack, in compilation cache or referenced - // by optimized version of function. - MarkBit code_mark = - Marking::MarkBitFrom(shared_info->code()); - if (code_mark.Get()) { - return false; - } - - // The function must be compiled and have the source code available, - // to be able to recompile it in case we need the function again. - if (!(shared_info->is_compiled() && HasSourceCode(heap, shared_info))) { - return false; - } - - // We never flush code for Api functions. - Object* function_data = shared_info->function_data(); - if (function_data->IsFunctionTemplateInfo()) { - return false; - } - - // Only flush code for functions. - if (shared_info->code()->kind() != Code::FUNCTION) { - return false; - } - - // Function must be lazy compilable. - if (!shared_info->allows_lazy_compilation()) { - return false; - } - - // If this is a full script wrapped in a function we do no flush the code. - if (shared_info->is_toplevel()) { - return false; - } - - // Age this shared function info. - if (shared_info->code_age() < kCodeAgeThreshold) { - shared_info->set_code_age(shared_info->code_age() + 1); - return false; - } - - return true; - } - - - static bool FlushCodeForFunction(Heap* heap, JSFunction* function) { - if (!IsFlushable(heap, function)) return false; - - // This function's code looks flushable. But we have to postpone the - // decision until we see all functions that point to the same - // SharedFunctionInfo because some of them might be optimized. - // That would make the nonoptimized version of the code nonflushable, - // because it is required for bailing out from optimized code. - heap->mark_compact_collector()->code_flusher()->AddCandidate(function); - return true; - } - - static inline bool IsValidNotBuiltinContext(Object* ctx) { - return ctx->IsContext() && - !Context::cast(ctx)->global_object()->IsJSBuiltinsObject(); - } - - - static void VisitSharedFunctionInfoGeneric(Map* map, HeapObject* object) { - SharedFunctionInfo::cast(object)->BeforeVisitingPointers(); - - FixedBodyVisitor<MarkCompactMarkingVisitor, - SharedFunctionInfo::BodyDescriptor, - void>::Visit(map, object); - } - - static void UpdateRegExpCodeAgeAndFlush(Heap* heap, JSRegExp* re, bool is_ascii) { @@ -1353,138 +1280,6 @@ class MarkCompactMarkingVisitor VisitJSRegExp(map, object); } - - 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); - return; - } - VisitSharedFunctionInfoAndFlushCodeGeneric(map, object, false); - } - - - static void VisitSharedFunctionInfoAndFlushCodeGeneric( - Map* map, HeapObject* object, bool known_flush_code_candidate) { - Heap* heap = map->GetHeap(); - SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); - - shared->BeforeVisitingPointers(); - - if (!known_flush_code_candidate) { - known_flush_code_candidate = IsFlushable(heap, shared); - if (known_flush_code_candidate) { - heap->mark_compact_collector()->code_flusher()->AddCandidate(shared); - } - } - - VisitSharedFunctionInfoFields(heap, object, known_flush_code_candidate); - } - - - static void VisitJSFunctionAndFlushCode(Map* map, HeapObject* object) { - Heap* heap = map->GetHeap(); - MarkCompactCollector* collector = heap->mark_compact_collector(); - if (!collector->is_code_flushing_enabled()) { - VisitJSFunction(map, object); - return; - } - - JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object); - // The function must have a valid context and not be a builtin. - bool flush_code_candidate = false; - if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) { - flush_code_candidate = FlushCodeForFunction(heap, jsfunction); - } - - if (!flush_code_candidate) { - Code* code = jsfunction->shared()->code(); - MarkBit code_mark = Marking::MarkBitFrom(code); - collector->MarkObject(code, code_mark); - - if (jsfunction->code()->kind() == Code::OPTIMIZED_FUNCTION) { - collector->MarkInlinedFunctionsCode(jsfunction->code()); - } - } - - VisitJSFunctionFields(map, - reinterpret_cast<JSFunction*>(object), - flush_code_candidate); - } - - - static void VisitJSFunction(Map* map, HeapObject* object) { - VisitJSFunctionFields(map, - reinterpret_cast<JSFunction*>(object), - false); - } - - - static inline void VisitJSFunctionFields(Map* map, - JSFunction* object, - bool flush_code_candidate) { - Heap* heap = map->GetHeap(); - - VisitPointers(heap, - HeapObject::RawField(object, JSFunction::kPropertiesOffset), - HeapObject::RawField(object, JSFunction::kCodeEntryOffset)); - - if (!flush_code_candidate) { - VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset); - } else { - // Don't visit code object. - - // Visit shared function info to avoid double checking of it's - // flushability. - SharedFunctionInfo* shared_info = object->unchecked_shared(); - MarkBit shared_info_mark = Marking::MarkBitFrom(shared_info); - if (!shared_info_mark.Get()) { - Map* shared_info_map = shared_info->map(); - MarkBit shared_info_map_mark = - Marking::MarkBitFrom(shared_info_map); - heap->mark_compact_collector()->SetMark(shared_info, shared_info_mark); - heap->mark_compact_collector()->MarkObject(shared_info_map, - shared_info_map_mark); - VisitSharedFunctionInfoAndFlushCodeGeneric(shared_info_map, - shared_info, - true); - } - } - - VisitPointers( - heap, - HeapObject::RawField(object, - JSFunction::kCodeEntryOffset + kPointerSize), - HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset)); - } - - - static void VisitSharedFunctionInfoFields(Heap* heap, - HeapObject* object, - bool flush_code_candidate) { - VisitPointer(heap, - HeapObject::RawField(object, SharedFunctionInfo::kNameOffset)); - - if (!flush_code_candidate) { - VisitPointer(heap, - HeapObject::RawField(object, - SharedFunctionInfo::kCodeOffset)); - } - - VisitPointers( - heap, - HeapObject::RawField(object, - SharedFunctionInfo::kOptimizedCodeMapOffset), - HeapObject::RawField(object, SharedFunctionInfo::kSize)); - } - static VisitorDispatchTable<Callback> non_count_table_; }; @@ -1544,7 +1339,8 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker< Map* map_obj = Map::cast(obj); ASSERT(map->instance_type() == MAP_TYPE); DescriptorArray* array = map_obj->instance_descriptors(); - if (array != heap->empty_descriptor_array()) { + if (map_obj->owns_descriptors() && + array != heap->empty_descriptor_array()) { int fixed_array_size = array->Size(); heap->RecordObjectStats(FIXED_ARRAY_TYPE, DESCRIPTOR_ARRAY_SUB_TYPE, @@ -1620,12 +1416,6 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker< void MarkCompactMarkingVisitor::Initialize() { StaticMarkingVisitor<MarkCompactMarkingVisitor>::Initialize(); - table_.Register(kVisitSharedFunctionInfo, - &VisitSharedFunctionInfoAndFlushCode); - - table_.Register(kVisitJSFunction, - &VisitJSFunctionAndFlushCode); - table_.Register(kVisitJSRegExp, &VisitRegExpAndFlushCode); @@ -1700,26 +1490,6 @@ class SharedFunctionInfoMarkingVisitor : public ObjectVisitor { }; -void MarkCompactCollector::MarkInlinedFunctionsCode(Code* code) { - // For optimized functions we should retain both non-optimized version - // of it's code and non-optimized version of all inlined functions. - // This is required to support bailing out from inlined code. - DeoptimizationInputData* data = - DeoptimizationInputData::cast(code->deoptimization_data()); - - FixedArray* literals = data->LiteralArray(); - - for (int i = 0, count = data->InlinedFunctionCount()->value(); - i < count; - i++) { - JSFunction* inlined = JSFunction::cast(literals->get(i)); - Code* inlined_code = inlined->shared()->code(); - MarkBit inlined_code_mark = Marking::MarkBitFrom(inlined_code); - MarkObject(inlined_code, inlined_code_mark); - } -} - - void MarkCompactCollector::PrepareThreadForCodeFlushing(Isolate* isolate, ThreadLocalTop* top) { for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { @@ -1732,7 +1502,8 @@ void MarkCompactCollector::PrepareThreadForCodeFlushing(Isolate* isolate, MarkBit code_mark = Marking::MarkBitFrom(code); MarkObject(code, code_mark); if (frame->is_optimized()) { - MarkInlinedFunctionsCode(frame->LookupCode()); + MarkCompactMarkingVisitor::MarkInlinedFunctionsCode(heap(), + frame->LookupCode()); } } } @@ -1741,21 +1512,13 @@ void MarkCompactCollector::PrepareThreadForCodeFlushing(Isolate* isolate, void MarkCompactCollector::PrepareForCodeFlushing() { ASSERT(heap() == Isolate::Current()->heap()); - // TODO(1609) Currently incremental marker does not support code flushing. - if (!FLAG_flush_code || was_marked_incrementally_) { - EnableCodeFlushing(false); - return; + // Enable code flushing for non-incremental cycles. + if (FLAG_flush_code && !FLAG_flush_code_incrementally) { + EnableCodeFlushing(!was_marked_incrementally_); } -#ifdef ENABLE_DEBUGGER_SUPPORT - if (heap()->isolate()->debug()->IsLoaded() || - heap()->isolate()->debug()->has_break_points()) { - EnableCodeFlushing(false); - return; - } -#endif - - EnableCodeFlushing(true); + // If code flushing is disabled, there is no need to prepare for it. + if (!is_code_flushing_enabled()) return; // Ensure that empty descriptor array is marked. Method MarkDescriptorArray // relies on it being marked before any other descriptor array. @@ -1874,97 +1637,6 @@ class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { }; -void MarkCompactCollector::ProcessNewlyMarkedObject(HeapObject* object) { - ASSERT(IsMarked(object)); - ASSERT(HEAP->Contains(object)); - if (object->IsMap()) { - Map* map = Map::cast(object); - heap_->ClearCacheOnMap(map); - - // When map collection is enabled we have to mark through map's transitions - // in a special way to make transition links weak. Only maps for subclasses - // of JSReceiver can have transitions. - STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); - if (FLAG_collect_maps && map->instance_type() >= FIRST_JS_RECEIVER_TYPE) { - marker_.MarkMapContents(map); - } else { - marking_deque_.PushBlack(map); - } - } else { - marking_deque_.PushBlack(object); - } -} - - -// Force instantiation of template instances. -template void Marker<IncrementalMarking>::MarkMapContents(Map* map); -template void Marker<MarkCompactCollector>::MarkMapContents(Map* map); - - -template <class T> -void Marker<T>::MarkMapContents(Map* map) { - // Make sure that the back pointer stored either in the map itself or inside - // its transitions array is marked. Treat pointers in the transitions array as - // weak and also mark that array to prevent visiting it later. - base_marker()->MarkObjectAndPush(HeapObject::cast(map->GetBackPointer())); - - Object** transitions_slot = - HeapObject::RawField(map, Map::kTransitionsOrBackPointerOffset); - Object* transitions = *transitions_slot; - if (transitions->IsTransitionArray()) { - MarkTransitionArray(reinterpret_cast<TransitionArray*>(transitions)); - } else { - // Already marked by marking map->GetBackPointer(). - ASSERT(transitions->IsMap() || transitions->IsUndefined()); - } - - // Mark the Object* fields of the Map. Since the transitions array has been - // marked already, it is fine that one of these fields contains a pointer to - // it. - Object** start_slot = - HeapObject::RawField(map, Map::kPointerFieldsBeginOffset); - Object** end_slot = HeapObject::RawField(map, Map::kPointerFieldsEndOffset); - for (Object** slot = start_slot; slot < end_slot; slot++) { - Object* obj = *slot; - if (!obj->NonFailureIsHeapObject()) continue; - mark_compact_collector()->RecordSlot(start_slot, slot, obj); - base_marker()->MarkObjectAndPush(reinterpret_cast<HeapObject*>(obj)); - } -} - - -template <class T> -void Marker<T>::MarkTransitionArray(TransitionArray* transitions) { - if (!base_marker()->MarkObjectWithoutPush(transitions)) return; - Object** transitions_start = transitions->data_start(); - - DescriptorArray* descriptors = transitions->descriptors(); - base_marker()->MarkObjectAndPush(descriptors); - mark_compact_collector()->RecordSlot( - transitions_start, transitions->GetDescriptorsSlot(), descriptors); - - if (transitions->HasPrototypeTransitions()) { - // 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. - Object** proto_trans_slot = transitions->GetPrototypeTransitionsSlot(); - HeapObject* prototype_transitions = HeapObject::cast(*proto_trans_slot); - base_marker()->MarkObjectWithoutPush(prototype_transitions); - mark_compact_collector()->RecordSlot( - transitions_start, proto_trans_slot, prototype_transitions); - } - - for (int i = 0; i < transitions->number_of_transitions(); ++i) { - Object** key_slot = transitions->GetKeySlot(i); - Object* key = *key_slot; - if (key->IsHeapObject()) { - base_marker()->MarkObjectAndPush(HeapObject::cast(key)); - mark_compact_collector()->RecordSlot(transitions_start, key_slot, key); - } - } -} - - // 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. @@ -2077,6 +1749,16 @@ bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) { } +bool MarkCompactCollector::IsUnmarkedHeapObjectWithHeap(Heap* heap, + Object** p) { + Object* o = *p; + ASSERT(o->IsHeapObject()); + HeapObject* heap_object = HeapObject::cast(o); + MarkBit mark = Marking::MarkBitFrom(heap_object); + return !mark.Get(); +} + + void MarkCompactCollector::MarkSymbolTable() { SymbolTable* symbol_table = heap()->symbol_table(); // Mark the symbol table itself. @@ -2105,54 +1787,6 @@ void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) { } -void MarkCompactCollector::MarkObjectGroups() { - List<ObjectGroup*>* object_groups = - heap()->isolate()->global_handles()->object_groups(); - - int last = 0; - for (int i = 0; i < object_groups->length(); i++) { - ObjectGroup* entry = object_groups->at(i); - ASSERT(entry != NULL); - - Object*** objects = entry->objects_; - bool group_marked = false; - for (size_t j = 0; j < entry->length_; j++) { - Object* object = *objects[j]; - if (object->IsHeapObject()) { - HeapObject* heap_object = HeapObject::cast(object); - MarkBit mark = Marking::MarkBitFrom(heap_object); - if (mark.Get()) { - group_marked = true; - break; - } - } - } - - if (!group_marked) { - (*object_groups)[last++] = entry; - continue; - } - - // An object in the group is marked, so mark as grey all white heap - // objects in the group. - for (size_t j = 0; j < entry->length_; ++j) { - Object* object = *objects[j]; - if (object->IsHeapObject()) { - HeapObject* heap_object = HeapObject::cast(object); - MarkBit mark = Marking::MarkBitFrom(heap_object); - MarkObject(heap_object, mark); - } - } - - // Once the entire group has been colored grey, set the object group - // to NULL so it won't be processed again. - entry->Dispose(); - object_groups->at(i) = NULL; - } - object_groups->Rewind(last); -} - - void MarkCompactCollector::MarkImplicitRefGroups() { List<ImplicitRefGroup*>* ref_groups = heap()->isolate()->global_handles()->implicit_ref_groups(); @@ -2271,11 +1905,12 @@ void MarkCompactCollector::ProcessMarkingDeque() { } -void MarkCompactCollector::ProcessExternalMarking() { +void MarkCompactCollector::ProcessExternalMarking(RootMarkingVisitor* visitor) { bool work_to_do = true; ASSERT(marking_deque_.IsEmpty()); while (work_to_do) { - MarkObjectGroups(); + heap()->isolate()->global_handles()->IterateObjectGroups( + visitor, &IsUnmarkedHeapObjectWithHeap); MarkImplicitRefGroups(); work_to_do = !marking_deque_.IsEmpty(); ProcessMarkingDeque(); @@ -2298,7 +1933,7 @@ void MarkCompactCollector::MarkLiveObjects() { // non-incremental marker can deal with them as if overflow // occured during normal marking. // But incremental marker uses a separate marking deque - // so we have to explicitly copy it's overflow state. + // so we have to explicitly copy its overflow state. incremental_marking->Finalize(); incremental_marking_overflowed = incremental_marking->marking_deque()->overflowed(); @@ -2354,7 +1989,7 @@ void MarkCompactCollector::MarkLiveObjects() { // The objects reachable from the roots are marked, yet unreachable // objects are unmarked. Mark objects reachable due to host // application specific logic. - ProcessExternalMarking(); + ProcessExternalMarking(&root_visitor); // The objects reachable from the roots or object groups are marked, // yet unreachable objects are unmarked. Mark objects reachable @@ -2373,7 +2008,7 @@ void MarkCompactCollector::MarkLiveObjects() { // Repeat host application specific marking to mark unmarked objects // reachable from the weak roots. - ProcessExternalMarking(); + ProcessExternalMarking(&root_visitor); AfterMarking(); } @@ -2407,6 +2042,11 @@ void MarkCompactCollector::AfterMarking() { // Flush code from collected candidates. if (is_code_flushing_enabled()) { code_flusher_->ProcessCandidates(); + // If incremental marker does not support code flushing, we need to + // disable it before incremental marking steps for next cycle. + if (FLAG_flush_code && !FLAG_flush_code_incrementally) { + EnableCodeFlushing(false); + } } if (!FLAG_watch_ic_patching) { @@ -2714,15 +2354,33 @@ class PointersUpdatingVisitor: public ObjectVisitor { void VisitEmbeddedPointer(RelocInfo* rinfo) { ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); Object* target = rinfo->target_object(); + Object* old_target = target; VisitPointer(&target); - rinfo->set_target_object(target); + // Avoid unnecessary changes that might unnecessary flush the instruction + // cache. + if (target != old_target) { + rinfo->set_target_object(target); + } } void VisitCodeTarget(RelocInfo* rinfo) { ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); + Object* old_target = target; VisitPointer(&target); - rinfo->set_target_address(Code::cast(target)->instruction_start()); + if (target != old_target) { + rinfo->set_target_address(Code::cast(target)->instruction_start()); + } + } + + void VisitCodeAgeSequence(RelocInfo* rinfo) { + ASSERT(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); + Object* stub = rinfo->code_age_stub(); + ASSERT(stub != NULL); + VisitPointer(&stub); + if (stub != rinfo->code_age_stub()) { + rinfo->set_code_age_stub(Code::cast(stub)); + } } void VisitDebugTarget(RelocInfo* rinfo) { @@ -3426,7 +3084,7 @@ void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { heap_->isolate()->inner_pointer_to_code_cache()->Flush(); -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { VerifyEvacuation(heap_); } @@ -3834,7 +3492,6 @@ void MarkCompactCollector::SweepSpace(PagedSpace* space, SweeperType sweeper) { intptr_t freed_bytes = 0; int pages_swept = 0; - intptr_t newspace_size = space->heap()->new_space()->Size(); bool lazy_sweeping_active = false; bool unused_page_present = false; @@ -3897,15 +3554,8 @@ void MarkCompactCollector::SweepSpace(PagedSpace* space, SweeperType sweeper) { } freed_bytes += SweepConservatively(space, p); pages_swept++; - if (freed_bytes > 2 * newspace_size) { - space->SetPagesToSweep(p->next_page()); - lazy_sweeping_active = true; - } else { - if (FLAG_gc_verbose) { - PrintF("Only %" V8PRIdPTR " bytes freed. Still sweeping.\n", - freed_bytes); - } - } + space->SetPagesToSweep(p->next_page()); + lazy_sweeping_active = true; break; } case PRECISE: { @@ -3973,11 +3623,19 @@ void MarkCompactCollector::SweepSpaces() { void MarkCompactCollector::EnableCodeFlushing(bool enable) { +#ifdef ENABLE_DEBUGGER_SUPPORT + if (heap()->isolate()->debug()->IsLoaded() || + heap()->isolate()->debug()->has_break_points()) { + enable = false; + } +#endif + if (enable) { if (code_flusher_ != NULL) return; code_flusher_ = new CodeFlusher(heap()->isolate()); } else { if (code_flusher_ == NULL) return; + code_flusher_->EvictAllCandidates(); delete code_flusher_; code_flusher_ = NULL; } diff --git a/deps/v8/src/mark-compact.h b/deps/v8/src/mark-compact.h index d252e1928e..9a0b014d63 100644 --- a/deps/v8/src/mark-compact.h +++ b/deps/v8/src/mark-compact.h @@ -304,6 +304,26 @@ class SlotsBuffer { NUMBER_OF_SLOT_TYPES }; + static const char* SlotTypeToString(SlotType type) { + switch (type) { + case EMBEDDED_OBJECT_SLOT: + return "EMBEDDED_OBJECT_SLOT"; + case RELOCATED_CODE_OBJECT: + return "RELOCATED_CODE_OBJECT"; + case CODE_TARGET_SLOT: + return "CODE_TARGET_SLOT"; + case CODE_ENTRY_SLOT: + return "CODE_ENTRY_SLOT"; + case DEBUG_TARGET_SLOT: + return "DEBUG_TARGET_SLOT"; + case JS_RETURN_SLOT: + return "JS_RETURN_SLOT"; + case NUMBER_OF_SLOT_TYPES: + return "NUMBER_OF_SLOT_TYPES"; + } + return "UNKNOWN SlotType"; + } + void UpdateSlots(Heap* heap); void UpdateSlotsWithFilter(Heap* heap); @@ -383,30 +403,96 @@ class SlotsBuffer { }; -// ------------------------------------------------------------------------- -// Marker shared between incremental and non-incremental marking -template<class BaseMarker> class Marker { +// CodeFlusher collects candidates for code flushing during marking and +// processes those candidates after marking has completed in order to +// reset those functions referencing code objects that would otherwise +// be unreachable. Code objects can be referenced in two ways: +// - SharedFunctionInfo references unoptimized code. +// - JSFunction references either unoptimized or optimized code. +// We are not allowed to flush unoptimized code for functions that got +// optimized or inlined into optimized code, because we might bailout +// into the unoptimized code again during deoptimization. +class CodeFlusher { public: - Marker(BaseMarker* base_marker, MarkCompactCollector* mark_compact_collector) - : base_marker_(base_marker), - mark_compact_collector_(mark_compact_collector) {} + explicit CodeFlusher(Isolate* isolate) + : isolate_(isolate), + jsfunction_candidates_head_(NULL), + shared_function_info_candidates_head_(NULL) {} + + void AddCandidate(SharedFunctionInfo* shared_info) { + if (GetNextCandidate(shared_info) == NULL) { + SetNextCandidate(shared_info, shared_function_info_candidates_head_); + shared_function_info_candidates_head_ = shared_info; + } + } - // Mark pointers in a Map and its DescriptorArray together, possibly - // treating transitions or back pointers weak. - void MarkMapContents(Map* map); - void MarkTransitionArray(TransitionArray* transitions); + void AddCandidate(JSFunction* function) { + ASSERT(function->code() == function->shared()->code()); + if (GetNextCandidate(function)->IsUndefined()) { + SetNextCandidate(function, jsfunction_candidates_head_); + jsfunction_candidates_head_ = function; + } + } + + void EvictCandidate(JSFunction* function); + + void ProcessCandidates() { + ProcessSharedFunctionInfoCandidates(); + ProcessJSFunctionCandidates(); + } + + void EvictAllCandidates() { + EvictJSFunctionCandidates(); + EvictSharedFunctionInfoCandidates(); + } + + void IteratePointersToFromSpace(ObjectVisitor* v); private: - BaseMarker* base_marker() { - return base_marker_; + void ProcessJSFunctionCandidates(); + void ProcessSharedFunctionInfoCandidates(); + void EvictJSFunctionCandidates(); + void EvictSharedFunctionInfoCandidates(); + + static JSFunction** GetNextCandidateSlot(JSFunction* candidate) { + return reinterpret_cast<JSFunction**>( + HeapObject::RawField(candidate, JSFunction::kNextFunctionLinkOffset)); + } + + static JSFunction* GetNextCandidate(JSFunction* candidate) { + Object* next_candidate = candidate->next_function_link(); + return reinterpret_cast<JSFunction*>(next_candidate); + } + + static void SetNextCandidate(JSFunction* candidate, + JSFunction* next_candidate) { + candidate->set_next_function_link(next_candidate); } - MarkCompactCollector* mark_compact_collector() { - return mark_compact_collector_; + static void ClearNextCandidate(JSFunction* candidate, Object* undefined) { + ASSERT(undefined->IsUndefined()); + candidate->set_next_function_link(undefined, SKIP_WRITE_BARRIER); } - BaseMarker* base_marker_; - MarkCompactCollector* mark_compact_collector_; + static SharedFunctionInfo* GetNextCandidate(SharedFunctionInfo* candidate) { + Object* next_candidate = candidate->code()->gc_metadata(); + return reinterpret_cast<SharedFunctionInfo*>(next_candidate); + } + + static void SetNextCandidate(SharedFunctionInfo* candidate, + SharedFunctionInfo* next_candidate) { + candidate->code()->set_gc_metadata(next_candidate); + } + + static void ClearNextCandidate(SharedFunctionInfo* candidate) { + candidate->code()->set_gc_metadata(NULL, SKIP_WRITE_BARRIER); + } + + Isolate* isolate_; + JSFunction* jsfunction_candidates_head_; + SharedFunctionInfo* shared_function_info_candidates_head_; + + DISALLOW_COPY_AND_ASSIGN(CodeFlusher); }; @@ -504,7 +590,7 @@ class MarkCompactCollector { PRECISE }; -#ifdef DEBUG +#ifdef VERIFY_HEAP void VerifyMarkbitsAreClean(); static void VerifyMarkbitsAreClean(PagedSpace* space); static void VerifyMarkbitsAreClean(NewSpace* space); @@ -572,8 +658,12 @@ class MarkCompactCollector { void ClearMarkbits(); + bool abort_incremental_marking() const { return abort_incremental_marking_; } + bool is_compacting() const { return compacting_; } + MarkingParity marking_parity() { return marking_parity_; } + private: MarkCompactCollector(); ~MarkCompactCollector(); @@ -606,6 +696,8 @@ class MarkCompactCollector { bool abort_incremental_marking_; + MarkingParity marking_parity_; + // True if we are collecting slots to perform evacuation from evacuation // candidates. bool compacting_; @@ -637,12 +729,6 @@ class MarkCompactCollector { friend class MarkCompactMarkingVisitor; friend class CodeMarkingVisitor; friend class SharedFunctionInfoMarkingVisitor; - friend class Marker<IncrementalMarking>; - friend class Marker<MarkCompactCollector>; - - // Mark non-optimize code for functions inlined into the given optimized - // code. This will prevent it from being flushed. - void MarkInlinedFunctionsCode(Code* code); // Mark code objects that are active on the stack to prevent them // from being flushed. @@ -656,25 +742,13 @@ class MarkCompactCollector { void AfterMarking(); // Marks the object black and pushes it on the marking stack. - // Returns true if object needed marking and false otherwise. - // This is for non-incremental marking only. - INLINE(bool MarkObjectAndPush(HeapObject* obj)); - - // Marks the object black and pushes it on the marking stack. // This is for non-incremental marking only. INLINE(void MarkObject(HeapObject* obj, MarkBit mark_bit)); - // Marks the object black without pushing it on the marking stack. - // Returns true if object needed marking and false otherwise. - // This is for non-incremental marking only. - INLINE(bool MarkObjectWithoutPush(HeapObject* obj)); - // Marks the object black assuming that it is not yet marked. // This is for non-incremental marking only. INLINE(void SetMark(HeapObject* obj, MarkBit mark_bit)); - void ProcessNewlyMarkedObject(HeapObject* obj); - // Mark the heap roots and all objects reachable from them. void MarkRoots(RootMarkingVisitor* visitor); @@ -682,17 +756,13 @@ class MarkCompactCollector { // symbol table are weak. void MarkSymbolTable(); - // Mark objects in object groups that have at least one object in the - // group marked. - void MarkObjectGroups(); - // Mark objects in implicit references groups if their parent object // is marked. void MarkImplicitRefGroups(); // Mark all objects which are reachable due to host application // logic like object groups or implicit references' groups. - void ProcessExternalMarking(); + void ProcessExternalMarking(RootMarkingVisitor* visitor); // Mark objects reachable (transitively) from objects in the marking stack // or overflowed in the heap. @@ -716,6 +786,7 @@ class MarkCompactCollector { // Callback function for telling whether the object *p is an unmarked // heap object. static bool IsUnmarkedHeapObject(Object** p); + static bool IsUnmarkedHeapObjectWithHeap(Heap* heap, Object** p); // Map transitions from a live map to a dead map must be killed. // We replace them with a null descriptor, with the same key. @@ -777,7 +848,6 @@ class MarkCompactCollector { MarkingDeque marking_deque_; CodeFlusher* code_flusher_; Object* encountered_weak_maps_; - Marker<MarkCompactCollector> marker_; List<Page*> evacuation_candidates_; List<Code*> invalidated_code_; diff --git a/deps/v8/src/math.js b/deps/v8/src/math.js index aee56af4f9..46863284f0 100644 --- a/deps/v8/src/math.js +++ b/deps/v8/src/math.js @@ -131,19 +131,16 @@ function MathMax(arg1, arg2) { // length == 2 // All comparisons failed, one of the arguments must be NaN. return 0/0; // Compiler constant-folds this to NaN. } - if (length == 0) { - return -1/0; // Compiler constant-folds this to -Infinity. - } - var r = arg1; - if (!IS_NUMBER(r)) r = NonNumberToNumber(r); - if (NUMBER_IS_NAN(r)) return r; - for (var i = 1; i < length; i++) { + var r = -1/0; // Compiler constant-folds this to -Infinity. + for (var i = 0; i < length; i++) { var n = %_Arguments(i); if (!IS_NUMBER(n)) n = NonNumberToNumber(n); - if (NUMBER_IS_NAN(n)) return n; // Make sure +0 is considered greater than -0. -0 is never a Smi, +0 can be // a Smi or heap number. - if (n > r || (r == 0 && n == 0 && !%_IsSmi(r) && 1 / r < 0)) r = n; + if (NUMBER_IS_NAN(n) || n > r || + (r == 0 && n == 0 && !%_IsSmi(r) && 1 / r < 0)) { + r = n; + } } return r; } @@ -164,19 +161,16 @@ function MathMin(arg1, arg2) { // length == 2 // All comparisons failed, one of the arguments must be NaN. return 0/0; // Compiler constant-folds this to NaN. } - if (length == 0) { - return 1/0; // Compiler constant-folds this to Infinity. - } - var r = arg1; - if (!IS_NUMBER(r)) r = NonNumberToNumber(r); - if (NUMBER_IS_NAN(r)) return r; - for (var i = 1; i < length; i++) { + var r = 1/0; // Compiler constant-folds this to Infinity. + for (var i = 0; i < length; i++) { var n = %_Arguments(i); if (!IS_NUMBER(n)) n = NonNumberToNumber(n); - if (NUMBER_IS_NAN(n)) return n; // Make sure -0 is considered less than +0. -0 is never a Smi, +0 can be a // Smi or a heap number. - if (n < r || (r == 0 && n == 0 && !%_IsSmi(n) && 1 / n < 0)) r = n; + if (NUMBER_IS_NAN(n) || n < r || + (r == 0 && n == 0 && !%_IsSmi(n) && 1 / n < 0)) { + r = n; + } } return r; } diff --git a/deps/v8/src/messages.cc b/deps/v8/src/messages.cc index a0793c2dfd..ce965fcf95 100644 --- a/deps/v8/src/messages.cc +++ b/deps/v8/src/messages.cc @@ -106,11 +106,20 @@ void MessageHandler::ReportMessage(Isolate* isolate, // We are calling into embedder's code which can throw exceptions. // Thus we need to save current exception state, reset it to the clean one // and ignore scheduled exceptions callbacks can throw. + + // We pass the exception object into the message handler callback though. + Object* exception_object = isolate->heap()->undefined_value(); + if (isolate->has_pending_exception()) { + isolate->pending_exception()->ToObject(&exception_object); + } + Handle<Object> exception_handle(exception_object); + Isolate::ExceptionScope exception_scope(isolate); isolate->clear_pending_exception(); isolate->set_external_caught_exception(false); v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message); + v8::Local<v8::Value> api_exception_obj = v8::Utils::ToLocal(exception_handle); v8::NeanderArray global_listeners(FACTORY->message_listeners()); int global_length = global_listeners.length(); @@ -123,15 +132,13 @@ void MessageHandler::ReportMessage(Isolate* isolate, for (int i = 0; i < global_length; i++) { HandleScope scope; if (global_listeners.get(i)->IsUndefined()) continue; - v8::NeanderObject listener(JSObject::cast(global_listeners.get(i))); - Handle<Foreign> callback_obj(Foreign::cast(listener.get(0))); + Handle<Foreign> callback_obj(Foreign::cast(global_listeners.get(i))); v8::MessageCallback callback = FUNCTION_CAST<v8::MessageCallback>(callback_obj->foreign_address()); - Handle<Object> callback_data(listener.get(1)); { // Do not allow exceptions to propagate. v8::TryCatch try_catch; - callback(api_message_obj, v8::Utils::ToLocal(callback_data)); + callback(api_message_obj, api_exception_obj); } if (isolate->has_scheduled_exception()) { isolate->clear_scheduled_exception(); @@ -148,7 +155,9 @@ Handle<String> MessageHandler::GetMessage(Handle<Object> data) { JSFunction::cast( Isolate::Current()->js_builtins_object()-> GetPropertyNoExceptionThrown(*fmt_str))); - Handle<Object> argv[] = { data }; + Handle<JSMessageObject> message = Handle<JSMessageObject>::cast(data); + Handle<Object> argv[] = { Handle<Object>(message->type()), + Handle<Object>(message->arguments()) }; bool caught_exception; Handle<Object> result = diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index d896ac3944..0a50ae7861 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -26,18 +26,137 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ------------------------------------------------------------------- -// -// If this object gets passed to an error constructor the error will -// get an accessor for .message that constructs a descriptive error -// message on access. -var kAddMessageAccessorsMarker = { }; - -// This will be lazily initialized when first needed (and forcibly -// overwritten even though it's const). -var kMessages = 0; -function FormatString(format, message) { - var args = %MessageGetArguments(message); +var kMessages = { + // Error + cyclic_proto: ["Cyclic __proto__ value"], + code_gen_from_strings: ["%0"], + // TypeError + unexpected_token: ["Unexpected token ", "%0"], + unexpected_token_number: ["Unexpected number"], + unexpected_token_string: ["Unexpected string"], + unexpected_token_identifier: ["Unexpected identifier"], + unexpected_reserved: ["Unexpected reserved word"], + unexpected_strict_reserved: ["Unexpected strict mode reserved word"], + unexpected_eos: ["Unexpected end of input"], + malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"], + unterminated_regexp: ["Invalid regular expression: missing /"], + regexp_flags: ["Cannot supply flags when constructing one RegExp from another"], + incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"], + invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"], + invalid_lhs_in_for_in: ["Invalid left-hand side in for-in"], + invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"], + invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"], + multiple_defaults_in_switch: ["More than one default clause in switch statement"], + newline_after_throw: ["Illegal newline after throw"], + redeclaration: ["%0", " '", "%1", "' has already been declared"], + no_catch_or_finally: ["Missing catch or finally after try"], + unknown_label: ["Undefined label '", "%0", "'"], + uncaught_exception: ["Uncaught ", "%0"], + stack_trace: ["Stack Trace:\n", "%0"], + called_non_callable: ["%0", " is not a function"], + undefined_method: ["Object ", "%1", " has no method '", "%0", "'"], + property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"], + cannot_convert_to_primitive: ["Cannot convert object to primitive value"], + not_constructor: ["%0", " is not a constructor"], + not_defined: ["%0", " is not defined"], + non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"], + non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"], + non_object_property_call: ["Cannot call method '", "%0", "' of ", "%1"], + with_expression: ["%0", " has no properties"], + illegal_invocation: ["Illegal invocation"], + no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"], + apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"], + apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"], + invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"], + instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"], + instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"], + null_to_object: ["Cannot convert null to object"], + reduce_no_initial: ["Reduce of empty array with no initial value"], + getter_must_be_callable: ["Getter must be a function: ", "%0"], + setter_must_be_callable: ["Setter must be a function: ", "%0"], + value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"], + proto_object_or_null: ["Object prototype may only be an Object or null"], + property_desc_object: ["Property description must be an object: ", "%0"], + redefine_disallowed: ["Cannot redefine property: ", "%0"], + define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."], + non_extensible_proto: ["%0", " is not extensible"], + handler_non_object: ["Proxy.", "%0", " called with non-object as handler"], + proto_non_object: ["Proxy.", "%0", " called with non-object as prototype"], + trap_function_expected: ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"], + handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"], + handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"], + handler_returned_false: ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"], + handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"], + proxy_prop_not_configurable: ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"], + proxy_non_object_prop_names: ["Trap '", "%1", "' returned non-object ", "%0"], + proxy_repeated_prop_name: ["Trap '", "%1", "' returned repeated property name '", "%2", "'"], + invalid_weakmap_key: ["Invalid value used as weak map key"], + not_date_object: ["this is not a Date object."], + observe_non_object: ["Object.", "%0", " cannot ", "%0", " non-object"], + observe_non_function: ["Object.", "%0", " cannot deliver to non-function"], + observe_callback_frozen: ["Object.observe cannot deliver to a frozen function object"], + observe_type_non_string: ["Invalid changeRecord with non-string 'type' property"], + observe_notify_non_notifier: ["notify called on non-notifier object"], + // RangeError + invalid_array_length: ["Invalid array length"], + stack_overflow: ["Maximum call stack size exceeded"], + invalid_time_value: ["Invalid time value"], + // SyntaxError + unable_to_parse: ["Parse error"], + invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"], + invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"], + illegal_break: ["Illegal break statement"], + illegal_continue: ["Illegal continue statement"], + illegal_return: ["Illegal return statement"], + illegal_let: ["Illegal let declaration outside extended mode"], + error_loading_debugger: ["Error loading debugger"], + no_input_to_regexp: ["No input to ", "%0"], + invalid_json: ["String '", "%0", "' is not valid JSON"], + circular_structure: ["Converting circular structure to JSON"], + called_on_non_object: ["%0", " called on non-object"], + called_on_null_or_undefined: ["%0", " called on null or undefined"], + array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"], + object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"], + illegal_access: ["Illegal access"], + invalid_preparser_data: ["Invalid preparser data for function ", "%0"], + strict_mode_with: ["Strict mode code may not include a with statement"], + strict_catch_variable: ["Catch variable may not be eval or arguments in strict mode"], + too_many_arguments: ["Too many arguments in function call (only 32766 allowed)"], + too_many_parameters: ["Too many parameters in function definition (only 32766 allowed)"], + too_many_variables: ["Too many variables declared (only 131071 allowed)"], + strict_param_name: ["Parameter name eval or arguments is not allowed in strict mode"], + strict_param_dupe: ["Strict mode function may not have duplicate parameter names"], + strict_var_name: ["Variable name may not be eval or arguments in strict mode"], + strict_function_name: ["Function name may not be eval or arguments in strict mode"], + strict_octal_literal: ["Octal literals are not allowed in strict mode."], + strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"], + accessor_data_property: ["Object literal may not have data and accessor property with the same name"], + accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"], + strict_lhs_assignment: ["Assignment to eval or arguments is not allowed in strict mode"], + strict_lhs_postfix: ["Postfix increment/decrement may not have eval or arguments operand in strict mode"], + strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"], + strict_reserved_word: ["Use of future reserved word in strict mode"], + strict_delete: ["Delete of an unqualified identifier in strict mode."], + strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"], + strict_const: ["Use of const in strict mode."], + strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ], + strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"], + strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"], + strict_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"], + strict_caller: ["Illegal access to a strict mode caller function."], + unprotected_let: ["Illegal let declaration in unprotected statement context."], + unprotected_const: ["Illegal const declaration in unprotected statement context."], + cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"], + redef_external_array_element: ["Cannot redefine a property of an object with external array elements"], + harmony_const_assign: ["Assignment to constant variable."], + invalid_module_path: ["Module does not export '", "%0", "', or export is not itself a module"], + module_type_error: ["Module '", "%0", "' used improperly"], + module_export_undefined: ["Export '", "%0", "' is not defined in module"], +}; + + +function FormatString(format, args) { var result = ""; var arg_num = 0; for (var i = 0; i < format.length; i++) { @@ -48,7 +167,7 @@ function FormatString(format, message) { if (arg_num < 4) { // str is one of %0, %1, %2 or %3. try { - str = ToDetailString(args[arg_num]); + str = NoSideEffectToString(args[arg_num]); } catch (e) { if (%IsJSModule(args[arg_num])) str = "module"; @@ -65,6 +184,27 @@ function FormatString(format, message) { } +function NoSideEffectToString(obj) { + if (IS_STRING(obj)) return obj; + if (IS_NUMBER(obj)) return %_NumberToString(obj); + if (IS_BOOLEAN(obj)) return x ? 'true' : 'false'; + if (IS_UNDEFINED(obj)) return 'undefined'; + if (IS_NULL(obj)) return 'null'; + if (IS_FUNCTION(obj)) return %_CallFunction(obj, FunctionToString); + if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) { + var constructor = obj.constructor; + if (typeof constructor == "function") { + var constructorName = constructor.name; + if (IS_STRING(constructorName) && constructorName !== "") { + return "#<" + constructorName + ">"; + } + } + } + if (IsNativeErrorObject(obj)) return %_CallFunction(obj, ErrorToString); + return %_CallFunction(obj, ObjectToString); +} + + // To check if something is a native error we need to check the // concrete native error types. It is not sufficient to use instanceof // since it possible to create an object that has Error.prototype on @@ -112,13 +252,8 @@ function ToDetailString(obj) { function MakeGenericError(constructor, type, args) { - if (IS_UNDEFINED(args)) { - args = []; - } - var e = new constructor(kAddMessageAccessorsMarker); - e.type = type; - e.arguments = args; - return e; + if (IS_UNDEFINED(args)) args = []; + return new constructor(FormatMessage(type, args)); } @@ -135,156 +270,10 @@ function MakeGenericError(constructor, type, args) { // Helper functions; called from the runtime system. -function FormatMessage(message) { - if (kMessages === 0) { - var messagesDictionary = [ - // Error - "cyclic_proto", ["Cyclic __proto__ value"], - "code_gen_from_strings", ["Code generation from strings disallowed for this context"], - // TypeError - "unexpected_token", ["Unexpected token ", "%0"], - "unexpected_token_number", ["Unexpected number"], - "unexpected_token_string", ["Unexpected string"], - "unexpected_token_identifier", ["Unexpected identifier"], - "unexpected_reserved", ["Unexpected reserved word"], - "unexpected_strict_reserved", ["Unexpected strict mode reserved word"], - "unexpected_eos", ["Unexpected end of input"], - "malformed_regexp", ["Invalid regular expression: /", "%0", "/: ", "%1"], - "unterminated_regexp", ["Invalid regular expression: missing /"], - "regexp_flags", ["Cannot supply flags when constructing one RegExp from another"], - "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"], - "invalid_lhs_in_assignment", ["Invalid left-hand side in assignment"], - "invalid_lhs_in_for_in", ["Invalid left-hand side in for-in"], - "invalid_lhs_in_postfix_op", ["Invalid left-hand side expression in postfix operation"], - "invalid_lhs_in_prefix_op", ["Invalid left-hand side expression in prefix operation"], - "multiple_defaults_in_switch", ["More than one default clause in switch statement"], - "newline_after_throw", ["Illegal newline after throw"], - "redeclaration", ["%0", " '", "%1", "' has already been declared"], - "no_catch_or_finally", ["Missing catch or finally after try"], - "unknown_label", ["Undefined label '", "%0", "'"], - "uncaught_exception", ["Uncaught ", "%0"], - "stack_trace", ["Stack Trace:\n", "%0"], - "called_non_callable", ["%0", " is not a function"], - "undefined_method", ["Object ", "%1", " has no method '", "%0", "'"], - "property_not_function", ["Property '", "%0", "' of object ", "%1", " is not a function"], - "cannot_convert_to_primitive", ["Cannot convert object to primitive value"], - "not_constructor", ["%0", " is not a constructor"], - "not_defined", ["%0", " is not defined"], - "non_object_property_load", ["Cannot read property '", "%0", "' of ", "%1"], - "non_object_property_store", ["Cannot set property '", "%0", "' of ", "%1"], - "non_object_property_call", ["Cannot call method '", "%0", "' of ", "%1"], - "with_expression", ["%0", " has no properties"], - "illegal_invocation", ["Illegal invocation"], - "no_setter_in_callback", ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"], - "apply_non_function", ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"], - "apply_wrong_args", ["Function.prototype.apply: Arguments list has wrong type"], - "invalid_in_operator_use", ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"], - "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"], - "instanceof_nonobject_proto", ["Function has non-object prototype '", "%0", "' in instanceof check"], - "null_to_object", ["Cannot convert null to object"], - "reduce_no_initial", ["Reduce of empty array with no initial value"], - "getter_must_be_callable", ["Getter must be a function: ", "%0"], - "setter_must_be_callable", ["Setter must be a function: ", "%0"], - "value_and_accessor", ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"], - "proto_object_or_null", ["Object prototype may only be an Object or null"], - "property_desc_object", ["Property description must be an object: ", "%0"], - "redefine_disallowed", ["Cannot redefine property: ", "%0"], - "define_disallowed", ["Cannot define property:", "%0", ", object is not extensible."], - "non_extensible_proto", ["%0", " is not extensible"], - "handler_non_object", ["Proxy.", "%0", " called with non-object as handler"], - "proto_non_object", ["Proxy.", "%0", " called with non-object as prototype"], - "trap_function_expected", ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"], - "handler_trap_missing", ["Proxy handler ", "%0", " has no '", "%1", "' trap"], - "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"], - "handler_returned_false", ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"], - "handler_returned_undefined", ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"], - "proxy_prop_not_configurable", ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"], - "proxy_non_object_prop_names", ["Trap '", "%1", "' returned non-object ", "%0"], - "proxy_repeated_prop_name", ["Trap '", "%1", "' returned repeated property name '", "%2", "'"], - "invalid_weakmap_key", ["Invalid value used as weak map key"], - "not_date_object", ["this is not a Date object."], - // RangeError - "invalid_array_length", ["Invalid array length"], - "stack_overflow", ["Maximum call stack size exceeded"], - "invalid_time_value", ["Invalid time value"], - // SyntaxError - "unable_to_parse", ["Parse error"], - "invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"], - "invalid_regexp", ["Invalid RegExp pattern /", "%0", "/"], - "illegal_break", ["Illegal break statement"], - "illegal_continue", ["Illegal continue statement"], - "illegal_return", ["Illegal return statement"], - "illegal_let", ["Illegal let declaration outside extended mode"], - "error_loading_debugger", ["Error loading debugger"], - "no_input_to_regexp", ["No input to ", "%0"], - "invalid_json", ["String '", "%0", "' is not valid JSON"], - "circular_structure", ["Converting circular structure to JSON"], - "called_on_non_object", ["%0", " called on non-object"], - "called_on_null_or_undefined", ["%0", " called on null or undefined"], - "array_indexof_not_defined", ["Array.getIndexOf: Argument undefined"], - "object_not_extensible", ["Can't add property ", "%0", ", object is not extensible"], - "illegal_access", ["Illegal access"], - "invalid_preparser_data", ["Invalid preparser data for function ", "%0"], - "strict_mode_with", ["Strict mode code may not include a with statement"], - "strict_catch_variable", ["Catch variable may not be eval or arguments in strict mode"], - "too_many_arguments", ["Too many arguments in function call (only 32766 allowed)"], - "too_many_parameters", ["Too many parameters in function definition (only 32766 allowed)"], - "too_many_variables", ["Too many variables declared (only 65535 allowed)"], - "strict_param_name", ["Parameter name eval or arguments is not allowed in strict mode"], - "strict_param_dupe", ["Strict mode function may not have duplicate parameter names"], - "strict_var_name", ["Variable name may not be eval or arguments in strict mode"], - "strict_function_name", ["Function name may not be eval or arguments in strict mode"], - "strict_octal_literal", ["Octal literals are not allowed in strict mode."], - "strict_duplicate_property", ["Duplicate data property in object literal not allowed in strict mode"], - "accessor_data_property", ["Object literal may not have data and accessor property with the same name"], - "accessor_get_set", ["Object literal may not have multiple get/set accessors with the same name"], - "strict_lhs_assignment", ["Assignment to eval or arguments is not allowed in strict mode"], - "strict_lhs_postfix", ["Postfix increment/decrement may not have eval or arguments operand in strict mode"], - "strict_lhs_prefix", ["Prefix increment/decrement may not have eval or arguments operand in strict mode"], - "strict_reserved_word", ["Use of future reserved word in strict mode"], - "strict_delete", ["Delete of an unqualified identifier in strict mode."], - "strict_delete_property", ["Cannot delete property '", "%0", "' of ", "%1"], - "strict_const", ["Use of const in strict mode."], - "strict_function", ["In strict mode code, functions can only be declared at top level or immediately within another function." ], - "strict_read_only_property", ["Cannot assign to read only property '", "%0", "' of ", "%1"], - "strict_cannot_assign", ["Cannot assign to read only '", "%0", "' in strict mode"], - "strict_poison_pill", ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"], - "strict_caller", ["Illegal access to a strict mode caller function."], - "unprotected_let", ["Illegal let declaration in unprotected statement context."], - "unprotected_const", ["Illegal const declaration in unprotected statement context."], - "cant_prevent_ext_external_array_elements", ["Cannot prevent extension of an object with external array elements"], - "redef_external_array_element", ["Cannot redefine a property of an object with external array elements"], - "harmony_const_assign", ["Assignment to constant variable."], - "invalid_module_path", ["Module does not export '", "%0", "', or export is not itself a module"], - "module_type_error", ["Module '", "%0", "' used improperly"], - "module_export_undefined", ["Export '", "%0", "' is not defined in module"], - ]; - var messages = { __proto__ : null }; - for (var i = 0; i < messagesDictionary.length; i += 2) { - var key = messagesDictionary[i]; - var format = messagesDictionary[i + 1]; - - for (var j = 0; j < format.length; j++) { - %IgnoreAttributesAndSetProperty(format, %_NumberToString(j), format[j], - DONT_DELETE | READ_ONLY | DONT_ENUM); - } - %IgnoreAttributesAndSetProperty(format, 'length', format.length, - DONT_DELETE | READ_ONLY | DONT_ENUM); - %PreventExtensions(format); - %IgnoreAttributesAndSetProperty(messages, - key, - format, - DONT_DELETE | DONT_ENUM | READ_ONLY); - } - %PreventExtensions(messages); - %IgnoreAttributesAndSetProperty(builtins, "kMessages", - messages, - DONT_DELETE | DONT_ENUM | READ_ONLY); - } - var message_type = %MessageGetType(message); - var format = kMessages[message_type]; - if (!format) return "<unknown message " + message_type + ">"; - return FormatString(format, message); +function FormatMessage(type, args) { + var format = kMessages[type]; + if (!format) return "<unknown message " + type + ">"; + return FormatString(format, args); } @@ -532,8 +521,8 @@ function ScriptLineCount() { /** - * Returns the name of script if available, contents of sourceURL comment - * otherwise. See + * If sourceURL comment is available and script starts at zero returns sourceURL + * comment contents. Otherwise, script name is returned. See * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt * for details on using //@ sourceURL comment to identify scritps that don't * have name. @@ -542,14 +531,15 @@ function ScriptLineCount() { * otherwise. */ function ScriptNameOrSourceURL() { - if (this.name) { + if (this.line_offset > 0 || this.column_offset > 0) { return this.name; } // The result is cached as on long scripts it takes noticable time to search // for the sourceURL. - if (this.hasCachedNameOrSourceURL) - return this.cachedNameOrSourceURL; + if (this.hasCachedNameOrSourceURL) { + return this.cachedNameOrSourceURL; + } this.hasCachedNameOrSourceURL = true; // TODO(608): the spaces in a regexp below had to be escaped as \040 @@ -761,29 +751,6 @@ function GetStackTraceLine(recv, fun, pos, isGlobal) { // ---------------------------------------------------------------------------- // Error implementation -// Defines accessors for a property that is calculated the first time -// the property is read. -function DefineOneShotAccessor(obj, name, fun) { - // Note that the accessors consistently operate on 'obj', not 'this'. - // Since the object may occur in someone else's prototype chain we - // can't rely on 'this' being the same as 'obj'. - var value; - var value_factory = fun; - var getter = function() { - if (value_factory == null) { - return value; - } - value = value_factory(obj); - value_factory = null; - return value; - }; - var setter = function(v) { - value_factory = null; - value = v; - }; - %DefineOrRedefineAccessorProperty(obj, name, getter, setter, DONT_ENUM); -} - function CallSite(receiver, fun, pos) { this.receiver = receiver; this.fun = fun; @@ -1118,9 +1085,21 @@ function captureStackTrace(obj, cons_opt) { var raw_stack = %CollectStackTrace(obj, cons_opt ? cons_opt : captureStackTrace, stackTraceLimit); - DefineOneShotAccessor(obj, 'stack', function (obj) { - return FormatRawStackTrace(obj, raw_stack); - }); + // Note that 'obj' and 'this' maybe different when called on objects that + // have the error object on its prototype chain. The getter replaces itself + // with a data property as soon as the stack trace has been formatted. + var getter = function() { + var value = FormatRawStackTrace(obj, raw_stack); + %DefineOrRedefineDataProperty(obj, 'stack', value, NONE); + return value; + }; + // The 'stack' property of the receiver is set as data property. If + // the receiver is the same as holder, this accessor pair is replaced. + var setter = function(v) { + %DefineOrRedefineDataProperty(this, 'stack', v, NONE); + }; + + %DefineOrRedefineAccessorProperty(obj, 'stack', getter, setter, DONT_ENUM); } @@ -1159,15 +1138,7 @@ function SetUpError() { // object. This avoids going through getters and setters defined // on prototype objects. %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM); - %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM); - %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM); - if (m === kAddMessageAccessorsMarker) { - // DefineOneShotAccessor always inserts a message property and - // ignores setters. - DefineOneShotAccessor(this, 'message', function (obj) { - return FormatMessage(%NewMessageObject(obj.type, obj.arguments)); - }); - } else if (!IS_UNDEFINED(m)) { + if (!IS_UNDEFINED(m)) { %IgnoreAttributesAndSetProperty( this, 'message', ToString(m), DONT_ENUM); } @@ -1226,15 +1197,9 @@ function GetPropertyWithoutInvokingMonkeyGetters(error, name) { function ErrorToStringDetectCycle(error) { if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker; try { - var type = GetPropertyWithoutInvokingMonkeyGetters(error, "type"); var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name"); name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name); var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message"); - var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty); - if (type && !hasMessage) { - var args = GetPropertyWithoutInvokingMonkeyGetters(error, "arguments"); - message = FormatMessage(%NewMessageObject(type, args)); - } message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message); if (name === "") return message; if (message === "") return name; @@ -1266,4 +1231,37 @@ InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]); // Boilerplate for exceptions for stack overflows. Used from // Isolate::StackOverflow(). -var kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []); +function SetUpStackOverflowBoilerplate() { + var boilerplate = MakeRangeError('stack_overflow', []); + + // The raw stack trace is stored as hidden property of the copy of this + // boilerplate error object. Note that the receiver 'this' may not be that + // error object copy, but can be found on the prototype chain of 'this'. + // When the stack trace is formatted, this accessor property is replaced by + // a data property. + function getter() { + var holder = this; + while (!IS_ERROR(holder)) { + holder = %GetPrototype(holder); + if (holder == null) return MakeSyntaxError('illegal_access', []); + } + var raw_stack = %GetOverflowedRawStackTrace(holder); + var result = IS_ARRAY(raw_stack) ? FormatRawStackTrace(holder, raw_stack) + : void 0; + %DefineOrRedefineDataProperty(holder, 'stack', result, NONE); + return result; + } + + // The 'stack' property of the receiver is set as data property. If + // the receiver is the same as holder, this accessor pair is replaced. + function setter(v) { + %DefineOrRedefineDataProperty(this, 'stack', v, NONE); + } + + %DefineOrRedefineAccessorProperty( + boilerplate, 'stack', getter, setter, DONT_ENUM); + + return boilerplate; +} + +var kStackOverflowBoilerplate = SetUpStackOverflowBoilerplate(); diff --git a/deps/v8/src/mips/assembler-mips-inl.h b/deps/v8/src/mips/assembler-mips-inl.h index 522bc78687..caf544f7c8 100644 --- a/deps/v8/src/mips/assembler-mips-inl.h +++ b/deps/v8/src/mips/assembler-mips-inl.h @@ -1,3 +1,4 @@ + // Copyright (c) 1994-2006 Sun Microsystems Inc. // All Rights Reserved. // @@ -156,6 +157,11 @@ void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) { } +Address Assembler::target_address_from_return_address(Address pc) { + return pc - kCallTargetAddressOffset; +} + + Object* RelocInfo::target_object() { ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); return reinterpret_cast<Object*>(Assembler::target_address_at(pc_)); @@ -226,6 +232,24 @@ void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell, } +static const int kNoCodeAgeSequenceLength = 7; + +Code* RelocInfo::code_age_stub() { + ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); + return Code::GetCodeFromTargetAddress( + Memory::Address_at(pc_ + Assembler::kInstrSize * + (kNoCodeAgeSequenceLength - 1))); +} + + +void RelocInfo::set_code_age_stub(Code* stub) { + ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); + Memory::Address_at(pc_ + Assembler::kInstrSize * + (kNoCodeAgeSequenceLength - 1)) = + stub->instruction_start(); +} + + Address RelocInfo::call_address() { ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence())); @@ -297,6 +321,8 @@ void RelocInfo::Visit(ObjectVisitor* visitor) { visitor->VisitGlobalPropertyCell(this); } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { visitor->VisitExternalReference(this); + } else if (RelocInfo::IsCodeAgeSequence(mode)) { + visitor->VisitCodeAgeSequence(this); #ifdef ENABLE_DEBUGGER_SUPPORT // TODO(isolates): Get a cached isolate below. } else if (((RelocInfo::IsJSReturn(mode) && @@ -323,6 +349,8 @@ void RelocInfo::Visit(Heap* heap) { StaticVisitor::VisitGlobalPropertyCell(heap, this); } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { StaticVisitor::VisitExternalReference(this); + } else if (RelocInfo::IsCodeAgeSequence(mode)) { + StaticVisitor::VisitCodeAgeSequence(heap, this); #ifdef ENABLE_DEBUGGER_SUPPORT } else if (heap->isolate()->debug()->has_break_points() && ((RelocInfo::IsJSReturn(mode) && diff --git a/deps/v8/src/mips/assembler-mips.cc b/deps/v8/src/mips/assembler-mips.cc index 801ca2c152..e7506206c9 100644 --- a/deps/v8/src/mips/assembler-mips.cc +++ b/deps/v8/src/mips/assembler-mips.cc @@ -267,45 +267,11 @@ const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask; const Instr kLwSwOffsetMask = kImm16Mask; -// Spare buffer. -static const int kMinimalBufferSize = 4 * KB; - - -Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size) - : AssemblerBase(arg_isolate), +Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) + : AssemblerBase(isolate, buffer, buffer_size), recorded_ast_id_(TypeFeedbackId::None()), - positions_recorder_(this), - emit_debug_code_(FLAG_debug_code) { - if (buffer == NULL) { - // Do our own buffer management. - if (buffer_size <= kMinimalBufferSize) { - buffer_size = kMinimalBufferSize; - - if (isolate()->assembler_spare_buffer() != NULL) { - buffer = isolate()->assembler_spare_buffer(); - isolate()->set_assembler_spare_buffer(NULL); - } - } - if (buffer == NULL) { - buffer_ = NewArray<byte>(buffer_size); - } else { - buffer_ = static_cast<byte*>(buffer); - } - buffer_size_ = buffer_size; - own_buffer_ = true; - - } else { - // Use externally provided buffer instead. - ASSERT(buffer_size > 0); - buffer_ = static_cast<byte*>(buffer); - buffer_size_ = buffer_size; - own_buffer_ = false; - } - - // Set up buffer pointers. - ASSERT(buffer_ != NULL); - pc_ = buffer_; - reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); + positions_recorder_(this) { + reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); last_trampoline_pool_end_ = 0; no_trampoline_pool_before_ = 0; @@ -324,18 +290,6 @@ Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size) } -Assembler::~Assembler() { - if (own_buffer_) { - if (isolate()->assembler_spare_buffer() == NULL && - buffer_size_ == kMinimalBufferSize) { - isolate()->set_assembler_spare_buffer(buffer_); - } else { - DeleteArray(buffer_); - } - } -} - - void Assembler::GetCode(CodeDesc* desc) { ASSERT(pc_ <= reloc_info_writer.pos()); // No overlap. // Set up code descriptor. @@ -580,17 +534,20 @@ bool Assembler::IsNop(Instr instr, unsigned int type) { // See Assembler::nop(type). ASSERT(type < 32); uint32_t opcode = GetOpcodeField(instr); + uint32_t function = GetFunctionField(instr); uint32_t rt = GetRt(instr); - uint32_t rs = GetRs(instr); + uint32_t rd = GetRd(instr); uint32_t sa = GetSa(instr); - // nop(type) == sll(zero_reg, zero_reg, type); - // Technically all these values will be 0 but - // this makes more sense to the reader. + // Traditional mips nop == sll(zero_reg, zero_reg, 0) + // When marking non-zero type, use sll(zero_reg, at, type) + // to avoid use of mips ssnop and ehb special encodings + // of the sll instruction. - bool ret = (opcode == SLL && - rt == static_cast<uint32_t>(ToNumber(zero_reg)) && - rs == static_cast<uint32_t>(ToNumber(zero_reg)) && + Register nop_rt_reg = (type == 0) ? zero_reg : at; + bool ret = (opcode == SPECIAL && function == SLL && + rd == static_cast<uint32_t>(ToNumber(zero_reg)) && + rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) && sa == type); return ret; diff --git a/deps/v8/src/mips/assembler-mips.h b/deps/v8/src/mips/assembler-mips.h index 7163770178..75d110a36c 100644 --- a/deps/v8/src/mips/assembler-mips.h +++ b/deps/v8/src/mips/assembler-mips.h @@ -318,12 +318,15 @@ const FPURegister f31 = { 31 }; // Register aliases. // cp is assumed to be a callee saved register. -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 DoubleRegister& kLithiumScratchDouble = f30; -static const FPURegister& kDoubleRegZero = f28; +// Defined using #define instead of "static const Register&" because Clang +// complains otherwise when a compilation unit that includes this header +// doesn't use the variables. +#define kRootRegister s6 +#define cp s7 +#define kLithiumScratchReg s3 +#define kLithiumScratchReg2 s4 +#define kLithiumScratchDouble f30 +#define kDoubleRegZero f28 // FPU (coprocessor 1) control registers. // Currently only FCSR (#31) is implemented. @@ -520,13 +523,7 @@ class Assembler : public AssemblerBase { // is too small, a fatal error occurs. No deallocation of the buffer is done // upon destruction of the assembler. Assembler(Isolate* isolate, void* buffer, int buffer_size); - ~Assembler(); - - // Overrides the default provided by FLAG_debug_code. - void set_emit_debug_code(bool value) { emit_debug_code_ = value; } - - // Dummy for cross platform compatibility. - void set_predictable_code_size(bool value) { } + virtual ~Assembler() { } // GetCode emits any pending (non-emitted) code and fills the descriptor // desc. GetCode() is idempotent; it returns the same result if no other @@ -571,6 +568,10 @@ class Assembler : public AssemblerBase { static Address target_address_at(Address pc); static void set_target_address_at(Address pc, Address target); + // Return the code target address at a call site from the return address + // of that call in the instruction stream. + inline static Address target_address_from_return_address(Address pc); + static void JumpLabelToJumpRegister(Address pc); static void QuietNaN(HeapObject* nan); @@ -631,6 +632,8 @@ class Assembler : public AssemblerBase { // register. static const int kPcLoadDelta = 4; + static const int kPatchDebugBreakSlotReturnOffset = 4 * kInstrSize; + // Number of instructions used for the JS return sequence. The constant is // used by the debugger to patch the JS return sequence. static const int kJSReturnSequenceInstructions = 7; @@ -660,13 +663,18 @@ class Assembler : public AssemblerBase { PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE, // Helper values. LAST_CODE_MARKER, - FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED + FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED, + // Code aging + CODE_AGE_MARKER_NOP = 6 }; - // Type == 0 is the default non-marking type. + // Type == 0 is the default non-marking nop. For mips this is a + // sll(zero_reg, zero_reg, 0). We use rt_reg == at for non-zero + // marking, to avoid conflict with ssnop and ehb instructions. void nop(unsigned int type = 0) { ASSERT(type < 32); - sll(zero_reg, zero_reg, type, true); + Register nop_rt_reg = (type == 0) ? zero_reg : at; + sll(zero_reg, nop_rt_reg, type, true); } @@ -935,8 +943,6 @@ class Assembler : public AssemblerBase { void db(uint8_t data); void dd(uint32_t data); - int32_t pc_offset() const { return pc_ - buffer_; } - PositionsRecorder* positions_recorder() { return &positions_recorder_; } // Postpone the generation of the trampoline pool for the specified number of @@ -1021,8 +1027,6 @@ class Assembler : public AssemblerBase { // the relocation info. TypeFeedbackId recorded_ast_id_; - bool emit_debug_code() const { return emit_debug_code_; } - int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; } // Decode branch instruction at pos and return branch target pos. @@ -1081,13 +1085,6 @@ class Assembler : public AssemblerBase { } private: - // Code buffer: - // The buffer into which code and relocation info are generated. - byte* buffer_; - int buffer_size_; - // True if the assembler owns the buffer, false if buffer is external. - bool own_buffer_; - // Buffer size and constant pool distance are checked together at regular // intervals of kBufferCheckInterval emitted bytes. static const int kBufferCheckInterval = 1*KB/2; @@ -1098,7 +1095,6 @@ class Assembler : public AssemblerBase { // not have to check for overflow. The same is true for writes of large // relocation info entries. static const int kGap = 32; - byte* pc_; // The program counter - moves forward. // Repeated checking whether the trampoline pool should be emitted is rather @@ -1273,7 +1269,6 @@ class Assembler : public AssemblerBase { friend class BlockTrampolinePoolScope; PositionsRecorder positions_recorder_; - bool emit_debug_code_; friend class PositionsRecorder; friend class EnsureSpace; }; diff --git a/deps/v8/src/mips/builtins-mips.cc b/deps/v8/src/mips/builtins-mips.cc index 0342e6505d..b2348fca20 100644 --- a/deps/v8/src/mips/builtins-mips.cc +++ b/deps/v8/src/mips/builtins-mips.cc @@ -1255,6 +1255,48 @@ void Builtins::Generate_LazyRecompile(MacroAssembler* masm) { } +static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) { + // For now, we are relying on the fact that make_code_young doesn't do any + // garbage collection which allows us to save/restore the registers without + // worrying about which of them contain pointers. We also don't build an + // internal frame to make the code faster, since we shouldn't have to do stack + // crawls in MakeCodeYoung. This seems a bit fragile. + + __ mov(a0, ra); + // Adjust a0 to point to the head of the PlatformCodeAge sequence + __ Subu(a0, a0, + Operand((kNoCodeAgeSequenceLength - 1) * Assembler::kInstrSize)); + // Restore the original return address of the function + __ mov(ra, at); + + // The following registers must be saved and restored when calling through to + // the runtime: + // a0 - contains return address (beginning of patch sequence) + // a1 - function object + RegList saved_regs = + (a0.bit() | a1.bit() | ra.bit() | fp.bit()) & ~sp.bit(); + FrameScope scope(masm, StackFrame::MANUAL); + __ MultiPush(saved_regs); + __ PrepareCallCFunction(1, 0, a1); + __ CallCFunction( + ExternalReference::get_make_code_young_function(masm->isolate()), 1); + __ MultiPop(saved_regs); + __ Jump(a0); +} + +#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \ +void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \ + MacroAssembler* masm) { \ + GenerateMakeCodeYoungAgainCommon(masm); \ +} \ +void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \ + MacroAssembler* masm) { \ + GenerateMakeCodeYoungAgainCommon(masm); \ +} +CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR) +#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR + + static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, Deoptimizer::BailoutType type) { { diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc index a5c80b8471..a05cee86bb 100644 --- a/deps/v8/src/mips/code-stubs-mips.cc +++ b/deps/v8/src/mips/code-stubs-mips.cc @@ -42,8 +42,7 @@ namespace internal { static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, - Condition cc, - bool never_nan_nan); + Condition cc); static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs, Register rhs, @@ -627,24 +626,6 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm, } -void FloatingPointHelper::LoadOperands( - MacroAssembler* masm, - FloatingPointHelper::Destination destination, - Register heap_number_map, - Register scratch1, - Register scratch2, - Label* slow) { - - // Load right operand (a0) to f12 or a2/a3. - LoadNumber(masm, destination, - a0, f14, a2, a3, heap_number_map, scratch1, scratch2, slow); - - // Load left operand (a1) to f14 or a0/a1. - LoadNumber(masm, destination, - a1, f12, a0, a1, heap_number_map, scratch1, scratch2, slow); -} - - void FloatingPointHelper::LoadNumber(MacroAssembler* masm, Destination destination, Register object, @@ -655,11 +636,9 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm, Register scratch1, Register scratch2, Label* not_number) { - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); Label is_smi, done; @@ -721,11 +700,9 @@ void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm, Register scratch3, FPURegister double_scratch, Label* not_number) { - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); Label done; Label not_in_int32_range; @@ -757,13 +734,13 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm, Register int_scratch, Destination destination, FPURegister double_dst, - Register dst1, - Register dst2, + Register dst_mantissa, + Register dst_exponent, Register scratch2, FPURegister single_scratch) { ASSERT(!int_scratch.is(scratch2)); - ASSERT(!int_scratch.is(dst1)); - ASSERT(!int_scratch.is(dst2)); + ASSERT(!int_scratch.is(dst_mantissa)); + ASSERT(!int_scratch.is(dst_exponent)); Label done; @@ -772,64 +749,65 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm, __ mtc1(int_scratch, single_scratch); __ cvt_d_w(double_dst, single_scratch); if (destination == kCoreRegisters) { - __ Move(dst1, dst2, double_dst); + __ Move(dst_mantissa, dst_exponent, double_dst); } } else { Label fewer_than_20_useful_bits; // Expected output: - // | dst2 | dst1 | + // | dst_exponent | dst_mantissa | // | s | exp | mantissa | // Check for zero. - __ mov(dst2, int_scratch); - __ mov(dst1, int_scratch); + __ mov(dst_exponent, int_scratch); + __ mov(dst_mantissa, int_scratch); __ Branch(&done, eq, int_scratch, Operand(zero_reg)); // Preload the sign of the value. - __ And(dst2, int_scratch, Operand(HeapNumber::kSignMask)); + __ And(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask)); // Get the absolute value of the object (as an unsigned integer). Label skip_sub; - __ Branch(&skip_sub, ge, dst2, Operand(zero_reg)); + __ Branch(&skip_sub, ge, dst_exponent, Operand(zero_reg)); __ Subu(int_scratch, zero_reg, int_scratch); __ bind(&skip_sub); // Get mantissa[51:20]. // Get the position of the first set bit. - __ Clz(dst1, int_scratch); + __ Clz(dst_mantissa, int_scratch); __ li(scratch2, 31); - __ Subu(dst1, scratch2, dst1); + __ Subu(dst_mantissa, scratch2, dst_mantissa); // Set the exponent. - __ Addu(scratch2, dst1, Operand(HeapNumber::kExponentBias)); - __ Ins(dst2, scratch2, + __ Addu(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias)); + __ Ins(dst_exponent, scratch2, HeapNumber::kExponentShift, HeapNumber::kExponentBits); // Clear the first non null bit. __ li(scratch2, Operand(1)); - __ sllv(scratch2, scratch2, dst1); + __ sllv(scratch2, scratch2, dst_mantissa); __ li(at, -1); __ Xor(scratch2, scratch2, at); __ And(int_scratch, int_scratch, scratch2); // Get the number of bits to set in the lower part of the mantissa. - __ Subu(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord)); + __ Subu(scratch2, dst_mantissa, + Operand(HeapNumber::kMantissaBitsInTopWord)); __ Branch(&fewer_than_20_useful_bits, lt, scratch2, Operand(zero_reg)); // Set the higher 20 bits of the mantissa. __ srlv(at, int_scratch, scratch2); - __ or_(dst2, dst2, at); + __ or_(dst_exponent, dst_exponent, at); __ li(at, 32); __ subu(scratch2, at, scratch2); - __ sllv(dst1, int_scratch, scratch2); + __ sllv(dst_mantissa, int_scratch, scratch2); __ Branch(&done); __ bind(&fewer_than_20_useful_bits); __ li(at, HeapNumber::kMantissaBitsInTopWord); - __ subu(scratch2, at, dst1); + __ subu(scratch2, at, dst_mantissa); __ sllv(scratch2, int_scratch, scratch2); - __ Or(dst2, dst2, scratch2); - // Set dst1 to 0. - __ mov(dst1, zero_reg); + __ Or(dst_exponent, dst_exponent, scratch2); + // Set dst_mantissa to 0. + __ mov(dst_mantissa, zero_reg); } __ bind(&done); } @@ -839,8 +817,9 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, Register object, Destination destination, DoubleRegister double_dst, - Register dst1, - Register dst2, + DoubleRegister double_scratch, + Register dst_mantissa, + Register dst_exponent, Register heap_number_map, Register scratch1, Register scratch2, @@ -856,16 +835,14 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, __ JumpIfNotSmi(object, &obj_is_not_smi); __ SmiUntag(scratch1, object); - ConvertIntToDouble(masm, scratch1, destination, double_dst, dst1, dst2, - scratch2, single_scratch); + ConvertIntToDouble(masm, scratch1, destination, double_dst, dst_mantissa, + dst_exponent, scratch2, single_scratch); __ Branch(&done); __ bind(&obj_is_not_smi); - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32); // Load the number. @@ -876,9 +853,10 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, Register except_flag = scratch2; __ EmitFPUTruncate(kRoundToZero, - single_scratch, - double_dst, scratch1, + double_dst, + at, + double_scratch, except_flag, kCheckForInexactConversion); @@ -886,27 +864,51 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, __ Branch(not_int32, ne, except_flag, Operand(zero_reg)); if (destination == kCoreRegisters) { - __ Move(dst1, dst2, double_dst); + __ Move(dst_mantissa, dst_exponent, double_dst); } } else { ASSERT(!scratch1.is(object) && !scratch2.is(object)); // Load the double value in the destination registers. - __ lw(dst2, FieldMemOperand(object, HeapNumber::kExponentOffset)); - __ lw(dst1, FieldMemOperand(object, HeapNumber::kMantissaOffset)); + bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent); + if (save_registers) { + // Save both output registers, because the other one probably holds + // an important value too. + __ Push(dst_exponent, dst_mantissa); + } + __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset)); + __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset)); // Check for 0 and -0. - __ And(scratch1, dst1, Operand(~HeapNumber::kSignMask)); - __ Or(scratch1, scratch1, Operand(dst2)); - __ Branch(&done, eq, scratch1, Operand(zero_reg)); + Label zero; + __ And(scratch1, dst_exponent, Operand(~HeapNumber::kSignMask)); + __ Or(scratch1, scratch1, Operand(dst_mantissa)); + __ Branch(&zero, eq, scratch1, Operand(zero_reg)); // Check that the value can be exactly represented by a 32-bit integer. // Jump to not_int32 if that's not the case. - DoubleIs32BitInteger(masm, dst1, dst2, scratch1, scratch2, not_int32); + Label restore_input_and_miss; + DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2, + &restore_input_and_miss); - // dst1 and dst2 were trashed. Reload the double value. - __ lw(dst2, FieldMemOperand(object, HeapNumber::kExponentOffset)); - __ lw(dst1, FieldMemOperand(object, HeapNumber::kMantissaOffset)); + // dst_* were trashed. Reload the double value. + if (save_registers) { + __ Pop(dst_exponent, dst_mantissa); + } + __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset)); + __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset)); + __ Branch(&done); + + __ bind(&restore_input_and_miss); + if (save_registers) { + __ Pop(dst_exponent, dst_mantissa); + } + __ Branch(not_int32); + + __ bind(&zero); + if (save_registers) { + __ Drop(2); + } } __ bind(&done); @@ -920,7 +922,8 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm, Register scratch1, Register scratch2, Register scratch3, - DoubleRegister double_scratch, + DoubleRegister double_scratch0, + DoubleRegister double_scratch1, Label* not_int32) { ASSERT(!dst.is(object)); ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object)); @@ -928,38 +931,34 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm, !scratch1.is(scratch3) && !scratch2.is(scratch3)); - Label done; + Label done, maybe_undefined; __ UntagAndJumpIfSmi(dst, object, &done); - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } - __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32); + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); + + __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, &maybe_undefined); // Object is a heap number. // Convert the floating point value to a 32-bit integer. if (CpuFeatures::IsSupported(FPU)) { CpuFeatures::Scope scope(FPU); // Load the double value. - __ ldc1(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset)); + __ ldc1(double_scratch0, FieldMemOperand(object, HeapNumber::kValueOffset)); - FPURegister single_scratch = double_scratch.low(); Register except_flag = scratch2; __ EmitFPUTruncate(kRoundToZero, - single_scratch, - double_scratch, + dst, + double_scratch0, scratch1, + double_scratch1, except_flag, kCheckForInexactConversion); // Jump to not_int32 if the operation did not succeed. __ Branch(not_int32, ne, except_flag, Operand(zero_reg)); - // Get the result in the destination register. - __ mfc1(dst, single_scratch); - } else { // Load the double value in the destination registers. __ lw(scratch2, FieldMemOperand(object, HeapNumber::kExponentOffset)); @@ -991,20 +990,28 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm, __ Subu(dst, zero_reg, dst); __ bind(&skip_sub); } + __ Branch(&done); + + __ bind(&maybe_undefined); + __ LoadRoot(at, Heap::kUndefinedValueRootIndex); + __ Branch(not_int32, ne, object, Operand(at)); + // |undefined| is truncated to 0. + __ li(dst, Operand(Smi::FromInt(0))); + // Fall through. __ bind(&done); } void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm, - Register src1, - Register src2, + Register src_exponent, + Register src_mantissa, Register dst, Register scratch, Label* not_int32) { // Get exponent alone in scratch. __ Ext(scratch, - src1, + src_exponent, HeapNumber::kExponentShift, HeapNumber::kExponentBits); @@ -1024,11 +1031,11 @@ void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm, // Another way to put it is that if (exponent - signbit) > 30 then the // number cannot be represented as an int32. Register tmp = dst; - __ srl(at, src1, 31); + __ srl(at, src_exponent, 31); __ subu(tmp, scratch, at); __ Branch(not_int32, gt, tmp, Operand(30)); // - Bits [21:0] in the mantissa are not null. - __ And(tmp, src2, 0x3fffff); + __ And(tmp, src_mantissa, 0x3fffff); __ Branch(not_int32, ne, tmp, Operand(zero_reg)); // Otherwise the exponent needs to be big enough to shift left all the @@ -1039,20 +1046,20 @@ void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm, // Get the 32 higher bits of the mantissa in dst. __ Ext(dst, - src2, + src_mantissa, HeapNumber::kMantissaBitsInTopWord, 32 - HeapNumber::kMantissaBitsInTopWord); - __ sll(at, src1, HeapNumber::kNonMantissaBitsInTopWord); + __ sll(at, src_exponent, HeapNumber::kNonMantissaBitsInTopWord); __ or_(dst, dst, at); // Create the mask and test the lower bits (of the higher bits). __ li(at, 32); __ subu(scratch, at, scratch); - __ li(src2, 1); - __ sllv(src1, src2, scratch); - __ Subu(src1, src1, Operand(1)); - __ And(src1, dst, src1); - __ Branch(not_int32, ne, src1, Operand(zero_reg)); + __ li(src_mantissa, 1); + __ sllv(src_exponent, src_mantissa, scratch); + __ Subu(src_exponent, src_exponent, Operand(1)); + __ And(src_exponent, dst, src_exponent); + __ Branch(not_int32, ne, src_exponent, Operand(zero_reg)); } @@ -1191,48 +1198,43 @@ void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { // for "identity and not NaN". static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, - Condition cc, - bool never_nan_nan) { + Condition cc) { Label not_identical; Label heap_number, return_equal; Register exp_mask_reg = t5; __ Branch(¬_identical, ne, a0, Operand(a1)); - // The two objects are identical. If we know that one of them isn't NaN then - // we now know they test equal. - if (cc != eq || !never_nan_nan) { - __ li(exp_mask_reg, Operand(HeapNumber::kExponentMask)); - - // Test for NaN. Sadly, we can't just compare to factory->nan_value(), - // so we do the second best thing - test it ourselves. - // They are both equal and they are not both Smis so both of them are not - // Smis. If it's not a heap number, then return equal. - if (cc == less || cc == greater) { - __ GetObjectType(a0, t4, t4); - __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE)); - } else { - __ GetObjectType(a0, t4, t4); - __ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE)); - // Comparing JS objects with <=, >= is complicated. - if (cc != eq) { - __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE)); - // Normally here we fall through to return_equal, but undefined is - // special: (undefined == undefined) == true, but - // (undefined <= undefined) == false! See ECMAScript 11.8.5. - if (cc == less_equal || cc == greater_equal) { - __ Branch(&return_equal, ne, t4, Operand(ODDBALL_TYPE)); - __ LoadRoot(t2, Heap::kUndefinedValueRootIndex); - __ Branch(&return_equal, ne, a0, Operand(t2)); - if (cc == le) { - // undefined <= undefined should fail. - __ li(v0, Operand(GREATER)); - } else { - // undefined >= undefined should fail. - __ li(v0, Operand(LESS)); - } - __ Ret(); + __ li(exp_mask_reg, Operand(HeapNumber::kExponentMask)); + + // Test for NaN. Sadly, we can't just compare to factory->nan_value(), + // so we do the second best thing - test it ourselves. + // They are both equal and they are not both Smis so both of them are not + // Smis. If it's not a heap number, then return equal. + if (cc == less || cc == greater) { + __ GetObjectType(a0, t4, t4); + __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE)); + } else { + __ GetObjectType(a0, t4, t4); + __ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE)); + // Comparing JS objects with <=, >= is complicated. + if (cc != eq) { + __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE)); + // Normally here we fall through to return_equal, but undefined is + // special: (undefined == undefined) == true, but + // (undefined <= undefined) == false! See ECMAScript 11.8.5. + if (cc == less_equal || cc == greater_equal) { + __ Branch(&return_equal, ne, t4, Operand(ODDBALL_TYPE)); + __ LoadRoot(t2, Heap::kUndefinedValueRootIndex); + __ Branch(&return_equal, ne, a0, Operand(t2)); + if (cc == le) { + // undefined <= undefined should fail. + __ li(v0, Operand(GREATER)); + } else { + // undefined >= undefined should fail. + __ li(v0, Operand(LESS)); } + __ Ret(); } } } @@ -1248,46 +1250,44 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, } __ Ret(); - if (cc != eq || !never_nan_nan) { - // For less and greater we don't have to check for NaN since the result of - // x < x is false regardless. For the others here is some code to check - // for NaN. - if (cc != lt && cc != gt) { - __ bind(&heap_number); - // It is a heap number, so return non-equal if it's NaN and equal if it's - // not NaN. - - // The representation of NaN values has all exponent bits (52..62) set, - // and not all mantissa bits (0..51) clear. - // Read top bits of double representation (second word of value). - __ lw(t2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); - // Test that exponent bits are all set. - __ And(t3, t2, Operand(exp_mask_reg)); - // If all bits not set (ne cond), then not a NaN, objects are equal. - __ Branch(&return_equal, ne, t3, Operand(exp_mask_reg)); - - // Shift out flag and all exponent bits, retaining only mantissa. - __ sll(t2, t2, HeapNumber::kNonMantissaBitsInTopWord); - // Or with all low-bits of mantissa. - __ lw(t3, FieldMemOperand(a0, HeapNumber::kMantissaOffset)); - __ Or(v0, t3, Operand(t2)); - // For equal we already have the right value in v0: Return zero (equal) - // if all bits in mantissa are zero (it's an Infinity) and non-zero if - // not (it's a NaN). For <= and >= we need to load v0 with the failing - // value if it's a NaN. - if (cc != eq) { - // All-zero means Infinity means equal. - __ Ret(eq, v0, Operand(zero_reg)); - if (cc == le) { - __ li(v0, Operand(GREATER)); // NaN <= NaN should fail. - } else { - __ li(v0, Operand(LESS)); // NaN >= NaN should fail. - } + // For less and greater we don't have to check for NaN since the result of + // x < x is false regardless. For the others here is some code to check + // for NaN. + if (cc != lt && cc != gt) { + __ bind(&heap_number); + // It is a heap number, so return non-equal if it's NaN and equal if it's + // not NaN. + + // The representation of NaN values has all exponent bits (52..62) set, + // and not all mantissa bits (0..51) clear. + // Read top bits of double representation (second word of value). + __ lw(t2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); + // Test that exponent bits are all set. + __ And(t3, t2, Operand(exp_mask_reg)); + // If all bits not set (ne cond), then not a NaN, objects are equal. + __ Branch(&return_equal, ne, t3, Operand(exp_mask_reg)); + + // Shift out flag and all exponent bits, retaining only mantissa. + __ sll(t2, t2, HeapNumber::kNonMantissaBitsInTopWord); + // Or with all low-bits of mantissa. + __ lw(t3, FieldMemOperand(a0, HeapNumber::kMantissaOffset)); + __ Or(v0, t3, Operand(t2)); + // For equal we already have the right value in v0: Return zero (equal) + // if all bits in mantissa are zero (it's an Infinity) and non-zero if + // not (it's a NaN). For <= and >= we need to load v0 with the failing + // value if it's a NaN. + if (cc != eq) { + // All-zero means Infinity means equal. + __ Ret(eq, v0, Operand(zero_reg)); + if (cc == le) { + __ li(v0, Operand(GREATER)); // NaN <= NaN should fail. + } else { + __ li(v0, Operand(LESS)); // NaN >= NaN should fail. } - __ Ret(); } - // No fall through here. + __ Ret(); } + // No fall through here. __ bind(¬_identical); } @@ -1760,43 +1760,61 @@ void NumberToStringStub::Generate(MacroAssembler* masm) { } -// On entry lhs_ (lhs) and rhs_ (rhs) are the things to be compared. -// On exit, v0 is 0, positive, or negative (smi) to indicate the result -// of the comparison. -void CompareStub::Generate(MacroAssembler* masm) { - Label slow; // Call builtin. - Label not_smis, both_loaded_as_doubles; +static void ICCompareStub_CheckInputType(MacroAssembler* masm, + Register input, + Register scratch, + CompareIC::State expected, + Label* fail) { + Label ok; + if (expected == CompareIC::SMI) { + __ JumpIfNotSmi(input, fail); + } else if (expected == CompareIC::HEAP_NUMBER) { + __ JumpIfSmi(input, &ok); + __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail, + DONT_DO_SMI_CHECK); + } + // We could be strict about symbol/string here, but as long as + // hydrogen doesn't care, the stub doesn't have to care either. + __ bind(&ok); +} - if (include_smi_compare_) { - Label not_two_smis, smi_done; - __ Or(a2, a1, a0); - __ JumpIfNotSmi(a2, ¬_two_smis); - __ sra(a1, a1, 1); - __ sra(a0, a0, 1); - __ Ret(USE_DELAY_SLOT); - __ subu(v0, a1, a0); - __ bind(¬_two_smis); - } else if (FLAG_debug_code) { - __ Or(a2, a1, a0); - __ And(a2, a2, kSmiTagMask); - __ Assert(ne, "CompareStub: unexpected smi operands.", - a2, Operand(zero_reg)); - } +// On entry a1 and a2 are the values to be compared. +// On exit a0 is 0, positive or negative to indicate the result of +// the comparison. +void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { + Register lhs = a1; + Register rhs = a0; + Condition cc = GetCondition(); + Label miss; + ICCompareStub_CheckInputType(masm, lhs, a2, left_, &miss); + ICCompareStub_CheckInputType(masm, rhs, a3, right_, &miss); + + Label slow; // Call builtin. + Label not_smis, both_loaded_as_doubles; + + Label not_two_smis, smi_done; + __ Or(a2, a1, a0); + __ JumpIfNotSmi(a2, ¬_two_smis); + __ sra(a1, a1, 1); + __ sra(a0, a0, 1); + __ Ret(USE_DELAY_SLOT); + __ subu(v0, a1, a0); + __ bind(¬_two_smis); // NOTICE! This code is only reached after a smi-fast-case check, so // it is certain that at least one operand isn't a smi. // Handle the case where the objects are identical. Either returns the answer // or goes to slow. Only falls through if the objects were not identical. - EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); + EmitIdenticalObjectComparison(masm, &slow, cc); // If either is a Smi (we know that not both are), then they can only // be strictly equal if the other is a HeapNumber. STATIC_ASSERT(kSmiTag == 0); ASSERT_EQ(0, Smi::FromInt(0)); - __ And(t2, lhs_, Operand(rhs_)); + __ And(t2, lhs, Operand(rhs)); __ JumpIfNotSmi(t2, ¬_smis, t0); // One operand is a smi. EmitSmiNonsmiComparison generates code that can: // 1) Return the answer. @@ -1806,8 +1824,8 @@ void CompareStub::Generate(MacroAssembler* masm) { // In cases 3 and 4 we have found out we were dealing with a number-number // comparison and the numbers have been loaded into f12 and f14 as doubles, // or in GP registers (a0, a1, a2, a3) depending on the presence of the FPU. - EmitSmiNonsmiComparison(masm, lhs_, rhs_, - &both_loaded_as_doubles, &slow, strict_); + EmitSmiNonsmiComparison(masm, lhs, rhs, + &both_loaded_as_doubles, &slow, strict()); __ bind(&both_loaded_as_doubles); // f12, f14 are the double representations of the left hand side @@ -1843,7 +1861,7 @@ void CompareStub::Generate(MacroAssembler* masm) { __ bind(&nan); // NaN comparisons always fail. // Load whatever we need in v0 to make the comparison fail. - if (cc_ == lt || cc_ == le) { + if (cc == lt || cc == le) { __ li(v0, Operand(GREATER)); } else { __ li(v0, Operand(LESS)); @@ -1852,20 +1870,20 @@ void CompareStub::Generate(MacroAssembler* masm) { } else { // Checks for NaN in the doubles we have loaded. Can return the answer or // fall through if neither is a NaN. Also binds rhs_not_nan. - EmitNanCheck(masm, cc_); + EmitNanCheck(masm, cc); // Compares two doubles that are not NaNs. Returns the answer. // Never falls through. - EmitTwoNonNanDoubleComparison(masm, cc_); + EmitTwoNonNanDoubleComparison(masm, cc); } __ bind(¬_smis); // At this point we know we are dealing with two different objects, // and neither of them is a Smi. The objects are in lhs_ and rhs_. - if (strict_) { + if (strict()) { // This returns non-equal for some object types, or falls through if it // was not lucky. - EmitStrictTwoHeapObjectCompare(masm, lhs_, rhs_); + EmitStrictTwoHeapObjectCompare(masm, lhs, rhs); } Label check_for_symbols; @@ -1875,38 +1893,38 @@ void CompareStub::Generate(MacroAssembler* masm) { // that case. If the inputs are not doubles then jumps to check_for_symbols. // In this case a2 will contain the type of lhs_. EmitCheckForTwoHeapNumbers(masm, - lhs_, - rhs_, + lhs, + rhs, &both_loaded_as_doubles, &check_for_symbols, &flat_string_check); __ bind(&check_for_symbols); - if (cc_ == eq && !strict_) { + if (cc == eq && !strict()) { // Returns an answer for two symbols or two detectable objects. // Otherwise jumps to string case or not both strings case. // Assumes that a2 is the type of lhs_ on entry. - EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check, &slow); + EmitCheckForSymbolsOrObjects(masm, lhs, rhs, &flat_string_check, &slow); } // Check for both being sequential ASCII strings, and inline if that is the // case. __ bind(&flat_string_check); - __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, a2, a3, &slow); + __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, a2, a3, &slow); __ IncrementCounter(isolate->counters()->string_compare_native(), 1, a2, a3); - if (cc_ == eq) { + if (cc == eq) { StringCompareStub::GenerateFlatAsciiStringEquals(masm, - lhs_, - rhs_, + lhs, + rhs, a2, a3, t0); } else { StringCompareStub::GenerateCompareFlatAsciiStrings(masm, - lhs_, - rhs_, + lhs, + rhs, a2, a3, t0, @@ -1917,18 +1935,18 @@ void CompareStub::Generate(MacroAssembler* masm) { __ bind(&slow); // Prepare for call to builtin. Push object pointers, a0 (lhs) first, // a1 (rhs) second. - __ Push(lhs_, rhs_); + __ Push(lhs, rhs); // Figure out which native to call and setup the arguments. Builtins::JavaScript native; - if (cc_ == eq) { - native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; + if (cc == eq) { + native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; } else { native = Builtins::COMPARE; int ncr; // NaN compare result. - if (cc_ == lt || cc_ == le) { + if (cc == lt || cc == le) { ncr = GREATER; } else { - ASSERT(cc_ == gt || cc_ == ge); // Remaining cases. + ASSERT(cc == gt || cc == ge); // Remaining cases. ncr = LESS; } __ li(a0, Operand(Smi::FromInt(ncr))); @@ -1938,6 +1956,9 @@ void CompareStub::Generate(MacroAssembler* masm) { // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) // tagged as a small integer. __ InvokeBuiltin(native, JUMP_FUNCTION); + + __ bind(&miss); + GenerateMiss(masm); } @@ -2378,20 +2399,23 @@ void UnaryOpStub::GenerateGenericCodeFallback( } +void BinaryOpStub::Initialize() { + platform_specific_bit_ = CpuFeatures::IsSupported(FPU); +} + + void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { Label get_result; __ Push(a1, a0); __ li(a2, Operand(Smi::FromInt(MinorKey()))); - __ li(a1, Operand(Smi::FromInt(op_))); - __ li(a0, Operand(Smi::FromInt(operands_type_))); - __ Push(a2, a1, a0); + __ push(a2); __ TailCallExternalReference( ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()), - 5, + 3, 1); } @@ -2402,59 +2426,8 @@ void BinaryOpStub::GenerateTypeTransitionWithSavedArgs( } -void BinaryOpStub::Generate(MacroAssembler* masm) { - // Explicitly allow generation of nested stubs. It is safe here because - // generation code does not use any raw pointers. - AllowStubCallsScope allow_stub_calls(masm, true); - switch (operands_type_) { - case BinaryOpIC::UNINITIALIZED: - GenerateTypeTransition(masm); - break; - case BinaryOpIC::SMI: - GenerateSmiStub(masm); - break; - case BinaryOpIC::INT32: - GenerateInt32Stub(masm); - break; - case BinaryOpIC::HEAP_NUMBER: - GenerateHeapNumberStub(masm); - break; - case BinaryOpIC::ODDBALL: - GenerateOddballStub(masm); - break; - case BinaryOpIC::BOTH_STRING: - GenerateBothStringStub(masm); - break; - case BinaryOpIC::STRING: - GenerateStringStub(masm); - break; - case BinaryOpIC::GENERIC: - GenerateGeneric(masm); - break; - default: - UNREACHABLE(); - } -} - - -void BinaryOpStub::PrintName(StringStream* stream) { - const char* op_name = Token::Name(op_); - const char* overwrite_name; - switch (mode_) { - case NO_OVERWRITE: overwrite_name = "Alloc"; break; - case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; - case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; - default: overwrite_name = "UnknownOverwrite"; break; - } - stream->Add("BinaryOpStub_%s_%s_%s", - op_name, - overwrite_name, - BinaryOpIC::GetName(operands_type_)); -} - - - -void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) { +void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm, + Token::Value op) { Register left = a1; Register right = a0; @@ -2465,7 +2438,7 @@ void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) { STATIC_ASSERT(kSmiTag == 0); Label not_smi_result; - switch (op_) { + switch (op) { case Token::ADD: __ AdduAndCheckForOverflow(v0, left, right, scratch1); __ RetOnNoOverflow(scratch1); @@ -2608,10 +2581,24 @@ void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) { } -void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, - bool smi_operands, - Label* not_numbers, - Label* gc_required) { +void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, + Register result, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* gc_required, + OverwriteMode mode); + + +void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, + BinaryOpIC::TypeInfo left_type, + BinaryOpIC::TypeInfo right_type, + bool smi_operands, + Label* not_numbers, + Label* gc_required, + Label* miss, + Token::Value op, + OverwriteMode mode) { Register left = a1; Register right = a0; Register scratch1 = t3; @@ -2619,15 +2606,21 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, Register scratch3 = t0; ASSERT(smi_operands || (not_numbers != NULL)); - if (smi_operands && FLAG_debug_code) { - __ AbortIfNotSmi(left); - __ AbortIfNotSmi(right); + if (smi_operands) { + __ AssertSmi(left); + __ AssertSmi(right); + } + if (left_type == BinaryOpIC::SMI) { + __ JumpIfNotSmi(left, miss); + } + if (right_type == BinaryOpIC::SMI) { + __ JumpIfNotSmi(right, miss); } Register heap_number_map = t2; __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); - switch (op_) { + switch (op) { case Token::ADD: case Token::SUB: case Token::MUL: @@ -2637,25 +2630,44 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, // depending on whether FPU is available or not. FloatingPointHelper::Destination destination = CpuFeatures::IsSupported(FPU) && - op_ != Token::MOD ? + op != Token::MOD ? FloatingPointHelper::kFPURegisters : FloatingPointHelper::kCoreRegisters; // Allocate new heap number for result. Register result = s0; - GenerateHeapResultAllocation( - masm, result, heap_number_map, scratch1, scratch2, gc_required); + BinaryOpStub_GenerateHeapResultAllocation( + masm, result, heap_number_map, scratch1, scratch2, gc_required, mode); // Load the operands. if (smi_operands) { FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); } else { - FloatingPointHelper::LoadOperands(masm, - destination, - heap_number_map, - scratch1, - scratch2, - not_numbers); + // Load right operand to f14 or a2/a3. + if (right_type == BinaryOpIC::INT32) { + FloatingPointHelper::LoadNumberAsInt32Double( + masm, right, destination, f14, f16, a2, a3, heap_number_map, + scratch1, scratch2, f2, miss); + } else { + Label* fail = (right_type == BinaryOpIC::HEAP_NUMBER) ? miss + : not_numbers; + FloatingPointHelper::LoadNumber( + masm, destination, right, f14, a2, a3, heap_number_map, + scratch1, scratch2, fail); + } + // Load left operand to f12 or a0/a1. This keeps a0/a1 intact if it + // jumps to |miss|. + if (left_type == BinaryOpIC::INT32) { + FloatingPointHelper::LoadNumberAsInt32Double( + masm, left, destination, f12, f16, a0, a1, heap_number_map, + scratch1, scratch2, f2, miss); + } else { + Label* fail = (left_type == BinaryOpIC::HEAP_NUMBER) ? miss + : not_numbers; + FloatingPointHelper::LoadNumber( + masm, destination, left, f12, a0, a1, heap_number_map, + scratch1, scratch2, fail); + } } // Calculate the result. @@ -2664,7 +2676,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, // f12: Left value. // f14: Right value. CpuFeatures::Scope scope(FPU); - switch (op_) { + switch (op) { case Token::ADD: __ add_d(f10, f12, f14); break; @@ -2690,7 +2702,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, } else { // Call the C function to handle the double operation. FloatingPointHelper::CallCCodeForDoubleOperation(masm, - op_, + op, result, scratch1); if (FLAG_debug_code) { @@ -2730,7 +2742,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, not_numbers); } Label result_not_a_smi; - switch (op_) { + switch (op) { case Token::BIT_OR: __ Or(a2, a3, Operand(a2)); break; @@ -2780,8 +2792,9 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, __ AllocateHeapNumber( result, scratch1, scratch2, heap_number_map, gc_required); } else { - GenerateHeapResultAllocation( - masm, result, heap_number_map, scratch1, scratch2, gc_required); + BinaryOpStub_GenerateHeapResultAllocation( + masm, result, heap_number_map, scratch1, scratch2, gc_required, + mode); } // a2: Answer as signed int32. @@ -2796,7 +2809,7 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, // mentioned above SHR needs to always produce a positive result. CpuFeatures::Scope scope(FPU); __ mtc1(a2, f0); - if (op_ == Token::SHR) { + if (op == Token::SHR) { __ Cvt_d_uw(f0, f0, f22); } else { __ cvt_d_w(f0, f0); @@ -2823,12 +2836,14 @@ void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, // Generate the smi code. If the operation on smis are successful this return is // generated. If the result is not a smi and heap number allocation is not // requested the code falls through. If number allocation is requested but a -// heap number cannot be allocated the code jumps to the lable gc_required. -void BinaryOpStub::GenerateSmiCode( +// heap number cannot be allocated the code jumps to the label gc_required. +void BinaryOpStub_GenerateSmiCode( MacroAssembler* masm, Label* use_runtime, Label* gc_required, - SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { + Token::Value op, + BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results, + OverwriteMode mode) { Label not_smis; Register left = a1; @@ -2841,12 +2856,14 @@ void BinaryOpStub::GenerateSmiCode( __ JumpIfNotSmi(scratch1, ¬_smis); // If the smi-smi operation results in a smi return is generated. - GenerateSmiSmiOperation(masm); + BinaryOpStub_GenerateSmiSmiOperation(masm, op); // If heap number results are possible generate the result in an allocated // heap number. - if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { - GenerateFPOperation(masm, true, use_runtime, gc_required); + if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) { + BinaryOpStub_GenerateFPOperation( + masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true, + use_runtime, gc_required, ¬_smis, op, mode); } __ bind(¬_smis); } @@ -2858,14 +2875,14 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { if (result_type_ == BinaryOpIC::UNINITIALIZED || result_type_ == BinaryOpIC::SMI) { // Only allow smi results. - GenerateSmiCode(masm, &call_runtime, NULL, NO_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, NULL, op_, NO_HEAPNUMBER_RESULTS, mode_); } else { // Allow heap number result and don't make a transition if a heap number // cannot be allocated. - GenerateSmiCode(masm, - &call_runtime, - &call_runtime, - ALLOW_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS, + mode_); } // Code falls through if the result is not returned as either a smi or heap @@ -2873,22 +2890,14 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { GenerateTypeTransition(masm); __ bind(&call_runtime); + GenerateRegisterArgsPush(masm); GenerateCallRuntime(masm); } -void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { - ASSERT(operands_type_ == BinaryOpIC::STRING); - // Try to add arguments as strings, otherwise, transition to the generic - // BinaryOpIC type. - GenerateAddStrings(masm); - GenerateTypeTransition(masm); -} - - void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { Label call_runtime; - ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); + ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING); ASSERT(op_ == Token::ADD); // If both arguments are strings, call the string add stub. // Otherwise, do a transition. @@ -2917,7 +2926,7 @@ void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { - ASSERT(operands_type_ == BinaryOpIC::INT32); + ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); Register left = a1; Register right = a0; @@ -2940,7 +2949,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Label skip; __ Or(scratch1, left, right); __ JumpIfNotSmi(scratch1, &skip); - GenerateSmiSmiOperation(masm); + BinaryOpStub_GenerateSmiSmiOperation(masm, op_); // Fall through if the result is not a smi. __ bind(&skip); @@ -2950,6 +2959,15 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { case Token::MUL: case Token::DIV: case Token::MOD: { + // It could be that only SMIs have been seen at either the left + // or the right operand. For precise type feedback, patch the IC + // again if this changes. + if (left_type_ == BinaryOpIC::SMI) { + __ JumpIfNotSmi(left, &transition); + } + if (right_type_ == BinaryOpIC::SMI) { + __ JumpIfNotSmi(right, &transition); + } // Load both operands and check that they are 32-bit integer. // Jump to type transition if they are not. The registers a0 and a1 (right // and left) are preserved for the runtime call. @@ -2962,6 +2980,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { right, destination, f14, + f16, a2, a3, heap_number_map, @@ -2973,6 +2992,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { left, destination, f12, + f16, t0, t1, heap_number_map, @@ -3009,9 +3029,10 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Register except_flag = scratch2; __ EmitFPUTruncate(kRoundToZero, - single_scratch, - f10, scratch1, + f10, + at, + f16, except_flag); if (result_type_ <= BinaryOpIC::INT32) { @@ -3020,7 +3041,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { } // Check if the result fits in a smi. - __ mfc1(scratch1, single_scratch); __ Addu(scratch2, scratch1, Operand(0x40000000)); // If not try to return a heap number. __ Branch(&return_heap_number, lt, scratch2, Operand(zero_reg)); @@ -3046,12 +3066,13 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { : BinaryOpIC::INT32)) { // We are using FPU registers so s0 is available. heap_number_result = s0; - GenerateHeapResultAllocation(masm, - heap_number_result, - heap_number_map, - scratch1, - scratch2, - &call_runtime); + BinaryOpStub_GenerateHeapResultAllocation(masm, + heap_number_result, + heap_number_map, + scratch1, + scratch2, + &call_runtime, + mode_); __ mov(v0, heap_number_result); __ sdc1(f10, FieldMemOperand(v0, HeapNumber::kValueOffset)); __ Ret(); @@ -3069,12 +3090,13 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { // Allocate a heap number to store the result. heap_number_result = s0; - GenerateHeapResultAllocation(masm, - heap_number_result, - heap_number_map, - scratch1, - scratch2, - &pop_and_call_runtime); + BinaryOpStub_GenerateHeapResultAllocation(masm, + heap_number_result, + heap_number_map, + scratch1, + scratch2, + &pop_and_call_runtime, + mode_); // Load the left value from the value saved on the stack. __ Pop(a1, a0); @@ -3113,6 +3135,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { scratch2, scratch3, f0, + f2, &transition); FloatingPointHelper::LoadNumberAsInt32(masm, right, @@ -3122,6 +3145,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { scratch2, scratch3, f0, + f2, &transition); // The ECMA-262 standard specifies that, for shift operations, only the @@ -3183,12 +3207,13 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { __ bind(&return_heap_number); heap_number_result = t1; - GenerateHeapResultAllocation(masm, - heap_number_result, - heap_number_map, - scratch1, - scratch2, - &call_runtime); + BinaryOpStub_GenerateHeapResultAllocation(masm, + heap_number_result, + heap_number_map, + scratch1, + scratch2, + &call_runtime, + mode_); if (CpuFeatures::IsSupported(FPU)) { CpuFeatures::Scope scope(FPU); @@ -3232,6 +3257,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { } __ bind(&call_runtime); + GenerateRegisterArgsPush(masm); GenerateCallRuntime(masm); } @@ -3270,20 +3296,32 @@ void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { - Label call_runtime; - GenerateFPOperation(masm, false, &call_runtime, &call_runtime); + Label call_runtime, transition; + BinaryOpStub_GenerateFPOperation( + masm, left_type_, right_type_, false, + &transition, &call_runtime, &transition, op_, mode_); + + __ bind(&transition); + GenerateTypeTransition(masm); __ bind(&call_runtime); + GenerateRegisterArgsPush(masm); GenerateCallRuntime(masm); } void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { - Label call_runtime, call_string_add_or_runtime; + Label call_runtime, call_string_add_or_runtime, transition; - GenerateSmiCode(masm, &call_runtime, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS, mode_); - GenerateFPOperation(masm, false, &call_string_add_or_runtime, &call_runtime); + BinaryOpStub_GenerateFPOperation( + masm, left_type_, right_type_, false, + &call_string_add_or_runtime, &call_runtime, &transition, op_, mode_); + + __ bind(&transition); + GenerateTypeTransition(masm); __ bind(&call_string_add_or_runtime); if (op_ == Token::ADD) { @@ -3291,6 +3329,7 @@ void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { } __ bind(&call_runtime); + GenerateRegisterArgsPush(masm); GenerateCallRuntime(masm); } @@ -3326,63 +3365,20 @@ void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { } -void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { - GenerateRegisterArgsPush(masm); - switch (op_) { - case Token::ADD: - __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); - break; - case Token::SUB: - __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); - break; - case Token::MUL: - __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); - break; - case Token::DIV: - __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); - break; - case Token::MOD: - __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); - break; - case Token::BIT_OR: - __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); - break; - case Token::BIT_AND: - __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); - break; - case Token::BIT_XOR: - __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); - break; - case Token::SAR: - __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); - break; - case Token::SHR: - __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); - break; - case Token::SHL: - __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); - break; - default: - UNREACHABLE(); - } -} - - -void BinaryOpStub::GenerateHeapResultAllocation( - MacroAssembler* masm, - Register result, - Register heap_number_map, - Register scratch1, - Register scratch2, - Label* gc_required) { - +void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, + Register result, + Register heap_number_map, + Register scratch1, + Register scratch2, + Label* gc_required, + OverwriteMode mode) { // Code below will scratch result if allocation fails. To keep both arguments // intact for the runtime call result cannot be one of these. ASSERT(!result.is(a0) && !result.is(a1)); - if (mode_ == OVERWRITE_LEFT || mode_ == OVERWRITE_RIGHT) { + if (mode == OVERWRITE_LEFT || mode == OVERWRITE_RIGHT) { Label skip_allocation, allocated; - Register overwritable_operand = mode_ == OVERWRITE_LEFT ? a1 : a0; + Register overwritable_operand = mode == OVERWRITE_LEFT ? a1 : a0; // If the overwritable operand is already an object, we skip the // allocation of a heap number. __ JumpIfNotSmi(overwritable_operand, &skip_allocation); @@ -3395,7 +3391,7 @@ void BinaryOpStub::GenerateHeapResultAllocation( __ mov(result, overwritable_operand); __ bind(&allocated); } else { - ASSERT(mode_ == NO_OVERWRITE); + ASSERT(mode == NO_OVERWRITE); __ AllocateHeapNumber( result, scratch1, scratch2, heap_number_map, gc_required); } @@ -3716,9 +3712,10 @@ void MathPowStub::Generate(MacroAssembler* masm) { Label int_exponent_convert; // Detect integer exponents stored as double. __ EmitFPUTruncate(kRoundToMinusInf, - single_scratch, - double_exponent, scratch, + double_exponent, + at, + double_scratch, scratch2, kCheckForInexactConversion); // scratch2 == 0 means there was no conversion error. @@ -3776,7 +3773,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ push(ra); { AllowExternalCallThatCantCauseGC scope(masm); - __ PrepareCallCFunction(0, 2, scratch); + __ PrepareCallCFunction(0, 2, scratch2); __ SetCallCDoubleArguments(double_base, double_exponent); __ CallCFunction( ExternalReference::power_double_double_function(masm->isolate()), @@ -3787,7 +3784,6 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ jmp(&done); __ bind(&int_exponent_convert); - __ mfc1(scratch, single_scratch); } // Calculate power with integer exponent. @@ -5091,7 +5087,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // regexp_data: RegExp data (FixedArray) // a0: Instance type of subject string STATIC_ASSERT(kStringEncodingMask == 4); - STATIC_ASSERT(kAsciiStringTag == 4); + STATIC_ASSERT(kOneByteStringTag == 4); STATIC_ASSERT(kTwoByteStringTag == 0); // Find the code object based on the assumptions above. __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ASCII. @@ -5330,7 +5326,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ lw(subject, FieldMemOperand(subject, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ Subu(subject, subject, SeqTwoByteString::kHeaderSize - kHeapObjectTag); @@ -5405,12 +5401,12 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { // Set FixedArray length. __ sll(t2, t1, kSmiTagSize); __ sw(t2, FieldMemOperand(a3, FixedArray::kLengthOffset)); - // Fill contents of fixed-array with the-hole. - __ li(a2, Operand(masm->isolate()->factory()->the_hole_value())); + // Fill contents of fixed-array with undefined. + __ LoadRoot(a2, Heap::kUndefinedValueRootIndex); __ Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - // Fill fixed array elements with hole. + // Fill fixed array elements with undefined. // v0: JSArray, tagged. - // a2: the hole. + // a2: undefined. // a3: Start of elements in FixedArray. // t1: Number of elements to fill. Label loop; @@ -5607,45 +5603,6 @@ void CallConstructStub::Generate(MacroAssembler* masm) { } -// Unfortunately you have to run without snapshots to see most of these -// names in the profile since most compare stubs end up in the snapshot. -void CompareStub::PrintName(StringStream* stream) { - ASSERT((lhs_.is(a0) && rhs_.is(a1)) || - (lhs_.is(a1) && rhs_.is(a0))); - const char* cc_name; - switch (cc_) { - case lt: cc_name = "LT"; break; - case gt: cc_name = "GT"; break; - case le: cc_name = "LE"; break; - case ge: cc_name = "GE"; break; - case eq: cc_name = "EQ"; break; - case ne: cc_name = "NE"; break; - default: cc_name = "UnknownCondition"; break; - } - bool is_equality = cc_ == eq || cc_ == ne; - stream->Add("CompareStub_%s", cc_name); - stream->Add(lhs_.is(a0) ? "_a0" : "_a1"); - stream->Add(rhs_.is(a0) ? "_a0" : "_a1"); - if (strict_ && is_equality) stream->Add("_STRICT"); - if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); - if (!include_number_compare_) stream->Add("_NO_NUMBER"); - if (!include_smi_compare_) stream->Add("_NO_SMI"); -} - - -int CompareStub::MinorKey() { - // Encode the two parameters in a unique 16 bit value. - ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); - ASSERT((lhs_.is(a0) && rhs_.is(a1)) || - (lhs_.is(a1) && rhs_.is(a0))); - return ConditionField::encode(static_cast<unsigned>(cc_)) - | RegisterField::encode(lhs_.is(a0)) - | StrictField::encode(strict_) - | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) - | IncludeSmiCompareField::encode(include_smi_compare_); -} - - // StringCharCodeAtGenerator. void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { Label flat_string; @@ -6079,7 +6036,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, // Check if the two characters match. // Assumes that word load is little endian. - __ lhu(scratch, FieldMemOperand(candidate, SeqAsciiString::kHeaderSize)); + __ lhu(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize)); __ Branch(&found_in_symbol_table, eq, chars, Operand(scratch)); __ bind(&next_probe[i]); } @@ -6258,7 +6215,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { // string's encoding is wrong because we always have to recheck encoding of // the newly created string's parent anyways due to externalized strings. Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ And(t0, a1, Operand(kStringEncodingMask)); __ Branch(&two_byte_slice, eq, t0, Operand(zero_reg)); @@ -6296,12 +6253,12 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ bind(&sequential_string); // Locate first character of underlying subject string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); - __ Addu(t1, t1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); + __ Addu(t1, t1, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ bind(&allocate_result); // Sequential acii string. Allocate the result. - STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); + STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); __ And(t0, a1, Operand(kStringEncodingMask)); __ Branch(&two_byte_sequential, eq, t0, Operand(zero_reg)); @@ -6312,13 +6269,13 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ Addu(t1, t1, a3); // Locate first character of result. - __ Addu(a1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ Addu(a1, v0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); // v0: result string // a1: first character of result string // a2: result string length // t1: first character of substring to copy - STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); + STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); StringHelper::GenerateCopyCharactersLong( masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED); __ jmp(&return_v0); @@ -6450,7 +6407,7 @@ void StringCompareStub::GenerateAsciiCharsCompareLoop( // doesn't need an additional compare. __ SmiUntag(length); __ Addu(scratch1, length, - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ Addu(left, left, Operand(scratch1)); __ Addu(right, right, Operand(scratch1)); __ Subu(length, zero_reg, length); @@ -6605,8 +6562,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { &call_runtime); // Get the two characters forming the sub string. - __ lbu(a2, FieldMemOperand(a0, SeqAsciiString::kHeaderSize)); - __ lbu(a3, FieldMemOperand(a1, SeqAsciiString::kHeaderSize)); + __ lbu(a2, FieldMemOperand(a0, SeqOneByteString::kHeaderSize)); + __ lbu(a3, FieldMemOperand(a1, SeqOneByteString::kHeaderSize)); // Try to lookup two character string in symbol table. If it is not found // just allocate a new one. @@ -6624,7 +6581,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { // in a little endian mode). __ li(t2, Operand(2)); __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime); - __ sh(a2, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); + __ sh(a2, FieldMemOperand(v0, SeqOneByteString::kHeaderSize)); __ IncrementCounter(counters->string_add_native(), 1, a2, a3); __ DropAndRet(2); @@ -6672,11 +6629,6 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ and_(at, at, t1); __ Branch(&ascii_data, ne, at, Operand(zero_reg)); - __ xor_(t0, t0, t1); - STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); - __ And(t0, t0, Operand(kAsciiStringTag | kAsciiDataHintTag)); - __ Branch(&ascii_data, eq, t0, Operand(kAsciiStringTag | kAsciiDataHintTag)); - // Allocate a two byte cons string. __ AllocateTwoByteConsString(v0, t2, t0, t1, &call_runtime); __ Branch(&allocated); @@ -6708,11 +6660,11 @@ void StringAddStub::Generate(MacroAssembler* masm) { STATIC_ASSERT(kSeqStringTag == 0); __ And(t4, t0, Operand(kStringRepresentationMask)); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); Label skip_first_add; __ Branch(&skip_first_add, ne, t4, Operand(zero_reg)); __ Branch(USE_DELAY_SLOT, &first_prepared); - __ addiu(t3, a0, SeqAsciiString::kHeaderSize - kHeapObjectTag); + __ addiu(t3, a0, SeqOneByteString::kHeaderSize - kHeapObjectTag); __ bind(&skip_first_add); // External string: rule out short external string and load string resource. STATIC_ASSERT(kShortExternalStringTag != 0); @@ -6723,11 +6675,11 @@ void StringAddStub::Generate(MacroAssembler* masm) { STATIC_ASSERT(kSeqStringTag == 0); __ And(t4, t1, Operand(kStringRepresentationMask)); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); Label skip_second_add; __ Branch(&skip_second_add, ne, t4, Operand(zero_reg)); __ Branch(USE_DELAY_SLOT, &second_prepared); - __ addiu(a1, a1, SeqAsciiString::kHeaderSize - kHeapObjectTag); + __ addiu(a1, a1, SeqOneByteString::kHeaderSize - kHeapObjectTag); __ bind(&skip_second_add); // External string: rule out short external string and load string resource. STATIC_ASSERT(kShortExternalStringTag != 0); @@ -6748,7 +6700,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ Branch(&non_ascii_string_add_flat_result, eq, t4, Operand(zero_reg)); __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime); - __ Addu(t2, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ Addu(t2, v0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); // v0: result string. // t3: first character of first string. // a1: first character of second string @@ -6836,7 +6788,7 @@ void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, void ICCompareStub::GenerateSmis(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::SMIS); + ASSERT(state_ == CompareIC::SMI); Label miss; __ Or(a2, a1, a0); __ JumpIfNotSmi(a2, &miss); @@ -6858,18 +6810,18 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) { void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::HEAP_NUMBERS); + ASSERT(state_ == CompareIC::HEAP_NUMBER); Label generic_stub; Label unordered, maybe_undefined1, maybe_undefined2; Label miss; - __ And(a2, a1, Operand(a0)); - __ JumpIfSmi(a2, &generic_stub); - __ GetObjectType(a0, a2, a2); - __ Branch(&maybe_undefined1, ne, a2, Operand(HEAP_NUMBER_TYPE)); - __ GetObjectType(a1, a2, a2); - __ Branch(&maybe_undefined2, ne, a2, Operand(HEAP_NUMBER_TYPE)); + if (left_ == CompareIC::SMI) { + __ JumpIfNotSmi(a1, &miss); + } + if (right_ == CompareIC::SMI) { + __ JumpIfNotSmi(a0, &miss); + } // Inlining the double comparison and falling back to the general compare // stub if NaN is involved or FPU is unsupported. @@ -6877,10 +6829,33 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { CpuFeatures::Scope scope(FPU); // Load left and right operand. - __ Subu(a2, a1, Operand(kHeapObjectTag)); - __ ldc1(f0, MemOperand(a2, HeapNumber::kValueOffset)); + Label done, left, left_smi, right_smi; + __ JumpIfSmi(a0, &right_smi); + __ CheckMap(a0, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1, + DONT_DO_SMI_CHECK); __ Subu(a2, a0, Operand(kHeapObjectTag)); __ ldc1(f2, MemOperand(a2, HeapNumber::kValueOffset)); + __ Branch(&left); + __ bind(&right_smi); + __ SmiUntag(a2, a0); // Can't clobber a0 yet. + FPURegister single_scratch = f6; + __ mtc1(a2, single_scratch); + __ cvt_d_w(f2, single_scratch); + + __ bind(&left); + __ JumpIfSmi(a1, &left_smi); + __ CheckMap(a1, a2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2, + DONT_DO_SMI_CHECK); + __ Subu(a2, a1, Operand(kHeapObjectTag)); + __ ldc1(f0, MemOperand(a2, HeapNumber::kValueOffset)); + __ Branch(&done); + __ bind(&left_smi); + __ SmiUntag(a2, a1); // Can't clobber a1 yet. + single_scratch = f8; + __ mtc1(a2, single_scratch); + __ cvt_d_w(f0, single_scratch); + + __ bind(&done); // Return a result of -1, 0, or 1, or use CompareStub for NaNs. Label fpu_eq, fpu_lt; @@ -6904,15 +6879,16 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { } __ bind(&unordered); - - CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, a1, a0); __ bind(&generic_stub); + ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC, + CompareIC::GENERIC); __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); __ bind(&maybe_undefined1); if (Token::IsOrderedRelationalCompareOp(op_)) { __ LoadRoot(at, Heap::kUndefinedValueRootIndex); __ Branch(&miss, ne, a0, Operand(at)); + __ JumpIfSmi(a1, &unordered); __ GetObjectType(a1, a2, a2); __ Branch(&maybe_undefined2, ne, a2, Operand(HEAP_NUMBER_TYPE)); __ jmp(&unordered); @@ -6930,7 +6906,7 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::SYMBOLS); + ASSERT(state_ == CompareIC::SYMBOL); Label miss; // Registers containing left and right operands respectively. @@ -6968,7 +6944,7 @@ void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { void ICCompareStub::GenerateStrings(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::STRINGS); + ASSERT(state_ == CompareIC::STRING); Label miss; bool equality = Token::IsEqualityOp(op_); @@ -7053,7 +7029,7 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) { void ICCompareStub::GenerateObjects(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::OBJECTS); + ASSERT(state_ == CompareIC::OBJECT); Label miss; __ And(a2, a1, Operand(a0)); __ JumpIfSmi(a2, &miss); @@ -7265,8 +7241,7 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, ASSERT(!name.is(scratch1)); ASSERT(!name.is(scratch2)); - // Assert that name contains a string. - if (FLAG_debug_code) __ AbortIfNotString(name); + __ AssertString(name); // Compute the capacity mask. __ lw(scratch1, FieldMemOperand(elements, kCapacityOffset)); @@ -7512,6 +7487,11 @@ void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { } +bool CodeStub::CanUseFPRegisters() { + return CpuFeatures::IsSupported(FPU); +} + + // Takes the input in 3 registers: address_ value_ and object_. A pointer to // the value has just been written into the object, now this stub makes sure // we keep the GC informed. The word in the object where the value has been @@ -7604,12 +7584,7 @@ void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { ASSERT(!address.is(a0)); __ Move(address, regs_.address()); __ Move(a0, regs_.object()); - if (mode == INCREMENTAL_COMPACTION) { - __ Move(a1, address); - } else { - ASSERT(mode == INCREMENTAL); - __ lw(a1, MemOperand(address, 0)); - } + __ Move(a1, address); __ li(a2, Operand(ExternalReference::isolate_address())); AllowExternalCallThatCantCauseGC scope(masm); @@ -7637,6 +7612,16 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker( Label need_incremental; Label need_incremental_pop_scratch; + __ And(regs_.scratch0(), regs_.object(), Operand(~Page::kPageAlignmentMask)); + __ lw(regs_.scratch1(), + MemOperand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset)); + __ Subu(regs_.scratch1(), regs_.scratch1(), Operand(1)); + __ sw(regs_.scratch1(), + MemOperand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset)); + __ Branch(&need_incremental, lt, regs_.scratch1(), Operand(zero_reg)); + // Let's look at the color of the object: If it is not black we don't have // to inform the incremental marker. __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black); @@ -7761,7 +7746,9 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS. __ bind(&double_elements); __ lw(t1, FieldMemOperand(a1, JSObject::kElementsOffset)); - __ StoreNumberToDoubleElements(a0, a3, a1, t1, t2, t3, t5, a2, + __ StoreNumberToDoubleElements(a0, a3, + // Overwrites all regs after this. + t1, t2, t3, t5, a2, &slow_elements); __ Ret(USE_DELAY_SLOT); __ mov(v0, a0); diff --git a/deps/v8/src/mips/code-stubs-mips.h b/deps/v8/src/mips/code-stubs-mips.h index e0954d837e..b560c63e0f 100644 --- a/deps/v8/src/mips/code-stubs-mips.h +++ b/deps/v8/src/mips/code-stubs-mips.h @@ -143,108 +143,6 @@ class UnaryOpStub: public CodeStub { }; -class BinaryOpStub: public CodeStub { - public: - BinaryOpStub(Token::Value op, OverwriteMode mode) - : op_(op), - mode_(mode), - operands_type_(BinaryOpIC::UNINITIALIZED), - result_type_(BinaryOpIC::UNINITIALIZED) { - use_fpu_ = CpuFeatures::IsSupported(FPU); - ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); - } - - BinaryOpStub( - int key, - BinaryOpIC::TypeInfo operands_type, - BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED) - : op_(OpBits::decode(key)), - mode_(ModeBits::decode(key)), - use_fpu_(FPUBits::decode(key)), - operands_type_(operands_type), - result_type_(result_type) { } - - private: - enum SmiCodeGenerateHeapNumberResults { - ALLOW_HEAPNUMBER_RESULTS, - NO_HEAPNUMBER_RESULTS - }; - - Token::Value op_; - OverwriteMode mode_; - bool use_fpu_; - - // Operand type information determined at runtime. - BinaryOpIC::TypeInfo operands_type_; - BinaryOpIC::TypeInfo result_type_; - - virtual void PrintName(StringStream* stream); - - // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM. - class ModeBits: public BitField<OverwriteMode, 0, 2> {}; - class OpBits: public BitField<Token::Value, 2, 7> {}; - class FPUBits: public BitField<bool, 9, 1> {}; - class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {}; - class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {}; - - Major MajorKey() { return BinaryOp; } - int MinorKey() { - return OpBits::encode(op_) - | ModeBits::encode(mode_) - | FPUBits::encode(use_fpu_) - | OperandTypeInfoBits::encode(operands_type_) - | ResultTypeInfoBits::encode(result_type_); - } - - void Generate(MacroAssembler* masm); - void GenerateGeneric(MacroAssembler* masm); - void GenerateSmiSmiOperation(MacroAssembler* masm); - void GenerateFPOperation(MacroAssembler* masm, - bool smi_operands, - Label* not_numbers, - Label* gc_required); - void GenerateSmiCode(MacroAssembler* masm, - Label* use_runtime, - Label* gc_required, - SmiCodeGenerateHeapNumberResults heapnumber_results); - void GenerateLoadArguments(MacroAssembler* masm); - void GenerateReturn(MacroAssembler* masm); - void GenerateUninitializedStub(MacroAssembler* masm); - void GenerateSmiStub(MacroAssembler* masm); - void GenerateInt32Stub(MacroAssembler* masm); - void GenerateHeapNumberStub(MacroAssembler* masm); - void GenerateOddballStub(MacroAssembler* masm); - void GenerateStringStub(MacroAssembler* masm); - void GenerateBothStringStub(MacroAssembler* masm); - void GenerateGenericStub(MacroAssembler* masm); - void GenerateAddStrings(MacroAssembler* masm); - void GenerateCallRuntime(MacroAssembler* masm); - - void GenerateHeapResultAllocation(MacroAssembler* masm, - Register result, - Register heap_number_map, - Register scratch1, - Register scratch2, - Label* gc_required); - void GenerateRegisterArgsPush(MacroAssembler* masm); - void GenerateTypeTransition(MacroAssembler* masm); - void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); - - virtual int GetCodeKind() { return Code::BINARY_OP_IC; } - - virtual InlineCacheState GetICState() { - return BinaryOpIC::ToState(operands_type_); - } - - virtual void FinishCode(Handle<Code> code) { - code->set_binary_op_type(operands_type_); - code->set_binary_op_result_type(result_type_); - } - - friend class CodeGenerator; -}; - - class StringHelper : public AllStatic { public: // Generate code for copying characters using a simple loop. This should only @@ -724,20 +622,6 @@ class FloatingPointHelper : public AllStatic { Register scratch1, Register scratch2); - // Loads objects from a0 and a1 (right and left in binary operations) into - // floating point registers. Depending on the destination the values ends up - // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination - // is floating point registers FPU must be supported. If core registers are - // requested when FPU is supported f12 and f14 will still be scratched. If - // either a0 or a1 is not a number (not smi and not heap number object) the - // not_number label is jumped to with a0 and a1 intact. - static void LoadOperands(MacroAssembler* masm, - FloatingPointHelper::Destination destination, - Register heap_number_map, - Register scratch1, - Register scratch2, - Label* not_number); - // Convert the smi or heap number in object to an int32 using the rules // for ToInt32 as described in ECMAScript 9.5.: the value is truncated // and brought into the range -2^31 .. +2^31 - 1. @@ -773,6 +657,7 @@ class FloatingPointHelper : public AllStatic { Register object, Destination destination, FPURegister double_dst, + FPURegister double_scratch, Register dst1, Register dst2, Register heap_number_map, @@ -794,7 +679,8 @@ class FloatingPointHelper : public AllStatic { Register scratch1, Register scratch2, Register scratch3, - FPURegister double_scratch, + FPURegister double_scratch0, + FPURegister double_scratch1, Label* not_int32); // Generate non FPU code to check if a double can be exactly represented by a @@ -834,7 +720,12 @@ class FloatingPointHelper : public AllStatic { Register heap_number_result, Register scratch); - private: + // Loads the objects from |object| into floating point registers. + // Depending on |destination| the value ends up either in |dst| or + // in |dst1|/|dst2|. If |destination| is kFPURegisters, then FPU + // must be supported. If kCoreRegisters are requested and FPU is + // supported, |dst| will be scratched. If |object| is neither smi nor + // heap number, |not_number| is jumped to with |object| still intact. static void LoadNumber(MacroAssembler* masm, FloatingPointHelper::Destination destination, Register object, diff --git a/deps/v8/src/mips/codegen-mips.cc b/deps/v8/src/mips/codegen-mips.cc index 44e0359e44..0119c11f53 100644 --- a/deps/v8/src/mips/codegen-mips.cc +++ b/deps/v8/src/mips/codegen-mips.cc @@ -31,11 +31,11 @@ #include "codegen.h" #include "macro-assembler.h" +#include "simulator-mips.h" namespace v8 { namespace internal { -#define __ ACCESS_MASM(masm) UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { switch (type) { @@ -49,6 +49,74 @@ UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { } +#define __ masm. + + +#if defined(USE_SIMULATOR) +byte* fast_exp_mips_machine_code = NULL; +double fast_exp_simulator(double x) { + return Simulator::current(Isolate::Current())->CallFP( + fast_exp_mips_machine_code, x, 0); +} +#endif + + +UnaryMathFunction CreateExpFunction() { + if (!CpuFeatures::IsSupported(FPU)) return &exp; + if (!FLAG_fast_math) return &exp; + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == NULL) return &exp; + ExternalReference::InitializeMathExpData(); + + MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); + + { + CpuFeatures::Scope use_fpu(FPU); + DoubleRegister input = f12; + DoubleRegister result = f0; + DoubleRegister double_scratch1 = f4; + DoubleRegister double_scratch2 = f6; + Register temp1 = t0; + Register temp2 = t1; + Register temp3 = t2; + + if (!IsMipsSoftFloatABI) { + // Input value is in f12 anyway, nothing to do. + } else { + __ Move(input, a0, a1); + } + __ Push(temp3, temp2, temp1); + MathExpGenerator::EmitMathExp( + &masm, input, result, double_scratch1, double_scratch2, + temp1, temp2, temp3); + __ Pop(temp3, temp2, temp1); + if (!IsMipsSoftFloatABI) { + // Result is already in f0, nothing to do. + } else { + __ Move(a0, a1, result); + } + __ Ret(); + } + + CodeDesc desc; + masm.GetCode(&desc); + + CPU::FlushICache(buffer, actual_size); + OS::ProtectCode(buffer, actual_size); + +#if !defined(USE_SIMULATOR) + return FUNCTION_CAST<UnaryMathFunction>(buffer); +#else + fast_exp_mips_machine_code = buffer; + return &fast_exp_simulator; +#endif +} + + +#undef __ + + UnaryMathFunction CreateSqrtFunction() { return &sqrt; } @@ -72,6 +140,8 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { // ------------------------------------------------------------------------- // Code generators +#define __ ACCESS_MASM(masm) + void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( MacroAssembler* masm) { // ----------- S t a t e ------------- @@ -408,7 +478,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, __ Branch(&external_string, ne, at, Operand(zero_reg)); // Prepare sequential strings - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ Addu(string, string, SeqTwoByteString::kHeaderSize - kHeapObjectTag); @@ -446,6 +516,152 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, __ bind(&done); } + +static MemOperand ExpConstant(int index, Register base) { + return MemOperand(base, index * kDoubleSize); +} + + +void MathExpGenerator::EmitMathExp(MacroAssembler* masm, + DoubleRegister input, + DoubleRegister result, + DoubleRegister double_scratch1, + DoubleRegister double_scratch2, + Register temp1, + Register temp2, + Register temp3) { + ASSERT(!input.is(result)); + ASSERT(!input.is(double_scratch1)); + ASSERT(!input.is(double_scratch2)); + ASSERT(!result.is(double_scratch1)); + ASSERT(!result.is(double_scratch2)); + ASSERT(!double_scratch1.is(double_scratch2)); + ASSERT(!temp1.is(temp2)); + ASSERT(!temp1.is(temp3)); + ASSERT(!temp2.is(temp3)); + ASSERT(ExternalReference::math_exp_constants(0).address() != NULL); + + Label done; + + __ li(temp3, Operand(ExternalReference::math_exp_constants(0))); + + __ ldc1(double_scratch1, ExpConstant(0, temp3)); + __ Move(result, kDoubleRegZero); + __ BranchF(&done, NULL, ge, double_scratch1, input); + __ ldc1(double_scratch2, ExpConstant(1, temp3)); + __ ldc1(result, ExpConstant(2, temp3)); + __ BranchF(&done, NULL, ge, input, double_scratch2); + __ ldc1(double_scratch1, ExpConstant(3, temp3)); + __ ldc1(result, ExpConstant(4, temp3)); + __ mul_d(double_scratch1, double_scratch1, input); + __ add_d(double_scratch1, double_scratch1, result); + __ Move(temp2, temp1, double_scratch1); + __ sub_d(double_scratch1, double_scratch1, result); + __ ldc1(result, ExpConstant(6, temp3)); + __ ldc1(double_scratch2, ExpConstant(5, temp3)); + __ mul_d(double_scratch1, double_scratch1, double_scratch2); + __ sub_d(double_scratch1, double_scratch1, input); + __ sub_d(result, result, double_scratch1); + __ mul_d(input, double_scratch1, double_scratch1); + __ mul_d(result, result, input); + __ srl(temp1, temp2, 11); + __ ldc1(double_scratch2, ExpConstant(7, temp3)); + __ mul_d(result, result, double_scratch2); + __ sub_d(result, result, double_scratch1); + __ ldc1(double_scratch2, ExpConstant(8, temp3)); + __ add_d(result, result, double_scratch2); + __ li(at, 0x7ff); + __ And(temp2, temp2, at); + __ Addu(temp1, temp1, Operand(0x3ff)); + __ sll(temp1, temp1, 20); + + // Must not call ExpConstant() after overwriting temp3! + __ li(temp3, Operand(ExternalReference::math_exp_log_table())); + __ sll(at, temp2, 3); + __ addu(at, at, temp3); + __ lw(at, MemOperand(at)); + __ Addu(temp3, temp3, Operand(kPointerSize)); + __ sll(temp2, temp2, 3); + __ addu(temp2, temp2, temp3); + __ lw(temp2, MemOperand(temp2)); + __ Or(temp1, temp1, temp2); + __ Move(input, at, temp1); + __ mul_d(result, result, input); + __ bind(&done); +} + + +// nop(CODE_AGE_MARKER_NOP) +static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180; + +static byte* GetNoCodeAgeSequence(uint32_t* length) { + // The sequence of instructions that is patched out for aging code is the + // following boilerplate stack-building prologue that is found in FUNCTIONS + static bool initialized = false; + static uint32_t sequence[kNoCodeAgeSequenceLength]; + byte* byte_sequence = reinterpret_cast<byte*>(sequence); + *length = kNoCodeAgeSequenceLength * Assembler::kInstrSize; + if (!initialized) { + CodePatcher patcher(byte_sequence, kNoCodeAgeSequenceLength); + patcher.masm()->Push(ra, fp, cp, a1); + patcher.masm()->LoadRoot(at, Heap::kUndefinedValueRootIndex); + patcher.masm()->Addu(fp, sp, Operand(2 * kPointerSize)); + initialized = true; + } + return byte_sequence; +} + + +bool Code::IsYoungSequence(byte* sequence) { + uint32_t young_length; + byte* young_sequence = GetNoCodeAgeSequence(&young_length); + bool result = !memcmp(sequence, young_sequence, young_length); + ASSERT(result || + Memory::uint32_at(sequence) == kCodeAgePatchFirstInstruction); + return result; +} + + +void Code::GetCodeAgeAndParity(byte* sequence, Age* age, + MarkingParity* parity) { + if (IsYoungSequence(sequence)) { + *age = kNoAge; + *parity = NO_MARKING_PARITY; + } else { + Address target_address = Memory::Address_at( + sequence + Assembler::kInstrSize * (kNoCodeAgeSequenceLength - 1)); + Code* stub = GetCodeFromTargetAddress(target_address); + GetCodeAgeAndParity(stub, age, parity); + } +} + + +void Code::PatchPlatformCodeAge(byte* sequence, + Code::Age age, + MarkingParity parity) { + uint32_t young_length; + byte* young_sequence = GetNoCodeAgeSequence(&young_length); + if (age == kNoAge) { + memcpy(sequence, young_sequence, young_length); + CPU::FlushICache(sequence, young_length); + } else { + Code* stub = GetCodeAgeStub(age, parity); + CodePatcher patcher(sequence, young_length / Assembler::kInstrSize); + // Mark this code sequence for FindPlatformCodeAgeSequence() + patcher.masm()->nop(Assembler::CODE_AGE_MARKER_NOP); + // Save the function's original return address + // (it will be clobbered by Call(t9)) + patcher.masm()->mov(at, ra); + // Load the stub address to t9 and call it + patcher.masm()->li(t9, + Operand(reinterpret_cast<uint32_t>(stub->instruction_start()))); + patcher.masm()->Call(t9); + // Record the stub address in the empty space for GetCodeAgeAndParity() + patcher.masm()->dd(reinterpret_cast<uint32_t>(stub->instruction_start())); + } +} + + #undef __ } } // namespace v8::internal diff --git a/deps/v8/src/mips/codegen-mips.h b/deps/v8/src/mips/codegen-mips.h index e704c4f56c..0ed2414a03 100644 --- a/deps/v8/src/mips/codegen-mips.h +++ b/deps/v8/src/mips/codegen-mips.h @@ -90,6 +90,22 @@ class StringCharLoadGenerator : public AllStatic { DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator); }; + +class MathExpGenerator : public AllStatic { + public: + static void EmitMathExp(MacroAssembler* masm, + DoubleRegister input, + DoubleRegister result, + DoubleRegister double_scratch1, + DoubleRegister double_scratch2, + Register temp1, + Register temp2, + Register temp3); + + private: + DISALLOW_COPY_AND_ASSIGN(MathExpGenerator); +}; + } } // namespace v8::internal #endif // V8_MIPS_CODEGEN_MIPS_H_ diff --git a/deps/v8/src/mips/deoptimizer-mips.cc b/deps/v8/src/mips/deoptimizer-mips.cc index 371d120887..e8ed9ccf7b 100644 --- a/deps/v8/src/mips/deoptimizer-mips.cc +++ b/deps/v8/src/mips/deoptimizer-mips.cc @@ -100,19 +100,7 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { // ignore all slots that might have been recorded on it. isolate->heap()->mark_compact_collector()->InvalidateCode(code); - // Iterate over all the functions which share the same code object - // and make them use unoptimized version. - Context* context = function->context()->native_context(); - Object* element = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); - SharedFunctionInfo* shared = function->shared(); - while (!element->IsUndefined()) { - JSFunction* func = JSFunction::cast(element); - // Grab element before code replacement as ReplaceCode alters the list. - element = func->next_function_link(); - if (func->code() == code) { - func->ReplaceCode(shared->code()); - } - } + ReplaceCodeForRelatedFunctions(function, code); if (FLAG_trace_deopt) { PrintF("[forced deoptimization: "); @@ -132,7 +120,7 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, Code* check_code, Code* replacement_code) { const int kInstrSize = Assembler::kInstrSize; - // This structure comes from FullCodeGenerator::EmitStackCheck. + // This structure comes from FullCodeGenerator::EmitBackEdgeBookkeeping. // The call of the stack guard check has the following form: // sltu at, sp, t0 / slt at, a3, zero_reg (in case of count based interrupts) // beq at, zero_reg, ok @@ -182,11 +170,7 @@ void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code, // Restore the sltu instruction so beq can be taken again. CodePatcher patcher(pc_after - 6 * kInstrSize, 1); - if (FLAG_count_based_interrupts) { - patcher.masm()->slt(at, a3, zero_reg); - } else { - patcher.masm()->sltu(at, sp, t0); - } + patcher.masm()->slt(at, a3, zero_reg); // Replace the on-stack replacement address in the load-immediate (lui/ori // pair) with the entry address of the normal stack-check code. diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc index bfa24252b9..f9f8c404c2 100644 --- a/deps/v8/src/mips/full-codegen-mips.cc +++ b/deps/v8/src/mips/full-codegen-mips.cc @@ -139,7 +139,7 @@ void FullCodeGenerator::Generate() { handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell( - Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget))); + Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); @@ -172,12 +172,13 @@ void FullCodeGenerator::Generate() { int locals_count = info->scope()->num_stack_slots(); + info->set_prologue_offset(masm_->pc_offset()); + // The following three instructions must remain together and unmodified for + // code aging to work properly. __ Push(ra, fp, cp, a1); - if (locals_count > 0) { - // Load undefined value here, so the value is ready for the loop - // below. - __ LoadRoot(at, Heap::kUndefinedValueRootIndex); - } + // Load undefined value here, so the value is ready for the loop + // below. + __ LoadRoot(at, Heap::kUndefinedValueRootIndex); // Adjust fp to point to caller's fp. __ Addu(fp, sp, Operand(2 * kPointerSize)); @@ -345,45 +346,34 @@ void FullCodeGenerator::EmitProfilingCounterReset() { } -void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, - Label* back_edge_target) { +void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, + Label* back_edge_target) { // The generated code is used in Deoptimizer::PatchStackCheckCodeAt so we need // to make sure it is constant. Branch may emit a skip-or-jump sequence // instead of the normal Branch. It seems that the "skip" part of that // sequence is about as long as this Branch would be so it is safe to ignore // that. Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); - Comment cmnt(masm_, "[ Stack check"); + Comment cmnt(masm_, "[ Back edge bookkeeping"); Label ok; - 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 / kBackEdgeDistanceUnit)); - } - EmitProfilingCounterDecrement(weight); - __ slt(at, a3, zero_reg); - __ beq(at, zero_reg, &ok); - // CallStub will emit a li t9 first, so it is safe to use the delay slot. - InterruptStub stub; - __ CallStub(&stub); - } else { - __ LoadRoot(t0, Heap::kStackLimitRootIndex); - __ sltu(at, sp, t0); - __ beq(at, zero_reg, &ok); - // CallStub will emit a li t9 first, so it is safe to use the delay slot. - StackCheckStub stub; - __ CallStub(&stub); + 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 / kBackEdgeDistanceUnit)); } + EmitProfilingCounterDecrement(weight); + __ slt(at, a3, zero_reg); + __ beq(at, zero_reg, &ok); + // CallStub will emit a li t9 first, so it is safe to use the delay slot. + InterruptStub 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. - RecordStackCheck(stmt->OsrEntryId()); - if (FLAG_count_based_interrupts) { - EmitProfilingCounterReset(); - } + RecordBackEdge(stmt->OsrEntryId()); + EmitProfilingCounterReset(); __ bind(&ok); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); @@ -929,34 +919,33 @@ void FullCodeGenerator::VisitFunctionDeclaration( void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { - VariableProxy* proxy = declaration->proxy(); - Variable* variable = proxy->var(); - Handle<JSModule> instance = declaration->module()->interface()->Instance(); - ASSERT(!instance.is_null()); + Variable* variable = declaration->proxy()->var(); + ASSERT(variable->location() == Variable::CONTEXT); + ASSERT(variable->interface()->IsFrozen()); - switch (variable->location()) { - case Variable::UNALLOCATED: { - Comment cmnt(masm_, "[ ModuleDeclaration"); - globals_->Add(variable->name(), zone()); - globals_->Add(instance, zone()); - Visit(declaration->module()); - break; - } + Comment cmnt(masm_, "[ ModuleDeclaration"); + EmitDebugCheckDeclarationContext(variable); - case Variable::CONTEXT: { - Comment cmnt(masm_, "[ ModuleDeclaration"); - EmitDebugCheckDeclarationContext(variable); - __ li(a1, Operand(instance)); - __ sw(a1, ContextOperand(cp, variable->index())); - Visit(declaration->module()); - break; - } + // Load instance object. + __ LoadContext(a1, scope_->ContextChainLength(scope_->GlobalScope())); + __ lw(a1, ContextOperand(a1, variable->interface()->Index())); + __ lw(a1, ContextOperand(a1, Context::EXTENSION_INDEX)); - case Variable::PARAMETER: - case Variable::LOCAL: - case Variable::LOOKUP: - UNREACHABLE(); - } + // Assign it. + __ sw(a1, ContextOperand(cp, variable->index())); + // We know that we have written a module, which is not a smi. + __ RecordWriteContextSlot(cp, + Context::SlotOffset(variable->index()), + a1, + a3, + kRAHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS); + + // Traverse into body. + Visit(declaration->module()); } @@ -999,6 +988,14 @@ void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { } +void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) { + // Call the runtime to declare the modules. + __ Push(descriptions); + __ CallRuntime(Runtime::kDeclareModules, 1); + // Return value is ignored. +} + + void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { Comment cmnt(masm_, "[ SwitchStatement"); Breakable nested_statement(this, stmt); @@ -1152,7 +1149,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ EnumLength(a1, v0); __ Branch(&no_descriptors, eq, a1, Operand(Smi::FromInt(0))); - __ LoadInstanceDescriptors(v0, a2, t0); + __ LoadInstanceDescriptors(v0, a2); __ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheOffset)); __ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheBridgeCacheOffset)); @@ -1251,7 +1248,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ Addu(a0, a0, Operand(Smi::FromInt(1))); __ push(a0); - EmitStackCheck(stmt, &loop); + EmitBackEdgeBookkeeping(stmt, &loop); __ Branch(&loop); // Remove the pointers stored on the stack. @@ -1399,9 +1396,9 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, } else if (var->mode() == DYNAMIC_LOCAL) { Variable* local = var->local_if_not_shadowed(); __ lw(v0, ContextSlotOperandCheckExtensions(local, slow)); - if (local->mode() == CONST || - local->mode() == CONST_HARMONY || - local->mode() == LET) { + if (local->mode() == LET || + local->mode() == CONST || + local->mode() == CONST_HARMONY) { __ LoadRoot(at, Heap::kTheHoleValueRootIndex); __ subu(at, v0, at); // Sub as compare: at == 0 on eq. if (local->mode() == CONST) { @@ -2208,44 +2205,17 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { ASSERT(prop != NULL); ASSERT(prop->key()->AsLiteral() != NULL); - // If the assignment starts a block of assignments to the same object, - // change to slow case to avoid the quadratic behavior of repeatedly - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - __ lw(t0, MemOperand(sp, kPointerSize)); // Receiver is now under value. - __ push(t0); - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - // Record source code position before IC call. SetSourcePosition(expr->position()); __ mov(a0, result_register()); // Load the value. __ li(a2, Operand(prop->key()->AsLiteral()->handle())); - // Load receiver to a1. Leave a copy in the stack if needed for turning the - // receiver into fast case. - if (expr->ends_initialization_block()) { - __ lw(a1, MemOperand(sp)); - } else { - __ pop(a1); - } + __ pop(a1); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ push(v0); // Result of assignment, saved even if not needed. - // Receiver is under the result value. - __ lw(t0, MemOperand(sp, kPointerSize)); - __ push(t0); - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(v0); - __ Drop(1); - } PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(v0); } @@ -2254,18 +2224,6 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { // Assignment to a property, using a keyed store IC. - // If the assignment starts a block of assignments to the same object, - // change to slow case to avoid the quadratic behavior of repeatedly - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - // Receiver is now under the key and value. - __ lw(t0, MemOperand(sp, 2 * kPointerSize)); - __ push(t0); - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - // Record source code position before IC call. SetSourcePosition(expr->position()); // Call keyed store IC. @@ -2275,29 +2233,13 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { // - a2 is the receiver. __ mov(a0, result_register()); __ pop(a1); // Key. - // Load receiver to a2. Leave a copy in the stack if needed for turning the - // receiver into fast case. - if (expr->ends_initialization_block()) { - __ lw(a2, MemOperand(sp)); - } else { - __ pop(a2); - } + __ pop(a2); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->KeyedStoreIC_Initialize() : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ push(v0); // Result of assignment, saved even if not needed. - // Receiver is under the result value. - __ lw(t0, MemOperand(sp, kPointerSize)); - __ push(t0); - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(v0); - __ Drop(1); - } PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(v0); } @@ -2457,7 +2399,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { VariableProxy* proxy = callee->AsVariableProxy(); Property* property = callee->AsProperty(); - if (proxy != NULL && proxy->var()->is_possibly_eval()) { + if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { // In a call to eval, we first call %ResolvePossiblyDirectEval to // resolve the function we need to call and the receiver of the // call. Then we call the resolved function using the given @@ -2745,7 +2687,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - if (generate_debug_code_) __ AbortIfSmi(v0); + __ AssertNotSmi(v0); __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); __ lbu(t0, FieldMemOperand(a1, Map::kBitField2Offset)); @@ -2759,27 +2701,31 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ Branch(if_false, eq, a2, Operand(t0)); // Look for valueOf symbol in the descriptor array, and indicate false if - // found. The type is not checked, so if it is a transition it is a false - // negative. - __ LoadInstanceDescriptors(a1, t0, a3); - __ lw(a3, FieldMemOperand(t0, FixedArray::kLengthOffset)); - // t0: descriptor array - // a3: length of descriptor array - // Calculate the end of the descriptor array. + // found. Since we omit an enumeration index check, if it is added via a + // transition that shares its descriptor array, this is a false positive. + Label entry, loop, done; + + // Skip loop if no descriptors are valid. + __ NumberOfOwnDescriptors(a3, a1); + __ Branch(&done, eq, a3, Operand(zero_reg)); + + __ LoadInstanceDescriptors(a1, t0); + // t0: descriptor array. + // a3: valid entries in the descriptor array. STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); STATIC_ASSERT(kPointerSize == 4); - __ Addu(a2, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ li(at, Operand(DescriptorArray::kDescriptorSize)); + __ Mul(a3, a3, at); + // Calculate location of the first key name. + __ Addu(t0, t0, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag)); + // Calculate the end of the descriptor array. + __ mov(a2, t0); __ sll(t1, a3, kPointerSizeLog2 - kSmiTagSize); __ Addu(a2, a2, t1); - // Calculate location of the first key name. - __ Addu(t0, - t0, - Operand(DescriptorArray::kFirstOffset - kHeapObjectTag)); // Loop through all the keys in the descriptor array. If one of these is the // symbol valueOf the result is false. - Label entry, loop; // The use of t2 to store the valueOf symbol asumes that it is not otherwise // used in the loop below. __ LoadRoot(t2, Heap::kvalue_of_symbolRootIndex); @@ -2791,7 +2737,8 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ bind(&entry); __ Branch(&loop, ne, t0, Operand(a2)); - // If a valueOf property is not found on the object check that it's + __ bind(&done); + // If a valueOf property is not found on the object check that its // prototype is the un-modified String prototype. If not result is false. __ lw(a2, FieldMemOperand(a1, Map::kPrototypeOffset)); __ JumpIfSmi(a2, if_false); @@ -3621,7 +3568,7 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) { ASSERT(args->length() == 1); VisitForAccumulatorValue(args->at(0)); - __ AbortIfNotString(v0); + __ AssertString(v0); __ lw(v0, FieldMemOperand(v0, String::kHashFieldOffset)); __ IndexFromHash(v0, v0); @@ -3706,7 +3653,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ lw(scratch1, FieldMemOperand(string, HeapObject::kMapOffset)); __ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout); - __ lw(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset)); + __ lw(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset)); __ AdduAndCheckForOverflow(string_length, string_length, scratch1, scratch3); __ BranchOnOverflow(&bailout, scratch3); __ Branch(&loop, lt, element, Operand(elements_end)); @@ -3733,7 +3680,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // Add (separator length times array_length) - separator length to the // string_length to get the length of the result string. array_length is not // smi but the other values are, so the result is a smi. - __ lw(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); + __ lw(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); __ Subu(string_length, string_length, Operand(scratch1)); __ Mult(array_length, scratch1); // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are @@ -3773,10 +3720,10 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { array_length = no_reg; __ Addu(result_pos, result, - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); // Check the length of the separator. - __ lw(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset)); + __ lw(scratch1, FieldMemOperand(separator, SeqOneByteString::kLengthOffset)); __ li(at, Operand(Smi::FromInt(1))); __ Branch(&one_char_separator, eq, scratch1, Operand(at)); __ Branch(&long_separator, gt, scratch1, Operand(at)); @@ -3793,7 +3740,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ Addu(element, element, kPointerSize); __ lw(string_length, FieldMemOperand(string, String::kLengthOffset)); __ SmiUntag(string_length); - __ Addu(string, string, SeqAsciiString::kHeaderSize - kHeapObjectTag); + __ Addu(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag); __ CopyBytes(string, result_pos, string_length, scratch1); // End while (element < elements_end). __ Branch(&empty_separator_loop, lt, element, Operand(elements_end)); @@ -3803,7 +3750,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // One-character separator case. __ bind(&one_char_separator); // Replace separator with its ASCII character value. - __ lbu(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize)); + __ lbu(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize)); // Jump into the loop after the code that copies the separator, so the first // element is not preceded by a separator. __ jmp(&one_char_separator_loop_entry); @@ -3825,7 +3772,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ Addu(element, element, kPointerSize); __ lw(string_length, FieldMemOperand(string, String::kLengthOffset)); __ SmiUntag(string_length); - __ Addu(string, string, SeqAsciiString::kHeaderSize - kHeapObjectTag); + __ Addu(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag); __ CopyBytes(string, result_pos, string_length, scratch1); // End while (element < elements_end). __ Branch(&one_char_separator_loop, lt, element, Operand(elements_end)); @@ -3846,7 +3793,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ SmiUntag(string_length); __ Addu(string, separator, - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); __ CopyBytes(string, result_pos, string_length, scratch1); __ bind(&long_separator); @@ -3854,7 +3801,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ Addu(element, element, kPointerSize); __ lw(string_length, FieldMemOperand(string, String::kLengthOffset)); __ SmiUntag(string_length); - __ Addu(string, string, SeqAsciiString::kHeaderSize - kHeapObjectTag); + __ Addu(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag); __ CopyBytes(string, result_pos, string_length, scratch1); // End while (element < elements_end). __ Branch(&long_separator_loop, lt, element, Operand(elements_end)); @@ -4150,9 +4097,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { JumpPatchSite patch_site(masm_); int count_value = expr->op() == Token::INC ? 1 : -1; - __ li(a1, Operand(Smi::FromInt(count_value))); - if (ShouldInlineSmiCase(expr->op())) { + __ li(a1, Operand(Smi::FromInt(count_value))); __ AdduAndCheckForOverflow(v0, a0, a1, t0); __ BranchOnOverflow(&stub_call, t0); // Do stub on overflow. @@ -4161,6 +4107,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { patch_site.EmitJumpIfSmi(v0, &done); __ bind(&stub_call); } + __ mov(a1, a0); + __ li(a0, Operand(Smi::FromInt(count_value))); // Record position before stub call. SetSourcePosition(expr->position()); @@ -4383,29 +4331,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { default: { VisitForAccumulatorValue(expr->right()); - Condition cc = eq; - switch (op) { - case Token::EQ_STRICT: - case Token::EQ: - cc = eq; - break; - case Token::LT: - cc = lt; - break; - case Token::GT: - cc = gt; - break; - case Token::LTE: - cc = le; - break; - case Token::GTE: - cc = ge; - break; - case Token::IN: - case Token::INSTANCEOF: - default: - UNREACHABLE(); - } + Condition cc = CompareIC::ComputeCondition(op); __ mov(a0, result_register()); __ pop(a1); diff --git a/deps/v8/src/mips/ic-mips.cc b/deps/v8/src/mips/ic-mips.cc index 3f2ecb88a5..4ac92aff19 100644 --- a/deps/v8/src/mips/ic-mips.cc +++ b/deps/v8/src/mips/ic-mips.cc @@ -1189,6 +1189,144 @@ void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, } +static void KeyedStoreGenerateGenericHelper( + MacroAssembler* masm, + Label* fast_object, + Label* fast_double, + Label* slow, + KeyedStoreCheckMap check_map, + KeyedStoreIncrementLength increment_length, + Register value, + Register key, + Register receiver, + Register receiver_map, + Register elements_map, + Register elements) { + Label transition_smi_elements; + Label finish_object_store, non_double_value, transition_double_elements; + Label fast_double_without_map_check; + + // Fast case: Do the store, could be either Object or double. + __ bind(fast_object); + Register scratch_value = t0; + Register address = t1; + if (check_map == kCheckMap) { + __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); + __ Branch(fast_double, ne, elements_map, + Operand(masm->isolate()->factory()->fixed_array_map())); + } + // Smi stores don't require further checks. + Label non_smi_value; + __ JumpIfNotSmi(value, &non_smi_value); + + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ Addu(scratch_value, key, Operand(Smi::FromInt(1))); + __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); + } + // It's irrelevant whether array is smi-only or not when writing a smi. + __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); + __ Addu(address, address, scratch_value); + __ sw(value, MemOperand(address)); + __ Ret(); + + __ bind(&non_smi_value); + // Escape to elements kind transition case. + __ CheckFastObjectElements(receiver_map, scratch_value, + &transition_smi_elements); + + // Fast elements array, store the value to the elements backing store. + __ bind(&finish_object_store); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ Addu(scratch_value, key, Operand(Smi::FromInt(1))); + __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); + } + __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); + __ Addu(address, address, scratch_value); + __ sw(value, MemOperand(address)); + // Update write barrier for the elements array address. + __ mov(scratch_value, value); // Preserve the value which is returned. + __ RecordWrite(elements, + address, + scratch_value, + kRAHasNotBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ Ret(); + + __ bind(fast_double); + if (check_map == kCheckMap) { + // Check for fast double array case. If this fails, call through to the + // runtime. + __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex); + __ Branch(slow, ne, elements_map, Operand(at)); + } + __ bind(&fast_double_without_map_check); + __ StoreNumberToDoubleElements(value, + key, + elements, // Overwritten. + a3, // Scratch regs... + t0, + t1, + t2, + &transition_double_elements); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ Addu(scratch_value, key, Operand(Smi::FromInt(1))); + __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); + } + __ Ret(); + + __ bind(&transition_smi_elements); + // Transition the array appropriately depending on the value type. + __ lw(t0, FieldMemOperand(value, HeapObject::kMapOffset)); + __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); + __ Branch(&non_double_value, ne, t0, Operand(at)); + + // Value is a double. Transition FAST_SMI_ELEMENTS -> + // FAST_DOUBLE_ELEMENTS and complete the store. + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_DOUBLE_ELEMENTS, + receiver_map, + t0, + slow); + ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 + ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow); + __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ jmp(&fast_double_without_map_check); + + __ bind(&non_double_value); + // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_ELEMENTS, + receiver_map, + t0, + slow); + ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 + ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); + __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); + + __ bind(&transition_double_elements); + // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a + // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and + // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS + __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, + FAST_ELEMENTS, + receiver_map, + t0, + slow); + ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 + ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow); + __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); +} + + void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode) { // ---------- S t a t e -------------- @@ -1197,11 +1335,9 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // -- a2 : receiver // -- ra : return address // ----------------------------------- - Label slow, array, extra, check_if_double_array; - Label fast_object_with_map_check, fast_object_without_map_check; - Label fast_double_with_map_check, fast_double_without_map_check; - Label transition_smi_elements, finish_object_store, non_double_value; - Label transition_double_elements; + Label slow, fast_object, fast_object_grow; + Label fast_double, fast_double_grow; + Label array, extra, check_if_double_array; // Register usage. Register value = a0; @@ -1233,7 +1369,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); // Check array bounds. Both the key and the length of FixedArray are smis. __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); - __ Branch(&fast_object_with_map_check, lo, key, Operand(t0)); + __ Branch(&fast_object, lo, key, Operand(t0)); // Slow case, handle jump to runtime. __ bind(&slow); @@ -1258,19 +1394,11 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ Branch( &check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex); - // Calculate key + 1 as smi. - STATIC_ASSERT(kSmiTag == 0); - __ Addu(t0, key, Operand(Smi::FromInt(1))); - __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); - __ Branch(&fast_object_without_map_check); + __ jmp(&fast_object_grow); __ bind(&check_if_double_array); __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex); - // Add 1 to key, and go to common element store code for doubles. - STATIC_ASSERT(kSmiTag == 0); - __ Addu(t0, key, Operand(Smi::FromInt(1))); - __ sw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); - __ jmp(&fast_double_without_map_check); + __ jmp(&fast_double_grow); // Array case: Get the length and the elements array from the JS // array. Check that the array is in fast mode (and writable); if it @@ -1281,110 +1409,15 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // Check the key against the length in the array. __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); __ Branch(&extra, hs, key, Operand(t0)); - // Fall through to fast case. - - __ bind(&fast_object_with_map_check); - Register scratch_value = t0; - Register address = t1; - __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); - __ Branch(&fast_double_with_map_check, - ne, - elements_map, - Heap::kFixedArrayMapRootIndex); - __ bind(&fast_object_without_map_check); - // Smi stores don't require further checks. - Label non_smi_value; - __ JumpIfNotSmi(value, &non_smi_value); - // It's irrelevant whether array is smi-only or not when writing a smi. - __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); - __ Addu(address, address, scratch_value); - __ sw(value, MemOperand(address)); - __ Ret(USE_DELAY_SLOT); - __ mov(v0, value); - - __ bind(&non_smi_value); - // Escape to elements kind transition case. - __ CheckFastObjectElements(receiver_map, scratch_value, - &transition_smi_elements); - // Fast elements array, store the value to the elements backing store. - __ bind(&finish_object_store); - __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize); - __ Addu(address, address, scratch_value); - __ sw(value, MemOperand(address)); - // Update write barrier for the elements array address. - __ mov(v0, value); // Preserve the value which is returned. - __ RecordWrite(elements, - address, - value, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - __ Ret(); - - __ bind(&fast_double_with_map_check); - // Check for fast double array case. If this fails, call through to the - // runtime. - __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex); - __ bind(&fast_double_without_map_check); - __ StoreNumberToDoubleElements(value, - key, - receiver, - elements, - a3, - t0, - t1, - t2, - &transition_double_elements); - __ Ret(USE_DELAY_SLOT); - __ mov(v0, value); - __ bind(&transition_smi_elements); - // Transition the array appropriately depending on the value type. - __ lw(t0, FieldMemOperand(value, HeapObject::kMapOffset)); - __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); - __ Branch(&non_double_value, ne, t0, Operand(at)); - - - // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS - // and complete the store. - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS, - receiver_map, - t0, - &slow); - ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 - ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow); - __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ jmp(&fast_double_without_map_check); - - __ bind(&non_double_value); - // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - t0, - &slow); - ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 - ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); - __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); - - __ bind(&transition_double_elements); - // Elements are double, but value is an Object that's not a HeapNumber. Make - // sure that the receiver is a Array with Object elements and transition array - // from double elements to Object elements. - __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - t0, - &slow); - ASSERT(receiver_map.is(a3)); // Transition code expects map in a3 - ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow); - __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); + KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, + &slow, kCheckMap, kDontIncrementLength, + value, key, receiver, receiver_map, + elements_map, elements); + KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, + &slow, kDontCheckMap, kIncrementLength, + value, key, receiver, receiver_map, + elements_map, elements); } @@ -1661,36 +1694,16 @@ Condition CompareIC::ComputeCondition(Token::Value op) { } -void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { - HandleScope scope; - Handle<Code> rewritten; - State previous_state = GetState(); - State state = TargetState(previous_state, false, x, y); - if (state == GENERIC) { - CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, a1, a0); - rewritten = stub.GetCode(); - } else { - ICCompareStub stub(op_, state); - if (state == KNOWN_OBJECTS) { - stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map())); - } - rewritten = stub.GetCode(); - } - set_target(*rewritten); - -#ifdef DEBUG - if (FLAG_trace_ic) { - PrintF("[CompareIC (%s->%s)#%s]\n", - GetStateName(previous_state), - GetStateName(state), - Token::Name(op_)); - } -#endif +bool CompareIC::HasInlinedSmiCode(Address address) { + // The address of the instruction following the call. + Address andi_instruction_address = + address + Assembler::kCallTargetAddressOffset; - // Activate inlined smi code. - if (previous_state == UNINITIALIZED) { - PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); - } + // If the instruction following the call is not a andi at, rx, #yyy, nothing + // was inlined. + Instr instr = Assembler::instr_at(andi_instruction_address); + return Assembler::IsAndImmediate(instr) && + Assembler::GetRt(instr) == (uint32_t)zero_reg.code(); } diff --git a/deps/v8/src/mips/lithium-codegen-mips.cc b/deps/v8/src/mips/lithium-codegen-mips.cc index db9748a4ae..22352e1184 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.cc +++ b/deps/v8/src/mips/lithium-codegen-mips.cc @@ -144,7 +144,13 @@ bool LCodeGen::GeneratePrologue() { __ bind(&ok); } + info()->set_prologue_offset(masm_->pc_offset()); + // The following three instructions must remain together and unmodified for + // code aging to work properly. __ Push(ra, fp, cp, a1); + // Add unused load of ip to ensure prologue sequence is identical for + // full-codegen and lithium-codegen. + __ LoadRoot(at, Heap::kUndefinedValueRootIndex); __ Addu(fp, sp, Operand(2 * kPointerSize)); // Adj. FP to point to saved FP. // Reserve space for the stack slots needed by the code. @@ -221,7 +227,30 @@ bool LCodeGen::GenerateBody() { } if (emit_instructions) { - Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); + if (FLAG_code_comments) { + HValue* hydrogen = instr->hydrogen_value(); + if (hydrogen != NULL) { + if (hydrogen->IsChange()) { + HValue* changed_value = HChange::cast(hydrogen)->value(); + int use_id = 0; + const char* use_mnemo = "dead"; + if (hydrogen->UseCount() >= 1) { + HValue* use_value = hydrogen->uses().value(); + use_id = use_value->id(); + use_mnemo = use_value->Mnemonic(); + } + Comment(";;; @%d: %s. <of #%d %s for #%d %s>", + current_instruction_, instr->Mnemonic(), + changed_value->id(), changed_value->Mnemonic(), + use_id, use_mnemo); + } else { + Comment(";;; @%d: %s. <#%d>", current_instruction_, + instr->Mnemonic(), hydrogen->id()); + } + } else { + Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); + } + } instr->CompileToNative(this); } } @@ -432,7 +461,9 @@ MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const { void LCodeGen::WriteTranslation(LEnvironment* environment, - Translation* translation) { + Translation* translation, + int* arguments_index, + int* arguments_count) { if (environment == NULL) return; // The translation includes one command per value in the environment. @@ -440,7 +471,17 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, // The output frame height does not include the parameters. int height = translation_size - environment->parameter_count(); - WriteTranslation(environment->outer(), translation); + // Function parameters are arguments to the outermost environment. The + // arguments index points to the first element of a sequence of tagged + // values on the stack that represent the arguments. This needs to be + // kept in sync with the LArgumentsElements implementation. + *arguments_index = -environment->parameter_count(); + *arguments_count = environment->parameter_count(); + + WriteTranslation(environment->outer(), + translation, + arguments_index, + arguments_count); int closure_id = *info()->closure() != *environment->closure() ? DefineDeoptimizationLiteral(environment->closure()) : Translation::kSelfLiteralId; @@ -466,6 +507,17 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); break; } + + // Inlined frames which push their arguments cause the index to be + // bumped and a new stack area to be used for materialization. + if (environment->entry() != NULL && + environment->entry()->arguments_pushed()) { + *arguments_index = *arguments_index < 0 + ? GetStackSlotCount() + : *arguments_index + *arguments_count; + *arguments_count = environment->entry()->arguments_count() + 1; + } + for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); // spilled_registers_ and spilled_double_registers_ are either @@ -477,7 +529,9 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, AddToTranslation(translation, environment->spilled_registers()[value->index()], environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } else if ( value->IsDoubleRegister() && environment->spilled_double_registers()[value->index()] != NULL) { @@ -486,14 +540,18 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation, environment->spilled_double_registers()[value->index()], false, - false); + false, + *arguments_index, + *arguments_count); } } AddToTranslation(translation, value, environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } } @@ -501,12 +559,14 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, void LCodeGen::AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32) { + bool is_uint32, + int arguments_index, + int arguments_count) { if (op == NULL) { // TODO(twuerthinger): Introduce marker operands to indicate that this value // is not present and must be reconstructed from the deoptimizer. Currently // this is only used for the arguments object. - translation->StoreArgumentsObject(); + translation->StoreArgumentsObject(arguments_index, arguments_count); } else if (op->IsStackSlot()) { if (is_tagged) { translation->StoreStackSlot(op->index()); @@ -602,6 +662,8 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, int frame_count = 0; int jsframe_count = 0; + int args_index = 0; + int args_count = 0; for (LEnvironment* e = environment; e != NULL; e = e->outer()) { ++frame_count; if (e->frame_type() == JS_FUNCTION) { @@ -609,7 +671,7 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, } } Translation translation(&translations_, frame_count, jsframe_count, zone()); - WriteTranslation(environment, &translation); + WriteTranslation(environment, &translation, &args_index, &args_count); int deoptimization_index = deoptimizations_.length(); int pc_offset = masm()->pc_offset(); environment->Register(deoptimization_index, @@ -878,7 +940,7 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { void LCodeGen::DoModI(LModI* instr) { Register scratch = scratch0(); - const Register left = ToRegister(instr->InputAt(0)); + const Register left = ToRegister(instr->left()); const Register result = ToRegister(instr->result()); Label done; @@ -906,7 +968,7 @@ void LCodeGen::DoModI(LModI* instr) { __ And(result, scratch, p2constant - 1); } else { // div runs in the background while we check for special cases. - Register right = EmitLoadRegister(instr->InputAt(1), scratch); + Register right = EmitLoadRegister(instr->right(), scratch); __ div(left, right); // Check for x % 0. @@ -926,8 +988,8 @@ void LCodeGen::DoModI(LModI* instr) { void LCodeGen::DoDivI(LDivI* instr) { - const Register left = ToRegister(instr->InputAt(0)); - const Register right = ToRegister(instr->InputAt(1)); + const Register left = ToRegister(instr->left()); + const Register right = ToRegister(instr->right()); const Register result = ToRegister(instr->result()); // On MIPS div is asynchronous - it will run in the background while we @@ -965,8 +1027,8 @@ void LCodeGen::DoMulI(LMulI* instr) { Register scratch = scratch0(); Register result = ToRegister(instr->result()); // Note that result may alias left. - Register left = ToRegister(instr->InputAt(0)); - LOperand* right_op = instr->InputAt(1); + Register left = ToRegister(instr->left()); + LOperand* right_op = instr->right(); bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); bool bailout_on_minus_zero = @@ -1036,7 +1098,7 @@ void LCodeGen::DoMulI(LMulI* instr) { } else { Register right = EmitLoadRegister(right_op, scratch); if (bailout_on_minus_zero) { - __ Or(ToRegister(instr->TempAt(0)), left, right); + __ Or(ToRegister(instr->temp()), left, right); } if (can_overflow) { @@ -1056,7 +1118,7 @@ void LCodeGen::DoMulI(LMulI* instr) { __ Branch(&done, ne, result, Operand(zero_reg)); DeoptimizeIf(lt, instr->environment(), - ToRegister(instr->TempAt(0)), + ToRegister(instr->temp()), Operand(zero_reg)); __ bind(&done); } @@ -1065,8 +1127,8 @@ void LCodeGen::DoMulI(LMulI* instr) { void LCodeGen::DoBitI(LBitI* instr) { - LOperand* left_op = instr->InputAt(0); - LOperand* right_op = instr->InputAt(1); + LOperand* left_op = instr->left(); + LOperand* right_op = instr->right(); ASSERT(left_op->IsRegister()); Register left = ToRegister(left_op); Register result = ToRegister(instr->result()); @@ -1099,14 +1161,17 @@ void LCodeGen::DoBitI(LBitI* instr) { void LCodeGen::DoShiftI(LShiftI* instr) { // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so // result may alias either of them. - LOperand* right_op = instr->InputAt(1); - Register left = ToRegister(instr->InputAt(0)); + LOperand* right_op = instr->right(); + Register left = ToRegister(instr->left()); Register result = ToRegister(instr->result()); if (right_op->IsRegister()) { // No need to mask the right operand on MIPS, it is built into the variable // shift instructions. switch (instr->op()) { + case Token::ROR: + __ Ror(result, left, Operand(ToRegister(right_op))); + break; case Token::SAR: __ srav(result, left, ToRegister(right_op)); break; @@ -1128,6 +1193,13 @@ void LCodeGen::DoShiftI(LShiftI* instr) { int value = ToInteger32(LConstantOperand::cast(right_op)); uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); switch (instr->op()) { + case Token::ROR: + if (shift_count != 0) { + __ Ror(result, left, Operand(shift_count)); + } else { + __ Move(result, left); + } + break; case Token::SAR: if (shift_count != 0) { __ sra(result, left, shift_count); @@ -1162,8 +1234,8 @@ void LCodeGen::DoShiftI(LShiftI* instr) { void LCodeGen::DoSubI(LSubI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); LOperand* result = instr->result(); bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); @@ -1227,28 +1299,28 @@ void LCodeGen::DoConstantT(LConstantT* instr) { void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ lw(result, FieldMemOperand(array, JSArray::kLengthOffset)); } void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ lw(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset)); } void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) { Register result = ToRegister(instr->result()); - Register map = ToRegister(instr->InputAt(0)); + Register map = ToRegister(instr->value()); __ EnumLength(result, map); } void LCodeGen::DoElementsKind(LElementsKind* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); // Load map into |result|. __ lw(result, FieldMemOperand(input, HeapObject::kMapOffset)); @@ -1261,9 +1333,9 @@ void LCodeGen::DoElementsKind(LElementsKind* instr) { void LCodeGen::DoValueOf(LValueOf* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); - Register map = ToRegister(instr->TempAt(0)); + Register map = ToRegister(instr->temp()); Label done; // If the object is a smi return the object. @@ -1280,9 +1352,9 @@ void LCodeGen::DoValueOf(LValueOf* instr) { void LCodeGen::DoDateField(LDateField* instr) { - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->date()); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); Smi* index = instr->index(); Label runtime, done; ASSERT(object.is(a0)); @@ -1318,14 +1390,14 @@ void LCodeGen::DoDateField(LDateField* instr) { void LCodeGen::DoBitNotI(LBitNotI* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); __ Nor(result, zero_reg, Operand(input)); } void LCodeGen::DoThrow(LThrow* instr) { - Register input_reg = EmitLoadRegister(instr->InputAt(0), at); + Register input_reg = EmitLoadRegister(instr->value(), at); __ push(input_reg); CallRuntime(Runtime::kThrow, 1, instr); @@ -1336,8 +1408,8 @@ void LCodeGen::DoThrow(LThrow* instr) { void LCodeGen::DoAddI(LAddI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); LOperand* result = instr->result(); bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); @@ -1375,8 +1447,8 @@ void LCodeGen::DoAddI(LAddI* instr) { void LCodeGen::DoMathMinMax(LMathMinMax* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); HMathMinMax::Operation operation = instr->hydrogen()->operation(); Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge; if (instr->hydrogen()->representation().IsInteger32()) { @@ -1437,8 +1509,8 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { void LCodeGen::DoArithmeticD(LArithmeticD* instr) { - DoubleRegister left = ToDoubleRegister(instr->InputAt(0)); - DoubleRegister right = ToDoubleRegister(instr->InputAt(1)); + DoubleRegister left = ToDoubleRegister(instr->left()); + DoubleRegister right = ToDoubleRegister(instr->right()); DoubleRegister result = ToDoubleRegister(instr->result()); switch (instr->op()) { case Token::ADD: @@ -1478,8 +1550,8 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { void LCodeGen::DoArithmeticT(LArithmeticT* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(a1)); - ASSERT(ToRegister(instr->InputAt(1)).is(a0)); + ASSERT(ToRegister(instr->left()).is(a1)); + ASSERT(ToRegister(instr->right()).is(a0)); ASSERT(ToRegister(instr->result()).is(v0)); BinaryOpStub stub(instr->op(), NO_OVERWRITE); @@ -1543,15 +1615,15 @@ void LCodeGen::DoBranch(LBranch* instr) { Representation r = instr->hydrogen()->value()->representation(); if (r.IsInteger32()) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg)); } else if (r.IsDouble()) { - DoubleRegister reg = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister reg = ToDoubleRegister(instr->value()); // Test the double value. Zero and NaN are false. EmitBranchF(true_block, false_block, ne, reg, kDoubleRegZero); } else { ASSERT(r.IsTagged()); - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); HType type = instr->hydrogen()->value()->type(); if (type.IsBoolean()) { __ LoadRoot(at, Heap::kTrueValueRootIndex); @@ -1685,8 +1757,8 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -1737,8 +1809,8 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); - Register right = ToRegister(instr->InputAt(1)); + Register left = ToRegister(instr->left()); + Register right = ToRegister(instr->right()); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -1747,7 +1819,7 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); + Register left = ToRegister(instr->left()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1759,7 +1831,7 @@ void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { Register scratch = scratch0(); - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); int false_block = chunk_->LookupDestination(instr->false_block_id()); // If the expression is known to be untagged or a smi, then it's definitely @@ -1825,8 +1897,8 @@ Condition LCodeGen::EmitIsObject(Register input, void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp1 = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp1 = ToRegister(instr->temp()); Register temp2 = scratch0(); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -1853,8 +1925,8 @@ Condition LCodeGen::EmitIsString(Register input, void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp1 = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp1 = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1872,15 +1944,15 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); - Register input_reg = EmitLoadRegister(instr->InputAt(0), at); + Register input_reg = EmitLoadRegister(instr->value(), at); __ And(at, input_reg, kSmiTagMask); EmitBranch(true_block, false_block, eq, at, Operand(zero_reg)); } void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register input = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1949,7 +2021,7 @@ static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { Register scratch = scratch0(); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1968,10 +2040,10 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); - __ AbortIfNotString(input); + __ AssertString(input); __ lw(result, FieldMemOperand(input, String::kHashFieldOffset)); __ IndexFromHash(result, result); @@ -1980,7 +2052,7 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { void LCodeGen::DoHasCachedArrayIndexAndBranch( LHasCachedArrayIndexAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register scratch = scratch0(); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -2060,9 +2132,9 @@ void LCodeGen::EmitClassOfTest(Label* is_true, void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register temp = scratch0(); - Register temp2 = ToRegister(instr->TempAt(0)); + Register temp2 = ToRegister(instr->temp()); Handle<String> class_name = instr->hydrogen()->class_name(); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -2078,8 +2150,8 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = instr->true_block_id(); int false_block = instr->false_block_id(); @@ -2090,8 +2162,8 @@ void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { void LCodeGen::DoInstanceOf(LInstanceOf* instr) { Label true_label, done; - ASSERT(ToRegister(instr->InputAt(0)).is(a0)); // Object is in a0. - ASSERT(ToRegister(instr->InputAt(1)).is(a1)); // Function is in a1. + ASSERT(ToRegister(instr->left()).is(a0)); // Object is in a0. + ASSERT(ToRegister(instr->right()).is(a1)); // Function is in a1. Register result = ToRegister(instr->result()); ASSERT(result.is(v0)); @@ -2128,8 +2200,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr); Label done, false_result; - Register object = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register object = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); Register result = ToRegister(instr->result()); ASSERT(object.is(a0)); @@ -2204,7 +2276,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, // Get the temp register reserved by the instruction. This needs to be t0 as // its slot of the pushing of safepoint registers is used to communicate the // offset to the location of the map check. - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); ASSERT(temp.is(t0)); __ LoadHeapObject(InstanceofStub::right(), instr->function()); static const int kAdditionalDelta = 7; @@ -2299,7 +2371,7 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { // it as no longer deleted. if (instr->hydrogen()->RequiresHoleCheck()) { // We use a temp to check the payload. - Register payload = ToRegister(instr->TempAt(0)); + Register payload = ToRegister(instr->temp()); __ lw(payload, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset)); __ LoadRoot(at, Heap::kTheHoleValueRootIndex); DeoptimizeIf(eq, instr->environment(), payload, Operand(at)); @@ -2382,7 +2454,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->object()); Register result = ToRegister(instr->result()); if (instr->hydrogen()->is_in_object()) { __ lw(result, FieldMemOperand(object, instr->hydrogen()->offset())); @@ -2535,7 +2607,7 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->object()); Register scratch = scratch0(); __ lw(result, FieldMemOperand(input, JSObject::kElementsOffset)); @@ -2568,7 +2640,7 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) { void LCodeGen::DoLoadExternalArrayPointer( LLoadExternalArrayPointer* instr) { Register to_reg = ToRegister(instr->result()); - Register from_reg = ToRegister(instr->InputAt(0)); + Register from_reg = ToRegister(instr->object()); __ lw(to_reg, FieldMemOperand(from_reg, ExternalArray::kExternalPointerOffset)); } @@ -2579,14 +2651,6 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { Register length = ToRegister(instr->length()); Register index = ToRegister(instr->index()); Register result = ToRegister(instr->result()); - - // Bailout index is not a valid argument index. Use unsigned check to get - // negative check for free. - - // TODO(plind): Shoud be optimized to do the sub before the DeoptimizeIf(), - // as they do in Arm. It will save us an instruction. - DeoptimizeIf(ls, instr->environment(), length, Operand(index)); - // There are two words between the frame pointer and the last argument. // Subtracting from length accounts for one of them, add one more. __ subu(length, length, index); @@ -2597,50 +2661,89 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { } -void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { - Register elements = ToRegister(instr->elements()); - Register result = ToRegister(instr->result()); - Register scratch = scratch0(); - Register store_base = scratch; - int offset = 0; - - if (instr->key()->IsConstantOperand()) { - LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); - offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + - instr->additional_index()); - store_base = elements; - } else { - Register key = EmitLoadRegister(instr->key(), scratch); - // Even though the HLoadKeyedFastElement instruction forces the input - // representation for the key to be an integer, the input gets replaced - // during bound check elimination with the index argument to the bounds - // check, which can be tagged, so that case must be handled here, too. - if (instr->hydrogen()->key()->representation().IsTagged()) { - __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize); - __ addu(scratch, elements, scratch); - } else { - __ sll(scratch, key, kPointerSizeLog2); - __ addu(scratch, elements, scratch); +void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { + Register external_pointer = ToRegister(instr->elements()); + Register key = no_reg; + ElementsKind elements_kind = instr->elements_kind(); + bool key_is_constant = instr->key()->IsConstantOperand(); + int constant_key = 0; + if (key_is_constant) { + constant_key = ToInteger32(LConstantOperand::cast(instr->key())); + if (constant_key & 0xF0000000) { + Abort("array index constant value too big."); } - offset = FixedArray::OffsetOfElementAt(instr->additional_index()); + } else { + key = ToRegister(instr->key()); } - __ lw(result, FieldMemOperand(store_base, offset)); + int element_size_shift = ElementsKindToShiftSize(elements_kind); + int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) + ? (element_size_shift - kSmiTagSize) : element_size_shift; + int additional_offset = instr->additional_index() << element_size_shift; - // Check for the hole value. - if (instr->hydrogen()->RequiresHoleCheck()) { - if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { - __ And(scratch, result, Operand(kSmiTagMask)); - DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg)); + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || + elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { + FPURegister result = ToDoubleRegister(instr->result()); + if (key_is_constant) { + __ Addu(scratch0(), external_pointer, constant_key << element_size_shift); } else { - __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); - DeoptimizeIf(eq, instr->environment(), result, Operand(scratch)); + __ sll(scratch0(), key, shift_size); + __ Addu(scratch0(), scratch0(), external_pointer); + } + + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { + __ lwc1(result, MemOperand(scratch0(), additional_offset)); + __ cvt_d_s(result, result); + } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS + __ ldc1(result, MemOperand(scratch0(), additional_offset)); + } + } else { + Register result = ToRegister(instr->result()); + MemOperand mem_operand = PrepareKeyedOperand( + key, external_pointer, key_is_constant, constant_key, + element_size_shift, shift_size, + instr->additional_index(), additional_offset); + switch (elements_kind) { + case EXTERNAL_BYTE_ELEMENTS: + __ lb(result, mem_operand); + break; + case EXTERNAL_PIXEL_ELEMENTS: + case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: + __ lbu(result, mem_operand); + break; + case EXTERNAL_SHORT_ELEMENTS: + __ lh(result, mem_operand); + break; + case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: + __ lhu(result, mem_operand); + break; + case EXTERNAL_INT_ELEMENTS: + __ lw(result, mem_operand); + break; + case EXTERNAL_UNSIGNED_INT_ELEMENTS: + __ lw(result, mem_operand); + if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { + DeoptimizeIf(Ugreater_equal, instr->environment(), + result, Operand(0x80000000)); + } + break; + case EXTERNAL_FLOAT_ELEMENTS: + case EXTERNAL_DOUBLE_ELEMENTS: + case FAST_DOUBLE_ELEMENTS: + case FAST_ELEMENTS: + case FAST_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case DICTIONARY_ELEMENTS: + case NON_STRICT_ARGUMENTS_ELEMENTS: + UNREACHABLE(); + break; } } } -void LCodeGen::DoLoadKeyedFastDoubleElement( - LLoadKeyedFastDoubleElement* instr) { +void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { Register elements = ToRegister(instr->elements()); bool key_is_constant = instr->key()->IsConstantOperand(); Register key = no_reg; @@ -2682,6 +2785,59 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( } +void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { + Register elements = ToRegister(instr->elements()); + Register result = ToRegister(instr->result()); + Register scratch = scratch0(); + Register store_base = scratch; + int offset = 0; + + if (instr->key()->IsConstantOperand()) { + LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); + offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + + instr->additional_index()); + store_base = elements; + } else { + Register key = EmitLoadRegister(instr->key(), scratch0()); + // Even though the HLoadKeyed instruction forces the input + // representation for the key to be an integer, the input gets replaced + // during bound check elimination with the index argument to the bounds + // check, which can be tagged, so that case must be handled here, too. + if (instr->hydrogen()->key()->representation().IsTagged()) { + __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize); + __ addu(scratch, elements, scratch); + } else { + __ sll(scratch, key, kPointerSizeLog2); + __ addu(scratch, elements, scratch); + } + offset = FixedArray::OffsetOfElementAt(instr->additional_index()); + } + __ lw(result, FieldMemOperand(store_base, offset)); + + // Check for the hole value. + if (instr->hydrogen()->RequiresHoleCheck()) { + if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { + __ And(scratch, result, Operand(kSmiTagMask)); + DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg)); + } else { + __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); + DeoptimizeIf(eq, instr->environment(), result, Operand(scratch)); + } + } +} + + +void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { + if (instr->is_external()) { + DoLoadKeyedExternalArray(instr); + } else if (instr->hydrogen()->representation().IsDouble()) { + DoLoadKeyedFixedDoubleArray(instr); + } else { + DoLoadKeyedFixedArray(instr); + } +} + + MemOperand LCodeGen::PrepareKeyedOperand(Register key, Register base, bool key_is_constant, @@ -2726,89 +2882,6 @@ MemOperand LCodeGen::PrepareKeyedOperand(Register key, } -void LCodeGen::DoLoadKeyedSpecializedArrayElement( - LLoadKeyedSpecializedArrayElement* instr) { - Register external_pointer = ToRegister(instr->external_pointer()); - Register key = no_reg; - ElementsKind elements_kind = instr->elements_kind(); - bool key_is_constant = instr->key()->IsConstantOperand(); - int constant_key = 0; - if (key_is_constant) { - constant_key = ToInteger32(LConstantOperand::cast(instr->key())); - if (constant_key & 0xF0000000) { - Abort("array index constant value too big."); - } - } else { - key = ToRegister(instr->key()); - } - int element_size_shift = ElementsKindToShiftSize(elements_kind); - int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) - ? (element_size_shift - kSmiTagSize) : element_size_shift; - int additional_offset = instr->additional_index() << element_size_shift; - - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || - elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { - FPURegister result = ToDoubleRegister(instr->result()); - if (key_is_constant) { - __ Addu(scratch0(), external_pointer, constant_key << element_size_shift); - } else { - __ sll(scratch0(), key, shift_size); - __ Addu(scratch0(), scratch0(), external_pointer); - } - - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { - __ lwc1(result, MemOperand(scratch0(), additional_offset)); - __ cvt_d_s(result, result); - } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS - __ ldc1(result, MemOperand(scratch0(), additional_offset)); - } - } else { - Register result = ToRegister(instr->result()); - MemOperand mem_operand = PrepareKeyedOperand( - key, external_pointer, key_is_constant, constant_key, - element_size_shift, shift_size, - instr->additional_index(), additional_offset); - switch (elements_kind) { - case EXTERNAL_BYTE_ELEMENTS: - __ lb(result, mem_operand); - break; - case EXTERNAL_PIXEL_ELEMENTS: - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ lbu(result, mem_operand); - break; - case EXTERNAL_SHORT_ELEMENTS: - __ lh(result, mem_operand); - break; - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ lhu(result, mem_operand); - break; - case EXTERNAL_INT_ELEMENTS: - __ lw(result, mem_operand); - break; - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ lw(result, mem_operand); - if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { - DeoptimizeIf(Ugreater_equal, instr->environment(), - result, Operand(0x80000000)); - } - break; - case EXTERNAL_FLOAT_ELEMENTS: - case EXTERNAL_DOUBLE_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_ELEMENTS: - case FAST_SMI_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - case FAST_HOLEY_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case DICTIONARY_ELEMENTS: - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNREACHABLE(); - break; - } - } -} - - void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(a1)); ASSERT(ToRegister(instr->key()).is(a0)); @@ -2841,7 +2914,7 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { - Register elem = ToRegister(instr->InputAt(0)); + Register elem = ToRegister(instr->elements()); Register result = ToRegister(instr->result()); Label done; @@ -2959,7 +3032,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { - LOperand* argument = instr->InputAt(0); + LOperand* argument = instr->value(); if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { Abort("DoPushArgument not implemented for double type."); } else { @@ -3010,7 +3083,7 @@ void LCodeGen::DoGlobalObject(LGlobalObject* instr) { void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { - Register global = ToRegister(instr->global()); + Register global = ToRegister(instr->global_object()); Register result = ToRegister(instr->result()); __ lw(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset)); } @@ -3071,7 +3144,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); Register scratch = scratch0(); @@ -3136,7 +3209,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); Label done; @@ -3167,7 +3240,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { Representation r = instr->hydrogen()->value()->representation(); if (r.IsDouble()) { - FPURegister input = ToDoubleRegister(instr->InputAt(0)); + FPURegister input = ToDoubleRegister(instr->value()); FPURegister result = ToDoubleRegister(instr->result()); __ abs_d(result, input); } else if (r.IsInteger32()) { @@ -3176,7 +3249,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { // Representation is tagged. DeferredMathAbsTaggedHeapNumber* deferred = new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); // Smi check. __ JumpIfNotSmi(input, deferred->entry()); // If smi, handle it directly. @@ -3187,24 +3260,21 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); Register result = ToRegister(instr->result()); - FPURegister single_scratch = double_scratch0().low(); Register scratch1 = scratch0(); - Register except_flag = ToRegister(instr->TempAt(0)); + Register except_flag = ToRegister(instr->temp()); __ EmitFPUTruncate(kRoundToMinusInf, - single_scratch, + result, input, scratch1, + double_scratch0(), except_flag); // Deopt if the operation did not succeed. DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg)); - // Load the result. - __ mfc1(result, single_scratch); - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { // Test for -0. Label done; @@ -3218,8 +3288,9 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); Register result = ToRegister(instr->result()); + DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp()); Register scratch = scratch0(); Label done, check_sign_on_zero; @@ -3271,17 +3342,15 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { } Register except_flag = scratch; - __ EmitFPUTruncate(kRoundToMinusInf, - double_scratch0().low(), - double_scratch0(), result, + double_scratch0(), + at, + double_scratch1, except_flag); DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg)); - __ mfc1(result, double_scratch0().low()); - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { // Test for -0. __ Branch(&done, ne, result, Operand(zero_reg)); @@ -3295,16 +3364,16 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); DoubleRegister result = ToDoubleRegister(instr->result()); __ sqrt_d(result, input); } void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); DoubleRegister result = ToDoubleRegister(instr->result()); - DoubleRegister temp = ToDoubleRegister(instr->TempAt(0)); + DoubleRegister temp = ToDoubleRegister(instr->temp()); ASSERT(!input.is(result)); @@ -3329,11 +3398,11 @@ void LCodeGen::DoPower(LPower* instr) { Representation exponent_type = instr->hydrogen()->right()->representation(); // Having marked this as a call, we can use any registers. // Just make sure that the input/output registers are the expected ones. - ASSERT(!instr->InputAt(1)->IsDoubleRegister() || - ToDoubleRegister(instr->InputAt(1)).is(f4)); - ASSERT(!instr->InputAt(1)->IsRegister() || - ToRegister(instr->InputAt(1)).is(a2)); - ASSERT(ToDoubleRegister(instr->InputAt(0)).is(f2)); + ASSERT(!instr->right()->IsDoubleRegister() || + ToDoubleRegister(instr->right()).is(f4)); + ASSERT(!instr->right()->IsRegister() || + ToRegister(instr->right()).is(a2)); + ASSERT(ToDoubleRegister(instr->left()).is(f2)); ASSERT(ToDoubleRegister(instr->result()).is(f0)); if (exponent_type.IsTagged()) { @@ -3370,7 +3439,7 @@ void LCodeGen::DoRandom(LRandom* instr) { // Having marked this instruction as a call we can use any // registers. ASSERT(ToDoubleRegister(instr->result()).is(f0)); - ASSERT(ToRegister(instr->InputAt(0)).is(a0)); + ASSERT(ToRegister(instr->global_object()).is(a0)); static const int kSeedSize = sizeof(uint32_t); STATIC_ASSERT(kPointerSize == kSeedSize); @@ -3431,6 +3500,20 @@ void LCodeGen::DoDeferredRandom(LRandom* instr) { } +void LCodeGen::DoMathExp(LMathExp* instr) { + DoubleRegister input = ToDoubleRegister(instr->value()); + DoubleRegister result = ToDoubleRegister(instr->result()); + DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp()); + DoubleRegister double_scratch2 = double_scratch0(); + Register temp1 = ToRegister(instr->temp1()); + Register temp2 = ToRegister(instr->temp2()); + + MathExpGenerator::EmitMathExp( + masm(), input, result, double_scratch1, double_scratch2, + temp1, temp2, scratch0()); +} + + void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { ASSERT(ToDoubleRegister(instr->result()).is(f4)); TranscendentalCacheStub stub(TranscendentalCache::LOG, @@ -3580,7 +3663,7 @@ void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { void LCodeGen::DoCallNew(LCallNew* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(a1)); + ASSERT(ToRegister(instr->constructor()).is(a1)); ASSERT(ToRegister(instr->result()).is(v0)); CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); @@ -3606,7 +3689,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { __ li(scratch, Operand(instr->transition())); __ sw(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); if (instr->hydrogen()->NeedsWriteBarrierForMap()) { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); // Update the write barrier for the map field. __ RecordWriteField(object, HeapObject::kMapOffset, @@ -3712,108 +3795,8 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { } -void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { - Register value = ToRegister(instr->value()); - Register elements = ToRegister(instr->object()); - Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; - Register scratch = scratch0(); - Register store_base = scratch; - int offset = 0; - - // Do the store. - if (instr->key()->IsConstantOperand()) { - ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); - LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); - offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + - instr->additional_index()); - store_base = elements; - } else { - // Even though the HLoadKeyedFastElement instruction forces the input - // representation for the key to be an integer, the input gets replaced - // during bound check elimination with the index argument to the bounds - // check, which can be tagged, so that case must be handled here, too. - if (instr->hydrogen()->key()->representation().IsTagged()) { - __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize); - __ addu(scratch, elements, scratch); - } else { - __ sll(scratch, key, kPointerSizeLog2); - __ addu(scratch, elements, scratch); - } - offset = FixedArray::OffsetOfElementAt(instr->additional_index()); - } - __ sw(value, FieldMemOperand(store_base, offset)); - - if (instr->hydrogen()->NeedsWriteBarrier()) { - HType type = instr->hydrogen()->value()->type(); - SmiCheck check_needed = - type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; - // Compute address of modified element and store it into key register. - __ Addu(key, store_base, Operand(offset - kHeapObjectTag)); - __ RecordWrite(elements, - key, - value, - kRAHasBeenSaved, - kSaveFPRegs, - EMIT_REMEMBERED_SET, - check_needed); - } -} - - -void LCodeGen::DoStoreKeyedFastDoubleElement( - LStoreKeyedFastDoubleElement* instr) { - DoubleRegister value = ToDoubleRegister(instr->value()); - Register elements = ToRegister(instr->elements()); - Register key = no_reg; - 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. - if (key_is_constant) { - constant_key = ToInteger32(LConstantOperand::cast(instr->key())); - if (constant_key & 0xF0000000) { - Abort("array index constant value too big."); - } - } else { - key = ToRegister(instr->key()); - } - int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); - int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) - ? (element_size_shift - kSmiTagSize) : element_size_shift; - if (key_is_constant) { - __ Addu(scratch, elements, Operand((constant_key << element_size_shift) + - FixedDoubleArray::kHeaderSize - kHeapObjectTag)); - } else { - __ sll(scratch, key, shift_size); - __ Addu(scratch, elements, Operand(scratch)); - __ Addu(scratch, scratch, - Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); - } - - 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()); - } - - __ bind(¬_nan); - __ sdc1(value, MemOperand(scratch, instr->additional_index() << - element_size_shift)); -} - - -void LCodeGen::DoStoreKeyedSpecializedArrayElement( - LStoreKeyedSpecializedArrayElement* instr) { - - Register external_pointer = ToRegister(instr->external_pointer()); +void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { + Register external_pointer = ToRegister(instr->elements()); Register key = no_reg; ElementsKind elements_kind = instr->elements_kind(); bool key_is_constant = instr->key()->IsConstantOperand(); @@ -3884,6 +3867,117 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( } } + +void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { + DoubleRegister value = ToDoubleRegister(instr->value()); + Register elements = ToRegister(instr->elements()); + Register key = no_reg; + 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. + if (key_is_constant) { + constant_key = ToInteger32(LConstantOperand::cast(instr->key())); + if (constant_key & 0xF0000000) { + Abort("array index constant value too big."); + } + } else { + key = ToRegister(instr->key()); + } + int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); + int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) + ? (element_size_shift - kSmiTagSize) : element_size_shift; + if (key_is_constant) { + __ Addu(scratch, elements, Operand((constant_key << element_size_shift) + + FixedDoubleArray::kHeaderSize - kHeapObjectTag)); + } else { + __ sll(scratch, key, shift_size); + __ Addu(scratch, elements, Operand(scratch)); + __ Addu(scratch, scratch, + Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); + } + + 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()); + } + + __ bind(¬_nan); + __ sdc1(value, MemOperand(scratch, instr->additional_index() << + element_size_shift)); +} + + +void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { + Register value = ToRegister(instr->value()); + Register elements = ToRegister(instr->elements()); + Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) + : no_reg; + Register scratch = scratch0(); + Register store_base = scratch; + int offset = 0; + + // Do the store. + if (instr->key()->IsConstantOperand()) { + ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); + LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); + offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + + instr->additional_index()); + store_base = elements; + } else { + // Even though the HLoadKeyed instruction forces the input + // representation for the key to be an integer, the input gets replaced + // during bound check elimination with the index argument to the bounds + // check, which can be tagged, so that case must be handled here, too. + if (instr->hydrogen()->key()->representation().IsTagged()) { + __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize); + __ addu(scratch, elements, scratch); + } else { + __ sll(scratch, key, kPointerSizeLog2); + __ addu(scratch, elements, scratch); + } + offset = FixedArray::OffsetOfElementAt(instr->additional_index()); + } + __ sw(value, FieldMemOperand(store_base, offset)); + + if (instr->hydrogen()->NeedsWriteBarrier()) { + HType type = instr->hydrogen()->value()->type(); + SmiCheck check_needed = + type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; + // Compute address of modified element and store it into key register. + __ Addu(key, store_base, Operand(offset - kHeapObjectTag)); + __ RecordWrite(elements, + key, + value, + kRAHasBeenSaved, + kSaveFPRegs, + EMIT_REMEMBERED_SET, + check_needed); + } +} + + +void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { + // By cases: external, fast double + if (instr->is_external()) { + DoStoreKeyedExternalArray(instr); + } else if (instr->hydrogen()->value()->representation().IsDouble()) { + DoStoreKeyedFixedDoubleArray(instr); + } else { + DoStoreKeyedFixedArray(instr); + } +} + + void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(a2)); ASSERT(ToRegister(instr->key()).is(a1)); @@ -3898,7 +3992,7 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { Register object_reg = ToRegister(instr->object()); - Register new_map_reg = ToRegister(instr->new_map_reg()); + Register new_map_reg = ToRegister(instr->new_map_temp()); Register scratch = scratch0(); Handle<Map> from_map = instr->original_map(); @@ -3920,7 +4014,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { scratch, kRAHasBeenSaved, kDontSaveFPRegs); } else if (IsFastSmiElementsKind(from_kind) && IsFastDoubleElementsKind(to_kind)) { - Register fixed_object_reg = ToRegister(instr->temp_reg()); + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(a2)); ASSERT(new_map_reg.is(a3)); __ mov(fixed_object_reg, object_reg); @@ -3928,7 +4022,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { RelocInfo::CODE_TARGET, instr); } else if (IsFastDoubleElementsKind(from_kind) && IsFastObjectElementsKind(to_kind)) { - Register fixed_object_reg = ToRegister(instr->temp_reg()); + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(a2)); ASSERT(new_map_reg.is(a3)); __ mov(fixed_object_reg, object_reg); @@ -3995,9 +4089,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { __ push(index); } CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); - if (FLAG_debug_code) { - __ AbortIfNotSmi(v0); - } + __ AssertSmi(v0); __ SmiUntag(v0); __ StoreToSafepointRegisterSlot(v0, result); } @@ -4053,14 +4145,14 @@ void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { void LCodeGen::DoStringLength(LStringLength* instr) { - Register string = ToRegister(instr->InputAt(0)); + Register string = ToRegister(instr->string()); Register result = ToRegister(instr->result()); __ lw(result, FieldMemOperand(string, String::kLengthOffset)); } void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() || input->IsStackSlot()); LOperand* output = instr->result(); ASSERT(output->IsDoubleRegister()); @@ -4077,7 +4169,7 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); LOperand* output = instr->result(); FPURegister dbl_scratch = double_scratch0(); @@ -4093,7 +4185,7 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_, - instr_->InputAt(0), + instr_->value(), SIGNED_INT32); } virtual LInstruction* instr() { return instr_; } @@ -4101,7 +4193,7 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { LNumberTagI* instr_; }; - Register src = ToRegister(instr->InputAt(0)); + Register src = ToRegister(instr->value()); Register dst = ToRegister(instr->result()); Register overflow = scratch0(); @@ -4119,7 +4211,7 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_, - instr_->InputAt(0), + instr_->value(), UNSIGNED_INT32); } virtual LInstruction* instr() { return instr_; } @@ -4127,7 +4219,7 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { LNumberTagU* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() && input->Equals(instr->result())); Register reg = ToRegister(input); @@ -4167,7 +4259,7 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, if (FLAG_inline_new) { __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(t1, a3, t0, t2, &slow); + __ AllocateHeapNumber(t1, a3, t0, t2, &slow, DONT_TAG_RESULT); __ Move(dst, t1); __ Branch(&done); } @@ -4181,11 +4273,13 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, __ StoreToSafepointRegisterSlot(zero_reg, dst); CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); __ Move(dst, v0); + __ Subu(dst, dst, kHeapObjectTag); // Done. Put the value in dbl_scratch into the value of the allocated heap // number. __ bind(&done); - __ sdc1(dbl_scratch, FieldMemOperand(dst, HeapNumber::kValueOffset)); + __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset)); + __ Addu(dst, dst, kHeapObjectTag); __ StoreToSafepointRegisterSlot(dst, dst); } @@ -4201,21 +4295,25 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { LNumberTagD* instr_; }; - DoubleRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input_reg = ToDoubleRegister(instr->value()); Register scratch = scratch0(); Register reg = ToRegister(instr->result()); - Register temp1 = ToRegister(instr->TempAt(0)); - Register temp2 = ToRegister(instr->TempAt(1)); + Register temp1 = ToRegister(instr->temp()); + Register temp2 = ToRegister(instr->temp2()); DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); if (FLAG_inline_new) { __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry()); + // We want the untagged address first for performance + __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(), + DONT_TAG_RESULT); } else { __ Branch(deferred->entry()); } __ bind(deferred->exit()); - __ sdc1(input_reg, FieldMemOperand(reg, HeapNumber::kValueOffset)); + __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset)); + // Now that we have finished with the object's real address tag it + __ Addu(reg, reg, kHeapObjectTag); } @@ -4228,19 +4326,20 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); + __ Subu(v0, v0, kHeapObjectTag); __ StoreToSafepointRegisterSlot(v0, reg); } void LCodeGen::DoSmiTag(LSmiTag* instr) { ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); - __ SmiTag(ToRegister(instr->result()), ToRegister(instr->InputAt(0))); + __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value())); } void LCodeGen::DoSmiUntag(LSmiUntag* instr) { Register scratch = scratch0(); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); if (instr->needs_check()) { STATIC_ASSERT(kHeapObjectTag == 1); @@ -4305,11 +4404,11 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { - Register input_reg = ToRegister(instr->InputAt(0)); + Register input_reg = ToRegister(instr->value()); Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); + Register scratch2 = ToRegister(instr->temp()); DoubleRegister double_scratch = double_scratch0(); - FPURegister single_scratch = double_scratch.low(); + DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp3()); ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1)); @@ -4324,8 +4423,8 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { // of the if. if (instr->truncating()) { - Register scratch3 = ToRegister(instr->TempAt(1)); - DoubleRegister double_scratch2 = ToDoubleRegister(instr->TempAt(2)); + Register scratch3 = ToRegister(instr->temp2()); + FPURegister single_scratch = double_scratch.low(); ASSERT(!scratch3.is(input_reg) && !scratch3.is(scratch1) && !scratch3.is(scratch2)); @@ -4360,18 +4459,16 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { Register except_flag = scratch2; __ EmitFPUTruncate(kRoundToZero, - single_scratch, + input_reg, double_scratch, scratch1, + double_scratch2, except_flag, kCheckForInexactConversion); // Deopt if the operation did not succeed. DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg)); - // Load the result. - __ mfc1(input_reg, single_scratch); - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { __ Branch(&done, ne, input_reg, Operand(zero_reg)); @@ -4395,7 +4492,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { LTaggedToI* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); ASSERT(input->Equals(instr->result())); @@ -4413,7 +4510,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); LOperand* result = instr->result(); ASSERT(result->IsDoubleRegister()); @@ -4431,12 +4528,12 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Register result_reg = ToRegister(instr->result()); Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); - DoubleRegister double_input = ToDoubleRegister(instr->InputAt(0)); - FPURegister single_scratch = double_scratch0().low(); + Register scratch2 = ToRegister(instr->temp()); + DoubleRegister double_input = ToDoubleRegister(instr->value()); if (instr->truncating()) { - Register scratch3 = ToRegister(instr->TempAt(1)); + Register scratch3 = ToRegister(instr->temp2()); + FPURegister single_scratch = double_scratch0().low(); __ EmitECMATruncate(result_reg, double_input, single_scratch, @@ -4447,37 +4544,35 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Register except_flag = scratch2; __ EmitFPUTruncate(kRoundToMinusInf, - single_scratch, + result_reg, double_input, scratch1, + double_scratch0(), except_flag, kCheckForInexactConversion); // Deopt if the operation did not succeed (except_flag != 0). DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg)); - - // Load the result. - __ mfc1(result_reg, single_scratch); } } void LCodeGen::DoCheckSmi(LCheckSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); __ And(at, ToRegister(input), Operand(kSmiTagMask)); DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); } void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); __ And(at, ToRegister(input), Operand(kSmiTagMask)); DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); } void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register scratch = scratch0(); __ GetObjectType(input, scratch, scratch); @@ -4547,7 +4642,7 @@ void LCodeGen::DoCheckMapCommon(Register reg, void LCodeGen::DoCheckMaps(LCheckMaps* instr) { Register scratch = scratch0(); - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); Register reg = ToRegister(input); Label success; @@ -4566,7 +4661,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) { void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { DoubleRegister value_reg = ToDoubleRegister(instr->unclamped()); Register result_reg = ToRegister(instr->result()); - DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0)); + DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); __ ClampDoubleToUint8(result_reg, value_reg, temp_reg); } @@ -4582,7 +4677,7 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { Register scratch = scratch0(); Register input_reg = ToRegister(instr->unclamped()); Register result_reg = ToRegister(instr->result()); - DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0)); + DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); Label is_smi, done, heap_number; // Both smi and heap number cases are handled. @@ -4614,8 +4709,9 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { - Register temp1 = ToRegister(instr->TempAt(0)); - Register temp2 = ToRegister(instr->TempAt(1)); + ASSERT(instr->temp()->Equals(instr->result())); + Register temp1 = ToRegister(instr->temp()); + Register temp2 = ToRegister(instr->temp2()); Handle<JSObject> holder = instr->holder(); Handle<JSObject> current_prototype = instr->prototype(); @@ -4656,8 +4752,8 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { new(zone()) DeferredAllocateObject(this, instr); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->TempAt(0)); - Register scratch2 = ToRegister(instr->TempAt(1)); + Register scratch = ToRegister(instr->temp()); + Register scratch2 = ToRegister(instr->temp2()); Handle<JSFunction> constructor = instr->hydrogen()->constructor(); Handle<Map> initial_map(constructor->initial_map()); int instance_size = initial_map->instance_size(); @@ -4953,7 +5049,7 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { void LCodeGen::DoToFastProperties(LToFastProperties* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(a0)); + ASSERT(ToRegister(instr->value()).is(a0)); ASSERT(ToRegister(instr->result()).is(v0)); __ push(a0); CallRuntime(Runtime::kToFastProperties, 1, instr); @@ -5035,14 +5131,14 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { ASSERT(ToRegister(instr->result()).is(v0)); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); __ push(input); CallRuntime(Runtime::kTypeof, 1, instr); } void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); Label* true_label = chunk_->GetAssemblyLabel(true_block); @@ -5169,7 +5265,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { - Register temp1 = ToRegister(instr->TempAt(0)); + Register temp1 = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -5368,7 +5464,6 @@ void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { Register map = ToRegister(instr->map()); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->scratch()); Label load_cache, done; __ EnumLength(result, map); __ Branch(&load_cache, ne, result, Operand(Smi::FromInt(0))); @@ -5376,7 +5471,7 @@ void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { __ jmp(&done); __ bind(&load_cache); - __ LoadInstanceDescriptors(map, result, scratch); + __ LoadInstanceDescriptors(map, result); __ lw(result, FieldMemOperand(result, DescriptorArray::kEnumCacheOffset)); __ lw(result, diff --git a/deps/v8/src/mips/lithium-codegen-mips.h b/deps/v8/src/mips/lithium-codegen-mips.h index aeafbcd74b..7363eb8efe 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.h +++ b/deps/v8/src/mips/lithium-codegen-mips.h @@ -143,7 +143,10 @@ class LCodeGen BASE_EMBEDDED { int additional_offset); // Emit frame translation commands for an environment. - void WriteTranslation(LEnvironment* environment, Translation* translation); + void WriteTranslation(LEnvironment* environment, + Translation* translation, + int* arguments_index, + int* arguments_count); // Declare methods that deal with the individual node types. #define DECLARE_DO(type) void Do##type(L##type* node); @@ -258,7 +261,9 @@ class LCodeGen BASE_EMBEDDED { void AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32); + bool is_uint32, + int arguments_index, + int arguments_count); void PopulateDeoptimizationData(Handle<Code> code); int DefineDeoptimizationLiteral(Handle<Object> literal); @@ -371,6 +376,12 @@ class LCodeGen BASE_EMBEDDED { }; void EnsureSpaceForLazyDeopt(); + void DoLoadKeyedExternalArray(LLoadKeyed* instr); + void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); + void DoLoadKeyedFixedArray(LLoadKeyed* instr); + void DoStoreKeyedExternalArray(LStoreKeyed* instr); + void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); + void DoStoreKeyedFixedArray(LStoreKeyed* instr); Zone* zone_; LPlatformChunk* const chunk_; diff --git a/deps/v8/src/mips/lithium-mips.cc b/deps/v8/src/mips/lithium-mips.cc index 958bbc491a..56dd33d246 100644 --- a/deps/v8/src/mips/lithium-mips.cc +++ b/deps/v8/src/mips/lithium-mips.cc @@ -177,6 +177,7 @@ const char* LArithmeticT::Mnemonic() const { case Token::BIT_AND: return "bit-and-t"; case Token::BIT_OR: return "bit-or-t"; case Token::BIT_XOR: return "bit-xor-t"; + case Token::ROR: return "ror-t"; case Token::SHL: return "sll-t"; case Token::SAR: return "sra-t"; case Token::SHR: return "srl-t"; @@ -194,22 +195,22 @@ void LGoto::PrintDataTo(StringStream* stream) { void LBranch::PrintDataTo(StringStream* stream) { stream->Add("B%d | B%d on ", true_block_id(), false_block_id()); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); } void LCmpIDAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - InputAt(0)->PrintTo(stream); + left()->PrintTo(stream); stream->Add(" %s ", Token::String(op())); - InputAt(1)->PrintTo(stream); + right()->PrintTo(stream); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); } void LIsNilAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(kind() == kStrictEquality ? " === " : " == "); stream->Add(nil() == kNullValue ? "null" : "undefined"); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); @@ -218,57 +219,57 @@ void LIsNilAndBranch::PrintDataTo(StringStream* stream) { void LIsObjectAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_object("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsStringAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_string("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_smi("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_undetectable("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LStringCompareAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if string_compare("); - InputAt(0)->PrintTo(stream); - InputAt(1)->PrintTo(stream); + left()->PrintTo(stream); + right()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_instance_type("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_cached_array_index("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if class_of_test("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(), true_block_id(), @@ -278,7 +279,7 @@ void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(" == \"%s\" then B%d else B%d", *hydrogen()->type_literal()->ToCString(), true_block_id(), false_block_id()); @@ -292,26 +293,31 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) { void LUnaryMathOperation::PrintDataTo(StringStream* stream) { stream->Add("/%s ", hydrogen()->OpName()); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); +} + + +void LMathExp::PrintDataTo(StringStream* stream) { + value()->PrintTo(stream); } void LLoadContextSlot::PrintDataTo(StringStream* stream) { - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); stream->Add("[%d]", slot_index()); } void LStoreContextSlot::PrintDataTo(StringStream* stream) { - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); stream->Add("[%d] <- ", slot_index()); - InputAt(1)->PrintTo(stream); + value()->PrintTo(stream); } void LInvokeFunction::PrintDataTo(StringStream* stream) { stream->Add("= "); - InputAt(0)->PrintTo(stream); + function()->PrintTo(stream); stream->Add(" #%d / ", arity()); } @@ -340,17 +346,15 @@ void LCallKnownGlobal::PrintDataTo(StringStream* stream) { void LCallNew::PrintDataTo(StringStream* stream) { stream->Add("= "); - InputAt(0)->PrintTo(stream); + constructor()->PrintTo(stream); stream->Add(" #%d / ", arity()); } void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { arguments()->PrintTo(stream); - stream->Add(" length "); length()->PrintTo(stream); - stream->Add(" index "); index()->PrintTo(stream); } @@ -374,20 +378,27 @@ void LStoreNamedGeneric::PrintDataTo(StringStream* stream) { } -void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) { - object()->PrintTo(stream); +void LLoadKeyed::PrintDataTo(StringStream* stream) { + elements()->PrintTo(stream); stream->Add("["); key()->PrintTo(stream); - stream->Add("] <- "); - value()->PrintTo(stream); + if (hydrogen()->IsDehoisted()) { + stream->Add(" + %d]", additional_index()); + } else { + stream->Add("]"); + } } -void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) { +void LStoreKeyed::PrintDataTo(StringStream* stream) { elements()->PrintTo(stream); stream->Add("["); key()->PrintTo(stream); - stream->Add("] <- "); + if (hydrogen()->IsDehoisted()) { + stream->Add(" + %d] <-", additional_index()); + } else { + stream->Add("] <- "); + } value()->PrintTo(stream); } @@ -704,15 +715,13 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op, right = UseRegisterAtStart(right_value); } + // Shift operations can only deoptimize if we do a logical shift + // by 0 and the result cannot be truncated to int32. bool does_deopt = false; - - if (FLAG_opt_safe_uint32_operations) { - does_deopt = !instr->CheckFlag(HInstruction::kUint32); - } else { - // Shift operations can only deoptimize if we do a logical shift - // by 0 and the result cannot be truncated to int32. - bool may_deopt = (op == Token::SHR && constant_value == 0); - if (may_deopt) { + if (op == Token::SHR && constant_value == 0) { + if (FLAG_opt_safe_uint32_operations) { + does_deopt = !instr->CheckFlag(HInstruction::kUint32); + } else { for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) { if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) { does_deopt = true; @@ -862,6 +871,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment( argument_count_, value_count, outer, + hydrogen_env->entry(), zone()); int argument_index = *argument_index_accumulator; for (int i = 0; i < value_count; ++i) { @@ -1035,6 +1045,15 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { LOperand* input = UseFixedDouble(instr->value(), f4); LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL); return MarkAsCall(DefineFixedDouble(result, f4), instr); + } else if (op == kMathExp) { + ASSERT(instr->representation().IsDouble()); + ASSERT(instr->value()->representation().IsDouble()); + LOperand* input = UseTempRegister(instr->value()); + LOperand* temp1 = TempRegister(); + LOperand* temp2 = TempRegister(); + LOperand* double_temp = FixedTemp(f6); // Chosen by fair dice roll. + LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2); + return DefineAsRegister(result); } else if (op == kMathPowHalf) { // Input cannot be the same as the result. // See lithium-codegen-mips.cc::DoMathPowHalf. @@ -1044,7 +1063,9 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { return DefineFixedDouble(result, f4); } else { LOperand* input = UseRegisterAtStart(instr->value()); - LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL; + + LOperand* temp = (op == kMathRound) ? FixedTemp(f6) : + (op == kMathFloor) ? TempRegister() : NULL; LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp); switch (op) { case kMathAbs: @@ -1111,6 +1132,11 @@ LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) { } +LInstruction* LChunkBuilder::DoRor(HRor* instr) { + return DoShift(Token::ROR, instr); +} + + LInstruction* LChunkBuilder::DoShr(HShr* instr) { return DoShift(Token::SHR, instr); } @@ -1351,7 +1377,7 @@ LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) { LInstruction* LChunkBuilder::DoCompareIDAndBranch( HCompareIDAndBranch* instr) { - Representation r = instr->GetInputRepresentation(); + Representation r = instr->representation(); if (r.IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); @@ -1556,8 +1582,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { LOperand* temp1 = TempRegister(); LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() : NULL; - LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(f22) - : NULL; + LOperand* temp3 = FixedTemp(f22); res = DefineSameAsFirst(new(zone()) LTaggedToI(value, temp1, temp2, @@ -1629,10 +1654,10 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { - LOperand* temp1 = TempRegister(); + LUnallocated* temp1 = TempRegister(); LOperand* temp2 = TempRegister(); - LInstruction* result = new(zone()) LCheckPrototypeMaps(temp1, temp2); - return AssignEnvironment(result); + LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2); + return AssignEnvironment(Define(result, temp1)); } @@ -1801,54 +1826,40 @@ LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( } -LInstruction* LChunkBuilder::DoLoadKeyedFastElement( - HLoadKeyedFastElement* instr) { - ASSERT(instr->representation().IsTagged()); +LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { ASSERT(instr->key()->representation().IsInteger32() || instr->key()->representation().IsTagged()); - LOperand* obj = UseRegisterAtStart(instr->object()); - LOperand* key = UseRegisterOrConstantAtStart(instr->key()); - LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key); - if (instr->RequiresHoleCheck()) AssignEnvironment(result); - return DefineAsRegister(result); -} - - -LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement( - HLoadKeyedFastDoubleElement* instr) { - ASSERT(instr->representation().IsDouble()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - LOperand* elements = UseTempRegister(instr->elements()); + ElementsKind elements_kind = instr->elements_kind(); LOperand* key = UseRegisterOrConstantAtStart(instr->key()); - LLoadKeyedFastDoubleElement* result = - new(zone()) LLoadKeyedFastDoubleElement(elements, key); - return AssignEnvironment(DefineAsRegister(result)); -} + LLoadKeyed* result = NULL; + if (!instr->is_external()) { + LOperand* obj = NULL; + if (instr->representation().IsDouble()) { + obj = UseTempRegister(instr->elements()); + } else { + ASSERT(instr->representation().IsTagged()); + obj = UseRegisterAtStart(instr->elements()); + } + result = new(zone()) LLoadKeyed(obj, key); + } else { + ASSERT( + (instr->representation().IsInteger32() && + (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && + (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || + (instr->representation().IsDouble() && + ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || + (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); + LOperand* external_pointer = UseRegister(instr->elements()); + result = new(zone()) LLoadKeyed(external_pointer, key); + } -LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( - HLoadKeyedSpecializedArrayElement* instr) { - ElementsKind elements_kind = instr->elements_kind(); - Representation representation(instr->representation()); - ASSERT( - (representation.IsInteger32() && - (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && - (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || - (representation.IsDouble() && - ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || - (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - LOperand* external_pointer = UseRegister(instr->external_pointer()); - LOperand* key = UseRegisterOrConstant(instr->key()); - LLoadKeyedSpecializedArrayElement* result = - new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key); - LInstruction* load_instr = DefineAsRegister(result); + DefineAsRegister(result); // An unsigned int array load might overflow and cause a deopt, make sure it // has an environment. - return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ? - AssignEnvironment(load_instr) : load_instr; + bool can_deoptimize = instr->RequiresHoleCheck() || + (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS); + return can_deoptimize ? AssignEnvironment(result) : result; } @@ -1862,67 +1873,49 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { } -LInstruction* LChunkBuilder::DoStoreKeyedFastElement( - HStoreKeyedFastElement* instr) { - bool needs_write_barrier = instr->NeedsWriteBarrier(); - ASSERT(instr->value()->representation().IsTagged()); - ASSERT(instr->object()->representation().IsTagged()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* obj = UseTempRegister(instr->object()); - LOperand* val = needs_write_barrier - ? UseTempRegister(instr->value()) - : UseRegisterAtStart(instr->value()); - LOperand* key = needs_write_barrier - ? UseTempRegister(instr->key()) - : UseRegisterOrConstantAtStart(instr->key()); - return new(zone()) LStoreKeyedFastElement(obj, key, val); -} - - -LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement( - HStoreKeyedFastDoubleElement* instr) { - ASSERT(instr->value()->representation().IsDouble()); - ASSERT(instr->elements()->representation().IsTagged()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* elements = UseRegisterAtStart(instr->elements()); - LOperand* val = UseTempRegister(instr->value()); - LOperand* key = UseRegisterOrConstantAtStart(instr->key()); +LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { + ElementsKind elements_kind = instr->elements_kind(); - return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val); -} + if (!instr->is_external()) { + ASSERT(instr->elements()->representation().IsTagged()); + bool needs_write_barrier = instr->NeedsWriteBarrier(); + LOperand* object = NULL; + LOperand* val = NULL; + LOperand* key = NULL; + + if (instr->value()->representation().IsDouble()) { + object = UseRegisterAtStart(instr->elements()); + key = UseRegisterOrConstantAtStart(instr->key()); + val = UseTempRegister(instr->value()); + } else { + ASSERT(instr->value()->representation().IsTagged()); + object = UseTempRegister(instr->elements()); + val = needs_write_barrier ? UseTempRegister(instr->value()) + : UseRegisterAtStart(instr->value()); + key = needs_write_barrier ? UseTempRegister(instr->key()) + : UseRegisterOrConstantAtStart(instr->key()); + } + return new(zone()) LStoreKeyed(object, key, val); + } -LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( - HStoreKeyedSpecializedArrayElement* instr) { - Representation representation(instr->value()->representation()); - ElementsKind elements_kind = instr->elements_kind(); ASSERT( - (representation.IsInteger32() && + (instr->value()->representation().IsInteger32() && (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || - (representation.IsDouble() && + (instr->value()->representation().IsDouble() && ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || - (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); - ASSERT(instr->external_pointer()->representation().IsExternal()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* external_pointer = UseRegister(instr->external_pointer()); + (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); + ASSERT(instr->elements()->representation().IsExternal()); bool val_is_temp_register = elements_kind == EXTERNAL_PIXEL_ELEMENTS || elements_kind == EXTERNAL_FLOAT_ELEMENTS; - LOperand* val = val_is_temp_register - ? UseTempRegister(instr->value()) + LOperand* val = val_is_temp_register ? UseTempRegister(instr->value()) : UseRegister(instr->value()); - LOperand* key = UseRegisterOrConstant(instr->key()); + LOperand* key = UseRegisterOrConstantAtStart(instr->key()); + LOperand* external_pointer = UseRegister(instr->elements()); - return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer, - key, - val); + return new(zone()) LStoreKeyed(external_pointer, key, val); } @@ -2068,6 +2061,7 @@ LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) { LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) { + ASSERT(argument_count_ == 0); allocator_->MarkAsOsrEntry(); current_block_->last_environment()->set_ast_id(instr->ast_id()); return AssignEnvironment(new(zone()) LOsrEntry); @@ -2106,12 +2100,10 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { - LOperand* arguments = UseRegister(instr->arguments()); + LOperand* args = UseRegister(instr->arguments()); LOperand* length = UseTempRegister(instr->length()); LOperand* index = UseRegister(instr->index()); - LAccessArgumentsAt* result = - new(zone()) LAccessArgumentsAt(arguments, length, index); - return AssignEnvironment(DefineAsRegister(result)); + return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index)); } @@ -2146,7 +2138,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { env->set_ast_id(instr->ast_id()); env->Drop(instr->pop_count()); - for (int i = 0; i < instr->values()->length(); ++i) { + for (int i = instr->values()->length() - 1; i >= 0; --i) { HValue* value = instr->values()->at(i); if (instr->HasAssignedIndexAt(i)) { env->Bind(instr->GetAssignedIndexAt(i), value); @@ -2195,6 +2187,7 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { if (instr->arguments_var() != NULL) { inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject()); } + inner->set_entry(instr); current_block_->UpdateEnvironment(inner); chunk_->AddInlinedClosure(instr->closure()); return NULL; @@ -2206,7 +2199,7 @@ LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { HEnvironment* env = current_block_->last_environment(); - if (instr->arguments_pushed()) { + if (env->entry()->arguments_pushed()) { int argument_count = env->arguments_environment()->parameter_count(); pop = new(zone()) LDrop(argument_count); argument_count_ -= argument_count; @@ -2237,9 +2230,7 @@ LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) { LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) { LOperand* map = UseRegister(instr->map()); - LOperand* scratch = TempRegister(); - return AssignEnvironment(DefineAsRegister( - new(zone()) LForInCacheArray(map, scratch))); + return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map))); } diff --git a/deps/v8/src/mips/lithium-mips.h b/deps/v8/src/mips/lithium-mips.h index 367cf2a90c..17ef24cb1a 100644 --- a/deps/v8/src/mips/lithium-mips.h +++ b/deps/v8/src/mips/lithium-mips.h @@ -125,14 +125,13 @@ class LCodeGen; V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ - V(LoadKeyedFastDoubleElement) \ - V(LoadKeyedFastElement) \ + V(LoadKeyed) \ V(LoadKeyedGeneric) \ - V(LoadKeyedSpecializedArrayElement) \ V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ V(MapEnumLength) \ + V(MathExp) \ V(MathMinMax) \ V(ModI) \ V(MulI) \ @@ -156,10 +155,8 @@ class LCodeGen; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ - V(StoreKeyedFastDoubleElement) \ - V(StoreKeyedFastElement) \ + V(StoreKeyed) \ V(StoreKeyedGeneric) \ - V(StoreKeyedSpecializedArrayElement) \ V(StoreNamedField) \ V(StoreNamedGeneric) \ V(StringAdd) \ @@ -259,9 +256,6 @@ class LInstruction: public ZoneObject { virtual bool HasResult() const = 0; virtual LOperand* result() = 0; - virtual int TempCount() = 0; - virtual LOperand* TempAt(int i) = 0; - LOperand* FirstInput() { return InputAt(0); } LOperand* Output() { return HasResult() ? result() : NULL; } @@ -275,6 +269,10 @@ class LInstruction: public ZoneObject { virtual int InputCount() = 0; virtual LOperand* InputAt(int i) = 0; + friend class TempIterator; + virtual int TempCount() = 0; + virtual LOperand* TempAt(int i) = 0; + LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; @@ -295,11 +293,6 @@ class LTemplateInstruction: public LInstruction { void set_result(LOperand* operand) { results_[0] = operand; } LOperand* result() { return results_[0]; } - LOperand* InputAt(int i) { return inputs_[i]; } - - int TempCount() { return T; } - LOperand* TempAt(int i) { return temps_[i]; } - protected: EmbeddedContainer<LOperand*, R> results_; EmbeddedContainer<LOperand*, I> inputs_; @@ -307,6 +300,10 @@ class LTemplateInstruction: public LInstruction { private: virtual int InputCount() { return I; } + virtual LOperand* InputAt(int i) { return inputs_[i]; } + + virtual int TempCount() { return T; } + virtual LOperand* TempAt(int i) { return temps_[i]; } }; @@ -524,6 +521,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = elements; } + LOperand* elements() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length") }; @@ -550,16 +549,22 @@ class LModI: public LTemplateInstruction<1, 2, 3> { // Used for the standard case. LModI(LOperand* left, LOperand* right, - LOperand* temp1, + LOperand* temp, LOperand* temp2, LOperand* temp3) { inputs_[0] = left; inputs_[1] = right; - temps_[0] = temp1; + temps_[0] = temp; temps_[1] = temp2; temps_[2] = temp3; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + LOperand* temp3() { return temps_[2]; } + DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i") DECLARE_HYDROGEN_ACCESSOR(Mod) }; @@ -572,6 +577,9 @@ class LDivI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i") DECLARE_HYDROGEN_ACCESSOR(Div) }; @@ -585,6 +593,10 @@ class LMulI: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i") DECLARE_HYDROGEN_ACCESSOR(Mul) }; @@ -597,12 +609,15 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch) Token::Value op() const { return hydrogen()->token(); } bool is_double() const { - return hydrogen()->GetInputRepresentation().IsDouble(); + return hydrogen()->representation().IsDouble(); } virtual void PrintDataTo(StringStream* stream); @@ -616,6 +631,9 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation") DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation) @@ -624,6 +642,30 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> { }; +class LMathExp: public LTemplateInstruction<1, 1, 3> { + public: + LMathExp(LOperand* value, + LOperand* double_temp, + LOperand* temp1, + LOperand* temp2) { + inputs_[0] = value; + temps_[0] = temp1; + temps_[1] = temp2; + temps_[2] = double_temp; + ExternalReference::InitializeMathExpData(); + } + + LOperand* value() { return inputs_[0]; } + LOperand* temp1() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + LOperand* double_temp() { return temps_[2]; } + + DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp") + + virtual void PrintDataTo(StringStream* stream); +}; + + class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { public: LCmpObjectEqAndBranch(LOperand* left, LOperand* right) { @@ -631,6 +673,9 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareObjectEqAndBranch) @@ -643,6 +688,8 @@ class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> { inputs_[0] = left; } + LOperand* left() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch, "cmp-constant-eq-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareConstantEqAndBranch) @@ -655,6 +702,8 @@ class LIsNilAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch) @@ -672,6 +721,9 @@ class LIsObjectAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch) @@ -686,6 +738,9 @@ class LIsStringAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch) @@ -699,6 +754,8 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch) @@ -713,6 +770,9 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, "is-undetectable-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch) @@ -728,6 +788,9 @@ class LStringCompareAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch, "string-compare-and-branch") DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch) @@ -744,6 +807,8 @@ class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch, "has-instance-type-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch) @@ -758,6 +823,8 @@ class LGetCachedArrayIndex: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex, "get-cached-array-index") DECLARE_HYDROGEN_ACCESSOR(GetCachedArrayIndex) }; @@ -769,6 +836,8 @@ class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch, "has-cached-array-index-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch) @@ -784,6 +853,9 @@ class LClassOfTestAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch") DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) @@ -799,6 +871,9 @@ class LCmpT: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t") DECLARE_HYDROGEN_ACCESSOR(CompareGeneric) @@ -813,6 +888,9 @@ class LInstanceOf: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of") }; @@ -824,6 +902,9 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal, "instance-of-known-global") DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) @@ -863,6 +944,9 @@ class LBitI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + Token::Value op() const { return hydrogen()->op(); } DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i") @@ -879,7 +963,8 @@ class LShiftI: public LTemplateInstruction<1, 2, 0> { } Token::Value op() const { return op_; } - + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } bool can_deopt() const { return can_deopt_; } DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i") @@ -897,6 +982,9 @@ class LSubI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i") DECLARE_HYDROGEN_ACCESSOR(Sub) }; @@ -935,6 +1023,8 @@ class LBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_HYDROGEN_ACCESSOR(Branch) @@ -949,6 +1039,9 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareMap) @@ -970,6 +1063,8 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) }; @@ -981,6 +1076,8 @@ class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength, "fixed-array-base-length") DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength) @@ -993,6 +1090,8 @@ class LMapEnumLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MapEnumLength, "map-enum-length") }; @@ -1003,6 +1102,8 @@ class LElementsKind: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind") DECLARE_HYDROGEN_ACCESSOR(ElementsKind) }; @@ -1015,6 +1116,9 @@ class LValueOf: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value-of") DECLARE_HYDROGEN_ACCESSOR(ValueOf) }; @@ -1027,9 +1131,12 @@ class LDateField: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* date() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + Smi* index() const { return index_; } + DECLARE_CONCRETE_INSTRUCTION(ValueOf, "date-field") DECLARE_HYDROGEN_ACCESSOR(ValueOf) - Smi* index() const { return index_; } private: Smi* index_; @@ -1042,6 +1149,8 @@ class LThrow: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Throw, "throw") }; @@ -1052,6 +1161,8 @@ class LBitNotI: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") }; @@ -1063,6 +1174,9 @@ class LAddI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i") DECLARE_HYDROGEN_ACCESSOR(Add) }; @@ -1075,6 +1189,9 @@ class LMathMinMax: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max") DECLARE_HYDROGEN_ACCESSOR(MathMinMax) }; @@ -1087,6 +1204,9 @@ class LPower: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(Power, "power") DECLARE_HYDROGEN_ACCESSOR(Power) }; @@ -1098,6 +1218,8 @@ class LRandom: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } + LOperand* global_object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Random, "random") DECLARE_HYDROGEN_ACCESSOR(Random) }; @@ -1112,6 +1234,8 @@ class LArithmeticD: public LTemplateInstruction<1, 2, 0> { } Token::Value op() const { return op_; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } virtual Opcode opcode() const { return LInstruction::kArithmeticD; } virtual void CompileToNative(LCodeGen* generator); @@ -1130,12 +1254,14 @@ class LArithmeticT: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + Token::Value op() const { return op_; } + virtual Opcode opcode() const { return LInstruction::kArithmeticT; } virtual void CompileToNative(LCodeGen* generator); virtual const char* Mnemonic() const; - Token::Value op() const { return op_; } - private: Token::Value op_; }; @@ -1147,6 +1273,8 @@ class LReturn: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Return, "return") }; @@ -1157,6 +1285,8 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field") DECLARE_HYDROGEN_ACCESSOR(LoadNamedField) }; @@ -1168,10 +1298,10 @@ class LLoadNamedFieldPolymorphic: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field-polymorphic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedFieldPolymorphic) - - LOperand* object() { return inputs_[0]; } }; @@ -1181,10 +1311,11 @@ class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric) - LOperand* object() { return inputs_[0]; } Handle<Object> name() const { return hydrogen()->name(); } }; @@ -1195,10 +1326,10 @@ class LLoadFunctionPrototype: public LTemplateInstruction<1, 1, 0> { inputs_[0] = function; } + LOperand* function() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype") DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype) - - LOperand* function() { return inputs_[0]; } }; @@ -1208,6 +1339,8 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements") }; @@ -1218,76 +1351,48 @@ class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer, "load-external-array-pointer") }; -class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { +class LLoadKeyed: public LTemplateInstruction<1, 2, 0> { public: - LLoadKeyedFastElement(LOperand* elements, LOperand* key) { + LLoadKeyed(LOperand* elements, LOperand* key) { inputs_[0] = elements; inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement) - LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - -class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> { - public: - LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) { - inputs_[0] = elements; - inputs_[1] = key; + ElementsKind elements_kind() const { + return hydrogen()->elements_kind(); } - - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement, - "load-keyed-fast-double-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement) - - LOperand* elements() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - -class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> { - public: - LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, - LOperand* key) { - inputs_[0] = external_pointer; - inputs_[1] = key; + bool is_external() const { + return hydrogen()->is_external(); } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement, - "load-keyed-specialized-array-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement) + DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") + DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) - LOperand* external_pointer() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - ElementsKind elements_kind() const { - return hydrogen()->elements_kind(); - } + virtual void PrintDataTo(StringStream* stream); uint32_t additional_index() const { return hydrogen()->index_offset(); } }; class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> { public: - LLoadKeyedGeneric(LOperand* obj, LOperand* key) { - inputs_[0] = obj; + LLoadKeyedGeneric(LOperand* object, LOperand* key) { + inputs_[0] = object; inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") - LOperand* object() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") }; @@ -1304,10 +1409,11 @@ class LLoadGlobalGeneric: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } + LOperand* global_object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic") DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric) - LOperand* global_object() { return inputs_[0]; } Handle<Object> name() const { return hydrogen()->name(); } bool for_typeof() const { return hydrogen()->for_typeof(); } }; @@ -1320,10 +1426,11 @@ class LStoreGlobalCell: public LTemplateInstruction<0, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell, "store-global-cell") DECLARE_HYDROGEN_ACCESSOR(StoreGlobalCell) - - LOperand* value() { return inputs_[0]; } }; @@ -1335,12 +1442,13 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> { inputs_[1] = value; } + LOperand* global_object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic") DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric) - LOperand* global_object() { return InputAt(0); } Handle<Object> name() const { return hydrogen()->name(); } - LOperand* value() { return InputAt(1); } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; @@ -1351,10 +1459,11 @@ class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } + LOperand* context() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot") DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot) - LOperand* context() { return InputAt(0); } int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); @@ -1368,11 +1477,12 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 0> { inputs_[1] = value; } + LOperand* context() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot") DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot) - LOperand* context() { return InputAt(0); } - LOperand* value() { return InputAt(1); } int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); @@ -1385,6 +1495,8 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument") }; @@ -1421,9 +1533,9 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } - DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context") + LOperand* context() { return inputs_[0]; } - LOperand* context() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context") }; @@ -1440,9 +1552,9 @@ class LGlobalObject: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } - DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") + LOperand* context() { return inputs_[0]; } - LOperand* context() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") }; @@ -1452,9 +1564,9 @@ class LGlobalReceiver: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } - DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver") + LOperand* global_object() { return inputs_[0]; } - LOperand* global() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver") }; @@ -1476,11 +1588,11 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> { inputs_[0] = function; } + LOperand* function() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function") DECLARE_HYDROGEN_ACCESSOR(InvokeFunction) - LOperand* function() { return inputs_[0]; } - virtual void PrintDataTo(StringStream* stream); int arity() const { return hydrogen()->argument_count() - 1; } @@ -1494,6 +1606,8 @@ class LCallKeyed: public LTemplateInstruction<1, 1, 0> { inputs_[0] = key; } + LOperand* key() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed") DECLARE_HYDROGEN_ACCESSOR(CallKeyed) @@ -1522,10 +1636,11 @@ class LCallFunction: public LTemplateInstruction<1, 1, 0> { inputs_[0] = function; } + LOperand* function() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function") DECLARE_HYDROGEN_ACCESSOR(CallFunction) - LOperand* function() { return inputs_[0]; } int arity() const { return hydrogen()->argument_count() - 1; } }; @@ -1560,6 +1675,8 @@ class LCallNew: public LTemplateInstruction<1, 1, 0> { inputs_[0] = constructor; } + LOperand* constructor() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new") DECLARE_HYDROGEN_ACCESSOR(CallNew) @@ -1585,6 +1702,8 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double") }; @@ -1595,6 +1714,8 @@ class LUint32ToDouble: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double") }; @@ -1605,6 +1726,8 @@ class LNumberTagI: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i") }; @@ -1615,18 +1738,24 @@ class LNumberTagU: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u") }; class LNumberTagD: public LTemplateInstruction<1, 1, 2> { public: - LNumberTagD(LOperand* value, LOperand* temp1, LOperand* temp2) { + LNumberTagD(LOperand* value, LOperand* temp, LOperand* temp2) { inputs_[0] = value; - temps_[0] = temp1; + temps_[0] = temp; temps_[1] = temp2; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d") }; @@ -1634,12 +1763,16 @@ class LNumberTagD: public LTemplateInstruction<1, 1, 2> { // Sometimes truncating conversion from a tagged value to an int32. class LDoubleToI: public LTemplateInstruction<1, 1, 2> { public: - LDoubleToI(LOperand* value, LOperand* temp1, LOperand* temp2) { + LDoubleToI(LOperand* value, LOperand* temp, LOperand* temp2) { inputs_[0] = value; - temps_[0] = temp1; + temps_[0] = temp; temps_[1] = temp2; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -1651,15 +1784,20 @@ class LDoubleToI: public LTemplateInstruction<1, 1, 2> { class LTaggedToI: public LTemplateInstruction<1, 1, 3> { public: LTaggedToI(LOperand* value, - LOperand* temp1, + LOperand* temp, LOperand* temp2, LOperand* temp3) { inputs_[0] = value; - temps_[0] = temp1; + temps_[0] = temp; temps_[1] = temp2; temps_[2] = temp3; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + LOperand* temp3() { return temps_[2]; } + DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -1673,6 +1811,8 @@ class LSmiTag: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag") }; @@ -1683,6 +1823,8 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag") DECLARE_HYDROGEN_ACCESSOR(Change) }; @@ -1695,10 +1837,11 @@ class LSmiUntag: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } - DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag") - + LOperand* value() { return inputs_[0]; } bool needs_check() const { return needs_check_; } + DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag") + private: bool needs_check_; }; @@ -1706,20 +1849,21 @@ class LSmiUntag: public LTemplateInstruction<1, 1, 0> { class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { public: - LStoreNamedField(LOperand* obj, LOperand* val, LOperand* temp) { - inputs_[0] = obj; - inputs_[1] = val; + LStoreNamedField(LOperand* object, LOperand* value, LOperand* temp) { + inputs_[0] = object; + inputs_[1] = value; temps_[0] = temp; } + LOperand* object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field") DECLARE_HYDROGEN_ACCESSOR(StoreNamedField) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* value() { return inputs_[1]; } - Handle<Object> name() const { return hydrogen()->name(); } bool is_in_object() { return hydrogen()->is_in_object(); } int offset() { return hydrogen()->offset(); } @@ -1729,109 +1873,67 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> { public: - LStoreNamedGeneric(LOperand* obj, LOperand* val) { - inputs_[0] = obj; - inputs_[1] = val; + LStoreNamedGeneric(LOperand* object, LOperand* value) { + inputs_[0] = object; + inputs_[1] = value; } + LOperand* object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic") DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* value() { return inputs_[1]; } Handle<Object> name() const { return hydrogen()->name(); } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; -class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> { +class LStoreKeyed: public LTemplateInstruction<0, 3, 0> { public: - LStoreKeyedFastElement(LOperand* obj, LOperand* key, LOperand* val) { - inputs_[0] = obj; + LStoreKeyed(LOperand* object, LOperand* key, LOperand* value) { + inputs_[0] = object; inputs_[1] = key; - inputs_[2] = val; + inputs_[2] = value; } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement, - "store-keyed-fast-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement) - - virtual void PrintDataTo(StringStream* stream); - - LOperand* object() { return inputs_[0]; } + bool is_external() const { return hydrogen()->is_external(); } + LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - -class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> { - public: - LStoreKeyedFastDoubleElement(LOperand* elements, - LOperand* key, - LOperand* val) { - inputs_[0] = elements; - inputs_[1] = key; - inputs_[2] = val; + ElementsKind elements_kind() const { + return hydrogen()->elements_kind(); } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement, - "store-keyed-fast-double-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement) + DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed") + DECLARE_HYDROGEN_ACCESSOR(StoreKeyed) virtual void PrintDataTo(StringStream* stream); - - LOperand* elements() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } - bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } + uint32_t additional_index() const { return hydrogen()->index_offset(); } }; class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { public: - LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val) { + LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* value) { inputs_[0] = obj; inputs_[1] = key; - inputs_[2] = val; + inputs_[2] = value; } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric) - - virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } - StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } -}; -class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> { - public: - LStoreKeyedSpecializedArrayElement(LOperand* external_pointer, - LOperand* key, - LOperand* val) { - inputs_[0] = external_pointer; - inputs_[1] = key; - inputs_[2] = val; - } + DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic") + DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric) - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement, - "store-keyed-specialized-array-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement) + virtual void PrintDataTo(StringStream* stream); - LOperand* external_pointer() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } - ElementsKind elements_kind() const { - return hydrogen()->elements_kind(); - } - uint32_t additional_index() const { return hydrogen()->index_offset(); } + StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; @@ -1839,21 +1941,22 @@ class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> { public: LTransitionElementsKind(LOperand* object, LOperand* new_map_temp, - LOperand* temp_reg) { + LOperand* temp) { inputs_[0] = object; temps_[0] = new_map_temp; - temps_[1] = temp_reg; + temps_[1] = temp; } + LOperand* object() { return inputs_[0]; } + LOperand* new_map_temp() { return temps_[0]; } + LOperand* temp() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind, "transition-elements-kind") DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* new_map_reg() { return temps_[0]; } - LOperand* temp_reg() { return temps_[1]; } Handle<Map> original_map() { return hydrogen()->original_map(); } Handle<Map> transitioned_map() { return hydrogen()->transitioned_map(); } }; @@ -1866,11 +1969,11 @@ class LStringAdd: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } - DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add") - DECLARE_HYDROGEN_ACCESSOR(StringAdd) - LOperand* left() { return inputs_[0]; } LOperand* right() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add") + DECLARE_HYDROGEN_ACCESSOR(StringAdd) }; @@ -1882,11 +1985,11 @@ class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> { inputs_[1] = index; } - DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at") - DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt) - LOperand* string() { return inputs_[0]; } LOperand* index() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at") + DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt) }; @@ -1896,10 +1999,10 @@ class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> { inputs_[0] = char_code; } + LOperand* char_code() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code") DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode) - - LOperand* char_code() { return inputs_[0]; } }; @@ -1909,10 +2012,10 @@ class LStringLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = string; } + LOperand* string() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length") DECLARE_HYDROGEN_ACCESSOR(StringLength) - - LOperand* string() { return inputs_[0]; } }; @@ -1922,7 +2025,7 @@ class LCheckFunction: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } - LOperand* value() { return InputAt(0); } + LOperand* value() { return inputs_[0]; } DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") DECLARE_HYDROGEN_ACCESSOR(CheckFunction) @@ -1935,6 +2038,8 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type") DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType) }; @@ -1946,18 +2051,23 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps") DECLARE_HYDROGEN_ACCESSOR(CheckMaps) }; -class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> { +class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 2> { public: - LCheckPrototypeMaps(LOperand* temp1, LOperand* temp2) { - temps_[0] = temp1; + LCheckPrototypeMaps(LOperand* temp, LOperand* temp2) { + temps_[0] = temp; temps_[1] = temp2; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) @@ -1972,6 +2082,8 @@ class LCheckSmi: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi") }; @@ -1982,18 +2094,21 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi") }; class LClampDToUint8: public LTemplateInstruction<1, 1, 1> { public: - LClampDToUint8(LOperand* value, LOperand* temp) { - inputs_[0] = value; + LClampDToUint8(LOperand* unclamped, LOperand* temp) { + inputs_[0] = unclamped; temps_[0] = temp; } LOperand* unclamped() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(ClampDToUint8, "clamp-d-to-uint8") }; @@ -2001,8 +2116,8 @@ class LClampDToUint8: public LTemplateInstruction<1, 1, 1> { class LClampIToUint8: public LTemplateInstruction<1, 1, 0> { public: - explicit LClampIToUint8(LOperand* value) { - inputs_[0] = value; + explicit LClampIToUint8(LOperand* unclamped) { + inputs_[0] = unclamped; } LOperand* unclamped() { return inputs_[0]; } @@ -2013,12 +2128,13 @@ class LClampIToUint8: public LTemplateInstruction<1, 1, 0> { class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { public: - LClampTToUint8(LOperand* value, LOperand* temp) { - inputs_[0] = value; + LClampTToUint8(LOperand* unclamped, LOperand* temp) { + inputs_[0] = unclamped; temps_[0] = temp; } LOperand* unclamped() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8, "clamp-t-to-uint8") }; @@ -2026,11 +2142,14 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { class LAllocateObject: public LTemplateInstruction<1, 0, 2> { public: - LAllocateObject(LOperand* temp1, LOperand* temp2) { - temps_[0] = temp1; + LAllocateObject(LOperand* temp, LOperand* temp2) { + temps_[0] = temp; temps_[1] = temp2; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object") DECLARE_HYDROGEN_ACCESSOR(AllocateObject) }; @@ -2079,6 +2198,8 @@ class LToFastProperties: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties") DECLARE_HYDROGEN_ACCESSOR(ToFastProperties) }; @@ -2090,6 +2211,8 @@ class LTypeof: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof") }; @@ -2100,6 +2223,8 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch") DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch) @@ -2115,6 +2240,8 @@ class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { temps_[0] = temp; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch, "is-construct-call-and-branch") }; @@ -2122,15 +2249,15 @@ class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { class LDeleteProperty: public LTemplateInstruction<1, 2, 0> { public: - LDeleteProperty(LOperand* obj, LOperand* key) { - inputs_[0] = obj; + LDeleteProperty(LOperand* object, LOperand* key) { + inputs_[0] = object; inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") - LOperand* object() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") }; @@ -2195,15 +2322,13 @@ class LForInPrepareMap: public LTemplateInstruction<1, 1, 0> { }; -class LForInCacheArray: public LTemplateInstruction<1, 1, 1> { +class LForInCacheArray: public LTemplateInstruction<1, 1, 0> { public: - explicit LForInCacheArray(LOperand* map, LOperand* scratch) { + explicit LForInCacheArray(LOperand* map) { inputs_[0] = map; - temps_[0] = scratch; } LOperand* map() { return inputs_[0]; } - LOperand* scratch() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray, "for-in-cache-array") diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc index 7ded494999..9249917c3f 100644 --- a/deps/v8/src/mips/macro-assembler-mips.cc +++ b/deps/v8/src/mips/macro-assembler-mips.cc @@ -1395,49 +1395,68 @@ void MacroAssembler::ConvertToInt32(Register source, void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode, - FPURegister result, + Register result, DoubleRegister double_input, - Register scratch1, + Register scratch, + DoubleRegister double_scratch, Register except_flag, CheckForInexactConversion check_inexact) { + ASSERT(!result.is(scratch)); + ASSERT(!double_input.is(double_scratch)); + ASSERT(!except_flag.is(scratch)); + ASSERT(CpuFeatures::IsSupported(FPU)); CpuFeatures::Scope scope(FPU); + Label done; + + // Clear the except flag (0 = no exception) + mov(except_flag, zero_reg); + + // Test for values that can be exactly represented as a signed 32-bit integer. + cvt_w_d(double_scratch, double_input); + mfc1(result, double_scratch); + cvt_d_w(double_scratch, double_scratch); + BranchF(&done, NULL, eq, double_input, double_scratch); int32_t except_mask = kFCSRFlagMask; // Assume interested in all exceptions. if (check_inexact == kDontCheckForInexactConversion) { - // Ingore inexact exceptions. + // Ignore inexact exceptions. except_mask &= ~kFCSRInexactFlagMask; } // Save FCSR. - cfc1(scratch1, FCSR); + cfc1(scratch, FCSR); // Disable FPU exceptions. ctc1(zero_reg, FCSR); // Do operation based on rounding mode. switch (rounding_mode) { case kRoundToNearest: - Round_w_d(result, double_input); + Round_w_d(double_scratch, double_input); break; case kRoundToZero: - Trunc_w_d(result, double_input); + Trunc_w_d(double_scratch, double_input); break; case kRoundToPlusInf: - Ceil_w_d(result, double_input); + Ceil_w_d(double_scratch, double_input); break; case kRoundToMinusInf: - Floor_w_d(result, double_input); + Floor_w_d(double_scratch, double_input); break; } // End of switch-statement. // Retrieve FCSR. cfc1(except_flag, FCSR); // Restore FCSR. - ctc1(scratch1, FCSR); + ctc1(scratch, FCSR); + // Move the converted value into the result register. + mfc1(result, double_scratch); // Check for fpu exceptions. And(except_flag, except_flag, Operand(except_mask)); + + bind(&done); } @@ -3109,9 +3128,9 @@ void MacroAssembler::AllocateAsciiString(Register result, Label* gc_required) { // Calculate the number of bytes needed for the characters in the string // while observing object alignment. - ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); + ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); ASSERT(kCharSize == 1); - addiu(scratch1, length, kObjectAlignmentMask + SeqAsciiString::kHeaderSize); + addiu(scratch1, length, kObjectAlignmentMask + SeqOneByteString::kHeaderSize); And(scratch1, scratch1, Operand(~kObjectAlignmentMask)); // Allocate ASCII string in new space. @@ -3215,7 +3234,8 @@ void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1, Register scratch2, Register heap_number_map, - Label* need_gc) { + Label* need_gc, + TaggingMode tagging_mode) { // Allocate an object in the heap for the heap number and tag it as a heap // object. AllocateInNewSpace(HeapNumber::kSize, @@ -3223,11 +3243,16 @@ void MacroAssembler::AllocateHeapNumber(Register result, scratch1, scratch2, need_gc, - TAG_OBJECT); + tagging_mode == TAG_RESULT ? TAG_OBJECT : + NO_ALLOCATION_FLAGS); // Store heap number map in the allocated object. AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); - sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset)); + if (tagging_mode == TAG_RESULT) { + sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset)); + } else { + sw(heap_number_map, MemOperand(result, HeapObject::kMapOffset)); + } } @@ -3380,13 +3405,13 @@ void MacroAssembler::CheckFastSmiElements(Register map, void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, Register key_reg, - Register receiver_reg, Register elements_reg, Register scratch1, Register scratch2, Register scratch3, Register scratch4, - Label* fail) { + Label* fail, + int elements_offset) { Label smi_value, maybe_nan, have_double_value, is_nan, done; Register mantissa_reg = scratch2; Register exponent_reg = scratch3; @@ -3412,8 +3437,10 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, bind(&have_double_value); sll(scratch1, key_reg, kDoubleSizeLog2 - kSmiTagSize); Addu(scratch1, scratch1, elements_reg); - sw(mantissa_reg, FieldMemOperand(scratch1, FixedDoubleArray::kHeaderSize)); - uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); + sw(mantissa_reg, FieldMemOperand( + scratch1, FixedDoubleArray::kHeaderSize - elements_offset)); + uint32_t offset = FixedDoubleArray::kHeaderSize - elements_offset + + sizeof(kHoleNanLower32); sw(exponent_reg, FieldMemOperand(scratch1, offset)); jmp(&done); @@ -3433,7 +3460,8 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, bind(&smi_value); Addu(scratch1, elements_reg, - Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); + Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag - + elements_offset)); sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize); Addu(scratch1, scratch1, scratch2); // scratch1 is now effective address of the double element @@ -3445,7 +3473,7 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, destination = FloatingPointHelper::kCoreRegisters; } - Register untagged_value = receiver_reg; + Register untagged_value = elements_reg; SmiUntag(untagged_value, value_reg); FloatingPointHelper::ConvertIntToDouble(this, untagged_value, @@ -3948,6 +3976,14 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, Addu(s2, s2, Operand(1)); sw(s2, MemOperand(s3, kLevelOffset)); + if (FLAG_log_timer_events) { + FrameScope frame(this, StackFrame::MANUAL); + PushSafepointRegisters(); + PrepareCallCFunction(0, a0); + CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0); + PopSafepointRegisters(); + } + // The O32 ABI requires us to pass a pointer in a0 where the returned struct // (4 bytes) will be placed. This is also built into the Simulator. // Set up the pointer to the returned value (a0). It was allocated in @@ -3960,6 +3996,14 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, DirectCEntryStub stub; stub.GenerateCall(this, function); + if (FLAG_log_timer_events) { + FrameScope frame(this, StackFrame::MANUAL); + PushSafepointRegisters(); + PrepareCallCFunction(0, a0); + CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0); + PopSafepointRegisters(); + } + // As mentioned above, on MIPS a pointer is returned - we need to dereference // it to get the actual return value (which is also a pointer). lw(v0, MemOperand(v0)); @@ -4798,38 +4842,46 @@ void MacroAssembler::JumpIfEitherSmi(Register reg1, } -void MacroAssembler::AbortIfSmi(Register object) { - STATIC_ASSERT(kSmiTag == 0); - andi(at, object, kSmiTagMask); - Assert(ne, "Operand is a smi", at, Operand(zero_reg)); +void MacroAssembler::AssertNotSmi(Register object) { + if (emit_debug_code()) { + STATIC_ASSERT(kSmiTag == 0); + andi(at, object, kSmiTagMask); + Check(ne, "Operand is a smi", at, Operand(zero_reg)); + } } -void MacroAssembler::AbortIfNotSmi(Register object) { - STATIC_ASSERT(kSmiTag == 0); - andi(at, object, kSmiTagMask); - Assert(eq, "Operand is a smi", at, Operand(zero_reg)); +void MacroAssembler::AssertSmi(Register object) { + if (emit_debug_code()) { + STATIC_ASSERT(kSmiTag == 0); + andi(at, object, kSmiTagMask); + Check(eq, "Operand is a smi", at, Operand(zero_reg)); + } } -void MacroAssembler::AbortIfNotString(Register object) { - STATIC_ASSERT(kSmiTag == 0); - And(t0, object, Operand(kSmiTagMask)); - Assert(ne, "Operand is not a string", t0, Operand(zero_reg)); - push(object); - lw(object, FieldMemOperand(object, HeapObject::kMapOffset)); - lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset)); - Assert(lo, "Operand is not a string", object, Operand(FIRST_NONSTRING_TYPE)); - pop(object); +void MacroAssembler::AssertString(Register object) { + if (emit_debug_code()) { + STATIC_ASSERT(kSmiTag == 0); + And(t0, object, Operand(kSmiTagMask)); + Check(ne, "Operand is a smi and not a string", t0, Operand(zero_reg)); + push(object); + lw(object, FieldMemOperand(object, HeapObject::kMapOffset)); + lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset)); + Check(lo, "Operand is not a string", object, Operand(FIRST_NONSTRING_TYPE)); + pop(object); + } } -void MacroAssembler::AbortIfNotRootValue(Register src, - Heap::RootListIndex root_value_index, - const char* message) { - ASSERT(!src.is(at)); - LoadRoot(at, root_value_index); - Assert(eq, message, src, Operand(at)); +void MacroAssembler::AssertRootValue(Register src, + Heap::RootListIndex root_value_index, + const char* message) { + if (emit_debug_code()) { + ASSERT(!src.is(at)); + LoadRoot(at, root_value_index); + Check(eq, message, src, Operand(at)); + } } @@ -4888,8 +4940,10 @@ void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii( Register scratch2, Label* failure) { int kFlatAsciiStringMask = - kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; + kIsNotStringMask | kStringEncodingMask | kAsciiDataHintMask | + kStringRepresentationMask; int kFlatAsciiStringTag = ASCII_STRING_TYPE; + ASSERT_EQ(ASCII_STRING_TYPE, ASCII_STRING_TYPE & kFlatAsciiStringMask); ASSERT(kFlatAsciiStringTag <= 0xffff); // Ensure this fits 16-bit immed. andi(scratch1, first, kFlatAsciiStringMask); Branch(failure, ne, scratch1, Operand(kFlatAsciiStringTag)); @@ -4902,8 +4956,10 @@ void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(Register type, Register scratch, Label* failure) { int kFlatAsciiStringMask = - kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; + kIsNotStringMask | kStringEncodingMask | kAsciiDataHintMask | + kStringRepresentationMask; int kFlatAsciiStringTag = ASCII_STRING_TYPE; + ASSERT_EQ(ASCII_STRING_TYPE, ASCII_STRING_TYPE & kFlatAsciiStringMask); And(scratch, type, Operand(kFlatAsciiStringMask)); Branch(failure, ne, scratch, Operand(kFlatAsciiStringTag)); } @@ -5264,7 +5320,7 @@ void MacroAssembler::EnsureNotWhite( // For ASCII (char-size of 1) we shift the smi tag away to get the length. // For UC16 (char-size of 2) we just leave the smi tag in place, thereby // getting the length multiplied by 2. - ASSERT(kAsciiStringTag == 4 && kStringEncodingMask == 4); + ASSERT(kOneByteStringTag == 4 && kStringEncodingMask == 4); ASSERT(kSmiTag == 0 && kSmiTagSize == 1); lw(t9, FieldMemOperand(value, String::kLengthOffset)); And(t8, instance_type, Operand(kStringEncodingMask)); @@ -5294,22 +5350,14 @@ void MacroAssembler::EnsureNotWhite( void MacroAssembler::LoadInstanceDescriptors(Register map, - Register descriptors, - Register scratch) { - Register temp = descriptors; - lw(temp, FieldMemOperand(map, Map::kTransitionsOrBackPointerOffset)); - - Label ok, fail; - CheckMap(temp, - scratch, - isolate()->factory()->fixed_array_map(), - &fail, - DONT_DO_SMI_CHECK); - lw(descriptors, FieldMemOperand(temp, TransitionArray::kDescriptorsOffset)); - jmp(&ok); - bind(&fail); - LoadRoot(descriptors, Heap::kEmptyDescriptorArrayRootIndex); - bind(&ok); + Register descriptors) { + lw(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset)); +} + + +void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { + lw(dst, FieldMemOperand(map, Map::kBitField3Offset)); + DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); } diff --git a/deps/v8/src/mips/macro-assembler-mips.h b/deps/v8/src/mips/macro-assembler-mips.h index 2a77d6ce23..474772e0be 100644 --- a/deps/v8/src/mips/macro-assembler-mips.h +++ b/deps/v8/src/mips/macro-assembler-mips.h @@ -65,6 +65,14 @@ enum AllocationFlags { SIZE_IN_WORDS = 1 << 2 }; +// Flags used for AllocateHeapNumber +enum TaggingMode { + // Tag the result. + TAG_RESULT, + // Don't tag + DONT_TAG_RESULT +}; + // Flags used for the ObjectToDoubleFPURegister function. enum ObjectToDoubleFlags { // No special flags. @@ -536,7 +544,8 @@ class MacroAssembler: public Assembler { Register scratch1, Register scratch2, Register heap_number_map, - Label* gc_required); + Label* gc_required, + TaggingMode tagging_mode = TAG_RESULT); void AllocateHeapNumberWithValue(Register result, FPURegister value, Register scratch1, @@ -620,6 +629,7 @@ class MacroAssembler: public Assembler { // Push a handle. void Push(Handle<Object> handle); + void Push(Smi* smi) { Push(Handle<Smi>(smi)); } // Push two registers. Pushes leftmost register first (to highest address). void Push(Register src1, Register src2) { @@ -752,14 +762,16 @@ class MacroAssembler: public Assembler { FPURegister double_scratch, Label *not_int32); - // Truncates a double using a specific rounding mode. + // Truncates a double using a specific rounding mode, and writes the value + // to the result register. // The except_flag will contain any exceptions caused by the instruction. - // If check_inexact is kDontCheckForInexactConversion, then the inexacat + // If check_inexact is kDontCheckForInexactConversion, then the inexact // exception is masked. void EmitFPUTruncate(FPURoundingMode rounding_mode, - FPURegister result, + Register result, DoubleRegister double_input, - Register scratch1, + Register scratch, + DoubleRegister double_scratch, Register except_flag, CheckForInexactConversion check_inexact = kDontCheckForInexactConversion); @@ -972,13 +984,14 @@ class MacroAssembler: public Assembler { // case scratch2, scratch3 and scratch4 are unmodified. void StoreNumberToDoubleElements(Register value_reg, Register key_reg, - Register receiver_reg, + // All regs below here overwritten. Register elements_reg, Register scratch1, Register scratch2, Register scratch3, Register scratch4, - Label* fail); + Label* fail, + int elements_offset = 0); // Compare an object's map with the specified map and its transitioned // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Jumps to @@ -1335,17 +1348,18 @@ class MacroAssembler: public Assembler { // Jump if either of the registers contain a smi. void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi); - // Abort execution if argument is a smi. Used in debug code. - void AbortIfSmi(Register object); - void AbortIfNotSmi(Register object); + // Abort execution if argument is a smi, enabled via --debug-code. + void AssertNotSmi(Register object); + void AssertSmi(Register object); - // Abort execution if argument is a string. Used in debug code. - void AbortIfNotString(Register object); + // Abort execution if argument is not a string, enabled via --debug-code. + void AssertString(Register object); - // Abort execution if argument is not the root value with the given index. - void AbortIfNotRootValue(Register src, - Heap::RootListIndex root_value_index, - const char* message); + // Abort execution if argument is not the root value with the given index, + // enabled via --debug-code. + void AssertRootValue(Register src, + Heap::RootListIndex root_value_index, + const char* message); // --------------------------------------------------------------------------- // HeapNumber utilities. @@ -1396,11 +1410,17 @@ class MacroAssembler: public Assembler { DoubleRegister temp_double_reg); - void LoadInstanceDescriptors(Register map, - Register descriptors, - Register scratch); + void LoadInstanceDescriptors(Register map, Register descriptors); void EnumLength(Register dst, Register map); - + void NumberOfOwnDescriptors(Register dst, Register map); + + template<typename Field> + void DecodeField(Register reg) { + static const int shift = Field::kShift; + static const int mask = (Field::kMask >> shift) << kSmiTagSize; + srl(reg, reg, shift); + And(reg, reg, Operand(mask)); + } // Activation support. void EnterFrame(StackFrame::Type type); diff --git a/deps/v8/src/mips/regexp-macro-assembler-mips.cc b/deps/v8/src/mips/regexp-macro-assembler-mips.cc index 21d1ce11b5..0dd72de339 100644 --- a/deps/v8/src/mips/regexp-macro-assembler-mips.cc +++ b/deps/v8/src/mips/regexp-macro-assembler-mips.cc @@ -1103,6 +1103,11 @@ void RegExpMacroAssemblerMIPS::WriteStackPointerToRegister(int reg) { } +bool RegExpMacroAssemblerMIPS::CanReadUnaligned() { + return false; +} + + // Private methods: void RegExpMacroAssemblerMIPS::CallCheckStackGuardState(Register scratch) { @@ -1150,7 +1155,7 @@ int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address, Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); // Current string. - bool is_ascii = subject->IsAsciiRepresentationUnderneath(); + bool is_ascii = subject->IsOneByteRepresentationUnderneath(); ASSERT(re_code->instruction_start() <= *return_address); ASSERT(*return_address <= @@ -1181,7 +1186,7 @@ int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address, } // String might have changed. - if (subject_tmp->IsAsciiRepresentation() != is_ascii) { + if (subject_tmp->IsOneByteRepresentation() != is_ascii) { // If we changed between an ASCII and an UC16 string, the specialized // code cannot be used, and we need to restart regexp matching from // scratch (including, potentially, compiling a new version of the code). diff --git a/deps/v8/src/mips/regexp-macro-assembler-mips.h b/deps/v8/src/mips/regexp-macro-assembler-mips.h index 5446f52439..8dd52a4847 100644 --- a/deps/v8/src/mips/regexp-macro-assembler-mips.h +++ b/deps/v8/src/mips/regexp-macro-assembler-mips.h @@ -112,6 +112,7 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler { virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); virtual void ClearRegisters(int reg_from, int reg_to); virtual void WriteStackPointerToRegister(int reg); + virtual bool CanReadUnaligned(); // Called from RegExp if the stack-guard is triggered. // If the code object is relocated, the return address is fixed before diff --git a/deps/v8/src/mips/simulator-mips.cc b/deps/v8/src/mips/simulator-mips.cc index cf87f93602..ea359eadea 100644 --- a/deps/v8/src/mips/simulator-mips.cc +++ b/deps/v8/src/mips/simulator-mips.cc @@ -1016,6 +1016,13 @@ void Simulator::set_register(int reg, int32_t value) { } +void Simulator::set_dw_register(int reg, const int* dbl) { + ASSERT((reg >= 0) && (reg < kNumSimuRegisters)); + registers_[reg] = dbl[0]; + registers_[reg + 1] = dbl[1]; +} + + void Simulator::set_fpu_register(int fpureg, int32_t value) { ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); FPUregisters_[fpureg] = value; @@ -1045,6 +1052,19 @@ int32_t Simulator::get_register(int reg) const { } +double Simulator::get_double_from_register_pair(int reg) { + ASSERT((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0)); + + double dm_val = 0.0; + // Read the bits from the unsigned integer register_[] array + // into the double precision floating point value and return it. + char buffer[2 * sizeof(registers_[0])]; + memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0])); + memcpy(&dm_val, buffer, 2 * sizeof(registers_[0])); + return(dm_val); +} + + int32_t Simulator::get_fpu_register(int fpureg) const { ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters)); return FPUregisters_[fpureg]; @@ -2219,10 +2239,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { set_register(HI, static_cast<int32_t>(u64hilo >> 32)); break; case DIV: - // Divide by zero was not checked in the configuration step - div and - // divu do not raise exceptions. On division by 0, the result will - // be UNPREDICTABLE. - if (rt != 0) { + // Divide by zero and overflow was not checked in the configuration + // step - div and divu do not raise exceptions. On division by 0 and + // on overflow (INT_MIN/-1), the result will be UNPREDICTABLE. + if (rt != 0 && !(rs == INT_MIN && rt == -1)) { set_register(LO, rs / rt); set_register(HI, rs % rt); } @@ -2718,34 +2738,7 @@ void Simulator::Execute() { } -int32_t Simulator::Call(byte* entry, int argument_count, ...) { - va_list parameters; - va_start(parameters, argument_count); - // Set up arguments. - - // First four arguments passed in registers. - ASSERT(argument_count >= 4); - set_register(a0, va_arg(parameters, int32_t)); - set_register(a1, va_arg(parameters, int32_t)); - set_register(a2, va_arg(parameters, int32_t)); - set_register(a3, va_arg(parameters, int32_t)); - - // Remaining arguments passed on stack. - int original_stack = get_register(sp); - // Compute position of stack on entry to generated code. - int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t) - - kCArgsSlotsSize); - if (OS::ActivationFrameAlignment() != 0) { - entry_stack &= -OS::ActivationFrameAlignment(); - } - // Store remaining arguments on stack, from low to high memory. - intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); - for (int i = 4; i < argument_count; i++) { - stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t); - } - va_end(parameters); - set_register(sp, entry_stack); - +void Simulator::CallInternal(byte* entry) { // Prepare to execute the code at entry. set_register(pc, reinterpret_cast<int32_t>(entry)); // Put down marker for end of simulation. The simulator will stop simulation @@ -2809,6 +2802,38 @@ int32_t Simulator::Call(byte* entry, int argument_count, ...) { set_register(gp, gp_val); set_register(sp, sp_val); set_register(fp, fp_val); +} + + +int32_t Simulator::Call(byte* entry, int argument_count, ...) { + va_list parameters; + va_start(parameters, argument_count); + // Set up arguments. + + // First four arguments passed in registers. + ASSERT(argument_count >= 4); + set_register(a0, va_arg(parameters, int32_t)); + set_register(a1, va_arg(parameters, int32_t)); + set_register(a2, va_arg(parameters, int32_t)); + set_register(a3, va_arg(parameters, int32_t)); + + // Remaining arguments passed on stack. + int original_stack = get_register(sp); + // Compute position of stack on entry to generated code. + int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t) + - kCArgsSlotsSize); + if (OS::ActivationFrameAlignment() != 0) { + entry_stack &= -OS::ActivationFrameAlignment(); + } + // Store remaining arguments on stack, from low to high memory. + intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); + for (int i = 4; i < argument_count; i++) { + stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t); + } + va_end(parameters); + set_register(sp, entry_stack); + + CallInternal(entry); // Pop stack passed arguments. CHECK_EQ(entry_stack, get_register(sp)); @@ -2819,6 +2844,27 @@ int32_t Simulator::Call(byte* entry, int argument_count, ...) { } +double Simulator::CallFP(byte* entry, double d0, double d1) { + if (!IsMipsSoftFloatABI) { + set_fpu_register_double(f12, d0); + set_fpu_register_double(f14, d1); + } else { + int buffer[2]; + ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0)); + memcpy(buffer, &d0, sizeof(d0)); + set_dw_register(a0, buffer); + memcpy(buffer, &d1, sizeof(d1)); + set_dw_register(a2, buffer); + } + CallInternal(entry); + if (!IsMipsSoftFloatABI) { + return get_fpu_register_double(f0); + } else { + return get_double_from_register_pair(v0); + } +} + + uintptr_t Simulator::PushAddress(uintptr_t address) { int new_sp = get_register(sp) - sizeof(uintptr_t); uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp); diff --git a/deps/v8/src/mips/simulator-mips.h b/deps/v8/src/mips/simulator-mips.h index 776badc29b..67f595302b 100644 --- a/deps/v8/src/mips/simulator-mips.h +++ b/deps/v8/src/mips/simulator-mips.h @@ -184,7 +184,9 @@ class Simulator { // architecture specification and is off by a 8 from the currently executing // instruction. void set_register(int reg, int32_t value); + void set_dw_register(int dreg, const int* dbl); int32_t get_register(int reg) const; + double get_double_from_register_pair(int reg); // Same for FPURegisters. void set_fpu_register(int fpureg, int32_t value); void set_fpu_register_float(int fpureg, float value); @@ -214,6 +216,8 @@ class Simulator { // generated RegExp code with 7 parameters. This is a convenience function, // which sets up the simulator state and grabs the result on return. int32_t Call(byte* entry, int argument_count, ...); + // Alternative: call a 2-argument double function. + double CallFP(byte* entry, double d0, double d1); // Push an address onto the JS stack. uintptr_t PushAddress(uintptr_t address); @@ -353,6 +357,7 @@ class Simulator { void GetFpArgs(double* x, int32_t* y); void SetFpResult(const double& result); + void CallInternal(byte* entry); // Architecture state. // Registers. diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc index 391f8e072b..323933b5de 100644 --- a/deps/v8/src/mips/stub-cache-mips.cc +++ b/deps/v8/src/mips/stub-cache-mips.cc @@ -314,18 +314,23 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, Register dst, Register src, Handle<JSObject> holder, - int index) { - // Adjust for the number of properties stored in the holder. - index -= holder->map()->inobject_properties(); - if (index < 0) { - // Get the property straight out of the holder. - int offset = holder->map()->instance_size() + (index * kPointerSize); + PropertyIndex index) { + if (index.is_header_index()) { + int offset = index.header_index() * kPointerSize; __ lw(dst, FieldMemOperand(src, offset)); } else { - // Calculate the offset into the properties array. - int offset = index * kPointerSize + FixedArray::kHeaderSize; - __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset)); - __ lw(dst, FieldMemOperand(dst, offset)); + // Adjust for the number of properties stored in the holder. + int slot = index.field_index() - holder->map()->inobject_properties(); + if (slot < 0) { + // Get the property straight out of the holder. + int offset = holder->map()->instance_size() + (slot * kPointerSize); + __ lw(dst, FieldMemOperand(src, offset)); + } else { + // Calculate the offset into the properties array. + int offset = slot * kPointerSize + FixedArray::kHeaderSize; + __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset)); + __ lw(dst, FieldMemOperand(dst, offset)); + } } } @@ -1200,7 +1205,7 @@ void StubCompiler::GenerateLoadField(Handle<JSObject> object, Register scratch1, Register scratch2, Register scratch3, - int index, + PropertyIndex index, Handle<String> name, Label* miss) { // Check that the receiver isn't a smi. @@ -1549,7 +1554,7 @@ void CallStubCompiler::GenerateMissBranch() { Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name) { // ----------- S t a t e ------------- // -- a2 : name @@ -1623,7 +1628,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( } else { Label call_builtin; if (argc == 1) { // Otherwise fall through to call the builtin. - Label attempt_to_grow_elements; + Label attempt_to_grow_elements, with_write_barrier, check_double; Register elements = t2; Register end_elements = t1; @@ -1634,7 +1639,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( __ CheckMap(elements, v0, Heap::kFixedArrayMapRootIndex, - &call_builtin, + &check_double, DONT_DO_SMI_CHECK); // Get the array's length into v0 and calculate new length. @@ -1650,7 +1655,6 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( __ Branch(&attempt_to_grow_elements, gt, v0, Operand(t0)); // Check if value is a smi. - Label with_write_barrier; __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize)); __ JumpIfNotSmi(t0, &with_write_barrier); @@ -1671,6 +1675,39 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( __ Drop(argc + 1); __ Ret(); + __ bind(&check_double); + + // Check that the elements are in fast mode and writable. + __ CheckMap(elements, + a0, + Heap::kFixedDoubleArrayMapRootIndex, + &call_builtin, + DONT_DO_SMI_CHECK); + + // Get the array's length into r0 and calculate new length. + __ lw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset)); + STATIC_ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0); + __ Addu(a0, a0, Operand(Smi::FromInt(argc))); + + // Get the elements' length. + __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); + + // Check if we could survive without allocation. + __ Branch(&call_builtin, gt, a0, Operand(t0)); + + __ lw(t0, MemOperand(sp, (argc - 1) * kPointerSize)); + __ StoreNumberToDoubleElements( + t0, a0, elements, a3, t1, a2, t5, + &call_builtin, argc * kDoubleSize); + + // Save new length. + __ sw(a0, FieldMemOperand(receiver, JSArray::kLengthOffset)); + + // Check for a smi. + __ Drop(argc + 1); + __ Ret(); + __ bind(&with_write_barrier); __ lw(a3, FieldMemOperand(receiver, HeapObject::kMapOffset)); @@ -1682,8 +1719,12 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( // In case of fast smi-only, convert to fast object, otherwise bail out. __ bind(¬_fast_object); __ CheckFastSmiElements(a3, t3, &call_builtin); + + __ lw(t3, FieldMemOperand(t0, HeapObject::kMapOffset)); + __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); + __ Branch(&call_builtin, eq, t3, Operand(at)); // edx: receiver - // r3: map + // a3: map Label try_holey_map; __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, @@ -2915,7 +2956,7 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name, Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name) { // ----------- S t a t e ------------- // -- a0 : receiver @@ -3106,7 +3147,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal( Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name, Handle<JSObject> receiver, Handle<JSObject> holder, - int index) { + PropertyIndex index) { // ----------- S t a t e ------------- // -- ra : return address // -- a0 : key @@ -3453,7 +3494,7 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( // t7: undefined __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset)); __ Check(ne, "Function constructed by construct stub.", - a3, Operand(JS_FUNCTION_TYPE)); + a3, Operand(JS_FUNCTION_TYPE)); #endif // Now allocate the JSObject in new space. @@ -3461,7 +3502,13 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( // a1: constructor function // a2: initial map // t7: undefined + ASSERT(function->has_initial_map()); __ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset)); +#ifdef DEBUG + int instance_size = function->initial_map()->instance_size(); + __ Check(eq, "Instance size of initial map changed.", + a3, Operand(instance_size >> kPointerSizeLog2)); +#endif __ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS); // Allocated the JSObject, now initialize the fields. Map is set to initial @@ -3524,7 +3571,6 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( } // Fill the unused in-object property fields with undefined. - ASSERT(function->has_initial_map()); for (int i = shared->this_property_assignments_count(); i < function->initial_map()->inobject_properties(); i++) { @@ -3649,6 +3695,7 @@ static void GenerateSmiKeyCheck(MacroAssembler* masm, Register scratch0, Register scratch1, FPURegister double_scratch0, + FPURegister double_scratch1, Label* fail) { if (CpuFeatures::IsSupported(FPU)) { CpuFeatures::Scope scope(FPU); @@ -3664,15 +3711,15 @@ static void GenerateSmiKeyCheck(MacroAssembler* masm, DONT_DO_SMI_CHECK); __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset)); __ EmitFPUTruncate(kRoundToZero, - double_scratch0, - double_scratch0, scratch0, + double_scratch0, + at, + double_scratch1, scratch1, kCheckForInexactConversion); __ Branch(fail, ne, scratch1, Operand(zero_reg)); - __ mfc1(scratch0, double_scratch0); __ SmiTagCheckOverflow(key, scratch0, scratch1); __ BranchOnOverflow(fail, scratch1); __ bind(&key_ok); @@ -3700,7 +3747,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // have been verified by the caller to not be a smi. // Check that the key is a smi or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic); + GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic); __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset)); // a3: elements array @@ -3800,34 +3847,41 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ Ret(); __ bind(&box_int); - // Allocate a HeapNumber for the result and perform int-to-double - // conversion. - // The arm version uses a temporary here to save r0, but we don't need to - // (a0 is not modified). - __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(v0, a3, t0, t1, &slow); if (CpuFeatures::IsSupported(FPU)) { CpuFeatures::Scope scope(FPU); + // Allocate a HeapNumber for the result and perform int-to-double + // conversion. + // The arm version uses a temporary here to save r0, but we don't need to + // (a0 is not modified). + __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex); + __ AllocateHeapNumber(v0, a3, t0, t1, &slow, DONT_TAG_RESULT); __ mtc1(value, f0); __ cvt_d_w(f0, f0); - __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); + __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset)); + __ Addu(v0, v0, kHeapObjectTag); __ Ret(); } else { - Register dst1 = t2; - Register dst2 = t3; + // Allocate a HeapNumber for the result and perform int-to-double + // conversion. + // The arm version uses a temporary here to save r0, but we don't need to + // (a0 is not modified). + __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex); + __ AllocateHeapNumber(v0, a3, t0, t1, &slow, TAG_RESULT); + Register dst_mantissa = t2; + Register dst_exponent = t3; FloatingPointHelper::Destination dest = FloatingPointHelper::kCoreRegisters; FloatingPointHelper::ConvertIntToDouble(masm, value, dest, f0, - dst1, - dst2, + dst_mantissa, + dst_exponent, t1, f2); - __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset)); - __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset)); + __ sw(dst_mantissa, FieldMemOperand(v0, HeapNumber::kMantissaOffset)); + __ sw(dst_exponent, FieldMemOperand(v0, HeapNumber::kExponentOffset)); __ Ret(); } } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { @@ -3850,7 +3904,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all // registers - also when jumping due to exhausted young space. __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(v0, t2, t3, t6, &slow); + __ AllocateHeapNumber(v0, t2, t3, t6, &slow, DONT_TAG_RESULT); // This is replaced by a macro: // __ mtc1(value, f0); // LS 32-bits. @@ -3859,8 +3913,9 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ Cvt_d_uw(f0, value, f22); - __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); + __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset)); + __ Addu(v0, v0, kHeapObjectTag); __ Ret(); } else { // Check whether unsigned integer fits into smi. @@ -3893,7 +3948,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // clobbers all registers - also when jumping due to exhausted young // space. __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(t2, t3, t5, t6, &slow); + __ AllocateHeapNumber(t2, t3, t5, t6, &slow, TAG_RESULT); __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset)); __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset)); @@ -3910,17 +3965,19 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // AllocateHeapNumber clobbers all registers - also when jumping due to // exhausted young space. __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(v0, t3, t5, t6, &slow); + __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT); // The float (single) value is already in fpu reg f0 (if we use float). __ cvt_d_s(f0, f0); - __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); + __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset)); + + __ Addu(v0, v0, kHeapObjectTag); __ Ret(); } else { // Allocate a HeapNumber for the result. Don't use a0 and a1 as // AllocateHeapNumber clobbers all registers - also when jumping due to // exhausted young space. __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(v0, t3, t5, t6, &slow); + __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT); // FPU is not available, do manual single to double conversion. // a2: floating point value (binary32). @@ -3975,16 +4032,18 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( // AllocateHeapNumber clobbers all registers - also when jumping due to // exhausted young space. __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(v0, t3, t5, t6, &slow); + __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT); // The double value is already in f0 - __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); + __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset)); + + __ Addu(v0, v0, kHeapObjectTag); __ Ret(); } else { // Allocate a HeapNumber for the result. Don't use a0 and a1 as // AllocateHeapNumber clobbers all registers - also when jumping due to // exhausted young space. __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(v0, t3, t5, t6, &slow); + __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT); __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset)); __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset)); @@ -4042,7 +4101,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( // have been verified by the caller to not be a smi. // Check that the key is a smi or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic); + GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic); __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset)); @@ -4121,7 +4180,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( } FloatingPointHelper::ConvertIntToDouble( masm, t1, destination, - f0, t2, t3, // These are: double_dst, dst1, dst2. + f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent. t0, f2); // These are: scratch2, single_scratch. if (destination == FloatingPointHelper::kFPURegisters) { CpuFeatures::Scope scope(FPU); @@ -4431,7 +4490,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { // have been verified by the caller to not be a smi. // Check that the key is a smi or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic); + GenerateSmiKeyCheck(masm, a0, t0, t1, f2, f4, &miss_force_generic); // Get the elements array. __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset)); @@ -4482,7 +4541,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( // have been verified by the caller to not be a smi. // 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); + GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic); // Get the elements array. __ lw(elements_reg, @@ -4502,7 +4561,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement( // Non-NaN. Allocate a new heap number and copy the double value into it. __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3, - heap_number_map, &slow_allocate_heapnumber); + heap_number_map, &slow_allocate_heapnumber, TAG_RESULT); // Don't need to reload the upper 32 bits of the double, it's already in // scratch. @@ -4556,7 +4615,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( // have been verified by the caller to not be a smi. // 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); + GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic); if (IsFastSmiElementsKind(elements_kind)) { __ JumpIfNotSmi(value_reg, &transition_elements_kind); @@ -4700,11 +4759,12 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // -- a1 : key // -- a2 : receiver // -- ra : return address - // -- a3 : scratch + // -- a3 : scratch (elements backing store) // -- t0 : scratch (elements_reg) // -- t1 : scratch (mantissa_reg) // -- t2 : scratch (exponent_reg) // -- t3 : scratch4 + // -- t4 : scratch // ----------------------------------- Label miss_force_generic, transition_elements_kind, grow, slow; Label finish_store, check_capacity; @@ -4717,13 +4777,14 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( Register scratch2 = t1; Register scratch3 = t2; Register scratch4 = t3; + Register scratch5 = t4; Register length_reg = 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 or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic); + GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic); __ lw(elements_reg, FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); @@ -4747,7 +4808,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ StoreNumberToDoubleElements(value_reg, key_reg, - receiver_reg, + // All registers after this are overwritten. elements_reg, scratch1, scratch2, @@ -4797,14 +4858,32 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT); - // Initialize the new FixedDoubleArray. Leave elements unitialized for - // efficiency, they are guaranteed to be initialized before use. + // Initialize the new FixedDoubleArray. __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex); __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset)); __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements))); __ sw(scratch1, FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset)); + __ mov(scratch1, elements_reg); + __ StoreNumberToDoubleElements(value_reg, + key_reg, + // All registers after this are overwritten. + scratch1, + scratch2, + scratch3, + scratch4, + scratch5, + &transition_elements_kind); + + __ li(scratch1, Operand(kHoleNanLower32)); + __ li(scratch2, Operand(kHoleNanUpper32)); + for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { + int offset = FixedDoubleArray::OffsetOfElementAt(i); + __ sw(scratch1, FieldMemOperand(elements_reg, offset)); + __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize)); + } + // Install the new backing store in the JSArray. __ sw(elements_reg, FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); @@ -4817,7 +4896,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); __ lw(elements_reg, FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); - __ jmp(&finish_store); + __ Ret(); __ bind(&check_capacity); // Make sure that the backing store can hold additional elements. diff --git a/deps/v8/src/mirror-debugger.js b/deps/v8/src/mirror-debugger.js index a5331a014d..7f1a05aed9 100644 --- a/deps/v8/src/mirror-debugger.js +++ b/deps/v8/src/mirror-debugger.js @@ -1844,10 +1844,14 @@ function ScopeDetails(frame, fun, index) { frame.details_.frameId(), frame.details_.inlinedFrameIndex(), index); + this.frame_id_ = frame.details_.frameId(); + this.inlined_frame_id_ = frame.details_.inlinedFrameIndex(); } else { this.details_ = %GetFunctionScopeDetails(fun.value(), index); + this.fun_value_ = fun.value(); this.break_id_ = undefined; } + this.index_ = index; } @@ -1867,6 +1871,22 @@ ScopeDetails.prototype.object = function() { }; +ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) { + var raw_res; + if (!IS_UNDEFINED(this.break_id_)) { + %CheckExecutionState(this.break_id_); + raw_res = %SetScopeVariableValue(this.break_id_, this.frame_id_, + this.inlined_frame_id_, this.index_, name, new_value); + } else { + raw_res = %SetScopeVariableValue(this.fun_value_, null, null, this.index_, + name, new_value); + } + if (!raw_res) { + throw new Error("Failed to set variable value"); + } +}; + + /** * Mirror object for scope of frame or function. Either frame or function must * be specified. @@ -1914,6 +1934,11 @@ ScopeMirror.prototype.scopeObject = function() { }; +ScopeMirror.prototype.setVariableValue = function(name, new_value) { + this.details_.setVariableValueImpl(name, new_value); +}; + + /** * Mirror object for script source. * @param {Script} script The script object diff --git a/deps/v8/src/mksnapshot.cc b/deps/v8/src/mksnapshot.cc index 275c8acc83..d7775517b7 100644 --- a/deps/v8/src/mksnapshot.cc +++ b/deps/v8/src/mksnapshot.cc @@ -166,30 +166,37 @@ class CppByteSink : public PartialSnapshotSink { } void WriteSpaceUsed( + const char* prefix, int new_space_used, int pointer_space_used, int data_space_used, int code_space_used, int map_space_used, - int cell_space_used, - int large_space_used) { - fprintf(fp_, "const int Snapshot::new_space_used_ = %d;\n", new_space_used); + int cell_space_used) { fprintf(fp_, - "const int Snapshot::pointer_space_used_ = %d;\n", + "const int Snapshot::%snew_space_used_ = %d;\n", + prefix, + new_space_used); + fprintf(fp_, + "const int Snapshot::%spointer_space_used_ = %d;\n", + prefix, pointer_space_used); fprintf(fp_, - "const int Snapshot::data_space_used_ = %d;\n", + "const int Snapshot::%sdata_space_used_ = %d;\n", + prefix, data_space_used); fprintf(fp_, - "const int Snapshot::code_space_used_ = %d;\n", + "const int Snapshot::%scode_space_used_ = %d;\n", + prefix, code_space_used); - fprintf(fp_, "const int Snapshot::map_space_used_ = %d;\n", map_space_used); fprintf(fp_, - "const int Snapshot::cell_space_used_ = %d;\n", - cell_space_used); + "const int Snapshot::%smap_space_used_ = %d;\n", + prefix, + map_space_used); fprintf(fp_, - "const int Snapshot::large_space_used_ = %d;\n", - large_space_used); + "const int Snapshot::%scell_space_used_ = %d;\n", + prefix, + cell_space_used); } void WritePartialSnapshot() { @@ -400,12 +407,20 @@ int main(int argc, char** argv) { sink.WritePartialSnapshot(); sink.WriteSpaceUsed( + "context_", partial_ser.CurrentAllocationAddress(i::NEW_SPACE), partial_ser.CurrentAllocationAddress(i::OLD_POINTER_SPACE), partial_ser.CurrentAllocationAddress(i::OLD_DATA_SPACE), partial_ser.CurrentAllocationAddress(i::CODE_SPACE), partial_ser.CurrentAllocationAddress(i::MAP_SPACE), - partial_ser.CurrentAllocationAddress(i::CELL_SPACE), - partial_ser.CurrentAllocationAddress(i::LO_SPACE)); + partial_ser.CurrentAllocationAddress(i::CELL_SPACE)); + sink.WriteSpaceUsed( + "", + ser.CurrentAllocationAddress(i::NEW_SPACE), + ser.CurrentAllocationAddress(i::OLD_POINTER_SPACE), + ser.CurrentAllocationAddress(i::OLD_DATA_SPACE), + ser.CurrentAllocationAddress(i::CODE_SPACE), + ser.CurrentAllocationAddress(i::MAP_SPACE), + ser.CurrentAllocationAddress(i::CELL_SPACE)); return 0; } diff --git a/deps/v8/src/object-observe.js b/deps/v8/src/object-observe.js new file mode 100644 index 0000000000..8c2895f4bd --- /dev/null +++ b/deps/v8/src/object-observe.js @@ -0,0 +1,242 @@ +// 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 observationState = %GetObservationState(); +if (IS_UNDEFINED(observationState.observerInfoMap)) { + observationState.observerInfoMap = %CreateObjectHashTable(); + observationState.objectInfoMap = %CreateObjectHashTable(); + observationState.notifierTargetMap = %CreateObjectHashTable(); + observationState.pendingObservers = new InternalArray; + observationState.observerPriority = 0; +} + +function InternalObjectHashTable(tableName) { + this.tableName = tableName; +} + +InternalObjectHashTable.prototype = { + get: function(key) { + return %ObjectHashTableGet(observationState[this.tableName], key); + }, + set: function(key, value) { + observationState[this.tableName] = + %ObjectHashTableSet(observationState[this.tableName], key, value); + }, + has: function(key) { + return !IS_UNDEFINED(this.get(key)); + } +}; + +var observerInfoMap = new InternalObjectHashTable('observerInfoMap'); +var objectInfoMap = new InternalObjectHashTable('objectInfoMap'); +var notifierTargetMap = new InternalObjectHashTable('notifierTargetMap'); + +function CreateObjectInfo(object) { + var info = { + changeObservers: new InternalArray, + notifier: null, + }; + objectInfoMap.set(object, info); + return info; +} + +function ObjectObserve(object, callback) { + if (!IS_SPEC_OBJECT(object)) + throw MakeTypeError("observe_non_object", ["observe"]); + if (!IS_SPEC_FUNCTION(callback)) + throw MakeTypeError("observe_non_function", ["observe"]); + if (ObjectIsFrozen(callback)) + throw MakeTypeError("observe_callback_frozen"); + + if (!observerInfoMap.has(callback)) { + observerInfoMap.set(callback, { + pendingChangeRecords: null, + priority: observationState.observerPriority++, + }); + } + + var objectInfo = objectInfoMap.get(object); + if (IS_UNDEFINED(objectInfo)) { + objectInfo = CreateObjectInfo(object); + %SetIsObserved(object, true); + } + + var changeObservers = objectInfo.changeObservers; + if (changeObservers.indexOf(callback) < 0) + changeObservers.push(callback); + + return object; +} + +function ObjectUnobserve(object, callback) { + if (!IS_SPEC_OBJECT(object)) + throw MakeTypeError("observe_non_object", ["unobserve"]); + if (!IS_SPEC_FUNCTION(callback)) + throw MakeTypeError("observe_non_function", ["unobserve"]); + + var objectInfo = objectInfoMap.get(object); + if (IS_UNDEFINED(objectInfo)) + return object; + + var changeObservers = objectInfo.changeObservers; + var index = changeObservers.indexOf(callback); + if (index >= 0) + changeObservers.splice(index, 1); + + return object; +} + +function EnqueueChangeRecord(changeRecord, observers) { + for (var i = 0; i < observers.length; i++) { + var observer = observers[i]; + var observerInfo = observerInfoMap.get(observer); + observationState.pendingObservers[observerInfo.priority] = observer; + %SetObserverDeliveryPending(); + if (IS_NULL(observerInfo.pendingChangeRecords)) { + observerInfo.pendingChangeRecords = new InternalArray(changeRecord); + } else { + observerInfo.pendingChangeRecords.push(changeRecord); + } + } +} + +function NotifyChange(type, object, name, oldValue) { + var objectInfo = objectInfoMap.get(object); + var changeRecord = (arguments.length < 4) ? + { type: type, object: object, name: name } : + { type: type, object: object, name: name, oldValue: oldValue }; + ObjectFreeze(changeRecord); + EnqueueChangeRecord(changeRecord, objectInfo.changeObservers); +} + +var notifierPrototype = {}; + +function ObjectNotifierNotify(changeRecord) { + if (!IS_SPEC_OBJECT(this)) + throw MakeTypeError("called_on_non_object", ["notify"]); + + var target = notifierTargetMap.get(this); + if (IS_UNDEFINED(target)) + throw MakeTypeError("observe_notify_non_notifier"); + + if (!IS_STRING(changeRecord.type)) + throw MakeTypeError("observe_type_non_string"); + + var objectInfo = objectInfoMap.get(target); + if (IS_UNDEFINED(objectInfo)) + return; + + if (!objectInfo.changeObservers.length) + return; + + var newRecord = { + object: target + }; + for (var prop in changeRecord) { + if (prop === 'object') + continue; + + %DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop], + READ_ONLY + DONT_DELETE); + } + ObjectFreeze(newRecord); + + EnqueueChangeRecord(newRecord, objectInfo.changeObservers); +} + +function ObjectGetNotifier(object) { + if (!IS_SPEC_OBJECT(object)) + throw MakeTypeError("observe_non_object", ["getNotifier"]); + + if (ObjectIsFrozen(object)) + return null; + + var objectInfo = objectInfoMap.get(object); + if (IS_UNDEFINED(objectInfo)) + objectInfo = CreateObjectInfo(object); + + if (IS_NULL(objectInfo.notifier)) { + objectInfo.notifier = { + __proto__: notifierPrototype + }; + notifierTargetMap.set(objectInfo.notifier, object); + } + + return objectInfo.notifier; +} + +function DeliverChangeRecordsForObserver(observer) { + var observerInfo = observerInfoMap.get(observer); + if (IS_UNDEFINED(observerInfo)) + return; + + var pendingChangeRecords = observerInfo.pendingChangeRecords; + if (IS_NULL(pendingChangeRecords)) + return; + + observerInfo.pendingChangeRecords = null; + delete observationState.pendingObservers[observerInfo.priority]; + var delivered = []; + %MoveArrayContents(pendingChangeRecords, delivered); + try { + %Call(void 0, delivered, observer); + } catch (ex) {} +} + +function ObjectDeliverChangeRecords(callback) { + if (!IS_SPEC_FUNCTION(callback)) + throw MakeTypeError("observe_non_function", ["deliverChangeRecords"]); + + DeliverChangeRecordsForObserver(callback); +} + +function DeliverChangeRecords() { + while (observationState.pendingObservers.length) { + var pendingObservers = observationState.pendingObservers; + observationState.pendingObservers = new InternalArray; + for (var i in pendingObservers) { + DeliverChangeRecordsForObserver(pendingObservers[i]); + } + } +} + +function SetupObjectObserve() { + %CheckIsBootstrapping(); + InstallFunctions($Object, DONT_ENUM, $Array( + "deliverChangeRecords", ObjectDeliverChangeRecords, + "getNotifier", ObjectGetNotifier, + "observe", ObjectObserve, + "unobserve", ObjectUnobserve + )); + InstallFunctions(notifierPrototype, DONT_ENUM, $Array( + "notify", ObjectNotifierNotify + )); +} + +SetupObjectObserve(); diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index 9761ed160b..e3226c18b8 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -35,7 +35,7 @@ namespace v8 { namespace internal { -#ifdef DEBUG +#ifdef VERIFY_HEAP void MaybeObject::Verify() { Object* this_as_object; @@ -55,18 +55,18 @@ void Object::VerifyPointer(Object* p) { if (p->IsHeapObject()) { HeapObject::VerifyHeapPointer(p); } else { - ASSERT(p->IsSmi()); + CHECK(p->IsSmi()); } } void Smi::SmiVerify() { - ASSERT(IsSmi()); + CHECK(IsSmi()); } void Failure::FailureVerify() { - ASSERT(IsFailure()); + CHECK(IsFailure()); } @@ -207,68 +207,68 @@ void HeapObject::HeapObjectVerify() { void HeapObject::VerifyHeapPointer(Object* p) { - ASSERT(p->IsHeapObject()); - ASSERT(HEAP->Contains(HeapObject::cast(p))); + CHECK(p->IsHeapObject()); + CHECK(HEAP->Contains(HeapObject::cast(p))); } void HeapNumber::HeapNumberVerify() { - ASSERT(IsHeapNumber()); + CHECK(IsHeapNumber()); } void ByteArray::ByteArrayVerify() { - ASSERT(IsByteArray()); + CHECK(IsByteArray()); } void FreeSpace::FreeSpaceVerify() { - ASSERT(IsFreeSpace()); + CHECK(IsFreeSpace()); } void ExternalPixelArray::ExternalPixelArrayVerify() { - ASSERT(IsExternalPixelArray()); + CHECK(IsExternalPixelArray()); } void ExternalByteArray::ExternalByteArrayVerify() { - ASSERT(IsExternalByteArray()); + CHECK(IsExternalByteArray()); } void ExternalUnsignedByteArray::ExternalUnsignedByteArrayVerify() { - ASSERT(IsExternalUnsignedByteArray()); + CHECK(IsExternalUnsignedByteArray()); } void ExternalShortArray::ExternalShortArrayVerify() { - ASSERT(IsExternalShortArray()); + CHECK(IsExternalShortArray()); } void ExternalUnsignedShortArray::ExternalUnsignedShortArrayVerify() { - ASSERT(IsExternalUnsignedShortArray()); + CHECK(IsExternalUnsignedShortArray()); } void ExternalIntArray::ExternalIntArrayVerify() { - ASSERT(IsExternalIntArray()); + CHECK(IsExternalIntArray()); } void ExternalUnsignedIntArray::ExternalUnsignedIntArrayVerify() { - ASSERT(IsExternalUnsignedIntArray()); + CHECK(IsExternalUnsignedIntArray()); } void ExternalFloatArray::ExternalFloatArrayVerify() { - ASSERT(IsExternalFloatArray()); + CHECK(IsExternalFloatArray()); } void ExternalDoubleArray::ExternalDoubleArrayVerify() { - ASSERT(IsExternalDoubleArray()); + CHECK(IsExternalDoubleArray()); } @@ -277,8 +277,8 @@ void JSObject::JSObjectVerify() { VerifyHeapPointer(elements()); if (GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) { - ASSERT(this->elements()->IsFixedArray()); - ASSERT(this->elements()->length() >= 2); + CHECK(this->elements()->IsFixedArray()); + CHECK_GE(this->elements()->length(), 2); } if (HasFastProperties()) { @@ -286,25 +286,25 @@ void JSObject::JSObjectVerify() { (map()->inobject_properties() + properties()->length() - map()->NextFreePropertyIndex())); } - ASSERT_EQ((map()->has_fast_smi_or_object_elements() || + CHECK_EQ((map()->has_fast_smi_or_object_elements() || (elements() == GetHeap()->empty_fixed_array())), (elements()->map() == GetHeap()->fixed_array_map() || elements()->map() == GetHeap()->fixed_cow_array_map())); - ASSERT(map()->has_fast_object_elements() == HasFastObjectElements()); + CHECK(map()->has_fast_object_elements() == HasFastObjectElements()); } void Map::MapVerify() { - ASSERT(!HEAP->InNewSpace(this)); - ASSERT(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE); - ASSERT(instance_size() == kVariableSizeSentinel || + CHECK(!HEAP->InNewSpace(this)); + CHECK(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE); + CHECK(instance_size() == kVariableSizeSentinel || (kPointerSize <= instance_size() && instance_size() < HEAP->Capacity())); VerifyHeapPointer(prototype()); VerifyHeapPointer(instance_descriptors()); DescriptorArray* descriptors = instance_descriptors(); for (int i = 0; i < NumberOfOwnDescriptors(); ++i) { - ASSERT_EQ(i, descriptors->GetDetails(i).descriptor_index() - 1); + CHECK_EQ(i, descriptors->GetDetails(i).descriptor_index() - 1); } SLOW_ASSERT(instance_descriptors()->IsSortedNoDuplicates()); if (HasTransitionArray()) { @@ -316,11 +316,11 @@ void Map::MapVerify() { void Map::SharedMapVerify() { MapVerify(); - ASSERT(is_shared()); - ASSERT(instance_descriptors()->IsEmpty()); - ASSERT_EQ(0, pre_allocated_property_fields()); - ASSERT_EQ(0, unused_property_fields()); - ASSERT_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()), + CHECK(is_shared()); + CHECK(instance_descriptors()->IsEmpty()); + CHECK_EQ(0, pre_allocated_property_fields()); + CHECK_EQ(0, unused_property_fields()); + CHECK_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()), visitor_id()); } @@ -328,15 +328,15 @@ void Map::SharedMapVerify() { void CodeCache::CodeCacheVerify() { VerifyHeapPointer(default_cache()); VerifyHeapPointer(normal_type_cache()); - ASSERT(default_cache()->IsFixedArray()); - ASSERT(normal_type_cache()->IsUndefined() + CHECK(default_cache()->IsFixedArray()); + CHECK(normal_type_cache()->IsUndefined() || normal_type_cache()->IsCodeCacheHashTable()); } void PolymorphicCodeCache::PolymorphicCodeCacheVerify() { VerifyHeapPointer(cache()); - ASSERT(cache()->IsUndefined() || cache()->IsPolymorphicCodeCacheHashTable()); + CHECK(cache()->IsUndefined() || cache()->IsPolymorphicCodeCacheHashTable()); } @@ -368,7 +368,7 @@ void FixedDoubleArray::FixedDoubleArrayVerify() { for (int i = 0; i < length(); i++) { if (!is_the_hole(i)) { double value = get_scalar(i); - ASSERT(!isnan(value) || + CHECK(!isnan(value) || (BitCast<uint64_t>(value) == BitCast<uint64_t>(canonical_not_the_hole_nan_as_double())) || ((BitCast<uint64_t>(value) & Double::kSignMask) != 0)); @@ -463,13 +463,13 @@ void String::StringVerify() { ConsString::cast(this)->ConsStringVerify(); } else if (IsSlicedString()) { SlicedString::cast(this)->SlicedStringVerify(); - } else if (IsSeqAsciiString()) { - SeqAsciiString::cast(this)->SeqAsciiStringVerify(); + } else if (IsSeqOneByteString()) { + SeqOneByteString::cast(this)->SeqOneByteStringVerify(); } } -void SeqAsciiString::SeqAsciiStringVerify() { +void SeqOneByteString::SeqOneByteStringVerify() { CHECK(String::IsAscii(GetChars(), length())); } @@ -499,7 +499,8 @@ void JSFunction::JSFunctionVerify() { VerifyObjectField(kPrototypeOrInitialMapOffset); VerifyObjectField(kNextFunctionLinkOffset); CHECK(code()->IsCode()); - CHECK(next_function_link()->IsUndefined() || + CHECK(next_function_link() == NULL || + next_function_link()->IsUndefined() || next_function_link()->IsJSFunction()); } @@ -555,14 +556,14 @@ void Oddball::OddballVerify() { VerifyHeapPointer(to_string()); Object* number = to_number(); if (number->IsHeapObject()) { - ASSERT(number == HEAP->nan_value()); + CHECK(number == HEAP->nan_value()); } else { - ASSERT(number->IsSmi()); + CHECK(number->IsSmi()); int value = Smi::cast(number)->value(); // Hidden oddballs have negative smis. const int kLeastHiddenOddballNumber = -4; - ASSERT(value <= 1); - ASSERT(value >= kLeastHiddenOddballNumber); + CHECK_LE(value, 1); + CHECK(value >= kLeastHiddenOddballNumber); } } @@ -591,8 +592,8 @@ void Code::CodeVerify() { void JSArray::JSArrayVerify() { JSObjectVerify(); - ASSERT(length()->IsNumber() || length()->IsUndefined()); - ASSERT(elements()->IsUndefined() || + CHECK(length()->IsNumber() || length()->IsUndefined()); + CHECK(elements()->IsUndefined() || elements()->IsFixedArray() || elements()->IsFixedDoubleArray()); } @@ -602,7 +603,7 @@ void JSSet::JSSetVerify() { CHECK(IsJSSet()); JSObjectVerify(); VerifyHeapPointer(table()); - ASSERT(table()->IsHashTable() || table()->IsUndefined()); + CHECK(table()->IsHashTable() || table()->IsUndefined()); } @@ -610,7 +611,7 @@ void JSMap::JSMapVerify() { CHECK(IsJSMap()); JSObjectVerify(); VerifyHeapPointer(table()); - ASSERT(table()->IsHashTable() || table()->IsUndefined()); + CHECK(table()->IsHashTable() || table()->IsUndefined()); } @@ -618,17 +619,17 @@ void JSWeakMap::JSWeakMapVerify() { CHECK(IsJSWeakMap()); JSObjectVerify(); VerifyHeapPointer(table()); - ASSERT(table()->IsHashTable() || table()->IsUndefined()); + CHECK(table()->IsHashTable() || table()->IsUndefined()); } void JSRegExp::JSRegExpVerify() { JSObjectVerify(); - ASSERT(data()->IsUndefined() || data()->IsFixedArray()); + CHECK(data()->IsUndefined() || data()->IsFixedArray()); switch (TypeTag()) { case JSRegExp::ATOM: { FixedArray* arr = FixedArray::cast(data()); - ASSERT(arr->get(JSRegExp::kAtomPatternIndex)->IsString()); + CHECK(arr->get(JSRegExp::kAtomPatternIndex)->IsString()); break; } case JSRegExp::IRREGEXP: { @@ -639,26 +640,26 @@ void JSRegExp::JSRegExpVerify() { // Smi : Not compiled yet (-1) or code prepared for flushing. // JSObject: Compilation error. // Code/ByteArray: Compiled code. - ASSERT(ascii_data->IsSmi() || + CHECK(ascii_data->IsSmi() || (is_native ? ascii_data->IsCode() : ascii_data->IsByteArray())); Object* uc16_data = arr->get(JSRegExp::kIrregexpUC16CodeIndex); - ASSERT(uc16_data->IsSmi() || + CHECK(uc16_data->IsSmi() || (is_native ? uc16_data->IsCode() : uc16_data->IsByteArray())); Object* ascii_saved = arr->get(JSRegExp::kIrregexpASCIICodeSavedIndex); - ASSERT(ascii_saved->IsSmi() || ascii_saved->IsString() || + CHECK(ascii_saved->IsSmi() || ascii_saved->IsString() || ascii_saved->IsCode()); Object* uc16_saved = arr->get(JSRegExp::kIrregexpUC16CodeSavedIndex); - ASSERT(uc16_saved->IsSmi() || uc16_saved->IsString() || + CHECK(uc16_saved->IsSmi() || uc16_saved->IsString() || uc16_saved->IsCode()); - ASSERT(arr->get(JSRegExp::kIrregexpCaptureCountIndex)->IsSmi()); - ASSERT(arr->get(JSRegExp::kIrregexpMaxRegisterCountIndex)->IsSmi()); + CHECK(arr->get(JSRegExp::kIrregexpCaptureCountIndex)->IsSmi()); + CHECK(arr->get(JSRegExp::kIrregexpMaxRegisterCountIndex)->IsSmi()); break; } default: - ASSERT_EQ(JSRegExp::NOT_COMPILED, TypeTag()); - ASSERT(data()->IsUndefined()); + CHECK_EQ(JSRegExp::NOT_COMPILED, TypeTag()); + CHECK(data()->IsUndefined()); break; } } @@ -667,7 +668,7 @@ void JSRegExp::JSRegExpVerify() { void JSProxy::JSProxyVerify() { CHECK(IsJSProxy()); VerifyPointer(handler()); - ASSERT(hash()->IsSmi() || hash()->IsUndefined()); + CHECK(hash()->IsSmi() || hash()->IsUndefined()); } @@ -680,7 +681,7 @@ void JSFunctionProxy::JSFunctionProxyVerify() { void Foreign::ForeignVerify() { - ASSERT(IsForeign()); + CHECK(IsForeign()); } @@ -784,6 +785,47 @@ void Script::ScriptVerify() { } +void JSFunctionResultCache::JSFunctionResultCacheVerify() { + JSFunction::cast(get(kFactoryIndex))->Verify(); + + int size = Smi::cast(get(kCacheSizeIndex))->value(); + CHECK(kEntriesIndex <= size); + CHECK(size <= length()); + CHECK_EQ(0, size % kEntrySize); + + int finger = Smi::cast(get(kFingerIndex))->value(); + CHECK(kEntriesIndex <= finger); + CHECK((finger < size) || (finger == kEntriesIndex && finger == size)); + CHECK_EQ(0, finger % kEntrySize); + + if (FLAG_enable_slow_asserts) { + for (int i = kEntriesIndex; i < size; i++) { + CHECK(!get(i)->IsTheHole()); + get(i)->Verify(); + } + for (int i = size; i < length(); i++) { + CHECK(get(i)->IsTheHole()); + get(i)->Verify(); + } + } +} + + +void NormalizedMapCache::NormalizedMapCacheVerify() { + FixedArray::cast(this)->Verify(); + if (FLAG_enable_slow_asserts) { + for (int i = 0; i < length(); i++) { + Object* e = get(i); + if (e->IsMap()) { + Map::cast(e)->SharedMapVerify(); + } else { + CHECK(e->IsUndefined()); + } + } + } +} + + #ifdef ENABLE_DEBUGGER_SUPPORT void DebugInfo::DebugInfoVerify() { CHECK(IsDebugInfo()); @@ -802,7 +844,9 @@ void BreakPointInfo::BreakPointInfoVerify() { VerifyPointer(break_point_objects()); } #endif // ENABLE_DEBUGGER_SUPPORT +#endif // VERIFY_HEAP +#ifdef DEBUG void JSObject::IncrementSpillStatistics(SpillInformation* info) { info->number_of_objects_++; @@ -901,7 +945,8 @@ void JSObject::SpillInformation::Print() { } -bool DescriptorArray::IsSortedNoDuplicates() { +bool DescriptorArray::IsSortedNoDuplicates(int valid_entries) { + if (valid_entries == -1) valid_entries = number_of_descriptors(); String* current_key = NULL; uint32_t current = 0; for (int i = 0; i < number_of_descriptors(); i++) { @@ -922,7 +967,8 @@ bool DescriptorArray::IsSortedNoDuplicates() { } -bool TransitionArray::IsSortedNoDuplicates() { +bool TransitionArray::IsSortedNoDuplicates(int valid_entries) { + ASSERT(valid_entries == -1); String* current_key = NULL; uint32_t current = 0; for (int i = 0; i < number_of_transitions(); i++) { @@ -960,63 +1006,6 @@ bool TransitionArray::IsConsistentWithBackPointers(Map* current_map) { } -void JSFunctionResultCache::JSFunctionResultCacheVerify() { - JSFunction::cast(get(kFactoryIndex))->Verify(); - - int size = Smi::cast(get(kCacheSizeIndex))->value(); - ASSERT(kEntriesIndex <= size); - ASSERT(size <= length()); - ASSERT_EQ(0, size % kEntrySize); - - int finger = Smi::cast(get(kFingerIndex))->value(); - ASSERT(kEntriesIndex <= finger); - ASSERT((finger < size) || (finger == kEntriesIndex && finger == size)); - ASSERT_EQ(0, finger % kEntrySize); - - if (FLAG_enable_slow_asserts) { - for (int i = kEntriesIndex; i < size; i++) { - ASSERT(!get(i)->IsTheHole()); - get(i)->Verify(); - } - for (int i = size; i < length(); i++) { - ASSERT(get(i)->IsTheHole()); - get(i)->Verify(); - } - } -} - - -void NormalizedMapCache::NormalizedMapCacheVerify() { - FixedArray::cast(this)->Verify(); - if (FLAG_enable_slow_asserts) { - for (int i = 0; i < length(); i++) { - Object* e = get(i); - if (e->IsMap()) { - Map::cast(e)->SharedMapVerify(); - } else { - ASSERT(e->IsUndefined()); - } - } - } -} - - -void Map::ZapTransitions() { - TransitionArray* transition_array = transitions(); - MemsetPointer(transition_array->data_start(), - GetHeap()->the_hole_value(), - transition_array->length()); -} - - -void Map::ZapPrototypeTransitions() { - FixedArray* proto_transitions = GetPrototypeTransitions(); - MemsetPointer(proto_transitions->data_start(), - GetHeap()->the_hole_value(), - proto_transitions->length()); -} - - #endif // DEBUG } } // namespace v8::internal diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 3b9bb0a137..077e782905 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -134,6 +134,14 @@ bool Object::IsFixedArrayBase() { } +// External objects are not extensible, so the map check is enough. +bool Object::IsExternal() { + return Object::IsHeapObject() && + HeapObject::cast(this)->map() == + HeapObject::cast(this)->GetHeap()->external_map(); +} + + bool Object::IsInstanceOf(FunctionTemplateInfo* expected) { // There is a constraint on the object; check. if (!this->IsJSObject()) return false; @@ -221,10 +229,10 @@ bool Object::IsSeqString() { } -bool Object::IsSeqAsciiString() { +bool Object::IsSeqOneByteString() { if (!IsString()) return false; return StringShape(String::cast(this)).IsSequential() && - String::cast(this)->IsAsciiRepresentation(); + String::cast(this)->IsOneByteRepresentation(); } @@ -244,7 +252,7 @@ bool Object::IsExternalString() { bool Object::IsExternalAsciiString() { if (!IsString()) return false; return StringShape(String::cast(this)).IsExternal() && - String::cast(this)->IsAsciiRepresentation(); + String::cast(this)->IsOneByteRepresentation(); } @@ -287,9 +295,9 @@ bool StringShape::IsSymbol() { } -bool String::IsAsciiRepresentation() { +bool String::IsOneByteRepresentation() { uint32_t type = map()->instance_type(); - return (type & kStringEncodingMask) == kAsciiStringTag; + return (type & kStringEncodingMask) == kOneByteStringTag; } @@ -299,18 +307,18 @@ bool String::IsTwoByteRepresentation() { } -bool String::IsAsciiRepresentationUnderneath() { +bool String::IsOneByteRepresentationUnderneath() { uint32_t type = map()->instance_type(); STATIC_ASSERT(kIsIndirectStringTag != 0); STATIC_ASSERT((kIsIndirectStringMask & kStringEncodingMask) == 0); ASSERT(IsFlat()); switch (type & (kIsIndirectStringMask | kStringEncodingMask)) { - case kAsciiStringTag: + case kOneByteStringTag: return true; case kTwoByteStringTag: return false; default: // Cons or sliced string. Need to go deeper. - return GetUnderlying()->IsAsciiRepresentation(); + return GetUnderlying()->IsOneByteRepresentation(); } } @@ -321,7 +329,7 @@ bool String::IsTwoByteRepresentationUnderneath() { STATIC_ASSERT((kIsIndirectStringMask & kStringEncodingMask) == 0); ASSERT(IsFlat()); switch (type & (kIsIndirectStringMask | kStringEncodingMask)) { - case kAsciiStringTag: + case kOneByteStringTag: return false; case kTwoByteStringTag: return true; @@ -333,8 +341,7 @@ bool String::IsTwoByteRepresentationUnderneath() { bool String::HasOnlyAsciiChars() { uint32_t type = map()->instance_type(); - return (type & kStringEncodingMask) == kAsciiStringTag || - (type & kAsciiDataHintMask) == kAsciiDataHintTag; + return (type & kAsciiDataHintMask) == kAsciiDataHintTag; } @@ -382,9 +389,12 @@ uint32_t StringShape::full_representation_tag() { STATIC_CHECK((kStringRepresentationMask | kStringEncodingMask) == Internals::kFullStringRepresentationMask); +STATIC_CHECK(static_cast<uint32_t>(kStringEncodingMask) == + Internals::kStringEncodingMask); + bool StringShape::IsSequentialAscii() { - return full_representation_tag() == (kSeqStringTag | kAsciiStringTag); + return full_representation_tag() == (kSeqStringTag | kOneByteStringTag); } @@ -394,10 +404,16 @@ bool StringShape::IsSequentialTwoByte() { bool StringShape::IsExternalAscii() { - return full_representation_tag() == (kExternalStringTag | kAsciiStringTag); + return full_representation_tag() == (kExternalStringTag | kOneByteStringTag); } +STATIC_CHECK((kExternalStringTag | kOneByteStringTag) == + Internals::kExternalAsciiRepresentationTag); + +STATIC_CHECK(v8::String::ASCII_ENCODING == kOneByteStringTag); + + bool StringShape::IsExternalTwoByte() { return full_representation_tag() == (kExternalStringTag | kTwoByteStringTag); } @@ -406,6 +422,7 @@ bool StringShape::IsExternalTwoByte() { STATIC_CHECK((kExternalStringTag | kTwoByteStringTag) == Internals::kExternalTwoByteRepresentationTag); +STATIC_CHECK(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag); uc32 FlatStringReader::Get(int index) { ASSERT(0 <= index && index <= length_); @@ -650,8 +667,8 @@ bool Object::IsDictionary() { bool Object::IsSymbolTable() { - return IsHashTable() && this == - HeapObject::cast(this)->GetHeap()->raw_unchecked_symbol_table(); + return IsHashTable() && + this == HeapObject::cast(this)->GetHeap()->raw_unchecked_symbol_table(); } @@ -664,7 +681,7 @@ bool Object::IsJSFunctionResultCache() { % JSFunctionResultCache::kEntrySize != 0) { return false; } -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { reinterpret_cast<JSFunctionResultCache*>(this)-> JSFunctionResultCacheVerify(); @@ -679,7 +696,7 @@ bool Object::IsNormalizedMapCache() { if (FixedArray::cast(this)->length() != NormalizedMapCache::kEntries) { return false; } -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { reinterpret_cast<NormalizedMapCache*>(this)->NormalizedMapCacheVerify(); } @@ -708,6 +725,11 @@ bool Object::IsMapCache() { } +bool Object::IsObjectHashTable() { + return IsHashTable(); +} + + bool Object::IsPrimitive() { return IsOddball() || IsNumber() || IsString(); } @@ -1042,7 +1064,11 @@ Failure* Failure::Construct(Type type, intptr_t value) { uintptr_t info = (static_cast<uintptr_t>(value) << kFailureTypeTagSize) | type; ASSERT(((info << kFailureTagSize) >> kFailureTagSize) == info); - return reinterpret_cast<Failure*>((info << kFailureTagSize) | kFailureTag); + // Fill the unused bits with a pattern that's easy to recognize in crash + // dumps. + static const int kFailureMagicPattern = 0x0BAD0000; + return reinterpret_cast<Failure*>( + (info << kFailureTagSize) | kFailureTag | kFailureMagicPattern); } @@ -1100,13 +1126,13 @@ HeapObject* MapWord::ToForwardingAddress() { } -#ifdef DEBUG +#ifdef VERIFY_HEAP void HeapObject::VerifyObjectField(int offset) { VerifyPointer(READ_FIELD(this, offset)); } void HeapObject::VerifySmiField(int offset) { - ASSERT(READ_FIELD(this, offset)->IsSmi()); + CHECK(READ_FIELD(this, offset)->IsSmi()); } #endif @@ -1404,6 +1430,43 @@ MaybeObject* JSObject::ResetElements() { } +MaybeObject* JSObject::AddFastPropertyUsingMap(Map* map) { + ASSERT(this->map()->NumberOfOwnDescriptors() + 1 == + map->NumberOfOwnDescriptors()); + if (this->map()->unused_property_fields() == 0) { + int new_size = properties()->length() + map->unused_property_fields() + 1; + FixedArray* new_properties; + MaybeObject* maybe_properties = properties()->CopySize(new_size); + if (!maybe_properties->To(&new_properties)) return maybe_properties; + set_properties(new_properties); + } + set_map(map); + return this; +} + + +bool JSObject::TryTransitionToField(Handle<JSObject> object, + Handle<String> key) { + if (!object->map()->HasTransitionArray()) return false; + Handle<TransitionArray> transitions(object->map()->transitions()); + int transition = transitions->Search(*key); + if (transition == TransitionArray::kNotFound) return false; + PropertyDetails target_details = transitions->GetTargetDetails(transition); + if (target_details.type() != FIELD) return false; + if (target_details.attributes() != NONE) return false; + Handle<Map> target(transitions->GetTarget(transition)); + JSObject::AddFastPropertyUsingMap(object, target); + return true; +} + + +int JSObject::LastAddedFieldIndex() { + Map* map = this->map(); + int last_added = map->LastAdded(); + return map->instance_descriptors()->GetFieldIndex(last_added); +} + + ACCESSORS(Oddball, to_string, String, kToStringOffset) ACCESSORS(Oddball, to_number, Object, kToNumberOffset) @@ -1803,7 +1866,7 @@ void FixedArray::set(int index, void FixedArray::NoIncrementalWriteBarrierSet(FixedArray* array, int index, Object* value) { - ASSERT(array->map() != HEAP->raw_unchecked_fixed_cow_array_map()); + ASSERT(array->map() != HEAP->fixed_cow_array_map()); ASSERT(index >= 0 && index < array->length()); int offset = kHeaderSize + index * kPointerSize; WRITE_FIELD(array, offset, value); @@ -1817,7 +1880,7 @@ void FixedArray::NoIncrementalWriteBarrierSet(FixedArray* array, void FixedArray::NoWriteBarrierSet(FixedArray* array, int index, Object* value) { - ASSERT(array->map() != HEAP->raw_unchecked_fixed_cow_array_map()); + ASSERT(array->map() != HEAP->fixed_cow_array_map()); ASSERT(index >= 0 && index < array->length()); ASSERT(!HEAP->InNewSpace(value)); WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value); @@ -1884,6 +1947,11 @@ void FixedArray::set_null_unchecked(Heap* heap, int index) { } +double* FixedDoubleArray::data_start() { + return reinterpret_cast<double*>(FIELD_ADDR(this, kHeaderSize)); +} + + Object** FixedArray::data_start() { return HeapObject::RawField(this, kHeaderSize); } @@ -1896,11 +1964,17 @@ bool DescriptorArray::IsEmpty() { } +void DescriptorArray::SetNumberOfDescriptors(int number_of_descriptors) { + WRITE_FIELD( + this, kDescriptorLengthOffset, Smi::FromInt(number_of_descriptors)); +} + + // Perform a binary search in a fixed array. Low and high are entry indices. If // there are three entries in this array it should be called with low=0 and // high=2. -template<typename T> -int BinarySearch(T* array, String* name, int low, int high) { +template<SearchMode search_mode, typename T> +int BinarySearch(T* array, String* name, int low, int high, int valid_entries) { uint32_t hash = name->Hash(); int limit = high; @@ -1922,60 +1996,83 @@ int BinarySearch(T* array, String* name, int low, int high) { int sort_index = array->GetSortedKeyIndex(low); String* entry = array->GetKey(sort_index); if (entry->Hash() != hash) break; - if (entry->Equals(name)) return sort_index; + if (entry->Equals(name)) { + if (search_mode == ALL_ENTRIES || sort_index < valid_entries) { + return sort_index; + } + return T::kNotFound; + } } return T::kNotFound; } + // Perform a linear search in this fixed array. len is the number of entry // indices that are valid. -template<typename T> -int LinearSearch(T* array, String* name, int len) { +template<SearchMode search_mode, typename T> +int LinearSearch(T* array, String* name, int len, int valid_entries) { uint32_t hash = name->Hash(); - for (int number = 0; number < len; number++) { - int sorted_index = array->GetSortedKeyIndex(number); - String* entry = array->GetKey(sorted_index); - uint32_t current_hash = entry->Hash(); - if (current_hash > hash) break; - if (current_hash == hash && entry->Equals(name)) return sorted_index; + if (search_mode == ALL_ENTRIES) { + for (int number = 0; number < len; number++) { + int sorted_index = array->GetSortedKeyIndex(number); + String* entry = array->GetKey(sorted_index); + uint32_t current_hash = entry->Hash(); + if (current_hash > hash) break; + if (current_hash == hash && entry->Equals(name)) return sorted_index; + } + } else { + ASSERT(len >= valid_entries); + for (int number = 0; number < valid_entries; number++) { + String* entry = array->GetKey(number); + uint32_t current_hash = entry->Hash(); + if (current_hash == hash && entry->Equals(name)) return number; + } } return T::kNotFound; } -template<typename T> -int Search(T* array, String* name) { - SLOW_ASSERT(array->IsSortedNoDuplicates()); +template<SearchMode search_mode, typename T> +int Search(T* array, String* name, int valid_entries) { + if (search_mode == VALID_ENTRIES) { + SLOW_ASSERT(array->IsSortedNoDuplicates(valid_entries)); + } else { + SLOW_ASSERT(array->IsSortedNoDuplicates()); + } int nof = array->number_of_entries(); if (nof == 0) return T::kNotFound; // Fast case: do linear search for small arrays. const int kMaxElementsForLinearSearch = 8; - if (nof < kMaxElementsForLinearSearch) { - return LinearSearch(array, name, nof); + if ((search_mode == ALL_ENTRIES && + nof <= kMaxElementsForLinearSearch) || + (search_mode == VALID_ENTRIES && + valid_entries <= (kMaxElementsForLinearSearch * 3))) { + return LinearSearch<search_mode>(array, name, nof, valid_entries); } // Slow case: perform binary search. - return BinarySearch(array, name, 0, nof - 1); + return BinarySearch<search_mode>(array, name, 0, nof - 1, valid_entries); } -int DescriptorArray::Search(String* name) { - return internal::Search(this, name); +int DescriptorArray::Search(String* name, int valid_descriptors) { + return internal::Search<VALID_ENTRIES>(this, name, valid_descriptors); } -int DescriptorArray::SearchWithCache(String* name) { - if (number_of_descriptors() == 0) return kNotFound; +int DescriptorArray::SearchWithCache(String* name, Map* map) { + int number_of_own_descriptors = map->NumberOfOwnDescriptors(); + if (number_of_own_descriptors == 0) return kNotFound; DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache(); - int number = cache->Lookup(this, name); + int number = cache->Lookup(map, name); if (number == DescriptorLookupCache::kAbsent) { - number = Search(name); - cache->Update(this, name, number); + number = Search(name, number_of_own_descriptors); + cache->Update(map, name, number); } return number; @@ -1986,7 +2083,7 @@ void Map::LookupDescriptor(JSObject* holder, String* name, LookupResult* result) { DescriptorArray* descriptors = this->instance_descriptors(); - int number = descriptors->SearchWithCache(name); + int number = descriptors->SearchWithCache(name, this); if (number == DescriptorArray::kNotFound) return result->NotFound(); result->DescriptorResult(holder, descriptors->GetDetails(number), number); } @@ -2030,10 +2127,9 @@ String* DescriptorArray::GetSortedKey(int descriptor_number) { } -void DescriptorArray::SetSortedKey(int pointer, int descriptor_number) { - int details_index = ToDetailsIndex(pointer); - PropertyDetails details = PropertyDetails(Smi::cast(get(details_index))); - set_unchecked(details_index, details.set_pointer(descriptor_number).AsSmi()); +void DescriptorArray::SetSortedKey(int descriptor_index, int pointer) { + PropertyDetails details = GetDetails(descriptor_index); + set(ToDetailsIndex(descriptor_index), details.set_pointer(pointer).AsSmi()); } @@ -2114,24 +2210,59 @@ void DescriptorArray::Set(int descriptor_number, } +void DescriptorArray::Set(int descriptor_number, Descriptor* desc) { + // Range check. + ASSERT(descriptor_number < number_of_descriptors()); + ASSERT(desc->GetDetails().descriptor_index() <= + number_of_descriptors()); + ASSERT(desc->GetDetails().descriptor_index() > 0); + + set(ToKeyIndex(descriptor_number), desc->GetKey()); + set(ToValueIndex(descriptor_number), desc->GetValue()); + set(ToDetailsIndex(descriptor_number), desc->GetDetails().AsSmi()); +} + + void DescriptorArray::Append(Descriptor* desc, - const WhitenessWitness& witness, - int number_of_set_descriptors) { - int enumeration_index = number_of_set_descriptors + 1; + const WhitenessWitness& witness) { + int descriptor_number = number_of_descriptors(); + int enumeration_index = descriptor_number + 1; + SetNumberOfDescriptors(descriptor_number + 1); + desc->SetEnumerationIndex(enumeration_index); + Set(descriptor_number, desc, witness); + + uint32_t hash = desc->GetKey()->Hash(); + + int insertion; + + for (insertion = descriptor_number; insertion > 0; --insertion) { + String* key = GetSortedKey(insertion - 1); + if (key->Hash() <= hash) break; + SetSortedKey(insertion, GetSortedKeyIndex(insertion - 1)); + } + + SetSortedKey(insertion, descriptor_number); +} + + +void DescriptorArray::Append(Descriptor* desc) { + int descriptor_number = number_of_descriptors(); + int enumeration_index = descriptor_number + 1; + SetNumberOfDescriptors(descriptor_number + 1); desc->SetEnumerationIndex(enumeration_index); - Set(number_of_set_descriptors, desc, witness); + Set(descriptor_number, desc); uint32_t hash = desc->GetKey()->Hash(); int insertion; - for (insertion = number_of_set_descriptors; insertion > 0; --insertion) { + for (insertion = descriptor_number; insertion > 0; --insertion) { String* key = GetSortedKey(insertion - 1); if (key->Hash() <= hash) break; SetSortedKey(insertion, GetSortedKeyIndex(insertion - 1)); } - SetSortedKey(insertion, number_of_set_descriptors); + SetSortedKey(insertion, descriptor_number); } @@ -2142,14 +2273,14 @@ void DescriptorArray::SwapSortedKeys(int first, int second) { } -FixedArray::WhitenessWitness::WhitenessWitness(FixedArray* array) +DescriptorArray::WhitenessWitness::WhitenessWitness(FixedArray* array) : marking_(array->GetHeap()->incremental_marking()) { marking_->EnterNoMarkingScope(); ASSERT(Marking::Color(array) == Marking::WHITE_OBJECT); } -FixedArray::WhitenessWitness::~WhitenessWitness() { +DescriptorArray::WhitenessWitness::~WhitenessWitness() { marking_->LeaveNoMarkingScope(); } @@ -2180,7 +2311,8 @@ int HashTable<Shape, Key>::FindEntry(Isolate* isolate, Key key) { // EnsureCapacity will guarantee the hash table is never full. while (true) { Object* element = KeyAt(entry); - // Empty entry. + // Empty entry. Uses raw unchecked accessors because it is called by the + // symbol table during bootstrapping. if (element == isolate->heap()->raw_unchecked_undefined_value()) break; if (element != isolate->heap()->raw_unchecked_the_hole_value() && Shape::IsMatch(key, element)) return entry; @@ -2230,7 +2362,7 @@ CAST_ACCESSOR(PolymorphicCodeCacheHashTable) CAST_ACCESSOR(MapCache) CAST_ACCESSOR(String) CAST_ACCESSOR(SeqString) -CAST_ACCESSOR(SeqAsciiString) +CAST_ACCESSOR(SeqOneByteString) CAST_ACCESSOR(SeqTwoByteString) CAST_ACCESSOR(SlicedString) CAST_ACCESSOR(ConsString) @@ -2334,18 +2466,18 @@ String* String::TryFlattenGetString(PretenureFlag pretenure) { uint16_t String::Get(int index) { ASSERT(index >= 0 && index < length()); switch (StringShape(this).full_representation_tag()) { - case kSeqStringTag | kAsciiStringTag: - return SeqAsciiString::cast(this)->SeqAsciiStringGet(index); + case kSeqStringTag | kOneByteStringTag: + return SeqOneByteString::cast(this)->SeqOneByteStringGet(index); case kSeqStringTag | kTwoByteStringTag: return SeqTwoByteString::cast(this)->SeqTwoByteStringGet(index); - case kConsStringTag | kAsciiStringTag: + case kConsStringTag | kOneByteStringTag: case kConsStringTag | kTwoByteStringTag: return ConsString::cast(this)->ConsStringGet(index); - case kExternalStringTag | kAsciiStringTag: + case kExternalStringTag | kOneByteStringTag: return ExternalAsciiString::cast(this)->ExternalAsciiStringGet(index); case kExternalStringTag | kTwoByteStringTag: return ExternalTwoByteString::cast(this)->ExternalTwoByteStringGet(index); - case kSlicedStringTag | kAsciiStringTag: + case kSlicedStringTag | kOneByteStringTag: case kSlicedStringTag | kTwoByteStringTag: return SlicedString::cast(this)->SlicedStringGet(index); default: @@ -2361,8 +2493,8 @@ void String::Set(int index, uint16_t value) { ASSERT(index >= 0 && index < length()); ASSERT(StringShape(this).IsSequential()); - return this->IsAsciiRepresentation() - ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value) + return this->IsOneByteRepresentation() + ? SeqOneByteString::cast(this)->SeqOneByteStringSet(index, value) : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value); } @@ -2384,25 +2516,96 @@ String* String::GetUnderlying() { } -uint16_t SeqAsciiString::SeqAsciiStringGet(int index) { +template<class Visitor, class ConsOp> +void String::Visit( + String* string, + unsigned offset, + Visitor& visitor, + ConsOp& consOp, + int32_t type, + unsigned length) { + + ASSERT(length == static_cast<unsigned>(string->length())); + ASSERT(offset <= length); + + unsigned sliceOffset = offset; + while (true) { + ASSERT(type == string->map()->instance_type()); + + switch (type & (kStringRepresentationMask | kStringEncodingMask)) { + case kSeqStringTag | kOneByteStringTag: + visitor.VisitOneByteString( + reinterpret_cast<const uint8_t*>( + SeqOneByteString::cast(string)->GetChars()) + sliceOffset, + length - offset); + return; + + case kSeqStringTag | kTwoByteStringTag: + visitor.VisitTwoByteString( + reinterpret_cast<const uint16_t*>( + SeqTwoByteString::cast(string)->GetChars()) + sliceOffset, + length - offset); + return; + + case kExternalStringTag | kOneByteStringTag: + visitor.VisitOneByteString( + reinterpret_cast<const uint8_t*>( + ExternalAsciiString::cast(string)->GetChars()) + sliceOffset, + length - offset); + return; + + case kExternalStringTag | kTwoByteStringTag: + visitor.VisitTwoByteString( + reinterpret_cast<const uint16_t*>( + ExternalTwoByteString::cast(string)->GetChars()) + sliceOffset, + length - offset); + return; + + case kSlicedStringTag | kOneByteStringTag: + case kSlicedStringTag | kTwoByteStringTag: { + SlicedString* slicedString = SlicedString::cast(string); + sliceOffset += slicedString->offset(); + string = slicedString->parent(); + type = string->map()->instance_type(); + continue; + } + + case kConsStringTag | kOneByteStringTag: + case kConsStringTag | kTwoByteStringTag: + string = consOp.Operate(ConsString::cast(string), &offset, &type, + &length); + if (string == NULL) return; + sliceOffset = offset; + ASSERT(length == static_cast<unsigned>(string->length())); + continue; + + default: + UNREACHABLE(); + return; + } + } +} + + +uint16_t SeqOneByteString::SeqOneByteStringGet(int index) { ASSERT(index >= 0 && index < length()); return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); } -void SeqAsciiString::SeqAsciiStringSet(int index, uint16_t value) { +void SeqOneByteString::SeqOneByteStringSet(int index, uint16_t value) { ASSERT(index >= 0 && index < length() && value <= kMaxAsciiCharCode); WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, static_cast<byte>(value)); } -Address SeqAsciiString::GetCharsAddress() { +Address SeqOneByteString::GetCharsAddress() { return FIELD_ADDR(this, kHeaderSize); } -char* SeqAsciiString::GetChars() { +char* SeqOneByteString::GetChars() { return reinterpret_cast<char*>(GetCharsAddress()); } @@ -2434,7 +2637,7 @@ int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) { } -int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) { +int SeqOneByteString::SeqOneByteStringSize(InstanceType instance_type) { return SizeFor(length()); } @@ -2562,6 +2765,146 @@ const uint16_t* ExternalTwoByteString::ExternalTwoByteStringGetData( } +unsigned ConsStringIteratorOp::OffsetForDepth(unsigned depth) { + return depth & kDepthMask; +} + + +uint32_t ConsStringIteratorOp::MaskForDepth(unsigned depth) { + return 1 << OffsetForDepth(depth); +} + + +void ConsStringIteratorOp::SetRightDescent() { + trace_ |= MaskForDepth(depth_ - 1); +} + + +void ConsStringIteratorOp::ClearRightDescent() { + trace_ &= ~MaskForDepth(depth_ - 1); +} + + +void ConsStringIteratorOp::PushLeft(ConsString* string) { + frames_[depth_++ & kDepthMask] = string; +} + + +void ConsStringIteratorOp::PushRight(ConsString* string, int32_t type) { + // Inplace update + frames_[(depth_-1) & kDepthMask] = string; + if (depth_ != 1) return; + // Optimization: can replace root in this case. + root_ = string; + root_type_ = type; + root_length_ = string->length(); +} + + +void ConsStringIteratorOp::AdjustMaximumDepth() { + if (depth_ > maximum_depth_) maximum_depth_ = depth_; +} + + +void ConsStringIteratorOp::Pop() { + ASSERT(depth_ > 0); + ASSERT(depth_ <= maximum_depth_); + depth_--; +} + + +void ConsStringIteratorOp::Reset() { + consumed_ = 0; + ResetStack(); +} + + +bool ConsStringIteratorOp::HasMore() { + return depth_ != 0; +} + + +void ConsStringIteratorOp::ResetStack() { + depth_ = 0; + maximum_depth_ = 0; +} + + +bool ConsStringIteratorOp::ContinueOperation(ContinueResponse* response) { + bool blewStack; + int32_t type; + String* string = NextLeaf(&blewStack, &type); + // String found. + if (string != NULL) { + unsigned length = string->length(); + consumed_ += length; + response->string_ = string; + response->offset_ = 0; + response->length_ = length; + response->type_ = type; + return true; + } + // Traversal complete. + if (!blewStack) return false; + // Restart search. + ResetStack(); + response->string_ = root_; + response->offset_ = consumed_; + response->length_ = root_length_; + response->type_ = root_type_; + return true; +} + + +uint16_t StringCharacterStream::GetNext() { + ASSERT(buffer8_ != NULL); + return is_one_byte_ ? *buffer8_++ : *buffer16_++; +} + + +StringCharacterStream::StringCharacterStream( + String* string, unsigned offset, ConsStringIteratorOp* op) + : is_one_byte_(true), + buffer8_(NULL), + end_(NULL), + op_(op) { + op->Reset(); + String::Visit(string, + offset, *this, *op, string->map()->instance_type(), string->length()); +} + + +bool StringCharacterStream::HasMore() { + if (buffer8_ != end_) return true; + if (!op_->HasMore()) return false; + ConsStringIteratorOp::ContinueResponse response; + // This has been checked above + if (!op_->ContinueOperation(&response)) { + UNREACHABLE(); + return false; + } + String::Visit(response.string_, + response.offset_, *this, *op_, response.type_, response.length_); + return true; +} + + +void StringCharacterStream::VisitOneByteString( + const uint8_t* chars, unsigned length) { + is_one_byte_ = true; + buffer8_ = chars; + end_ = chars + length; +} + + +void StringCharacterStream::VisitTwoByteString( + const uint16_t* chars, unsigned length) { + is_one_byte_ = false; + buffer16_ = chars; + end_ = reinterpret_cast<const uint8_t*>(chars + length); +} + + void JSFunctionResultCache::MakeZeroSize() { set_finger_index(kEntriesIndex); set_size(kEntriesIndex); @@ -2852,8 +3195,8 @@ int HeapObject::SizeFromMap(Map* map) { return FixedArray::BodyDescriptor::SizeOf(map, this); } if (instance_type == ASCII_STRING_TYPE) { - return SeqAsciiString::SizeFor( - reinterpret_cast<SeqAsciiString*>(this)->length()); + return SeqOneByteString::SizeFor( + reinterpret_cast<SeqOneByteString*>(this)->length()); } if (instance_type == BYTE_ARRAY_TYPE) { return reinterpret_cast<ByteArray*>(this)->ByteArraySize(); @@ -3030,6 +3373,26 @@ Code::Flags Code::flags() { } +void Map::set_owns_descriptors(bool is_shared) { + set_bit_field3(OwnsDescriptors::update(bit_field3(), is_shared)); +} + + +bool Map::owns_descriptors() { + return OwnsDescriptors::decode(bit_field3()); +} + + +void Map::set_is_observed(bool is_observed) { + set_bit_field3(IsObserved::update(bit_field3(), is_observed)); +} + + +bool Map::is_observed() { + return IsObserved::decode(bit_field3()); +} + + void Code::set_flags(Code::Flags flags) { STATIC_ASSERT(Code::NUMBER_OF_KINDS <= KindField::kMax + 1); // Make sure that all call stubs have an arguments count. @@ -3272,66 +3635,6 @@ void Code::set_unary_op_type(byte value) { } -byte Code::binary_op_type() { - ASSERT(is_binary_op_stub()); - return BinaryOpTypeField::decode( - READ_UINT32_FIELD(this, kKindSpecificFlags1Offset)); -} - - -void Code::set_binary_op_type(byte value) { - ASSERT(is_binary_op_stub()); - int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset); - int updated = BinaryOpTypeField::update(previous, value); - WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated); -} - - -byte Code::binary_op_result_type() { - ASSERT(is_binary_op_stub()); - return BinaryOpResultTypeField::decode( - READ_UINT32_FIELD(this, kKindSpecificFlags1Offset)); -} - - -void Code::set_binary_op_result_type(byte value) { - ASSERT(is_binary_op_stub()); - int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset); - int updated = BinaryOpResultTypeField::update(previous, value); - WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated); -} - - -byte Code::compare_state() { - ASSERT(is_compare_ic_stub()); - return CompareStateField::decode( - READ_UINT32_FIELD(this, kKindSpecificFlags1Offset)); -} - - -void Code::set_compare_state(byte value) { - ASSERT(is_compare_ic_stub()); - int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset); - int updated = CompareStateField::update(previous, value); - WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated); -} - - -byte Code::compare_operation() { - ASSERT(is_compare_ic_stub()); - return CompareOperationField::decode( - READ_UINT32_FIELD(this, kKindSpecificFlags1Offset)); -} - - -void Code::set_compare_operation(byte value) { - ASSERT(is_compare_ic_stub()); - int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset); - int updated = CompareOperationField::update(previous, value); - WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated); -} - - byte Code::to_boolean_state() { ASSERT(is_to_boolean_ic_stub()); return ToBooleanStateField::decode( @@ -3465,41 +3768,30 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) { } -DescriptorArray* Map::instance_descriptors() { - if (!HasTransitionArray()) return GetHeap()->empty_descriptor_array(); - return transitions()->descriptors(); -} - - // If the descriptor is using the empty transition array, install a new empty // transition array that will have place for an element transition. static MaybeObject* EnsureHasTransitionArray(Map* map) { - if (map->HasTransitionArray()) return map; - TransitionArray* transitions; - MaybeObject* maybe_transitions = TransitionArray::Allocate(0); - if (!maybe_transitions->To(&transitions)) return maybe_transitions; + MaybeObject* maybe_transitions; + if (!map->HasTransitionArray()) { + maybe_transitions = TransitionArray::Allocate(0); + if (!maybe_transitions->To(&transitions)) return maybe_transitions; + transitions->set_back_pointer_storage(map->GetBackPointer()); + } else if (!map->transitions()->IsFullTransitionArray()) { + maybe_transitions = map->transitions()->ExtendToFullTransitionArray(); + if (!maybe_transitions->To(&transitions)) return maybe_transitions; + } else { + return map; + } map->set_transitions(transitions); return transitions; } -MaybeObject* Map::SetDescriptors(DescriptorArray* value, - WriteBarrierMode mode) { - ASSERT(!is_shared()); - MaybeObject* maybe_failure = EnsureHasTransitionArray(this); - if (maybe_failure->IsFailure()) return maybe_failure; - - transitions()->set_descriptors(value, mode); - return this; -} - - -MaybeObject* Map::InitializeDescriptors(DescriptorArray* descriptors) { -#ifdef DEBUG +void Map::InitializeDescriptors(DescriptorArray* descriptors) { int len = descriptors->number_of_descriptors(); +#ifdef DEBUG ASSERT(len <= DescriptorArray::kMaxNumberOfDescriptors); - SLOW_ASSERT(descriptors->IsSortedNoDuplicates()); bool used_indices[DescriptorArray::kMaxNumberOfDescriptors]; for (int i = 0; i < len; ++i) used_indices[i] = false; @@ -3515,28 +3807,22 @@ MaybeObject* Map::InitializeDescriptors(DescriptorArray* descriptors) { } #endif - MaybeObject* maybe_failure = SetDescriptors(descriptors); - if (maybe_failure->IsFailure()) return maybe_failure; - - SetNumberOfOwnDescriptors(descriptors->number_of_descriptors()); - - return this; + set_instance_descriptors(descriptors); + SetNumberOfOwnDescriptors(len); } +ACCESSORS(Map, instance_descriptors, DescriptorArray, kDescriptorsOffset) SMI_ACCESSORS(Map, bit_field3, kBitField3Offset) void Map::ClearTransitions(Heap* heap, WriteBarrierMode mode) { Object* back_pointer = GetBackPointer(); -#ifdef DEBUG - Object* object = READ_FIELD(this, kTransitionsOrBackPointerOffset); - if (object->IsTransitionArray()) { + + if (Heap::ShouldZapGarbage() && HasTransitionArray()) { ZapTransitions(); - } else { - ASSERT(object->IsMap() || object->IsUndefined()); } -#endif + WRITE_FIELD(this, kTransitionsOrBackPointerOffset, back_pointer); CONDITIONAL_WRITE_BARRIER( heap, this, kTransitionsOrBackPointerOffset, back_pointer, mode); @@ -3547,8 +3833,8 @@ void Map::AppendDescriptor(Descriptor* desc, const DescriptorArray::WhitenessWitness& witness) { DescriptorArray* descriptors = instance_descriptors(); int number_of_own_descriptors = NumberOfOwnDescriptors(); - ASSERT(number_of_own_descriptors < descriptors->number_of_descriptors()); - descriptors->Append(desc, witness, number_of_own_descriptors); + ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors); + descriptors->Append(desc, witness); SetNumberOfOwnDescriptors(number_of_own_descriptors + 1); } @@ -3588,9 +3874,11 @@ bool Map::CanHaveMoreTransitions() { } -MaybeObject* Map::AddTransition(String* key, Map* target) { +MaybeObject* Map::AddTransition(String* key, + Map* target, + SimpleTransitionFlag flag) { if (HasTransitionArray()) return transitions()->CopyInsert(key, target); - return TransitionArray::NewWith(key, target); + return TransitionArray::NewWith(flag, key, target, GetBackPointer()); } @@ -3599,6 +3887,11 @@ void Map::SetTransition(int transition_index, Map* target) { } +Map* Map::GetTransition(int transition_index) { + return transitions()->GetTarget(transition_index); +} + + MaybeObject* Map::set_elements_transition_map(Map* transitioned_map) { MaybeObject* allow_elements = EnsureHasTransitionArray(this); if (allow_elements->IsFailure()) return allow_elements; @@ -3644,14 +3937,11 @@ TransitionArray* Map::transitions() { void Map::set_transitions(TransitionArray* transition_array, WriteBarrierMode mode) { - transition_array->set_descriptors(instance_descriptors()); - transition_array->set_back_pointer_storage(GetBackPointer()); -#ifdef DEBUG - if (HasTransitionArray()) { - ASSERT(transitions() != transition_array); + // In release mode, only run this code if verify_heap is on. + if (Heap::ShouldZapGarbage() && HasTransitionArray()) { + CHECK(transitions() != transition_array); ZapTransitions(); } -#endif WRITE_FIELD(this, kTransitionsOrBackPointerOffset, transition_array); CONDITIONAL_WRITE_BARRIER( @@ -4037,7 +4327,7 @@ bool Script::HasValidSource() { if (!src->IsString()) return true; String* src_str = String::cast(src); if (!StringShape(src_str).IsExternal()) return true; - if (src_str->IsAsciiRepresentation()) { + if (src_str->IsOneByteRepresentation()) { return ExternalAsciiString::cast(src)->resource() != NULL; } else if (src_str->IsTwoByteRepresentation()) { return ExternalTwoByteString::cast(src)->resource() != NULL; @@ -4305,42 +4595,6 @@ void JSFunction::set_initial_map(Map* value) { } -MaybeObject* JSFunction::set_initial_map_and_cache_transitions( - Map* initial_map) { - Context* native_context = context()->native_context(); - Object* array_function = - native_context->get(Context::ARRAY_FUNCTION_INDEX); - if (array_function->IsJSFunction() && - this == JSFunction::cast(array_function)) { - // Replace all of the cached initial array maps in the native context with - // the appropriate transitioned elements kind maps. - Heap* heap = GetHeap(); - MaybeObject* maybe_maps = - heap->AllocateFixedArrayWithHoles(kElementsKindCount); - FixedArray* maps; - if (!maybe_maps->To(&maps)) return maybe_maps; - - Map* current_map = initial_map; - ElementsKind kind = current_map->elements_kind(); - ASSERT(kind == GetInitialFastElementsKind()); - maps->set(kind, current_map); - for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1; - i < kFastElementsKindCount; ++i) { - Map* new_map; - ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i); - MaybeObject* maybe_new_map = - current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - maps->set(next_kind, new_map); - current_map = new_map; - } - native_context->set_js_array_maps(maps); - } - set_initial_map(initial_map); - return this; -} - - bool JSFunction::has_initial_map() { return prototype_or_initial_map()->IsMap(); } @@ -4532,13 +4786,49 @@ JSMessageObject* JSMessageObject::cast(Object* obj) { INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset) +INT_ACCESSORS(Code, prologue_offset, kPrologueOffset) ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset) ACCESSORS(Code, handler_table, FixedArray, kHandlerTableOffset) ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset) -ACCESSORS(Code, type_feedback_info, Object, kTypeFeedbackInfoOffset) + + +// Type feedback slot: type_feedback_info for FUNCTIONs, stub_info for STUBs. +void Code::InitializeTypeFeedbackInfoNoWriteBarrier(Object* value) { + WRITE_FIELD(this, kTypeFeedbackInfoOffset, value); +} + + +Object* Code::type_feedback_info() { + ASSERT(kind() == FUNCTION); + return Object::cast(READ_FIELD(this, kTypeFeedbackInfoOffset)); +} + + +void Code::set_type_feedback_info(Object* value, WriteBarrierMode mode) { + ASSERT(kind() == FUNCTION); + WRITE_FIELD(this, kTypeFeedbackInfoOffset, value); + CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kTypeFeedbackInfoOffset, + value, mode); +} + + +int Code::stub_info() { + ASSERT(kind() == COMPARE_IC || kind() == BINARY_OP_IC); + Object* value = READ_FIELD(this, kTypeFeedbackInfoOffset); + return Smi::cast(value)->value(); +} + + +void Code::set_stub_info(int value) { + ASSERT(kind() == COMPARE_IC || kind() == BINARY_OP_IC); + WRITE_FIELD(this, kTypeFeedbackInfoOffset, Smi::FromInt(value)); +} + + ACCESSORS(Code, gc_metadata, Object, kGCMetadataOffset) INT_ACCESSORS(Code, ic_age, kICAgeOffset) + byte* Code::instruction_start() { return FIELD_ADDR(this, kHeaderSize); } @@ -4666,6 +4956,13 @@ void JSRegExp::SetDataAtUnchecked(int index, Object* value, Heap* heap) { } +void JSRegExp::ResetLastIndex() { + InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, + Smi::FromInt(0), + SKIP_WRITE_BARRIER); // It's a Smi. +} + + ElementsKind JSObject::GetElementsKind() { ElementsKind kind = map()->elements_kind(); #if DEBUG @@ -4719,6 +5016,11 @@ bool JSObject::HasFastHoleyElements() { } +bool JSObject::HasFastElements() { + return IsFastElementsKind(GetElementsKind()); +} + + bool JSObject::HasDictionaryElements() { return GetElementsKind() == DICTIONARY_ELEMENTS; } @@ -4825,8 +5127,7 @@ StringHasher::StringHasher(int length, uint32_t seed) raw_running_hash_(seed), array_index_(0), is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize), - is_first_char_(true), - is_valid_(true) { + is_first_char_(true) { ASSERT(FLAG_randomize_hashes || raw_running_hash_ == 0); } @@ -4836,6 +5137,25 @@ bool StringHasher::has_trivial_hash() { } +uint32_t StringHasher::AddCharacterCore(uint32_t running_hash, uint32_t c) { + running_hash += c; + running_hash += (running_hash << 10); + running_hash ^= (running_hash >> 6); + return running_hash; +} + + +uint32_t StringHasher::GetHashCore(uint32_t running_hash) { + running_hash += (running_hash << 3); + running_hash ^= (running_hash >> 11); + running_hash += (running_hash << 15); + if ((running_hash & String::kHashBitMask) == 0) { + return kZeroHash; + } + return running_hash; +} + + void StringHasher::AddCharacter(uint32_t c) { if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) { AddSurrogatePair(c); // Not inlined. @@ -4843,9 +5163,7 @@ void StringHasher::AddCharacter(uint32_t c) { } // Use the Jenkins one-at-a-time hash function to update the hash // for the given character. - raw_running_hash_ += c; - raw_running_hash_ += (raw_running_hash_ << 10); - raw_running_hash_ ^= (raw_running_hash_ >> 6); + raw_running_hash_ = AddCharacterCore(raw_running_hash_, c); // Incremental array index computation. if (is_array_index_) { if (c < '0' || c > '9') { @@ -4875,23 +5193,14 @@ void StringHasher::AddCharacterNoIndex(uint32_t c) { AddSurrogatePairNoIndex(c); // Not inlined. return; } - raw_running_hash_ += c; - raw_running_hash_ += (raw_running_hash_ << 10); - raw_running_hash_ ^= (raw_running_hash_ >> 6); + raw_running_hash_ = AddCharacterCore(raw_running_hash_, c); } uint32_t StringHasher::GetHash() { // Get the calculated raw hash value and do some more bit ops to distribute // the hash further. Ensure that we never return zero as the hash value. - uint32_t result = raw_running_hash_; - result += (result << 3); - result ^= (result >> 11); - result += (result << 15); - if ((result & String::kHashBitMask) == 0) { - result = 27; - } - return result; + return GetHashCore(raw_running_hash_); } @@ -4947,9 +5256,23 @@ bool JSReceiver::HasLocalProperty(String* name) { PropertyAttributes JSReceiver::GetPropertyAttribute(String* key) { + uint32_t index; + if (IsJSObject() && key->AsArrayIndex(&index)) { + return GetElementAttribute(index); + } return GetPropertyAttributeWithReceiver(this, key); } + +PropertyAttributes JSReceiver::GetElementAttribute(uint32_t index) { + if (IsJSProxy()) { + return JSProxy::cast(this)->GetElementAttributeWithHandler(this, index); + } + return JSObject::cast(this)->GetElementAttributeWithReceiver( + this, index, true); +} + + // TODO(504): this may be useful in other places too where JSGlobalProxy // is used. Object* JSObject::BypassGlobalProxy() { @@ -4974,7 +5297,26 @@ bool JSReceiver::HasElement(uint32_t index) { if (IsJSProxy()) { return JSProxy::cast(this)->HasElementWithHandler(index); } - return JSObject::cast(this)->HasElementWithReceiver(this, index); + return JSObject::cast(this)->GetElementAttributeWithReceiver( + this, index, true) != ABSENT; +} + + +bool JSReceiver::HasLocalElement(uint32_t index) { + if (IsJSProxy()) { + return JSProxy::cast(this)->HasElementWithHandler(index); + } + return JSObject::cast(this)->GetElementAttributeWithReceiver( + this, index, false) != ABSENT; +} + + +PropertyAttributes JSReceiver::GetLocalElementAttribute(uint32_t index) { + if (IsJSProxy()) { + return JSProxy::cast(this)->GetElementAttributeWithHandler(this, index); + } + return JSObject::cast(this)->GetElementAttributeWithReceiver( + this, index, false); } @@ -5138,8 +5480,8 @@ void Map::ClearCodeCache(Heap* heap) { // Please note this function is used during marking: // - MarkCompactCollector::MarkUnmarkedObject // - IncrementalMarking::Step - ASSERT(!heap->InNewSpace(heap->raw_unchecked_empty_fixed_array())); - WRITE_FIELD(this, kCodeCacheOffset, heap->raw_unchecked_empty_fixed_array()); + ASSERT(!heap->InNewSpace(heap->empty_fixed_array())); + WRITE_FIELD(this, kCodeCacheOffset, heap->empty_fixed_array()); } @@ -5233,7 +5575,7 @@ Handle<Object> TypeFeedbackCells::MegamorphicSentinel(Isolate* isolate) { Object* TypeFeedbackCells::RawUninitializedSentinel(Heap* heap) { - return heap->raw_unchecked_the_hole_value(); + return heap->the_hole_value(); } diff --git a/deps/v8/src/objects-printer.cc b/deps/v8/src/objects-printer.cc index 1ba0bb0d09..9a1a58ef82 100644 --- a/deps/v8/src/objects-printer.cc +++ b/deps/v8/src/objects-printer.cc @@ -254,7 +254,7 @@ void ExternalDoubleArray::ExternalDoubleArrayPrint(FILE* out) { void JSObject::PrintProperties(FILE* out) { if (HasFastProperties()) { DescriptorArray* descs = map()->instance_descriptors(); - for (int i = 0; i < descs->number_of_descriptors(); i++) { + for (int i = 0; i < map()->NumberOfOwnDescriptors(); i++) { PrintF(out, " "); descs->GetKey(i)->StringPrint(out); PrintF(out, ": "); @@ -384,7 +384,7 @@ void JSObject::PrintElements(FILE* out) { case EXTERNAL_DOUBLE_ELEMENTS: { ExternalDoubleArray* p = ExternalDoubleArray::cast(elements()); for (int i = 0; i < p->length(); i++) { - PrintF(out, " %d: %f\n", i, p->get_scalar(i)); + PrintF(out, " %d: %f\n", i, p->get_scalar(i)); } break; } @@ -393,11 +393,16 @@ void JSObject::PrintElements(FILE* out) { break; case NON_STRICT_ARGUMENTS_ELEMENTS: { FixedArray* p = FixedArray::cast(elements()); + PrintF(out, " parameter map:"); for (int i = 2; i < p->length(); i++) { - PrintF(out, " %d: ", i); + PrintF(out, " %d:", i - 2); p->get(i)->ShortPrint(out); - PrintF(out, "\n"); } + PrintF(out, "\n context: "); + p->get(0)->ShortPrint(out); + PrintF(out, "\n arguments: "); + p->get(1)->ShortPrint(out); + PrintF(out, "\n"); break; } } @@ -562,7 +567,11 @@ void Map::MapPrint(FILE* out) { if (is_access_check_needed()) { PrintF(out, " - access_check_needed\n"); } - PrintF(out, " - instance descriptors: "); + PrintF(out, " - back pointer: "); + GetBackPointer()->ShortPrint(out); + PrintF(out, "\n - instance descriptors %i #%i: ", + owns_descriptors(), + NumberOfOwnDescriptors()); instance_descriptors()->ShortPrint(out); if (HasTransitionArray()) { PrintF(out, "\n - transitions: "); diff --git a/deps/v8/src/objects-visiting-inl.h b/deps/v8/src/objects-visiting-inl.h index 856ae06b7b..4a9dab5caa 100644 --- a/deps/v8/src/objects-visiting-inl.h +++ b/deps/v8/src/objects-visiting-inl.h @@ -68,7 +68,7 @@ void StaticNewSpaceVisitor<StaticVisitor>::Initialize() { SharedFunctionInfo::BodyDescriptor, int>::Visit); - table_.Register(kVisitSeqAsciiString, &VisitSeqAsciiString); + table_.Register(kVisitSeqOneByteString, &VisitSeqOneByteString); table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString); @@ -110,10 +110,7 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() { SlicedString::BodyDescriptor, void>::Visit); - table_.Register(kVisitFixedArray, - &FlexibleBodyVisitor<StaticVisitor, - FixedArray::BodyDescriptor, - void>::Visit); + table_.Register(kVisitFixedArray, &FixedArrayVisitor::Visit); table_.Register(kVisitFixedDoubleArray, &DataObjectVisitor::Visit); @@ -123,7 +120,7 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() { table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit); - table_.Register(kVisitSeqAsciiString, &DataObjectVisitor::Visit); + table_.Register(kVisitSeqOneByteString, &DataObjectVisitor::Visit); table_.Register(kVisitSeqTwoByteString, &DataObjectVisitor::Visit); @@ -134,16 +131,13 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() { Oddball::BodyDescriptor, void>::Visit); - table_.Register(kVisitMap, - &FixedBodyVisitor<StaticVisitor, - Map::BodyDescriptor, - void>::Visit); + table_.Register(kVisitMap, &VisitMap); - table_.Register(kVisitCode, &StaticVisitor::VisitCode); + table_.Register(kVisitCode, &VisitCode); - // Registration for kVisitSharedFunctionInfo is done by StaticVisitor. + table_.Register(kVisitSharedFunctionInfo, &VisitSharedFunctionInfo); - // Registration for kVisitJSFunction is done by StaticVisitor. + table_.Register(kVisitJSFunction, &VisitJSFunction); // Registration for kVisitJSRegExp is done by StaticVisitor. @@ -217,9 +211,8 @@ void StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget( // when they might be keeping a Context alive, or when the heap is about // to be serialized. if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub() - && (target->ic_state() == MEGAMORPHIC || Serializer::enabled() || - heap->isolate()->context_exit_happened() || - target->ic_age() != heap->global_ic_age())) { + && (target->ic_state() == MEGAMORPHIC || heap->flush_monomorphic_ics() || + Serializer::enabled() || target->ic_age() != heap->global_ic_age())) { IC::Clear(rinfo->pc()); target = Code::GetCodeFromTargetAddress(rinfo->target_address()); } @@ -229,6 +222,17 @@ void StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget( template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::VisitCodeAgeSequence( + Heap* heap, RelocInfo* rinfo) { + ASSERT(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); + Code* target = rinfo->code_age_stub(); + ASSERT(target != NULL); + heap->mark_compact_collector()->RecordRelocSlot(rinfo, target); + StaticVisitor::MarkObject(heap, target); +} + + +template<typename StaticVisitor> void StaticMarkingVisitor<StaticVisitor>::VisitNativeContext( Map* map, HeapObject* object) { FixedBodyVisitor<StaticVisitor, @@ -247,6 +251,32 @@ void StaticMarkingVisitor<StaticVisitor>::VisitNativeContext( template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::VisitMap( + Map* map, HeapObject* object) { + Heap* heap = map->GetHeap(); + Map* map_object = Map::cast(object); + + // Clears the cache of ICs related to this map. + if (FLAG_cleanup_code_caches_at_gc) { + map_object->ClearCodeCache(heap); + } + + // When map collection is enabled we have to mark through map's + // transitions and back pointers in a special way to make these links + // weak. Only maps for subclasses of JSReceiver can have transitions. + STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); + if (FLAG_collect_maps && + map_object->instance_type() >= FIRST_JS_RECEIVER_TYPE) { + MarkMapContents(heap, map_object); + } else { + StaticVisitor::VisitPointers(heap, + HeapObject::RawField(object, Map::kPointerFieldsBeginOffset), + HeapObject::RawField(object, Map::kPointerFieldsEndOffset)); + } +} + + +template<typename StaticVisitor> void StaticMarkingVisitor<StaticVisitor>::VisitCode( Map* map, HeapObject* object) { Heap* heap = map->GetHeap(); @@ -254,11 +284,79 @@ void StaticMarkingVisitor<StaticVisitor>::VisitCode( if (FLAG_cleanup_code_caches_at_gc) { code->ClearTypeFeedbackCells(heap); } + if (FLAG_age_code && !Serializer::enabled()) { + code->MakeOlder(heap->mark_compact_collector()->marking_parity()); + } code->CodeIterateBody<StaticVisitor>(heap); } template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfo( + Map* map, HeapObject* object) { + Heap* heap = map->GetHeap(); + SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); + if (shared->ic_age() != heap->global_ic_age()) { + shared->ResetForNewContext(heap->global_ic_age()); + } + MarkCompactCollector* collector = heap->mark_compact_collector(); + if (collector->is_code_flushing_enabled()) { + if (IsFlushable(heap, shared)) { + // This function's code looks flushable. But we have to postpone + // the decision until we see all functions that point to the same + // SharedFunctionInfo because some of them might be optimized. + // That would also make the non-optimized version of the code + // non-flushable, because it is required for bailing out from + // optimized code. + collector->code_flusher()->AddCandidate(shared); + // Treat the reference to the code object weakly. + VisitSharedFunctionInfoWeakCode(heap, object); + return; + } + } + VisitSharedFunctionInfoStrongCode(heap, object); +} + + +template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::VisitJSFunction( + Map* map, HeapObject* object) { + Heap* heap = map->GetHeap(); + JSFunction* function = JSFunction::cast(object); + MarkCompactCollector* collector = heap->mark_compact_collector(); + if (collector->is_code_flushing_enabled()) { + if (IsFlushable(heap, function)) { + // This function's code looks flushable. But we have to postpone + // the decision until we see all functions that point to the same + // SharedFunctionInfo because some of them might be optimized. + // That would also make the non-optimized version of the code + // non-flushable, because it is required for bailing out from + // optimized code. + collector->code_flusher()->AddCandidate(function); + // Visit shared function info immediately to avoid double checking + // of its flushability later. This is just an optimization because + // the shared function info would eventually be visited. + SharedFunctionInfo* shared = function->unchecked_shared(); + if (StaticVisitor::MarkObjectWithoutPush(heap, shared)) { + StaticVisitor::MarkObject(heap, shared->map()); + VisitSharedFunctionInfoWeakCode(heap, shared); + } + // Treat the reference to the code object weakly. + VisitJSFunctionWeakCode(heap, object); + return; + } else { + // Visit all unoptimized code objects to prevent flushing them. + StaticVisitor::MarkObject(heap, function->shared()->code()); + if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) { + MarkInlinedFunctionsCode(heap, function->code()); + } + } + } + VisitJSFunctionStrongCode(heap, object); +} + + +template<typename StaticVisitor> void StaticMarkingVisitor<StaticVisitor>::VisitJSRegExp( Map* map, HeapObject* object) { int last_property_offset = @@ -269,6 +367,260 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSRegExp( } +template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::MarkMapContents( + Heap* heap, Map* map) { + // Make sure that the back pointer stored either in the map itself or + // inside its transitions array is marked. Skip recording the back + // pointer slot since map space is not compacted. + StaticVisitor::MarkObject(heap, HeapObject::cast(map->GetBackPointer())); + + // Treat pointers in the transitions array as weak and also mark that + // array to prevent visiting it later. Skip recording the transition + // array slot, since it will be implicitly recorded when the pointer + // fields of this map are visited. + TransitionArray* transitions = map->unchecked_transition_array(); + if (transitions->IsTransitionArray()) { + MarkTransitionArray(heap, transitions); + } else { + // Already marked by marking map->GetBackPointer() above. + ASSERT(transitions->IsMap() || transitions->IsUndefined()); + } + + // Mark the pointer fields of the Map. Since the transitions array has + // been marked already, it is fine that one of these fields contains a + // pointer to it. + StaticVisitor::VisitPointers(heap, + HeapObject::RawField(map, Map::kPointerFieldsBeginOffset), + HeapObject::RawField(map, Map::kPointerFieldsEndOffset)); +} + + +template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::MarkTransitionArray( + Heap* heap, TransitionArray* transitions) { + if (!StaticVisitor::MarkObjectWithoutPush(heap, transitions)) return; + + // Simple transitions do not have keys nor prototype transitions. + if (transitions->IsSimpleTransition()) return; + + if (transitions->HasPrototypeTransitions()) { + // Mark prototype transitions array but do not push it onto marking + // stack, this will make references from it weak. We will clean dead + // prototype transitions in ClearNonLiveTransitions. + Object** slot = transitions->GetPrototypeTransitionsSlot(); + HeapObject* obj = HeapObject::cast(*slot); + heap->mark_compact_collector()->RecordSlot(slot, slot, obj); + StaticVisitor::MarkObjectWithoutPush(heap, obj); + } + + for (int i = 0; i < transitions->number_of_transitions(); ++i) { + StaticVisitor::VisitPointer(heap, transitions->GetKeySlot(i)); + } +} + + +template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::MarkInlinedFunctionsCode( + Heap* heap, Code* code) { + // For optimized functions we should retain both non-optimized version + // of its code and non-optimized version of all inlined functions. + // This is required to support bailing out from inlined code. + DeoptimizationInputData* data = + DeoptimizationInputData::cast(code->deoptimization_data()); + FixedArray* literals = data->LiteralArray(); + for (int i = 0, count = data->InlinedFunctionCount()->value(); + i < count; + i++) { + JSFunction* inlined = JSFunction::cast(literals->get(i)); + StaticVisitor::MarkObject(heap, inlined->shared()->code()); + } +} + + +inline static bool IsValidNonBuiltinContext(Object* context) { + return context->IsContext() && + !Context::cast(context)->global_object()->IsJSBuiltinsObject(); +} + + +inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { + Object* undefined = heap->undefined_value(); + return (info->script() != undefined) && + (reinterpret_cast<Script*>(info->script())->source() != undefined); +} + + +template<typename StaticVisitor> +bool StaticMarkingVisitor<StaticVisitor>::IsFlushable( + Heap* heap, JSFunction* function) { + SharedFunctionInfo* shared_info = function->unchecked_shared(); + + // Code is either on stack, in compilation cache or referenced + // by optimized version of function. + MarkBit code_mark = Marking::MarkBitFrom(function->code()); + if (code_mark.Get()) { + if (!FLAG_age_code) { + if (!Marking::MarkBitFrom(shared_info).Get()) { + shared_info->set_code_age(0); + } + } + return false; + } + + // The function must have a valid context and not be a builtin. + if (!IsValidNonBuiltinContext(function->unchecked_context())) { + return false; + } + + // We do not (yet) flush code for optimized functions. + if (function->code() != shared_info->code()) { + return false; + } + + // Check age of optimized code. + if (FLAG_age_code && !function->code()->IsOld()) { + return false; + } + + return IsFlushable(heap, shared_info); +} + + +template<typename StaticVisitor> +bool StaticMarkingVisitor<StaticVisitor>::IsFlushable( + Heap* heap, SharedFunctionInfo* shared_info) { + // Code is either on stack, in compilation cache or referenced + // by optimized version of function. + MarkBit code_mark = Marking::MarkBitFrom(shared_info->code()); + if (code_mark.Get()) { + return false; + } + + // The function must be compiled and have the source code available, + // to be able to recompile it in case we need the function again. + if (!(shared_info->is_compiled() && HasSourceCode(heap, shared_info))) { + return false; + } + + // We never flush code for API functions. + Object* function_data = shared_info->function_data(); + if (function_data->IsFunctionTemplateInfo()) { + return false; + } + + // Only flush code for functions. + if (shared_info->code()->kind() != Code::FUNCTION) { + return false; + } + + // Function must be lazy compilable. + if (!shared_info->allows_lazy_compilation()) { + return false; + } + + // If this is a full script wrapped in a function we do no flush the code. + if (shared_info->is_toplevel()) { + return false; + } + + if (FLAG_age_code) { + return shared_info->code()->IsOld(); + } else { + // How many collections newly compiled code object will survive before being + // flushed. + static const int kCodeAgeThreshold = 5; + + // Age this shared function info. + if (shared_info->code_age() < kCodeAgeThreshold) { + shared_info->set_code_age(shared_info->code_age() + 1); + return false; + } + return true; + } +} + + +template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfoStrongCode( + Heap* heap, HeapObject* object) { + StaticVisitor::BeforeVisitingSharedFunctionInfo(object); + Object** start_slot = + HeapObject::RawField(object, + SharedFunctionInfo::BodyDescriptor::kStartOffset); + Object** end_slot = + HeapObject::RawField(object, + SharedFunctionInfo::BodyDescriptor::kEndOffset); + StaticVisitor::VisitPointers(heap, start_slot, end_slot); +} + + +template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfoWeakCode( + Heap* heap, HeapObject* object) { + StaticVisitor::BeforeVisitingSharedFunctionInfo(object); + Object** name_slot = + HeapObject::RawField(object, SharedFunctionInfo::kNameOffset); + StaticVisitor::VisitPointer(heap, name_slot); + + // Skip visiting kCodeOffset as it is treated weakly here. + STATIC_ASSERT(SharedFunctionInfo::kNameOffset + kPointerSize == + SharedFunctionInfo::kCodeOffset); + STATIC_ASSERT(SharedFunctionInfo::kCodeOffset + kPointerSize == + SharedFunctionInfo::kOptimizedCodeMapOffset); + + Object** start_slot = + HeapObject::RawField(object, + SharedFunctionInfo::kOptimizedCodeMapOffset); + Object** end_slot = + HeapObject::RawField(object, + SharedFunctionInfo::BodyDescriptor::kEndOffset); + StaticVisitor::VisitPointers(heap, start_slot, end_slot); +} + + +template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionStrongCode( + Heap* heap, HeapObject* object) { + Object** start_slot = + HeapObject::RawField(object, JSFunction::kPropertiesOffset); + Object** end_slot = + HeapObject::RawField(object, JSFunction::kCodeEntryOffset); + StaticVisitor::VisitPointers(heap, start_slot, end_slot); + + VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset); + STATIC_ASSERT(JSFunction::kCodeEntryOffset + kPointerSize == + JSFunction::kPrototypeOrInitialMapOffset); + + start_slot = + HeapObject::RawField(object, JSFunction::kPrototypeOrInitialMapOffset); + end_slot = + HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset); + StaticVisitor::VisitPointers(heap, start_slot, end_slot); +} + + +template<typename StaticVisitor> +void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionWeakCode( + Heap* heap, HeapObject* object) { + Object** start_slot = + HeapObject::RawField(object, JSFunction::kPropertiesOffset); + Object** end_slot = + HeapObject::RawField(object, JSFunction::kCodeEntryOffset); + StaticVisitor::VisitPointers(heap, start_slot, end_slot); + + // Skip visiting kCodeEntryOffset as it is treated weakly here. + STATIC_ASSERT(JSFunction::kCodeEntryOffset + kPointerSize == + JSFunction::kPrototypeOrInitialMapOffset); + + start_slot = + HeapObject::RawField(object, JSFunction::kPrototypeOrInitialMapOffset); + end_slot = + HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset); + StaticVisitor::VisitPointers(heap, start_slot, end_slot); +} + + void Code::CodeIterateBody(ObjectVisitor* v) { int mode_mask = RelocInfo::kCodeTargetMask | RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | diff --git a/deps/v8/src/objects-visiting.cc b/deps/v8/src/objects-visiting.cc index a2dc43e247..7082e59f35 100644 --- a/deps/v8/src/objects-visiting.cc +++ b/deps/v8/src/objects-visiting.cc @@ -45,8 +45,8 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( if (instance_type < FIRST_NONSTRING_TYPE) { switch (instance_type & kStringRepresentationMask) { case kSeqStringTag: - if ((instance_type & kStringEncodingMask) == kAsciiStringTag) { - return kVisitSeqAsciiString; + if ((instance_type & kStringEncodingMask) == kOneByteStringTag) { + return kVisitSeqOneByteString; } else { return kVisitSeqTwoByteString; } diff --git a/deps/v8/src/objects-visiting.h b/deps/v8/src/objects-visiting.h index 76a0f74e86..29f3cbc598 100644 --- a/deps/v8/src/objects-visiting.h +++ b/deps/v8/src/objects-visiting.h @@ -47,7 +47,7 @@ namespace internal { class StaticVisitorBase : public AllStatic { public: #define VISITOR_ID_LIST(V) \ - V(SeqAsciiString) \ + V(SeqOneByteString) \ V(SeqTwoByteString) \ V(ShortcutCandidate) \ V(ByteArray) \ @@ -318,9 +318,9 @@ class StaticNewSpaceVisitor : public StaticVisitorBase { return JSObjectVisitor::Visit(map, object); } - static inline int VisitSeqAsciiString(Map* map, HeapObject* object) { - return SeqAsciiString::cast(object)-> - SeqAsciiStringSize(map->instance_type()); + static inline int VisitSeqOneByteString(Map* map, HeapObject* object) { + return SeqOneByteString::cast(object)-> + SeqOneByteStringSize(map->instance_type()); } static inline int VisitSeqTwoByteString(Map* map, HeapObject* object) { @@ -391,15 +391,38 @@ class StaticMarkingVisitor : public StaticVisitorBase { static inline void VisitGlobalPropertyCell(Heap* heap, RelocInfo* rinfo); static inline void VisitDebugTarget(Heap* heap, RelocInfo* rinfo); static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo); + static inline void VisitCodeAgeSequence(Heap* heap, RelocInfo* rinfo); static inline void VisitExternalReference(RelocInfo* rinfo) { } static inline void VisitRuntimeEntry(RelocInfo* rinfo) { } // TODO(mstarzinger): This should be made protected once refactoring is done. - static inline void VisitNativeContext(Map* map, HeapObject* object); + // Mark non-optimize code for functions inlined into the given optimized + // code. This will prevent it from being flushed. + static void MarkInlinedFunctionsCode(Heap* heap, Code* code); protected: + static inline void VisitMap(Map* map, HeapObject* object); static inline void VisitCode(Map* map, HeapObject* object); + static inline void VisitSharedFunctionInfo(Map* map, HeapObject* object); + static inline void VisitJSFunction(Map* map, HeapObject* object); static inline void VisitJSRegExp(Map* map, HeapObject* object); + static inline void VisitNativeContext(Map* map, HeapObject* object); + + // Mark pointers in a Map and its TransitionArray together, possibly + // treating transitions or back pointers weak. + static void MarkMapContents(Heap* heap, Map* map); + static void MarkTransitionArray(Heap* heap, TransitionArray* transitions); + + // Code flushing support. + static inline bool IsFlushable(Heap* heap, JSFunction* function); + static inline bool IsFlushable(Heap* heap, SharedFunctionInfo* shared_info); + + // Helpers used by code flushing support that visit pointer fields and treat + // references to code objects either strongly or weakly. + static void VisitSharedFunctionInfoStrongCode(Heap* heap, HeapObject* object); + static void VisitSharedFunctionInfoWeakCode(Heap* heap, HeapObject* object); + static void VisitJSFunctionStrongCode(Heap* heap, HeapObject* object); + static void VisitJSFunctionWeakCode(Heap* heap, HeapObject* object); class DataObjectVisitor { public: @@ -412,6 +435,10 @@ class StaticMarkingVisitor : public StaticVisitorBase { }; typedef FlexibleBodyVisitor<StaticVisitor, + FixedArray::BodyDescriptor, + void> FixedArrayVisitor; + + typedef FlexibleBodyVisitor<StaticVisitor, JSObject::BodyDescriptor, void> JSObjectVisitor; diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 254cd26f57..fcc2efad31 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -27,6 +27,7 @@ #include "v8.h" +#include "accessors.h" #include "api.h" #include "arguments.h" #include "bootstrapper.h" @@ -247,6 +248,18 @@ MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw, } +Handle<Object> Object::GetProperty(Handle<Object> object, Handle<String> name) { + // TODO(rossberg): The index test should not be here but in the GetProperty + // method (or somewhere else entirely). Needs more global clean-up. + uint32_t index; + if (name->AsArrayIndex(&index)) return GetElement(object, index); + Isolate* isolate = object->IsHeapObject() + ? Handle<HeapObject>::cast(object)->GetIsolate() + : Isolate::Current(); + CALL_HEAP_FUNCTION(isolate, object->GetProperty(*name), Object); +} + + Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) { Isolate* isolate = object->IsHeapObject() ? Handle<HeapObject>::cast(object)->GetIsolate() @@ -641,7 +654,8 @@ MaybeObject* Object::GetProperty(Object* receiver, ASSERT(!value->IsTheHole() || result->IsReadOnly()); return value->IsTheHole() ? heap->undefined_value() : value; case FIELD: - value = result->holder()->FastPropertyAt(result->GetFieldIndex()); + value = result->holder()->FastPropertyAt( + result->GetFieldIndex().field_index()); ASSERT(!value->IsTheHole() || result->IsReadOnly()); return value->IsTheHole() ? heap->undefined_value() : value; case CONSTANT_FUNCTION: @@ -881,14 +895,15 @@ MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) { int len = length(); Object* object; String* result; - if (IsAsciiRepresentation()) { - { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure); + if (IsOneByteRepresentation()) { + { MaybeObject* maybe_object = + heap->AllocateRawOneByteString(len, tenure); if (!maybe_object->ToObject(&object)) return maybe_object; } result = String::cast(object); String* first = cs->first(); int first_length = first->length(); - char* dest = SeqAsciiString::cast(result)->GetChars(); + char* dest = SeqOneByteString::cast(result)->GetChars(); WriteToFlat(first, dest, 0, first_length); String* second = cs->second(); WriteToFlat(second, @@ -941,7 +956,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) { if (size < ExternalString::kShortSize) { return false; } - bool is_ascii = this->IsAsciiRepresentation(); + bool is_ascii = this->IsOneByteRepresentation(); bool is_symbol = this->IsSymbol(); // Morph the object to an external string by adjusting the map and @@ -1118,6 +1133,10 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) { } break; } + case JS_MODULE_TYPE: { + accumulator->Add("<JS Module>"); + break; + } // All other JSObjects are rather similar to each other (JSObject, // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue). default: { @@ -1340,7 +1359,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size, SlicedString::BodyDescriptor::IterateBody(this, v); break; case kExternalStringTag: - if ((type & kStringEncodingMask) == kAsciiStringTag) { + if ((type & kStringEncodingMask) == kOneByteStringTag) { reinterpret_cast<ExternalAsciiString*>(this)-> ExternalAsciiStringIterateBody(v); } else { @@ -1539,8 +1558,9 @@ MaybeObject* JSObject::AddFastProperty(String* name, PropertyAttributes attributes, StoreFromKeyed store_mode) { ASSERT(!IsJSGlobalProxy()); - ASSERT(map()->instance_descriptors()->Search(name) == - DescriptorArray::kNotFound); + ASSERT(DescriptorArray::kNotFound == + map()->instance_descriptors()->Search( + name, map()->NumberOfOwnDescriptors())); // Normalize the object if the name is an actual string (not the // hidden symbols) and is not a real identifier. @@ -1676,39 +1696,88 @@ MaybeObject* JSObject::AddProperty(String* name, ASSERT(!IsJSGlobalProxy()); Map* map_of_this = map(); Heap* heap = GetHeap(); + Isolate* isolate = heap->isolate(); + MaybeObject* result; if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK && !map_of_this->is_extensible()) { if (strict_mode == kNonStrictMode) { return value; } else { Handle<Object> args[1] = {Handle<String>(name)}; - return heap->isolate()->Throw( + return isolate->Throw( *FACTORY->NewTypeError("object_not_extensible", HandleVector(args, 1))); } } + if (HasFastProperties()) { // Ensure the descriptor array does not get too big. - if (map_of_this->instance_descriptors()->number_of_descriptors() < + if (map_of_this->NumberOfOwnDescriptors() < DescriptorArray::kMaxNumberOfDescriptors) { if (value->IsJSFunction()) { - return AddConstantFunctionProperty(name, - JSFunction::cast(value), - attributes); + result = AddConstantFunctionProperty(name, + JSFunction::cast(value), + attributes); } else { - return AddFastProperty(name, value, attributes, store_mode); + result = AddFastProperty(name, value, attributes, store_mode); } } else { // Normalize the object to prevent very large instance descriptors. // This eliminates unwanted N^2 allocation and lookup behavior. Object* obj; - { MaybeObject* maybe_obj = - NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } + MaybeObject* maybe = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); + if (!maybe->To(&obj)) return maybe; + result = AddSlowProperty(name, value, attributes); } + } else { + result = AddSlowProperty(name, value, attributes); } - return AddSlowProperty(name, value, attributes); + + Handle<Object> hresult; + if (!result->ToHandle(&hresult, isolate)) return result; + + if (FLAG_harmony_observation && map()->is_observed()) { + EnqueueChangeRecord(handle(this, isolate), + "new", + handle(name, isolate), + handle(heap->the_hole_value(), isolate)); + } + + return *hresult; +} + + +void JSObject::EnqueueChangeRecord(Handle<JSObject> object, + const char* type_str, + Handle<String> name, + Handle<Object> old_value) { + Isolate* isolate = object->GetIsolate(); + HandleScope scope; + Handle<String> type = isolate->factory()->LookupAsciiSymbol(type_str); + if (object->IsJSGlobalObject()) { + object = handle(JSGlobalObject::cast(*object)->global_receiver(), isolate); + } + Handle<Object> args[] = { type, object, name, old_value }; + bool threw; + Execution::Call(Handle<JSFunction>(isolate->observers_notify_change()), + Handle<Object>(isolate->heap()->undefined_value()), + old_value->IsTheHole() ? 3 : 4, args, + &threw); + ASSERT(!threw); +} + + +void JSObject::DeliverChangeRecords(Isolate* isolate) { + ASSERT(isolate->observer_delivery_pending()); + bool threw = false; + Execution::Call( + isolate->observers_deliver_changes(), + isolate->factory()->undefined_value(), + 0, + NULL, + &threw); + ASSERT(!threw); + isolate->set_observer_delivery_pending(false); } @@ -1760,6 +1829,7 @@ MaybeObject* JSObject::ConvertTransitionToMapTransition( Object* new_value, PropertyAttributes attributes) { Map* old_map = map(); + Map* old_target = old_map->GetTransition(transition_index); Object* result; MaybeObject* maybe_result = @@ -1770,13 +1840,35 @@ MaybeObject* JSObject::ConvertTransitionToMapTransition( // This method should only be used to convert existing transitions. Objects // with the map of "new Object()" cannot have transitions in the first place. - ASSERT(map() != GetIsolate()->empty_object_map()); + Map* new_map = map(); + ASSERT(new_map != GetIsolate()->empty_object_map()); // TODO(verwaest): From here on we lose existing map transitions, causing // invalid back pointers. This will change once we can store multiple // transitions with the same key. - old_map->SetTransition(transition_index, map()); - map()->SetBackPointer(old_map); + + bool owned_descriptors = old_map->owns_descriptors(); + if (owned_descriptors || + old_target->instance_descriptors() == old_map->instance_descriptors()) { + // Since the conversion above generated a new fast map with an additional + // property which can be shared as well, install this descriptor pointer + // along the entire chain of smaller maps. + Map* map; + DescriptorArray* new_descriptors = new_map->instance_descriptors(); + DescriptorArray* old_descriptors = old_map->instance_descriptors(); + for (Object* current = old_map; + !current->IsUndefined(); + current = map->GetBackPointer()) { + map = Map::cast(current); + if (map->instance_descriptors() != old_descriptors) break; + map->SetEnumLength(Map::kInvalidEnumCache); + map->set_instance_descriptors(new_descriptors); + } + old_map->set_owns_descriptors(false); + } + + old_map->SetTransition(transition_index, new_map); + new_map->SetBackPointer(old_map); return result; } @@ -1883,7 +1975,7 @@ MaybeObject* JSReceiver::SetProperty(String* name, StrictModeFlag strict_mode, JSReceiver::StoreFromKeyed store_mode) { LookupResult result(GetIsolate()); - LocalLookup(name, &result); + LocalLookup(name, &result, true); if (!result.IsFound()) { map()->LookupTransition(JSObject::cast(this), name, &result); } @@ -2100,11 +2192,13 @@ enum RightTrimMode { FROM_GC, FROM_MUTATOR }; static void ZapEndOfFixedArray(Address new_end, int to_trim) { // If we are doing a big trim in old space then we zap the space. Object** zap = reinterpret_cast<Object**>(new_end); + zap++; // Header of filler must be at least one word so skip that. for (int i = 1; i < to_trim; i++) { *zap++ = Smi::FromInt(0); } } + template<RightTrimMode trim_mode> static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { ASSERT(elms->map() != HEAP->fixed_cow_array_map()); @@ -2117,12 +2211,8 @@ static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim); - if (trim_mode == FROM_GC) { -#ifdef DEBUG - ZapEndOfFixedArray(new_end, to_trim); -#endif - } else { - ZapEndOfFixedArray(new_end, to_trim); + if (trim_mode != FROM_GC || Heap::ShouldZapGarbage()) { + ZapEndOfFixedArray(new_end, to_trim); } int size_delta = to_trim * kPointerSize; @@ -2145,13 +2235,31 @@ static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { } -void Map::CopyAppendCallbackDescriptors(Handle<Map> map, - Handle<Object> descriptors) { +void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { + Handle<DescriptorArray> descriptors(map->instance_descriptors()); + if (slack <= descriptors->NumberOfSlackDescriptors()) return; + int number_of_descriptors = descriptors->number_of_descriptors(); + Isolate* isolate = map->GetIsolate(); + Handle<DescriptorArray> new_descriptors = + isolate->factory()->NewDescriptorArray(number_of_descriptors, slack); + DescriptorArray::WhitenessWitness witness(*new_descriptors); + + for (int i = 0; i < number_of_descriptors; ++i) { + new_descriptors->CopyFrom(i, *descriptors, i, witness); + } + + map->set_instance_descriptors(*new_descriptors); +} + + +void Map::AppendCallbackDescriptors(Handle<Map> map, + Handle<Object> descriptors) { Isolate* isolate = map->GetIsolate(); Handle<DescriptorArray> array(map->instance_descriptors()); - v8::NeanderArray callbacks(descriptors); + NeanderArray callbacks(descriptors); int nof_callbacks = callbacks.length(); - int descriptor_count = array->number_of_descriptors(); + + ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks); // Ensure the keys are symbols before writing them into the instance // descriptor. Since it may cause a GC, it has to be done before we @@ -2164,23 +2272,7 @@ void Map::CopyAppendCallbackDescriptors(Handle<Map> map, entry->set_name(*key); } - Handle<DescriptorArray> result = - isolate->factory()->NewDescriptorArray(descriptor_count + nof_callbacks); - - // Ensure that marking will not progress and change color of objects. - DescriptorArray::WhitenessWitness witness(*result); - - // Copy the descriptors from the array. - if (0 < descriptor_count) { - for (int i = 0; i < descriptor_count; i++) { - result->CopyFrom(i, *array, i, witness); - } - } - - // After this point the GC is not allowed to run anymore until the map is in a - // consistent state again, i.e., all the descriptors are appended and the - // descriptor array is trimmed to the right size. - Map::SetDescriptors(map, result); + int nof = map->NumberOfOwnDescriptors(); // Fill in new callback descriptors. Process the callbacks from // back to front so that the last callback with a given name takes @@ -2189,26 +2281,14 @@ void Map::CopyAppendCallbackDescriptors(Handle<Map> map, AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); String* key = String::cast(entry->name()); // Check if a descriptor with this name already exists before writing. - if (LinearSearch(*result, key, map->NumberOfOwnDescriptors()) == - DescriptorArray::kNotFound) { + if (array->Search(key, nof) == DescriptorArray::kNotFound) { CallbacksDescriptor desc(key, entry, entry->property_attributes()); - map->AppendDescriptor(&desc, witness); + array->Append(&desc); + nof += 1; } } - int new_number_of_descriptors = map->NumberOfOwnDescriptors(); - // Reinstall the original descriptor array if no new elements were added. - if (new_number_of_descriptors == descriptor_count) { - Map::SetDescriptors(map, array); - return; - } - - // If duplicates were detected, trim the descriptor array to the right size. - int new_array_size = DescriptorArray::LengthFor(new_number_of_descriptors); - if (new_array_size < result->length()) { - RightTrimFixedArray<FROM_MUTATOR>( - isolate->heap(), *result, result->length() - new_array_size); - } + map->SetNumberOfOwnDescriptors(nof); } @@ -2381,7 +2461,7 @@ void JSObject::LocalLookupRealNamedProperty(String* name, // occur as fields. if (result->IsField() && result->IsReadOnly() && - FastPropertyAt(result->GetFieldIndex())->IsTheHole()) { + FastPropertyAt(result->GetFieldIndex().field_index())->IsTheHole()) { result->DisallowCaching(); } return; @@ -2721,12 +2801,14 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler( MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler( - JSReceiver* receiver, + JSReceiver* receiver_raw, uint32_t index) { Isolate* isolate = GetIsolate(); HandleScope scope(isolate); + Handle<JSProxy> proxy(this); + Handle<JSReceiver> receiver(receiver_raw); Handle<String> name = isolate->factory()->Uint32ToString(index); - return GetPropertyAttributeWithHandler(receiver, *name); + return proxy->GetPropertyAttributeWithHandler(*receiver, *name); } @@ -2782,13 +2864,22 @@ MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name, } -MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, +void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object, + Handle<Map> map) { + CALL_HEAP_FUNCTION_VOID( + object->GetIsolate(), + object->AddFastPropertyUsingMap(*map)); +} + + +MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, String* name_raw, Object* value_raw, PropertyAttributes attributes, StrictModeFlag strict_mode, StoreFromKeyed store_mode) { Heap* heap = GetHeap(); + Isolate* isolate = heap->isolate(); // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc; @@ -2807,9 +2898,9 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, // Check access rights if needed. if (IsAccessCheckNeeded()) { - if (!heap->isolate()->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { + if (!isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { return SetPropertyWithFailedAccessCheck( - result, name_raw, value_raw, true, strict_mode); + lookup, name_raw, value_raw, true, strict_mode); } } @@ -2818,66 +2909,78 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, if (proto->IsNull()) return value_raw; ASSERT(proto->IsJSGlobalObject()); return JSObject::cast(proto)->SetPropertyForResult( - result, name_raw, value_raw, attributes, strict_mode, store_mode); + lookup, name_raw, value_raw, attributes, strict_mode, store_mode); } // From this point on everything needs to be handlified, because // SetPropertyViaPrototypes might call back into JavaScript. - HandleScope scope(GetIsolate()); + HandleScope scope(isolate); Handle<JSObject> self(this); Handle<String> name(name_raw); - Handle<Object> value(value_raw); + Handle<Object> value(value_raw, isolate); - if (!result->IsProperty() && !self->IsJSContextExtensionObject()) { + if (!lookup->IsProperty() && !self->IsJSContextExtensionObject()) { bool done = false; MaybeObject* result_object = self->SetPropertyViaPrototypes( *name, *value, attributes, strict_mode, &done); if (done) return result_object; } - if (!result->IsFound()) { + if (!lookup->IsFound()) { // Neither properties nor transitions found. return self->AddProperty( *name, *value, attributes, strict_mode, store_mode); } - if (result->IsProperty() && result->IsReadOnly()) { + + if (lookup->IsProperty() && lookup->IsReadOnly()) { if (strict_mode == kStrictMode) { Handle<Object> args[] = { name, self }; - return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( + return isolate->Throw(*isolate->factory()->NewTypeError( "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); } else { return *value; } } + Handle<Object> old_value(heap->the_hole_value(), isolate); + if (FLAG_harmony_observation && map()->is_observed()) { + old_value = handle(lookup->GetLazyValue(), isolate); + } + // This is a real property that is not read-only, or it is a // transition or null descriptor and there are no setters in the prototypes. - switch (result->type()) { + MaybeObject* result = *value; + switch (lookup->type()) { case NORMAL: - return self->SetNormalizedProperty(result, *value); + result = self->SetNormalizedProperty(lookup, *value); + break; case FIELD: - return self->FastPropertyAtPut(result->GetFieldIndex(), *value); + result = self->FastPropertyAtPut( + lookup->GetFieldIndex().field_index(), *value); + break; case CONSTANT_FUNCTION: // Only replace the function if necessary. - if (*value == result->GetConstantFunction()) return *value; + if (*value == lookup->GetConstantFunction()) return *value; // Preserve the attributes of this existing property. - attributes = result->GetAttributes(); - return self->ConvertDescriptorToField(*name, *value, attributes); + attributes = lookup->GetAttributes(); + result = self->ConvertDescriptorToField(*name, *value, attributes); + break; case CALLBACKS: { - Object* callback_object = result->GetCallbackObject(); + Object* callback_object = lookup->GetCallbackObject(); return self->SetPropertyWithCallback(callback_object, *name, *value, - result->holder(), + lookup->holder(), strict_mode); } case INTERCEPTOR: - return self->SetPropertyWithInterceptor(*name, - *value, - attributes, - strict_mode); + result = self->SetPropertyWithInterceptor(*name, + *value, + attributes, + strict_mode); + break; case TRANSITION: { - Map* transition_map = result->GetTransitionTarget(); + Map* transition_map = lookup->GetTransitionTarget(); int descriptor = transition_map->LastAdded(); DescriptorArray* descriptors = transition_map->instance_descriptors(); @@ -2886,37 +2989,55 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, if (details.type() == FIELD) { if (attributes == details.attributes()) { int field_index = descriptors->GetFieldIndex(descriptor); - return self->AddFastPropertyUsingMap(transition_map, - *name, - *value, - field_index); + result = self->AddFastPropertyUsingMap(transition_map, + *name, + *value, + field_index); + } else { + result = self->ConvertDescriptorToField(*name, *value, attributes); } - return self->ConvertDescriptorToField(*name, *value, attributes); } else if (details.type() == CALLBACKS) { - return ConvertDescriptorToField(*name, *value, attributes); - } - - ASSERT(details.type() == CONSTANT_FUNCTION); - - Object* constant_function = descriptors->GetValue(descriptor); - // If the same constant function is being added we can simply - // transition to the target map. - if (constant_function == *value) { - self->set_map(transition_map); - return constant_function; + result = self->ConvertDescriptorToField(*name, *value, attributes); + } else { + ASSERT(details.type() == CONSTANT_FUNCTION); + + Object* constant_function = descriptors->GetValue(descriptor); + if (constant_function == *value) { + // If the same constant function is being added we can simply + // transition to the target map. + self->set_map(transition_map); + result = constant_function; + } else { + // Otherwise, replace with a map transition to a new map with a FIELD, + // even if the value is a constant function. + result = self->ConvertTransitionToMapTransition( + lookup->GetTransitionIndex(), *name, *value, attributes); + } } - // Otherwise, replace with a map transition to a new map with a FIELD, - // even if the value is a constant function. - return ConvertTransitionToMapTransition( - result->GetTransitionIndex(), *name, *value, attributes); + break; } case HANDLER: case NONEXISTENT: UNREACHABLE(); - return *value; } - UNREACHABLE(); // keep the compiler happy - return *value; + + Handle<Object> hresult; + if (!result->ToHandle(&hresult, isolate)) return result; + + if (FLAG_harmony_observation && map()->is_observed()) { + if (lookup->IsTransition()) { + EnqueueChangeRecord(self, "new", name, old_value); + } else { + LookupResult new_lookup(isolate); + self->LocalLookup(*name, &new_lookup, true); + ASSERT(!new_lookup.GetLazyValue()->IsTheHole()); + if (!new_lookup.GetLazyValue()->SameValue(*old_value)) { + EnqueueChangeRecord(self, "updated", name, old_value); + } + } + } + + return *hresult; } @@ -2942,22 +3063,22 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes( MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( - String* name, - Object* value, + String* name_raw, + Object* value_raw, PropertyAttributes attributes) { // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc; Isolate* isolate = GetIsolate(); - LookupResult result(isolate); - LocalLookup(name, &result); - if (!result.IsFound()) map()->LookupTransition(this, name, &result); + LookupResult lookup(isolate); + LocalLookup(name_raw, &lookup, true); + if (!lookup.IsFound()) map()->LookupTransition(this, name_raw, &lookup); // Check access rights if needed. if (IsAccessCheckNeeded()) { - if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { - return SetPropertyWithFailedAccessCheck(&result, - name, - value, + if (!isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { + return SetPropertyWithFailedAccessCheck(&lookup, + name_raw, + value_raw, false, kNonStrictMode); } @@ -2965,40 +3086,69 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); - if (proto->IsNull()) return value; + if (proto->IsNull()) return value_raw; ASSERT(proto->IsJSGlobalObject()); return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes( - name, - value, + name_raw, + value_raw, attributes); } // Check for accessor in prototype chain removed here in clone. - if (!result.IsFound()) { + if (!lookup.IsFound()) { // Neither properties nor transitions found. - return AddProperty(name, value, attributes, kNonStrictMode); + return AddProperty(name_raw, value_raw, attributes, kNonStrictMode); + } + + // From this point on everything needs to be handlified. + HandleScope scope(isolate); + Handle<JSObject> self(this); + Handle<String> name(name_raw); + Handle<Object> value(value_raw, isolate); + + Handle<Object> old_value(isolate->heap()->the_hole_value(), isolate); + PropertyAttributes old_attributes = ABSENT; + bool is_observed = FLAG_harmony_observation && self->map()->is_observed(); + if (is_observed) { + // Function prototypes are stored specially + if (self->IsJSFunction() && + JSFunction::cast(*self)->should_have_prototype() && + name->Equals(isolate->heap()->prototype_symbol())) { + MaybeObject* maybe = Accessors::FunctionGetPrototype(*self, NULL); + if (!maybe->ToHandle(&old_value, isolate)) return maybe; + } else { + old_value = handle(lookup.GetLazyValue(), isolate); + } + old_attributes = lookup.GetAttributes(); } // Check of IsReadOnly removed from here in clone. - switch (result.type()) { + MaybeObject* result = *value; + switch (lookup.type()) { case NORMAL: { PropertyDetails details = PropertyDetails(attributes, NORMAL); - return SetNormalizedProperty(name, value, details); + result = self->SetNormalizedProperty(*name, *value, details); + break; } case FIELD: - return FastPropertyAtPut(result.GetFieldIndex(), value); + result = self->FastPropertyAtPut( + lookup.GetFieldIndex().field_index(), *value); + break; case CONSTANT_FUNCTION: // Only replace the function if necessary. - if (value == result.GetConstantFunction()) return value; - // Preserve the attributes of this existing property. - attributes = result.GetAttributes(); - return ConvertDescriptorToField(name, value, attributes); + if (*value != lookup.GetConstantFunction()) { + // Preserve the attributes of this existing property. + attributes = lookup.GetAttributes(); + result = self->ConvertDescriptorToField(*name, *value, attributes); + } + break; case CALLBACKS: case INTERCEPTOR: // Override callback in clone - return ConvertDescriptorToField(name, value, attributes); + result = self->ConvertDescriptorToField(*name, *value, attributes); + break; case TRANSITION: { - Map* transition_map = result.GetTransitionTarget(); + Map* transition_map = lookup.GetTransitionTarget(); int descriptor = transition_map->LastAdded(); DescriptorArray* descriptors = transition_map->instance_descriptors(); @@ -3007,29 +3157,48 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( if (details.type() == FIELD) { if (attributes == details.attributes()) { int field_index = descriptors->GetFieldIndex(descriptor); - return AddFastPropertyUsingMap(transition_map, - name, - value, - field_index); + result = self->AddFastPropertyUsingMap( + transition_map, *name, *value, field_index); + } else { + result = self->ConvertDescriptorToField(*name, *value, attributes); } - return ConvertDescriptorToField(name, value, attributes); } else if (details.type() == CALLBACKS) { - return ConvertDescriptorToField(name, value, attributes); - } - - ASSERT(details.type() == CONSTANT_FUNCTION); + result = self->ConvertDescriptorToField(*name, *value, attributes); + } else { + ASSERT(details.type() == CONSTANT_FUNCTION); - // Replace transition to CONSTANT FUNCTION with a map transition to a new - // map with a FIELD, even if the value is a function. - return ConvertTransitionToMapTransition( - result.GetTransitionIndex(), name, value, attributes); + // Replace transition to CONSTANT FUNCTION with a map transition to a + // new map with a FIELD, even if the value is a function. + result = self->ConvertTransitionToMapTransition( + lookup.GetTransitionIndex(), *name, *value, attributes); + } + break; } case HANDLER: case NONEXISTENT: UNREACHABLE(); } - UNREACHABLE(); // keep the compiler happy - return value; + + Handle<Object> hresult; + if (!result->ToHandle(&hresult, isolate)) return result; + + if (is_observed) { + if (lookup.IsTransition()) { + EnqueueChangeRecord(self, "new", name, old_value); + } else { + LookupResult new_lookup(isolate); + self->LocalLookup(*name, &new_lookup, true); + ASSERT(!new_lookup.GetLazyValue()->IsTheHole()); + if (old_value->IsTheHole() || + new_lookup.GetAttributes() != old_attributes) { + EnqueueChangeRecord(self, "reconfigured", name, old_value); + } else if (!new_lookup.GetLazyValue()->SameValue(*old_value)) { + EnqueueChangeRecord(self, "updated", name, old_value); + } + } + } + + return *hresult; } @@ -3110,42 +3279,43 @@ PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver( String* key) { uint32_t index = 0; if (IsJSObject() && key->AsArrayIndex(&index)) { - return JSObject::cast(this)->HasElementWithReceiver(receiver, index) - ? NONE : ABSENT; + return JSObject::cast(this)->GetElementAttributeWithReceiver( + receiver, index, true); } // Named property. - LookupResult result(GetIsolate()); - Lookup(key, &result); - return GetPropertyAttribute(receiver, &result, key, true); + LookupResult lookup(GetIsolate()); + Lookup(key, &lookup); + return GetPropertyAttributeForResult(receiver, &lookup, key, true); } -PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver, - LookupResult* result, - String* name, - bool continue_search) { +PropertyAttributes JSReceiver::GetPropertyAttributeForResult( + JSReceiver* receiver, + LookupResult* lookup, + String* name, + bool continue_search) { // Check access rights if needed. if (IsAccessCheckNeeded()) { JSObject* this_obj = JSObject::cast(this); Heap* heap = GetHeap(); if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) { return this_obj->GetPropertyAttributeWithFailedAccessCheck( - receiver, result, name, continue_search); + receiver, lookup, name, continue_search); } } - if (result->IsFound()) { - switch (result->type()) { + if (lookup->IsFound()) { + switch (lookup->type()) { case NORMAL: // fall through case FIELD: case CONSTANT_FUNCTION: case CALLBACKS: - return result->GetAttributes(); + return lookup->GetAttributes(); case HANDLER: { - return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler( + return JSProxy::cast(lookup->proxy())->GetPropertyAttributeWithHandler( receiver, name); } case INTERCEPTOR: - return result->holder()->GetPropertyAttributeWithInterceptor( + return lookup->holder()->GetPropertyAttributeWithInterceptor( JSObject::cast(receiver), name, continue_search); case TRANSITION: case NONEXISTENT: @@ -3160,13 +3330,118 @@ PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { // Check whether the name is an array index. uint32_t index = 0; if (IsJSObject() && name->AsArrayIndex(&index)) { - if (JSObject::cast(this)->HasLocalElement(index)) return NONE; - return ABSENT; + return GetLocalElementAttribute(index); } // Named property. - LookupResult result(GetIsolate()); - LocalLookup(name, &result); - return GetPropertyAttribute(this, &result, name, false); + LookupResult lookup(GetIsolate()); + LocalLookup(name, &lookup, true); + return GetPropertyAttributeForResult(this, &lookup, name, false); +} + + +PropertyAttributes JSObject::GetElementAttributeWithReceiver( + JSReceiver* receiver, uint32_t index, bool continue_search) { + Isolate* isolate = GetIsolate(); + + // Check access rights if needed. + if (IsAccessCheckNeeded()) { + if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { + isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + return ABSENT; + } + } + + if (IsJSGlobalProxy()) { + Object* proto = GetPrototype(); + if (proto->IsNull()) return ABSENT; + ASSERT(proto->IsJSGlobalObject()); + return JSObject::cast(proto)->GetElementAttributeWithReceiver( + receiver, index, continue_search); + } + + // Check for lookup interceptor except when bootstrapping. + if (HasIndexedInterceptor() && !isolate->bootstrapper()->IsActive()) { + return GetElementAttributeWithInterceptor(receiver, index, continue_search); + } + + // Handle [] on String objects. + if (this->IsStringObjectWithCharacterAt(index)) { + return static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE); + } + + return GetElementAttributeWithoutInterceptor( + receiver, index, continue_search); +} + + +PropertyAttributes JSObject::GetElementAttributeWithInterceptor( + JSReceiver* receiver, uint32_t index, bool continue_search) { + Isolate* isolate = GetIsolate(); + // Make sure that the top context does not change when doing + // callbacks or interceptor calls. + AssertNoContextChange ncc; + HandleScope scope(isolate); + Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); + Handle<JSReceiver> hreceiver(receiver); + Handle<JSObject> holder(this); + CustomArguments args(isolate, interceptor->data(), receiver, this); + v8::AccessorInfo info(args.end()); + if (!interceptor->query()->IsUndefined()) { + v8::IndexedPropertyQuery query = + v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query()); + LOG(isolate, + ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); + v8::Handle<v8::Integer> result; + { + // Leaving JavaScript. + VMState state(isolate, EXTERNAL); + result = query(index, info); + } + if (!result.IsEmpty()) + return static_cast<PropertyAttributes>(result->Int32Value()); + } else if (!interceptor->getter()->IsUndefined()) { + v8::IndexedPropertyGetter getter = + v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); + LOG(isolate, + ApiIndexedPropertyAccess("interceptor-indexed-get-has", this, index)); + v8::Handle<v8::Value> result; + { + // Leaving JavaScript. + VMState state(isolate, EXTERNAL); + result = getter(index, info); + } + if (!result.IsEmpty()) return NONE; + } + + return holder->GetElementAttributeWithoutInterceptor( + *hreceiver, index, continue_search); +} + + +PropertyAttributes JSObject::GetElementAttributeWithoutInterceptor( + JSReceiver* receiver, uint32_t index, bool continue_search) { + Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); + Handle<JSReceiver> hreceiver(receiver); + Handle<JSObject> holder(this); + PropertyAttributes attr = holder->GetElementsAccessor()->GetAttributes( + *hreceiver, *holder, index); + if (attr != ABSENT) return attr; + + if (holder->IsStringObjectWithCharacterAt(index)) { + return static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE); + } + + if (!continue_search) return ABSENT; + + Object* pt = holder->GetPrototype(); + if (pt->IsJSProxy()) { + // We need to follow the spec and simulate a call to [[GetOwnProperty]]. + return JSProxy::cast(pt)->GetElementAttributeWithHandler(*hreceiver, index); + } + if (pt->IsNull()) return ABSENT; + return JSObject::cast(pt)->GetElementAttributeWithReceiver( + *hreceiver, index, true); } @@ -3178,10 +3453,12 @@ MaybeObject* NormalizedMapCache::Get(JSObject* obj, Object* result = get(index); if (result->IsMap() && Map::cast(result)->EquivalentToForNormalization(fast, mode)) { -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { Map::cast(result)->SharedMapVerify(); } +#endif +#ifdef DEBUG if (FLAG_enable_slow_asserts) { // The cached map should match newly created normalized map bit-by-bit, // except for the code cache, which can contain some ics which can be @@ -3271,19 +3548,19 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, Map* map_of_this = map(); // Allocate new content. - int property_count = map_of_this->NumberOfDescribedProperties(); + int real_size = map_of_this->NumberOfOwnDescriptors(); + int property_count = real_size; if (expected_additional_properties > 0) { property_count += expected_additional_properties; } else { property_count += 2; // Make space for two more properties. } StringDictionary* dictionary; - { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count); - if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; - } + MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count); + if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; DescriptorArray* descs = map_of_this->instance_descriptors(); - for (int i = 0; i < descs->number_of_descriptors(); i++) { + for (int i = 0; i < real_size; i++) { PropertyDetails details = descs->GetDetails(i); switch (details.type()) { case CONSTANT_FUNCTION: { @@ -3328,8 +3605,7 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, Heap* current_heap = GetHeap(); // Copy the next enumeration index from instance descriptor. - int index = map_of_this->instance_descriptors()->NextEnumerationIndex(); - dictionary->SetNextEnumerationIndex(index); + dictionary->SetNextEnumerationIndex(real_size + 1); Map* new_map; MaybeObject* maybe_map = @@ -3557,7 +3833,6 @@ Object* JSObject::GetHiddenProperty(String* key) { ASSERT(!IsJSGlobalProxy()); MaybeObject* hidden_lookup = GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); - ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg. Object* inline_value = hidden_lookup->ToObjectUnchecked(); if (inline_value->IsSmi()) { @@ -3598,13 +3873,11 @@ MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) { return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value); } ASSERT(!IsJSGlobalProxy()); - - // If there is no backing store yet, store the identity hash inline. MaybeObject* hidden_lookup = GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); - ASSERT(!hidden_lookup->IsFailure()); Object* inline_value = hidden_lookup->ToObjectUnchecked(); + // If there is no backing store yet, store the identity hash inline. if (value->IsSmi() && key == GetHeap()->identity_hash_symbol() && (inline_value->IsUndefined() || inline_value->IsSmi())) { @@ -3641,15 +3914,16 @@ void JSObject::DeleteHiddenProperty(String* key) { JSObject::cast(proxy_parent)->DeleteHiddenProperty(key); return; } + ASSERT(!IsJSGlobalProxy()); MaybeObject* hidden_lookup = GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); - ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg. - if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return; + Object* inline_value = hidden_lookup->ToObjectUnchecked(); + // We never delete (inline-stored) identity hashes. - ASSERT(!hidden_lookup->ToObjectUnchecked()->IsSmi()); + ASSERT(key != GetHeap()->identity_hash_symbol()); + if (inline_value->IsUndefined() || inline_value->IsSmi()) return; - ObjectHashTable* hashtable = - ObjectHashTable::cast(hidden_lookup->ToObjectUnchecked()); + ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value); MaybeObject* delete_result = hashtable->Put(key, GetHeap()->the_hole_value()); USE(delete_result); ASSERT(!delete_result->IsFailure()); // Delete does not cause GC. @@ -3675,10 +3949,11 @@ MaybeObject* JSObject::GetHiddenPropertiesHashTable( DescriptorArray* descriptors = this->map()->instance_descriptors(); if (descriptors->number_of_descriptors() > 0) { int sorted_index = descriptors->GetSortedKeyIndex(0); - if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol()) { + if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() && + sorted_index < map()->NumberOfOwnDescriptors()) { ASSERT(descriptors->GetType(sorted_index) == FIELD); - inline_value = this->FastPropertyAt( - descriptors->GetFieldIndex(sorted_index)); + inline_value = + this->FastPropertyAt(descriptors->GetFieldIndex(sorted_index)); } else { inline_value = GetHeap()->undefined_value(); } @@ -3743,7 +4018,8 @@ MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) { DescriptorArray* descriptors = this->map()->instance_descriptors(); if (descriptors->number_of_descriptors() > 0) { int sorted_index = descriptors->GetSortedKeyIndex(0); - if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol()) { + if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() && + sorted_index < map()->NumberOfOwnDescriptors()) { ASSERT(descriptors->GetType(sorted_index) == FIELD); this->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), value); @@ -3868,6 +4144,21 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { return isolate->heap()->false_value(); } + if (IsStringObjectWithCharacterAt(index)) { + if (mode == STRICT_DELETION) { + // Deleting a non-configurable property in strict mode. + HandleScope scope(isolate); + Handle<Object> holder(this); + Handle<Object> name = isolate->factory()->NewNumberFromUint(index); + Handle<Object> args[2] = { name, holder }; + Handle<Object> error = + isolate->factory()->NewTypeError("strict_delete_property", + HandleVector(args, 2)); + return isolate->Throw(*error); + } + return isolate->heap()->false_value(); + } + if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return isolate->heap()->false_value(); @@ -3875,15 +4166,38 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { return JSGlobalObject::cast(proto)->DeleteElement(index, mode); } - if (HasIndexedInterceptor()) { - // Skip interceptor if forcing deletion. - if (mode != FORCE_DELETION) { - return DeleteElementWithInterceptor(index); + // From this point on everything needs to be handlified. + HandleScope scope(isolate); + Handle<JSObject> self(this); + + Handle<Object> old_value; + bool should_enqueue_change_record = false; + if (FLAG_harmony_observation && self->map()->is_observed()) { + should_enqueue_change_record = self->HasLocalElement(index); + if (should_enqueue_change_record) { + old_value = self->GetLocalElementAccessorPair(index) != NULL + ? Handle<Object>::cast(isolate->factory()->the_hole_value()) + : Object::GetElement(self, index); } - mode = JSReceiver::FORCE_DELETION; } - return GetElementsAccessor()->Delete(this, index, mode); + MaybeObject* result; + // Skip interceptor if forcing deletion. + if (self->HasIndexedInterceptor() && mode != FORCE_DELETION) { + result = self->DeleteElementWithInterceptor(index); + } else { + result = self->GetElementsAccessor()->Delete(*self, index, mode); + } + + Handle<Object> hresult; + if (!result->ToHandle(&hresult, isolate)) return result; + + if (should_enqueue_change_record && !self->HasLocalElement(index)) { + Handle<String> name = isolate->factory()->Uint32ToString(index); + EnqueueChangeRecord(self, "deleted", name, old_value); + } + + return *hresult; } @@ -3917,38 +4231,60 @@ MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { uint32_t index = 0; if (name->AsArrayIndex(&index)) { return DeleteElement(index, mode); - } else { - LookupResult result(isolate); - LocalLookup(name, &result); - if (!result.IsFound()) return isolate->heap()->true_value(); - // Ignore attributes if forcing a deletion. - if (result.IsDontDelete() && mode != FORCE_DELETION) { - if (mode == STRICT_DELETION) { - // Deleting a non-configurable property in strict mode. - HandleScope scope(isolate); - Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; - return isolate->Throw(*isolate->factory()->NewTypeError( - "strict_delete_property", HandleVector(args, 2))); - } - return isolate->heap()->false_value(); - } - // Check for interceptor. - if (result.IsInterceptor()) { - // Skip interceptor if forcing a deletion. - if (mode == FORCE_DELETION) { - return DeletePropertyPostInterceptor(name, mode); - } - return DeletePropertyWithInterceptor(name); + } + + LookupResult lookup(isolate); + LocalLookup(name, &lookup, true); + if (!lookup.IsFound()) return isolate->heap()->true_value(); + // Ignore attributes if forcing a deletion. + if (lookup.IsDontDelete() && mode != FORCE_DELETION) { + if (mode == STRICT_DELETION) { + // Deleting a non-configurable property in strict mode. + HandleScope scope(isolate); + Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; + return isolate->Throw(*isolate->factory()->NewTypeError( + "strict_delete_property", HandleVector(args, 2))); } + return isolate->heap()->false_value(); + } + + // From this point on everything needs to be handlified. + HandleScope scope(isolate); + Handle<JSObject> self(this); + Handle<String> hname(name); + + Handle<Object> old_value(isolate->heap()->the_hole_value()); + bool is_observed = FLAG_harmony_observation && self->map()->is_observed(); + if (is_observed) { + old_value = handle(lookup.GetLazyValue(), isolate); + } + MaybeObject* result; + + // Check for interceptor. + if (lookup.IsInterceptor()) { + // Skip interceptor if forcing a deletion. + if (mode == FORCE_DELETION) { + result = self->DeletePropertyPostInterceptor(*hname, mode); + } else { + result = self->DeletePropertyWithInterceptor(*hname); + } + } else { // Normalize object if needed. Object* obj; - { MaybeObject* maybe_obj = - NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } + result = self->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); + if (!result->To(&obj)) return result; // Make sure the properties are normalized before removing the entry. - return DeleteNormalizedProperty(name, mode); + result = self->DeleteNormalizedProperty(*hname, mode); } + + Handle<Object> hresult; + if (!result->ToHandle(&hresult, isolate)) return result; + + if (is_observed && !self->HasLocalProperty(*hname)) { + EnqueueChangeRecord(self, "deleted", hname, old_value); + } + + return *hresult; } @@ -4178,21 +4514,15 @@ bool JSReceiver::IsSimpleEnum() { } -void Map::SetDescriptors(Handle<Map> map, - Handle<DescriptorArray> descriptors) { - Isolate* isolate = map->GetIsolate(); - CALL_HEAP_FUNCTION_VOID(isolate, map->SetDescriptors(*descriptors)); -} - - -int Map::NumberOfDescribedProperties(PropertyAttributes filter) { +int Map::NumberOfDescribedProperties(DescriptorFlag which, + PropertyAttributes filter) { int result = 0; DescriptorArray* descs = instance_descriptors(); - for (int i = 0; i < descs->number_of_descriptors(); i++) { - PropertyDetails details = descs->GetDetails(i); - if ((details.attributes() & filter) == 0) { - result++; - } + int limit = which == ALL_DESCRIPTORS + ? descs->number_of_descriptors() + : NumberOfOwnDescriptors(); + for (int i = 0; i < limit; i++) { + if ((descs->GetDetails(i).attributes() & filter) == 0) result++; } return result; } @@ -4200,7 +4530,8 @@ int Map::NumberOfDescribedProperties(PropertyAttributes filter) { int Map::PropertyIndexFor(String* name) { DescriptorArray* descs = instance_descriptors(); - for (int i = 0; i < descs->number_of_descriptors(); i++) { + int limit = NumberOfOwnDescriptors(); + for (int i = 0; i < limit; i++) { if (name->Equals(descs->GetKey(i))) return descs->GetFieldIndex(i); } return -1; @@ -4209,8 +4540,9 @@ int Map::PropertyIndexFor(String* name) { int Map::NextFreePropertyIndex() { int max_index = -1; + int number_of_own_descriptors = NumberOfOwnDescriptors(); DescriptorArray* descs = instance_descriptors(); - for (int i = 0; i < descs->number_of_descriptors(); i++) { + for (int i = 0; i < number_of_own_descriptors; i++) { if (descs->GetType(i) == FIELD) { int current_index = descs->GetFieldIndex(i); if (current_index > max_index) max_index = current_index; @@ -4222,8 +4554,9 @@ int Map::NextFreePropertyIndex() { AccessorDescriptor* Map::FindAccessor(String* name) { DescriptorArray* descs = instance_descriptors(); - for (int i = 0; i < descs->number_of_descriptors(); i++) { - if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { + int number_of_own_descriptors = NumberOfOwnDescriptors(); + for (int i = 0; i < number_of_own_descriptors; i++) { + if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) { return descs->GetCallbacks(i); } } @@ -4231,7 +4564,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) { } -void JSReceiver::LocalLookup(String* name, LookupResult* result) { +void JSReceiver::LocalLookup( + String* name, LookupResult* result, bool search_hidden_prototypes) { ASSERT(name->IsString()); Heap* heap = GetHeap(); @@ -4240,7 +4574,8 @@ void JSReceiver::LocalLookup(String* name, LookupResult* result) { Object* proto = GetPrototype(); if (proto->IsNull()) return result->NotFound(); ASSERT(proto->IsJSGlobalObject()); - return JSReceiver::cast(proto)->LocalLookup(name, result); + return JSReceiver::cast(proto)->LocalLookup( + name, result, search_hidden_prototypes); } if (IsJSProxy()) { @@ -4270,6 +4605,14 @@ void JSReceiver::LocalLookup(String* name, LookupResult* result) { } js_object->LocalLookupRealNamedProperty(name, result); + if (result->IsFound() || !search_hidden_prototypes) return; + + Object* proto = js_object->GetPrototype(); + if (!proto->IsJSReceiver()) return; + JSReceiver* receiver = JSReceiver::cast(proto); + if (receiver->map()->is_hidden_prototype()) { + receiver->LocalLookup(name, result, search_hidden_prototypes); + } } @@ -4279,7 +4622,7 @@ void JSReceiver::Lookup(String* name, LookupResult* result) { for (Object* current = this; current != heap->null_value(); current = JSObject::cast(current)->GetPrototype()) { - JSReceiver::cast(current)->LocalLookup(name, result); + JSReceiver::cast(current)->LocalLookup(name, result, false); if (result->IsFound()) return; } result->NotFound(); @@ -4420,7 +4763,9 @@ MaybeObject* JSObject::DefinePropertyAccessor(String* name, // 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) { + if (HasFastProperties() && !only_attribute_changes && + (map()->NumberOfOwnDescriptors() < + DescriptorArray::kMaxNumberOfDescriptors)) { MaybeObject* getterOk = heap->undefined_value(); if (!getter->IsNull()) { getterOk = DefineFastAccessor(name, ACCESSOR_GETTER, getter, attributes); @@ -4550,14 +4895,14 @@ void JSObject::DefineAccessor(Handle<JSObject> object, object->DefineAccessor(*name, *getter, *setter, attributes)); } -MaybeObject* JSObject::DefineAccessor(String* name, - Object* getter, - Object* setter, +MaybeObject* JSObject::DefineAccessor(String* name_raw, + Object* getter_raw, + Object* setter_raw, PropertyAttributes attributes) { Isolate* isolate = GetIsolate(); // Check access rights if needed. if (IsAccessCheckNeeded() && - !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { + !isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) { isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); return isolate->heap()->undefined_value(); } @@ -4567,7 +4912,7 @@ MaybeObject* JSObject::DefineAccessor(String* name, if (proto->IsNull()) return this; ASSERT(proto->IsJSGlobalObject()); return JSObject::cast(proto)->DefineAccessor( - name, getter, setter, attributes); + name_raw, getter_raw, setter_raw, attributes); } // Make sure that the top context does not change when doing callbacks or @@ -4575,14 +4920,50 @@ MaybeObject* JSObject::DefineAccessor(String* name, AssertNoContextChange ncc; // Try to flatten before operating on the string. - name->TryFlatten(); + name_raw->TryFlatten(); - if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); + if (!CanSetCallback(name_raw)) return isolate->heap()->undefined_value(); + + // From this point on everything needs to be handlified. + HandleScope scope(isolate); + Handle<JSObject> self(this); + Handle<String> name(name_raw); + Handle<Object> getter(getter_raw); + Handle<Object> setter(setter_raw); uint32_t index = 0; - return name->AsArrayIndex(&index) ? - DefineElementAccessor(index, getter, setter, attributes) : - DefinePropertyAccessor(name, getter, setter, attributes); + bool is_element = name->AsArrayIndex(&index); + + Handle<Object> old_value = isolate->factory()->the_hole_value(); + bool is_observed = FLAG_harmony_observation && self->map()->is_observed(); + bool preexists = false; + if (is_observed) { + if (is_element) { + preexists = HasLocalElement(index); + if (preexists && self->GetLocalElementAccessorPair(index) == NULL) { + old_value = Object::GetElement(self, index); + } + } else { + LookupResult lookup(isolate); + LocalLookup(*name, &lookup, true); + preexists = lookup.IsProperty(); + if (preexists) old_value = handle(lookup.GetLazyValue(), isolate); + } + } + + MaybeObject* result = is_element ? + self->DefineElementAccessor(index, *getter, *setter, attributes) : + self->DefinePropertyAccessor(*name, *getter, *setter, attributes); + + Handle<Object> hresult; + if (!result->ToHandle(&hresult, isolate)) return result; + + if (is_observed) { + const char* type = preexists ? "reconfigured" : "new"; + EnqueueChangeRecord(self, type, name, old_value); + } + + return *hresult; } @@ -4647,9 +5028,10 @@ MaybeObject* JSObject::DefineFastAccessor(String* name, if (result.IsFound()) { Map* target = result.GetTransitionTarget(); - ASSERT(target->instance_descriptors()->number_of_descriptors() == - map()->instance_descriptors()->number_of_descriptors()); - ASSERT(target->instance_descriptors()->GetKey(descriptor_number) == name); + ASSERT(target->NumberOfOwnDescriptors() == + map()->NumberOfOwnDescriptors()); + // This works since descriptors are sorted in order of addition. + ASSERT(map()->instance_descriptors()->GetKey(descriptor_number) == name); return TryAccessorTransition( this, target, descriptor_number, component, accessor, attributes); } @@ -4661,7 +5043,8 @@ MaybeObject* JSObject::DefineFastAccessor(String* name, if (result.IsFound()) { Map* target = result.GetTransitionTarget(); int descriptor_number = target->LastAdded(); - ASSERT(target->instance_descriptors()->GetKey(descriptor_number) == name); + ASSERT(target->instance_descriptors()->GetKey(descriptor_number) + ->Equals(name)); return TryAccessorTransition( this, target, descriptor_number, component, accessor, attributes); } @@ -4760,7 +5143,7 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { } else { // Lookup the name. LookupResult result(isolate); - LocalLookup(name, &result); + LocalLookup(name, &result, true); // ES5 forbids turning a property into an accessor if it's not // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5). if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) { @@ -4832,8 +5215,9 @@ Object* JSObject::LookupAccessor(String* name, AccessorComponent component) { Object* JSObject::SlowReverseLookup(Object* value) { if (HasFastProperties()) { + int number_of_own_descriptors = map()->NumberOfOwnDescriptors(); DescriptorArray* descs = map()->instance_descriptors(); - for (int i = 0; i < descs->number_of_descriptors(); i++) { + for (int i = 0; i < number_of_own_descriptors; i++) { if (descs->GetType(i) == FIELD) { if (FastPropertyAt(descs->GetFieldIndex(i)) == value) { return descs->GetKey(i); @@ -4861,9 +5245,11 @@ MaybeObject* Map::RawCopy(int instance_size) { result->set_constructor(constructor()); result->set_bit_field(bit_field()); result->set_bit_field2(bit_field2()); - result->set_bit_field3(bit_field3()); - result->SetNumberOfOwnDescriptors(0); - result->SetEnumLength(kInvalidEnumCache); + int new_bit_field3 = bit_field3(); + new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); + new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); + new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache); + result->set_bit_field3(new_bit_field3); return result; } @@ -4887,7 +5273,7 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, result->set_is_shared(sharing == SHARED_NORMALIZED_MAP); result->set_dictionary_map(true); -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap && result->is_shared()) { result->SharedMapVerify(); } @@ -4913,22 +5299,100 @@ MaybeObject* Map::CopyDropDescriptors() { } +MaybeObject* Map::ShareDescriptor(DescriptorArray* descriptors, + Descriptor* descriptor) { + // Sanity check. This path is only to be taken if the map owns its descriptor + // array, implying that its NumberOfOwnDescriptors equals the number of + // descriptors in the descriptor array. + ASSERT(NumberOfOwnDescriptors() == + instance_descriptors()->number_of_descriptors()); + Map* result; + MaybeObject* maybe_result = CopyDropDescriptors(); + if (!maybe_result->To(&result)) return maybe_result; + + String* name = descriptor->GetKey(); + + TransitionArray* transitions; + MaybeObject* maybe_transitions = + AddTransition(name, result, SIMPLE_TRANSITION); + if (!maybe_transitions->To(&transitions)) return maybe_transitions; + + int old_size = descriptors->number_of_descriptors(); + + DescriptorArray* new_descriptors; + + if (descriptors->NumberOfSlackDescriptors() > 0) { + new_descriptors = descriptors; + new_descriptors->Append(descriptor); + } else { + // Descriptor arrays grow by 50%. + MaybeObject* maybe_descriptors = DescriptorArray::Allocate( + old_size, old_size < 4 ? 1 : old_size / 2); + if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; + + DescriptorArray::WhitenessWitness witness(new_descriptors); + + // Copy the descriptors, inserting a descriptor. + for (int i = 0; i < old_size; ++i) { + new_descriptors->CopyFrom(i, descriptors, i, witness); + } + + new_descriptors->Append(descriptor, witness); + + if (old_size > 0) { + // If the source descriptors had an enum cache we copy it. This ensures + // that the maps to which we push the new descriptor array back can rely + // on a cache always being available once it is set. If the map has more + // enumerated descriptors than available in the original cache, the cache + // will be lazily replaced by the extended cache when needed. + if (descriptors->HasEnumCache()) { + new_descriptors->CopyEnumCacheFrom(descriptors); + } + + Map* map; + // Replace descriptors by new_descriptors in all maps that share it. + for (Object* current = GetBackPointer(); + !current->IsUndefined(); + current = map->GetBackPointer()) { + map = Map::cast(current); + if (map->instance_descriptors() != descriptors) break; + map->set_instance_descriptors(new_descriptors); + } + + set_instance_descriptors(new_descriptors); + } + } + + result->SetBackPointer(this); + result->InitializeDescriptors(new_descriptors); + ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1); + + set_transitions(transitions); + set_owns_descriptors(false); + + return result; +} + + MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, String* name, - TransitionFlag flag) { + TransitionFlag flag, + int descriptor_index) { + ASSERT(descriptors->IsSortedNoDuplicates()); + Map* result; MaybeObject* maybe_result = CopyDropDescriptors(); if (!maybe_result->To(&result)) return maybe_result; - if (descriptors->number_of_descriptors() != 0) { - MaybeObject* maybe_failure = result->SetDescriptors(descriptors); - if (maybe_failure->IsFailure()) return maybe_failure; - result->SetNumberOfOwnDescriptors(descriptors->number_of_descriptors()); - } + result->InitializeDescriptors(descriptors); if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) { TransitionArray* transitions; - MaybeObject* maybe_transitions = AddTransition(name, result); + SimpleTransitionFlag simple_flag = + (descriptor_index == descriptors->number_of_descriptors() - 1) + ? SIMPLE_TRANSITION + : FULL_TRANSITION; + MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag); if (!maybe_transitions->To(&transitions)) return maybe_transitions; set_transitions(transitions); @@ -4940,12 +5404,6 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { - // Create a new free-floating map only if we are not allowed to store it. - Map* new_map = NULL; - MaybeObject* maybe_new_map = Copy(); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; - new_map->set_elements_kind(kind); - if (flag == INSERT_TRANSITION) { ASSERT(!HasElementsTransition() || ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || @@ -4956,10 +5414,40 @@ MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { ASSERT(!IsFastElementsKind(kind) || IsMoreGeneralElementsKindTransition(elements_kind(), kind)); ASSERT(kind != elements_kind()); + } + + bool insert_transition = + flag == INSERT_TRANSITION && !HasElementsTransition(); + + if (insert_transition && owns_descriptors()) { + // In case the map owned its own descriptors, share the descriptors and + // transfer ownership to the new map. + Map* new_map; + MaybeObject* maybe_new_map = CopyDropDescriptors(); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; MaybeObject* added_elements = set_elements_transition_map(new_map); if (added_elements->IsFailure()) return added_elements; + new_map->set_elements_kind(kind); + new_map->InitializeDescriptors(instance_descriptors()); + new_map->SetBackPointer(this); + set_owns_descriptors(false); + return new_map; + } + + // In case the map did not own its own descriptors, a split is forced by + // copying the map; creating a new descriptor array cell. + // Create a new free-floating map only if we are not allowed to store it. + Map* new_map; + MaybeObject* maybe_new_map = Copy(); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; + + new_map->set_elements_kind(kind); + + if (insert_transition) { + MaybeObject* added_elements = set_elements_transition_map(new_map); + if (added_elements->IsFailure()) return added_elements; new_map->SetBackPointer(this); } @@ -4977,13 +5465,25 @@ MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { Map* map = ctor->initial_map(); DescriptorArray* descriptors = map->instance_descriptors(); - return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); + int number_of_own_descriptors = map->NumberOfOwnDescriptors(); + DescriptorArray* new_descriptors; + MaybeObject* maybe_descriptors = + descriptors->CopyUpTo(number_of_own_descriptors); + if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; + + return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); } MaybeObject* Map::Copy() { DescriptorArray* descriptors = instance_descriptors(); - return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); + DescriptorArray* new_descriptors; + int number_of_own_descriptors = NumberOfOwnDescriptors(); + MaybeObject* maybe_descriptors = + descriptors->CopyUpTo(number_of_own_descriptors); + if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; + + return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); } @@ -4995,28 +5495,39 @@ MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, MaybeObject* maybe_failure = descriptor->KeyToSymbol(); if (maybe_failure->IsFailure()) return maybe_failure; - String* key = descriptor->GetKey(); - ASSERT(descriptors->Search(key) == DescriptorArray::kNotFound); - - int old_size = descriptors->number_of_descriptors(); + int old_size = NumberOfOwnDescriptors(); int new_size = old_size + 1; + descriptor->SetEnumerationIndex(new_size); + + if (flag == INSERT_TRANSITION && + owns_descriptors() && + CanHaveMoreTransitions()) { + return ShareDescriptor(descriptors, descriptor); + } DescriptorArray* new_descriptors; - MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size); + MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1); if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; - FixedArray::WhitenessWitness witness(new_descriptors); + DescriptorArray::WhitenessWitness witness(new_descriptors); // Copy the descriptors, inserting a descriptor. for (int i = 0; i < old_size; ++i) { new_descriptors->CopyFrom(i, descriptors, i, witness); } - new_descriptors->Append(descriptor, witness, old_size); + if (old_size != descriptors->number_of_descriptors()) { + new_descriptors->SetNumberOfDescriptors(new_size); + new_descriptors->Set(old_size, descriptor, witness); + new_descriptors->Sort(); + } else { + new_descriptors->Append(descriptor, witness); + } - SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); + String* key = descriptor->GetKey(); + int insertion_index = new_descriptors->number_of_descriptors() - 1; - return CopyReplaceDescriptors(new_descriptors, key, flag); + return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index); } @@ -5029,21 +5540,38 @@ MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, if (maybe_result->IsFailure()) return maybe_result; // We replace the key if it is already present. - int index = old_descriptors->SearchWithCache(descriptor->GetKey()); + int index = old_descriptors->SearchWithCache(descriptor->GetKey(), this); if (index != DescriptorArray::kNotFound) { - return CopyReplaceDescriptor(descriptor, index, flag); + return CopyReplaceDescriptor(old_descriptors, descriptor, index, flag); } return CopyAddDescriptor(descriptor, flag); } -MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor, +MaybeObject* DescriptorArray::CopyUpTo(int enumeration_index) { + if (enumeration_index == 0) return GetHeap()->empty_descriptor_array(); + + int size = enumeration_index; + + DescriptorArray* descriptors; + MaybeObject* maybe_descriptors = Allocate(size); + if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; + DescriptorArray::WhitenessWitness witness(descriptors); + + for (int i = 0; i < size; ++i) { + descriptors->CopyFrom(i, this, i, witness); + } + + if (number_of_descriptors() != enumeration_index) descriptors->Sort(); + + return descriptors; +} + + +MaybeObject* Map::CopyReplaceDescriptor(DescriptorArray* descriptors, + Descriptor* descriptor, int insertion_index, TransitionFlag flag) { - DescriptorArray* descriptors = instance_descriptors(); - int size = descriptors->number_of_descriptors(); - ASSERT(0 <= insertion_index && insertion_index < size); - // Ensure the key is a symbol. MaybeObject* maybe_failure = descriptor->KeyToSymbol(); if (maybe_failure->IsFailure()) return maybe_failure; @@ -5051,27 +5579,30 @@ MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor, String* key = descriptor->GetKey(); ASSERT(key == descriptors->GetKey(insertion_index)); + int new_size = NumberOfOwnDescriptors(); + ASSERT(0 <= insertion_index && insertion_index < new_size); + + PropertyDetails details = descriptors->GetDetails(insertion_index); + ASSERT_LE(details.descriptor_index(), new_size); + descriptor->SetEnumerationIndex(details.descriptor_index()); + DescriptorArray* new_descriptors; - MaybeObject* maybe_descriptors = DescriptorArray::Allocate(size); + MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size); if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; + DescriptorArray::WhitenessWitness witness(new_descriptors); - FixedArray::WhitenessWitness witness(new_descriptors); - - // Copy the descriptors, replacing a descriptor. - for (int index = 0; index < size; ++index) { - if (index == insertion_index) continue; - new_descriptors->CopyFrom(index, descriptors, index, witness); + for (int i = 0; i < new_size; ++i) { + if (i == insertion_index) { + new_descriptors->Set(i, descriptor, witness); + } else { + new_descriptors->CopyFrom(i, descriptors, i, witness); + } } - PropertyDetails original_details = descriptors->GetDetails(insertion_index); - descriptor->SetEnumerationIndex(original_details.descriptor_index()); - descriptor->SetSortedKey(original_details.pointer()); - - new_descriptors->Set(insertion_index, descriptor, witness); - - SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); + // Re-sort if descriptors were removed. + if (new_size != descriptors->length()) new_descriptors->Sort(); - return CopyReplaceDescriptors(new_descriptors, key, flag); + return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index); } @@ -5846,39 +6377,39 @@ bool FixedArray::IsEqualTo(FixedArray* other) { #endif -MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { +MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) { Heap* heap = Isolate::Current()->heap(); // Do not use DescriptorArray::cast on incomplete object. + int size = number_of_descriptors + slack; + if (size == 0) return heap->empty_descriptor_array(); FixedArray* result; - if (number_of_descriptors == 0) return heap->empty_descriptor_array(); // Allocate the array of keys. - MaybeObject* maybe_array = - heap->AllocateFixedArray(LengthFor(number_of_descriptors)); + MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size)); if (!maybe_array->To(&result)) return maybe_array; + result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors)); result->set(kEnumCacheIndex, Smi::FromInt(0)); return result; } +void DescriptorArray::ClearEnumCache() { + set(kEnumCacheIndex, Smi::FromInt(0)); +} + + void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, FixedArray* new_cache, Object* new_index_cache) { ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); - if (HasEnumCache()) { - FixedArray::cast(get(kEnumCacheIndex))-> - set(kEnumCacheBridgeCacheIndex, new_cache); - FixedArray::cast(get(kEnumCacheIndex))-> - set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); - } else { - if (IsEmpty()) return; // Do nothing for empty descriptor array. - FixedArray::cast(bridge_storage)-> - set(kEnumCacheBridgeCacheIndex, new_cache); - FixedArray::cast(bridge_storage)-> - set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); - set(kEnumCacheIndex, bridge_storage); - } + ASSERT(!IsEmpty()); + ASSERT(!HasEnumCache() || new_cache->length() > GetEnumCache()->length()); + FixedArray::cast(bridge_storage)-> + set(kEnumCacheBridgeCacheIndex, new_cache); + FixedArray::cast(bridge_storage)-> + set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); + set(kEnumCacheIndex, bridge_storage); } @@ -5948,6 +6479,7 @@ void DescriptorArray::Sort() { parent_index = child_index; } } + ASSERT(IsSortedNoDuplicates()); } @@ -6025,10 +6557,10 @@ String::FlatContent String::GetFlatContent() { ASSERT(shape.representation_tag() != kConsStringTag && shape.representation_tag() != kSlicedStringTag); } - if (shape.encoding_tag() == kAsciiStringTag) { + if (shape.encoding_tag() == kOneByteStringTag) { const char* start; if (shape.representation_tag() == kSeqStringTag) { - start = SeqAsciiString::cast(string)->GetChars(); + start = SeqOneByteString::cast(string)->GetChars(); } else { start = ExternalAsciiString::cast(string)->GetChars(); } @@ -6111,7 +6643,7 @@ const uc16* String::GetTwoByteData() { const uc16* String::GetTwoByteData(unsigned start) { - ASSERT(!IsAsciiRepresentationUnderneath()); + ASSERT(!IsOneByteRepresentationUnderneath()); switch (StringShape(this).representation_tag()) { case kSeqStringTag: return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); @@ -6192,7 +6724,7 @@ void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, } -const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock( +const unibrow::byte* SeqOneByteString::SeqOneByteStringReadBlock( unsigned* remaining, unsigned* offset_ptr, unsigned max_chars) { @@ -6320,7 +6852,7 @@ void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer( } -void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, +void SeqOneByteString::SeqOneByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb, unsigned* offset_ptr, unsigned max_chars) { unsigned capacity = rbb->capacity - rbb->cursor; @@ -6363,9 +6895,9 @@ const unibrow::byte* String::ReadBlock(String* input, } switch (StringShape(input).representation_tag()) { case kSeqStringTag: - if (input->IsAsciiRepresentation()) { - SeqAsciiString* str = SeqAsciiString::cast(input); - return str->SeqAsciiStringReadBlock(&rbb->remaining, + if (input->IsOneByteRepresentation()) { + SeqOneByteString* str = SeqOneByteString::cast(input); + return str->SeqOneByteStringReadBlock(&rbb->remaining, offset_ptr, max_chars); } else { @@ -6380,7 +6912,7 @@ const unibrow::byte* String::ReadBlock(String* input, offset_ptr, max_chars); case kExternalStringTag: - if (input->IsAsciiRepresentation()) { + if (input->IsOneByteRepresentation()) { return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock( &rbb->remaining, offset_ptr, @@ -6494,8 +7026,128 @@ void StringInputBuffer::Seek(unsigned pos) { } -void SafeStringInputBuffer::Seek(unsigned pos) { - Reset(pos, input_); +String* ConsStringIteratorOp::Operate(ConsString* consString, + unsigned* outerOffset, int32_t* typeOut, unsigned* lengthOut) { + ASSERT(*lengthOut == (unsigned)consString->length()); + // Push the root string. + PushLeft(consString); + root_ = consString; + root_type_ = *typeOut; + root_length_ = *lengthOut; + unsigned targetOffset = *outerOffset; + unsigned offset = 0; + while (true) { + // Loop until the string is found which contains the target offset. + String* string = consString->first(); + unsigned length = string->length(); + int32_t type; + if (targetOffset < offset + length) { + // Target offset is in the left branch. + // Mark the descent. + ClearRightDescent(); + // Keep going if we're still in a ConString. + type = string->map()->instance_type(); + if ((type & kStringRepresentationMask) == kConsStringTag) { + consString = ConsString::cast(string); + PushLeft(consString); + continue; + } + } else { + // Descend right. + // Update progress through the string. + offset += length; + // Keep going if we're still in a ConString. + string = consString->second(); + type = string->map()->instance_type(); + if ((type & kStringRepresentationMask) == kConsStringTag) { + consString = ConsString::cast(string); + PushRight(consString, type); + continue; + } + // Mark the descent. + SetRightDescent(); + // Need this to be updated for the current string. + length = string->length(); + // Account for the possibility of an empty right leaf. + while (length == 0) { + bool blewStack; + // Need to adjust maximum depth for NextLeaf to work. + AdjustMaximumDepth(); + string = NextLeaf(&blewStack, &type); + if (string == NULL) { + // Luckily, this case is impossible. + ASSERT(!blewStack); + return NULL; + } + length = string->length(); + } + } + // Tell the stack we're done decending. + AdjustMaximumDepth(); + ASSERT(length != 0); + // Adjust return values and exit. + unsigned innerOffset = targetOffset - offset; + consumed_ += length - innerOffset; + *outerOffset = innerOffset; + *typeOut = type; + *lengthOut = length; + return string; + } + UNREACHABLE(); + return NULL; +} + + +String* ConsStringIteratorOp::NextLeaf(bool* blewStack, int32_t* typeOut) { + while (true) { + // Tree traversal complete. + if (depth_ == 0) { + *blewStack = false; + return NULL; + } + // We've lost track of higher nodes. + if (maximum_depth_ - depth_ == kStackSize) { + *blewStack = true; + return NULL; + } + // Check if we're done with this level. + bool haveAlreadyReadRight = trace_ & MaskForDepth(depth_ - 1); + if (haveAlreadyReadRight) { + Pop(); + continue; + } + // Go right. + ConsString* consString = frames_[OffsetForDepth(depth_ - 1)]; + String* string = consString->second(); + int32_t type = string->map()->instance_type(); + if ((type & kStringRepresentationMask) != kConsStringTag) { + // Don't need to mark the descent here. + // Pop stack so next iteration is in correct place. + Pop(); + *typeOut = type; + return string; + } + // No need to mark the descent. + consString = ConsString::cast(string); + PushRight(consString, type); + // Need to traverse all the way left. + while (true) { + // Continue left. + // Update marker. + ClearRightDescent(); + string = consString->first(); + type = string->map()->instance_type(); + if ((type & kStringRepresentationMask) != kConsStringTag) { + AdjustMaximumDepth(); + *typeOut = type; + return string; + } + consString = ConsString::cast(string); + PushLeft(consString); + } + } + UNREACHABLE(); + return NULL; } @@ -6512,8 +7164,8 @@ void String::ReadBlockIntoBuffer(String* input, switch (StringShape(input).representation_tag()) { case kSeqStringTag: - if (input->IsAsciiRepresentation()) { - SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb, + if (input->IsOneByteRepresentation()) { + SeqOneByteString::cast(input)->SeqOneByteStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); return; @@ -6529,7 +7181,7 @@ void String::ReadBlockIntoBuffer(String* input, max_chars); return; case kExternalStringTag: - if (input->IsAsciiRepresentation()) { + if (input->IsOneByteRepresentation()) { ExternalAsciiString::cast(input)-> ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars); } else { @@ -6714,7 +7366,7 @@ void String::WriteToFlat(String* src, while (true) { ASSERT(0 <= from && from <= to && to <= source->length()); switch (StringShape(source).full_representation_tag()) { - case kAsciiStringTag | kExternalStringTag: { + case kOneByteStringTag | kExternalStringTag: { CopyChars(sink, ExternalAsciiString::cast(source)->GetChars() + from, to - from); @@ -6728,9 +7380,9 @@ void String::WriteToFlat(String* src, to - from); return; } - case kAsciiStringTag | kSeqStringTag: { + case kOneByteStringTag | kSeqStringTag: { CopyChars(sink, - SeqAsciiString::cast(source)->GetChars() + from, + SeqOneByteString::cast(source)->GetChars() + from, to - from); return; } @@ -6740,7 +7392,7 @@ void String::WriteToFlat(String* src, to - from); return; } - case kAsciiStringTag | kConsStringTag: + case kOneByteStringTag | kConsStringTag: case kTwoByteStringTag | kConsStringTag: { ConsString* cons_string = ConsString::cast(source); String* first = cons_string->first(); @@ -6765,9 +7417,9 @@ void String::WriteToFlat(String* src, // common case of sequential ascii right child. if (to - boundary == 1) { sink[boundary - from] = static_cast<sinkchar>(second->Get(0)); - } else if (second->IsSeqAsciiString()) { + } else if (second->IsSeqOneByteString()) { CopyChars(sink + boundary - from, - SeqAsciiString::cast(second)->GetChars(), + SeqOneByteString::cast(second)->GetChars(), to - boundary); } else { WriteToFlat(second, @@ -6781,7 +7433,7 @@ void String::WriteToFlat(String* src, } break; } - case kAsciiStringTag | kSlicedStringTag: + case kOneByteStringTag | kSlicedStringTag: case kTwoByteStringTag | kSlicedStringTag: { SlicedString* slice = SlicedString::cast(source); unsigned offset = slice->offset(); @@ -6906,8 +7558,8 @@ bool String::SlowEquals(String* other) { if (StringShape(lhs).IsSequentialAscii() && StringShape(rhs).IsSequentialAscii()) { - const char* str1 = SeqAsciiString::cast(lhs)->GetChars(); - const char* str2 = SeqAsciiString::cast(rhs)->GetChars(); + const char* str1 = SeqOneByteString::cast(lhs)->GetChars(); + const char* str2 = SeqOneByteString::cast(rhs)->GetChars(); return CompareRawStringContents(Vector<const char>(str1, len), Vector<const char>(str2, len)); } @@ -7035,7 +7687,7 @@ uint32_t String::ComputeAndSetHash() { // Compute the hash code. uint32_t field = 0; if (StringShape(this).IsSequentialAscii()) { - field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), + field = HashSequentialString(SeqOneByteString::cast(this)->GetChars(), len, GetHeap()->HashSeed()); } else if (StringShape(this).IsSequentialTwoByte()) { @@ -7103,6 +7755,36 @@ bool String::SlowAsArrayIndex(uint32_t* index) { } +String* SeqString::Truncate(int new_length) { + Heap* heap = GetHeap(); + if (new_length <= 0) return heap->empty_string(); + + int string_size, allocated_string_size; + int old_length = length(); + if (old_length <= new_length) return this; + + if (IsSeqOneByteString()) { + allocated_string_size = SeqOneByteString::SizeFor(old_length); + string_size = SeqOneByteString::SizeFor(new_length); + } else { + allocated_string_size = SeqTwoByteString::SizeFor(old_length); + string_size = SeqTwoByteString::SizeFor(new_length); + } + + int delta = allocated_string_size - string_size; + set_length(new_length); + + // String sizes are pointer size aligned, so that we can use filler objects + // that are a multiple of pointer size. + Address end_of_string = address() + string_size; + heap->CreateFillerObjectAt(end_of_string, delta); + if (Marking::IsBlack(Marking::MarkBitFrom(this))) { + MemoryChunk::IncrementLiveBytesFromMutator(address(), -delta); + } + return this; +} + + uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) { // For array indexes mix the length into the hash as an array index could // be zero. @@ -7138,7 +7820,6 @@ void StringHasher::AddSurrogatePairNoIndex(uc32 c) { uint32_t StringHasher::GetHashField() { - ASSERT(is_valid()); if (length_ <= String::kMaxHashCalcLength) { if (is_array_index()) { return MakeArrayIndexHash(array_index(), length_); @@ -7193,13 +7874,46 @@ void String::PrintOn(FILE* file) { } +static void TrimEnumCache(Heap* heap, Map* map, DescriptorArray* descriptors) { + int live_enum = map->EnumLength(); + if (live_enum == Map::kInvalidEnumCache) { + live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM); + } + if (live_enum == 0) return descriptors->ClearEnumCache(); + + FixedArray* enum_cache = descriptors->GetEnumCache(); + + int to_trim = enum_cache->length() - live_enum; + if (to_trim <= 0) return; + RightTrimFixedArray<FROM_GC>(heap, descriptors->GetEnumCache(), to_trim); + + if (!descriptors->HasEnumIndicesCache()) return; + FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache(); + RightTrimFixedArray<FROM_GC>(heap, enum_indices_cache, to_trim); +} + + +static void TrimDescriptorArray(Heap* heap, + Map* map, + DescriptorArray* descriptors, + int number_of_own_descriptors) { + int number_of_descriptors = descriptors->number_of_descriptors(); + int to_trim = number_of_descriptors - number_of_own_descriptors; + if (to_trim <= 0) return; + + RightTrimFixedArray<FROM_GC>(heap, descriptors, to_trim); + descriptors->SetNumberOfDescriptors(number_of_own_descriptors); + + if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors); + descriptors->Sort(); +} + + // 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. -static bool ClearBackPointer(Heap* heap, Object* target) { - ASSERT(target->IsMap()); - Map* map = Map::cast(target); - if (Marking::MarkBitFrom(map).Get()) return false; - map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); +static bool ClearBackPointer(Heap* heap, Map* target) { + if (Marking::MarkBitFrom(target).Get()) return false; + target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); return true; } @@ -7218,9 +7932,17 @@ void Map::ClearNonLiveTransitions(Heap* heap) { int transition_index = 0; + DescriptorArray* descriptors = instance_descriptors(); + bool descriptors_owner_died = false; + // Compact all live descriptors to the left. for (int i = 0; i < t->number_of_transitions(); ++i) { - if (!ClearBackPointer(heap, t->GetTarget(i))) { + Map* target = t->GetTarget(i); + if (ClearBackPointer(heap, target)) { + if (target->instance_descriptors() == descriptors) { + descriptors_owner_died = true; + } + } else { if (i != transition_index) { String* key = t->GetKey(i); t->SetKey(transition_index, key); @@ -7235,6 +7957,9 @@ void Map::ClearNonLiveTransitions(Heap* heap) { if (t->HasElementsTransition() && ClearBackPointer(heap, t->elements_transition())) { + if (t->elements_transition()->instance_descriptors() == descriptors) { + descriptors_owner_died = true; + } t->ClearElementsTransition(); } else { // If there are no transitions to be cleared, return. @@ -7243,19 +7968,21 @@ void Map::ClearNonLiveTransitions(Heap* heap) { if (transition_index == t->number_of_transitions()) return; } - // If the final transition array does not contain any live transitions, remove - // the transition array from the map. - if (transition_index == 0 && - !t->HasElementsTransition() && - !t->HasPrototypeTransitions() && - t->descriptors()->IsEmpty()) { - return ClearTransitions(heap); + int number_of_own_descriptors = NumberOfOwnDescriptors(); + + if (descriptors_owner_died) { + if (number_of_own_descriptors > 0) { + TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors); + ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors); + } else { + ASSERT(descriptors == GetHeap()->empty_descriptor_array()); + } } int trim = t->number_of_transitions() - transition_index; if (trim > 0) { - RightTrimFixedArray<FROM_GC>( - heap, t, trim * TransitionArray::kTransitionSize); + RightTrimFixedArray<FROM_GC>(heap, t, t->IsSimpleTransition() + ? trim : trim * TransitionArray::kTransitionSize); } } @@ -7289,6 +8016,7 @@ bool Map::EquivalentToForNormalization(Map* other, instance_type() == other->instance_type() && bit_field() == other->bit_field() && bit_field2() == other->bit_field2() && + is_observed() == other->is_observed() && function_with_prototype() == other->function_with_prototype(); } @@ -7469,6 +8197,35 @@ MaybeObject* JSObject::OptimizeAsPrototype() { } +MUST_USE_RESULT static MaybeObject* CacheInitialJSArrayMaps( + Context* native_context, Map* initial_map) { + // Replace all of the cached initial array maps in the native context with + // the appropriate transitioned elements kind maps. + Heap* heap = native_context->GetHeap(); + MaybeObject* maybe_maps = + heap->AllocateFixedArrayWithHoles(kElementsKindCount); + FixedArray* maps; + if (!maybe_maps->To(&maps)) return maybe_maps; + + Map* current_map = initial_map; + ElementsKind kind = current_map->elements_kind(); + ASSERT(kind == GetInitialFastElementsKind()); + maps->set(kind, current_map); + for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1; + i < kFastElementsKindCount; ++i) { + Map* new_map; + ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i); + MaybeObject* maybe_new_map = + current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION); + if (!maybe_new_map->To(&new_map)) return maybe_new_map; + maps->set(next_kind, new_map); + current_map = new_map; + } + native_context->set_js_array_maps(maps); + return initial_map; +} + + MaybeObject* JSFunction::SetInstancePrototype(Object* value) { ASSERT(value->IsJSReceiver()); Heap* heap = GetHeap(); @@ -7483,14 +8240,29 @@ MaybeObject* JSFunction::SetInstancePrototype(Object* value) { // Now some logic for the maps of the objects that are created by using this // function as a constructor. if (has_initial_map()) { - // If the function has allocated the initial map - // replace it with a copy containing the new prototype. + // If the function has allocated the initial map replace it with a + // copy containing the new prototype. Also complete any in-object + // slack tracking that is in progress at this point because it is + // still tracking the old copy. + if (shared()->IsInobjectSlackTrackingInProgress()) { + shared()->CompleteInobjectSlackTracking(); + } Map* new_map; - MaybeObject* maybe_new_map = initial_map()->Copy(); - if (!maybe_new_map->To(&new_map)) return maybe_new_map; + MaybeObject* maybe_object = initial_map()->Copy(); + if (!maybe_object->To(&new_map)) return maybe_object; new_map->set_prototype(value); - MaybeObject* maybe_object = set_initial_map_and_cache_transitions(new_map); - if (maybe_object->IsFailure()) return maybe_object; + + // If the function is used as the global Array function, cache the + // initial map (and transitioned versions) in the native context. + Context* native_context = context()->native_context(); + Object* array_function = native_context->get(Context::ARRAY_FUNCTION_INDEX); + if (array_function->IsJSFunction() && + this == JSFunction::cast(array_function)) { + MaybeObject* ok = CacheInitialJSArrayMaps(native_context, new_map); + if (ok->IsFailure()) return ok; + } + + set_initial_map(new_map); } else { // Put the value in the initial map field until an initial map is // needed. At that point, a new initial map is created and the @@ -7875,7 +8647,7 @@ void SharedFunctionInfo::DetachInitialMap() { // constructor is called. The countdown will continue and (possibly after // several more GCs) CompleteInobjectSlackTracking will eventually be called. Heap* heap = map->GetHeap(); - set_initial_map(heap->raw_unchecked_undefined_value()); + set_initial_map(heap->undefined_value()); Builtins* builtins = heap->isolate()->builtins(); ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), *RawField(this, kConstructStubOffset)); @@ -8003,6 +8775,15 @@ void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { } +void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) { + ASSERT(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); + Object* stub = rinfo->code_age_stub(); + if (stub) { + VisitPointer(&stub); + } +} + + void ObjectVisitor::VisitCodeEntry(Address entry_address) { Object* code = Code::GetObjectFromEntryAddress(entry_address); Object* old_code = code; @@ -8197,6 +8978,7 @@ void Code::ClearInlineCaches() { void Code::ClearTypeFeedbackCells(Heap* heap) { + if (kind() != FUNCTION) return; Object* raw_info = type_feedback_info(); if (raw_info->IsTypeFeedbackInfo()) { TypeFeedbackCells* type_feedback_cells = @@ -8211,7 +8993,92 @@ void Code::ClearTypeFeedbackCells(Heap* heap) { bool Code::allowed_in_shared_map_code_cache() { return is_keyed_load_stub() || is_keyed_store_stub() || - (is_compare_ic_stub() && compare_state() == CompareIC::KNOWN_OBJECTS); + (is_compare_ic_stub() && + ICCompareStub::CompareState(stub_info()) == CompareIC::KNOWN_OBJECTS); +} + + +void Code::MakeCodeAgeSequenceYoung(byte* sequence) { + PatchPlatformCodeAge(sequence, kNoAge, NO_MARKING_PARITY); +} + + +void Code::MakeOlder(MarkingParity current_parity) { + byte* sequence = FindCodeAgeSequence(); + if (sequence != NULL) { + Age age; + MarkingParity code_parity; + GetCodeAgeAndParity(sequence, &age, &code_parity); + if (age != kLastCodeAge && code_parity != current_parity) { + PatchPlatformCodeAge(sequence, static_cast<Age>(age + 1), + current_parity); + } + } +} + + +bool Code::IsOld() { + byte* sequence = FindCodeAgeSequence(); + if (sequence == NULL) return false; + Age age; + MarkingParity parity; + GetCodeAgeAndParity(sequence, &age, &parity); + return age >= kSexagenarianCodeAge; +} + + +byte* Code::FindCodeAgeSequence() { + return FLAG_age_code && + prologue_offset() != kPrologueOffsetNotSet && + (kind() == OPTIMIZED_FUNCTION || + (kind() == FUNCTION && !has_debug_break_slots())) + ? instruction_start() + prologue_offset() + : NULL; +} + + +void Code::GetCodeAgeAndParity(Code* code, Age* age, + MarkingParity* parity) { + Isolate* isolate = Isolate::Current(); + Builtins* builtins = isolate->builtins(); + Code* stub = NULL; +#define HANDLE_CODE_AGE(AGE) \ + stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \ + if (code == stub) { \ + *age = k##AGE##CodeAge; \ + *parity = EVEN_MARKING_PARITY; \ + return; \ + } \ + stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \ + if (code == stub) { \ + *age = k##AGE##CodeAge; \ + *parity = ODD_MARKING_PARITY; \ + return; \ + } + CODE_AGE_LIST(HANDLE_CODE_AGE) +#undef HANDLE_CODE_AGE + UNREACHABLE(); +} + + +Code* Code::GetCodeAgeStub(Age age, MarkingParity parity) { + Isolate* isolate = Isolate::Current(); + Builtins* builtins = isolate->builtins(); + switch (age) { +#define HANDLE_CODE_AGE(AGE) \ + case k##AGE##CodeAge: { \ + Code* stub = parity == EVEN_MARKING_PARITY \ + ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \ + : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \ + return stub; \ + } + CODE_AGE_LIST(HANDLE_CODE_AGE) +#undef HANDLE_CODE_AGE + default: + UNREACHABLE(); + break; + } + return NULL; } @@ -8473,11 +9340,15 @@ void Code::Disassemble(const char* name, FILE* out) { 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); + ASSERT(major_key() == CodeStub::CompareIC); + CompareIC::State left_state, right_state, handler_state; + Token::Value op; + ICCompareStub::DecodeMinorKey(stub_info(), &left_state, &right_state, + &handler_state, &op); + PrintF(out, "compare_state = %s*%s -> %s\n", + CompareIC::GetStateName(left_state), + CompareIC::GetStateName(right_state), + CompareIC::GetStateName(handler_state)); PrintF(out, "compare_operation = %s\n", Token::Name(op)); } } @@ -8523,8 +9394,6 @@ void Code::Disassemble(const char* name, FILE* out) { PrintF(out, "\n"); } PrintF(out, "\n"); - // Just print if type feedback info is ever used for optimized code. - ASSERT(type_feedback_info()->IsUndefined()); } else if (kind() == FUNCTION) { unsigned offset = stack_check_table_offset(); // If there is no stack check table, the "table start" will at or after @@ -8566,9 +9435,8 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength( // Allocate a new fast elements backing store. FixedArray* new_elements; - { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity); - if (!maybe->To(&new_elements)) return maybe; - } + MaybeObject* maybe = heap->AllocateUninitializedFixedArray(capacity); + if (!maybe->To(&new_elements)) return maybe; ElementsKind elements_kind = GetElementsKind(); ElementsKind new_elements_kind; @@ -8592,10 +9460,10 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength( } FixedArrayBase* old_elements = elements(); ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind); - { MaybeObject* maybe_obj = - accessor->CopyElements(this, new_elements, new_elements_kind); - if (maybe_obj->IsFailure()) return maybe_obj; - } + MaybeObject* maybe_obj = + accessor->CopyElements(this, new_elements, new_elements_kind); + if (maybe_obj->IsFailure()) return maybe_obj; + if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) { Map* new_map = map(); if (new_elements_kind != elements_kind) { @@ -8701,7 +9569,53 @@ void JSArray::Expand(int required_size) { MaybeObject* JSArray::SetElementsLength(Object* len) { // We should never end in here with a pixel or external array. ASSERT(AllowsSetElementsLength()); - return GetElementsAccessor()->SetLength(this, len); + if (!(FLAG_harmony_observation && map()->is_observed())) + return GetElementsAccessor()->SetLength(this, len); + + Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); + Handle<JSArray> self(this); + List<Handle<String> > indices; + List<Handle<Object> > old_values; + Handle<Object> old_length_handle(self->length()); + Handle<Object> new_length_handle(len); + uint32_t old_length = 0; + CHECK(old_length_handle->ToArrayIndex(&old_length)); + uint32_t new_length = 0; + if (!new_length_handle->ToArrayIndex(&new_length)) + return Failure::InternalError(); + + // TODO(adamk): This loop can be very slow for arrays in dictionary mode. + // Find another way to iterate over arrays with dictionary elements. + for (uint32_t i = old_length - 1; i + 1 > new_length; --i) { + PropertyAttributes attributes = self->GetLocalElementAttribute(i); + if (attributes == ABSENT) continue; + // A non-configurable property will cause the truncation operation to + // stop at this index. + if (attributes == DONT_DELETE) break; + old_values.Add( + self->GetLocalElementAccessorPair(i) == NULL + ? Object::GetElement(self, i) + : Handle<Object>::cast(isolate->factory()->the_hole_value())); + indices.Add(isolate->factory()->Uint32ToString(i)); + } + + MaybeObject* result = + self->GetElementsAccessor()->SetLength(*self, *new_length_handle); + Handle<Object> hresult; + if (!result->ToHandle(&hresult, isolate)) return result; + + CHECK(self->length()->ToArrayIndex(&new_length)); + if (old_length != new_length) { + for (int i = 0; i < indices.length(); ++i) { + JSObject::EnqueueChangeRecord( + self, "deleted", indices[i], old_values[i]); + } + JSObject::EnqueueChangeRecord( + self, "updated", isolate->factory()->length_symbol(), + old_length_handle); + } + return *hresult; } @@ -8765,6 +9679,22 @@ MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { } +void Map::ZapTransitions() { + TransitionArray* transition_array = transitions(); + MemsetPointer(transition_array->data_start(), + GetHeap()->the_hole_value(), + transition_array->length()); +} + + +void Map::ZapPrototypeTransitions() { + FixedArray* proto_transitions = GetPrototypeTransitions(); + MemsetPointer(proto_transitions->data_start(), + GetHeap()->the_hole_value(), + proto_transitions->length()); +} + + MaybeObject* JSReceiver::SetPrototype(Object* value, bool skip_hidden_prototypes) { #ifdef DEBUG @@ -8862,203 +9792,51 @@ MaybeObject* JSObject::EnsureCanContainElements(Arguments* args, } -bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) { - Isolate* isolate = GetIsolate(); - // Make sure that the top context does not change when doing - // callbacks or interceptor calls. - AssertNoContextChange ncc; - HandleScope scope(isolate); - Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); - Handle<JSReceiver> receiver_handle(receiver); - Handle<JSObject> holder_handle(this); - CustomArguments args(isolate, interceptor->data(), receiver, this); - v8::AccessorInfo info(args.end()); - if (!interceptor->query()->IsUndefined()) { - v8::IndexedPropertyQuery query = - v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query()); - LOG(isolate, - ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); - v8::Handle<v8::Integer> result; - { - // Leaving JavaScript. - VMState state(isolate, EXTERNAL); - result = query(index, info); - } - if (!result.IsEmpty()) { - ASSERT(result->IsInt32()); - return true; // absence of property is signaled by empty handle. - } - } else if (!interceptor->getter()->IsUndefined()) { - v8::IndexedPropertyGetter getter = - v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); - LOG(isolate, - ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index)); - v8::Handle<v8::Value> result; - { - // Leaving JavaScript. - VMState state(isolate, EXTERNAL); - result = getter(index, info); - } - if (!result.IsEmpty()) return true; +PropertyType JSObject::GetLocalPropertyType(String* name) { + uint32_t index = 0; + if (name->AsArrayIndex(&index)) { + return GetLocalElementType(index); } + LookupResult lookup(GetIsolate()); + LocalLookup(name, &lookup, true); + return lookup.type(); +} - if (holder_handle->GetElementsAccessor()->HasElement( - *receiver_handle, *holder_handle, index)) { - return true; - } - if (holder_handle->IsStringObjectWithCharacterAt(index)) return true; - Object* pt = holder_handle->GetPrototype(); - if (pt->IsJSProxy()) { - // We need to follow the spec and simulate a call to [[GetOwnProperty]]. - return JSProxy::cast(pt)->GetElementAttributeWithHandler( - receiver, index) != ABSENT; - } - if (pt->IsNull()) return false; - return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index); +PropertyType JSObject::GetLocalElementType(uint32_t index) { + return GetElementsAccessor()->GetType(this, this, index); } -JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) { - // Check access rights if needed. - if (IsAccessCheckNeeded()) { - Heap* heap = GetHeap(); - if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { - heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); - return UNDEFINED_ELEMENT; - } - } - - if (IsJSGlobalProxy()) { - Object* proto = GetPrototype(); - if (proto->IsNull()) return UNDEFINED_ELEMENT; - ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->HasLocalElement(index); +AccessorPair* JSObject::GetLocalPropertyAccessorPair(String* name) { + uint32_t index = 0; + if (name->AsArrayIndex(&index)) { + return GetLocalElementAccessorPair(index); } - // Check for lookup interceptor - if (HasIndexedInterceptor()) { - return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT - : UNDEFINED_ELEMENT; - } + LookupResult lookup(GetIsolate()); + LocalLookupRealNamedProperty(name, &lookup); - // Handle [] on String objects. - if (this->IsStringObjectWithCharacterAt(index)) { - return STRING_CHARACTER_ELEMENT; - } - - switch (GetElementsKind()) { - case FAST_SMI_ELEMENTS: - case FAST_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_HOLEY_ELEMENTS: { - uint32_t length = IsJSArray() ? - static_cast<uint32_t> - (Smi::cast(JSArray::cast(this)->length())->value()) : - static_cast<uint32_t>(FixedArray::cast(elements())->length()); - if ((index < length) && - !FixedArray::cast(elements())->get(index)->IsTheHole()) { - return FAST_ELEMENT; - } - break; - } - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: { - uint32_t length = IsJSArray() ? - static_cast<uint32_t> - (Smi::cast(JSArray::cast(this)->length())->value()) : - static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length()); - if ((index < length) && - !FixedDoubleArray::cast(elements())->is_the_hole(index)) { - return FAST_ELEMENT; - } - break; - } - case EXTERNAL_PIXEL_ELEMENTS: { - ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); - if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT; - break; - } - case EXTERNAL_BYTE_ELEMENTS: - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - case EXTERNAL_SHORT_ELEMENTS: - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - case EXTERNAL_INT_ELEMENTS: - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - case EXTERNAL_FLOAT_ELEMENTS: - case EXTERNAL_DOUBLE_ELEMENTS: { - ExternalArray* array = ExternalArray::cast(elements()); - if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT; - break; - } - case DICTIONARY_ELEMENTS: { - if (element_dictionary()->FindEntry(index) != - SeededNumberDictionary::kNotFound) { - return DICTIONARY_ELEMENT; - } - break; - } - case NON_STRICT_ARGUMENTS_ELEMENTS: { - // Aliased parameters and non-aliased elements in a fast backing store - // behave as FAST_ELEMENT. Non-aliased elements in a dictionary - // backing store behave as DICTIONARY_ELEMENT. - FixedArray* parameter_map = FixedArray::cast(elements()); - uint32_t length = parameter_map->length(); - Object* probe = - index < (length - 2) ? parameter_map->get(index + 2) : NULL; - if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT; - // If not aliased, check the arguments. - FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); - if (arguments->IsDictionary()) { - SeededNumberDictionary* dictionary = - SeededNumberDictionary::cast(arguments); - if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) { - return DICTIONARY_ELEMENT; - } - } else { - length = arguments->length(); - probe = (index < length) ? arguments->get(index) : NULL; - if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT; - } - break; - } + if (lookup.IsPropertyCallbacks() && + lookup.GetCallbackObject()->IsAccessorPair()) { + return AccessorPair::cast(lookup.GetCallbackObject()); } - - return UNDEFINED_ELEMENT; + return NULL; } -bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) { - // Check access rights if needed. - if (IsAccessCheckNeeded()) { - Heap* heap = GetHeap(); - if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { - heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); - return false; - } - } - - // Check for lookup interceptor - if (HasIndexedInterceptor()) { - return HasElementWithInterceptor(receiver, index); - } - - ElementsAccessor* accessor = GetElementsAccessor(); - if (accessor->HasElement(receiver, this, index)) { - return true; +AccessorPair* JSObject::GetLocalElementAccessorPair(uint32_t index) { + if (IsJSGlobalProxy()) { + Object* proto = GetPrototype(); + if (proto->IsNull()) return NULL; + ASSERT(proto->IsJSGlobalObject()); + return JSObject::cast(proto)->GetLocalElementAccessorPair(index); } - // Handle [] on String objects. - if (this->IsStringObjectWithCharacterAt(index)) return true; + // Check for lookup interceptor. + if (HasIndexedInterceptor()) return NULL; - Object* pt = GetPrototype(); - if (pt->IsNull()) return false; - if (pt->IsJSProxy()) { - // We need to follow the spec and simulate a call to [[GetOwnProperty]]. - return JSProxy::cast(pt)->GetElementAttributeWithHandler( - receiver, index) != ABSENT; - } - return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); + return GetElementsAccessor()->GetAccessorPair(this, this, index); } @@ -9367,7 +10145,7 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, MaybeObject* JSObject::SetDictionaryElement(uint32_t index, - Object* value, + Object* value_raw, PropertyAttributes attributes, StrictModeFlag strict_mode, bool check_prototype, @@ -9375,24 +10153,23 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); Isolate* isolate = GetIsolate(); Heap* heap = isolate->heap(); + Handle<JSObject> self(this); + Handle<Object> value(value_raw); // Insert element in the dictionary. - FixedArray* elements = FixedArray::cast(this->elements()); + Handle<FixedArray> elements(FixedArray::cast(this->elements())); bool is_arguments = (elements->map() == heap->non_strict_arguments_elements_map()); - SeededNumberDictionary* dictionary = NULL; - if (is_arguments) { - dictionary = SeededNumberDictionary::cast(elements->get(1)); - } else { - dictionary = SeededNumberDictionary::cast(elements); - } + Handle<SeededNumberDictionary> dictionary(is_arguments + ? SeededNumberDictionary::cast(elements->get(1)) + : SeededNumberDictionary::cast(*elements)); int entry = dictionary->FindEntry(index); if (entry != SeededNumberDictionary::kNotFound) { Object* element = dictionary->ValueAt(entry); PropertyDetails details = dictionary->DetailsAt(entry); if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) { - return SetElementWithCallback(element, index, value, this, strict_mode); + return SetElementWithCallback(element, index, *value, this, strict_mode); } else { dictionary->UpdateMaxNumberKey(index); // If a value has not been initialized we allow writing to it even if it @@ -9421,24 +10198,24 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, Context* context = Context::cast(elements->get(0)); int context_index = entry->aliased_context_slot(); ASSERT(!context->get(context_index)->IsTheHole()); - context->set(context_index, value); + context->set(context_index, *value); // For elements that are still writable we keep slow aliasing. - if (!details.IsReadOnly()) value = element; + if (!details.IsReadOnly()) value = handle(element, isolate); } - dictionary->ValueAtPut(entry, value); + dictionary->ValueAtPut(entry, *value); } } else { // Index not already used. Look for an accessor in the prototype chain. + // Can cause GC! if (check_prototype) { bool found; - MaybeObject* result = - SetElementWithCallbackSetterInPrototypes( - index, value, &found, strict_mode); + MaybeObject* result = SetElementWithCallbackSetterInPrototypes( + index, *value, &found, strict_mode); if (found) return result; } // When we set the is_extensible flag to false we always force the // element into dictionary mode (and force them to stay there). - if (!map()->is_extensible()) { + if (!self->map()->is_extensible()) { if (strict_mode == kNonStrictMode) { return isolate->heap()->undefined_value(); } else { @@ -9453,30 +10230,31 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, } FixedArrayBase* new_dictionary; PropertyDetails details = PropertyDetails(attributes, NORMAL); - MaybeObject* maybe = dictionary->AddNumberEntry(index, value, details); + MaybeObject* maybe = dictionary->AddNumberEntry(index, *value, details); if (!maybe->To(&new_dictionary)) return maybe; - if (dictionary != SeededNumberDictionary::cast(new_dictionary)) { + if (*dictionary != SeededNumberDictionary::cast(new_dictionary)) { if (is_arguments) { elements->set(1, new_dictionary); } else { - set_elements(new_dictionary); + self->set_elements(new_dictionary); } - dictionary = SeededNumberDictionary::cast(new_dictionary); + dictionary = + handle(SeededNumberDictionary::cast(new_dictionary), isolate); } } // Update the array length if this JSObject is an array. - if (IsJSArray()) { + if (self->IsJSArray()) { MaybeObject* result = - JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value); + JSArray::cast(*self)->JSArrayUpdateLengthFromIndex(index, *value); if (result->IsFailure()) return result; } // Attempt to put this object back in fast case. - if (ShouldConvertToFastElements()) { + if (self->ShouldConvertToFastElements()) { uint32_t new_length = 0; - if (IsJSArray()) { - CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); + if (self->IsJSArray()) { + CHECK(JSArray::cast(*self)->length()->ToArrayIndex(&new_length)); } else { new_length = dictionary->max_number_key() + 1; } @@ -9485,16 +10263,15 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, : kDontAllowSmiElements; bool has_smi_only_elements = false; bool should_convert_to_fast_double_elements = - ShouldConvertToFastDoubleElements(&has_smi_only_elements); + self->ShouldConvertToFastDoubleElements(&has_smi_only_elements); if (has_smi_only_elements) { smi_mode = kForceSmiElements; } MaybeObject* result = should_convert_to_fast_double_elements - ? SetFastDoubleElementsCapacityAndLength(new_length, new_length) - : SetFastElementsCapacityAndLength(new_length, - new_length, - smi_mode); - ValidateElements(); + ? self->SetFastDoubleElementsCapacityAndLength(new_length, new_length) + : self->SetFastElementsCapacityAndLength( + new_length, new_length, smi_mode); + self->ValidateElements(); if (result->IsFailure()) return result; #ifdef DEBUG if (FLAG_trace_normalization) { @@ -9503,7 +10280,7 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, } #endif } - return value; + return *value; } @@ -9659,28 +10436,27 @@ Handle<Object> JSObject::SetElement(Handle<JSObject> object, MaybeObject* JSObject::SetElement(uint32_t index, - Object* value, + Object* value_raw, PropertyAttributes attributes, StrictModeFlag strict_mode, bool check_prototype, SetPropertyMode set_mode) { + Isolate* isolate = GetIsolate(); + // Check access rights if needed. if (IsAccessCheckNeeded()) { - Heap* heap = GetHeap(); - if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { - HandleScope scope(heap->isolate()); - Handle<Object> value_handle(value); - heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); - return *value_handle; + if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_SET)) { + isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); + return value_raw; } } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); - if (proto->IsNull()) return value; + if (proto->IsNull()) return value_raw; ASSERT(proto->IsJSGlobalObject()); return JSObject::cast(proto)->SetElement(index, - value, + value_raw, attributes, strict_mode, check_prototype, @@ -9689,10 +10465,8 @@ MaybeObject* JSObject::SetElement(uint32_t index, // Don't allow element properties to be redefined for external arrays. if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) { - Isolate* isolate = GetHeap()->isolate(); - Handle<Object> receiver(this); Handle<Object> number = isolate->factory()->NewNumberFromUint(index); - Handle<Object> args[] = { receiver, number }; + Handle<Object> args[] = { handle(this, isolate), number }; Handle<Object> error = isolate->factory()->NewTypeError( "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args))); return isolate->Throw(*error); @@ -9707,22 +10481,55 @@ MaybeObject* JSObject::SetElement(uint32_t index, dictionary->set_requires_slow_elements(); } + if (!(FLAG_harmony_observation && map()->is_observed())) { + return HasIndexedInterceptor() + ? SetElementWithInterceptor( + index, value_raw, attributes, strict_mode, check_prototype, set_mode) + : SetElementWithoutInterceptor( + index, value_raw, attributes, strict_mode, check_prototype, set_mode); + } + + // From here on, everything has to be handlified. + Handle<JSObject> self(this); + Handle<Object> value(value_raw); + PropertyAttributes old_attributes = self->GetLocalElementAttribute(index); + Handle<Object> old_value = isolate->factory()->the_hole_value(); + Handle<Object> old_length; + + if (old_attributes != ABSENT) { + if (self->GetLocalElementAccessorPair(index) == NULL) + old_value = Object::GetElement(self, index); + } else if (self->IsJSArray()) { + // Store old array length in case adding an element grows the array. + old_length = handle(Handle<JSArray>::cast(self)->length(), isolate); + } + // Check for lookup interceptor - if (HasIndexedInterceptor()) { - return SetElementWithInterceptor(index, - value, - attributes, - strict_mode, - check_prototype, - set_mode); + MaybeObject* result = self->HasIndexedInterceptor() + ? self->SetElementWithInterceptor( + index, *value, attributes, strict_mode, check_prototype, set_mode) + : self->SetElementWithoutInterceptor( + index, *value, attributes, strict_mode, check_prototype, set_mode); + + Handle<Object> hresult; + if (!result->ToHandle(&hresult, isolate)) return result; + + Handle<String> name = isolate->factory()->Uint32ToString(index); + PropertyAttributes new_attributes = self->GetLocalElementAttribute(index); + if (old_attributes == ABSENT) { + EnqueueChangeRecord(self, "new", name, old_value); + if (self->IsJSArray() && + !old_length->SameValue(Handle<JSArray>::cast(self)->length())) { + EnqueueChangeRecord( + self, "updated", isolate->factory()->length_symbol(), old_length); + } + } else if (old_attributes != new_attributes || old_value->IsTheHole()) { + EnqueueChangeRecord(self, "reconfigured", name, old_value); + } else if (!old_value->SameValue(*Object::GetElement(self, index))) { + EnqueueChangeRecord(self, "updated", name, old_value); } - return SetElementWithoutInterceptor(index, - value, - attributes, - strict_mode, - check_prototype, - set_mode); + return *hresult; } @@ -9838,6 +10645,8 @@ MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) { to_kind = GetHoleyElementsKind(to_kind); } + if (from_kind == to_kind) return this; + Isolate* isolate = GetIsolate(); if (elements() == isolate->heap()->empty_fixed_array() || (IsFastSmiOrObjectElementsKind(from_kind) && @@ -10372,9 +11181,16 @@ bool JSObject::HasRealNamedCallbackProperty(String* key) { int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { - return HasFastProperties() ? - map()->NumberOfDescribedProperties(filter) : - property_dictionary()->NumberOfElementsFilterAttributes(filter); + if (HasFastProperties()) { + Map* map = this->map(); + if (filter == NONE) return map->NumberOfOwnDescriptors(); + if (filter == DONT_ENUM) { + int result = map->EnumLength(); + if (result != Map::kInvalidEnumCache) return result; + } + return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter); + } + return property_dictionary()->NumberOfElementsFilterAttributes(filter); } @@ -10497,9 +11313,10 @@ void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) { void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { ASSERT(storage->length() >= (NumberOfLocalProperties() - index)); if (HasFastProperties()) { + int real_size = map()->NumberOfOwnDescriptors(); DescriptorArray* descs = map()->instance_descriptors(); - ASSERT(storage->length() >= index + descs->number_of_descriptors()); - for (int i = 0; i < descs->number_of_descriptors(); i++) { + ASSERT(storage->length() >= index + real_size); + for (int i = 0; i < real_size; i++) { storage->set(index + i, descs->GetKey(i)); } } else { @@ -10931,11 +11748,10 @@ class AsciiSymbolKey : public SequentialSymbolKey<char> { class SubStringAsciiSymbolKey : public HashTableKey { public: - explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string, + explicit SubStringAsciiSymbolKey(Handle<SeqOneByteString> string, int from, - int length, - uint32_t seed) - : string_(string), from_(from), length_(length), seed_(seed) { } + int length) + : string_(string), from_(from), length_(length) { } uint32_t Hash() { ASSERT(length_ >= 0); @@ -10952,7 +11768,7 @@ class SubStringAsciiSymbolKey : public HashTableKey { // chance this is an array index. while (i < length_ && hasher.is_array_index()) { hasher.AddCharacter(static_cast<uc32>( - string_->SeqAsciiStringGet(i + from_))); + string_->SeqOneByteStringGet(i + from_))); i++; } @@ -10960,7 +11776,7 @@ class SubStringAsciiSymbolKey : public HashTableKey { // index. while (i < length_) { hasher.AddCharacterNoIndex(static_cast<uc32>( - string_->SeqAsciiStringGet(i + from_))); + string_->SeqOneByteStringGet(i + from_))); i++; } hash_field_ = hasher.GetHashField(); @@ -10988,11 +11804,10 @@ class SubStringAsciiSymbolKey : public HashTableKey { } private: - Handle<SeqAsciiString> string_; + Handle<SeqOneByteString> string_; int from_; int length_; uint32_t hash_field_; - uint32_t seed_; }; @@ -11827,7 +12642,7 @@ class TwoCharHashTableKey : public HashTableKey { hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; - if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash; + if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash; #ifdef DEBUG StringHasher hasher(2, seed); hasher.AddCharacter(c1); @@ -11913,11 +12728,12 @@ MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str, } -MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str, - int from, - int length, - Object** s) { - SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed()); +MaybeObject* SymbolTable::LookupSubStringAsciiSymbol( + Handle<SeqOneByteString> str, + int from, + int length, + Object** s) { + SubStringAsciiSymbolKey key(str, from, length); return LookupKey(&key, s); } @@ -12202,8 +13018,8 @@ MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() { int pos = 0; for (int i = 0; i < capacity; i++) { if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { - enumeration_order->set( - pos++, Smi::FromInt(DetailsAt(i).dictionary_index())); + int index = DetailsAt(i).dictionary_index(); + enumeration_order->set(pos++, Smi::FromInt(index)); } } @@ -12332,7 +13148,8 @@ MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key, uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash); // Insert element at empty or deleted entry if (!details.IsDeleted() && - details.dictionary_index() == 0 && Shape::kIsEnumerable) { + details.dictionary_index() == 0 && + Shape::kIsEnumerable) { // Assign an enumeration index to the property and update // SetNextEnumerationIndex. int index = NextEnumerationIndex(); @@ -12604,8 +13421,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor( PropertyType type = DetailsAt(i).type(); ASSERT(type != FIELD); instance_descriptor_length++; - if (type == NORMAL && - (!value->IsJSFunction() || heap->InNewSpace(value))) { + if (type == NORMAL && !value->IsJSFunction()) { number_of_fields += 1; } } @@ -12638,7 +13454,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor( return maybe_descriptors; } - FixedArray::WhitenessWitness witness(descriptors); + DescriptorArray::WhitenessWitness witness(descriptors); int number_of_allocated_fields = number_of_fields + unused_property_fields - inobject_props; @@ -12670,7 +13486,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor( int enumeration_index = details.descriptor_index(); PropertyType type = details.type(); - if (value->IsJSFunction() && !heap->InNewSpace(value)) { + if (value->IsJSFunction()) { ConstantFunctionDescriptor d(key, JSFunction::cast(value), details.attributes(), @@ -12705,8 +13521,7 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor( descriptors->Sort(); - MaybeObject* maybe_failure = new_map->InitializeDescriptors(descriptors); - if (maybe_failure->IsFailure()) return maybe_failure; + new_map->InitializeDescriptors(descriptors); new_map->set_unused_property_fields(unused_property_fields); // Transform the object. diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 18e388f991..701712be32 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -97,7 +97,7 @@ // - ExternalFloatArray // - String // - SeqString -// - SeqAsciiString +// - SeqOneByteString // - SeqTwoByteString // - SlicedString // - ConsString @@ -178,6 +178,35 @@ enum TransitionFlag { }; +// Indicates whether the transition is simple: the target map of the transition +// either extends the current map with a new property, or it modifies the +// property that was added last to the current map. +enum SimpleTransitionFlag { + SIMPLE_TRANSITION, + FULL_TRANSITION +}; + + +// Indicates whether we are only interested in the descriptors of a particular +// map, or in all descriptors in the descriptor array. +enum DescriptorFlag { + ALL_DESCRIPTORS, + OWN_DESCRIPTORS +}; + +// The GC maintains a bit of information, the MarkingParity, which toggles +// from odd to even and back every time marking is completed. Incremental +// marking can visit an object twice during a marking phase, so algorithms that +// that piggy-back on marking can use the parity to ensure that they only +// perform an operation on an object once per marking phase: they record the +// MarkingParity when they visit an object, and only re-visit the object when it +// is marked again and the MarkingParity changes. +enum MarkingParity { + NO_MARKING_PARITY, + ODD_MARKING_PARITY, + EVEN_MARKING_PARITY +}; + // Instance size sentinel for objects of variable size. const int kVariableSizeSentinel = 0; @@ -450,7 +479,7 @@ const uint32_t kSymbolTag = 0x40; // two-byte characters or one-byte characters. const uint32_t kStringEncodingMask = 0x4; const uint32_t kTwoByteStringTag = 0x0; -const uint32_t kAsciiStringTag = 0x4; +const uint32_t kOneByteStringTag = 0x4; // If bit 7 is clear, the low-order 2 bits indicate the representation // of the string. @@ -501,39 +530,46 @@ const uint32_t kShortcutTypeTag = kConsStringTag; enum InstanceType { // String types. SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kSeqStringTag, - ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kSeqStringTag, + ASCII_SYMBOL_TYPE = kOneByteStringTag | kAsciiDataHintTag | kSymbolTag | + kSeqStringTag, CONS_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kConsStringTag, - CONS_ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kConsStringTag, + CONS_ASCII_SYMBOL_TYPE = kOneByteStringTag | kAsciiDataHintTag | kSymbolTag | + kConsStringTag, SHORT_EXTERNAL_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kExternalStringTag | kShortExternalStringTag, SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE = kTwoByteStringTag | kSymbolTag | kExternalStringTag | kAsciiDataHintTag | kShortExternalStringTag, - SHORT_EXTERNAL_ASCII_SYMBOL_TYPE = kAsciiStringTag | kExternalStringTag | - kSymbolTag | kShortExternalStringTag, + SHORT_EXTERNAL_ASCII_SYMBOL_TYPE = kOneByteStringTag | kAsciiDataHintTag | + kExternalStringTag | kSymbolTag | + kShortExternalStringTag, EXTERNAL_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kExternalStringTag, EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE = kTwoByteStringTag | kSymbolTag | kExternalStringTag | kAsciiDataHintTag, EXTERNAL_ASCII_SYMBOL_TYPE = - kAsciiStringTag | kSymbolTag | kExternalStringTag, + kOneByteStringTag | kAsciiDataHintTag | kSymbolTag | kExternalStringTag, STRING_TYPE = kTwoByteStringTag | kSeqStringTag, - ASCII_STRING_TYPE = kAsciiStringTag | kSeqStringTag, + ASCII_STRING_TYPE = kOneByteStringTag | kAsciiDataHintTag | kSeqStringTag, CONS_STRING_TYPE = kTwoByteStringTag | kConsStringTag, - CONS_ASCII_STRING_TYPE = kAsciiStringTag | kConsStringTag, + CONS_ASCII_STRING_TYPE = + kOneByteStringTag | kAsciiDataHintTag | kConsStringTag, SLICED_STRING_TYPE = kTwoByteStringTag | kSlicedStringTag, - SLICED_ASCII_STRING_TYPE = kAsciiStringTag | kSlicedStringTag, + SLICED_ASCII_STRING_TYPE = + kOneByteStringTag | kAsciiDataHintTag | kSlicedStringTag, SHORT_EXTERNAL_STRING_TYPE = kTwoByteStringTag | kExternalStringTag | kShortExternalStringTag, SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE = kTwoByteStringTag | kExternalStringTag | kAsciiDataHintTag | kShortExternalStringTag, SHORT_EXTERNAL_ASCII_STRING_TYPE = - kAsciiStringTag | kExternalStringTag | kShortExternalStringTag, + kOneByteStringTag | kAsciiDataHintTag | + kExternalStringTag | kShortExternalStringTag, EXTERNAL_STRING_TYPE = kTwoByteStringTag | kExternalStringTag, EXTERNAL_STRING_WITH_ASCII_DATA_TYPE = kTwoByteStringTag | kExternalStringTag | kAsciiDataHintTag, // LAST_STRING_TYPE - EXTERNAL_ASCII_STRING_TYPE = kAsciiStringTag | kExternalStringTag, + EXTERNAL_ASCII_STRING_TYPE = + kOneByteStringTag | kAsciiDataHintTag | kExternalStringTag, PRIVATE_EXTERNAL_ASCII_STRING_TYPE = EXTERNAL_ASCII_STRING_TYPE, // Objects allocated in their own spaces (never in new space). @@ -714,6 +750,11 @@ struct ValueInfo : public Malloced { // A template-ized version of the IsXXX functions. template <class C> static inline bool Is(Object* obj); +#ifdef VERIFY_HEAP +#define DECLARE_VERIFIER(Name) void Name##Verify(); +#else +#define DECLARE_VERIFIER(Name) +#endif class MaybeObject BASE_EMBEDDED { public: @@ -732,7 +773,9 @@ class MaybeObject BASE_EMBEDDED { return reinterpret_cast<Failure*>(this); } inline Object* ToObjectUnchecked() { - ASSERT(!IsFailure()); + // TODO(jkummerow): Turn this back into an ASSERT when we can be certain + // that it never fires in Release mode in the wild. + CHECK(!IsFailure()); return reinterpret_cast<Object*>(this); } inline Object* ToObjectChecked() { @@ -747,6 +790,13 @@ class MaybeObject BASE_EMBEDDED { return true; } + template<typename T> + inline bool ToHandle(Handle<T>* obj, Isolate* isolate) { + if (IsFailure()) return false; + *obj = handle(T::cast(reinterpret_cast<Object*>(this)), isolate); + return true; + } + #ifdef OBJECT_PRINT // Prints this object with details. inline void Print() { @@ -758,7 +808,7 @@ class MaybeObject BASE_EMBEDDED { void Print(FILE* out); void PrintLn(FILE* out); #endif -#ifdef DEBUG +#ifdef VERIFY_HEAP // Verifies the object. void Verify(); #endif @@ -781,7 +831,7 @@ class MaybeObject BASE_EMBEDDED { V(ExternalTwoByteString) \ V(ExternalAsciiString) \ V(SeqTwoByteString) \ - V(SeqAsciiString) \ + V(SeqOneByteString) \ \ V(ExternalArray) \ V(ExternalByteArray) \ @@ -844,6 +894,7 @@ class MaybeObject BASE_EMBEDDED { V(UndetectableObject) \ V(AccessCheckNeeded) \ V(JSGlobalPropertyCell) \ + V(ObjectHashTable) \ class JSReceiver; @@ -865,6 +916,7 @@ class Object : public MaybeObject { #undef IS_TYPE_FUNCTION_DECL inline bool IsFixedArrayBase(); + inline bool IsExternal(); // Returns true if this object is an instance of the specified // function template. @@ -923,6 +975,7 @@ class Object : public MaybeObject { String* key, PropertyAttributes* attributes); + static Handle<Object> GetProperty(Handle<Object> object, Handle<String> key); static Handle<Object> GetProperty(Handle<Object> object, Handle<Object> receiver, LookupResult* result, @@ -965,7 +1018,7 @@ class Object : public MaybeObject { // < the length of the string. Used to implement [] on strings. inline bool IsStringObjectWithCharacterAt(uint32_t index); -#ifdef DEBUG +#ifdef VERIFY_HEAP // Verify a pointer is a valid object pointer. static void VerifyPointer(Object* p); #endif @@ -1020,9 +1073,8 @@ class Smi: public Object { } void SmiPrint(FILE* out); void SmiPrint(StringStream* accumulator); -#ifdef DEBUG - void SmiVerify(); -#endif + + DECLARE_VERIFIER(Smi) static const int kMinValue = (static_cast<unsigned int>(-1)) << (kSmiValueSize - 1); @@ -1093,9 +1145,8 @@ class Failure: public MaybeObject { } void FailurePrint(FILE* out); void FailurePrint(StringStream* accumulator); -#ifdef DEBUG - void FailureVerify(); -#endif + + DECLARE_VERIFIER(Failure) private: inline intptr_t value() const; @@ -1226,9 +1277,8 @@ class HeapObject: public Object { void HeapObjectPrint(FILE* out); void PrintHeader(FILE* out, const char* id); #endif - -#ifdef DEBUG - void HeapObjectVerify(); + DECLARE_VERIFIER(HeapObject) +#ifdef VERIFY_HEAP inline void VerifyObjectField(int offset); inline void VerifySmiField(int offset); @@ -1314,9 +1364,7 @@ class HeapNumber: public HeapObject { } void HeapNumberPrint(FILE* out); void HeapNumberPrint(StringStream* accumulator); -#ifdef DEBUG - void HeapNumberVerify(); -#endif + DECLARE_VERIFIER(HeapNumber) inline int get_exponent(); inline int get_sign(); @@ -1445,10 +1493,14 @@ class JSReceiver: public HeapObject { String* name); PropertyAttributes GetLocalPropertyAttribute(String* name); + inline PropertyAttributes GetElementAttribute(uint32_t index); + inline PropertyAttributes GetLocalElementAttribute(uint32_t index); + // Can cause a GC. inline bool HasProperty(String* name); inline bool HasLocalProperty(String* name); inline bool HasElement(uint32_t index); + inline bool HasLocalElement(uint32_t index); // Return the object's prototype (might be Heap::null_value()). inline Object* GetPrototype(); @@ -1466,17 +1518,18 @@ class JSReceiver: public HeapObject { // Lookup a property. If found, the result is valid and has // detailed information. - void LocalLookup(String* name, LookupResult* result); + void LocalLookup(String* name, LookupResult* result, + bool search_hidden_prototypes = false); void Lookup(String* name, LookupResult* result); protected: Smi* GenerateIdentityHash(); private: - PropertyAttributes GetPropertyAttribute(JSReceiver* receiver, - LookupResult* result, - String* name, - bool continue_search); + PropertyAttributes GetPropertyAttributeForResult(JSReceiver* receiver, + LookupResult* result, + String* name, + bool continue_search); DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver); }; @@ -1525,6 +1578,8 @@ class JSObject: public JSReceiver { // Returns true if an object has elements of FAST_ELEMENTS or // FAST_SMI_ONLY_ELEMENTS. inline bool HasFastSmiOrObjectElements(); + // Returns true if an object has any of the fast elements kinds. + inline bool HasFastElements(); // Returns true if an object has elements of FAST_DOUBLE_ELEMENTS // ElementsKind. inline bool HasFastDoubleElements(); @@ -1604,6 +1659,18 @@ class JSObject: public JSReceiver { Handle<Object> value, PropertyAttributes attributes); + // Try to follow an existing transition to a field with attributes NONE. The + // return value indicates whether the transition was successful. + static inline bool TryTransitionToField(Handle<JSObject> object, + Handle<String> key); + + inline int LastAddedFieldIndex(); + + // Extend the receiver with a single fast property appeared first in the + // passed map. This also extends the property backing store if necessary. + static void AddFastPropertyUsingMap(Handle<JSObject> object, Handle<Map> map); + inline MUST_USE_RESULT MaybeObject* AddFastPropertyUsingMap(Map* map); + // Can cause GC. MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes( String* key, @@ -1651,12 +1718,16 @@ class JSObject: public JSReceiver { LookupResult* result, String* name, bool continue_search); + PropertyAttributes GetElementAttributeWithReceiver(JSReceiver* receiver, + uint32_t index, + bool continue_search); static void DefineAccessor(Handle<JSObject> object, Handle<String> name, Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes); + // Can cause GC. MUST_USE_RESULT MaybeObject* DefineAccessor(String* name, Object* getter, Object* setter, @@ -1732,6 +1803,7 @@ class JSObject: public JSReceiver { static Handle<Object> DeleteProperty(Handle<JSObject> obj, Handle<String> name); + // Can cause GC. MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode); static Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index); @@ -1770,36 +1842,18 @@ class JSObject: public JSReceiver { // be represented as a double and not a Smi. bool ShouldConvertToFastDoubleElements(bool* has_smi_only_elements); - // Tells whether the index'th element is present. - bool HasElementWithReceiver(JSReceiver* receiver, uint32_t index); - // Computes the new capacity when expanding the elements of a JSObject. static int NewElementsCapacity(int old_capacity) { // (old_capacity + 50%) + 16 return old_capacity + (old_capacity >> 1) + 16; } - // Tells whether the index'th element is present and how it is stored. - enum LocalElementType { - // There is no element with given index. - UNDEFINED_ELEMENT, - - // Element with given index is handled by interceptor. - INTERCEPTED_ELEMENT, + PropertyType GetLocalPropertyType(String* name); + PropertyType GetLocalElementType(uint32_t index); - // Element with given index is character in string. - STRING_CHARACTER_ELEMENT, - - // Element with given index is stored in fast backing store. - FAST_ELEMENT, - - // Element with given index is stored in slow backing store. - DICTIONARY_ELEMENT - }; - - LocalElementType HasLocalElement(uint32_t index); - - bool HasElementWithInterceptor(JSReceiver* receiver, uint32_t index); + // These methods do not perform access checks! + AccessorPair* GetLocalPropertyAccessorPair(String* name); + AccessorPair* GetLocalElementAccessorPair(uint32_t index); MUST_USE_RESULT MaybeObject* SetFastElement(uint32_t index, Object* value, @@ -1826,7 +1880,7 @@ class JSObject: public JSReceiver { StrictModeFlag strict_mode); // Empty handle is returned if the element cannot be set to the given value. - static MUST_USE_RESULT Handle<Object> SetElement( + static Handle<Object> SetElement( Handle<JSObject> object, uint32_t index, Handle<Object> value, @@ -1979,7 +2033,7 @@ class JSObject: public JSReceiver { Object* value, PropertyAttributes attributes); - // Add a property to an object. + // Add a property to an object. May cause GC. MUST_USE_RESULT MaybeObject* AddProperty( String* name, Object* value, @@ -2061,9 +2115,7 @@ class JSObject: public JSReceiver { } void JSObjectPrint(FILE* out); #endif -#ifdef DEBUG - void JSObjectVerify(); -#endif + DECLARE_VERIFIER(JSObject) #ifdef OBJECT_PRINT inline void PrintProperties() { PrintProperties(stdout); @@ -2152,6 +2204,15 @@ class JSObject: public JSReceiver { static inline int SizeOf(Map* map, HeapObject* object); }; + // Enqueue change record for Object.observe. May cause GC. + static void EnqueueChangeRecord(Handle<JSObject> object, + const char* type, + Handle<String> name, + Handle<Object> old_value); + + // Deliver change records to observers. May cause GC. + static void DeliverChangeRecords(Isolate* isolate); + private: friend class DictionaryElementsAccessor; @@ -2159,6 +2220,14 @@ class JSObject: public JSReceiver { Object* structure, uint32_t index, Object* holder); + MUST_USE_RESULT PropertyAttributes GetElementAttributeWithInterceptor( + JSReceiver* receiver, + uint32_t index, + bool continue_search); + MUST_USE_RESULT PropertyAttributes GetElementAttributeWithoutInterceptor( + JSReceiver* receiver, + uint32_t index, + bool continue_search); MUST_USE_RESULT MaybeObject* SetElementWithCallback( Object* structure, uint32_t index, @@ -2303,12 +2372,12 @@ class FixedArray: public FixedArrayBase { inline void set_unchecked(Heap* heap, int index, Object* value, WriteBarrierMode mode); - // Gives access to raw memory which stores the array's data. - inline Object** data_start(); - inline Object** GetFirstElementAddress(); inline bool ContainsOnlySmisOrHoles(); + // Gives access to raw memory which stores the array's data. + inline Object** data_start(); + // Copy operations. MUST_USE_RESULT inline MaybeObject* Copy(); MUST_USE_RESULT MaybeObject* CopySize(int new_length); @@ -2345,8 +2414,8 @@ class FixedArray: public FixedArrayBase { } void FixedArrayPrint(FILE* out); #endif + DECLARE_VERIFIER(FixedArray) #ifdef DEBUG - void FixedArrayVerify(); // Checks if two FixedArrays have identical contents. bool IsEqualTo(FixedArray* other); #endif @@ -2368,23 +2437,6 @@ class FixedArray: public FixedArrayBase { } }; - // WhitenessWitness is used to prove that a descriptor array is white - // (unmarked), so incremental write barriers can be skipped because the - // marking invariant cannot be broken and slots pointing into evacuation - // candidates will be discovered when the object is scanned. A witness is - // always stack-allocated right after creating an array. By allocating a - // witness, incremental marking is globally disabled. The witness is then - // passed along wherever needed to statically prove that the array is known to - // be white. - class WhitenessWitness { - public: - inline explicit WhitenessWitness(FixedArray* array); - inline ~WhitenessWitness(); - - private: - IncrementalMarking* marking_; - }; - protected: // Set operation on FixedArray without using write barriers. Can // only be used for storing old space objects or smis. @@ -2400,6 +2452,8 @@ class FixedArray: public FixedArrayBase { Object* value); private: + STATIC_CHECK(kHeaderSize == Internals::kFixedArrayHeaderSize); + DISALLOW_IMPLICIT_CONSTRUCTORS(FixedArray); }; @@ -2425,6 +2479,9 @@ class FixedDoubleArray: public FixedArrayBase { return kHeaderSize + length * kDoubleSize; } + // Gives access to raw memory which stores the array's data. + inline double* data_start(); + // Code Generation support. static int OffsetOfElementAt(int index) { return SizeFor(index); } @@ -2449,10 +2506,7 @@ class FixedDoubleArray: public FixedArrayBase { } void FixedDoubleArrayPrint(FILE* out); #endif - -#ifdef DEBUG - void FixedDoubleArrayVerify(); -#endif + DECLARE_VERIFIER(FixedDoubleArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(FixedDoubleArray); @@ -2461,13 +2515,31 @@ class FixedDoubleArray: public FixedArrayBase { // DescriptorArrays are fixed arrays used to hold instance descriptors. // The format of the these objects is: -// [0]: Either Smi(0) if uninitialized, or a pointer to small fixed array: +// [0]: Number of descriptors +// [1]: Either Smi(0) if uninitialized, or a pointer to small fixed array: // [0]: pointer to fixed array with enum cache // [1]: either Smi(0) or pointer to fixed array with indices -// [1]: first key -// [length() - kDescriptorSize]: last key +// [2]: first key +// [2 + number of descriptors * kDescriptorSize]: start of slack class DescriptorArray: public FixedArray { public: + // WhitenessWitness is used to prove that a descriptor array is white + // (unmarked), so incremental write barriers can be skipped because the + // marking invariant cannot be broken and slots pointing into evacuation + // candidates will be discovered when the object is scanned. A witness is + // always stack-allocated right after creating an array. By allocating a + // witness, incremental marking is globally disabled. The witness is then + // passed along wherever needed to statically prove that the array is known to + // be white. + class WhitenessWitness { + public: + inline explicit WhitenessWitness(FixedArray* array); + inline ~WhitenessWitness(); + + private: + IncrementalMarking* marking_; + }; + // Returns true for both shared empty_descriptor_array and for smis, which the // map uses to encode additional bit fields when the descriptor array is not // yet used. @@ -2477,20 +2549,47 @@ class DescriptorArray: public FixedArray { int number_of_descriptors() { ASSERT(length() >= kFirstIndex || IsEmpty()); int len = length(); - return len <= kFirstIndex ? 0 : (len - kFirstIndex) / kDescriptorSize; + return len == 0 ? 0 : Smi::cast(get(kDescriptorLengthIndex))->value(); + } + + int number_of_descriptors_storage() { + int len = length(); + return len == 0 ? 0 : (len - kFirstIndex) / kDescriptorSize; + } + + int NumberOfSlackDescriptors() { + return number_of_descriptors_storage() - number_of_descriptors(); } + inline void SetNumberOfDescriptors(int number_of_descriptors); inline int number_of_entries() { return number_of_descriptors(); } - inline int NextEnumerationIndex() { return number_of_descriptors() + 1; } bool HasEnumCache() { return !IsEmpty() && !get(kEnumCacheIndex)->IsSmi(); } - Object* GetEnumCache() { + void CopyEnumCacheFrom(DescriptorArray* array) { + set(kEnumCacheIndex, array->get(kEnumCacheIndex)); + } + + FixedArray* GetEnumCache() { ASSERT(HasEnumCache()); FixedArray* bridge = FixedArray::cast(get(kEnumCacheIndex)); - return bridge->get(kEnumCacheBridgeCacheIndex); + return FixedArray::cast(bridge->get(kEnumCacheBridgeCacheIndex)); + } + + bool HasEnumIndicesCache() { + if (IsEmpty()) return false; + Object* object = get(kEnumCacheIndex); + if (object->IsSmi()) return false; + FixedArray* bridge = FixedArray::cast(object); + return !bridge->get(kEnumCacheBridgeIndicesCacheIndex)->IsSmi(); + } + + FixedArray* GetEnumIndicesCache() { + ASSERT(HasEnumIndicesCache()); + FixedArray* bridge = FixedArray::cast(get(kEnumCacheIndex)); + return FixedArray::cast(bridge->get(kEnumCacheBridgeIndicesCacheIndex)); } Object** GetEnumCacheSlot() { @@ -2499,6 +2598,8 @@ class DescriptorArray: public FixedArray { kEnumCacheOffset); } + void ClearEnumCache(); + // Initialize or change the enum cache, // using the supplied storage for the small "bridge". void SetEnumCache(FixedArray* bridge_storage, @@ -2526,13 +2627,13 @@ class DescriptorArray: public FixedArray { inline void Set(int descriptor_number, Descriptor* desc, const WhitenessWitness&); + inline void Set(int descriptor_number, Descriptor* desc); // Append automatically sets the enumeration index. This should only be used // to add descriptors in bulk at the end, followed by sorting the descriptor // array. - inline void Append(Descriptor* desc, - const WhitenessWitness&, - int number_of_set_descriptors); + inline void Append(Descriptor* desc, const WhitenessWitness&); + inline void Append(Descriptor* desc); // Transfer a complete descriptor from the src descriptor array to this // descriptor array. @@ -2541,23 +2642,22 @@ class DescriptorArray: public FixedArray { int src_index, const WhitenessWitness&); + MUST_USE_RESULT MaybeObject* CopyUpTo(int enumeration_index); + // Sort the instance descriptors by the hash codes of their keys. void Sort(); - inline void SwapSortedKeys(int first, int second); // Search the instance descriptors for given name. - INLINE(int Search(String* name)); + INLINE(int Search(String* name, int number_of_own_descriptors)); // As the above, but uses DescriptorLookupCache and updates it when // necessary. - INLINE(int SearchWithCache(String* name)); - - // Tells whether the name is present int the array. - bool Contains(String* name) { return kNotFound != Search(name); } + INLINE(int SearchWithCache(String* name, Map* map)); // Allocates a DescriptorArray, but returns the singleton // empty descriptor array object if number_of_descriptors is 0. - MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors); + MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors, + int slack = 0); // Casting. static inline DescriptorArray* cast(Object* obj); @@ -2565,8 +2665,9 @@ class DescriptorArray: public FixedArray { // Constant for denoting key was not found. static const int kNotFound = -1; - static const int kEnumCacheIndex = 0; - static const int kFirstIndex = 1; + static const int kDescriptorLengthIndex = 0; + static const int kEnumCacheIndex = 1; + static const int kFirstIndex = 2; // The length of the "bridge" to the enum cache. static const int kEnumCacheBridgeLength = 2; @@ -2574,7 +2675,8 @@ class DescriptorArray: public FixedArray { static const int kEnumCacheBridgeIndicesCacheIndex = 1; // Layout description. - static const int kEnumCacheOffset = FixedArray::kHeaderSize; + static const int kDescriptorLengthOffset = FixedArray::kHeaderSize; + static const int kEnumCacheOffset = kDescriptorLengthOffset + kPointerSize; static const int kFirstOffset = kEnumCacheOffset + kPointerSize; // Layout description for the bridge array. @@ -2596,7 +2698,7 @@ class DescriptorArray: public FixedArray { #ifdef DEBUG // Is the descriptor array sorted and without duplicates? - bool IsSortedNoDuplicates(); + bool IsSortedNoDuplicates(int valid_descriptors = -1); // Is the descriptor array consistent with the back pointers in targets? bool IsConsistentWithBackPointers(Map* current_map); @@ -2649,24 +2751,21 @@ class DescriptorArray: public FixedArray { kDescriptorValue; } - // Swap operation on FixedArray without using write barriers. - static inline void NoIncrementalWriteBarrierSwap( - FixedArray* array, int first, int second); - // Swap first and second descriptor. - inline void NoIncrementalWriteBarrierSwapDescriptors( - int first, int second); + inline void SwapSortedKeys(int first, int second); DISALLOW_IMPLICIT_CONSTRUCTORS(DescriptorArray); }; -template<typename T> -inline int LinearSearch(T* array, String* name, int len); +enum SearchMode { ALL_ENTRIES, VALID_ENTRIES }; +template<SearchMode search_mode, typename T> +inline int LinearSearch(T* array, String* name, int len, int valid_entries); -template<typename T> -inline int Search(T* array, String* name); + +template<SearchMode search_mode, typename T> +inline int Search(T* array, String* name, int valid_entries = 0); // HashTable is a subclass of FixedArray that implements a hash table @@ -2868,11 +2967,12 @@ class HashTable: public FixedArray { return (hash + GetProbeOffset(number)) & (size - 1); } - static uint32_t FirstProbe(uint32_t hash, uint32_t size) { + inline static uint32_t FirstProbe(uint32_t hash, uint32_t size) { return hash & (size - 1); } - static uint32_t NextProbe(uint32_t last, uint32_t number, uint32_t size) { + inline static uint32_t NextProbe( + uint32_t last, uint32_t number, uint32_t size) { return (last + number) & (size - 1); } @@ -2923,7 +3023,7 @@ class SymbolTableShape : public BaseShape<HashTableKey*> { static const int kEntrySize = 1; }; -class SeqAsciiString; +class SeqOneByteString; // SymbolTable. // @@ -2939,7 +3039,7 @@ class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> { MUST_USE_RESULT MaybeObject* LookupAsciiSymbol(Vector<const char> str, Object** s); MUST_USE_RESULT MaybeObject* LookupSubStringAsciiSymbol( - Handle<SeqAsciiString> str, + Handle<SeqOneByteString> str, int from, int length, Object** s); @@ -2959,6 +3059,8 @@ class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> { private: MUST_USE_RESULT MaybeObject* LookupKey(HashTableKey* key, Object** s); + template <bool seq_ascii> friend class JsonParser; + DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolTable); }; @@ -3340,9 +3442,7 @@ class JSFunctionResultCache: public FixedArray { // Casting static inline JSFunctionResultCache* cast(Object* obj); -#ifdef DEBUG - void JSFunctionResultCacheVerify(); -#endif + DECLARE_VERIFIER(JSFunctionResultCache) }; @@ -3562,9 +3662,7 @@ class NormalizedMapCache: public FixedArray { // Casting static inline NormalizedMapCache* cast(Object* obj); -#ifdef DEBUG - void NormalizedMapCacheVerify(); -#endif + DECLARE_VERIFIER(NormalizedMapCache) }; @@ -3613,9 +3711,7 @@ class ByteArray: public FixedArrayBase { } void ByteArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ByteArrayVerify(); -#endif + DECLARE_VERIFIER(ByteArray) // Layout description. static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize); @@ -3649,9 +3745,7 @@ class FreeSpace: public HeapObject { } void FreeSpacePrint(FILE* out); #endif -#ifdef DEBUG - void FreeSpaceVerify(); -#endif + DECLARE_VERIFIER(FreeSpace) // Layout description. // Size is smi tagged when it is stored. @@ -3731,9 +3825,7 @@ class ExternalPixelArray: public ExternalArray { } void ExternalPixelArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalPixelArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalPixelArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalPixelArray); @@ -3760,9 +3852,7 @@ class ExternalByteArray: public ExternalArray { } void ExternalByteArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalByteArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalByteArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalByteArray); @@ -3789,9 +3879,7 @@ class ExternalUnsignedByteArray: public ExternalArray { } void ExternalUnsignedByteArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalUnsignedByteArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalUnsignedByteArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedByteArray); @@ -3818,9 +3906,7 @@ class ExternalShortArray: public ExternalArray { } void ExternalShortArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalShortArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalShortArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalShortArray); @@ -3847,9 +3933,7 @@ class ExternalUnsignedShortArray: public ExternalArray { } void ExternalUnsignedShortArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalUnsignedShortArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalUnsignedShortArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedShortArray); @@ -3876,9 +3960,7 @@ class ExternalIntArray: public ExternalArray { } void ExternalIntArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalIntArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalIntArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalIntArray); @@ -3905,9 +3987,7 @@ class ExternalUnsignedIntArray: public ExternalArray { } void ExternalUnsignedIntArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalUnsignedIntArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalUnsignedIntArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUnsignedIntArray); @@ -3934,9 +4014,7 @@ class ExternalFloatArray: public ExternalArray { } void ExternalFloatArrayPrint(FILE* out); #endif -#ifdef DEBUG - void ExternalFloatArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalFloatArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloatArray); @@ -3963,9 +4041,7 @@ class ExternalDoubleArray: public ExternalArray { } void ExternalDoubleArrayPrint(FILE* out); #endif // OBJECT_PRINT -#ifdef DEBUG - void ExternalDoubleArrayVerify(); -#endif // DEBUG + DECLARE_VERIFIER(ExternalDoubleArray) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalDoubleArray); @@ -4233,8 +4309,12 @@ class Code: public HeapObject { DECL_ACCESSORS(deoptimization_data, FixedArray) // [type_feedback_info]: Struct containing type feedback information. - // Will contain either a TypeFeedbackInfo object, or undefined. + // STUBs can use this slot to store arbitrary information as a Smi. + // Will contain either a TypeFeedbackInfo object, or undefined, or a Smi. DECL_ACCESSORS(type_feedback_info, Object) + inline void InitializeTypeFeedbackInfoNoWriteBarrier(Object* value); + inline int stub_info(); + inline void set_stub_info(int info); // [gc_metadata]: Field used to hold GC related metadata. The contents of this // field does not have to be traced during garbage collection since @@ -4246,6 +4326,11 @@ class Code: public HeapObject { inline void set_ic_age(int count); inline int ic_age(); + // [prologue_offset]: Offset of the function prologue, used for aging + // FUNCTIONs and OPTIMIZED_FUNCTIONs. + inline int prologue_offset(); + inline void set_prologue_offset(int offset); + // Unchecked accessors to be used during GC. inline ByteArray* unchecked_relocation_info(); inline FixedArray* unchecked_deoptimization_data(); @@ -4340,21 +4425,6 @@ class Code: public HeapObject { inline byte unary_op_type(); inline void set_unary_op_type(byte value); - // [type-recording binary op type]: For kind BINARY_OP_IC. - inline byte binary_op_type(); - inline void set_binary_op_type(byte value); - inline byte binary_op_result_type(); - inline void set_binary_op_result_type(byte value); - - // [compare state]: For kind COMPARE_IC, tells what state the stub is in. - 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); @@ -4488,12 +4558,27 @@ class Code: public HeapObject { } void CodePrint(FILE* out); #endif -#ifdef DEBUG - void CodeVerify(); -#endif + DECLARE_VERIFIER(Code) + void ClearInlineCaches(); void ClearTypeFeedbackCells(Heap* heap); +#define DECLARE_CODE_AGE_ENUM(X) k##X##CodeAge, + enum Age { + kNoAge = 0, + CODE_AGE_LIST(DECLARE_CODE_AGE_ENUM) + kAfterLastCodeAge, + kLastCodeAge = kAfterLastCodeAge - 1, + kCodeAgeCount = kAfterLastCodeAge - 1 + }; +#undef DECLARE_CODE_AGE_ENUM + + // Code aging + static void MakeCodeAgeSequenceYoung(byte* sequence); + void MakeOlder(MarkingParity); + static bool IsYoungSequence(byte* sequence); + bool IsOld(); + // Max loop nesting marker used to postpose OSR. We don't take loop // nesting that is deeper than 5 levels into account. static const int kMaxLoopNestingMarker = 6; @@ -4513,8 +4598,10 @@ class Code: public HeapObject { static const int kKindSpecificFlags1Offset = kFlagsOffset + kIntSize; static const int kKindSpecificFlags2Offset = kKindSpecificFlags1Offset + kIntSize; + // Note: We might be able to squeeze this into the flags above. + static const int kPrologueOffset = kKindSpecificFlags2Offset + kIntSize; - static const int kHeaderPaddingStart = kKindSpecificFlags2Offset + kIntSize; + static const int kHeaderPaddingStart = kPrologueOffset + kIntSize; // Add padding to align the instruction start following right after // the Code object header. @@ -4548,18 +4635,6 @@ class Code: public HeapObject { static const int kUnaryOpTypeFirstBit = kStackSlotsFirstBit + kStackSlotsBitCount; static const int kUnaryOpTypeBitCount = 3; - static const int kBinaryOpTypeFirstBit = - kStackSlotsFirstBit + kStackSlotsBitCount; - static const int kBinaryOpTypeBitCount = 3; - static const int kBinaryOpResultTypeFirstBit = - kBinaryOpTypeFirstBit + kBinaryOpTypeBitCount; - static const int kBinaryOpResultTypeBitCount = 3; - static const int kCompareStateFirstBit = - kStackSlotsFirstBit + kStackSlotsBitCount; - static const int kCompareStateBitCount = 3; - static const int kCompareOperationFirstBit = - kCompareStateFirstBit + kCompareStateBitCount; - static const int kCompareOperationBitCount = 4; static const int kToBooleanStateFirstBit = kStackSlotsFirstBit + kStackSlotsBitCount; static const int kToBooleanStateBitCount = 8; @@ -4569,11 +4644,6 @@ class Code: public HeapObject { STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32); STATIC_ASSERT(kUnaryOpTypeFirstBit + kUnaryOpTypeBitCount <= 32); - STATIC_ASSERT(kBinaryOpTypeFirstBit + kBinaryOpTypeBitCount <= 32); - STATIC_ASSERT(kBinaryOpResultTypeFirstBit + - kBinaryOpResultTypeBitCount <= 32); - STATIC_ASSERT(kCompareStateFirstBit + kCompareStateBitCount <= 32); - STATIC_ASSERT(kCompareOperationFirstBit + kCompareOperationBitCount <= 32); STATIC_ASSERT(kToBooleanStateFirstBit + kToBooleanStateBitCount <= 32); STATIC_ASSERT(kHasFunctionCacheFirstBit + kHasFunctionCacheBitCount <= 32); @@ -4581,14 +4651,6 @@ class Code: public HeapObject { kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT class UnaryOpTypeField: public BitField<int, kUnaryOpTypeFirstBit, kUnaryOpTypeBitCount> {}; // NOLINT - class BinaryOpTypeField: public BitField<int, - kBinaryOpTypeFirstBit, kBinaryOpTypeBitCount> {}; // NOLINT - class BinaryOpResultTypeField: public BitField<int, - kBinaryOpResultTypeFirstBit, kBinaryOpResultTypeBitCount> {}; // NOLINT - class CompareStateField: public BitField<int, - kCompareStateFirstBit, kCompareStateBitCount> {}; // NOLINT - class CompareOperationField: public BitField<int, - kCompareOperationFirstBit, kCompareOperationBitCount> {}; // NOLINT class ToBooleanStateField: public BitField<int, kToBooleanStateFirstBit, kToBooleanStateBitCount> {}; // NOLINT class HasFunctionCacheField: public BitField<bool, @@ -4622,6 +4684,20 @@ class Code: public HeapObject { TypeField::kMask | CacheHolderField::kMask; private: + friend class RelocIterator; + + // Code aging + byte* FindCodeAgeSequence(); + static void GetCodeAgeAndParity(Code* code, Age* age, + MarkingParity* parity); + static void GetCodeAgeAndParity(byte* sequence, Age* age, + MarkingParity* parity); + static Code* GetCodeAgeStub(Age age, MarkingParity parity); + + // Code aging -- platform-specific + static void PatchPlatformCodeAge(byte* sequence, Age age, + MarkingParity parity); + DISALLOW_IMPLICIT_CONSTRUCTORS(Code); }; @@ -4672,6 +4748,8 @@ class Map: public HeapObject { class IsShared: public BitField<bool, 22, 1> {}; class FunctionWithPrototype: public BitField<bool, 23, 1> {}; class DictionaryMap: public BitField<bool, 24, 1> {}; + class OwnsDescriptors: public BitField<bool, 25, 1> {}; + class IsObserved: public BitField<bool, 26, 1> {}; // Tells whether the object in the prototype property will be used // for instances created from this function. If the prototype @@ -4797,8 +4875,11 @@ class Map: public HeapObject { inline Map* elements_transition_map(); MUST_USE_RESULT inline MaybeObject* set_elements_transition_map( Map* transitioned_map); - inline void SetTransition(int index, Map* target); - MUST_USE_RESULT inline MaybeObject* AddTransition(String* key, Map* target); + inline void SetTransition(int transition_index, Map* target); + inline Map* GetTransition(int transition_index); + MUST_USE_RESULT inline MaybeObject* AddTransition(String* key, + Map* target, + SimpleTransitionFlag flag); DECL_ACCESSORS(transitions, TransitionArray) inline void ClearTransitions(Heap* heap, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); @@ -4836,14 +4917,8 @@ class Map: public HeapObject { inline JSFunction* unchecked_constructor(); // [instance descriptors]: describes the object. - inline DescriptorArray* instance_descriptors(); - MUST_USE_RESULT inline MaybeObject* SetDescriptors( - DescriptorArray* descriptors, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - static void SetDescriptors(Handle<Map> map, - Handle<DescriptorArray> descriptors); - MUST_USE_RESULT inline MaybeObject* InitializeDescriptors( - DescriptorArray* descriptors); + DECL_ACCESSORS(instance_descriptors, DescriptorArray) + inline void InitializeDescriptors(DescriptorArray* descriptors); // [stub cache]: contains stubs compiled for this map. DECL_ACCESSORS(code_cache, Object) @@ -4920,31 +4995,50 @@ class Map: public HeapObject { } void SetNumberOfOwnDescriptors(int number) { + ASSERT(number <= instance_descriptors()->number_of_descriptors()); set_bit_field3(NumberOfOwnDescriptorsBits::update(bit_field3(), number)); } + inline JSGlobalPropertyCell* RetrieveDescriptorsPointer(); + int EnumLength() { return EnumLengthBits::decode(bit_field3()); } - void SetEnumLength(int index) { - set_bit_field3(EnumLengthBits::update(bit_field3(), index)); + void SetEnumLength(int length) { + if (length != kInvalidEnumCache) { + ASSERT(length >= 0); + ASSERT(length == 0 || instance_descriptors()->HasEnumCache()); + ASSERT(length <= NumberOfOwnDescriptors()); + } + set_bit_field3(EnumLengthBits::update(bit_field3(), length)); } + + inline bool owns_descriptors(); + inline void set_owns_descriptors(bool is_shared); + inline bool is_observed(); + inline void set_is_observed(bool is_observed); + MUST_USE_RESULT MaybeObject* RawCopy(int instance_size); MUST_USE_RESULT MaybeObject* CopyWithPreallocatedFieldDescriptors(); MUST_USE_RESULT MaybeObject* CopyDropDescriptors(); MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors( DescriptorArray* descriptors, String* name, - TransitionFlag flag); + TransitionFlag flag, + int descriptor_index); + MUST_USE_RESULT MaybeObject* ShareDescriptor(DescriptorArray* descriptors, + Descriptor* descriptor); MUST_USE_RESULT MaybeObject* CopyAddDescriptor(Descriptor* descriptor, TransitionFlag flag); MUST_USE_RESULT MaybeObject* CopyInsertDescriptor(Descriptor* descriptor, TransitionFlag flag); - MUST_USE_RESULT MaybeObject* CopyReplaceDescriptor(Descriptor* descriptor, - int index, - TransitionFlag flag); + MUST_USE_RESULT MaybeObject* CopyReplaceDescriptor( + DescriptorArray* descriptors, + Descriptor* descriptor, + int index, + TransitionFlag flag); MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind, TransitionFlag flag); @@ -4966,7 +5060,8 @@ class Map: public HeapObject { // Returns the number of properties described in instance_descriptors // filtering out properties with the specified attributes. - int NumberOfDescribedProperties(PropertyAttributes filter = NONE); + int NumberOfDescribedProperties(DescriptorFlag which = OWN_DESCRIPTORS, + PropertyAttributes filter = NONE); // Casting. static inline Map* cast(Object* obj); @@ -4987,8 +5082,10 @@ class Map: public HeapObject { // Extend the descriptor array of the map with the list of descriptors. // In case of duplicates, the latest descriptor is used. - static void CopyAppendCallbackDescriptors(Handle<Map> map, - Handle<Object> descriptors); + static void AppendCallbackDescriptors(Handle<Map> map, + Handle<Object> descriptors); + + static void EnsureDescriptorSlack(Handle<Map> map, int slack); // Returns the found code or undefined if absent. Object* FindInCodeCache(String* name, Code::Flags flags); @@ -5026,14 +5123,14 @@ class Map: public HeapObject { Handle<Map> FindTransitionedMap(MapHandleList* candidates); Map* FindTransitionedMap(MapList* candidates); - // Zaps the contents of backing data structures in debug mode. Note that the + // Zaps the contents of backing data structures. Note that the // heap verifier (i.e. VerifyMarkingVisitor) relies on zapping of objects // holding weak references when incremental marking is used, because it also // iterates over objects that are otherwise unreachable. -#ifdef DEBUG + // In general we only want to call these functions in release mode when + // heap verification is turned on. void ZapPrototypeTransitions(); void ZapTransitions(); -#endif // Dispatched behavior. #ifdef OBJECT_PRINT @@ -5042,8 +5139,9 @@ class Map: public HeapObject { } void MapPrint(FILE* out); #endif -#ifdef DEBUG - void MapVerify(); + DECLARE_VERIFIER(Map) + +#ifdef VERIFY_HEAP void SharedMapVerify(); #endif @@ -5070,7 +5168,7 @@ class Map: public HeapObject { static const int kMaxPreAllocatedPropertyFields = 255; - // Constant for denoting that the Enum Cache field was not yet used. + // Constant for denoting that the enum cache is not yet initialized. static const int kInvalidEnumCache = EnumLengthBits::kMax; // Layout description. @@ -5084,11 +5182,12 @@ class Map: public HeapObject { // indirection. static const int kTransitionsOrBackPointerOffset = kConstructorOffset + kPointerSize; - static const int kCodeCacheOffset = + static const int kDescriptorsOffset = kTransitionsOrBackPointerOffset + kPointerSize; + static const int kCodeCacheOffset = + kDescriptorsOffset + kPointerSize; static const int kBitField3Offset = kCodeCacheOffset + kPointerSize; - static const int kPadStart = kBitField3Offset + kPointerSize; - static const int kSize = MAP_POINTER_ALIGN(kPadStart); + static const int kSize = kBitField3Offset + kPointerSize; // Layout of pointer fields. Heap iteration code relies on them // being continuously allocated. @@ -5246,9 +5345,7 @@ class Script: public Struct { } void ScriptPrint(FILE* out); #endif -#ifdef DEBUG - void ScriptVerify(); -#endif + DECLARE_VERIFIER(Script) static const int kSourceOffset = HeapObject::kHeaderSize; static const int kNameOffset = kSourceOffset + kPointerSize; @@ -5728,9 +5825,7 @@ class SharedFunctionInfo: public HeapObject { } void SharedFunctionInfoPrint(FILE* out); #endif -#ifdef DEBUG - void SharedFunctionInfoVerify(); -#endif + DECLARE_VERIFIER(SharedFunctionInfo) void ResetForNewContext(int new_ic_age); @@ -5964,9 +6059,7 @@ class JSModule: public JSObject { } void JSModulePrint(FILE* out); #endif -#ifdef DEBUG - void JSModuleVerify(); -#endif + DECLARE_VERIFIER(JSModule) // Layout description. static const int kContextOffset = JSObject::kHeaderSize; @@ -6069,8 +6162,6 @@ class JSFunction: public JSObject { // The initial map for an object created by this constructor. inline Map* initial_map(); inline void set_initial_map(Map* value); - MUST_USE_RESULT inline MaybeObject* set_initial_map_and_cache_transitions( - Map* value); inline bool has_initial_map(); // Get and set the prototype property on a JSFunction. If the @@ -6127,9 +6218,7 @@ class JSFunction: public JSObject { } void JSFunctionPrint(FILE* out); #endif -#ifdef DEBUG - void JSFunctionVerify(); -#endif + DECLARE_VERIFIER(JSFunction) // Returns the number of allocated literals. inline int NumberOfLiterals(); @@ -6188,9 +6277,7 @@ class JSGlobalProxy : public JSObject { } void JSGlobalProxyPrint(FILE* out); #endif -#ifdef DEBUG - void JSGlobalProxyVerify(); -#endif + DECLARE_VERIFIER(JSGlobalProxy) // Layout description. static const int kNativeContextOffset = JSObject::kHeaderSize; @@ -6237,7 +6324,7 @@ class GlobalObject: public JSObject { Handle<GlobalObject> global, Handle<String> name); // TODO(kmillikin): This function can be eliminated once the stub cache is - // full handlified (and the static helper can be written directly). + // fully handlified (and the static helper can be written directly). MUST_USE_RESULT MaybeObject* EnsurePropertyCell(String* name); // Casting. @@ -6268,9 +6355,7 @@ class JSGlobalObject: public GlobalObject { } void JSGlobalObjectPrint(FILE* out); #endif -#ifdef DEBUG - void JSGlobalObjectVerify(); -#endif + DECLARE_VERIFIER(JSGlobalObject) // Layout description. static const int kSize = GlobalObject::kHeaderSize; @@ -6302,9 +6387,7 @@ class JSBuiltinsObject: public GlobalObject { } void JSBuiltinsObjectPrint(FILE* out); #endif -#ifdef DEBUG - void JSBuiltinsObjectVerify(); -#endif + DECLARE_VERIFIER(JSBuiltinsObject) // Layout description. The size of the builtins object includes // room for two pointers per runtime routine written in javascript @@ -6345,9 +6428,7 @@ class JSValue: public JSObject { } void JSValuePrint(FILE* out); #endif -#ifdef DEBUG - void JSValueVerify(); -#endif + DECLARE_VERIFIER(JSValue) // Layout description. static const int kValueOffset = JSObject::kHeaderSize; @@ -6401,9 +6482,8 @@ class JSDate: public JSObject { } void JSDatePrint(FILE* out); #endif -#ifdef DEBUG - void JSDateVerify(); -#endif + DECLARE_VERIFIER(JSDate) + // The order is important. It must be kept in sync with date macros // in macros.py. enum FieldIndex { @@ -6499,9 +6579,7 @@ class JSMessageObject: public JSObject { } void JSMessageObjectPrint(FILE* out); #endif -#ifdef DEBUG - void JSMessageObjectVerify(); -#endif + DECLARE_VERIFIER(JSMessageObject) // Layout description. static const int kTypeOffset = JSObject::kHeaderSize; @@ -6570,6 +6648,7 @@ class JSRegExp: public JSObject { inline Object* DataAtUnchecked(int index); inline void SetDataAtUnchecked(int index, Object* value, Heap* heap); inline Type TypeTagUnchecked(); + inline void ResetLastIndex(); static int code_index(bool is_ascii) { if (is_ascii) { @@ -6590,9 +6669,7 @@ class JSRegExp: public JSObject { static inline JSRegExp* cast(Object* obj); // Dispatched behavior. -#ifdef DEBUG - void JSRegExpVerify(); -#endif + DECLARE_VERIFIER(JSRegExp) static const int kDataOffset = JSObject::kHeaderSize; static const int kSize = kDataOffset + kPointerSize; @@ -6748,9 +6825,7 @@ class CodeCache: public Struct { } void CodeCachePrint(FILE* out); #endif -#ifdef DEBUG - void CodeCacheVerify(); -#endif + DECLARE_VERIFIER(CodeCache) static const int kDefaultCacheOffset = HeapObject::kHeaderSize; static const int kNormalTypeCacheOffset = @@ -6839,9 +6914,7 @@ class PolymorphicCodeCache: public Struct { } void PolymorphicCodeCachePrint(FILE* out); #endif -#ifdef DEBUG - void PolymorphicCodeCacheVerify(); -#endif + DECLARE_VERIFIER(PolymorphicCodeCache) static const int kCacheOffset = HeapObject::kHeaderSize; static const int kSize = kCacheOffset + kPointerSize; @@ -6894,9 +6967,7 @@ class TypeFeedbackInfo: public Struct { } void TypeFeedbackInfoPrint(FILE* out); #endif -#ifdef DEBUG - void TypeFeedbackInfoVerify(); -#endif + DECLARE_VERIFIER(TypeFeedbackInfo) static const int kStorage1Offset = HeapObject::kHeaderSize; static const int kStorage2Offset = kStorage1Offset + kPointerSize; @@ -6942,9 +7013,7 @@ class AliasedArgumentsEntry: public Struct { } void AliasedArgumentsEntryPrint(FILE* out); #endif -#ifdef DEBUG - void AliasedArgumentsEntryVerify(); -#endif + DECLARE_VERIFIER(AliasedArgumentsEntry) static const int kAliasedContextSlot = HeapObject::kHeaderSize; static const int kSize = kAliasedContextSlot + kPointerSize; @@ -6987,10 +7056,6 @@ class StringHasher { // index. bool is_array_index() { return is_array_index_; } - bool is_valid() { return is_valid_; } - - void invalidate() { is_valid_ = false; } - // Calculated hash value for a string consisting of 1 to // String::kMaxArrayIndexSize digits with no leading zeros (except "0"). // value is represented decimal value. @@ -7009,13 +7074,33 @@ class StringHasher { inline uint32_t GetHash(); + // Reusable parts of the hashing algorithm. + INLINE(static uint32_t AddCharacterCore(uint32_t running_hash, uint32_t c)); + INLINE(static uint32_t GetHashCore(uint32_t running_hash)); + int length_; uint32_t raw_running_hash_; uint32_t array_index_; bool is_array_index_; bool is_first_char_; - bool is_valid_; friend class TwoCharHashTableKey; + + template <bool seq_ascii> friend class JsonParser; +}; + + +class IncrementalAsciiStringHasher { + public: + explicit inline IncrementalAsciiStringHasher(uint32_t seed, char first_char); + inline void AddCharacter(uc32 c); + inline uint32_t GetHash(); + + private: + int length_; + uint32_t raw_running_hash_; + uint32_t array_index_; + bool is_array_index_; + char first_char_; }; @@ -7085,6 +7170,8 @@ class StringShape BASE_EMBEDDED { // All string values have a length field. class String: public HeapObject { public: + enum Encoding { ONE_BYTE_ENCODING, TWO_BYTE_ENCODING }; + // Representation of the flat content of a String. // A non-flat string doesn't have flat content. // A flat string has content that's encoded as a sequence of either @@ -7142,13 +7229,13 @@ class String: public HeapObject { // be ASCII encoded. This might be the case even if the string is // two-byte. Such strings may appear when the embedder prefers // two-byte external representations even for ASCII data. - inline bool IsAsciiRepresentation(); + inline bool IsOneByteRepresentation(); inline bool IsTwoByteRepresentation(); // Cons and slices have an encoding flag that may not represent the actual // encoding of the underlying string. This is taken into account here. // Requires: this->IsFlat() - inline bool IsAsciiRepresentationUnderneath(); + inline bool IsOneByteRepresentationUnderneath(); inline bool IsTwoByteRepresentationUnderneath(); // NOTE: this should be considered only a hint. False negatives are @@ -7275,9 +7362,8 @@ class String: public HeapObject { char* ToAsciiArray(); #endif -#ifdef DEBUG - void StringVerify(); -#endif + DECLARE_VERIFIER(String) + inline bool IsFlat(); // Layout description. @@ -7346,7 +7432,7 @@ class String: public HeapObject { kIsNotArrayIndexMask | kHashNotComputedMask; // Value of hash field containing computed hash equal to zero. - static const int kZeroHash = kIsNotArrayIndexMask; + static const int kEmptyStringHash = kIsNotArrayIndexMask; // Maximal string length. static const int kMaxLength = (1 << (32 - 2)) - 1; @@ -7381,34 +7467,57 @@ class String: public HeapObject { int from, int to); - static inline bool IsAscii(const char* chars, int length) { + // The return value may point to the first aligned word containing the + // first non-ascii character, rather than directly to the non-ascii character. + // If the return value is >= the passed length, the entire string was ASCII. + static inline int NonAsciiStart(const char* chars, int length) { + const char* start = chars; const char* limit = chars + length; #ifdef V8_HOST_CAN_READ_UNALIGNED ASSERT(kMaxAsciiCharCode == 0x7F); const uintptr_t non_ascii_mask = kUintptrAllBitsSet / 0xFF * 0x80; while (chars + sizeof(uintptr_t) <= limit) { if (*reinterpret_cast<const uintptr_t*>(chars) & non_ascii_mask) { - return false; + return static_cast<int>(chars - start); } chars += sizeof(uintptr_t); } #endif while (chars < limit) { - if (static_cast<uint8_t>(*chars) > kMaxAsciiCharCodeU) return false; + if (static_cast<uint8_t>(*chars) > kMaxAsciiCharCodeU) { + return static_cast<int>(chars - start); + } ++chars; } - return true; + return static_cast<int>(chars - start); } - static inline bool IsAscii(const uc16* chars, int length) { + static inline bool IsAscii(const char* chars, int length) { + return NonAsciiStart(chars, length) >= length; + } + + static inline int NonAsciiStart(const uc16* chars, int length) { const uc16* limit = chars + length; + const uc16* start = chars; while (chars < limit) { - if (*chars > kMaxAsciiCharCodeU) return false; + if (*chars > kMaxAsciiCharCodeU) return static_cast<int>(chars - start); ++chars; } - return true; + return static_cast<int>(chars - start); + } + + static inline bool IsAscii(const uc16* chars, int length) { + return NonAsciiStart(chars, length) >= length; } + template<class Visitor, class ConsOp> + static inline void Visit(String* string, + unsigned offset, + Visitor& visitor, + ConsOp& consOp, + int32_t type, + unsigned length); + protected: class ReadBlockBuffer { public: @@ -7467,6 +7576,11 @@ class SeqString: public String { // Layout description. static const int kHeaderSize = String::kSize; + // Truncate the string in-place if possible and return the result. + // In case of new_length == 0, the empty string is returned without + // truncating the original string. + MUST_USE_RESULT String* Truncate(int new_length); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString); }; @@ -7474,13 +7588,13 @@ class SeqString: public String { // The AsciiString class captures sequential ASCII string objects. // Each character in the AsciiString is an ASCII character. -class SeqAsciiString: public SeqString { +class SeqOneByteString: public SeqString { public: static const bool kHasAsciiEncoding = true; // Dispatched behavior. - inline uint16_t SeqAsciiStringGet(int index); - inline void SeqAsciiStringSet(int index, uint16_t value); + inline uint16_t SeqOneByteStringGet(int index); + inline void SeqOneByteStringSet(int index, uint16_t value); // Get the address of the characters in this string. inline Address GetCharsAddress(); @@ -7488,12 +7602,12 @@ class SeqAsciiString: public SeqString { inline char* GetChars(); // Casting - static inline SeqAsciiString* cast(Object* obj); + static inline SeqOneByteString* cast(Object* obj); // Garbage collection support. This method is called by the // garbage collector to compute the actual size of an AsciiString // instance. - inline int SeqAsciiStringSize(InstanceType instance_type); + inline int SeqOneByteStringSize(InstanceType instance_type); // Computes the size for an AsciiString instance of a given length. static int SizeFor(int length) { @@ -7507,19 +7621,17 @@ class SeqAsciiString: public SeqString { static const int kMaxLength = (kMaxSize - kHeaderSize); // Support for StringInputBuffer. - inline void SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* buffer, + inline void SeqOneByteStringReadBlockIntoBuffer(ReadBlockBuffer* buffer, unsigned* offset, unsigned chars); - inline const unibrow::byte* SeqAsciiStringReadBlock(unsigned* remaining, + inline const unibrow::byte* SeqOneByteStringReadBlock(unsigned* remaining, unsigned* offset, unsigned chars); -#ifdef DEBUG - void SeqAsciiStringVerify(); -#endif + DECLARE_VERIFIER(SeqOneByteString) private: - DISALLOW_IMPLICIT_CONSTRUCTORS(SeqAsciiString); + DISALLOW_IMPLICIT_CONSTRUCTORS(SeqOneByteString); }; @@ -7621,9 +7733,7 @@ class ConsString: public String { typedef FixedBodyDescriptor<kFirstOffset, kSecondOffset + kPointerSize, kSize> BodyDescriptor; -#ifdef DEBUG - void ConsStringVerify(); -#endif + DECLARE_VERIFIER(ConsString) private: DISALLOW_IMPLICIT_CONSTRUCTORS(ConsString); @@ -7675,9 +7785,7 @@ class SlicedString: public String { kOffsetOffset + kPointerSize, kSize> BodyDescriptor; -#ifdef DEBUG - void SlicedStringVerify(); -#endif + DECLARE_VERIFIER(SlicedString) private: DISALLOW_IMPLICIT_CONSTRUCTORS(SlicedString); @@ -7864,14 +7972,75 @@ class StringInputBuffer: public unibrow::InputBuffer<String, String*, 1024> { }; -class SafeStringInputBuffer - : public unibrow::InputBuffer<String, String**, 256> { +// This maintains an off-stack representation of the stack frames required +// to traverse a ConsString, allowing an entirely iterative and restartable +// traversal of the entire string +// Note: this class is not GC-safe. +class ConsStringIteratorOp { public: - virtual void Seek(unsigned pos); - inline SafeStringInputBuffer() - : unibrow::InputBuffer<String, String**, 256>() {} - explicit inline SafeStringInputBuffer(String** backing) - : unibrow::InputBuffer<String, String**, 256>(backing) {} + struct ContinueResponse { + String* string_; + unsigned offset_; + unsigned length_; + int32_t type_; + }; + inline ConsStringIteratorOp() {} + String* Operate(ConsString* consString, unsigned* outerOffset, + int32_t* typeOut, unsigned* lengthOut); + inline bool ContinueOperation(ContinueResponse* response); + inline void Reset(); + inline bool HasMore(); + + private: + // TODO(dcarney): Templatize this out for different stack sizes. + static const unsigned kStackSize = 32; + // Use a mask instead of doing modulo operations for stack wrapping. + static const unsigned kDepthMask = kStackSize-1; + STATIC_ASSERT(IS_POWER_OF_TWO(kStackSize)); + static inline unsigned OffsetForDepth(unsigned depth); + static inline uint32_t MaskForDepth(unsigned depth); + + inline void ClearRightDescent(); + inline void SetRightDescent(); + inline void PushLeft(ConsString* string); + inline void PushRight(ConsString* string, int32_t type); + inline void AdjustMaximumDepth(); + inline void Pop(); + inline void ResetStack(); + String* NextLeaf(bool* blewStack, int32_t* typeOut); + + unsigned depth_; + unsigned maximum_depth_; + uint32_t trace_; + ConsString* frames_[kStackSize]; + unsigned consumed_; + ConsString* root_; + int32_t root_type_; + unsigned root_length_; + DISALLOW_COPY_AND_ASSIGN(ConsStringIteratorOp); +}; + + +// Note: this class is not GC-safe. +class StringCharacterStream { + public: + inline StringCharacterStream( + String* string, unsigned offset, ConsStringIteratorOp* op); + inline uint16_t GetNext(); + inline bool HasMore(); + inline void Reset(String* string, unsigned offset, ConsStringIteratorOp* op); + inline void VisitOneByteString(const uint8_t* chars, unsigned length); + inline void VisitTwoByteString(const uint16_t* chars, unsigned length); + + private: + bool is_one_byte_; + union { + const uint8_t* buffer8_; + const uint16_t* buffer16_; + }; + const uint8_t* end_; + ConsStringIteratorOp* op_; + DISALLOW_COPY_AND_ASSIGN(StringCharacterStream); }; @@ -7904,9 +8073,7 @@ class Oddball: public HeapObject { static inline Oddball* cast(Object* obj); // Dispatched behavior. -#ifdef DEBUG - void OddballVerify(); -#endif + DECLARE_VERIFIER(Oddball) // Initialize the fields. MUST_USE_RESULT MaybeObject* Initialize(const char* to_string, @@ -7957,9 +8124,8 @@ class JSGlobalPropertyCell: public HeapObject { return address() + kValueOffset; } -#ifdef DEBUG - void JSGlobalPropertyCellVerify(); -#endif + DECLARE_VERIFIER(JSGlobalPropertyCell) + #ifdef OBJECT_PRINT inline void JSGlobalPropertyCellPrint() { JSGlobalPropertyCellPrint(stdout); @@ -8062,9 +8228,7 @@ class JSProxy: public JSReceiver { } void JSProxyPrint(FILE* out); #endif -#ifdef DEBUG - void JSProxyVerify(); -#endif + DECLARE_VERIFIER(JSProxy) // Layout description. We add padding so that a proxy has the same // size as a virgin JSObject. This is essential for becoming a JSObject @@ -8105,9 +8269,7 @@ class JSFunctionProxy: public JSProxy { } void JSFunctionProxyPrint(FILE* out); #endif -#ifdef DEBUG - void JSFunctionProxyVerify(); -#endif + DECLARE_VERIFIER(JSFunctionProxy) // Layout description. static const int kCallTrapOffset = JSProxy::kPaddingOffset; @@ -8142,9 +8304,7 @@ class JSSet: public JSObject { } void JSSetPrint(FILE* out); #endif -#ifdef DEBUG - void JSSetVerify(); -#endif + DECLARE_VERIFIER(JSSet) static const int kTableOffset = JSObject::kHeaderSize; static const int kSize = kTableOffset + kPointerSize; @@ -8169,9 +8329,7 @@ class JSMap: public JSObject { } void JSMapPrint(FILE* out); #endif -#ifdef DEBUG - void JSMapVerify(); -#endif + DECLARE_VERIFIER(JSMap) static const int kTableOffset = JSObject::kHeaderSize; static const int kSize = kTableOffset + kPointerSize; @@ -8199,9 +8357,7 @@ class JSWeakMap: public JSObject { } void JSWeakMapPrint(FILE* out); #endif -#ifdef DEBUG - void JSWeakMapVerify(); -#endif + DECLARE_VERIFIER(JSWeakMap) static const int kTableOffset = JSObject::kHeaderSize; static const int kNextOffset = kTableOffset + kPointerSize; @@ -8236,9 +8392,7 @@ class Foreign: public HeapObject { } void ForeignPrint(FILE* out); #endif -#ifdef DEBUG - void ForeignVerify(); -#endif + DECLARE_VERIFIER(Foreign) // Layout description. @@ -8276,6 +8430,7 @@ class JSArray: public JSObject { // Initializes the array to a certain length. inline bool AllowsSetElementsLength(); + // Can cause GC. MUST_USE_RESULT MaybeObject* SetElementsLength(Object* length); // Set the content of the array to the content of storage. @@ -8295,9 +8450,7 @@ class JSArray: public JSObject { } void JSArrayPrint(FILE* out); #endif -#ifdef DEBUG - void JSArrayVerify(); -#endif + DECLARE_VERIFIER(JSArray) // Number of element slots to pre-allocate for an empty array. static const int kPreallocatedArrayElements = 4; @@ -8376,9 +8529,7 @@ class AccessorInfo: public Struct { } void AccessorInfoPrint(FILE* out); #endif -#ifdef DEBUG - void AccessorInfoVerify(); -#endif + DECLARE_VERIFIER(AccessorInfo) static const int kGetterOffset = HeapObject::kHeaderSize; static const int kSetterOffset = kGetterOffset + kPointerSize; @@ -8442,9 +8593,7 @@ class AccessorPair: public Struct { #ifdef OBJECT_PRINT void AccessorPairPrint(FILE* out = stdout); #endif -#ifdef DEBUG - void AccessorPairVerify(); -#endif + DECLARE_VERIFIER(AccessorPair) static const int kGetterOffset = HeapObject::kHeaderSize; static const int kSetterOffset = kGetterOffset + kPointerSize; @@ -8478,9 +8627,7 @@ class AccessCheckInfo: public Struct { } void AccessCheckInfoPrint(FILE* out); #endif -#ifdef DEBUG - void AccessCheckInfoVerify(); -#endif + DECLARE_VERIFIER(AccessCheckInfo) static const int kNamedCallbackOffset = HeapObject::kHeaderSize; static const int kIndexedCallbackOffset = kNamedCallbackOffset + kPointerSize; @@ -8509,9 +8656,7 @@ class InterceptorInfo: public Struct { } void InterceptorInfoPrint(FILE* out); #endif -#ifdef DEBUG - void InterceptorInfoVerify(); -#endif + DECLARE_VERIFIER(InterceptorInfo) static const int kGetterOffset = HeapObject::kHeaderSize; static const int kSetterOffset = kGetterOffset + kPointerSize; @@ -8539,9 +8684,7 @@ class CallHandlerInfo: public Struct { } void CallHandlerInfoPrint(FILE* out); #endif -#ifdef DEBUG - void CallHandlerInfoVerify(); -#endif + DECLARE_VERIFIER(CallHandlerInfo) static const int kCallbackOffset = HeapObject::kHeaderSize; static const int kDataOffset = kCallbackOffset + kPointerSize; @@ -8557,9 +8700,7 @@ class TemplateInfo: public Struct { DECL_ACCESSORS(tag, Object) DECL_ACCESSORS(property_list, Object) -#ifdef DEBUG - void TemplateInfoVerify(); -#endif + DECLARE_VERIFIER(TemplateInfo) static const int kTagOffset = HeapObject::kHeaderSize; static const int kPropertyListOffset = kTagOffset + kPointerSize; @@ -8602,9 +8743,7 @@ class FunctionTemplateInfo: public TemplateInfo { } void FunctionTemplateInfoPrint(FILE* out); #endif -#ifdef DEBUG - void FunctionTemplateInfoVerify(); -#endif + DECLARE_VERIFIER(FunctionTemplateInfo) static const int kSerialNumberOffset = TemplateInfo::kHeaderSize; static const int kCallCodeOffset = kSerialNumberOffset + kPointerSize; @@ -8651,9 +8790,7 @@ class ObjectTemplateInfo: public TemplateInfo { } void ObjectTemplateInfoPrint(FILE* out); #endif -#ifdef DEBUG - void ObjectTemplateInfoVerify(); -#endif + DECLARE_VERIFIER(ObjectTemplateInfo) static const int kConstructorOffset = TemplateInfo::kHeaderSize; static const int kInternalFieldCountOffset = @@ -8675,9 +8812,7 @@ class SignatureInfo: public Struct { } void SignatureInfoPrint(FILE* out); #endif -#ifdef DEBUG - void SignatureInfoVerify(); -#endif + DECLARE_VERIFIER(SignatureInfo) static const int kReceiverOffset = Struct::kHeaderSize; static const int kArgsOffset = kReceiverOffset + kPointerSize; @@ -8700,9 +8835,7 @@ class TypeSwitchInfo: public Struct { } void TypeSwitchInfoPrint(FILE* out); #endif -#ifdef DEBUG - void TypeSwitchInfoVerify(); -#endif + DECLARE_VERIFIER(TypeSwitchInfo) static const int kTypesOffset = Struct::kHeaderSize; static const int kSize = kTypesOffset + kPointerSize; @@ -8752,9 +8885,7 @@ class DebugInfo: public Struct { } void DebugInfoPrint(FILE* out); #endif -#ifdef DEBUG - void DebugInfoVerify(); -#endif + DECLARE_VERIFIER(DebugInfo) static const int kSharedFunctionInfoIndex = Struct::kHeaderSize; static const int kOriginalCodeIndex = kSharedFunctionInfoIndex + kPointerSize; @@ -8810,9 +8941,7 @@ class BreakPointInfo: public Struct { } void BreakPointInfoPrint(FILE* out); #endif -#ifdef DEBUG - void BreakPointInfoVerify(); -#endif + DECLARE_VERIFIER(BreakPointInfo) static const int kCodePositionIndex = Struct::kHeaderSize; static const int kSourcePositionIndex = kCodePositionIndex + kPointerSize; @@ -8830,6 +8959,7 @@ class BreakPointInfo: public Struct { #undef DECL_BOOLEAN_ACCESSORS #undef DECL_ACCESSORS +#undef DECLARE_VERIFIER #define VISITOR_SYNCHRONIZATION_TAGS_LIST(V) \ V(kSymbolTable, "symbol_table", "(Symbols)") \ @@ -8894,6 +9024,10 @@ class ObjectVisitor BASE_EMBEDDED { // Visits a debug call target in the instruction stream. virtual void VisitDebugTarget(RelocInfo* rinfo); + // Visits the byte sequence in a function's prologue that contains information + // about the code's age. + virtual void VisitCodeAgeSequence(RelocInfo* rinfo); + // Handy shorthand for visiting a single pointer. virtual void VisitPointer(Object** p) { VisitPointers(p, p + 1); } diff --git a/deps/v8/src/optimizing-compiler-thread.cc b/deps/v8/src/optimizing-compiler-thread.cc index 06018dd1a9..e41c352f48 100644 --- a/deps/v8/src/optimizing-compiler-thread.cc +++ b/deps/v8/src/optimizing-compiler-thread.cc @@ -48,6 +48,8 @@ void OptimizingCompilerThread::Run() { while (true) { input_queue_semaphore_->Wait(); + Logger::TimerEventScope timer( + isolate_, Logger::TimerEventScope::v8_recompile_parallel); if (Acquire_Load(&stop_thread_)) { stop_semaphore_->Signal(); if (FLAG_trace_parallel_recompilation) { @@ -72,7 +74,13 @@ void OptimizingCompilerThread::Run() { USE(status); output_queue_.Enqueue(optimizing_compiler); - isolate_->stack_guard()->RequestCodeReadyEvent(); + if (!FLAG_manual_parallel_recompilation) { + isolate_->stack_guard()->RequestCodeReadyEvent(); + } else { + // In manual mode, do not trigger a code ready event. + // Instead, wait for the optimized functions to be installed manually. + output_queue_semaphore_->Signal(); + } if (FLAG_trace_parallel_recompilation) { time_spent_compiling_ += OS::Ticks() - compiling_start; @@ -99,6 +107,9 @@ void OptimizingCompilerThread::InstallOptimizedFunctions() { HandleScope handle_scope(isolate_); int functions_installed = 0; while (!output_queue_.IsEmpty()) { + if (FLAG_manual_parallel_recompilation) { + output_queue_semaphore_->Wait(); + } OptimizingCompiler* compiler = NULL; output_queue_.Dequeue(&compiler); Compiler::InstallOptimizedCode(compiler); @@ -110,6 +121,18 @@ void OptimizingCompilerThread::InstallOptimizedFunctions() { } +Handle<SharedFunctionInfo> + OptimizingCompilerThread::InstallNextOptimizedFunction() { + ASSERT(FLAG_manual_parallel_recompilation); + output_queue_semaphore_->Wait(); + OptimizingCompiler* compiler = NULL; + output_queue_.Dequeue(&compiler); + Handle<SharedFunctionInfo> shared = compiler->info()->shared_info(); + Compiler::InstallOptimizedCode(compiler); + return shared; +} + + void OptimizingCompilerThread::QueueForOptimization( OptimizingCompiler* optimizing_compiler) { input_queue_.Enqueue(optimizing_compiler); diff --git a/deps/v8/src/optimizing-compiler-thread.h b/deps/v8/src/optimizing-compiler-thread.h index d5627266d0..2d56d1a72b 100644 --- a/deps/v8/src/optimizing-compiler-thread.h +++ b/deps/v8/src/optimizing-compiler-thread.h @@ -29,8 +29,8 @@ #define V8_OPTIMIZING_COMPILER_THREAD_H_ #include "atomicops.h" -#include "platform.h" #include "flags.h" +#include "platform.h" #include "unbound-queue.h" namespace v8 { @@ -38,14 +38,19 @@ namespace internal { class HGraphBuilder; class OptimizingCompiler; +class SharedFunctionInfo; class OptimizingCompilerThread : public Thread { public: explicit OptimizingCompilerThread(Isolate *isolate) : Thread("OptimizingCompilerThread"), +#ifdef DEBUG + thread_id_(0), +#endif isolate_(isolate), stop_semaphore_(OS::CreateSemaphore(0)), input_queue_semaphore_(OS::CreateSemaphore(0)), + output_queue_semaphore_(OS::CreateSemaphore(0)), time_spent_compiling_(0), time_spent_total_(0) { NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(false)); @@ -57,6 +62,9 @@ class OptimizingCompilerThread : public Thread { void QueueForOptimization(OptimizingCompiler* optimizing_compiler); void InstallOptimizedFunctions(); + // Wait for the next optimized function and install it. + Handle<SharedFunctionInfo> InstallNextOptimizedFunction(); + inline bool IsQueueAvailable() { // We don't need a barrier since we have a data dependency right // after. @@ -76,24 +84,26 @@ class OptimizingCompilerThread : public Thread { #endif ~OptimizingCompilerThread() { + delete output_queue_semaphore_; // Only used for manual mode. delete input_queue_semaphore_; delete stop_semaphore_; } private: +#ifdef DEBUG + int thread_id_; +#endif + Isolate* isolate_; Semaphore* stop_semaphore_; Semaphore* input_queue_semaphore_; + Semaphore* output_queue_semaphore_; UnboundQueue<OptimizingCompiler*> input_queue_; UnboundQueue<OptimizingCompiler*> output_queue_; volatile AtomicWord stop_thread_; volatile Atomic32 queue_length_; int64_t time_spent_compiling_; int64_t time_spent_total_; - -#ifdef DEBUG - int thread_id_; -#endif }; } } // namespace v8::internal diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 37e903aac9..94d2f9e6a0 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -614,11 +614,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, ASSERT(target_stack_ == NULL); if (pre_data_ != NULL) pre_data_->Initialize(); - // Compute the parsing mode. - Mode mode = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY; - if (allow_natives_syntax_ || extension_ != NULL) mode = PARSE_EAGERLY; - ParsingModeScope parsing_mode(this, mode); - Handle<String> no_name = isolate()->factory()->empty_symbol(); FunctionLiteral* result = NULL; @@ -637,12 +632,19 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, scope->set_start_position(0); scope->set_end_position(source->length()); + // Compute the parsing mode. + Mode mode = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY; + if (allow_natives_syntax_ || extension_ != NULL || scope->is_eval_scope()) { + mode = PARSE_EAGERLY; + } + ParsingModeScope parsing_mode(this, mode); + FunctionState function_state(this, scope, isolate()); // Enters 'scope'. top_scope_->SetLanguageMode(info->language_mode()); ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone()); bool ok = true; int beg_loc = scanner().location().beg_pos; - ParseSourceElements(body, Token::EOS, info->is_eval(), &ok); + ParseSourceElements(body, Token::EOS, info->is_eval(), true, &ok); if (ok && !top_scope_->is_classic_mode()) { CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok); } @@ -832,145 +834,10 @@ void Parser::ReportMessageAt(Scanner::Location source_location, } -// Base class containing common code for the different finder classes used by -// the parser. -class ParserFinder { - protected: - ParserFinder() {} - static Assignment* AsAssignment(Statement* stat) { - if (stat == NULL) return NULL; - ExpressionStatement* exp_stat = stat->AsExpressionStatement(); - if (exp_stat == NULL) return NULL; - return exp_stat->expression()->AsAssignment(); - } -}; - - -// An InitializationBlockFinder finds and marks sequences of statements of the -// form expr.a = ...; expr.b = ...; etc. -class InitializationBlockFinder : public ParserFinder { - public: - // We find and mark the initialization blocks in top level - // non-looping code only. This is because the optimization prevents - // reuse of the map transitions, so it should be used only for code - // that will only be run once. - InitializationBlockFinder(Scope* top_scope, Target* target) - : enabled_(top_scope->DeclarationScope()->is_global_scope() && - !IsLoopTarget(target)), - first_in_block_(NULL), - last_in_block_(NULL), - block_size_(0) {} - - ~InitializationBlockFinder() { - if (!enabled_) return; - if (InBlock()) EndBlock(); - } - - void Update(Statement* stat) { - if (!enabled_) return; - Assignment* assignment = AsAssignment(stat); - if (InBlock()) { - if (BlockContinues(assignment)) { - UpdateBlock(assignment); - } else { - EndBlock(); - } - } - if (!InBlock() && (assignment != NULL) && - (assignment->op() == Token::ASSIGN)) { - StartBlock(assignment); - } - } - - private: - // The minimum number of contiguous assignment that will - // be treated as an initialization block. Benchmarks show that - // the overhead exceeds the savings below this limit. - static const int kMinInitializationBlock = 3; - - static bool IsLoopTarget(Target* target) { - while (target != NULL) { - if (target->node()->AsIterationStatement() != NULL) return true; - target = target->previous(); - } - return false; - } - - // Returns true if the expressions appear to denote the same object. - // In the context of initialization blocks, we only consider expressions - // of the form 'expr.x' or expr["x"]. - static bool SameObject(Expression* e1, Expression* e2) { - VariableProxy* v1 = e1->AsVariableProxy(); - VariableProxy* v2 = e2->AsVariableProxy(); - if (v1 != NULL && v2 != NULL) { - return v1->name()->Equals(*v2->name()); - } - Property* p1 = e1->AsProperty(); - Property* p2 = e2->AsProperty(); - if ((p1 == NULL) || (p2 == NULL)) return false; - Literal* key1 = p1->key()->AsLiteral(); - Literal* key2 = p2->key()->AsLiteral(); - if ((key1 == NULL) || (key2 == NULL)) return false; - if (!key1->handle()->IsString() || !key2->handle()->IsString()) { - return false; - } - String* name1 = String::cast(*key1->handle()); - String* name2 = String::cast(*key2->handle()); - if (!name1->Equals(name2)) return false; - return SameObject(p1->obj(), p2->obj()); - } - - // Returns true if the expressions appear to denote different properties - // of the same object. - static bool PropertyOfSameObject(Expression* e1, Expression* e2) { - Property* p1 = e1->AsProperty(); - Property* p2 = e2->AsProperty(); - if ((p1 == NULL) || (p2 == NULL)) return false; - return SameObject(p1->obj(), p2->obj()); - } - - bool BlockContinues(Assignment* assignment) { - if ((assignment == NULL) || (first_in_block_ == NULL)) return false; - if (assignment->op() != Token::ASSIGN) return false; - return PropertyOfSameObject(first_in_block_->target(), - assignment->target()); - } - - void StartBlock(Assignment* assignment) { - first_in_block_ = assignment; - last_in_block_ = assignment; - block_size_ = 1; - } - - void UpdateBlock(Assignment* assignment) { - last_in_block_ = assignment; - ++block_size_; - } - - void EndBlock() { - if (block_size_ >= kMinInitializationBlock) { - first_in_block_->mark_block_start(); - last_in_block_->mark_block_end(); - } - last_in_block_ = first_in_block_ = NULL; - block_size_ = 0; - } - - bool InBlock() { return first_in_block_ != NULL; } - - const bool enabled_; - Assignment* first_in_block_; - Assignment* last_in_block_; - int block_size_; - - DISALLOW_COPY_AND_ASSIGN(InitializationBlockFinder); -}; - - // A ThisNamedPropertyAssignmentFinder finds and marks statements of the form // this.x = ...;, where x is a named property. It also determines whether a // function contains only assignments of this type. -class ThisNamedPropertyAssignmentFinder : public ParserFinder { +class ThisNamedPropertyAssignmentFinder { public: ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone) : isolate_(isolate), @@ -981,6 +848,13 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder { zone_(zone) { } + static Assignment* AsAssignment(Statement* stat) { + if (stat == NULL) return NULL; + ExpressionStatement* exp_stat = stat->AsExpressionStatement(); + if (exp_stat == NULL) return NULL; + return exp_stat->expression()->AsAssignment(); + } + void Update(Scope* scope, Statement* stat) { // Bail out if function already has property assignment that are // not simple this property assignments. @@ -1135,6 +1009,7 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder { void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, int end_token, bool is_eval, + bool is_global, bool* ok) { // SourceElements :: // (ModuleElement)* <end_token> @@ -1146,7 +1021,6 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, TargetScope scope(&this->target_stack_); ASSERT(processor != NULL); - InitializationBlockFinder block_finder(top_scope_, target_stack_); ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(), zone()); bool directive_prologue = true; // Parsing directive prologue. @@ -1157,7 +1031,12 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, } Scanner::Location token_loc = scanner().peek_location(); - Statement* stat = ParseModuleElement(NULL, CHECK_OK); + Statement* stat; + if (is_global && !is_eval) { + stat = ParseModuleElement(NULL, CHECK_OK); + } else { + stat = ParseBlockElement(NULL, CHECK_OK); + } if (stat == NULL || stat->IsEmpty()) { directive_prologue = false; // End of directive prologue. continue; @@ -1182,12 +1061,14 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, // as specified in ES5 10.4.2(3). The correct fix would be to always // add this scope in DoParseProgram(), but that requires adaptations // all over the code base, so we go with a quick-fix for now. + // In the same manner, we have to patch the parsing mode. if (is_eval && !top_scope_->is_eval_scope()) { ASSERT(top_scope_->is_global_scope()); Scope* scope = NewScope(top_scope_, EVAL_SCOPE); scope->set_start_position(top_scope_->start_position()); scope->set_end_position(top_scope_->end_position()); top_scope_ = scope; + mode_ = PARSE_EAGERLY; } // TODO(ES6): Fix entering extended mode, once it is specified. top_scope_->SetLanguageMode(FLAG_harmony_scoping @@ -1201,7 +1082,6 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, } } - block_finder.Update(stat); // Find and mark all assignments to named properties in this (this.x =) if (top_scope_->is_function_scope()) { this_property_assignment_finder.Update(top_scope_, stat); @@ -1284,7 +1164,7 @@ Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) { #endif Module* module = ParseModule(CHECK_OK); - VariableProxy* proxy = NewUnresolved(name, LET, module->interface()); + VariableProxy* proxy = NewUnresolved(name, MODULE, module->interface()); Declaration* declaration = factory()->NewModuleDeclaration(proxy, module, top_scope_); Declare(declaration, true, CHECK_OK); @@ -1303,7 +1183,7 @@ Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) { if (module->body() == NULL) return factory()->NewEmptyStatement(); else - return module->body(); + return factory()->NewModuleStatement(proxy, module->body()); } @@ -1354,13 +1234,11 @@ Module* Parser::ParseModuleLiteral(bool* ok) { TargetCollector collector(zone()); Target target(&this->target_stack_, &collector); Target target_body(&this->target_stack_, body); - InitializationBlockFinder block_finder(top_scope_, target_stack_); while (peek() != Token::RBRACE) { Statement* stat = ParseModuleElement(NULL, CHECK_OK); if (stat && !stat->IsEmpty()) { body->AddStatement(stat, zone()); - block_finder.Update(stat); } } } @@ -1454,12 +1332,15 @@ Module* Parser::ParseModuleUrl(bool* ok) { if (FLAG_print_interface_details) PrintF("# Url "); #endif - Module* result = factory()->NewModuleUrl(symbol); - Interface* interface = result->interface(); + // Create an empty literal as long as the feature isn't finished. + USE(symbol); + Scope* scope = NewScope(top_scope_, MODULE_SCOPE); + Block* body = factory()->NewBlock(NULL, 1, false); + body->set_scope(scope); + Interface* interface = scope->interface(); + Module* result = factory()->NewModuleLiteral(body, interface); interface->Freeze(ok); ASSERT(*ok); - // Create dummy scope to avoid errors as long as the feature isn't finished. - Scope* scope = NewScope(top_scope_, MODULE_SCOPE); interface->Unify(scope->interface(), zone(), ok); ASSERT(*ok); return result; @@ -1828,10 +1709,9 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { *ok = false; return; } - const char* type = - (var->mode() == VAR) ? "var" : var->is_const_mode() ? "const" : "let"; Handle<String> type_string = - isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED); + isolate()->factory()->NewStringFromUtf8(CStrVector("Variable"), + TENURED); Expression* expression = NewThrowTypeError(isolate()->factory()->redeclaration_symbol(), type_string, name); @@ -2036,12 +1916,10 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { Block* result = factory()->NewBlock(labels, 16, false); Target target(&this->target_stack_, result); Expect(Token::LBRACE, CHECK_OK); - InitializationBlockFinder block_finder(top_scope_, target_stack_); while (peek() != Token::RBRACE) { Statement* stat = ParseStatement(NULL, CHECK_OK); if (stat && !stat->IsEmpty()) { result->AddStatement(stat, zone()); - block_finder.Update(stat); } } Expect(Token::RBRACE, CHECK_OK); @@ -2066,13 +1944,11 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { TargetCollector collector(zone()); Target target(&this->target_stack_, &collector); Target target_body(&this->target_stack_, body); - InitializationBlockFinder block_finder(top_scope_, target_stack_); while (peek() != Token::RBRACE) { Statement* stat = ParseBlockElement(NULL, CHECK_OK); if (stat && !stat->IsEmpty()) { body->AddStatement(stat, zone()); - block_finder.Update(stat); } } } @@ -2926,8 +2802,6 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { if (peek() == Token::IN && !name.is_null()) { Interface* interface = is_const ? Interface::NewConst() : Interface::NewValue(); - VariableProxy* each = - top_scope_->NewUnresolved(factory(), name, interface); ForInStatement* loop = factory()->NewForInStatement(labels); Target target(&this->target_stack_, loop); @@ -2935,6 +2809,8 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Expression* enumerable = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); + VariableProxy* each = + top_scope_->NewUnresolved(factory(), name, interface); Statement* body = ParseStatement(NULL, CHECK_OK); loop->Initialize(each, enumerable, body); Block* result = factory()->NewBlock(NULL, 2, false); @@ -2972,18 +2848,24 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { // TODO(keuchel): Move the temporary variable to the block scope, after // implementing stack allocated block scoped variables. - Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name); + Factory* heap_factory = isolate()->factory(); + Handle<String> tempstr = + heap_factory->NewConsString(heap_factory->dot_for_symbol(), name); + Handle<String> tempname = heap_factory->LookupSymbol(tempstr); + Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname); VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); - Interface* interface = Interface::NewValue(); - VariableProxy* each = - top_scope_->NewUnresolved(factory(), name, interface); ForInStatement* loop = factory()->NewForInStatement(labels); Target target(&this->target_stack_, loop); + // The expression does not see the loop variable. Expect(Token::IN, CHECK_OK); + top_scope_ = saved_scope; Expression* enumerable = ParseExpression(true, CHECK_OK); + top_scope_ = for_scope; Expect(Token::RPAREN, CHECK_OK); + VariableProxy* each = + top_scope_->NewUnresolved(factory(), name, Interface::NewValue()); Statement* body = ParseStatement(NULL, CHECK_OK); Block* body_block = factory()->NewBlock(NULL, 3, false); Assignment* assignment = factory()->NewAssignment( @@ -3327,7 +3209,8 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { if (op == Token::NOT) { // Convert the literal to a boolean condition and negate it. bool condition = literal->ToBoolean()->IsTrue(); - Handle<Object> result(isolate()->heap()->ToBoolean(!condition)); + Handle<Object> result(isolate()->heap()->ToBoolean(!condition), + isolate()); return factory()->NewLiteral(result); } else if (literal->IsNumber()) { // Compute some expressions involving only number literals. @@ -3835,17 +3718,16 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { int literal_index = current_function_state_->NextMaterializedLiteralIndex(); // Allocate a fixed array to hold all the object literals. - Handle<FixedArray> object_literals = - isolate()->factory()->NewFixedArray(values->length(), TENURED); - Handle<FixedDoubleArray> double_literals; - ElementsKind elements_kind = FAST_SMI_ELEMENTS; - bool has_only_undefined_values = true; - bool has_hole_values = false; + Handle<JSArray> array = + isolate()->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS); + isolate()->factory()->SetElementsCapacityAndLength( + array, values->length(), values->length()); // Fill in the literals. Heap* heap = isolate()->heap(); bool is_simple = true; int depth = 1; + bool is_holey = false; for (int i = 0, n = values->length(); i < n; i++) { MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral(); if (m_literal != NULL && m_literal->depth() + 1 > depth) { @@ -3853,91 +3735,33 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { } Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i)); if (boilerplate_value->IsTheHole()) { - has_hole_values = true; - object_literals->set_the_hole(i); - if (elements_kind == FAST_DOUBLE_ELEMENTS) { - double_literals->set_the_hole(i); - } + is_holey = true; } else if (boilerplate_value->IsUndefined()) { is_simple = false; - object_literals->set(i, Smi::FromInt(0)); - if (elements_kind == FAST_DOUBLE_ELEMENTS) { - double_literals->set(i, 0); - } + JSObject::SetOwnElement( + array, i, handle(Smi::FromInt(0), isolate()), kNonStrictMode); } else { - // Examine each literal element, and adjust the ElementsKind if the - // literal element is not of a type that can be stored in the current - // ElementsKind. Start with FAST_SMI_ONLY_ELEMENTS, and transition to - // FAST_DOUBLE_ELEMENTS and FAST_ELEMENTS as necessary. Always remember - // the tagged value, no matter what the ElementsKind is in case we - // ultimately end up in FAST_ELEMENTS. - has_only_undefined_values = false; - object_literals->set(i, *boilerplate_value); - if (elements_kind == FAST_SMI_ELEMENTS) { - // Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or - // FAST_ELEMENTS is required. - if (!boilerplate_value->IsSmi()) { - if (boilerplate_value->IsNumber() && FLAG_smi_only_arrays) { - // Allocate a double array on the FAST_DOUBLE_ELEMENTS transition to - // avoid over-allocating in TENURED space. - double_literals = isolate()->factory()->NewFixedDoubleArray( - values->length(), TENURED); - // Copy the contents of the FAST_SMI_ONLY_ELEMENT array to the - // FAST_DOUBLE_ELEMENTS array so that they are in sync. - for (int j = 0; j < i; ++j) { - Object* smi_value = object_literals->get(j); - if (smi_value->IsTheHole()) { - double_literals->set_the_hole(j); - } else { - double_literals->set(j, Smi::cast(smi_value)->value()); - } - } - double_literals->set(i, boilerplate_value->Number()); - elements_kind = FAST_DOUBLE_ELEMENTS; - } else { - elements_kind = FAST_ELEMENTS; - } - } - } else if (elements_kind == FAST_DOUBLE_ELEMENTS) { - // Continue to store double values in to FAST_DOUBLE_ELEMENTS arrays - // until the first value is seen that can't be stored as a double. - if (boilerplate_value->IsNumber()) { - double_literals->set(i, boilerplate_value->Number()); - } else { - elements_kind = FAST_ELEMENTS; - } - } + JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode); } } - // Very small array literals that don't have a concrete hint about their type - // from a constant value should default to the slow case to avoid lots of - // elements transitions on really small objects. - if (has_only_undefined_values && values->length() <= 2) { - elements_kind = FAST_ELEMENTS; - } + Handle<FixedArrayBase> element_values(array->elements()); // Simple and shallow arrays can be lazily copied, we transform the // elements array to a copy-on-write array. if (is_simple && depth == 1 && values->length() > 0 && - elements_kind != FAST_DOUBLE_ELEMENTS) { - object_literals->set_map(heap->fixed_cow_array_map()); + array->HasFastSmiOrObjectElements()) { + element_values->set_map(heap->fixed_cow_array_map()); } - Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS - ? Handle<FixedArrayBase>(double_literals) - : Handle<FixedArrayBase>(object_literals); - // Remember both the literal's constant values as well as the ElementsKind // in a 2-element FixedArray. - Handle<FixedArray> literals = - isolate()->factory()->NewFixedArray(2, TENURED); + Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(2, TENURED); - if (has_hole_values || !FLAG_packed_arrays) { - elements_kind = GetHoleyElementsKind(elements_kind); - } + ElementsKind kind = array->GetElementsKind(); + kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind); - literals->set(0, Smi::FromInt(elements_kind)); + literals->set(0, Smi::FromInt(kind)); literals->set(1, *element_values); return factory()->NewArrayLiteral( @@ -4667,7 +4491,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, RelocInfo::kNoPosition)), zone()); } - ParseSourceElements(body, Token::RBRACE, false, CHECK_OK); + ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK); materialized_literal_count = function_state.materialized_literal_count(); expected_property_count = function_state.expected_property_count(); diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h index 93dd03a63b..0f85f91583 100644 --- a/deps/v8/src/parser.h +++ b/deps/v8/src/parser.h @@ -96,7 +96,6 @@ class FunctionEntry BASE_EMBEDDED { private: Vector<unsigned> backing_; - bool owns_data_; }; @@ -454,7 +453,7 @@ class Parser { // construct a hashable id, so if more than 2^17 are allowed, this // should be checked. static const int kMaxNumFunctionParameters = 32766; - static const int kMaxNumFunctionLocals = 65535; + static const int kMaxNumFunctionLocals = 131071; // 2^17-1 enum Mode { PARSE_LAZILY, @@ -590,8 +589,8 @@ class Parser { // which is set to false if parsing failed; it is unchanged otherwise. // By making the 'exception handling' explicit, we are forced to check // for failure at the call sites. - void* ParseSourceElements(ZoneList<Statement*>* processor, - int end_token, bool is_eval, bool* ok); + void* ParseSourceElements(ZoneList<Statement*>* processor, int end_token, + bool is_eval, bool is_global, bool* ok); Statement* ParseModuleElement(ZoneStringList* labels, bool* ok); Statement* ParseModuleDeclaration(ZoneStringList* names, bool* ok); Module* ParseModule(bool* ok); diff --git a/deps/v8/src/platform-cygwin.cc b/deps/v8/src/platform-cygwin.cc index 089ea38d9a..8c5e5b9083 100644 --- a/deps/v8/src/platform-cygwin.cc +++ b/deps/v8/src/platform-cygwin.cc @@ -359,6 +359,12 @@ bool VirtualMemory::Guard(void* address) { } +bool VirtualMemory::HasLazyCommits() { + // TODO(alph): implement for the platform. + return false; +} + + class Thread::PlatformData : public Malloced { public: PlatformData() : thread_(kNoThread) {} @@ -649,24 +655,13 @@ class SamplerThread : public Thread { SamplerRegistry::State state; while ((state = SamplerRegistry::GetState()) != SamplerRegistry::HAS_NO_SAMPLERS) { - bool cpu_profiling_enabled = - (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); - bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); // When CPU profiling is enabled both JavaScript and C++ code is // profiled. We must not suspend. - if (!cpu_profiling_enabled) { + if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { + SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); + } else { if (rate_limiter_.SuspendIfNecessary()) continue; } - if (cpu_profiling_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { - return; - } - } - if (runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { - return; - } - } OS::Sleep(interval_); } } @@ -679,11 +674,6 @@ class SamplerThread : public Thread { sampler_thread->SampleContext(sampler); } - static void DoRuntimeProfile(Sampler* sampler, void* ignored) { - if (!sampler->isolate()->IsInitialized()) return; - sampler->isolate()->runtime_profiler()->NotifyTick(); - } - void SampleContext(Sampler* sampler) { HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); if (profiled_thread == NULL) return; diff --git a/deps/v8/src/platform-freebsd.cc b/deps/v8/src/platform-freebsd.cc index 738df11698..d02d668422 100644 --- a/deps/v8/src/platform-freebsd.cc +++ b/deps/v8/src/platform-freebsd.cc @@ -43,15 +43,12 @@ #include <sys/fcntl.h> // open #include <unistd.h> // getpagesize // If you don't have execinfo.h then you need devel/libexecinfo from ports. +#include <execinfo.h> // backtrace, backtrace_symbols #include <strings.h> // index #include <errno.h> #include <stdarg.h> #include <limits.h> -#if !defined(__DragonFly__) -#include <execinfo.h> // backtrace, backtrace_symbols -#endif - #undef MAP_TYPE #include "v8.h" @@ -299,9 +296,6 @@ void OS::SignalCodeMovingGC() { int OS::StackWalk(Vector<OS::StackFrame> frames) { -#if defined(__DragonFly__) - return 0; -#else int frames_size = frames.length(); ScopedVector<void*> addresses(frames_size); @@ -326,7 +320,6 @@ int OS::StackWalk(Vector<OS::StackFrame> frames) { free(symbols); return frames_count; -#endif } @@ -463,6 +456,12 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { } +bool VirtualMemory::HasLazyCommits() { + // TODO(alph): implement for the platform. + return false; +} + + class Thread::PlatformData : public Malloced { public: pthread_t thread_; // Thread handle for pthread. @@ -619,13 +618,6 @@ void FreeBSDSemaphore::Wait() { bool FreeBSDSemaphore::Wait(int timeout) { -#if defined(__DragonFly__) - /* DragonFlyBSD lacks sem_timedwait() and there is no good way to emulate it. - */ - if (sem_wait(&sem_)) abort(); - USE(timeout); - return true; -#else const long kOneSecondMicros = 1000000; // NOLINT // Split timeout into second and nanosecond parts. @@ -651,7 +643,6 @@ bool FreeBSDSemaphore::Wait(int timeout) { if (result == -1 && errno == ETIMEDOUT) return false; // Timeout. CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. } -#endif } @@ -721,11 +712,6 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { class SignalSender : public Thread { public: - enum SleepInterval { - HALF_INTERVAL, - FULL_INTERVAL - }; - static const int kSignalSenderStackSize = 64 * KB; explicit SignalSender(int interval) @@ -776,38 +762,14 @@ class SignalSender : public Thread { SamplerRegistry::State state; while ((state = SamplerRegistry::GetState()) != SamplerRegistry::HAS_NO_SAMPLERS) { - bool cpu_profiling_enabled = - (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); - bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); // When CPU profiling is enabled both JavaScript and C++ code is // profiled. We must not suspend. - if (!cpu_profiling_enabled) { - if (rate_limiter_.SuspendIfNecessary()) continue; - } - if (cpu_profiling_enabled && runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { - return; - } - Sleep(HALF_INTERVAL); - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { - return; - } - Sleep(HALF_INTERVAL); + if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { + SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); } else { - if (cpu_profiling_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, - this)) { - return; - } - } - if (runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, - NULL)) { - return; - } - } - Sleep(FULL_INTERVAL); + if (rate_limiter_.SuspendIfNecessary()) continue; } + Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough. } } @@ -817,21 +779,15 @@ class SignalSender : public Thread { sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); } - static void DoRuntimeProfile(Sampler* sampler, void* ignored) { - if (!sampler->isolate()->IsInitialized()) return; - sampler->isolate()->runtime_profiler()->NotifyTick(); - } - void SendProfilingSignal(pthread_t tid) { if (!signal_handler_installed_) return; pthread_kill(tid, SIGPROF); } - void Sleep(SleepInterval full_or_half) { + void Sleep() { // Convert ms to us and subtract 100 us to compensate delays // occuring during signal delivery. useconds_t interval = interval_ * 1000 - 100; - if (full_or_half == HALF_INTERVAL) interval /= 2; int result = usleep(interval); #ifdef DEBUG if (result != 0 && errno != EINTR) { diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc index 606d10236e..7a186413b5 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -148,6 +148,9 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) { case ARMv7: search_string = "ARMv7"; break; + case SUDIV: + search_string = "idiva"; + break; default: UNREACHABLE(); } @@ -171,6 +174,24 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) { } +CpuImplementer OS::GetCpuImplementer() { + static bool use_cached_value = false; + static CpuImplementer cached_value = UNKNOWN_IMPLEMENTER; + if (use_cached_value) { + return cached_value; + } + if (CPUInfoContainsString("CPU implementer\t: 0x41")) { + cached_value = ARM_IMPLEMENTER; + } else if (CPUInfoContainsString("CPU implementer\t: 0x51")) { + cached_value = QUALCOMM_IMPLEMENTER; + } else { + cached_value = UNKNOWN_IMPLEMENTER; + } + use_cached_value = true; + return cached_value; +} + + bool OS::ArmUsingHardFloat() { // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify // the Floating Point ABI used (PCS stands for Procedure Call Standard). @@ -701,6 +722,11 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { } +bool VirtualMemory::HasLazyCommits() { + return true; +} + + class Thread::PlatformData : public Malloced { public: PlatformData() : thread_(kNoThread) {} @@ -1065,11 +1091,6 @@ class Sampler::PlatformData : public Malloced { class SignalSender : public Thread { public: - enum SleepInterval { - HALF_INTERVAL, - FULL_INTERVAL - }; - static const int kSignalSenderStackSize = 64 * KB; explicit SignalSender(int interval) @@ -1125,43 +1146,16 @@ class SignalSender : public Thread { SamplerRegistry::State state; while ((state = SamplerRegistry::GetState()) != SamplerRegistry::HAS_NO_SAMPLERS) { - bool cpu_profiling_enabled = - (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); - bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); - if (cpu_profiling_enabled && !signal_handler_installed_) { - InstallSignalHandler(); - } else if (!cpu_profiling_enabled && signal_handler_installed_) { - RestoreSignalHandler(); - } // When CPU profiling is enabled both JavaScript and C++ code is // profiled. We must not suspend. - if (!cpu_profiling_enabled) { - if (rate_limiter_.SuspendIfNecessary()) continue; - } - if (cpu_profiling_enabled && runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { - return; - } - Sleep(HALF_INTERVAL); - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { - return; - } - Sleep(HALF_INTERVAL); + if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { + if (!signal_handler_installed_) InstallSignalHandler(); + SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); } else { - if (cpu_profiling_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, - this)) { - return; - } - } - if (runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, - NULL)) { - return; - } - } - Sleep(FULL_INTERVAL); + if (signal_handler_installed_) RestoreSignalHandler(); + if (rate_limiter_.SuspendIfNecessary()) continue; } + Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough. } } @@ -1171,11 +1165,6 @@ class SignalSender : public Thread { sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); } - static void DoRuntimeProfile(Sampler* sampler, void* ignored) { - if (!sampler->isolate()->IsInitialized()) return; - sampler->isolate()->runtime_profiler()->NotifyTick(); - } - void SendProfilingSignal(int tid) { if (!signal_handler_installed_) return; // Glibc doesn't provide a wrapper for tgkill(2). @@ -1186,11 +1175,10 @@ class SignalSender : public Thread { #endif } - void Sleep(SleepInterval full_or_half) { + void Sleep() { // Convert ms to us and subtract 100 us to compensate delays // occuring during signal delivery. useconds_t interval = interval_ * 1000 - 100; - if (full_or_half == HALF_INTERVAL) interval /= 2; #if defined(ANDROID) usleep(interval); #else diff --git a/deps/v8/src/platform-macos.cc b/deps/v8/src/platform-macos.cc index a216f6e4ca..e69833885c 100644 --- a/deps/v8/src/platform-macos.cc +++ b/deps/v8/src/platform-macos.cc @@ -471,6 +471,11 @@ bool VirtualMemory::ReleaseRegion(void* address, size_t size) { } +bool VirtualMemory::HasLazyCommits() { + return false; +} + + class Thread::PlatformData : public Malloced { public: PlatformData() : thread_(kNoThread) {} @@ -782,24 +787,13 @@ class SamplerThread : public Thread { SamplerRegistry::State state; while ((state = SamplerRegistry::GetState()) != SamplerRegistry::HAS_NO_SAMPLERS) { - bool cpu_profiling_enabled = - (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); - bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); // When CPU profiling is enabled both JavaScript and C++ code is // profiled. We must not suspend. - if (!cpu_profiling_enabled) { + if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { + SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); + } else { if (rate_limiter_.SuspendIfNecessary()) continue; } - if (cpu_profiling_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { - return; - } - } - if (runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { - return; - } - } OS::Sleep(interval_); } } @@ -812,11 +806,6 @@ class SamplerThread : public Thread { sampler_thread->SampleContext(sampler); } - static void DoRuntimeProfile(Sampler* sampler, void* ignored) { - if (!sampler->isolate()->IsInitialized()) return; - sampler->isolate()->runtime_profiler()->NotifyTick(); - } - void SampleContext(Sampler* sampler) { thread_act_t profiled_thread = sampler->platform_data()->profiled_thread(); TickSample sample_obj; diff --git a/deps/v8/src/platform-nullos.cc b/deps/v8/src/platform-nullos.cc index 679ef8e89e..ccd21231ea 100644 --- a/deps/v8/src/platform-nullos.cc +++ b/deps/v8/src/platform-nullos.cc @@ -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: @@ -215,6 +215,11 @@ double OS::nan_value() { } +CpuImplementer OS::GetCpuImplementer() { + UNIMPLEMENTED(); +} + + bool OS::ArmCpuHasFeature(CpuFeature feature) { UNIMPLEMENTED(); } @@ -335,6 +340,12 @@ bool VirtualMemory::Guard(void* address) { } +bool VirtualMemory::HasLazyCommits() { + // TODO(alph): implement for the platform. + return false; +} + + class Thread::PlatformData : public Malloced { public: PlatformData() { diff --git a/deps/v8/src/platform-openbsd.cc b/deps/v8/src/platform-openbsd.cc index 408d4dc0f8..d4ab9a66ee 100644 --- a/deps/v8/src/platform-openbsd.cc +++ b/deps/v8/src/platform-openbsd.cc @@ -504,6 +504,12 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { } +bool VirtualMemory::HasLazyCommits() { + // TODO(alph): implement for the platform. + return false; +} + + class Thread::PlatformData : public Malloced { public: PlatformData() : thread_(kNoThread) {} @@ -778,11 +784,6 @@ class Sampler::PlatformData : public Malloced { class SignalSender : public Thread { public: - enum SleepInterval { - HALF_INTERVAL, - FULL_INTERVAL - }; - static const int kSignalSenderStackSize = 64 * KB; explicit SignalSender(int interval) @@ -838,43 +839,16 @@ class SignalSender : public Thread { SamplerRegistry::State state; while ((state = SamplerRegistry::GetState()) != SamplerRegistry::HAS_NO_SAMPLERS) { - bool cpu_profiling_enabled = - (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); - bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); - if (cpu_profiling_enabled && !signal_handler_installed_) { - InstallSignalHandler(); - } else if (!cpu_profiling_enabled && signal_handler_installed_) { - RestoreSignalHandler(); - } // When CPU profiling is enabled both JavaScript and C++ code is // profiled. We must not suspend. - if (!cpu_profiling_enabled) { - if (rate_limiter_.SuspendIfNecessary()) continue; - } - if (cpu_profiling_enabled && runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { - return; - } - Sleep(HALF_INTERVAL); - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { - return; - } - Sleep(HALF_INTERVAL); + if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { + if (!signal_handler_installed_) InstallSignalHandler(); + SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); } else { - if (cpu_profiling_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, - this)) { - return; - } - } - if (runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, - NULL)) { - return; - } - } - Sleep(FULL_INTERVAL); + if (signal_handler_installed_) RestoreSignalHandler(); + if (rate_limiter_.SuspendIfNecessary()) continue; } + Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough. } } @@ -884,21 +858,15 @@ class SignalSender : public Thread { sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); } - static void DoRuntimeProfile(Sampler* sampler, void* ignored) { - if (!sampler->isolate()->IsInitialized()) return; - sampler->isolate()->runtime_profiler()->NotifyTick(); - } - void SendProfilingSignal(pthread_t tid) { if (!signal_handler_installed_) return; pthread_kill(tid, SIGPROF); } - void Sleep(SleepInterval full_or_half) { + void Sleep() { // Convert ms to us and subtract 100 us to compensate delays // occuring during signal delivery. useconds_t interval = interval_ * 1000 - 100; - if (full_or_half == HALF_INTERVAL) interval /= 2; int result = usleep(interval); #ifdef DEBUG if (result != 0 && errno != EINTR) { diff --git a/deps/v8/src/platform-posix.cc b/deps/v8/src/platform-posix.cc index 2b80015161..0016d59d3a 100644 --- a/deps/v8/src/platform-posix.cc +++ b/deps/v8/src/platform-posix.cc @@ -109,20 +109,11 @@ void* OS::GetRandomMmapAddr() { raw_addr &= V8_UINT64_C(0x3ffffffff000); #else uint32_t raw_addr = V8::RandomPrivate(isolate); - - // For our 32-bit mmap() hint, we pick a random address in the bottom - // half of the top half of the address space (that is, the third quarter). - // Because we do not MAP_FIXED, this will be treated only as a hint -- the - // system will not fail to mmap() because something else happens to already - // be mapped at our random address. We deliberately set the hint high enough - // to get well above the system's break (that is, the heap); systems will - // either try the hint and if that fails move higher (MacOS and other BSD - // derivatives) or try the hint and if that fails allocate as if there were - // no hint at all (Linux, Solaris, illumos and derivatives). The high hint - // prevents the break from getting hemmed in at low values, ceding half of - // the address space to the system heap. + // The range 0x20000000 - 0x60000000 is relatively unpopulated across a + // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos + // 10.6 and 10.7. raw_addr &= 0x3ffff000; - raw_addr += 0x80000000; + raw_addr += 0x20000000; #endif return reinterpret_cast<void*>(raw_addr); } @@ -151,11 +142,19 @@ UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) +UNARY_MATH_FUNCTION(exp, CreateExpFunction()) UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) #undef MATH_FUNCTION +void lazily_initialize_fast_exp() { + if (fast_exp_function == NULL) { + init_fast_exp_function(); + } +} + + double OS::nan_value() { // NAN from math.h is defined in C99 and not in POSIX. return NAN; @@ -341,6 +340,7 @@ void POSIXPostSetUp() { init_fast_cos_function(); init_fast_tan_function(); init_fast_log_function(); + // fast_exp is initialized lazily. init_fast_sqrt_function(); } diff --git a/deps/v8/src/platform-solaris.cc b/deps/v8/src/platform-solaris.cc index 4248ea214f..70f86596e8 100644 --- a/deps/v8/src/platform-solaris.cc +++ b/deps/v8/src/platform-solaris.cc @@ -125,12 +125,8 @@ const char* OS::LocalTimezone(double time) { double OS::LocalTimeOffset() { - // On Solaris, struct tm does not contain a tm_gmtoff field. - time_t utc = time(NULL); - ASSERT(utc != -1); - struct tm* loc = localtime(&utc); - ASSERT(loc != NULL); - return static_cast<double>((mktime(loc) - utc) * msPerSecond); + tzset(); + return -static_cast<double>(timezone * msPerSecond); } @@ -448,6 +444,12 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { } +bool VirtualMemory::HasLazyCommits() { + // TODO(alph): implement for the platform. + return false; +} + + class Thread::PlatformData : public Malloced { public: PlatformData() : thread_(kNoThread) { } @@ -699,11 +701,6 @@ class Sampler::PlatformData : public Malloced { class SignalSender : public Thread { public: - enum SleepInterval { - HALF_INTERVAL, - FULL_INTERVAL - }; - static const int kSignalSenderStackSize = 64 * KB; explicit SignalSender(int interval) @@ -758,44 +755,16 @@ class SignalSender : public Thread { SamplerRegistry::State state; while ((state = SamplerRegistry::GetState()) != SamplerRegistry::HAS_NO_SAMPLERS) { - bool cpu_profiling_enabled = - (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); - bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); - if (cpu_profiling_enabled && !signal_handler_installed_) { - InstallSignalHandler(); - } else if (!cpu_profiling_enabled && signal_handler_installed_) { - RestoreSignalHandler(); - } - // When CPU profiling is enabled both JavaScript and C++ code is // profiled. We must not suspend. - if (!cpu_profiling_enabled) { - if (rate_limiter_.SuspendIfNecessary()) continue; - } - if (cpu_profiling_enabled && runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { - return; - } - Sleep(HALF_INTERVAL); - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { - return; - } - Sleep(HALF_INTERVAL); + if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { + if (!signal_handler_installed_) InstallSignalHandler(); + SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); } else { - if (cpu_profiling_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, - this)) { - return; - } - } - if (runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, - NULL)) { - return; - } - } - Sleep(FULL_INTERVAL); + if (signal_handler_installed_) RestoreSignalHandler(); + if (rate_limiter_.SuspendIfNecessary()) continue; } + Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough. } } @@ -805,21 +774,15 @@ class SignalSender : public Thread { sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); } - static void DoRuntimeProfile(Sampler* sampler, void* ignored) { - if (!sampler->isolate()->IsInitialized()) return; - sampler->isolate()->runtime_profiler()->NotifyTick(); - } - void SendProfilingSignal(pthread_t tid) { if (!signal_handler_installed_) return; pthread_kill(tid, SIGPROF); } - void Sleep(SleepInterval full_or_half) { + void Sleep() { // Convert ms to us and subtract 100 us to compensate delays // occuring during signal delivery. useconds_t interval = interval_ * 1000 - 100; - if (full_or_half == HALF_INTERVAL) interval /= 2; int result = usleep(interval); #ifdef DEBUG if (result != 0 && errno != EINTR) { diff --git a/deps/v8/src/platform-win32.cc b/deps/v8/src/platform-win32.cc index 49463be8e0..f00d6b01b2 100644 --- a/deps/v8/src/platform-win32.cc +++ b/deps/v8/src/platform-win32.cc @@ -199,11 +199,19 @@ UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) +UNARY_MATH_FUNCTION(exp, CreateExpFunction()) UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) #undef MATH_FUNCTION +void lazily_initialize_fast_exp() { + if (fast_exp_function == NULL) { + init_fast_exp_function(); + } +} + + void MathSetup() { #ifdef _WIN64 init_modulo_function(); @@ -212,6 +220,7 @@ void MathSetup() { init_fast_cos_function(); init_fast_tan_function(); init_fast_log_function(); + // fast_exp is initialized lazily. init_fast_sqrt_function(); } @@ -1551,6 +1560,12 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { } +bool VirtualMemory::HasLazyCommits() { + // TODO(alph): implement for the platform. + return false; +} + + // ---------------------------------------------------------------------------- // Win32 thread support. @@ -1995,24 +2010,13 @@ class SamplerThread : public Thread { SamplerRegistry::State state; while ((state = SamplerRegistry::GetState()) != SamplerRegistry::HAS_NO_SAMPLERS) { - bool cpu_profiling_enabled = - (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); - bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); // When CPU profiling is enabled both JavaScript and C++ code is // profiled. We must not suspend. - if (!cpu_profiling_enabled) { + if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { + SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); + } else { if (rate_limiter_.SuspendIfNecessary()) continue; } - if (cpu_profiling_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { - return; - } - } - if (runtime_profiler_enabled) { - if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { - return; - } - } OS::Sleep(interval_); } } @@ -2025,11 +2029,6 @@ class SamplerThread : public Thread { sampler_thread->SampleContext(sampler); } - static void DoRuntimeProfile(Sampler* sampler, void* ignored) { - if (!sampler->isolate()->IsInitialized()) return; - sampler->isolate()->runtime_profiler()->NotifyTick(); - } - void SampleContext(Sampler* sampler) { HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); if (profiled_thread == NULL) return; diff --git a/deps/v8/src/platform.h b/deps/v8/src/platform.h index a32fbbc028..6f75ca83d5 100644 --- a/deps/v8/src/platform.h +++ b/deps/v8/src/platform.h @@ -107,7 +107,11 @@ namespace internal { // Use AtomicWord for a machine-sized pointer. It is assumed that // reads and writes of naturally aligned values of this type are atomic. +#if defined(__OpenBSD__) && defined(__i386__) +typedef Atomic32 AtomicWord; +#else typedef intptr_t AtomicWord; +#endif class Semaphore; class Mutex; @@ -115,12 +119,16 @@ class Mutex; double ceiling(double x); double modulo(double x, double y); -// Custom implementation of sin, cos, tan and log. +// Custom implementation of math functions. double fast_sin(double input); double fast_cos(double input); double fast_tan(double input); double fast_log(double input); +double fast_exp(double input); double fast_sqrt(double input); +// The custom exp implementation needs 16KB of lookup data; initialize it +// on demand. +void lazily_initialize_fast_exp(); // Forward declarations. class Socket; @@ -304,6 +312,9 @@ class OS { // Returns the double constant NAN static double nan_value(); + // Support runtime detection of Cpu implementer + static CpuImplementer GetCpuImplementer(); + // Support runtime detection of VFP3 on ARM CPUs. static bool ArmCpuHasFeature(CpuFeature feature); @@ -425,6 +436,11 @@ class VirtualMemory { // and the same size it was reserved with. static bool ReleaseRegion(void* base, size_t size); + // Returns true if OS performs lazy commits, i.e. the memory allocation call + // defers actual physical memory allocation till the first memory access. + // Otherwise returns false. + static bool HasLazyCommits(); + private: void* address_; // Start address of the virtual memory. size_t size_; // Size of the virtual memory. diff --git a/deps/v8/src/preparser.h b/deps/v8/src/preparser.h index 13261f7a5b..ad52d74bbd 100644 --- a/deps/v8/src/preparser.h +++ b/deps/v8/src/preparser.h @@ -150,11 +150,11 @@ class PreParser { // Parses a single function literal, from the opening parentheses before // parameters to the closing brace after the body. - // Returns a FunctionEntry describing the body of the funciton in enough + // Returns a FunctionEntry describing the body of the function in enough // detail that it can be lazily compiled. // The scanner is expected to have matched the "function" keyword and // parameters, and have consumed the initial '{'. - // At return, unless an error occured, the scanner is positioned before the + // At return, unless an error occurred, the scanner is positioned before the // the final '}'. PreParseResult PreParseLazyFunction(i::LanguageMode mode, i::ParserRecorder* log); diff --git a/deps/v8/src/prettyprinter.cc b/deps/v8/src/prettyprinter.cc index 0d8dadce1a..602fbb40b9 100644 --- a/deps/v8/src/prettyprinter.cc +++ b/deps/v8/src/prettyprinter.cc @@ -122,6 +122,14 @@ void PrettyPrinter::VisitModuleUrl(ModuleUrl* node) { } +void PrettyPrinter::VisitModuleStatement(ModuleStatement* node) { + Print("module "); + PrintLiteral(node->proxy()->name(), false); + Print(" "); + Visit(node->body()); +} + + void PrettyPrinter::VisitExpressionStatement(ExpressionStatement* node) { Visit(node->expression()); Print(";"); @@ -822,6 +830,13 @@ void AstPrinter::VisitModuleUrl(ModuleUrl* node) { } +void AstPrinter::VisitModuleStatement(ModuleStatement* node) { + IndentedScope indent(this, "MODULE"); + PrintLiteralIndented("NAME", node->proxy()->name(), true); + PrintStatements(node->body()->statements()); +} + + void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) { Visit(node->expression()); } diff --git a/deps/v8/src/profile-generator-inl.h b/deps/v8/src/profile-generator-inl.h index 02e146f14a..e4f32a7c7a 100644 --- a/deps/v8/src/profile-generator-inl.h +++ b/deps/v8/src/profile-generator-inl.h @@ -84,7 +84,7 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { return gc_entry_; case JS: case COMPILER: - case PARALLEL_COMPILER_PROLOGUE: + case PARALLEL_COMPILER: // DOM events handlers are reported as OTHER / EXTERNAL entries. // To avoid confusing people, let's put all these entries into // one bucket. diff --git a/deps/v8/src/profile-generator.cc b/deps/v8/src/profile-generator.cc index c3b7622b09..6e49c7bd9e 100644 --- a/deps/v8/src/profile-generator.cc +++ b/deps/v8/src/profile-generator.cc @@ -1644,12 +1644,14 @@ HeapObject* const V8HeapExplorer::kLastGcSubrootObject = V8HeapExplorer::V8HeapExplorer( HeapSnapshot* snapshot, - SnapshottingProgressReportingInterface* progress) + SnapshottingProgressReportingInterface* progress, + v8::HeapProfiler::ObjectNameResolver* resolver) : heap_(Isolate::Current()->heap()), snapshot_(snapshot), collection_(snapshot_->collection()), progress_(progress), - filler_(NULL) { + filler_(NULL), + global_object_name_resolver_(resolver) { } @@ -1774,7 +1776,14 @@ void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) { const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) { switch (object->map()->instance_type()) { - case MAP_TYPE: return "system / Map"; + case MAP_TYPE: + switch (Map::cast(object)->instance_type()) { +#define MAKE_STRING_MAP_CASE(instance_type, size, name, Name) \ + case instance_type: return "system / Map (" #Name ")"; + STRING_TYPE_LIST(MAKE_STRING_MAP_CASE) +#undef MAKE_STRING_MAP_CASE + default: return "system / Map"; + } case JS_GLOBAL_PROPERTY_CELL_TYPE: return "system / JSGlobalPropertyCell"; case FOREIGN_TYPE: return "system / Foreign"; case ODDBALL_TYPE: return "system / Oddball"; @@ -1851,7 +1860,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { ExtractJSObjectReferences(entry, JSObject::cast(obj)); } else if (obj->IsString()) { ExtractStringReferences(entry, String::cast(obj)); - extract_indexed_refs = false; } else if (obj->IsContext()) { ExtractContextReferences(entry, Context::cast(obj)); } else if (obj->IsMap()) { @@ -1966,11 +1974,14 @@ void V8HeapExplorer::ExtractJSObjectReferences( 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()); + SetInternalReference(cs, entry, "first", cs->first(), + ConsString::kFirstOffset); + SetInternalReference(cs, entry, "second", cs->second(), + ConsString::kSecondOffset); } else if (string->IsSlicedString()) { SlicedString* ss = SlicedString::cast(string); - SetInternalReference(ss, entry, "parent", ss->parent()); + SetInternalReference(ss, entry, "parent", ss->parent(), + SlicedString::kParentOffset); } } @@ -1988,7 +1999,7 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { "(context func. result caches)"); TagObject(context->normalized_map_cache(), "(context norm. map cache)"); TagObject(context->runtime_context(), "(runtime context)"); - TagObject(context->data(), "(context data)"); + TagObject(context->embedder_data(), "(context data)"); NATIVE_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD); #undef EXTRACT_CONTEXT_FIELD for (int i = Context::FIRST_WEAK_SLOT; @@ -2009,21 +2020,32 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { Map::kConstructorOffset); if (map->HasTransitionArray()) { TransitionArray* transitions = map->transitions(); - if (!transitions->descriptors()->IsEmpty()) { - DescriptorArray* descriptors = transitions->descriptors(); - TagObject(descriptors, "(map descriptors)"); - SetInternalReference(transitions, entry, - "descriptors", descriptors, - TransitionArray::kDescriptorsOffset); - IndexedReferencesExtractor refs_extractor( - this, transitions, entry); - transitions->Iterate(&refs_extractor); - } + + Object* back_pointer = transitions->back_pointer_storage(); + TagObject(transitions->back_pointer_storage(), "(back pointer)"); + SetInternalReference(transitions, entry, + "backpointer", back_pointer, + TransitionArray::kBackPointerStorageOffset); + IndexedReferencesExtractor transitions_refs(this, transitions, entry); + transitions->Iterate(&transitions_refs); + TagObject(transitions, "(transition array)"); SetInternalReference(map, entry, "transitions", transitions, Map::kTransitionsOrBackPointerOffset); + } else { + Object* back_pointer = map->GetBackPointer(); + TagObject(back_pointer, "(back pointer)"); + SetInternalReference(map, entry, + "backpointer", back_pointer, + Map::kTransitionsOrBackPointerOffset); } + DescriptorArray* descriptors = map->instance_descriptors(); + TagObject(descriptors, "(map descriptors)"); + SetInternalReference(map, entry, + "descriptors", descriptors, + Map::kDescriptorsOffset); + SetInternalReference(map, entry, "code_cache", map->code_cache(), Map::kCodeCacheOffset); @@ -2119,9 +2141,11 @@ void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) { SetInternalReference(code, entry, "deoptimization_data", code->deoptimization_data(), Code::kDeoptimizationDataOffset); - SetInternalReference(code, entry, - "type_feedback_info", code->type_feedback_info(), - Code::kTypeFeedbackInfoOffset); + if (code->kind() == Code::FUNCTION) { + SetInternalReference(code, entry, + "type_feedback_info", code->type_feedback_info(), + Code::kTypeFeedbackInfoOffset); + } SetInternalReference(code, entry, "gc_metadata", code->gc_metadata(), Code::kGCMetadataOffset); @@ -2179,7 +2203,9 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) { void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { if (js_obj->HasFastProperties()) { DescriptorArray* descs = js_obj->map()->instance_descriptors(); + int real_size = js_obj->map()->NumberOfOwnDescriptors(); for (int i = 0; i < descs->number_of_descriptors(); i++) { + if (descs->GetDetails(i).descriptor_index() > real_size) continue; switch (descs->GetType(i)) { case FIELD: { int index = descs->GetFieldIndex(i); @@ -2430,19 +2456,17 @@ bool V8HeapExplorer::IterateAndExtractReferences( 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(); + && object != heap_->empty_byte_array() + && object != heap_->empty_fixed_array() + && object != heap_->empty_descriptor_array() + && object != heap_->fixed_array_map() + && object != heap_->global_property_cell_map() + && object != heap_->shared_function_info_map() + && object != heap_->free_space_map() + && object != heap_->one_pointer_filler_map() + && object != heap_->two_pointer_filler_map(); } @@ -2690,21 +2714,30 @@ void V8HeapExplorer::TagGlobalObjects() { isolate->factory()->NewStringFromAscii(CStrVector("URL")); const char** urls = NewArray<const char*>(enumerator.count()); for (int i = 0, l = enumerator.count(); i < l; ++i) { - urls[i] = NULL; - HandleScope scope; - Handle<JSGlobalObject> global_obj = enumerator.at(i); - Object* obj_document; - if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && - obj_document->IsJSObject()) { - // FixMe: Workaround: SharedWorker's current Isolate has NULL context. - // As result GetProperty(*url_string) will crash. - if (!Isolate::Current()->context() && obj_document->IsJSGlobalProxy()) - continue; - JSObject* document = JSObject::cast(obj_document); - Object* obj_url; - if (document->GetProperty(*url_string)->ToObject(&obj_url) && - obj_url->IsString()) { - urls[i] = collection_->names()->GetName(String::cast(obj_url)); + if (global_object_name_resolver_) { + HandleScope scope; + Handle<JSGlobalObject> global_obj = enumerator.at(i); + urls[i] = global_object_name_resolver_->GetName( + Utils::ToLocal(Handle<JSObject>::cast(global_obj))); + } else { + // TODO(yurys): This branch is going to be removed once Chromium migrates + // to the new name resolver. + urls[i] = NULL; + HandleScope scope; + Handle<JSGlobalObject> global_obj = enumerator.at(i); + Object* obj_document; + if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && + obj_document->IsJSObject()) { + // FixMe: Workaround: SharedWorker's current Isolate has NULL context. + // As result GetProperty(*url_string) will crash. + if (!Isolate::Current()->context() && obj_document->IsJSGlobalProxy()) + continue; + JSObject* document = JSObject::cast(obj_document); + Object* obj_url; + if (document->GetProperty(*url_string)->ToObject(&obj_url) && + obj_url->IsString()) { + urls[i] = collection_->names()->GetName(String::cast(obj_url)); + } } } } @@ -3059,11 +3092,13 @@ class SnapshotFiller : public SnapshotFillerInterface { }; -HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot, - v8::ActivityControl* control) +HeapSnapshotGenerator::HeapSnapshotGenerator( + HeapSnapshot* snapshot, + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver) : snapshot_(snapshot), control_(control), - v8_heap_explorer_(snapshot_, this), + v8_heap_explorer_(snapshot_, this, resolver), dom_explorer_(snapshot_, this) { } @@ -3082,26 +3117,26 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { Heap::kMakeHeapIterableMask, "HeapSnapshotGenerator::GenerateSnapshot"); -#ifdef DEBUG +#ifdef VERIFY_HEAP Heap* debug_heap = Isolate::Current()->heap(); - ASSERT(!debug_heap->old_data_space()->was_swept_conservatively()); - ASSERT(!debug_heap->old_pointer_space()->was_swept_conservatively()); - ASSERT(!debug_heap->code_space()->was_swept_conservatively()); - ASSERT(!debug_heap->cell_space()->was_swept_conservatively()); - ASSERT(!debug_heap->map_space()->was_swept_conservatively()); + CHECK(!debug_heap->old_data_space()->was_swept_conservatively()); + CHECK(!debug_heap->old_pointer_space()->was_swept_conservatively()); + CHECK(!debug_heap->code_space()->was_swept_conservatively()); + CHECK(!debug_heap->cell_space()->was_swept_conservatively()); + CHECK(!debug_heap->map_space()->was_swept_conservatively()); #endif // The following code uses heap iterators, so we want the heap to be // stable. It should follow TagGlobalObjects as that can allocate. AssertNoAllocation no_alloc; -#ifdef DEBUG +#ifdef VERIFY_HEAP debug_heap->Verify(); #endif SetProgressTotal(1); // 1 pass. -#ifdef DEBUG +#ifdef VERIFY_HEAP debug_heap->Verify(); #endif diff --git a/deps/v8/src/profile-generator.h b/deps/v8/src/profile-generator.h index 04f4a1c71d..f306659aba 100644 --- a/deps/v8/src/profile-generator.h +++ b/deps/v8/src/profile-generator.h @@ -851,7 +851,8 @@ class SnapshottingProgressReportingInterface { class V8HeapExplorer : public HeapEntriesAllocator { public: V8HeapExplorer(HeapSnapshot* snapshot, - SnapshottingProgressReportingInterface* progress); + SnapshottingProgressReportingInterface* progress, + v8::HeapProfiler::ObjectNameResolver* resolver); virtual ~V8HeapExplorer(); virtual HeapEntry* AllocateEntry(HeapThing ptr); void AddRootEntries(SnapshotFillerInterface* filler); @@ -945,6 +946,7 @@ class V8HeapExplorer : public HeapEntriesAllocator { SnapshotFillerInterface* filler_; HeapObjectsSet objects_tags_; HeapObjectsSet strong_gc_subroot_names_; + v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_; static HeapObject* const kGcRootsObject; static HeapObject* const kFirstGcSubrootObject; @@ -1021,7 +1023,8 @@ class NativeObjectsExplorer { class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface { public: HeapSnapshotGenerator(HeapSnapshot* snapshot, - v8::ActivityControl* control); + v8::ActivityControl* control, + v8::HeapProfiler::ObjectNameResolver* resolver); bool GenerateSnapshot(); private: diff --git a/deps/v8/src/property-details.h b/deps/v8/src/property-details.h index b8fbb3c92a..510e9852a9 100644 --- a/deps/v8/src/property-details.h +++ b/deps/v8/src/property-details.h @@ -38,6 +38,10 @@ enum PropertyAttributes { READ_ONLY = v8::ReadOnly, DONT_ENUM = v8::DontEnum, DONT_DELETE = v8::DontDelete, + + SEALED = DONT_ENUM | DONT_DELETE, + FROZEN = SEALED | READ_ONLY, + ABSENT = 16 // Used in runtime to indicate a property is absent. // ABSENT can never be stored in or returned from a descriptor's attributes // bitfield. It is only used as a return value meaning the attributes of @@ -96,7 +100,9 @@ class PropertyDetails BASE_EMBEDDED { PropertyType type() { return TypeField::decode(value_); } - PropertyAttributes attributes() { return AttributesField::decode(value_); } + PropertyAttributes attributes() const { + return AttributesField::decode(value_); + } int dictionary_index() { return DictionaryStorageField::decode(value_); @@ -112,10 +118,10 @@ class PropertyDetails BASE_EMBEDDED { return DictionaryStorageField::is_valid(index); } - bool IsReadOnly() { return (attributes() & READ_ONLY) != 0; } - bool IsDontDelete() { return (attributes() & DONT_DELETE) != 0; } - bool IsDontEnum() { return (attributes() & DONT_ENUM) != 0; } - bool IsDeleted() { return DeletedField::decode(value_) != 0;} + bool IsReadOnly() const { return (attributes() & READ_ONLY) != 0; } + bool IsDontDelete() const { return (attributes() & DONT_DELETE) != 0; } + bool IsDontEnum() const { return (attributes() & DONT_ENUM) != 0; } + bool IsDeleted() const { return DeletedField::decode(value_) != 0;} // Bit fields in value_ (type, shift, size). Must be public so the // constants can be embedded in generated code. diff --git a/deps/v8/src/property.cc b/deps/v8/src/property.cc index 05342eea95..cbf2fc859d 100644 --- a/deps/v8/src/property.cc +++ b/deps/v8/src/property.cc @@ -63,7 +63,7 @@ void LookupResult::Print(FILE* out) { break; case FIELD: PrintF(out, " -type = field\n"); - PrintF(out, " -index = %d", GetFieldIndex()); + PrintF(out, " -index = %d", GetFieldIndex().field_index()); PrintF(out, "\n"); break; case CALLBACKS: diff --git a/deps/v8/src/property.h b/deps/v8/src/property.h index 6bf52a7019..c41c6dc816 100644 --- a/deps/v8/src/property.h +++ b/deps/v8/src/property.h @@ -68,7 +68,7 @@ class Descriptor BASE_EMBEDDED { details_ = PropertyDetails(details_.attributes(), details_.type(), index); } - void SetSortedKey(int index) { details_ = details_.set_pointer(index); } + void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); } private: String* key_; @@ -132,6 +132,44 @@ class CallbacksDescriptor: public Descriptor { }; +// Holds a property index value distinguishing if it is a field index or an +// index inside the object header. +class PropertyIndex { + public: + static PropertyIndex NewFieldIndex(int index) { + return PropertyIndex(index, false); + } + static PropertyIndex NewHeaderIndex(int index) { + return PropertyIndex(index, true); + } + + bool is_field_index() { return (index_ & kHeaderIndexBit) == 0; } + bool is_header_index() { return (index_ & kHeaderIndexBit) != 0; } + + int field_index() { + ASSERT(is_field_index()); + return value(); + } + int header_index() { + ASSERT(is_header_index()); + return value(); + } + + private: + static const int kHeaderIndexBit = 1 << 31; + static const int kIndexMask = ~kHeaderIndexBit; + + int value() { return index_ & kIndexMask; } + + PropertyIndex(int index, bool is_header_based) + : index_(index | (is_header_based ? kHeaderIndexBit : 0)) { + ASSERT(index <= kIndexMask); + } + + int index_; +}; + + class LookupResult BASE_EMBEDDED { public: explicit LookupResult(Isolate* isolate) @@ -278,7 +316,7 @@ class LookupResult BASE_EMBEDDED { Object* GetLazyValue() { switch (type()) { case FIELD: - return holder()->FastPropertyAt(GetFieldIndex()); + return holder()->FastPropertyAt(GetFieldIndex().field_index()); case NORMAL: { Object* value; value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); @@ -290,7 +328,7 @@ class LookupResult BASE_EMBEDDED { case CONSTANT_FUNCTION: return GetConstantFunction(); default: - return Smi::FromInt(0); + return Isolate::Current()->heap()->the_hole_value(); } } @@ -334,10 +372,11 @@ class LookupResult BASE_EMBEDDED { return number_; } - int GetFieldIndex() { + PropertyIndex GetFieldIndex() { ASSERT(lookup_type_ == DESCRIPTOR_TYPE); ASSERT(IsField()); - return Descriptor::IndexFromValue(GetValue()); + return PropertyIndex::NewFieldIndex( + Descriptor::IndexFromValue(GetValue())); } int GetLocalFieldIndexFromMap(Map* map) { @@ -384,6 +423,7 @@ class LookupResult BASE_EMBEDDED { Object* GetValueFromMap(Map* map) const { ASSERT(lookup_type_ == DESCRIPTOR_TYPE); + ASSERT(number_ < map->NumberOfOwnDescriptors()); return map->instance_descriptors()->GetValue(number_); } diff --git a/deps/v8/src/proxy.js b/deps/v8/src/proxy.js index 4e86c8892a..53a3572474 100644 --- a/deps/v8/src/proxy.js +++ b/deps/v8/src/proxy.js @@ -31,7 +31,7 @@ global.Proxy = new $Object(); var $Proxy = global.Proxy -$Proxy.create = function(handler, proto) { +function ProxyCreate(handler, proto) { if (!IS_SPEC_OBJECT(handler)) throw MakeTypeError("handler_non_object", ["create"]) if (IS_UNDEFINED(proto)) @@ -41,7 +41,7 @@ $Proxy.create = function(handler, proto) { return %CreateJSProxy(handler, proto) } -$Proxy.createFunction = function(handler, callTrap, constructTrap) { +function ProxyCreateFunction(handler, callTrap, constructTrap) { if (!IS_SPEC_OBJECT(handler)) throw MakeTypeError("handler_non_object", ["create"]) if (!IS_SPEC_FUNCTION(callTrap)) @@ -62,6 +62,11 @@ $Proxy.createFunction = function(handler, callTrap, constructTrap) { handler, callTrap, constructTrap, $Function.prototype) } +%CheckIsBootstrapping() +InstallFunctions($Proxy, DONT_ENUM, [ + "create", ProxyCreate, + "createFunction", ProxyCreateFunction +]) //////////////////////////////////////////////////////////////////////////////// diff --git a/deps/v8/src/regexp-macro-assembler.cc b/deps/v8/src/regexp-macro-assembler.cc index a4719b53fc..ee9347acbb 100644 --- a/deps/v8/src/regexp-macro-assembler.cc +++ b/deps/v8/src/regexp-macro-assembler.cc @@ -67,11 +67,7 @@ NativeRegExpMacroAssembler::~NativeRegExpMacroAssembler() { bool NativeRegExpMacroAssembler::CanReadUnaligned() { -#ifdef V8_TARGET_CAN_READ_UNALIGNED - return !slow_safe(); -#else - return false; -#endif + return FLAG_enable_unaligned_accesses && !slow_safe(); } const byte* NativeRegExpMacroAssembler::StringCharacterPosition( @@ -81,14 +77,14 @@ const byte* NativeRegExpMacroAssembler::StringCharacterPosition( ASSERT(subject->IsExternalString() || subject->IsSeqString()); ASSERT(start_index >= 0); ASSERT(start_index <= subject->length()); - if (subject->IsAsciiRepresentation()) { + if (subject->IsOneByteRepresentation()) { const byte* address; if (StringShape(subject).IsExternal()) { const char* data = ExternalAsciiString::cast(subject)->GetChars(); address = reinterpret_cast<const byte*>(data); } else { - ASSERT(subject->IsSeqAsciiString()); - char* data = SeqAsciiString::cast(subject)->GetChars(); + ASSERT(subject->IsSeqOneByteString()); + char* data = SeqOneByteString::cast(subject)->GetChars(); address = reinterpret_cast<const byte*>(data); } return address + start_index; @@ -137,7 +133,7 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match( slice_offset = slice->offset(); } // Ensure that an underlying string has the same ASCII-ness. - bool is_ascii = subject_ptr->IsAsciiRepresentation(); + bool is_ascii = subject_ptr->IsOneByteRepresentation(); ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString()); // String is now either Sequential or External int char_size_shift = is_ascii ? 0 : 1; diff --git a/deps/v8/src/regexp-stack.cc b/deps/v8/src/regexp-stack.cc index ff9547f3a7..325a1496c9 100644 --- a/deps/v8/src/regexp-stack.cc +++ b/deps/v8/src/regexp-stack.cc @@ -51,6 +51,7 @@ RegExpStack::RegExpStack() RegExpStack::~RegExpStack() { + thread_local_.Free(); } diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js index 38090397aa..da1883f3a4 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -140,18 +140,15 @@ function BuildResultFromMatchInfo(lastMatchInfo, s) { var j = REGEXP_FIRST_CAPTURE + 2; for (var i = 1; i < numResults; i++) { start = lastMatchInfo[j++]; - end = lastMatchInfo[j++]; - if (end != -1) { + if (start != -1) { + end = lastMatchInfo[j]; if (start + 1 == end) { result[i] = %_StringCharAt(s, start); } else { result[i] = %_SubString(s, start, end); } - } else { - // Make sure the element is present. Avoid reading the undefined - // property from the global object since this may change. - result[i] = void 0; } + j++; } return result; } @@ -164,6 +161,7 @@ function RegExpExecNoTests(regexp, string, start) { lastMatchInfoOverride = null; return BuildResultFromMatchInfo(matchInfo, string); } + regexp.lastIndex = 0; return null; } @@ -196,7 +194,7 @@ function RegExpExec(string) { var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo); if (matchIndices === null) { - if (global) this.lastIndex = 0; + this.lastIndex = 0; return null; } @@ -259,7 +257,10 @@ function RegExpTest(string) { %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [regexp, string, lastIndex]); // matchIndices is either null or the lastMatchInfo array. var matchIndices = %_RegExpExec(regexp, string, 0, lastMatchInfo); - if (matchIndices === null) return false; + if (matchIndices === null) { + this.lastIndex = 0; + return false; + } lastMatchInfoOverride = null; return true; } diff --git a/deps/v8/src/rewriter.cc b/deps/v8/src/rewriter.cc index 6541546cb6..2a98787177 100644 --- a/deps/v8/src/rewriter.cc +++ b/deps/v8/src/rewriter.cc @@ -109,6 +109,13 @@ void Processor::VisitBlock(Block* node) { } +void Processor::VisitModuleStatement(ModuleStatement* node) { + bool set_after_body = is_set_; + Visit(node->body()); + is_set_ = is_set_ && set_after_body; +} + + void Processor::VisitExpressionStatement(ExpressionStatement* node) { // Rewrite : <x>; -> .result = <x>; if (!is_set_ && !node->expression()->IsThrow()) { @@ -257,7 +264,7 @@ bool Rewriter::Rewrite(CompilationInfo* info) { // coincides with the end of the with scope which is the position of '1'. int position = function->end_position(); VariableProxy* result_proxy = processor.factory()->NewVariableProxy( - result->name(), false, Interface::NewValue(), position); + result->name(), false, result->interface(), position); result_proxy->BindTo(result); Statement* result_statement = processor.factory()->NewReturnStatement(result_proxy); diff --git a/deps/v8/src/runtime-profiler.cc b/deps/v8/src/runtime-profiler.cc index 23f41fa7d2..262cd1d582 100644 --- a/deps/v8/src/runtime-profiler.cc +++ b/deps/v8/src/runtime-profiler.cc @@ -140,6 +140,9 @@ static void GetICCounts(JSFunction* function, void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) { ASSERT(function->IsOptimizable()); + // If we are in manual mode, don't auto-optimize anything. + if (FLAG_manual_parallel_recompilation) return; + if (FLAG_trace_opt) { PrintF("[marking "); function->PrintName(); @@ -193,16 +196,9 @@ void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) { // Get the stack check stub code object to match against. We aren't // prepared to generate it, but we don't expect to have to. - bool found_code = false; Code* stack_check_code = NULL; - if (FLAG_count_based_interrupts) { - InterruptStub interrupt_stub; - found_code = interrupt_stub.FindCodeInCache(&stack_check_code); - } else // NOLINT - { // NOLINT - StackCheckStub check_stub; - found_code = check_stub.FindCodeInCache(&stack_check_code); - } + InterruptStub interrupt_stub; + bool found_code = interrupt_stub.FindCodeInCache(&stack_check_code, isolate_); if (found_code) { Code* replacement_code = isolate_->builtins()->builtin(Builtins::kOnStackReplacement); @@ -376,12 +372,6 @@ void RuntimeProfiler::OptimizeNow() { } -void RuntimeProfiler::NotifyTick() { - if (FLAG_count_based_interrupts) return; - isolate_->stack_guard()->RequestRuntimeProfilerTick(); -} - - void RuntimeProfiler::SetUp() { ASSERT(has_been_globally_set_up_); if (!FLAG_watch_ic_patching) { diff --git a/deps/v8/src/runtime-profiler.h b/deps/v8/src/runtime-profiler.h index ab6cb378ea..507535f0b4 100644 --- a/deps/v8/src/runtime-profiler.h +++ b/deps/v8/src/runtime-profiler.h @@ -52,8 +52,6 @@ class RuntimeProfiler { void OptimizeNow(); - void NotifyTick(); - void SetUp(); void Reset(); void TearDown(); diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 3c9a10dbff..446443148d 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -46,6 +46,7 @@ #include "isolate-inl.h" #include "jsregexp.h" #include "json-parser.h" +#include "json-stringifier.h" #include "liveedit.h" #include "liveobjectlist-inl.h" #include "misc-intrinsics.h" @@ -782,6 +783,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); + Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); + return Smi::FromInt(table->NumberOfElements()); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -841,6 +851,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); + Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); + return Smi::FromInt(table->NumberOfElements()); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -948,104 +967,107 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) { } -// Recursively traverses hidden prototypes if property is not found -static void GetOwnPropertyImplementation(JSObject* obj, - String* name, - LookupResult* result) { - obj->LocalLookupRealNamedProperty(name, result); +static bool CheckAccessException(Object* callback, + v8::AccessType access_type) { + if (callback->IsAccessorInfo()) { + AccessorInfo* info = AccessorInfo::cast(callback); + return + (access_type == v8::ACCESS_HAS && + (info->all_can_read() || info->all_can_write())) || + (access_type == v8::ACCESS_GET && info->all_can_read()) || + (access_type == v8::ACCESS_SET && info->all_can_write()); + } + return false; +} - if (result->IsFound()) return; - Object* proto = obj->GetPrototype(); - if (proto->IsJSObject() && - JSObject::cast(proto)->map()->is_hidden_prototype()) - GetOwnPropertyImplementation(JSObject::cast(proto), - name, result); +template<class Key> +static bool CheckGenericAccess( + JSObject* receiver, + JSObject* holder, + Key key, + v8::AccessType access_type, + bool (Isolate::*mayAccess)(JSObject*, Key, v8::AccessType)) { + Isolate* isolate = receiver->GetIsolate(); + for (JSObject* current = receiver; + true; + current = JSObject::cast(current->GetPrototype())) { + if (current->IsAccessCheckNeeded() && + !(isolate->*mayAccess)(current, key, access_type)) { + return false; + } + if (current == holder) break; + } + return true; } -static bool CheckAccessException(LookupResult* result, - v8::AccessType access_type) { - if (result->type() == CALLBACKS) { - Object* callback = result->GetCallbackObject(); - if (callback->IsAccessorInfo()) { - AccessorInfo* info = AccessorInfo::cast(callback); - bool can_access = - (access_type == v8::ACCESS_HAS && - (info->all_can_read() || info->all_can_write())) || - (access_type == v8::ACCESS_GET && info->all_can_read()) || - (access_type == v8::ACCESS_SET && info->all_can_write()); - return can_access; - } +enum AccessCheckResult { + ACCESS_FORBIDDEN, + ACCESS_ALLOWED, + ACCESS_ABSENT +}; + + +static AccessCheckResult CheckElementAccess( + JSObject* obj, + uint32_t index, + v8::AccessType access_type) { + // TODO(1095): we should traverse hidden prototype hierachy as well. + if (CheckGenericAccess( + obj, obj, index, access_type, &Isolate::MayIndexedAccess)) { + return ACCESS_ALLOWED; } - return false; + obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type); + return ACCESS_FORBIDDEN; } -static bool CheckAccess(JSObject* obj, - String* name, - LookupResult* result, - v8::AccessType access_type) { - ASSERT(result->IsProperty()); - - JSObject* holder = result->holder(); - JSObject* current = obj; - Isolate* isolate = obj->GetIsolate(); - while (true) { - if (current->IsAccessCheckNeeded() && - !isolate->MayNamedAccess(current, name, access_type)) { - // Access check callback denied the access, but some properties - // can have a special permissions which override callbacks descision - // (currently see v8::AccessControl). - break; - } +static AccessCheckResult CheckPropertyAccess( + JSObject* obj, + String* name, + v8::AccessType access_type) { + uint32_t index; + if (name->AsArrayIndex(&index)) { + return CheckElementAccess(obj, index, access_type); + } - if (current == holder) { - return true; - } + LookupResult lookup(obj->GetIsolate()); + obj->LocalLookup(name, &lookup, true); - current = JSObject::cast(current->GetPrototype()); + if (!lookup.IsProperty()) return ACCESS_ABSENT; + if (CheckGenericAccess<Object*>( + obj, lookup.holder(), name, access_type, &Isolate::MayNamedAccess)) { + return ACCESS_ALLOWED; } + // Access check callback denied the access, but some properties + // can have a special permissions which override callbacks descision + // (currently see v8::AccessControl). // API callbacks can have per callback access exceptions. - switch (result->type()) { - case CALLBACKS: { - if (CheckAccessException(result, access_type)) { - return true; + switch (lookup.type()) { + case CALLBACKS: + if (CheckAccessException(lookup.GetCallbackObject(), access_type)) { + return ACCESS_ALLOWED; } break; - } - case INTERCEPTOR: { + case INTERCEPTOR: // If the object has an interceptor, try real named properties. // Overwrite the result to fetch the correct property later. - holder->LookupRealNamedProperty(name, result); - if (result->IsProperty()) { - if (CheckAccessException(result, access_type)) { - return true; + lookup.holder()->LookupRealNamedProperty(name, &lookup); + if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) { + if (CheckAccessException(lookup.GetCallbackObject(), access_type)) { + return ACCESS_ALLOWED; } } break; - } default: break; } - isolate->ReportFailedAccessCheck(current, access_type); - return false; -} - - -// TODO(1095): we should traverse hidden prototype hierachy as well. -static bool CheckElementAccess(JSObject* obj, - uint32_t index, - v8::AccessType access_type) { - if (obj->IsAccessCheckNeeded() && - !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) { - return false; - } - - return true; + obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type); + return ACCESS_FORBIDDEN; } @@ -1066,141 +1088,43 @@ static MaybeObject* GetOwnProperty(Isolate* isolate, Handle<JSObject> obj, Handle<String> name) { Heap* heap = isolate->heap(); - Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); - Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms); - LookupResult result(isolate); - // This could be an element. - uint32_t index; - if (name->AsArrayIndex(&index)) { - switch (obj->HasLocalElement(index)) { - case JSObject::UNDEFINED_ELEMENT: - return heap->undefined_value(); - - case JSObject::STRING_CHARACTER_ELEMENT: { - // Special handling of string objects according to ECMAScript 5 - // 15.5.5.2. Note that this might be a string object with elements - // other than the actual string value. This is covered by the - // subsequent cases. - Handle<JSValue> js_value = Handle<JSValue>::cast(obj); - Handle<String> str(String::cast(js_value->value())); - Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED); - - elms->set(IS_ACCESSOR_INDEX, heap->false_value()); - elms->set(VALUE_INDEX, *substr); - elms->set(WRITABLE_INDEX, heap->false_value()); - elms->set(ENUMERABLE_INDEX, heap->true_value()); - elms->set(CONFIGURABLE_INDEX, heap->false_value()); - return *desc; - } - - case JSObject::INTERCEPTED_ELEMENT: - case JSObject::FAST_ELEMENT: { - elms->set(IS_ACCESSOR_INDEX, heap->false_value()); - Handle<Object> value = Object::GetElement(obj, index); - RETURN_IF_EMPTY_HANDLE(isolate, value); - elms->set(VALUE_INDEX, *value); - elms->set(WRITABLE_INDEX, heap->true_value()); - elms->set(ENUMERABLE_INDEX, heap->true_value()); - elms->set(CONFIGURABLE_INDEX, heap->true_value()); - return *desc; - } - - case JSObject::DICTIONARY_ELEMENT: { - Handle<JSObject> holder = obj; - if (obj->IsJSGlobalProxy()) { - Object* proto = obj->GetPrototype(); - if (proto->IsNull()) return heap->undefined_value(); - ASSERT(proto->IsJSGlobalObject()); - holder = Handle<JSObject>(JSObject::cast(proto)); - } - FixedArray* elements = FixedArray::cast(holder->elements()); - SeededNumberDictionary* dictionary = NULL; - if (elements->map() == heap->non_strict_arguments_elements_map()) { - dictionary = SeededNumberDictionary::cast(elements->get(1)); - } else { - dictionary = SeededNumberDictionary::cast(elements); - } - int entry = dictionary->FindEntry(index); - ASSERT(entry != SeededNumberDictionary::kNotFound); - PropertyDetails details = dictionary->DetailsAt(entry); - switch (details.type()) { - case CALLBACKS: { - // This is an accessor property with getter and/or setter. - AccessorPair* accessors = - AccessorPair::cast(dictionary->ValueAt(entry)); - elms->set(IS_ACCESSOR_INDEX, heap->true_value()); - if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) { - elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER)); - } - if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) { - elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER)); - } - break; - } - case NORMAL: { - // This is a data property. - elms->set(IS_ACCESSOR_INDEX, heap->false_value()); - Handle<Object> value = Object::GetElement(obj, index); - ASSERT(!value.is_null()); - elms->set(VALUE_INDEX, *value); - elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly())); - break; - } - default: - UNREACHABLE(); - break; - } - elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum())); - elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete())); - return *desc; - } - } - } - - // Use recursive implementation to also traverse hidden prototypes - GetOwnPropertyImplementation(*obj, *name, &result); - - if (!result.IsProperty()) { - return heap->undefined_value(); - } - - if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) { - return heap->false_value(); + // Due to some WebKit tests, we want to make sure that we do not log + // more than one access failure here. + switch (CheckPropertyAccess(*obj, *name, v8::ACCESS_HAS)) { + case ACCESS_FORBIDDEN: return heap->false_value(); + case ACCESS_ALLOWED: break; + case ACCESS_ABSENT: return heap->undefined_value(); } - elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum())); - elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete())); - - bool is_js_accessor = result.IsPropertyCallbacks() && - (result.GetCallbackObject()->IsAccessorPair()); + PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name); + if (attrs == ABSENT) return heap->undefined_value(); + AccessorPair* accessors = obj->GetLocalPropertyAccessorPair(*name); - if (is_js_accessor) { - // __defineGetter__/__defineSetter__ callback. - elms->set(IS_ACCESSOR_INDEX, heap->true_value()); - - AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject()); + Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); + elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); + elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); + elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(accessors != NULL)); + + if (accessors == NULL) { + elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); + // GetProperty does access check. + Handle<Object> value = GetProperty(obj, name); + if (value.is_null()) return Failure::Exception(); + elms->set(VALUE_INDEX, *value); + } else { + // Access checks are performed for both accessors separately. + // When they fail, the respective field is not set in the descriptor. Object* getter = accessors->GetComponent(ACCESSOR_GETTER); - if (!getter->IsMap() && CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) { + Object* setter = accessors->GetComponent(ACCESSOR_SETTER); + if (!getter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_GET)) { elms->set(GETTER_INDEX, getter); } - Object* setter = accessors->GetComponent(ACCESSOR_SETTER); - if (!setter->IsMap() && CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) { + if (!setter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_SET)) { elms->set(SETTER_INDEX, setter); } - } else { - elms->set(IS_ACCESSOR_INDEX, heap->false_value()); - elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly())); - - PropertyAttributes attrs; - Object* value; - // GetProperty will check access and report any violations. - { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs); - if (!maybe_value->ToObject(&value)) return maybe_value; - } - elms->set(VALUE_INDEX, value); } - return *desc; + return *isolate->factory()->NewJSArrayWithElements(elms); } @@ -1358,8 +1282,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { 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); + ASSERT(is_var + is_const + is_function == 1); if (is_var || is_const) { // Lookup the property in the global object, and don't set the @@ -1367,13 +1290,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { // Do the lookup locally only, see ES5 erratum. LookupResult lookup(isolate); if (FLAG_es52_globals) { - Object* obj = *global; - do { - JSObject::cast(obj)->LocalLookup(*name, &lookup); - if (lookup.IsFound()) break; - obj = obj->GetPrototype(); - } while (obj->IsJSObject() && - JSObject::cast(obj)->map()->is_hidden_prototype()); + global->LocalLookup(*name, &lookup, true); } else { global->Lookup(*name, &lookup); } @@ -1397,30 +1314,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { } LookupResult lookup(isolate); - global->LocalLookup(*name, &lookup); + global->LocalLookup(*name, &lookup, true); // Compute the property attributes. According to ECMA-262, // the property must be non-configurable except in eval. int attr = NONE; bool is_eval = DeclareGlobalsEvalFlag::decode(flags); - if (!is_eval || is_module) { + if (!is_eval) { attr |= DONT_DELETE; } bool is_native = DeclareGlobalsNativeFlag::decode(flags); - if (is_const || is_module || (is_native && is_function)) { + if (is_const || (is_native && is_function)) { attr |= READ_ONLY; } LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags); - if (!lookup.IsFound() || is_function || is_module) { + if (!lookup.IsFound() || is_function) { // If the local property exists, check that we can reconfigure it // as required for function declarations. if (lookup.IsFound() && lookup.IsDontDelete()) { if (lookup.IsReadOnly() || lookup.IsDontEnum() || lookup.IsPropertyCallbacks()) { - return ThrowRedeclarationError( - isolate, is_function ? "function" : "module", name); + return ThrowRedeclarationError(isolate, "function", name); } // If the existing property is not configurable, keep its attributes. attr = lookup.GetAttributes(); @@ -1576,27 +1492,20 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { // the whole chain of hidden prototypes to do a 'local' lookup. Object* object = global; LookupResult lookup(isolate); - while (object->IsJSObject() && - JSObject::cast(object)->map()->is_hidden_prototype()) { - JSObject* raw_holder = JSObject::cast(object); - raw_holder->LocalLookup(*name, &lookup); - if (lookup.IsInterceptor()) { - HandleScope handle_scope(isolate); - Handle<JSObject> holder(raw_holder); - PropertyAttributes intercepted = holder->GetPropertyAttribute(*name); - // Update the raw pointer in case it's changed due to GC. - raw_holder = *holder; - if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { - // Found an interceptor that's not read only. - if (assign) { - return raw_holder->SetProperty( - &lookup, *name, args[2], attributes, strict_mode_flag); - } else { - return isolate->heap()->undefined_value(); - } + JSObject::cast(object)->LocalLookup(*name, &lookup, true); + if (lookup.IsInterceptor()) { + HandleScope handle_scope(isolate); + PropertyAttributes intercepted = + lookup.holder()->GetPropertyAttribute(*name); + if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { + // Found an interceptor that's not read only. + if (assign) { + return lookup.holder()->SetProperty( + &lookup, *name, args[2], attributes, strict_mode_flag); + } else { + return isolate->heap()->undefined_value(); } } - object = raw_holder->GetPrototype(); } // Reload global in case the loop above performed a GC. @@ -1660,7 +1569,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { // Strict mode handling not needed (const is disallowed in strict mode). if (lookup.IsField()) { FixedArray* properties = global->properties(); - int index = lookup.GetFieldIndex(); + int index = lookup.GetFieldIndex().field_index(); if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) { properties->set(index, *value); } @@ -1750,7 +1659,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { if (lookup.IsField()) { FixedArray* properties = object->properties(); - int index = lookup.GetFieldIndex(); + int index = lookup.GetFieldIndex().field_index(); if (properties->get(index)->IsTheHole()) { properties->set(index, *value); } @@ -1881,9 +1790,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) { JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER); regexp->InObjectPropertyAtPut( JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER); - regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, - Smi::FromInt(0), - SKIP_WRITE_BARRIER); // It's a Smi. + regexp->ResetLastIndex(); return regexp; } @@ -2166,7 +2073,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) { // Construct a new field descriptor with updated attributes. DescriptorArray* instance_desc = function->map()->instance_descriptors(); - int index = instance_desc->SearchWithCache(name); + int index = instance_desc->SearchWithCache(name, function->map()); ASSERT(index != DescriptorArray::kNotFound); PropertyDetails details = instance_desc->GetDetails(index); @@ -2179,7 +2086,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) { Map* new_map; MaybeObject* maybe_map = function->map()->CopyReplaceDescriptor( - &new_desc, index, OMIT_TRANSITION); + instance_desc, &new_desc, index, OMIT_TRANSITION); if (!maybe_map->To(&new_map)) return maybe_map; function->set_map(new_map); @@ -2254,6 +2161,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { // Set the code of the target function. target->ReplaceCode(source_shared->code()); + ASSERT(target->next_function_link()->IsUndefined()); // Make sure we get a fresh copy of the literal vector to avoid cross // context contamination. @@ -2267,7 +2175,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { } target->set_context(*context); target->set_literals(*literals); - target->set_next_function_link(isolate->heap()->undefined_value()); if (isolate->logger()->is_logging_code_events() || CpuProfiler::is_profiling(isolate)) { @@ -2442,7 +2349,7 @@ class ReplacementStringBuilder { array_builder_(heap->isolate(), estimated_part_count), subject_(subject), character_count_(0), - is_ascii_(subject->IsAsciiRepresentation()) { + is_ascii_(subject->IsOneByteRepresentation()) { // Require a non-zero initial size. Ensures that doubling the size to // extend the array will work. ASSERT(estimated_part_count > 0); @@ -2482,7 +2389,7 @@ class ReplacementStringBuilder { int length = string->length(); ASSERT(length > 0); AddElement(*string); - if (!string->IsAsciiRepresentation()) { + if (!string->IsOneByteRepresentation()) { is_ascii_ = false; } IncrementCharacterCount(length); @@ -2496,7 +2403,7 @@ class ReplacementStringBuilder { Handle<String> joined_string; if (is_ascii_) { - Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_); + Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_); AssertNoAllocation no_alloc; char* char_buffer = seq->GetChars(); StringBuilderConcatHelper(*subject_, @@ -2527,8 +2434,8 @@ class ReplacementStringBuilder { } private: - Handle<SeqAsciiString> NewRawAsciiString(int length) { - return heap_->isolate()->factory()->NewRawAsciiString(length); + Handle<SeqOneByteString> NewRawOneByteString(int length) { + return heap_->isolate()->factory()->NewRawOneByteString(length); } @@ -2853,6 +2760,23 @@ void FindAsciiStringIndices(Vector<const char> subject, } +void FindTwoByteStringIndices(const Vector<const uc16> subject, + uc16 pattern, + ZoneList<int>* indices, + unsigned int limit, + Zone* zone) { + ASSERT(limit > 0); + const uc16* subject_start = subject.start(); + const uc16* subject_end = subject_start + subject.length(); + for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) { + if (*pos == pattern) { + indices->Add(static_cast<int>(pos - subject_start), zone); + limit--; + } + } +} + + template <typename SubjectChar, typename PatternChar> void FindStringIndices(Isolate* isolate, Vector<const SubjectChar> subject, @@ -2917,19 +2841,37 @@ void FindStringIndicesDispatch(Isolate* isolate, } else { Vector<const uc16> subject_vector = subject_content.ToUC16Vector(); if (pattern_content.IsAscii()) { - FindStringIndices(isolate, - subject_vector, - pattern_content.ToAsciiVector(), - indices, - limit, - zone); + Vector<const char> pattern_vector = pattern_content.ToAsciiVector(); + if (pattern_vector.length() == 1) { + FindTwoByteStringIndices(subject_vector, + pattern_vector[0], + indices, + limit, + zone); + } else { + FindStringIndices(isolate, + subject_vector, + pattern_vector, + indices, + limit, + zone); + } } else { - FindStringIndices(isolate, - subject_vector, - pattern_content.ToUC16Vector(), - indices, - limit, - zone); + Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector(); + if (pattern_vector.length() == 1) { + FindTwoByteStringIndices(subject_vector, + pattern_vector[0], + indices, + limit, + zone); + } else { + FindStringIndices(isolate, + subject_vector, + pattern_vector, + indices, + limit, + zone); + } } } } @@ -2960,7 +2902,10 @@ MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString( isolate, *subject, pattern, &indices, 0xffffffff, zone); int matches = indices.length(); - if (matches == 0) return *subject; + if (matches == 0) { + pattern_regexp->ResetLastIndex(); + return *subject; + } // Detect integer overflow. int64_t result_len_64 = @@ -2977,7 +2922,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString( Handle<ResultSeqString> result; if (ResultSeqString::kHasAsciiEncoding) { result = Handle<ResultSeqString>::cast( - isolate->factory()->NewRawAsciiString(result_len)); + isolate->factory()->NewRawOneByteString(result_len)); } else { result = Handle<ResultSeqString>::cast( isolate->factory()->NewRawTwoByteString(result_len)); @@ -3046,7 +2991,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString( regexp->TypeTag() == JSRegExp::ATOM && simple_replace) { if (subject->HasOnlyAsciiChars() && replacement->HasOnlyAsciiChars()) { - return StringReplaceAtomRegExpWithString<SeqAsciiString>( + return StringReplaceAtomRegExpWithString<SeqOneByteString>( isolate, subject, regexp, replacement, last_match_info); } else { return StringReplaceAtomRegExpWithString<SeqTwoByteString>( @@ -3060,6 +3005,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString( int32_t* current_match = global_cache.FetchNext(); if (current_match == NULL) { if (global_cache.HasException()) return Failure::Exception(); + regexp->ResetLastIndex(); return *subject; } @@ -3134,9 +3080,9 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( // Shortcut for simple non-regexp global replacements if (is_global && regexp->TypeTag() == JSRegExp::ATOM) { - Handle<String> empty_string(HEAP->empty_string()); + Handle<String> empty_string = isolate->factory()->empty_string(); if (subject->HasOnlyAsciiChars()) { - return StringReplaceAtomRegExpWithString<SeqAsciiString>( + return StringReplaceAtomRegExpWithString<SeqOneByteString>( isolate, subject, regexp, @@ -3158,6 +3104,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( int32_t* current_match = global_cache.FetchNext(); if (current_match == NULL) { if (global_cache.HasException()) return Failure::Exception(); + regexp->ResetLastIndex(); return *subject; } @@ -3172,7 +3119,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( Handle<ResultSeqString> answer; if (ResultSeqString::kHasAsciiEncoding) { answer = Handle<ResultSeqString>::cast( - isolate->factory()->NewRawAsciiString(new_length)); + isolate->factory()->NewRawOneByteString(new_length)); } else { answer = Handle<ResultSeqString>::cast( isolate->factory()->NewRawTwoByteString(new_length)); @@ -3264,7 +3211,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) { if (replacement->length() == 0) { if (subject->HasOnlyAsciiChars()) { - return StringReplaceRegExpWithEmptyString<SeqAsciiString>( + return StringReplaceRegExpWithEmptyString<SeqOneByteString>( isolate, subject, regexp, last_match_info); } else { return StringReplaceRegExpWithEmptyString<SeqTwoByteString>( @@ -3849,7 +3796,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { } char* str = DoubleToRadixCString(value, radix); MaybeObject* result = - isolate->heap()->AllocateStringFromAscii(CStrVector(str)); + isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); DeleteArray(str); return result; } @@ -3860,21 +3807,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) { ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(value, 0); - if (isnan(value)) { - return *isolate->factory()->nan_symbol(); - } - if (isinf(value)) { - if (value < 0) { - return *isolate->factory()->minus_infinity_symbol(); - } - return *isolate->factory()->infinity_symbol(); - } CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); int f = FastD2IChecked(f_number); RUNTIME_ASSERT(f >= 0); char* str = DoubleToFixedCString(value, f); MaybeObject* res = - isolate->heap()->AllocateStringFromAscii(CStrVector(str)); + isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); DeleteArray(str); return res; } @@ -3885,21 +3823,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) { ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(value, 0); - if (isnan(value)) { - return *isolate->factory()->nan_symbol(); - } - if (isinf(value)) { - if (value < 0) { - return *isolate->factory()->minus_infinity_symbol(); - } - return *isolate->factory()->infinity_symbol(); - } CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); int f = FastD2IChecked(f_number); RUNTIME_ASSERT(f >= -1 && f <= 20); char* str = DoubleToExponentialCString(value, f); MaybeObject* res = - isolate->heap()->AllocateStringFromAscii(CStrVector(str)); + isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); DeleteArray(str); return res; } @@ -3910,21 +3839,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) { ASSERT(args.length() == 2); CONVERT_DOUBLE_ARG_CHECKED(value, 0); - if (isnan(value)) { - return *isolate->factory()->nan_symbol(); - } - if (isinf(value)) { - if (value < 0) { - return *isolate->factory()->minus_infinity_symbol(); - } - return *isolate->factory()->infinity_symbol(); - } CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); int f = FastD2IChecked(f_number); RUNTIME_ASSERT(f >= 1 && f <= 21); char* str = DoubleToPrecisionCString(value, f); MaybeObject* res = - isolate->heap()->AllocateStringFromAscii(CStrVector(str)); + isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); DeleteArray(str); return res; } @@ -4057,7 +3977,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { LookupResult result(isolate); receiver->LocalLookup(key, &result); if (result.IsField()) { - int offset = result.GetFieldIndex(); + int offset = result.GetFieldIndex().field_index(); keyed_lookup_cache->Update(receiver_map, key, offset); return receiver->FastPropertyAt(offset); } @@ -4083,8 +4003,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { // become FAST_DOUBLE_ELEMENTS. Handle<JSObject> js_object(args.at<JSObject>(0)); ElementsKind elements_kind = js_object->GetElementsKind(); - if (IsFastElementsKind(elements_kind) && - !IsFastObjectElementsKind(elements_kind)) { + if (IsFastDoubleElementsKind(elements_kind)) { FixedArrayBase* elements = js_object->elements(); if (args.at<Smi>(1)->value() >= elements->length()) { if (IsFastHoleyElementsKind(elements_kind)) { @@ -4097,6 +4016,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { isolate); if (maybe_object->IsFailure()) return maybe_object; } + } else { + ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || + !IsFastElementsKind(elements_kind)); } } } else if (args[0]->IsString() && args[1]->IsSmi()) { @@ -4219,6 +4141,34 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { } +// Return property without being observable by accessors or interceptors. +RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) { + ASSERT(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); + CONVERT_ARG_HANDLE_CHECKED(String, key, 1); + LookupResult lookup(isolate); + object->LookupRealNamedProperty(*key, &lookup); + if (!lookup.IsFound()) return isolate->heap()->undefined_value(); + switch (lookup.type()) { + case NORMAL: + return lookup.holder()->GetNormalizedProperty(&lookup); + case FIELD: + return lookup.holder()->FastPropertyAt( + lookup.GetFieldIndex().field_index()); + case CONSTANT_FUNCTION: + return lookup.GetConstantFunction(); + case CALLBACKS: + case HANDLER: + case INTERCEPTOR: + case TRANSITION: + return isolate->heap()->undefined_value(); + case NONEXISTENT: + UNREACHABLE(); + } + return isolate->heap()->undefined_value(); +} + + MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, Handle<Object> object, Handle<Object> key, @@ -4678,41 +4628,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) { CONVERT_ARG_CHECKED(JSObject, object, 0); CONVERT_ARG_CHECKED(String, key, 1); - uint32_t index; - if (key->AsArrayIndex(&index)) { - JSObject::LocalElementType type = object->HasLocalElement(index); - switch (type) { - case JSObject::UNDEFINED_ELEMENT: - case JSObject::STRING_CHARACTER_ELEMENT: - return isolate->heap()->false_value(); - case JSObject::INTERCEPTED_ELEMENT: - case JSObject::FAST_ELEMENT: - return isolate->heap()->true_value(); - case JSObject::DICTIONARY_ELEMENT: { - if (object->IsJSGlobalProxy()) { - Object* proto = object->GetPrototype(); - if (proto->IsNull()) { - return isolate->heap()->false_value(); - } - ASSERT(proto->IsJSGlobalObject()); - object = JSObject::cast(proto); - } - FixedArray* elements = FixedArray::cast(object->elements()); - SeededNumberDictionary* dictionary = NULL; - if (elements->map() == - isolate->heap()->non_strict_arguments_elements_map()) { - dictionary = SeededNumberDictionary::cast(elements->get(1)); - } else { - dictionary = SeededNumberDictionary::cast(elements); - } - int entry = dictionary->FindEntry(index); - ASSERT(entry != SeededNumberDictionary::kNotFound); - PropertyDetails details = dictionary->DetailsAt(entry); - return isolate->heap()->ToBoolean(!details.IsDontEnum()); - } - } - } - PropertyAttributes att = object->GetLocalPropertyAttribute(key); return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0); } @@ -5032,15 +4947,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) { - ASSERT(args.length() == 1); - Object* obj = args[0]; - return (obj->IsJSObject() && !obj->IsJSGlobalProxy()) - ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0) - : obj; -} - - RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) { NoHandleAllocation ha; ASSERT(args.length() == 1); @@ -5121,10 +5027,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { // Fast case: short integer or some sorts of junk values. int len = subject->length(); - if (subject->IsSeqAsciiString()) { + if (subject->IsSeqOneByteString()) { if (len == 0) return Smi::FromInt(0); - char const* data = SeqAsciiString::cast(subject)->GetChars(); + char const* data = SeqOneByteString::cast(subject)->GetChars(); bool minus = (data[0] == '-'); int start_pos = (minus ? 1 : 0); @@ -5168,46 +5074,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) { - NoHandleAllocation ha; - ASSERT(args.length() == 1); - - CONVERT_ARG_CHECKED(JSArray, codes, 0); - int length = Smi::cast(codes->length())->value(); - - // Check if the string can be ASCII. - int i; - for (i = 0; i < length; i++) { - Object* element; - { MaybeObject* maybe_element = codes->GetElement(i); - // We probably can't get an exception here, but just in order to enforce - // the checking of inputs in the runtime calls we check here. - if (!maybe_element->ToObject(&element)) return maybe_element; - } - CONVERT_NUMBER_CHECKED(int, chr, Int32, element); - if ((chr & 0xffff) > String::kMaxAsciiCharCode) - break; +RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) { + CONVERT_SMI_ARG_CHECKED(length, 0); + CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1); + if (length == 0) return isolate->heap()->empty_string(); + if (is_one_byte) { + return isolate->heap()->AllocateRawOneByteString(length); + } else { + return isolate->heap()->AllocateRawTwoByteString(length); } +} - MaybeObject* maybe_object = NULL; - if (i == length) { // The string is ASCII. - maybe_object = isolate->heap()->AllocateRawAsciiString(length); - } else { // The string is not ASCII. - maybe_object = isolate->heap()->AllocateRawTwoByteString(length); - } - Object* object = NULL; - if (!maybe_object->ToObject(&object)) return maybe_object; - String* result = String::cast(object); - for (int i = 0; i < length; i++) { - Object* element; - { MaybeObject* maybe_element = codes->GetElement(i); - if (!maybe_element->ToObject(&element)) return maybe_element; - } - CONVERT_NUMBER_CHECKED(int, chr, Int32, element); - result->Set(i, chr & 0xffff); - } - return result; +RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) { + CONVERT_ARG_CHECKED(SeqString, string, 0); + CONVERT_SMI_ARG_CHECKED(new_length, 1); + return string->Truncate(new_length); } @@ -5285,7 +5167,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) { } Object* o; { MaybeObject* maybe_o = - isolate->heap()->AllocateRawAsciiString(escaped_length); + isolate->heap()->AllocateRawOneByteString(escaped_length); if (!maybe_o->ToObject(&o)) return maybe_o; } String* destination = String::cast(o); @@ -5393,7 +5275,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) { Object* o; { MaybeObject* maybe_o = ascii ? - isolate->heap()->AllocateRawAsciiString(unescaped_length) : + isolate->heap()->AllocateRawOneByteString(unescaped_length) : isolate->heap()->AllocateRawTwoByteString(unescaped_length); if (!maybe_o->ToObject(&o)) return maybe_o; } @@ -5491,8 +5373,8 @@ MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) { template <> -MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) { - return isolate->heap()->AllocateRawAsciiString(length); +MaybeObject* AllocateRawString<SeqOneByteString>(Isolate* isolate, int length) { + return isolate->heap()->AllocateRawOneByteString(length); } @@ -5643,7 +5525,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate, flat.ToUC16Vector()); } else { - return QuoteJsonString<char, SeqAsciiString, false>(isolate, + return QuoteJsonString<char, SeqOneByteString, false>(isolate, flat.ToAsciiVector()); } } @@ -5666,7 +5548,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) { return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate, flat.ToUC16Vector()); } else { - return QuoteJsonString<char, SeqAsciiString, true>(isolate, + return QuoteJsonString<char, SeqOneByteString, true>(isolate, flat.ToAsciiVector()); } } @@ -5758,7 +5640,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) { } if (ascii) { - return QuoteJsonStringArray<char, SeqAsciiString>(isolate, + return QuoteJsonStringArray<char, SeqOneByteString>(isolate, elements, worst_case_length); } else { @@ -5769,6 +5651,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) { + ASSERT(args.length() == 1); + HandleScope scope(isolate); + BasicJsonStringifier stringifier(isolate); + return stringifier.Stringify(Handle<Object>(args[0])); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { NoHandleAllocation ha; @@ -5815,8 +5705,8 @@ MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( // might break in the future if we implement more context and locale // dependent upper/lower conversions. Object* o; - { MaybeObject* maybe_o = s->IsAsciiRepresentation() - ? isolate->heap()->AllocateRawAsciiString(length) + { MaybeObject* maybe_o = s->IsOneByteRepresentation() + ? isolate->heap()->AllocateRawOneByteString(length) : isolate->heap()->AllocateRawTwoByteString(length); if (!maybe_o->ToObject(&o)) return maybe_o; } @@ -6047,14 +5937,14 @@ MUST_USE_RESULT static MaybeObject* ConvertCase( // character is also ASCII. This is currently the case, but it // might break in the future if we implement more context and locale // dependent upper/lower conversions. - if (s->IsSeqAsciiString()) { + if (s->IsSeqOneByteString()) { Object* o; - { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length); + { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length); if (!maybe_o->ToObject(&o)) return maybe_o; } - SeqAsciiString* result = SeqAsciiString::cast(o); + SeqOneByteString* result = SeqOneByteString::cast(o); bool has_changed_character = ConvertTraits::AsciiConverter::Convert( - result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length); + result->GetChars(), SeqOneByteString::cast(s)->GetChars(), length); return has_changed_character ? result : s; } @@ -6256,7 +6146,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) { Handle<FixedArray> elements; int position = 0; - if (s->IsFlat() && s->IsAsciiRepresentation()) { + if (s->IsFlat() && s->IsOneByteRepresentation()) { // Try using cached chars where possible. Object* obj; { MaybeObject* maybe_obj = @@ -6629,10 +6519,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { if (ascii) { { MaybeObject* maybe_object = - isolate->heap()->AllocateRawAsciiString(length); + isolate->heap()->AllocateRawOneByteString(length); if (!maybe_object->ToObject(&object)) return maybe_object; } - SeqAsciiString* answer = SeqAsciiString::cast(object); + SeqOneByteString* answer = SeqOneByteString::cast(object); StringBuilderConcatHelper(special, answer->GetChars(), fixed_array, @@ -6791,10 +6681,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) { // Find total length of join result. int string_length = 0; - bool is_ascii = separator->IsAsciiRepresentation(); + bool is_ascii = separator->IsOneByteRepresentation(); int max_string_length; if (is_ascii) { - max_string_length = SeqAsciiString::kMaxLength; + max_string_length = SeqOneByteString::kMaxLength; } else { max_string_length = SeqTwoByteString::kMaxLength; } @@ -6808,7 +6698,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) { RUNTIME_ASSERT(elements->get(i + 1)->IsString()); String* string = String::cast(elements->get(i + 1)); int length = string->length(); - if (is_ascii && !string->IsAsciiRepresentation()) { + if (is_ascii && !string->IsOneByteRepresentation()) { is_ascii = false; max_string_length = SeqTwoByteString::kMaxLength; } @@ -6844,10 +6734,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) { if (is_ascii) { MaybeObject* result_allocation = - isolate->heap()->AllocateRawAsciiString(string_length); + isolate->heap()->AllocateRawOneByteString(string_length); if (result_allocation->IsFailure()) return result_allocation; - SeqAsciiString* result_string = - SeqAsciiString::cast(result_allocation->ToObjectUnchecked()); + SeqOneByteString* result_string = + SeqOneByteString::cast(result_allocation->ToObjectUnchecked()); JoinSparseArrayWithSeparator<char>(elements, elements_length, array_length, @@ -7250,7 +7140,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) { isolate->counters()->math_exp()->Increment(); CONVERT_DOUBLE_ARG_CHECKED(x, 0); - return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x); + lazily_initialize_fast_exp(); + return isolate->heap()->NumberFromDouble(fast_exp(x)); } @@ -7909,7 +7800,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) { // If the function is not optimizable or debugger is active continue using the // code from the full compiler. - if (!function->shared()->code()->optimizable() || + if (!FLAG_crankshaft || + !function->shared()->code()->optimizable() || isolate->DebuggerHasBreakPoints()) { if (FLAG_trace_opt) { PrintF("[failed to optimize "); @@ -7941,7 +7833,34 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ParallelRecompile) { HandleScope handle_scope(isolate); ASSERT(FLAG_parallel_recompilation); Compiler::RecompileParallel(args.at<JSFunction>(0)); - return *isolate->factory()->undefined_value(); + return isolate->heap()->undefined_value(); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ForceParallelRecompile) { + if (!V8::UseCrankshaft()) return isolate->heap()->undefined_value(); + HandleScope handle_scope(isolate); + ASSERT(FLAG_parallel_recompilation && FLAG_manual_parallel_recompilation); + if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) { + return isolate->Throw( + *isolate->factory()->LookupAsciiSymbol("Recompile queue is full.")); + } + CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); + fun->ReplaceCode(isolate->builtins()->builtin(Builtins::kParallelRecompile)); + Compiler::RecompileParallel(fun); + return isolate->heap()->undefined_value(); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_InstallRecompiledCode) { + if (!V8::UseCrankshaft()) return isolate->heap()->undefined_value(); + HandleScope handle_scope(isolate); + ASSERT(FLAG_parallel_recompilation && FLAG_manual_parallel_recompilation); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); + OptimizingCompilerThread* opt_thread = isolate->optimizing_compiler_thread(); + Handle<SharedFunctionInfo> shared(fun->shared()); + while (*opt_thread->InstallNextOptimizedFunction() != *shared) { } + return isolate->heap()->undefined_value(); } @@ -7970,35 +7889,6 @@ class ActivationsFinder : public ThreadVisitor { }; -static void MaterializeArgumentsObjectInFrame(Isolate* isolate, - JavaScriptFrame* frame) { - Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate); - Handle<Object> arguments; - for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) { - if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) { - if (arguments.is_null()) { - // FunctionGetArguments can't throw an exception, so cast away the - // doubt with an assert. - arguments = Handle<Object>( - Accessors::FunctionGetArguments(*function, - NULL)->ToObjectUnchecked()); - ASSERT(*arguments != isolate->heap()->null_value()); - 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"); - } - } - } -} - - RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -8007,25 +7897,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { static_cast<Deoptimizer::BailoutType>(args.smi_at(0)); Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); ASSERT(isolate->heap()->IsAllocationAllowed()); - int jsframes = deoptimizer->jsframe_count(); + JavaScriptFrameIterator it(isolate); - deoptimizer->MaterializeHeapNumbers(); + // Make sure to materialize objects before causing any allocation. + deoptimizer->MaterializeHeapObjects(&it); delete deoptimizer; - JavaScriptFrameIterator it(isolate); - for (int i = 0; i < jsframes - 1; i++) { - MaterializeArgumentsObjectInFrame(isolate, it.frame()); - it.Advance(); - } - JavaScriptFrame* frame = it.frame(); RUNTIME_ASSERT(frame->function()->IsJSFunction()); Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate); - MaterializeArgumentsObjectInFrame(isolate, frame); - - if (type == Deoptimizer::EAGER) { - RUNTIME_ASSERT(function->IsOptimized()); - } + RUNTIME_ASSERT(type != Deoptimizer::EAGER || function->IsOptimized()); // Avoid doing too much work when running with --always-opt and keep // the optimized code around. @@ -8254,15 +8135,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { function->PrintName(); PrintF("]\n"); } - Handle<Code> check_code; - if (FLAG_count_based_interrupts) { - InterruptStub interrupt_stub; - check_code = interrupt_stub.GetCode(); - } else // NOLINT - { // NOLINT - StackCheckStub check_stub; - check_code = check_stub.GetCode(); - } + InterruptStub interrupt_stub; + Handle<Code> check_code = interrupt_stub.GetCode(); Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement(); Deoptimizer::RevertStackCheckCode(*unoptimized, *check_code, @@ -8524,20 +8398,89 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) { RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) { - NoHandleAllocation ha; - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(JSModule, instance, 0); + ASSERT(args.length() == 2); + CONVERT_SMI_ARG_CHECKED(index, 0); + + if (!args[1]->IsScopeInfo()) { + // Module already initialized. Find hosting context and retrieve context. + Context* host = Context::cast(isolate->context())->global_context(); + Context* context = Context::cast(host->get(index)); + ASSERT(context->previous() == isolate->context()); + isolate->set_context(context); + return context; + } - Context* context = Context::cast(instance->context()); + CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1); + + // Allocate module context. + HandleScope scope(isolate); + Factory* factory = isolate->factory(); + Handle<Context> context = factory->NewModuleContext(scope_info); + Handle<JSModule> module = factory->NewJSModule(context, scope_info); + context->set_module(*module); Context* previous = isolate->context(); - ASSERT(context->IsModuleContext()); - // Initialize the context links. context->set_previous(previous); context->set_closure(previous->closure()); context->set_global_object(previous->global_object()); - isolate->set_context(context); + isolate->set_context(*context); - return context; + // Find hosting scope and initialize internal variable holding module there. + previous->global_context()->set(index, *context); + + return *context; +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0); + Context* host_context = isolate->context(); + + for (int i = 0; i < descriptions->length(); ++i) { + Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i))); + int host_index = description->host_index(); + Handle<Context> context(Context::cast(host_context->get(host_index))); + Handle<JSModule> module(context->module()); + + for (int j = 0; j < description->length(); ++j) { + Handle<String> name(description->name(j)); + VariableMode mode = description->mode(j); + int index = description->index(j); + switch (mode) { + case VAR: + case LET: + case CONST: + case CONST_HARMONY: { + PropertyAttributes attr = + IsImmutableVariableMode(mode) ? FROZEN : SEALED; + Handle<AccessorInfo> info = + Accessors::MakeModuleExport(name, index, attr); + Handle<Object> result = SetAccessor(module, info); + ASSERT(!(result.is_null() || result->IsUndefined())); + USE(result); + break; + } + case MODULE: { + Object* referenced_context = Context::cast(host_context)->get(index); + Handle<JSModule> value(Context::cast(referenced_context)->module()); + JSReceiver::SetProperty(module, name, value, FROZEN, kStrictMode); + break; + } + case INTERNAL: + case TEMPORARY: + case DYNAMIC: + case DYNAMIC_GLOBAL: + case DYNAMIC_LOCAL: + UNREACHABLE(); + } + } + + JSObject::PreventExtensions(module); + } + + ASSERT(!isolate->has_pending_exception()); + return isolate->heap()->undefined_value(); } @@ -9055,7 +8998,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { source = Handle<String>(source->TryFlattenGetString()); // Optimized fast case where we only have ASCII characters. Handle<Object> result; - if (source->IsSeqAsciiString()) { + if (source->IsSeqOneByteString()) { result = JsonParser<true>::Parse(source, zone); } else { result = JsonParser<false>::Parse(source, zone); @@ -9098,8 +9041,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { // strings. Throw an exception if it doesn't. if (context->allow_code_gen_from_strings()->IsFalse() && !CodeGenerationFromStringsAllowed(isolate, context)) { - return isolate->Throw(*isolate->factory()->NewError( - "code_gen_from_strings", HandleVector<Object>(NULL, 0))); + Handle<Object> error_message = + context->ErrorMessageForCodeGenerationFromStrings(); + return isolate->Throw(*isolate->factory()->NewEvalError( + "code_gen_from_strings", HandleVector<Object>(&error_message, 1))); } // Compile source string in the native context. @@ -9126,8 +9071,10 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, // strings. Throw an exception if it doesn't. if (native_context->allow_code_gen_from_strings()->IsFalse() && !CodeGenerationFromStringsAllowed(isolate, native_context)) { - isolate->Throw(*isolate->factory()->NewError( - "code_gen_from_strings", HandleVector<Object>(NULL, 0))); + Handle<Object> error_message = + native_context->ErrorMessageForCodeGenerationFromStrings(); + isolate->Throw(*isolate->factory()->NewEvalError( + "code_gen_from_strings", HandleVector<Object>(&error_message, 1))); return MakePair(Failure::Exception(), NULL); } @@ -9221,7 +9168,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) { RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) { ASSERT(args.length() == 2); CONVERT_ARG_CHECKED(JSArray, array, 0); - CONVERT_ARG_CHECKED(JSObject, element, 1); + CONVERT_ARG_CHECKED(JSReceiver, element, 1); RUNTIME_ASSERT(array->HasFastSmiOrObjectElements()); int length = Smi::cast(array->length())->value(); FixedArray* elements = FixedArray::cast(array->elements()); @@ -9290,7 +9237,7 @@ class ArrayConcatVisitor { clear_storage(); set_storage(*result); } -} + } void increase_index_offset(uint32_t delta) { if (JSObject::kMaxElementCount - index_offset_ < delta) { @@ -9381,10 +9328,22 @@ static uint32_t EstimateElementCount(Handle<JSArray> array) { break; } case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - // TODO(1810): Decide if it's worthwhile to implement this. - UNREACHABLE(); + case FAST_HOLEY_DOUBLE_ELEMENTS: { + // Fast elements can't have lengths that are not representable by + // a 32-bit signed integer. + ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0); + int fast_length = static_cast<int>(length); + if (array->elements()->IsFixedArray()) { + ASSERT(FixedArray::cast(array->elements())->length() == 0); + break; + } + Handle<FixedDoubleArray> elements( + FixedDoubleArray::cast(array->elements())); + for (int i = 0; i < fast_length; i++) { + if (!elements->is_the_hole(i)) element_count++; + } break; + } case DICTIONARY_ELEMENTS: { Handle<SeededNumberDictionary> dictionary( SeededNumberDictionary::cast(array->elements())); @@ -9627,8 +9586,27 @@ static bool IterateElements(Isolate* isolate, } case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_DOUBLE_ELEMENTS: { - // TODO(1810): Decide if it's worthwhile to implement this. - UNREACHABLE(); + // Run through the elements FixedArray and use HasElement and GetElement + // to check the prototype for missing elements. + Handle<FixedDoubleArray> elements( + FixedDoubleArray::cast(receiver->elements())); + int fast_length = static_cast<int>(length); + ASSERT(fast_length <= elements->length()); + for (int j = 0; j < fast_length; j++) { + HandleScope loop_scope(isolate); + if (!elements->is_the_hole(j)) { + double double_value = elements->get_scalar(j); + Handle<Object> element_value = + isolate->factory()->NewNumber(double_value); + visitor->visit(j, element_value); + } else if (receiver->HasElement(j)) { + // Call GetElement on receiver, not its prototype, or getters won't + // have the correct receiver. + Handle<Object> element_value = Object::GetElement(receiver, j); + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); + visitor->visit(j, element_value); + } + } break; } case DICTIONARY_ELEMENTS: { @@ -9731,48 +9709,51 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { // that mutate other arguments (but will otherwise be precise). // The number of elements is precise if there are no inherited elements. + ElementsKind kind = FAST_SMI_ELEMENTS; + uint32_t estimate_result_length = 0; uint32_t estimate_nof_elements = 0; - { - for (int i = 0; i < argument_count; i++) { - HandleScope loop_scope; - Handle<Object> obj(elements->get(i)); - uint32_t length_estimate; - uint32_t element_estimate; - if (obj->IsJSArray()) { - Handle<JSArray> array(Handle<JSArray>::cast(obj)); - // TODO(1810): Find out if it's worthwhile to properly support - // arbitrary ElementsKinds. For now, pessimistically transition to - // FAST_*_ELEMENTS. - if (array->HasFastDoubleElements()) { - ElementsKind to_kind = FAST_ELEMENTS; - if (array->HasFastHoleyElements()) { - to_kind = FAST_HOLEY_ELEMENTS; - } - array = Handle<JSArray>::cast( - JSObject::TransitionElementsKind(array, to_kind)); + for (int i = 0; i < argument_count; i++) { + HandleScope loop_scope; + Handle<Object> obj(elements->get(i)); + uint32_t length_estimate; + uint32_t element_estimate; + if (obj->IsJSArray()) { + Handle<JSArray> array(Handle<JSArray>::cast(obj)); + length_estimate = static_cast<uint32_t>(array->length()->Number()); + if (length_estimate != 0) { + ElementsKind array_kind = + GetPackedElementsKind(array->map()->elements_kind()); + if (IsMoreGeneralElementsKindTransition(kind, array_kind)) { + kind = array_kind; } - length_estimate = - static_cast<uint32_t>(array->length()->Number()); - element_estimate = - EstimateElementCount(array); - } else { - length_estimate = 1; - element_estimate = 1; - } - // Avoid overflows by capping at kMaxElementCount. - if (JSObject::kMaxElementCount - estimate_result_length < - length_estimate) { - estimate_result_length = JSObject::kMaxElementCount; - } else { - estimate_result_length += length_estimate; } - if (JSObject::kMaxElementCount - estimate_nof_elements < - element_estimate) { - estimate_nof_elements = JSObject::kMaxElementCount; - } else { - estimate_nof_elements += element_estimate; + element_estimate = EstimateElementCount(array); + } else { + if (obj->IsHeapObject()) { + if (obj->IsNumber()) { + if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) { + kind = FAST_DOUBLE_ELEMENTS; + } + } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) { + kind = FAST_ELEMENTS; + } } + length_estimate = 1; + element_estimate = 1; + } + // Avoid overflows by capping at kMaxElementCount. + if (JSObject::kMaxElementCount - estimate_result_length < + length_estimate) { + estimate_result_length = JSObject::kMaxElementCount; + } else { + estimate_result_length += length_estimate; + } + if (JSObject::kMaxElementCount - estimate_nof_elements < + element_estimate) { + estimate_nof_elements = JSObject::kMaxElementCount; + } else { + estimate_nof_elements += element_estimate; } } @@ -9783,8 +9764,76 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { Handle<FixedArray> storage; if (fast_case) { - // The backing storage array must have non-existing elements to - // preserve holes across concat operations. + if (kind == FAST_DOUBLE_ELEMENTS) { + Handle<FixedDoubleArray> double_storage = + isolate->factory()->NewFixedDoubleArray(estimate_result_length); + int j = 0; + bool failure = false; + for (int i = 0; i < argument_count; i++) { + Handle<Object> obj(elements->get(i)); + if (obj->IsSmi()) { + double_storage->set(j, Smi::cast(*obj)->value()); + j++; + } else if (obj->IsNumber()) { + double_storage->set(j, obj->Number()); + j++; + } else { + JSArray* array = JSArray::cast(*obj); + uint32_t length = static_cast<uint32_t>(array->length()->Number()); + switch (array->map()->elements_kind()) { + case FAST_HOLEY_DOUBLE_ELEMENTS: + case FAST_DOUBLE_ELEMENTS: { + // Empty fixed array indicates that there are no elements. + if (array->elements()->IsFixedArray()) break; + FixedDoubleArray* elements = + FixedDoubleArray::cast(array->elements()); + for (uint32_t i = 0; i < length; i++) { + if (elements->is_the_hole(i)) { + failure = true; + break; + } + double double_value = elements->get_scalar(i); + double_storage->set(j, double_value); + j++; + } + break; + } + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_SMI_ELEMENTS: { + FixedArray* elements( + FixedArray::cast(array->elements())); + for (uint32_t i = 0; i < length; i++) { + Object* element = elements->get(i); + if (element->IsTheHole()) { + failure = true; + break; + } + int32_t int_value = Smi::cast(element)->value(); + double_storage->set(j, int_value); + j++; + } + break; + } + case FAST_HOLEY_ELEMENTS: + ASSERT_EQ(0, length); + break; + default: + UNREACHABLE(); + } + } + if (failure) break; + } + Handle<JSArray> array = isolate->factory()->NewJSArray(0); + Smi* length = Smi::FromInt(j); + Handle<Map> map; + map = isolate->factory()->GetElementsTransitionMap(array, kind); + array->set_map(*map); + array->set_length(length); + array->set_elements(*double_storage); + return *array; + } + // The backing storage array must have non-existing elements to preserve + // holes across concat operations. storage = isolate->factory()->NewFixedArrayWithHoles( estimate_result_length); } else { @@ -9998,8 +10047,8 @@ static MaybeObject* DebugLookupResultValue(Heap* heap, return value; case FIELD: value = - JSObject::cast( - result->holder())->FastPropertyAt(result->GetFieldIndex()); + JSObject::cast(result->holder())->FastPropertyAt( + result->GetFieldIndex().field_index()); if (value->IsTheHole()) { return heap->undefined_value(); } @@ -10638,7 +10687,8 @@ static bool CopyContextLocalsToScopeObject( RETURN_IF_EMPTY_HANDLE_VALUE( isolate, - SetProperty(scope_object, + SetProperty(isolate, + scope_object, Handle<String>(scope_info->ContextLocalName(i)), Handle<Object>(context->get(context_index), isolate), NONE, @@ -10673,7 +10723,8 @@ static Handle<JSObject> MaterializeLocalScopeWithFrameInspector( RETURN_IF_EMPTY_HANDLE_VALUE( isolate, - SetProperty(local_scope, + SetProperty(isolate, + local_scope, Handle<String>(scope_info->ParameterName(i)), value, NONE, @@ -10685,7 +10736,8 @@ static Handle<JSObject> MaterializeLocalScopeWithFrameInspector( for (int i = 0; i < scope_info->StackLocalCount(); ++i) { RETURN_IF_EMPTY_HANDLE_VALUE( isolate, - SetProperty(local_scope, + SetProperty(isolate, + local_scope, Handle<String>(scope_info->StackLocalName(i)), Handle<Object>(frame_inspector->GetExpression(i)), NONE, @@ -10719,7 +10771,8 @@ static Handle<JSObject> MaterializeLocalScopeWithFrameInspector( Handle<String> key(String::cast(keys->get(i))); RETURN_IF_EMPTY_HANDLE_VALUE( isolate, - SetProperty(local_scope, + SetProperty(isolate, + local_scope, key, GetProperty(ext, key), NONE, @@ -10780,7 +10833,8 @@ static Handle<JSObject> MaterializeClosure(Isolate* isolate, Handle<String> key(String::cast(keys->get(i))); RETURN_IF_EMPTY_HANDLE_VALUE( isolate, - SetProperty(closure_scope, + SetProperty(isolate, + closure_scope, key, GetProperty(ext, key), NONE, @@ -10793,6 +10847,52 @@ static Handle<JSObject> MaterializeClosure(Isolate* isolate, } +// This method copies structure of MaterializeClosure method above. +static bool SetClosureVariableValue(Isolate* isolate, + Handle<Context> context, + Handle<String> variable_name, + Handle<Object> new_value) { + ASSERT(context->IsFunctionContext()); + + Handle<SharedFunctionInfo> shared(context->closure()->shared()); + Handle<ScopeInfo> scope_info(shared->scope_info()); + + // Context locals to the context extension. + for (int i = 0; i < scope_info->ContextLocalCount(); i++) { + Handle<String> next_name(scope_info->ContextLocalName(i)); + if (variable_name->Equals(*next_name)) { + VariableMode mode; + InitializationFlag init_flag; + int context_index = + scope_info->ContextSlotIndex(*next_name, &mode, &init_flag); + if (context_index < 0) { + return false; + } + context->set(context_index, *new_value); + return true; + } + } + + // Properties from the function context extension. This will + // be variables introduced by eval. + if (context->has_extension()) { + Handle<JSObject> ext(JSObject::cast(context->extension())); + if (ext->HasProperty(*variable_name)) { + // We don't expect this to do anything except replacing property value. + SetProperty(isolate, + ext, + variable_name, + new_value, + NONE, + kNonStrictMode); + return true; + } + } + + return false; +} + + // Create a plain JSObject which materializes the scope for the specified // catch context. static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, @@ -10804,7 +10904,12 @@ static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, isolate->factory()->NewJSObject(isolate->object_function()); RETURN_IF_EMPTY_HANDLE_VALUE( isolate, - SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode), + SetProperty(isolate, + catch_scope, + name, + thrown_object, + NONE, + kNonStrictMode), Handle<JSObject>()); return catch_scope; } @@ -10880,7 +10985,8 @@ class ScopeIterator { inlined_jsframe_index_(inlined_jsframe_index), function_(JSFunction::cast(frame->function())), context_(Context::cast(frame->context())), - nested_scope_chain_(4) { + nested_scope_chain_(4), + failed_(false) { // Catch the case when the debugger stops in an internal function. Handle<SharedFunctionInfo> shared_info(function_->shared()); @@ -10954,17 +11060,24 @@ class ScopeIterator { frame_(NULL), inlined_jsframe_index_(0), function_(function), - context_(function->context()) { + context_(function->context()), + failed_(false) { if (function->IsBuiltin()) { context_ = Handle<Context>(); } } // More scopes? - bool Done() { return context_.is_null(); } + bool Done() { + ASSERT(!failed_); + return context_.is_null(); + } + + bool Failed() { return failed_; } // Move to the next scope. void Next() { + ASSERT(!failed_); ScopeType scope_type = Type(); if (scope_type == ScopeTypeGlobal) { // The global scope is always the last in the chain. @@ -10985,6 +11098,7 @@ class ScopeIterator { // Return the type of the current scope. ScopeType Type() { + ASSERT(!failed_); if (!nested_scope_chain_.is_empty()) { Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); switch (scope_info->Type()) { @@ -11034,6 +11148,7 @@ class ScopeIterator { // Return the JavaScript object with the content of the current scope. Handle<JSObject> ScopeObject() { + ASSERT(!failed_); switch (Type()) { case ScopeIterator::ScopeTypeGlobal: return Handle<JSObject>(CurrentContext()->global_object()); @@ -11058,7 +11173,35 @@ class ScopeIterator { return Handle<JSObject>(); } + bool SetVariableValue(Handle<String> variable_name, + Handle<Object> new_value) { + ASSERT(!failed_); + switch (Type()) { + case ScopeIterator::ScopeTypeGlobal: + break; + case ScopeIterator::ScopeTypeLocal: + // TODO(2399): implement. + break; + case ScopeIterator::ScopeTypeWith: + break; + case ScopeIterator::ScopeTypeCatch: + // TODO(2399): implement. + break; + case ScopeIterator::ScopeTypeClosure: + return SetClosureVariableValue(isolate_, CurrentContext(), + variable_name, new_value); + case ScopeIterator::ScopeTypeBlock: + // TODO(2399): should we implement it? + break; + case ScopeIterator::ScopeTypeModule: + // TODO(2399): should we implement it? + break; + } + return false; + } + Handle<ScopeInfo> CurrentScopeInfo() { + ASSERT(!failed_); if (!nested_scope_chain_.is_empty()) { return nested_scope_chain_.last(); } else if (context_->IsBlockContext()) { @@ -11072,6 +11215,7 @@ class ScopeIterator { // Return the context for this scope. For the local context there might not // be an actual context. Handle<Context> CurrentContext() { + ASSERT(!failed_); if (Type() == ScopeTypeGlobal || nested_scope_chain_.is_empty()) { return context_; @@ -11085,6 +11229,7 @@ class ScopeIterator { #ifdef DEBUG // Debug print of the content of the current scope. void DebugPrint() { + ASSERT(!failed_); switch (Type()) { case ScopeIterator::ScopeTypeGlobal: PrintF("Global:\n"); @@ -11142,6 +11287,7 @@ class ScopeIterator { Handle<JSFunction> function_; Handle<Context> context_; List<Handle<ScopeInfo> > nested_scope_chain_; + bool failed_; void RetrieveScopeChain(Scope* scope, Handle<SharedFunctionInfo> shared_info) { @@ -11154,7 +11300,9 @@ class ScopeIterator { // faulty. We fail in debug mode but in release mode we only provide the // information we get from the context chain but nothing about // completely stack allocated scopes or stack allocated locals. - UNREACHABLE(); + // Or it could be due to stack overflow. + ASSERT(isolate_->has_pending_exception()); + failed_ = true; } } @@ -11291,6 +11439,64 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) { } +static bool SetScopeVariableValue(ScopeIterator* it, int index, + Handle<String> variable_name, + Handle<Object> new_value) { + for (int n = 0; !it->Done() && n < index; it->Next()) { + n++; + } + if (it->Done()) { + return false; + } + return it->SetVariableValue(variable_name, new_value); +} + + +// Change variable value in closure or local scope +// args[0]: number or JsFunction: break id or function +// args[1]: number: frame index (when arg[0] is break id) +// args[2]: number: inlined frame index (when arg[0] is break id) +// args[3]: number: scope index +// args[4]: string: variable name +// args[5]: object: new value +// +// Return true if success and false otherwise +RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) { + HandleScope scope(isolate); + ASSERT(args.length() == 6); + + // Check arguments. + CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); + CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); + Handle<Object> new_value = args.at<Object>(5); + + bool res; + if (args[0]->IsNumber()) { + Object* check; + { MaybeObject* maybe_check = Runtime_CheckExecutionState( + RUNTIME_ARGUMENTS(isolate, args)); + if (!maybe_check->ToObject(&check)) return maybe_check; + } + CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); + CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); + + // Get the frame where the debugging is performed. + StackFrame::Id id = UnwrapFrameId(wrapped_id); + JavaScriptFrameIterator frame_it(isolate, id); + JavaScriptFrame* frame = frame_it.frame(); + + ScopeIterator it(isolate, frame, inlined_jsframe_index); + res = SetScopeVariableValue(&it, index, variable_name, new_value); + } else { + CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); + ScopeIterator it(isolate, fun); + res = SetScopeVariableValue(&it, index, variable_name, new_value); + } + + return isolate->heap()->ToBoolean(res); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) { HandleScope scope(isolate); ASSERT(args.length() == 0); @@ -11579,6 +11785,8 @@ static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate, List<Handle<Context> > context_chain; ScopeIterator it(isolate, frame, inlined_jsframe_index); + if (it.Failed()) return Handle<Context>::null(); + for (; it.Type() != ScopeIterator::ScopeTypeGlobal && it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) { ASSERT(!it.Done()); @@ -11607,9 +11815,7 @@ static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate, // Materialize the contents of the block scope into a JSObject. Handle<JSObject> block_scope_object = MaterializeBlockScope(isolate, current); - if (block_scope_object.is_null()) { - return Handle<Context>::null(); - } + CHECK(!block_scope_object.is_null()); // Allocate a new function context for the debug evaluation and set the // extension object. Handle<Context> new_context = @@ -11770,6 +11976,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { context, frame, inlined_jsframe_index); + if (context.is_null()) { + ASSERT(isolate->has_pending_exception()); + MaybeObject* exception = isolate->pending_exception(); + isolate->clear_pending_exception(); + return exception; + } if (additional_context->IsJSObject()) { Handle<JSObject> extension = Handle<JSObject>::cast(additional_context); @@ -11813,6 +12025,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { scope_info, function_context); + // Check if eval is blocked in the context and temporarily allow it + // for debugger. + Handle<Context> native_context = Handle<Context>(context->native_context()); + bool eval_disabled = + native_context->allow_code_gen_from_strings()->IsFalse(); + if (eval_disabled) { + native_context->set_allow_code_gen_from_strings( + isolate->heap()->true_value()); + } // Invoke the evaluation function and return the result. Handle<Object> argv[] = { arguments, source }; Handle<Object> result = @@ -11821,6 +12042,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { ARRAY_SIZE(argv), argv, &has_pending_exception); + if (eval_disabled) { + native_context->set_allow_code_gen_from_strings( + isolate->heap()->false_value()); + } if (has_pending_exception) return Failure::Exception(); // Skip the global proxy as it has no properties and always delegates to the @@ -12856,47 +13081,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) { } -// Determines whether the given stack frame should be displayed in -// a stack trace. The caller is the error constructor that asked -// for the stack trace to be collected. The first time a construct -// call to this function is encountered it is skipped. The seen_caller -// in/out parameter is used to remember if the caller has been seen -// yet. -static bool ShowFrameInStackTrace(StackFrame* raw_frame, - Object* caller, - bool* seen_caller) { - // Only display JS frames. - if (!raw_frame->is_java_script()) { - return false; - } - JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); - Object* raw_fun = frame->function(); - // Not sure when this can happen but skip it just in case. - if (!raw_fun->IsJSFunction()) { - return false; - } - if ((raw_fun == caller) && !(*seen_caller)) { - *seen_caller = true; - return false; - } - // Skip all frames until we've seen the caller. - if (!(*seen_caller)) return false; - // Also, skip non-visible built-in functions and any call with the builtins - // object as receiver, so as to not reveal either the builtins object or - // an internal function. - // The --builtins-in-stack-traces command line flag allows including - // internal call sites in the stack trace for debugging purposes. - if (!FLAG_builtins_in_stack_traces) { - JSFunction* fun = JSFunction::cast(raw_fun); - if (frame->receiver()->IsJSBuiltinsObject() || - (fun->IsBuiltin() && !fun->shared()->native())) { - return false; - } - } - return true; -} - - // Collect the raw data for a stack trace. Returns an array of 4 // element segments each containing a receiver, function, code and // native code offset. @@ -12907,57 +13091,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) { CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]); HandleScope scope(isolate); - Factory* factory = isolate->factory(); + // Optionally capture a more detailed stack trace for the message. + isolate->CaptureAndSetDetailedStackTrace(error_object); + // Capture a simple stack trace for the stack property. + return *isolate->CaptureSimpleStackTrace(error_object, caller, limit); +} - limit = Max(limit, 0); // Ensure that limit is not negative. - int initial_size = Min(limit, 10); - Handle<FixedArray> elements = - factory->NewFixedArrayWithHoles(initial_size * 4); - StackFrameIterator iter(isolate); - // If the caller parameter is a function we skip frames until we're - // under it before starting to collect. - bool seen_caller = !caller->IsJSFunction(); - int cursor = 0; - int frames_seen = 0; - while (!iter.done() && frames_seen < limit) { - StackFrame* raw_frame = iter.frame(); - if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) { - frames_seen++; - JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); - // Set initial size to the maximum inlining level + 1 for the outermost - // function. - List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1); - frame->Summarize(&frames); - for (int i = frames.length() - 1; i >= 0; i--) { - if (cursor + 4 > elements->length()) { - int new_capacity = JSObject::NewElementsCapacity(elements->length()); - Handle<FixedArray> new_elements = - factory->NewFixedArrayWithHoles(new_capacity); - for (int i = 0; i < cursor; i++) { - new_elements->set(i, elements->get(i)); - } - elements = new_elements; - } - ASSERT(cursor + 4 <= elements->length()); - - Handle<Object> recv = frames[i].receiver(); - Handle<JSFunction> fun = frames[i].function(); - Handle<Code> code = frames[i].code(); - Handle<Smi> offset(Smi::FromInt(frames[i].offset())); - elements->set(cursor++, *recv); - elements->set(cursor++, *fun); - elements->set(cursor++, *code); - elements->set(cursor++, *offset); - } - } - iter.Advance(); - } - Handle<JSArray> result = factory->NewJSArrayWithElements(elements); - // Capture and attach a more detailed stack trace if necessary. - isolate->CaptureAndSetCurrentStackTraceFor(error_object); - result->set_length(Smi::FromInt(cursor)); - return *result; +// Retrieve the raw stack trace collected on stack overflow and delete +// it since it is used only once to avoid keeping it alive. +RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOverflowedRawStackTrace) { + ASSERT_EQ(args.length(), 1); + CONVERT_ARG_CHECKED(JSObject, error_object, 0); + String* key = isolate->heap()->hidden_stack_trace_symbol(); + Object* result = error_object->GetHiddenProperty(key); + RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined()); + error_object->DeleteHiddenProperty(key); + return result; } @@ -12969,7 +13119,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) { const char* version_string = v8::V8::GetVersion(); - return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string), + return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string), NOT_TENURED); } @@ -13040,7 +13190,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { if (pending_exception) return Failure::Exception(); } -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { cache_handle->JSFunctionResultCacheVerify(); } @@ -13071,7 +13221,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { cache_handle->set(index + 1, *value); cache_handle->set_finger_index(index); -#ifdef DEBUG +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { cache_handle->JSFunctionResultCacheVerify(); } @@ -13081,33 +13231,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { } -RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) { - HandleScope scope(isolate); - CONVERT_ARG_HANDLE_CHECKED(String, type, 0); - CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1); - return *isolate->factory()->NewJSMessageObject( - type, - arguments, - 0, - 0, - isolate->factory()->undefined_value(), - isolate->factory()->undefined_value(), - isolate->factory()->undefined_value()); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) { - CONVERT_ARG_CHECKED(JSMessageObject, message, 0); - return message->type(); -} - - -RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) { - CONVERT_ARG_CHECKED(JSMessageObject, message, 0); - return message->arguments(); -} - - RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) { CONVERT_ARG_CHECKED(JSMessageObject, message, 0); return Smi::FromInt(message->start_position()); @@ -13220,6 +13343,88 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) { return isolate->heap()->ToBoolean(obj1->map() == obj2->map()); } + +RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) { + ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(JSReceiver, obj, 0); + if (obj->IsJSGlobalProxy()) { + Object* proto = obj->GetPrototype(); + if (obj->IsNull()) return isolate->heap()->false_value(); + ASSERT(proto->IsJSGlobalObject()); + obj = JSReceiver::cast(proto); + } + return isolate->heap()->ToBoolean(obj->map()->is_observed()); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) { + ASSERT(args.length() == 2); + CONVERT_ARG_CHECKED(JSReceiver, obj, 0); + CONVERT_BOOLEAN_ARG_CHECKED(is_observed, 1); + if (obj->IsJSGlobalProxy()) { + Object* proto = obj->GetPrototype(); + if (obj->IsNull()) return isolate->heap()->undefined_value(); + ASSERT(proto->IsJSGlobalObject()); + obj = JSReceiver::cast(proto); + } + if (obj->map()->is_observed() != is_observed) { + MaybeObject* maybe = obj->map()->Copy(); + Map* map; + if (!maybe->To(&map)) return maybe; + map->set_is_observed(is_observed); + obj->set_map(map); + } + return isolate->heap()->undefined_value(); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_SetObserverDeliveryPending) { + ASSERT(args.length() == 0); + isolate->set_observer_delivery_pending(true); + return isolate->heap()->undefined_value(); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) { + ASSERT(args.length() == 0); + return isolate->heap()->observation_state(); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectHashTable) { + ASSERT(args.length() == 0); + return ObjectHashTable::Allocate(0); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectHashTableGet) { + NoHandleAllocation ha; + ASSERT(args.length() == 2); + CONVERT_ARG_CHECKED(ObjectHashTable, table, 0); + Object* key = args[1]; + if (key->IsJSGlobalProxy()) { + key = key->GetPrototype(); + if (key->IsNull()) return isolate->heap()->undefined_value(); + } + Object* lookup = table->Lookup(key); + return lookup->IsTheHole() ? isolate->heap()->undefined_value() : lookup; +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectHashTableSet) { + HandleScope scope(isolate); + ASSERT(args.length() == 3); + CONVERT_ARG_HANDLE_CHECKED(ObjectHashTable, table, 0); + Handle<Object> key = args.at<Object>(1); + if (key->IsJSGlobalProxy()) { + key = handle(key->GetPrototype(), isolate); + if (key->IsNull()) return *table; + } + Handle<Object> value = args.at<Object>(2); + return *PutIntoObjectHashTable(table, key, value); +} + + // ---------------------------------------------------------------------------- // Implementation of Runtime diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index da60ee10b7..c77f988215 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -62,7 +62,6 @@ namespace internal { F(GetIndexedInterceptorElementNames, 1, 1) \ F(GetArgumentsProperty, 1, 1) \ F(ToFastProperties, 1, 1) \ - F(ToSlowProperties, 1, 1) \ F(FinishArrayPrototypeSetup, 1, 1) \ F(SpecialArrayFunctions, 1, 1) \ F(GetDefaultReceiver, 1, 1) \ @@ -86,7 +85,9 @@ namespace internal { F(NewStrictArgumentsFast, 3, 1) \ F(LazyCompile, 1, 1) \ F(LazyRecompile, 1, 1) \ - F(ParallelRecompile, 1, 1) \ + F(ParallelRecompile, 1, 1) \ + F(ForceParallelRecompile, 1, 1) \ + F(InstallRecompiledCode, 1, 1) \ F(NotifyDeoptimized, 1, 1) \ F(NotifyOSR, 0, 1) \ F(DeoptimizeFunction, 1, 1) \ @@ -112,7 +113,6 @@ namespace internal { F(Typeof, 1, 1) \ \ F(StringToNumber, 1, 1) \ - F(StringFromCharCodeArray, 1, 1) \ F(StringParseInt, 2, 1) \ F(StringParseFloat, 1, 1) \ F(StringToLowerCase, 1, 1) \ @@ -121,9 +121,6 @@ namespace internal { F(CharFromCode, 1, 1) \ F(URIEscape, 1, 1) \ F(URIUnescape, 1, 1) \ - F(QuoteJSONString, 1, 1) \ - F(QuoteJSONStringComma, 1, 1) \ - F(QuoteJSONStringArray, 1, 1) \ \ F(NumberToString, 1, 1) \ F(NumberToStringSkipCache, 1, 1) \ @@ -192,6 +189,10 @@ namespace internal { \ /* JSON */ \ F(ParseJson, 1, 1) \ + F(BasicJSONStringify, 1, 1) \ + F(QuoteJSONString, 1, 1) \ + F(QuoteJSONStringComma, 1, 1) \ + F(QuoteJSONStringArray, 1, 1) \ \ /* Strings */ \ F(StringCharCodeAt, 2, 1) \ @@ -205,6 +206,8 @@ namespace internal { F(StringTrim, 3, 1) \ F(StringToArray, 2, 1) \ F(NewStringWrapper, 1, 1) \ + F(NewString, 2, 1) \ + F(TruncateString, 2, 1) \ \ /* Numbers */ \ F(NumberToRadixString, 2, 1) \ @@ -233,6 +236,7 @@ namespace internal { F(FunctionIsBuiltin, 1, 1) \ F(GetScript, 1, 1) \ F(CollectStackTrace, 3, 1) \ + F(GetOverflowedRawStackTrace, 1, 1) \ F(GetV8Version, 0, 1) \ \ F(ClassOf, 1, 1) \ @@ -267,6 +271,7 @@ namespace internal { F(DefineOrRedefineDataProperty, 4, 1) \ F(DefineOrRedefineAccessorProperty, 5, 1) \ F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */, 1) \ + F(GetDataProperty, 2, 1) \ \ /* Arrays */ \ F(RemoveArrayHoles, 2, 1) \ @@ -302,6 +307,7 @@ namespace internal { F(SetAdd, 2, 1) \ F(SetHas, 2, 1) \ F(SetDelete, 2, 1) \ + F(SetGetSize, 1, 1) \ \ /* Harmony maps */ \ F(MapInitialize, 1, 1) \ @@ -309,6 +315,7 @@ namespace internal { F(MapHas, 2, 1) \ F(MapDelete, 2, 1) \ F(MapSet, 3, 1) \ + F(MapGetSize, 1, 1) \ \ /* Harmony weakmaps */ \ F(WeakMapInitialize, 1, 1) \ @@ -317,6 +324,15 @@ namespace internal { F(WeakMapDelete, 2, 1) \ F(WeakMapSet, 3, 1) \ \ + /* Harmony observe */ \ + F(IsObserved, 1, 1) \ + F(SetIsObserved, 2, 1) \ + F(SetObserverDeliveryPending, 0, 1) \ + F(GetObservationState, 0, 1) \ + F(CreateObjectHashTable, 0, 1) \ + F(ObjectHashTableGet, 2, 1) \ + F(ObjectHashTableSet, 3, 1) \ + \ /* Statements */ \ F(NewClosure, 3, 1) \ F(NewObject, 1, 1) \ @@ -336,7 +352,7 @@ namespace internal { F(PushWithContext, 2, 1) \ F(PushCatchContext, 3, 1) \ F(PushBlockContext, 2, 1) \ - F(PushModuleContext, 1, 1) \ + F(PushModuleContext, 2, 1) \ F(DeleteContextSlot, 2, 1) \ F(LoadContextSlot, 2, 2) \ F(LoadContextSlotNoReferenceError, 2, 2) \ @@ -344,6 +360,7 @@ namespace internal { \ /* Declarations and initialization */ \ F(DeclareGlobals, 3, 1) \ + F(DeclareModules, 1, 1) \ F(DeclareContextSlot, 4, 1) \ F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \ F(InitializeConstGlobal, 2, 1) \ @@ -364,9 +381,6 @@ namespace internal { F(GetFromCache, 2, 1) \ \ /* Message objects */ \ - F(NewMessageObject, 2, 1) \ - F(MessageGetType, 1, 1) \ - F(MessageGetArguments, 1, 1) \ F(MessageGetStartPosition, 1, 1) \ F(MessageGetScript, 1, 1) \ \ @@ -419,6 +433,7 @@ namespace internal { F(GetScopeDetails, 4, 1) \ F(GetFunctionScopeCount, 1, 1) \ F(GetFunctionScopeDetails, 2, 1) \ + F(SetScopeVariableValue, 6, 1) \ F(DebugPrintScopes, 0, 1) \ F(GetThreadCount, 1, 1) \ F(GetThreadDetails, 2, 1) \ @@ -515,6 +530,8 @@ namespace internal { F(DateField, 2 /* date object, field index */, 1) \ F(StringCharFromCode, 1, 1) \ F(StringCharAt, 2, 1) \ + F(OneByteSeqStringSetChar, 3, 1) \ + F(TwoByteSeqStringSetChar, 3, 1) \ F(ObjectEquals, 2, 1) \ F(RandomHeapNumber, 0, 1) \ F(IsObject, 1, 1) \ diff --git a/deps/v8/src/scopeinfo.cc b/deps/v8/src/scopeinfo.cc index 02b4323980..c0b2c4c8e6 100644 --- a/deps/v8/src/scopeinfo.cc +++ b/deps/v8/src/scopeinfo.cc @@ -321,6 +321,7 @@ int ScopeInfo::ContextSlotIndex(String* name, return result; } } + // Cache as not found. Mode and init flag don't matter. context_slot_cache->Update(this, name, INTERNAL, kNeedsInitialization, -1); } return -1; @@ -504,4 +505,32 @@ void ScopeInfo::Print() { } #endif // DEBUG + +//--------------------------------------------------------------------------- +// ModuleInfo. + +Handle<ModuleInfo> ModuleInfo::Create( + Isolate* isolate, Interface* interface, Scope* scope) { + Handle<ModuleInfo> info = Allocate(isolate, interface->Length()); + info->set_host_index(interface->Index()); + int i = 0; + for (Interface::Iterator it = interface->iterator(); + !it.done(); it.Advance(), ++i) { + Variable* var = scope->LocalLookup(it.name()); + info->set_name(i, *it.name()); + info->set_mode(i, var->mode()); + ASSERT((var->mode() == MODULE) == (it.interface()->IsModule())); + if (var->mode() == MODULE) { + ASSERT(it.interface()->IsFrozen()); + ASSERT(it.interface()->Index() >= 0); + info->set_index(i, it.interface()->Index()); + } else { + ASSERT(var->index() >= 0); + info->set_index(i, var->index()); + } + } + ASSERT(i == info->length()); + return info; +} + } } // namespace v8::internal diff --git a/deps/v8/src/scopeinfo.h b/deps/v8/src/scopeinfo.h index 93734f5a16..a884b3b9ed 100644 --- a/deps/v8/src/scopeinfo.h +++ b/deps/v8/src/scopeinfo.h @@ -114,9 +114,9 @@ class ContextSlotCache { // Bit fields in value_ (type, shift, size). Must be public so the // constants can be embedded in generated code. - class ModeField: public BitField<VariableMode, 0, 3> {}; - class InitField: public BitField<InitializationFlag, 3, 1> {}; - class IndexField: public BitField<int, 4, 32-4> {}; + class ModeField: public BitField<VariableMode, 0, 4> {}; + class InitField: public BitField<InitializationFlag, 4, 1> {}; + class IndexField: public BitField<int, 5, 32-5> {}; private: uint32_t value_; @@ -130,6 +130,67 @@ class ContextSlotCache { }; + + +//--------------------------------------------------------------------------- +// Auxiliary class used for the description of module instances. +// Used by Runtime_DeclareModules. + +class ModuleInfo: public FixedArray { + public: + static ModuleInfo* cast(Object* description) { + return static_cast<ModuleInfo*>(FixedArray::cast(description)); + } + + static Handle<ModuleInfo> Create( + Isolate* isolate, Interface* interface, Scope* scope); + + // Index of module's context in host context. + int host_index() { return Smi::cast(get(HOST_OFFSET))->value(); } + + // Name, mode, and index of the i-th export, respectively. + // For value exports, the index is the slot of the value in the module + // context, for exported modules it is the slot index of the + // referred module's context in the host context. + // TODO(rossberg): This format cannot yet handle exports of modules declared + // in earlier scripts. + String* name(int i) { return String::cast(get(name_offset(i))); } + VariableMode mode(int i) { + return static_cast<VariableMode>(Smi::cast(get(mode_offset(i)))->value()); + } + int index(int i) { return Smi::cast(get(index_offset(i)))->value(); } + + int length() { return (FixedArray::length() - HEADER_SIZE) / ITEM_SIZE; } + + private: + // The internal format is: Index, (Name, VariableMode, Index)* + enum { + HOST_OFFSET, + NAME_OFFSET, + MODE_OFFSET, + INDEX_OFFSET, + HEADER_SIZE = NAME_OFFSET, + ITEM_SIZE = INDEX_OFFSET - NAME_OFFSET + 1 + }; + inline int name_offset(int i) { return NAME_OFFSET + i * ITEM_SIZE; } + inline int mode_offset(int i) { return MODE_OFFSET + i * ITEM_SIZE; } + inline int index_offset(int i) { return INDEX_OFFSET + i * ITEM_SIZE; } + + static Handle<ModuleInfo> Allocate(Isolate* isolate, int length) { + return Handle<ModuleInfo>::cast( + isolate->factory()->NewFixedArray(HEADER_SIZE + ITEM_SIZE * length)); + } + void set_host_index(int index) { set(HOST_OFFSET, Smi::FromInt(index)); } + void set_name(int i, String* name) { set(name_offset(i), name); } + void set_mode(int i, VariableMode mode) { + set(mode_offset(i), Smi::FromInt(mode)); + } + void set_index(int i, int index) { + set(index_offset(i), Smi::FromInt(index)); + } +}; + + } } // namespace v8::internal #endif // V8_SCOPEINFO_H_ diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc index c9612577af..56a922d25d 100644 --- a/deps/v8/src/scopes.cc +++ b/deps/v8/src/scopes.cc @@ -108,6 +108,7 @@ Scope::Scope(Scope* outer_scope, ScopeType type, Zone* zone) : isolate_(Isolate::Current()), inner_scopes_(4, zone), variables_(zone), + internals_(4, zone), temps_(4, zone), params_(4, zone), unresolved_(16, zone), @@ -131,6 +132,7 @@ Scope::Scope(Scope* inner_scope, : isolate_(Isolate::Current()), inner_scopes_(4, zone), variables_(zone), + internals_(4, zone), temps_(4, zone), params_(4, zone), unresolved_(16, zone), @@ -153,6 +155,7 @@ Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name, Zone* zone) : isolate_(Isolate::Current()), inner_scopes_(1, zone), variables_(zone), + internals_(0, zone), temps_(0, zone), params_(0, zone), unresolved_(0, zone), @@ -197,6 +200,8 @@ void Scope::SetDefaults(ScopeType type, num_var_or_const_ = 0; num_stack_slots_ = 0; num_heap_slots_ = 0; + num_modules_ = 0; + module_var_ = NULL, scope_info_ = scope_info; start_position_ = RelocInfo::kNoPosition; end_position_ = RelocInfo::kNoPosition; @@ -375,6 +380,7 @@ void Scope::Initialize() { Scope* Scope::FinalizeBlockScope() { ASSERT(is_block_scope()); + ASSERT(internals_.is_empty()); ASSERT(temps_.is_empty()); ASSERT(params_.is_empty()); @@ -515,6 +521,19 @@ void Scope::RemoveUnresolved(VariableProxy* var) { } +Variable* Scope::NewInternal(Handle<String> name) { + ASSERT(!already_resolved()); + Variable* var = new(zone()) Variable(this, + name, + INTERNAL, + false, + Variable::NORMAL, + kCreatedInitialized); + internals_.Add(var, zone()); + return var; +} + + Variable* Scope::NewTemporary(Handle<String> name) { ASSERT(!already_resolved()); Variable* var = new(zone()) Variable(this, @@ -615,6 +634,15 @@ void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals, ASSERT(stack_locals != NULL); ASSERT(context_locals != NULL); + // Collect internals which are always allocated on the heap. + for (int i = 0; i < internals_.length(); i++) { + Variable* var = internals_[i]; + if (var->is_used()) { + ASSERT(var->IsContextSlot()); + context_locals->Add(var, zone()); + } + } + // Collect temporaries which are always allocated on the stack. for (int i = 0; i < temps_.length(); i++) { Variable* var = temps_[i]; @@ -624,9 +652,8 @@ void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals, } } - ZoneList<VarAndOrder> vars(variables_.occupancy(), zone()); - // Collect declared local variables. + ZoneList<VarAndOrder> vars(variables_.occupancy(), zone()); for (VariableMap::Entry* p = variables_.Start(); p != NULL; p = variables_.Next(p)) { @@ -659,18 +686,18 @@ bool Scope::AllocateVariables(CompilationInfo* info, } PropagateScopeInfo(outer_scope_calls_non_strict_eval); - // 2) Resolve variables. + // 2) Allocate module instances. + if (FLAG_harmony_modules && (is_global_scope() || is_module_scope())) { + ASSERT(num_modules_ == 0); + AllocateModulesRecursively(this); + } + + // 3) Resolve variables. if (!ResolveVariablesRecursively(info, factory)) return false; - // 3) Allocate variables. + // 4) Allocate variables. AllocateVariablesRecursively(); - // 4) Allocate and link module instance objects. - if (FLAG_harmony_modules && (is_global_scope() || is_module_scope())) { - AllocateModules(info); - LinkModules(info); - } - return true; } @@ -702,17 +729,12 @@ bool Scope::HasTrivialOuterContext() const { bool Scope::HasLazyCompilableOuterContext() const { Scope* outer = outer_scope_; if (outer == NULL) return true; - // There are several reasons that prevent lazy compilation: - // - This scope is inside a with scope and all declaration scopes between - // them have empty contexts. Such declaration scopes become invisible - // during scope info deserialization. - // - This scope is inside a strict eval scope with variables that are - // potentially context allocated in an artificial function scope that - // is not deserialized correctly. + // We have to prevent lazy compilation if this scope is inside a with scope + // and all declaration scopes between them have empty contexts. Such + // declaration scopes may become invisible during scope info deserialization. outer = outer->DeclarationScope(); bool found_non_trivial_declarations = false; for (const Scope* scope = outer; scope != NULL; scope = scope->outer_scope_) { - if (scope->is_eval_scope()) return false; if (scope->is_with_scope() && !found_non_trivial_declarations) return false; if (scope->is_declaration_scope() && scope->num_heap_slots() > 0) { found_non_trivial_declarations = true; @@ -742,6 +764,15 @@ int Scope::ContextChainLength(Scope* scope) { } +Scope* Scope::GlobalScope() { + Scope* scope = this; + while (!scope->is_global_scope()) { + scope = scope->outer_scope(); + } + return scope; +} + + Scope* Scope::DeclarationScope() { Scope* scope = this; while (!scope->is_declaration_scope()) { @@ -915,6 +946,11 @@ void Scope::Print(int n) { PrintVar(n1, temps_[i]); } + Indent(n1, "// internal vars\n"); + for (int i = 0; i < internals_.length(); i++) { + PrintVar(n1, internals_[i]); + } + Indent(n1, "// local vars\n"); PrintMap(n1, &variables_); @@ -1065,7 +1101,6 @@ bool Scope::ResolveVariable(CompilationInfo* info, } ASSERT(var != NULL); - proxy->BindTo(var); if (FLAG_harmony_modules) { bool ok; @@ -1101,6 +1136,8 @@ bool Scope::ResolveVariable(CompilationInfo* info, } } + proxy->BindTo(var); + return true; } @@ -1175,6 +1212,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 (var->mode() == INTERNAL) return true; if (is_catch_scope() || is_block_scope() || is_module_scope()) return true; if (is_global_scope() && IsLexicalVariableMode(var->mode())) return true; return var->has_forced_context_allocation() || @@ -1281,15 +1319,17 @@ void Scope::AllocateNonParameterLocals() { AllocateNonParameterLocal(temps_[i]); } - ZoneList<VarAndOrder> vars(variables_.occupancy(), zone()); + for (int i = 0; i < internals_.length(); i++) { + AllocateNonParameterLocal(internals_[i]); + } + ZoneList<VarAndOrder> vars(variables_.occupancy(), zone()); for (VariableMap::Entry* p = variables_.Start(); p != NULL; p = variables_.Next(p)) { Variable* var = reinterpret_cast<Variable*>(p->value); vars.Add(VarAndOrder(var, p->order), zone()); } - vars.Sort(VarAndOrder::Compare); int var_count = vars.length(); for (int i = 0; i < var_count; i++) { @@ -1342,89 +1382,35 @@ void Scope::AllocateVariablesRecursively() { } -int Scope::StackLocalCount() const { - return num_stack_slots() - - (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_->proxy()->var()->IsContextSlot() ? 1 : 0); -} - - -void Scope::AllocateModules(CompilationInfo* info) { - ASSERT(is_global_scope() || is_module_scope()); - +void Scope::AllocateModulesRecursively(Scope* host_scope) { + if (already_resolved()) return; if (is_module_scope()) { ASSERT(interface_->IsFrozen()); - ASSERT(scope_info_.is_null()); - - // TODO(rossberg): This has to be the initial compilation of this code. - // We currently do not allow recompiling any module definitions. - Handle<ScopeInfo> scope_info = GetScopeInfo(); - Factory* factory = info->isolate()->factory(); - Handle<Context> context = factory->NewModuleContext(scope_info); - Handle<JSModule> instance = factory->NewJSModule(context, scope_info); - context->set_module(*instance); - - bool ok; - interface_->MakeSingleton(instance, &ok); - ASSERT(ok); + const char raw_name[] = ".module"; + Handle<String> name = isolate_->factory()->LookupSymbol( + Vector<const char>(raw_name, StrLength(raw_name))); + ASSERT(module_var_ == NULL); + module_var_ = host_scope->NewInternal(name); + ++host_scope->num_modules_; } - // Allocate nested modules. for (int i = 0; i < inner_scopes_.length(); i++) { Scope* inner_scope = inner_scopes_.at(i); - if (inner_scope->is_module_scope()) { - inner_scope->AllocateModules(info); - } + inner_scope->AllocateModulesRecursively(host_scope); } } -void Scope::LinkModules(CompilationInfo* info) { - ASSERT(is_global_scope() || is_module_scope()); +int Scope::StackLocalCount() const { + return num_stack_slots() - + (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); +} - if (is_module_scope()) { - Handle<JSModule> instance = interface_->Instance(); - - // Populate the module instance object. - const PropertyAttributes ro_attr = - static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE | DONT_ENUM); - const PropertyAttributes rw_attr = - static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM); - for (Interface::Iterator it = 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, ro_attr, kStrictMode); - } else { - Variable* var = LocalLookup(it.name()); - ASSERT(var != NULL && var->IsContextSlot()); - PropertyAttributes attr = var->is_const_mode() ? ro_attr : rw_attr; - Handle<AccessorInfo> info = - Accessors::MakeModuleExport(it.name(), var->index(), attr); - Handle<Object> result = SetAccessor(instance, info); - ASSERT(!(result.is_null() || result->IsUndefined())); - USE(result); - } - } - USE(JSObject::PreventExtensions(instance)); - } - // Link nested modules. - for (int i = 0; i < inner_scopes_.length(); i++) { - Scope* inner_scope = inner_scopes_.at(i); - if (inner_scope->is_module_scope()) { - inner_scope->LinkModules(info); - } - } +int Scope::ContextLocalCount() const { + if (num_heap_slots() == 0) return 0; + return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - + (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 6e35d05a7f..c60c2e7d49 100644 --- a/deps/v8/src/scopes.h +++ b/deps/v8/src/scopes.h @@ -186,10 +186,16 @@ class Scope: public ZoneObject { // such a variable again if it was added; otherwise this is a no-op. void RemoveUnresolved(VariableProxy* var); - // Creates a new temporary variable in this scope. The name is only used + // Creates a new internal variable in this scope. The name is only used // for printing and cannot be used to find the variable. In particular, // the only way to get hold of the temporary is by keeping the Variable* // around. + Variable* NewInternal(Handle<String> name); + + // Creates a new temporary variable in this scope. The name is only used + // for printing and cannot be used to find the variable. In particular, + // the only way to get hold of the temporary is by keeping the Variable* + // around. The name should not clash with a legitimate variable names. Variable* NewTemporary(Handle<String> name); // Adds the specific declaration node to the list of declarations in @@ -369,6 +375,12 @@ class Scope: public ZoneObject { int StackLocalCount() const; int ContextLocalCount() const; + // For global scopes, the number of module literals (including nested ones). + int num_modules() const { return num_modules_; } + + // For module scopes, the host scope's internal variable binding this module. + Variable* module_var() const { return module_var_; } + // Make sure this scope and all outer scopes are eagerly compiled. void ForceEagerCompilation() { force_eager_compilation_ = true; } @@ -387,6 +399,9 @@ class Scope: public ZoneObject { // The number of contexts between this and scope; zero if this == scope. int ContextChainLength(Scope* scope); + // Find the innermost global scope. + Scope* GlobalScope(); + // Find the first function, global, or eval scope. This is the scope // where var declarations will be hoisted to in the implementation. Scope* DeclarationScope(); @@ -441,6 +456,8 @@ class Scope: public ZoneObject { // variables may be implicitly 'declared' by being used (possibly in // an inner scope) with no intervening with statements or eval calls. VariableMap variables_; + // Compiler-allocated (user-invisible) internals. + ZoneList<Variable*> internals_; // Compiler-allocated (user-invisible) temporaries. ZoneList<Variable*> temps_; // Parameter list in source order. @@ -494,6 +511,12 @@ class Scope: public ZoneObject { int num_stack_slots_; int num_heap_slots_; + // The number of modules (including nested ones). + int num_modules_; + + // For module scopes, the host scope's internal variable binding this module. + Variable* module_var_; + // Serialized scope info support. Handle<ScopeInfo> scope_info_; bool already_resolved() { return already_resolved_; } @@ -578,6 +601,7 @@ class Scope: public ZoneObject { void AllocateNonParameterLocal(Variable* var); void AllocateNonParameterLocals(); void AllocateVariablesRecursively(); + void AllocateModulesRecursively(Scope* host_scope); // Resolve and fill in the allocation information for all variables // in this scopes. Must be called *after* all scopes have been @@ -591,13 +615,6 @@ class Scope: public ZoneObject { bool AllocateVariables(CompilationInfo* info, AstNodeFactory<AstNullVisitor>* factory); - // Instance objects have to be created ahead of time (before code generation) - // because of potentially cyclic references between them. - // Linking also has to be a separate stage, since populating one object may - // potentially require (forward) references to others. - void AllocateModules(CompilationInfo* info); - void LinkModules(CompilationInfo* info); - private: // Construct a scope based on the scope info. Scope(Scope* inner_scope, ScopeType type, Handle<ScopeInfo> scope_info, diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc index 792f25c51d..dfc55740a3 100644 --- a/deps/v8/src/serialize.cc +++ b/deps/v8/src/serialize.cc @@ -523,6 +523,10 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) { UNCLASSIFIED, 50, "pending_message_script"); + Add(ExternalReference::get_make_code_young_function(isolate).address(), + UNCLASSIFIED, + 51, + "Code::MakeCodeYoung"); } @@ -599,109 +603,34 @@ Deserializer::Deserializer(SnapshotByteSource* source) : isolate_(NULL), source_(source), external_reference_decoder_(NULL) { -} - - -// This routine both allocates a new object, and also keeps -// track of where objects have been allocated so that we can -// fix back references when deserializing. -Address Deserializer::Allocate(int space_index, Space* space, int size) { - Address address; - if (!SpaceIsLarge(space_index)) { - ASSERT(!SpaceIsPaged(space_index) || - size <= Page::kPageSize - Page::kObjectStartOffset); - MaybeObject* maybe_new_allocation; - if (space_index == NEW_SPACE) { - maybe_new_allocation = - reinterpret_cast<NewSpace*>(space)->AllocateRaw(size); - } else { - maybe_new_allocation = - reinterpret_cast<PagedSpace*>(space)->AllocateRaw(size); - } - ASSERT(!maybe_new_allocation->IsFailure()); - Object* new_allocation = maybe_new_allocation->ToObjectUnchecked(); - HeapObject* new_object = HeapObject::cast(new_allocation); - address = new_object->address(); - high_water_[space_index] = address + size; - } else { - ASSERT(SpaceIsLarge(space_index)); - LargeObjectSpace* lo_space = reinterpret_cast<LargeObjectSpace*>(space); - Object* new_allocation; - if (space_index == kLargeData || space_index == kLargeFixedArray) { - new_allocation = - lo_space->AllocateRaw(size, NOT_EXECUTABLE)->ToObjectUnchecked(); - } else { - ASSERT_EQ(kLargeCode, space_index); - new_allocation = - lo_space->AllocateRaw(size, EXECUTABLE)->ToObjectUnchecked(); - } - HeapObject* new_object = HeapObject::cast(new_allocation); - // Record all large objects in the same space. - address = new_object->address(); - pages_[LO_SPACE].Add(address); + for (int i = 0; i < LAST_SPACE + 1; i++) { + reservations_[i] = kUninitializedReservation; } - last_object_address_ = address; - return address; -} - - -// This returns the address of an object that has been described in the -// snapshot as being offset bytes back in a particular space. -HeapObject* Deserializer::GetAddressFromEnd(int space) { - int offset = source_->GetInt(); - ASSERT(!SpaceIsLarge(space)); - offset <<= kObjectAlignmentBits; - return HeapObject::FromAddress(high_water_[space] - offset); -} - - -// This returns the address of an object that has been described in the -// snapshot as being offset bytes into a particular space. -HeapObject* Deserializer::GetAddressFromStart(int space) { - int offset = source_->GetInt(); - if (SpaceIsLarge(space)) { - // Large spaces have one object per 'page'. - return HeapObject::FromAddress(pages_[LO_SPACE][offset]); - } - offset <<= kObjectAlignmentBits; - if (space == NEW_SPACE) { - // New space has only one space - numbered 0. - return HeapObject::FromAddress(pages_[space][0] + offset); - } - ASSERT(SpaceIsPaged(space)); - int page_of_pointee = offset >> kPageSizeBits; - Address object_address = pages_[space][page_of_pointee] + - (offset & Page::kPageAlignmentMask); - return HeapObject::FromAddress(object_address); } void Deserializer::Deserialize() { isolate_ = Isolate::Current(); ASSERT(isolate_ != NULL); - { - // Don't GC while deserializing - just expand the heap. - AlwaysAllocateScope always_allocate; - // Don't use the free lists while deserializing. - LinearAllocationScope allocate_linearly; - // No active threads. - ASSERT_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse()); - // No active handles. - ASSERT(isolate_->handle_scope_implementer()->blocks()->is_empty()); - ASSERT_EQ(NULL, external_reference_decoder_); - external_reference_decoder_ = new ExternalReferenceDecoder(); - isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG); - isolate_->heap()->IterateWeakRoots(this, VISIT_ALL); - - isolate_->heap()->set_native_contexts_list( - isolate_->heap()->undefined_value()); - - // Update data pointers to the external strings containing natives sources. - for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { - Object* source = isolate_->heap()->natives_source_cache()->get(i); - if (!source->IsUndefined()) { - ExternalAsciiString::cast(source)->update_data_cache(); - } + isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]); + // No active threads. + ASSERT_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse()); + // No active handles. + ASSERT(isolate_->handle_scope_implementer()->blocks()->is_empty()); + ASSERT_EQ(NULL, external_reference_decoder_); + external_reference_decoder_ = new ExternalReferenceDecoder(); + isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG); + isolate_->heap()->RepairFreeListsAfterBoot(); + isolate_->heap()->IterateWeakRoots(this, VISIT_ALL); + + isolate_->heap()->set_native_contexts_list( + isolate_->heap()->undefined_value()); + + // Update data pointers to the external strings containing natives sources. + for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { + Object* source = isolate_->heap()->natives_source_cache()->get(i); + if (!source->IsUndefined()) { + ExternalAsciiString::cast(source)->update_data_cache(); } } @@ -713,10 +642,10 @@ void Deserializer::Deserialize() { void Deserializer::DeserializePartial(Object** root) { isolate_ = Isolate::Current(); - // Don't GC while deserializing - just expand the heap. - AlwaysAllocateScope always_allocate; - // Don't use the free lists while deserializing. - LinearAllocationScope allocate_linearly; + for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) { + ASSERT(reservations_[i] != kUninitializedReservation); + } + isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]); if (external_reference_decoder_ == NULL) { external_reference_decoder_ = new ExternalReferenceDecoder(); } @@ -758,10 +687,9 @@ void Deserializer::VisitPointers(Object** start, Object** end) { // written very late, which means the FreeSpace map is not set up by the // time we need to use it to mark the space at the end of a page free. void Deserializer::ReadObject(int space_number, - Space* space, Object** write_back) { int size = source_->GetInt() << kObjectAlignmentBits; - Address address = Allocate(space_number, space, size); + Address address = Allocate(space_number, size); *write_back = HeapObject::FromAddress(address); Object** current = reinterpret_cast<Object**>(address); Object** limit = current + (size >> kPointerSizeLog2); @@ -770,44 +698,19 @@ void Deserializer::ReadObject(int space_number, } ReadChunk(current, limit, space_number, address); #ifdef DEBUG - bool is_codespace = (space == HEAP->code_space()) || - ((space == HEAP->lo_space()) && (space_number == kLargeCode)); + bool is_codespace = (space_number == CODE_SPACE); ASSERT(HeapObject::FromAddress(address)->IsCode() == is_codespace); #endif } - -// This macro is always used with a constant argument so it should all fold -// away to almost nothing in the generated code. It might be nicer to do this -// with the ternary operator but there are type issues with that. -#define ASSIGN_DEST_SPACE(space_number) \ - Space* dest_space; \ - if (space_number == NEW_SPACE) { \ - dest_space = isolate->heap()->new_space(); \ - } else if (space_number == OLD_POINTER_SPACE) { \ - dest_space = isolate->heap()->old_pointer_space(); \ - } else if (space_number == OLD_DATA_SPACE) { \ - dest_space = isolate->heap()->old_data_space(); \ - } else if (space_number == CODE_SPACE) { \ - dest_space = isolate->heap()->code_space(); \ - } else if (space_number == MAP_SPACE) { \ - dest_space = isolate->heap()->map_space(); \ - } else if (space_number == CELL_SPACE) { \ - dest_space = isolate->heap()->cell_space(); \ - } else { \ - ASSERT(space_number >= LO_SPACE); \ - dest_space = isolate->heap()->lo_space(); \ - } - - -static const int kUnknownOffsetFromStart = -1; - - void Deserializer::ReadChunk(Object** current, Object** limit, int source_space, Address current_object_address) { Isolate* const isolate = isolate_; + // Write barrier support costs around 1% in startup time. In fact there + // are no new space objects in current boot snapshots, so it's not needed, + // but that may change. bool write_barrier_needed = (current_object_address != NULL && source_space != NEW_SPACE && source_space != CELL_SPACE && @@ -823,21 +726,19 @@ void Deserializer::ReadChunk(Object** current, ASSERT((within & ~kWhereToPointMask) == 0); \ ASSERT((space_number & ~kSpaceMask) == 0); -#define CASE_BODY(where, how, within, space_number_if_any, offset_from_start) \ +#define CASE_BODY(where, how, within, space_number_if_any) \ { \ bool emit_write_barrier = false; \ bool current_was_incremented = false; \ int space_number = space_number_if_any == kAnyOldSpace ? \ (data & kSpaceMask) : space_number_if_any; \ if (where == kNewObject && how == kPlain && within == kStartOfObject) {\ - ASSIGN_DEST_SPACE(space_number) \ - ReadObject(space_number, dest_space, current); \ + ReadObject(space_number, current); \ emit_write_barrier = (space_number == NEW_SPACE); \ } else { \ Object* new_object = NULL; /* May not be a real Object pointer. */ \ if (where == kNewObject) { \ - ASSIGN_DEST_SPACE(space_number) \ - ReadObject(space_number, dest_space, &new_object); \ + ReadObject(space_number, &new_object); \ } else if (where == kRootArray) { \ int root_id = source_->GetInt(); \ new_object = isolate->heap()->roots_array_start()[root_id]; \ @@ -848,6 +749,9 @@ void Deserializer::ReadChunk(Object** current, [cache_index]; \ emit_write_barrier = isolate->heap()->InNewSpace(new_object); \ } else if (where == kExternalReference) { \ + int skip = source_->GetInt(); \ + current = reinterpret_cast<Object**>(reinterpret_cast<Address>( \ + current) + skip); \ int reference_id = source_->GetInt(); \ Address address = external_reference_decoder_-> \ Decode(reference_id); \ @@ -856,15 +760,12 @@ void Deserializer::ReadChunk(Object** current, emit_write_barrier = (space_number == NEW_SPACE); \ new_object = GetAddressFromEnd(data & kSpaceMask); \ } else { \ - ASSERT(where == kFromStart); \ - if (offset_from_start == kUnknownOffsetFromStart) { \ - emit_write_barrier = (space_number == NEW_SPACE); \ - new_object = GetAddressFromStart(data & kSpaceMask); \ - } else { \ - Address object_address = pages_[space_number][0] + \ - (offset_from_start << kObjectAlignmentBits); \ - new_object = HeapObject::FromAddress(object_address); \ - } \ + ASSERT(where == kBackrefWithSkip); \ + int skip = source_->GetInt(); \ + current = reinterpret_cast<Object**>( \ + reinterpret_cast<Address>(current) + skip); \ + emit_write_barrier = (space_number == NEW_SPACE); \ + new_object = GetAddressFromEnd(data & kSpaceMask); \ } \ if (within == kInnerPointer) { \ if (space_number != CODE_SPACE || new_object->IsCode()) { \ @@ -872,7 +773,7 @@ void Deserializer::ReadChunk(Object** current, new_object = reinterpret_cast<Object*>( \ new_code_object->instruction_start()); \ } else { \ - ASSERT(space_number == CODE_SPACE || space_number == kLargeCode);\ + ASSERT(space_number == CODE_SPACE); \ JSGlobalPropertyCell* cell = \ JSGlobalPropertyCell::cast(new_object); \ new_object = reinterpret_cast<Object*>( \ @@ -904,47 +805,18 @@ void Deserializer::ReadChunk(Object** current, break; \ } \ -// This generates a case and a body for each space. The large object spaces are -// very rare in snapshots so they are grouped in one body. -#define ONE_PER_SPACE(where, how, within) \ - CASE_STATEMENT(where, how, within, NEW_SPACE) \ - CASE_BODY(where, how, within, NEW_SPACE, kUnknownOffsetFromStart) \ - CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \ - CASE_BODY(where, how, within, OLD_DATA_SPACE, kUnknownOffsetFromStart) \ - CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \ - CASE_BODY(where, how, within, OLD_POINTER_SPACE, kUnknownOffsetFromStart) \ - CASE_STATEMENT(where, how, within, CODE_SPACE) \ - CASE_BODY(where, how, within, CODE_SPACE, kUnknownOffsetFromStart) \ - CASE_STATEMENT(where, how, within, CELL_SPACE) \ - CASE_BODY(where, how, within, CELL_SPACE, kUnknownOffsetFromStart) \ - CASE_STATEMENT(where, how, within, MAP_SPACE) \ - CASE_BODY(where, how, within, MAP_SPACE, kUnknownOffsetFromStart) \ - CASE_STATEMENT(where, how, within, kLargeData) \ - CASE_STATEMENT(where, how, within, kLargeCode) \ - CASE_STATEMENT(where, how, within, kLargeFixedArray) \ - CASE_BODY(where, how, within, kAnyOldSpace, kUnknownOffsetFromStart) - // This generates a case and a body for the new space (which has to do extra // write barrier handling) and handles the other spaces with 8 fall-through // cases and one body. #define ALL_SPACES(where, how, within) \ CASE_STATEMENT(where, how, within, NEW_SPACE) \ - CASE_BODY(where, how, within, NEW_SPACE, kUnknownOffsetFromStart) \ + CASE_BODY(where, how, within, NEW_SPACE) \ CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \ CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \ CASE_STATEMENT(where, how, within, CODE_SPACE) \ CASE_STATEMENT(where, how, within, CELL_SPACE) \ CASE_STATEMENT(where, how, within, MAP_SPACE) \ - CASE_STATEMENT(where, how, within, kLargeData) \ - CASE_STATEMENT(where, how, within, kLargeCode) \ - CASE_STATEMENT(where, how, within, kLargeFixedArray) \ - CASE_BODY(where, how, within, kAnyOldSpace, kUnknownOffsetFromStart) - -#define ONE_PER_CODE_SPACE(where, how, within) \ - CASE_STATEMENT(where, how, within, CODE_SPACE) \ - CASE_BODY(where, how, within, CODE_SPACE, kUnknownOffsetFromStart) \ - CASE_STATEMENT(where, how, within, kLargeCode) \ - CASE_BODY(where, how, within, kLargeCode, kUnknownOffsetFromStart) + CASE_BODY(where, how, within, kAnyOldSpace) #define FOUR_CASES(byte_code) \ case byte_code: \ @@ -958,14 +830,48 @@ void Deserializer::ReadChunk(Object** current, FOUR_CASES(byte_code + 8) \ FOUR_CASES(byte_code + 12) +#define COMMON_RAW_LENGTHS(f) \ + f(1) \ + f(2) \ + f(3) \ + f(4) \ + f(5) \ + f(6) \ + f(7) \ + f(8) \ + f(9) \ + f(10) \ + f(11) \ + f(12) \ + f(13) \ + f(14) \ + f(15) \ + f(16) \ + f(17) \ + f(18) \ + f(19) \ + f(20) \ + f(21) \ + f(22) \ + f(23) \ + f(24) \ + f(25) \ + f(26) \ + f(27) \ + f(28) \ + f(29) \ + f(30) \ + f(31) + // We generate 15 cases and bodies that process special tags that combine // the raw data tag and the length into one byte. -#define RAW_CASE(index, size) \ - case kRawData + index: { \ - byte* raw_data_out = reinterpret_cast<byte*>(current); \ - source_->CopyRaw(raw_data_out, size); \ - current = reinterpret_cast<Object**>(raw_data_out + size); \ - break; \ +#define RAW_CASE(index) \ + case kRawData + index: { \ + byte* raw_data_out = reinterpret_cast<byte*>(current); \ + source_->CopyRaw(raw_data_out, index * kPointerSize); \ + current = \ + reinterpret_cast<Object**>(raw_data_out + index * kPointerSize); \ + break; \ } COMMON_RAW_LENGTHS(RAW_CASE) #undef RAW_CASE @@ -976,13 +882,24 @@ void Deserializer::ReadChunk(Object** current, int size = source_->GetInt(); byte* raw_data_out = reinterpret_cast<byte*>(current); source_->CopyRaw(raw_data_out, size); - current = reinterpret_cast<Object**>(raw_data_out + size); break; } - SIXTEEN_CASES(kRootArrayLowConstants) - SIXTEEN_CASES(kRootArrayHighConstants) { + SIXTEEN_CASES(kRootArrayConstants + kNoSkipDistance) + SIXTEEN_CASES(kRootArrayConstants + kNoSkipDistance + 16) { + int root_id = RootArrayConstantFromByteCode(data); + Object* object = isolate->heap()->roots_array_start()[root_id]; + ASSERT(!isolate->heap()->InNewSpace(object)); + *current++ = object; + break; + } + + SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance) + SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance + 16) { int root_id = RootArrayConstantFromByteCode(data); + int skip = source_->GetInt(); + current = reinterpret_cast<Object**>( + reinterpret_cast<intptr_t>(current) + skip); Object* object = isolate->heap()->roots_array_start()[root_id]; ASSERT(!isolate->heap()->InNewSpace(object)); *current++ = object; @@ -1000,10 +917,11 @@ void Deserializer::ReadChunk(Object** current, STATIC_ASSERT(kRootArrayNumberOfConstantEncodings == Heap::kOldSpaceRoots); - STATIC_ASSERT(kMaxRepeats == 12); - FOUR_CASES(kConstantRepeat) - FOUR_CASES(kConstantRepeat + 4) - FOUR_CASES(kConstantRepeat + 8) { + STATIC_ASSERT(kMaxRepeats == 13); + case kConstantRepeat: + FOUR_CASES(kConstantRepeat + 1) + FOUR_CASES(kConstantRepeat + 5) + FOUR_CASES(kConstantRepeat + 9) { int repeats = RepeatsForCode(data); Object* object = current[-1]; ASSERT(!isolate->heap()->InNewSpace(object)); @@ -1014,100 +932,80 @@ void Deserializer::ReadChunk(Object** current, // Deserialize a new object and write a pointer to it to the current // object. - ONE_PER_SPACE(kNewObject, kPlain, kStartOfObject) + ALL_SPACES(kNewObject, kPlain, kStartOfObject) // Support for direct instruction pointers in functions. It's an inner // pointer because it points at the entry point, not at the start of the // code object. - ONE_PER_CODE_SPACE(kNewObject, kPlain, kInnerPointer) + CASE_STATEMENT(kNewObject, kPlain, kInnerPointer, CODE_SPACE) + CASE_BODY(kNewObject, kPlain, kInnerPointer, CODE_SPACE) // Deserialize a new code object and write a pointer to its first // instruction to the current code object. - ONE_PER_SPACE(kNewObject, kFromCode, kInnerPointer) + ALL_SPACES(kNewObject, kFromCode, kInnerPointer) // Find a recently deserialized object using its offset from the current // allocation point and write a pointer to it to the current object. ALL_SPACES(kBackref, kPlain, kStartOfObject) + ALL_SPACES(kBackrefWithSkip, kPlain, kStartOfObject) #if V8_TARGET_ARCH_MIPS // Deserialize a new object from pointer found in code and write // a pointer to it to the current object. Required only for MIPS, and // omitted on the other architectures because it is fully unrolled and // would cause bloat. - ONE_PER_SPACE(kNewObject, kFromCode, kStartOfObject) + ALL_SPACES(kNewObject, kFromCode, kStartOfObject) // Find a recently deserialized code object using its offset from the // current allocation point and write a pointer to it to the current // object. Required only for MIPS. ALL_SPACES(kBackref, kFromCode, kStartOfObject) - // Find an already deserialized code object using its offset from - // the start and write a pointer to it to the current object. - // Required only for MIPS. - ALL_SPACES(kFromStart, kFromCode, kStartOfObject) + ALL_SPACES(kBackrefWithSkip, kFromCode, kStartOfObject) #endif // Find a recently deserialized code object using its offset from the // current allocation point and write a pointer to its first instruction // to the current code object or the instruction pointer in a function // object. ALL_SPACES(kBackref, kFromCode, kInnerPointer) + ALL_SPACES(kBackrefWithSkip, kFromCode, kInnerPointer) ALL_SPACES(kBackref, kPlain, kInnerPointer) - // Find an already deserialized object using its offset from the start - // and write a pointer to it to the current object. - ALL_SPACES(kFromStart, kPlain, kStartOfObject) - ALL_SPACES(kFromStart, kPlain, kInnerPointer) - // Find an already deserialized code object using its offset from the - // start and write a pointer to its first instruction to the current code - // object. - ALL_SPACES(kFromStart, kFromCode, kInnerPointer) + ALL_SPACES(kBackrefWithSkip, kPlain, kInnerPointer) // Find an object in the roots array and write a pointer to it to the // current object. CASE_STATEMENT(kRootArray, kPlain, kStartOfObject, 0) - CASE_BODY(kRootArray, kPlain, kStartOfObject, 0, kUnknownOffsetFromStart) + CASE_BODY(kRootArray, kPlain, kStartOfObject, 0) // Find an object in the partial snapshots cache and write a pointer to it // to the current object. CASE_STATEMENT(kPartialSnapshotCache, kPlain, kStartOfObject, 0) CASE_BODY(kPartialSnapshotCache, kPlain, kStartOfObject, - 0, - kUnknownOffsetFromStart) + 0) // Find an code entry in the partial snapshots cache and // write a pointer to it to the current object. CASE_STATEMENT(kPartialSnapshotCache, kPlain, kInnerPointer, 0) CASE_BODY(kPartialSnapshotCache, kPlain, kInnerPointer, - 0, - kUnknownOffsetFromStart) + 0) // Find an external reference and write a pointer to it to the current // object. CASE_STATEMENT(kExternalReference, kPlain, kStartOfObject, 0) CASE_BODY(kExternalReference, kPlain, kStartOfObject, - 0, - kUnknownOffsetFromStart) + 0) // Find an external reference and write a pointer to it in the current // code object. CASE_STATEMENT(kExternalReference, kFromCode, kStartOfObject, 0) CASE_BODY(kExternalReference, kFromCode, kStartOfObject, - 0, - kUnknownOffsetFromStart) + 0) #undef CASE_STATEMENT #undef CASE_BODY -#undef ONE_PER_SPACE #undef ALL_SPACES -#undef ASSIGN_DEST_SPACE - - case kNewPage: { - int space = source_->Get(); - pages_[space].Add(last_object_address_); - if (space == CODE_SPACE) { - CPU::FlushICache(last_object_address_, Page::kPageSize); - } - break; - } case kSkip: { - current++; + int size = source_->GetInt(); + current = reinterpret_cast<Object**>( + reinterpret_cast<intptr_t>(current) + size); break; } @@ -1132,18 +1030,20 @@ void Deserializer::ReadChunk(Object** current, UNREACHABLE(); } } - ASSERT_EQ(current, limit); + ASSERT_EQ(limit, current); } void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) { - const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7; - for (int shift = max_shift; shift > 0; shift -= 7) { - if (integer >= static_cast<uintptr_t>(1u) << shift) { - Put((static_cast<int>((integer >> shift)) & 0x7f) | 0x80, "IntPart"); - } - } - PutSection(static_cast<int>(integer & 0x7f), "IntLastPart"); + ASSERT(integer < 1 << 22); + integer <<= 2; + int bytes = 1; + if (integer > 0xff) bytes = 2; + if (integer > 0xffff) bytes = 3; + integer |= bytes; + Put(static_cast<int>(integer & 0xff), "IntPart1"); + if (bytes > 1) Put(static_cast<int>((integer >> 8) & 0xff), "IntPart2"); + if (bytes > 2) Put(static_cast<int>((integer >> 16) & 0xff), "IntPart3"); } @@ -1151,7 +1051,6 @@ Serializer::Serializer(SnapshotByteSink* sink) : sink_(sink), current_root_index_(0), external_reference_encoder_(new ExternalReferenceEncoder), - large_object_total_(0), root_index_wave_front_(0) { isolate_ = Isolate::Current(); // The serializer is meant to be used only to generate initial heap images @@ -1184,6 +1083,7 @@ void StartupSerializer::SerializeStrongReferences() { void PartialSerializer::Serialize(Object** object) { this->VisitPointer(object); + Pad(); } @@ -1198,14 +1098,14 @@ void Serializer::VisitPointers(Object** start, Object** end) { if (reinterpret_cast<Address>(current) == isolate->heap()->store_buffer()->TopAddress()) { sink_->Put(kSkip, "Skip"); + sink_->PutInt(kPointerSize, "SkipOneWord"); } else if ((*current)->IsSmi()) { - sink_->Put(kRawData, "RawData"); - sink_->PutInt(kPointerSize, "length"); + sink_->Put(kRawData + 1, "Smi"); for (int i = 0; i < kPointerSize; i++) { sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte"); } } else { - SerializeObject(*current, kPlain, kStartOfObject); + SerializeObject(*current, kPlain, kStartOfObject, 0); } } } @@ -1292,58 +1192,50 @@ void Serializer::SerializeReferenceToPreviousObject( int space, int address, HowToCode how_to_code, - WhereToPoint where_to_point) { + WhereToPoint where_to_point, + int skip) { int offset = CurrentAllocationAddress(space) - address; - bool from_start = true; - if (SpaceIsPaged(space)) { - // For paged space it is simple to encode back from current allocation if - // the object is on the same page as the current allocation pointer. - if ((CurrentAllocationAddress(space) >> kPageSizeBits) == - (address >> kPageSizeBits)) { - from_start = false; - address = offset; - } - } else if (space == NEW_SPACE) { - // For new space it is always simple to encode back from current allocation. - if (offset < address) { - from_start = false; - address = offset; - } - } - // If we are actually dealing with real offsets (and not a numbering of - // all objects) then we should shift out the bits that are always 0. - if (!SpaceIsLarge(space)) address >>= kObjectAlignmentBits; - if (from_start) { - sink_->Put(kFromStart + how_to_code + where_to_point + space, "RefSer"); - sink_->PutInt(address, "address"); - } else { + // Shift out the bits that are always 0. + offset >>= kObjectAlignmentBits; + if (skip == 0) { sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer"); - sink_->PutInt(address, "address"); + } else { + sink_->Put(kBackrefWithSkip + how_to_code + where_to_point + space, + "BackRefSerWithSkip"); + sink_->PutInt(skip, "BackRefSkipDistance"); } + sink_->PutInt(offset, "offset"); } void StartupSerializer::SerializeObject( Object* o, HowToCode how_to_code, - WhereToPoint where_to_point) { + WhereToPoint where_to_point, + int skip) { CHECK(o->IsHeapObject()); HeapObject* heap_object = HeapObject::cast(o); int root_index; if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) { - PutRoot(root_index, heap_object, how_to_code, where_to_point); + PutRoot(root_index, heap_object, how_to_code, where_to_point, skip); return; } if (address_mapper_.IsMapped(heap_object)) { - int space = SpaceOfAlreadySerializedObject(heap_object); + int space = SpaceOfObject(heap_object); int address = address_mapper_.MappedTo(heap_object); SerializeReferenceToPreviousObject(space, address, how_to_code, - where_to_point); + where_to_point, + skip); } else { + if (skip != 0) { + sink_->Put(kSkip, "FlushPendingSkip"); + sink_->PutInt(skip, "SkipDistance"); + } + // Object has not yet been serialized. Serialize it here. ObjectSerializer object_serializer(this, heap_object, @@ -1365,25 +1257,32 @@ void StartupSerializer::SerializeWeakReferences() { Object* undefined = isolate->heap()->undefined_value(); VisitPointer(&undefined); HEAP->IterateWeakRoots(this, VISIT_ALL); + Pad(); } void Serializer::PutRoot(int root_index, HeapObject* object, SerializerDeserializer::HowToCode how_to_code, - SerializerDeserializer::WhereToPoint where_to_point) { + SerializerDeserializer::WhereToPoint where_to_point, + int skip) { if (how_to_code == kPlain && where_to_point == kStartOfObject && root_index < kRootArrayNumberOfConstantEncodings && !HEAP->InNewSpace(object)) { - if (root_index < kRootArrayNumberOfLowConstantEncodings) { - sink_->Put(kRootArrayLowConstants + root_index, "RootLoConstant"); + if (skip == 0) { + sink_->Put(kRootArrayConstants + kNoSkipDistance + root_index, + "RootConstant"); } else { - sink_->Put(kRootArrayHighConstants + root_index - - kRootArrayNumberOfLowConstantEncodings, - "RootHiConstant"); + sink_->Put(kRootArrayConstants + kHasSkipDistance + root_index, + "RootConstant"); + sink_->PutInt(skip, "SkipInPutRoot"); } } else { + if (skip != 0) { + sink_->Put(kSkip, "SkipFromPutRoot"); + sink_->PutInt(skip, "SkipFromPutRootDistance"); + } sink_->Put(kRootArray + how_to_code + where_to_point, "RootSerialization"); sink_->PutInt(root_index, "root_index"); } @@ -1393,7 +1292,8 @@ void Serializer::PutRoot(int root_index, void PartialSerializer::SerializeObject( Object* o, HowToCode how_to_code, - WhereToPoint where_to_point) { + WhereToPoint where_to_point, + int skip) { CHECK(o->IsHeapObject()); HeapObject* heap_object = HeapObject::cast(o); @@ -1401,16 +1301,21 @@ void PartialSerializer::SerializeObject( // The code-caches link to context-specific code objects, which // the startup and context serializes cannot currently handle. ASSERT(Map::cast(heap_object)->code_cache() == - heap_object->GetHeap()->raw_unchecked_empty_fixed_array()); + heap_object->GetHeap()->empty_fixed_array()); } int root_index; if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) { - PutRoot(root_index, heap_object, how_to_code, where_to_point); + PutRoot(root_index, heap_object, how_to_code, where_to_point, skip); return; } if (ShouldBeInThePartialSnapshotCache(heap_object)) { + if (skip != 0) { + sink_->Put(kSkip, "SkipFromSerializeObject"); + sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); + } + int cache_index = PartialSnapshotCacheIndex(heap_object); sink_->Put(kPartialSnapshotCache + how_to_code + where_to_point, "PartialSnapshotCache"); @@ -1427,13 +1332,18 @@ void PartialSerializer::SerializeObject( ASSERT(!heap_object->IsSymbol()); if (address_mapper_.IsMapped(heap_object)) { - int space = SpaceOfAlreadySerializedObject(heap_object); + int space = SpaceOfObject(heap_object); int address = address_mapper_.MappedTo(heap_object); SerializeReferenceToPreviousObject(space, address, how_to_code, - where_to_point); + where_to_point, + skip); } else { + if (skip != 0) { + sink_->Put(kSkip, "SkipFromSerializeObject"); + sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); + } // Object has not yet been serialized. Serialize it here. ObjectSerializer serializer(this, heap_object, @@ -1457,16 +1367,11 @@ void Serializer::ObjectSerializer::Serialize() { SnapshotPositionEvent(object_->address(), sink_->Position())); // Mark this object as already serialized. - bool start_new_page; - int offset = serializer_->Allocate(space, size, &start_new_page); + int offset = serializer_->Allocate(space, size); serializer_->address_mapper()->AddMapping(object_, offset); - if (start_new_page) { - sink_->Put(kNewPage, "NewPage"); - sink_->PutSection(space, "NewPageSpace"); - } // Serialize the map (first word of the object). - serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject); + serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject, 0); // Serialize the rest of the object. CHECK_EQ(0, bytes_processed_so_far_); @@ -1507,7 +1412,8 @@ void Serializer::ObjectSerializer::VisitPointers(Object** start, sink_->Put(CodeForRepeats(repeat_count), "SerializeRepeats"); } } else { - serializer_->SerializeObject(current_contents, kPlain, kStartOfObject); + serializer_->SerializeObject( + current_contents, kPlain, kStartOfObject, 0); bytes_processed_so_far_ += kPointerSize; current++; } @@ -1519,9 +1425,10 @@ void Serializer::ObjectSerializer::VisitPointers(Object** start, void Serializer::ObjectSerializer::VisitEmbeddedPointer(RelocInfo* rinfo) { Object** current = rinfo->target_object_address(); - OutputRawData(rinfo->target_address_address()); + int skip = OutputRawData(rinfo->target_address_address(), + kCanReturnSkipInsteadOfSkipping); HowToCode representation = rinfo->IsCodedSpecially() ? kFromCode : kPlain; - serializer_->SerializeObject(*current, representation, kStartOfObject); + serializer_->SerializeObject(*current, representation, kStartOfObject, skip); bytes_processed_so_far_ += rinfo->target_address_size(); } @@ -1529,10 +1436,12 @@ void Serializer::ObjectSerializer::VisitEmbeddedPointer(RelocInfo* rinfo) { void Serializer::ObjectSerializer::VisitExternalReferences(Address* start, Address* end) { Address references_start = reinterpret_cast<Address>(start); - OutputRawData(references_start); + int skip = OutputRawData(references_start, kCanReturnSkipInsteadOfSkipping); for (Address* current = start; current < end; current++) { sink_->Put(kExternalReference + kPlain + kStartOfObject, "ExternalRef"); + sink_->PutInt(skip, "SkipB4ExternalRef"); + skip = 0; int reference_id = serializer_->EncodeExternalReference(*current); sink_->PutInt(reference_id, "reference id"); } @@ -1542,12 +1451,13 @@ void Serializer::ObjectSerializer::VisitExternalReferences(Address* start, void Serializer::ObjectSerializer::VisitExternalReference(RelocInfo* rinfo) { Address references_start = rinfo->target_address_address(); - OutputRawData(references_start); + int skip = OutputRawData(references_start, kCanReturnSkipInsteadOfSkipping); Address* current = rinfo->target_reference_address(); int representation = rinfo->IsCodedSpecially() ? kFromCode + kStartOfObject : kPlain + kStartOfObject; sink_->Put(kExternalReference + representation, "ExternalRef"); + sink_->PutInt(skip, "SkipB4ExternalRef"); int reference_id = serializer_->EncodeExternalReference(*current); sink_->PutInt(reference_id, "reference id"); bytes_processed_so_far_ += rinfo->target_address_size(); @@ -1556,7 +1466,7 @@ void Serializer::ObjectSerializer::VisitExternalReference(RelocInfo* rinfo) { void Serializer::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) { Address target_start = rinfo->target_address_address(); - OutputRawData(target_start); + int skip = OutputRawData(target_start, kCanReturnSkipInsteadOfSkipping); Address target = rinfo->target_address(); uint32_t encoding = serializer_->EncodeExternalReference(target); CHECK(target == NULL ? encoding == 0 : encoding != 0); @@ -1568,6 +1478,7 @@ void Serializer::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) { representation = kStartOfObject + kPlain; } sink_->Put(kExternalReference + representation, "ExternalReference"); + sink_->PutInt(skip, "SkipB4ExternalRef"); sink_->PutInt(encoding, "reference id"); bytes_processed_so_far_ += rinfo->target_address_size(); } @@ -1576,17 +1487,17 @@ void Serializer::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) { void Serializer::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) { CHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); Address target_start = rinfo->target_address_address(); - OutputRawData(target_start); + int skip = OutputRawData(target_start, kCanReturnSkipInsteadOfSkipping); Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); - serializer_->SerializeObject(target, kFromCode, kInnerPointer); + serializer_->SerializeObject(target, kFromCode, kInnerPointer, skip); bytes_processed_so_far_ += rinfo->target_address_size(); } void Serializer::ObjectSerializer::VisitCodeEntry(Address entry_address) { Code* target = Code::cast(Code::GetObjectFromEntryAddress(entry_address)); - OutputRawData(entry_address); - serializer_->SerializeObject(target, kPlain, kInnerPointer); + int skip = OutputRawData(entry_address, kCanReturnSkipInsteadOfSkipping); + serializer_->SerializeObject(target, kPlain, kInnerPointer, skip); bytes_processed_so_far_ += kPointerSize; } @@ -1595,8 +1506,8 @@ void Serializer::ObjectSerializer::VisitGlobalPropertyCell(RelocInfo* rinfo) { ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL); JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(rinfo->target_cell()); - OutputRawData(rinfo->pc()); - serializer_->SerializeObject(cell, kPlain, kInnerPointer); + int skip = OutputRawData(rinfo->pc(), kCanReturnSkipInsteadOfSkipping); + serializer_->SerializeObject(cell, kPlain, kInnerPointer, skip); } @@ -1624,59 +1535,58 @@ void Serializer::ObjectSerializer::VisitExternalAsciiString( } -void Serializer::ObjectSerializer::OutputRawData(Address up_to) { +int Serializer::ObjectSerializer::OutputRawData( + Address up_to, Serializer::ObjectSerializer::ReturnSkip return_skip) { Address object_start = object_->address(); + Address base = object_start + bytes_processed_so_far_; int up_to_offset = static_cast<int>(up_to - object_start); - int skipped = up_to_offset - bytes_processed_so_far_; + int to_skip = up_to_offset - bytes_processed_so_far_; + int bytes_to_output = to_skip; + bytes_processed_so_far_ += to_skip; // This assert will fail if the reloc info gives us the target_address_address // locations in a non-ascending order. Luckily that doesn't happen. - ASSERT(skipped >= 0); - if (skipped != 0) { - Address base = object_start + bytes_processed_so_far_; -#define RAW_CASE(index, length) \ - if (skipped == length) { \ + ASSERT(to_skip >= 0); + bool outputting_code = false; + if (to_skip != 0 && code_object_ && !code_has_been_output_) { + // Output the code all at once and fix later. + bytes_to_output = object_->Size() + to_skip - bytes_processed_so_far_; + outputting_code = true; + code_has_been_output_ = true; + } + if (bytes_to_output != 0 && + (!code_object_ || outputting_code)) { +#define RAW_CASE(index) \ + if (!outputting_code && bytes_to_output == index * kPointerSize && \ + index * kPointerSize == to_skip) { \ sink_->PutSection(kRawData + index, "RawDataFixed"); \ + to_skip = 0; /* This insn already skips. */ \ } else /* NOLINT */ COMMON_RAW_LENGTHS(RAW_CASE) #undef RAW_CASE { /* NOLINT */ + // We always end up here if we are outputting the code of a code object. sink_->Put(kRawData, "RawData"); - sink_->PutInt(skipped, "length"); + sink_->PutInt(bytes_to_output, "length"); } - for (int i = 0; i < skipped; i++) { + for (int i = 0; i < bytes_to_output; i++) { unsigned int data = base[i]; sink_->PutSection(data, "Byte"); } - bytes_processed_so_far_ += skipped; } -} - - -int Serializer::SpaceOfObject(HeapObject* object) { - for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) { - AllocationSpace s = static_cast<AllocationSpace>(i); - if (HEAP->InSpace(object, s)) { - if (i == LO_SPACE) { - if (object->IsCode()) { - return kLargeCode; - } else if (object->IsFixedArray()) { - return kLargeFixedArray; - } else { - return kLargeData; - } - } - return i; - } + if (to_skip != 0 && return_skip == kIgnoringReturn) { + sink_->Put(kSkip, "Skip"); + sink_->PutInt(to_skip, "SkipDistance"); + to_skip = 0; } - UNREACHABLE(); - return 0; + return to_skip; } -int Serializer::SpaceOfAlreadySerializedObject(HeapObject* object) { +int Serializer::SpaceOfObject(HeapObject* object) { for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) { AllocationSpace s = static_cast<AllocationSpace>(i); if (HEAP->InSpace(object, s)) { + ASSERT(i < kNumberOfSpaces); return i; } } @@ -1685,34 +1595,8 @@ int Serializer::SpaceOfAlreadySerializedObject(HeapObject* object) { } -int Serializer::Allocate(int space, int size, bool* new_page) { +int Serializer::Allocate(int space, int size) { CHECK(space >= 0 && space < kNumberOfSpaces); - if (SpaceIsLarge(space)) { - // In large object space we merely number the objects instead of trying to - // determine some sort of address. - *new_page = true; - large_object_total_ += size; - return fullness_[LO_SPACE]++; - } - *new_page = false; - if (fullness_[space] == 0) { - *new_page = true; - } - if (SpaceIsPaged(space)) { - // Paged spaces are a little special. We encode their addresses as if the - // pages were all contiguous and each page were filled up in the range - // 0 - Page::kObjectAreaSize. In practice the pages may not be contiguous - // and allocation does not start at offset 0 in the page, but this scheme - // means the deserializer can get the page number quickly by shifting the - // serialized address. - CHECK(IsPowerOf2(Page::kPageSize)); - int used_in_this_page = (fullness_[space] & (Page::kPageSize - 1)); - CHECK(size <= SpaceAreaSize(space)); - if (used_in_this_page + size > SpaceAreaSize(space)) { - *new_page = true; - fullness_[space] = RoundUp(fullness_[space], Page::kPageSize); - } - } int allocation_address = fullness_[space]; fullness_[space] = allocation_address + size; return allocation_address; @@ -1728,4 +1612,21 @@ int Serializer::SpaceAreaSize(int space) { } +void Serializer::Pad() { + // The non-branching GetInt will read up to 3 bytes too far, so we need + // to pad the snapshot to make sure we don't read over the end. + for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) { + sink_->Put(kNop, "Padding"); + } +} + + +bool SnapshotByteSource::AtEOF() { + if (0u + length_ - position_ > 2 * sizeof(uint32_t)) return false; + for (int x = position_; x < length_; x++) { + if (data_[x] != SerializerDeserializer::nop()) return false; + } + return true; +} + } } // namespace v8::internal diff --git a/deps/v8/src/serialize.h b/deps/v8/src/serialize.h index 8beb88e8b2..2041792856 100644 --- a/deps/v8/src/serialize.h +++ b/deps/v8/src/serialize.h @@ -170,13 +170,27 @@ class SnapshotByteSource { return data_[position_++]; } + int32_t GetUnalignedInt() { +#if defined(V8_HOST_CAN_READ_UNALIGNED) && __BYTE_ORDER == __LITTLE_ENDIAN + int32_t answer; + ASSERT(position_ + sizeof(answer) <= length_ + 0u); + answer = *reinterpret_cast<const int32_t*>(data_ + position_); +#else + int32_t answer = data_[position_]; + answer |= data_[position_ + 1] << 8; + answer |= data_[position_ + 2] << 16; + answer |= data_[position_ + 3] << 24; +#endif + return answer; + } + + void Advance(int by) { position_ += by; } + inline void CopyRaw(byte* to, int number_of_bytes); inline int GetInt(); - bool AtEOF() { - return position_ == length_; - } + bool AtEOF(); int position() { return position_; } @@ -187,23 +201,6 @@ class SnapshotByteSource { }; -#define COMMON_RAW_LENGTHS(f) \ - f(1, 1) \ - f(2, 2) \ - f(3, 3) \ - f(4, 4) \ - f(5, 5) \ - f(6, 6) \ - f(7, 7) \ - f(8, 8) \ - f(9, 12) \ - f(10, 16) \ - f(11, 20) \ - f(12, 24) \ - f(13, 28) \ - f(14, 32) \ - f(15, 36) - // The Serializer/Deserializer class is a common superclass for Serializer and // Deserializer which is used to store common constants and methods used by // both. @@ -211,23 +208,24 @@ class SerializerDeserializer: public ObjectVisitor { public: static void Iterate(ObjectVisitor* visitor); + static int nop() { return kNop; } + protected: // Where the pointed-to object can be found: enum Where { kNewObject = 0, // Object is next in snapshot. - // 1-8 One per space. + // 1-6 One per space. kRootArray = 0x9, // Object is found in root array. kPartialSnapshotCache = 0xa, // Object is in the cache. kExternalReference = 0xb, // Pointer to an external reference. - kSkip = 0xc, // Skip a pointer sized cell. - // 0xd-0xf Free. - kBackref = 0x10, // Object is described relative to end. - // 0x11-0x18 One per space. - // 0x19-0x1f Free. - kFromStart = 0x20, // Object is described relative to start. - // 0x21-0x28 One per space. - // 0x29-0x2f Free. - // 0x30-0x3f Used by misc. tags below. + kSkip = 0xc, // Skip n bytes. + kNop = 0xd, // Does nothing, used to pad. + // 0xe-0xf Free. + kBackref = 0x10, // Object is described relative to end. + // 0x11-0x16 One per space. + kBackrefWithSkip = 0x18, // Object is described relative to end. + // 0x19-0x1e One per space. + // 0x20-0x3f Used by misc. tags below. kPointedToMask = 0x3f }; @@ -239,6 +237,13 @@ class SerializerDeserializer: public ObjectVisitor { kHowToCodeMask = 0x40 }; + // For kRootArrayConstants + enum WithSkip { + kNoSkipDistance = 0, + kHasSkipDistance = 0x40, + kWithSkipMask = 0x40 + }; + // Where to point within the object. enum WhereToPoint { kStartOfObject = 0, @@ -247,9 +252,12 @@ class SerializerDeserializer: public ObjectVisitor { }; // Misc. - // Raw data to be copied from the snapshot. - static const int kRawData = 0x30; - // Some common raw lengths: 0x31-0x3f + // Raw data to be copied from the snapshot. This byte code does not advance + // the current pointer, which is used for code objects, where we write the + // entire code in one memcpy, then fix up stuff with kSkip and other byte + // codes that overwrite data. + static const int kRawData = 0x20; + // Some common raw lengths: 0x21-0x3f. These autoadvance the current pointer. // A tag emitted at strategic points in the snapshot to delineate sections. // If the deserializer does not find these at the expected moments then it // is an indication that the snapshot and the VM do not fit together. @@ -259,64 +267,44 @@ class SerializerDeserializer: public ObjectVisitor { // Used for the source code of the natives, which is in the executable, but // is referred to from external strings in the snapshot. static const int kNativesStringResource = 0x71; - static const int kNewPage = 0x72; - static const int kRepeat = 0x73; - static const int kConstantRepeat = 0x74; - // 0x74-0x7f Repeat last word (subtract 0x73 to get the count). - static const int kMaxRepeats = 0x7f - 0x73; + static const int kRepeat = 0x72; + static const int kConstantRepeat = 0x73; + // 0x73-0x7f Repeat last word (subtract 0x72 to get the count). + static const int kMaxRepeats = 0x7f - 0x72; static int CodeForRepeats(int repeats) { ASSERT(repeats >= 1 && repeats <= kMaxRepeats); - return 0x73 + repeats; + return 0x72 + repeats; } static int RepeatsForCode(int byte_code) { ASSERT(byte_code >= kConstantRepeat && byte_code <= 0x7f); - return byte_code - 0x73; + return byte_code - 0x72; } - static const int kRootArrayLowConstants = 0xb0; - // 0xb0-0xbf Things from the first 16 elements of the root array. - static const int kRootArrayHighConstants = 0xf0; - // 0xf0-0xff Things from the next 16 elements of the root array. + static const int kRootArrayConstants = 0xa0; + // 0xa0-0xbf Things from the first 32 elements of the root array. static const int kRootArrayNumberOfConstantEncodings = 0x20; - static const int kRootArrayNumberOfLowConstantEncodings = 0x10; static int RootArrayConstantFromByteCode(int byte_code) { - int constant = (byte_code & 0xf) | ((byte_code & 0x40) >> 2); - ASSERT(constant >= 0 && constant < kRootArrayNumberOfConstantEncodings); - return constant; + return byte_code & 0x1f; } - - static const int kLargeData = LAST_SPACE; - static const int kLargeCode = kLargeData + 1; - static const int kLargeFixedArray = kLargeCode + 1; - static const int kNumberOfSpaces = kLargeFixedArray + 1; + static const int kNumberOfSpaces = LO_SPACE; static const int kAnyOldSpace = -1; // A bitmask for getting the space out of an instruction. - static const int kSpaceMask = 15; - - static inline bool SpaceIsLarge(int space) { return space >= kLargeData; } - static inline bool SpaceIsPaged(int space) { - return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE; - } + static const int kSpaceMask = 7; }; int SnapshotByteSource::GetInt() { - // A little unwind to catch the really small ints. - int snapshot_byte = Get(); - if ((snapshot_byte & 0x80) == 0) { - return snapshot_byte; - } - int accumulator = (snapshot_byte & 0x7f) << 7; - while (true) { - snapshot_byte = Get(); - if ((snapshot_byte & 0x80) == 0) { - return accumulator | snapshot_byte; - } - accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7; - } - UNREACHABLE(); - return accumulator; + // This way of variable-length encoding integers does not suffer from branch + // mispredictions. + uint32_t answer = GetUnalignedInt(); + int bytes = answer & 3; + Advance(bytes); + uint32_t mask = 0xffffffffu; + mask >>= 32 - (bytes << 3); + answer &= mask; + answer >>= 2; + return answer; } @@ -340,6 +328,12 @@ class Deserializer: public SerializerDeserializer { // Deserialize a single object and the objects reachable from it. void DeserializePartial(Object** root); + void set_reservation(int space_number, int reservation) { + ASSERT(space_number >= 0); + ASSERT(space_number <= LAST_SPACE); + reservations_[space_number] = reservation; + } + private: virtual void VisitPointers(Object** start, Object** end); @@ -358,28 +352,36 @@ class Deserializer: public SerializerDeserializer { // the heap. void ReadChunk( Object** start, Object** end, int space, Address object_address); - HeapObject* GetAddressFromStart(int space); - inline HeapObject* GetAddressFromEnd(int space); - Address Allocate(int space_number, Space* space, int size); - void ReadObject(int space_number, Space* space, Object** write_back); + void ReadObject(int space_number, Object** write_back); + + // This routine both allocates a new object, and also keeps + // track of where objects have been allocated so that we can + // fix back references when deserializing. + Address Allocate(int space_index, int size) { + Address address = high_water_[space_index]; + high_water_[space_index] = address + size; + return address; + } + + // This returns the address of an object that has been described in the + // snapshot as being offset bytes back in a particular space. + HeapObject* GetAddressFromEnd(int space) { + int offset = source_->GetInt(); + offset <<= kObjectAlignmentBits; + return HeapObject::FromAddress(high_water_[space] - offset); + } + // Cached current isolate. Isolate* isolate_; - // Keep track of the pages in the paged spaces. - // (In large object space we are keeping track of individual objects - // rather than pages.) In new space we just need the address of the - // first object and the others will flow from that. - List<Address> pages_[SerializerDeserializer::kNumberOfSpaces]; - SnapshotByteSource* source_; // This is the address of the next object that will be allocated in each // space. It is used to calculate the addresses of back-references. Address high_water_[LAST_SPACE + 1]; - // This is the address of the most recent object that was allocated. It - // is used to set the location of the new page when we encounter a - // START_NEW_PAGE_SERIALIZATION tag. - Address last_object_address_; + + int reservations_[LAST_SPACE + 1]; + static const intptr_t kUninitializedReservation = -1; ExternalReferenceDecoder* external_reference_decoder_; @@ -461,7 +463,7 @@ class Serializer : public SerializerDeserializer { // You can call this after serialization to find out how much space was used // in each space. int CurrentAllocationAddress(int space) { - if (SpaceIsLarge(space)) return large_object_total_; + ASSERT(space < kNumberOfSpaces); return fullness_[space]; } @@ -478,8 +480,11 @@ class Serializer : public SerializerDeserializer { static void TooLateToEnableNow() { too_late_to_enable_now_ = true; } static bool enabled() { return serialization_enabled_; } SerializationAddressMapper* address_mapper() { return &address_mapper_; } - void PutRoot( - int index, HeapObject* object, HowToCode how, WhereToPoint where); + void PutRoot(int index, + HeapObject* object, + HowToCode how, + WhereToPoint where, + int skip); protected: static const int kInvalidRootIndex = -1; @@ -503,7 +508,9 @@ class Serializer : public SerializerDeserializer { object_(HeapObject::cast(o)), sink_(sink), reference_representation_(how_to_code + where_to_point), - bytes_processed_so_far_(0) { } + bytes_processed_so_far_(0), + code_object_(o->IsCode()), + code_has_been_output_(false) { } void Serialize(); void VisitPointers(Object** start, Object** end); void VisitEmbeddedPointer(RelocInfo* target); @@ -523,34 +530,36 @@ class Serializer : public SerializerDeserializer { } private: - void OutputRawData(Address up_to); + enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn }; + // This function outputs or skips the raw data between the last pointer and + // up to the current position. It optionally can just return the number of + // bytes to skip instead of performing a skip instruction, in case the skip + // can be merged into the next instruction. + int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn); Serializer* serializer_; HeapObject* object_; SnapshotByteSink* sink_; int reference_representation_; int bytes_processed_so_far_; + bool code_object_; + bool code_has_been_output_; }; virtual void SerializeObject(Object* o, HowToCode how_to_code, - WhereToPoint where_to_point) = 0; + WhereToPoint where_to_point, + int skip) = 0; void SerializeReferenceToPreviousObject( int space, int address, HowToCode how_to_code, - WhereToPoint where_to_point); + WhereToPoint where_to_point, + int skip); void InitializeAllocators(); - // This will return the space for an object. If the object is in large - // object space it may return kLargeCode or kLargeFixedArray in order - // to indicate to the deserializer what kind of large object allocation - // to make. + // This will return the space for an object. static int SpaceOfObject(HeapObject* object); - // This just returns the space of the object. It will return LO_SPACE - // for all large objects since you can't check the type of the object - // once the map has been used for the serialization address. - static int SpaceOfAlreadySerializedObject(HeapObject* object); - int Allocate(int space, int size, bool* new_page_started); + int Allocate(int space, int size); int EncodeExternalReference(Address addr) { return external_reference_encoder_->Encode(addr); } @@ -559,9 +568,7 @@ class Serializer : public SerializerDeserializer { Isolate* isolate_; // Keep track of the fullness of each space in order to generate - // relative addresses for back references. Large objects are - // just numbered sequentially since relative addresses make no - // sense in large object space. + // relative addresses for back references. int fullness_[LAST_SPACE + 1]; SnapshotByteSink* sink_; int current_root_index_; @@ -569,9 +576,9 @@ class Serializer : public SerializerDeserializer { static bool serialization_enabled_; // Did we already make use of the fact that serialization was not enabled? static bool too_late_to_enable_now_; - int large_object_total_; SerializationAddressMapper address_mapper_; intptr_t root_index_wave_front_; + void Pad(); friend class ObjectSerializer; friend class Deserializer; @@ -594,7 +601,8 @@ class PartialSerializer : public Serializer { virtual void Serialize(Object** o); virtual void SerializeObject(Object* o, HowToCode how_to_code, - WhereToPoint where_to_point); + WhereToPoint where_to_point, + int skip); protected: virtual int PartialSnapshotCacheIndex(HeapObject* o); @@ -632,11 +640,13 @@ class StartupSerializer : public Serializer { virtual void SerializeStrongReferences(); virtual void SerializeObject(Object* o, HowToCode how_to_code, - WhereToPoint where_to_point); + WhereToPoint where_to_point, + int skip); void SerializeWeakReferences(); void Serialize() { SerializeStrongReferences(); SerializeWeakReferences(); + Pad(); } private: diff --git a/deps/v8/src/snapshot-common.cc b/deps/v8/src/snapshot-common.cc index 3a4ac70edf..a8806f053f 100644 --- a/deps/v8/src/snapshot-common.cc +++ b/deps/v8/src/snapshot-common.cc @@ -37,10 +37,47 @@ namespace v8 { namespace internal { -bool Snapshot::Deserialize(const byte* content, int len) { - SnapshotByteSource source(content, len); - Deserializer deserializer(&source); - return V8::Initialize(&deserializer); + +static void ReserveSpaceForSnapshot(Deserializer* deserializer, + const char* file_name) { + int file_name_length = StrLength(file_name) + 10; + Vector<char> name = Vector<char>::New(file_name_length + 1); + OS::SNPrintF(name, "%s.size", file_name); + FILE* fp = OS::FOpen(name.start(), "r"); + CHECK_NE(NULL, fp); + int new_size, pointer_size, data_size, code_size, map_size, cell_size; +#ifdef _MSC_VER + // Avoid warning about unsafe fscanf from MSVC. + // Please note that this is only fine if %c and %s are not being used. +#define fscanf fscanf_s +#endif + CHECK_EQ(1, fscanf(fp, "new %d\n", &new_size)); + CHECK_EQ(1, fscanf(fp, "pointer %d\n", &pointer_size)); + CHECK_EQ(1, fscanf(fp, "data %d\n", &data_size)); + CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size)); + CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size)); + CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size)); +#ifdef _MSC_VER +#undef fscanf +#endif + fclose(fp); + deserializer->set_reservation(NEW_SPACE, new_size); + deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size); + deserializer->set_reservation(OLD_DATA_SPACE, data_size); + deserializer->set_reservation(CODE_SPACE, code_size); + deserializer->set_reservation(MAP_SPACE, map_size); + deserializer->set_reservation(CELL_SPACE, cell_size); + name.Dispose(); +} + + +void Snapshot::ReserveSpaceForLinkedInSnapshot(Deserializer* deserializer) { + deserializer->set_reservation(NEW_SPACE, new_space_used_); + deserializer->set_reservation(OLD_POINTER_SPACE, pointer_space_used_); + deserializer->set_reservation(OLD_DATA_SPACE, data_space_used_); + deserializer->set_reservation(CODE_SPACE, code_space_used_); + deserializer->set_reservation(MAP_SPACE, map_space_used_); + deserializer->set_reservation(CELL_SPACE, cell_space_used_); } @@ -49,12 +86,20 @@ bool Snapshot::Initialize(const char* snapshot_file) { int len; byte* str = ReadBytes(snapshot_file, &len); if (!str) return false; - Deserialize(str, len); + bool success; + { + SnapshotByteSource source(str, len); + Deserializer deserializer(&source); + ReserveSpaceForSnapshot(&deserializer, snapshot_file); + success = V8::Initialize(&deserializer); + } DeleteArray(str); - return true; + return success; } else if (size_ > 0) { - Deserialize(raw_data_, raw_size_); - return true; + SnapshotByteSource source(raw_data_, raw_size_); + Deserializer deserializer(&source); + ReserveSpaceForLinkedInSnapshot(&deserializer); + return V8::Initialize(&deserializer); } return false; } @@ -69,17 +114,16 @@ Handle<Context> Snapshot::NewContextFromSnapshot() { if (context_size_ == 0) { return Handle<Context>(); } - HEAP->ReserveSpace(new_space_used_, - pointer_space_used_, - data_space_used_, - code_space_used_, - map_space_used_, - cell_space_used_, - large_space_used_); SnapshotByteSource source(context_raw_data_, context_raw_size_); Deserializer deserializer(&source); Object* root; + deserializer.set_reservation(NEW_SPACE, context_new_space_used_); + deserializer.set_reservation(OLD_POINTER_SPACE, context_pointer_space_used_); + deserializer.set_reservation(OLD_DATA_SPACE, context_data_space_used_); + deserializer.set_reservation(CODE_SPACE, context_code_space_used_); + deserializer.set_reservation(MAP_SPACE, context_map_space_used_); + deserializer.set_reservation(CELL_SPACE, context_cell_space_used_); deserializer.DeserializePartial(&root); CHECK(root->IsContext()); return Handle<Context>(Context::cast(root)); diff --git a/deps/v8/src/snapshot-empty.cc b/deps/v8/src/snapshot-empty.cc index 0b35720cce..70e7ab815c 100644 --- a/deps/v8/src/snapshot-empty.cc +++ b/deps/v8/src/snapshot-empty.cc @@ -49,6 +49,12 @@ const int Snapshot::data_space_used_ = 0; const int Snapshot::code_space_used_ = 0; const int Snapshot::map_space_used_ = 0; const int Snapshot::cell_space_used_ = 0; -const int Snapshot::large_space_used_ = 0; + +const int Snapshot::context_new_space_used_ = 0; +const int Snapshot::context_pointer_space_used_ = 0; +const int Snapshot::context_data_space_used_ = 0; +const int Snapshot::context_code_space_used_ = 0; +const int Snapshot::context_map_space_used_ = 0; +const int Snapshot::context_cell_space_used_ = 0; } } // namespace v8::internal diff --git a/deps/v8/src/snapshot.h b/deps/v8/src/snapshot.h index ab4529e517..c4ae45eee0 100644 --- a/deps/v8/src/snapshot.h +++ b/deps/v8/src/snapshot.h @@ -77,13 +77,18 @@ class Snapshot { static const int code_space_used_; static const int map_space_used_; static const int cell_space_used_; - static const int large_space_used_; + static const int context_new_space_used_; + static const int context_pointer_space_used_; + static const int context_data_space_used_; + static const int context_code_space_used_; + static const int context_map_space_used_; + static const int context_cell_space_used_; static const int size_; static const int raw_size_; static const int context_size_; static const int context_raw_size_; - static bool Deserialize(const byte* content, int len); + static void ReserveSpaceForLinkedInSnapshot(Deserializer* deserializer); DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot); }; diff --git a/deps/v8/src/spaces-inl.h b/deps/v8/src/spaces-inl.h index ed78fc7a15..8a576a83f6 100644 --- a/deps/v8/src/spaces-inl.h +++ b/deps/v8/src/spaces-inl.h @@ -214,6 +214,19 @@ MemoryChunk* MemoryChunk::FromAnyPointerAddress(Address addr) { } +void MemoryChunk::UpdateHighWaterMark(Address mark) { + if (mark == NULL) return; + // Need to subtract one from the mark because when a chunk is full the + // top points to the next address after the chunk, which effectively belongs + // to another chunk. See the comment to Page::FromAllocationTop. + MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1); + int new_mark = static_cast<int>(mark - chunk->address()); + if (new_mark > chunk->high_water_mark_) { + chunk->high_water_mark_ = new_mark; + } +} + + PointerChunkIterator::PointerChunkIterator(Heap* heap) : state_(kOldPointerState), old_pointer_iterator_(heap->old_pointer_space()), @@ -269,6 +282,10 @@ MaybeObject* PagedSpace::AllocateRaw(int size_in_bytes) { return object; } + ASSERT(!heap()->linear_allocation() || + (anchor_.next_chunk() == &anchor_ && + anchor_.prev_chunk() == &anchor_)); + object = free_list_.Allocate(size_in_bytes); if (object != NULL) { if (identity() == CODE_SPACE) { diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index 62873fa1cf..cacd969150 100644 --- a/deps/v8/src/spaces.cc +++ b/deps/v8/src/spaces.cc @@ -447,6 +447,9 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, chunk->InitializeReservedMemory(); chunk->slots_buffer_ = NULL; chunk->skip_list_ = NULL; + chunk->write_barrier_counter_ = kWriteBarrierCounterGranularity; + chunk->progress_bar_ = 0; + chunk->high_water_mark_ = static_cast<int>(area_start - base); chunk->ResetLiveBytes(); Bitmap::Clear(chunk); chunk->initialize_scan_on_scavenge(false); @@ -496,6 +499,7 @@ MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t body_size, VirtualMemory reservation; Address area_start = NULL; Address area_end = NULL; + if (executable == EXECUTABLE) { chunk_size = RoundUp(CodePageAreaStartOffset() + body_size, OS::CommitPageSize()) + CodePageGuardSize(); @@ -528,10 +532,11 @@ MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t body_size, size_executable_ += reservation.size(); } -#ifdef DEBUG - ZapBlock(base, CodePageGuardStartOffset()); - ZapBlock(base + CodePageAreaStartOffset(), body_size); -#endif + if (Heap::ShouldZapGarbage()) { + ZapBlock(base, CodePageGuardStartOffset()); + ZapBlock(base + CodePageAreaStartOffset(), body_size); + } + area_start = base + CodePageAreaStartOffset(); area_end = area_start + body_size; } else { @@ -543,9 +548,9 @@ MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t body_size, if (base == NULL) return NULL; -#ifdef DEBUG - ZapBlock(base, chunk_size); -#endif + if (Heap::ShouldZapGarbage()) { + ZapBlock(base, chunk_size); + } area_start = base + Page::kObjectStartOffset; area_end = base + chunk_size; @@ -621,9 +626,11 @@ bool MemoryAllocator::CommitBlock(Address start, size_t size, Executability executable) { if (!VirtualMemory::CommitRegion(start, size, executable)) return false; -#ifdef DEBUG - ZapBlock(start, size); -#endif + + if (Heap::ShouldZapGarbage()) { + ZapBlock(start, size); + } + isolate_->counters()->memory_allocated()->Increment(static_cast<int>(size)); return true; } @@ -819,6 +826,18 @@ void PagedSpace::TearDown() { } +size_t PagedSpace::CommittedPhysicalMemory() { + if (!VirtualMemory::HasLazyCommits()) return CommittedMemory(); + MemoryChunk::UpdateHighWaterMark(allocation_info_.top); + size_t size = 0; + PageIterator it(this); + while (it.has_next()) { + size += it.next()->CommittedPhysicalMemory(); + } + return size; +} + + MaybeObject* PagedSpace::FindObject(Address addr) { // Note: this function can only be called on precisely swept spaces. ASSERT(!heap()->mark_compact_collector()->in_use()); @@ -881,10 +900,10 @@ intptr_t PagedSpace::SizeOfFirstPage() { size = 192 * KB; break; case MAP_SPACE: - size = 128 * KB; + size = 16 * kPointerSize * KB; break; case CELL_SPACE: - size = 96 * KB; + size = 16 * kPointerSize * KB; break; case CODE_SPACE: if (kPointerSize == 8) { @@ -984,8 +1003,7 @@ void PagedSpace::ReleaseAllUnusedPages() { void PagedSpace::Print() { } #endif - -#ifdef DEBUG +#ifdef VERIFY_HEAP void PagedSpace::Verify(ObjectVisitor* visitor) { // We can only iterate over the pages if they were swept precisely. if (was_swept_conservatively_) return; @@ -995,23 +1013,23 @@ void PagedSpace::Verify(ObjectVisitor* visitor) { PageIterator page_iterator(this); while (page_iterator.has_next()) { Page* page = page_iterator.next(); - ASSERT(page->owner() == this); + CHECK(page->owner() == this); if (page == Page::FromAllocationTop(allocation_info_.top)) { allocation_pointer_found_in_space = true; } - ASSERT(page->WasSweptPrecisely()); + CHECK(page->WasSweptPrecisely()); HeapObjectIterator it(page, NULL); Address end_of_previous_object = page->area_start(); Address top = page->area_end(); int black_size = 0; for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) { - ASSERT(end_of_previous_object <= object->address()); + CHECK(end_of_previous_object <= object->address()); // The first word should be a map, and we expect all map pointers to // be in map space. Map* map = object->map(); - ASSERT(map->IsMap()); - ASSERT(heap()->map_space()->Contains(map)); + CHECK(map->IsMap()); + CHECK(heap()->map_space()->Contains(map)); // Perform space-specific object verification. VerifyObject(object); @@ -1026,15 +1044,14 @@ void PagedSpace::Verify(ObjectVisitor* visitor) { black_size += size; } - ASSERT(object->address() + size <= top); + CHECK(object->address() + size <= top); end_of_previous_object = object->address() + size; } - ASSERT_LE(black_size, page->LiveBytes()); + CHECK_LE(black_size, page->LiveBytes()); } - ASSERT(allocation_pointer_found_in_space); + CHECK(allocation_pointer_found_in_space); } -#endif - +#endif // VERIFY_HEAP // ----------------------------------------------------------------------------- // NewSpace implementation @@ -1172,6 +1189,7 @@ void NewSpace::Shrink() { void NewSpace::UpdateAllocationInfo() { + MemoryChunk::UpdateHighWaterMark(allocation_info_.top); allocation_info_.top = to_space_.page_low(); allocation_info_.limit = to_space_.page_high(); @@ -1258,7 +1276,7 @@ MaybeObject* NewSpace::SlowAllocateRaw(int size_in_bytes) { } -#ifdef DEBUG +#ifdef VERIFY_HEAP // We do not use the SemiSpaceIterator because verification doesn't assume // that it works (it depends on the invariants we are checking). void NewSpace::Verify() { @@ -1307,8 +1325,8 @@ void NewSpace::Verify() { } // Check semi-spaces. - ASSERT_EQ(from_space_.id(), kFromSpace); - ASSERT_EQ(to_space_.id(), kToSpace); + CHECK_EQ(from_space_.id(), kFromSpace); + CHECK_EQ(to_space_.id(), kToSpace); from_space_.Verify(); to_space_.Verify(); } @@ -1384,6 +1402,17 @@ bool SemiSpace::Uncommit() { } +size_t SemiSpace::CommittedPhysicalMemory() { + if (!is_committed()) return 0; + size_t size = 0; + NewSpacePageIterator it(this); + while (it.has_next()) { + size += it.next()->CommittedPhysicalMemory(); + } + return size; +} + + bool SemiSpace::GrowTo(int new_capacity) { if (!is_committed()) { if (!Commit()) return false; @@ -1524,8 +1553,9 @@ void SemiSpace::set_age_mark(Address mark) { #ifdef DEBUG void SemiSpace::Print() { } +#endif - +#ifdef VERIFY_HEAP void SemiSpace::Verify() { bool is_from_space = (id_ == kFromSpace); NewSpacePage* page = anchor_.next_page(); @@ -1555,8 +1585,9 @@ void SemiSpace::Verify() { page = page->next_page(); } } +#endif - +#ifdef DEBUG void SemiSpace::AssertValidRange(Address start, Address end) { // Addresses belong to same semi-space NewSpacePage* page = NewSpacePage::FromLimit(start); @@ -1816,6 +1847,17 @@ void NewSpace::RecordPromotion(HeapObject* obj) { promoted_histogram_[type].increment_bytes(obj->Size()); } + +size_t NewSpace::CommittedPhysicalMemory() { + if (!VirtualMemory::HasLazyCommits()) return CommittedMemory(); + MemoryChunk::UpdateHighWaterMark(allocation_info_.top); + size_t size = to_space_.CommittedPhysicalMemory(); + if (from_space_.is_committed()) { + size += from_space_.CommittedPhysicalMemory(); + } + return size; +} + // ----------------------------------------------------------------------------- // Free lists for old object spaces implementation @@ -2258,11 +2300,40 @@ bool PagedSpace::ReserveSpace(int size_in_bytes) { Free(top(), old_linear_size); SetTop(new_area->address(), new_area->address() + size_in_bytes); - Allocate(size_in_bytes); return true; } +static void RepairFreeList(Heap* heap, FreeListNode* n) { + while (n != NULL) { + Map** map_location = reinterpret_cast<Map**>(n->address()); + if (*map_location == NULL) { + *map_location = heap->free_space_map(); + } else { + ASSERT(*map_location == heap->free_space_map()); + } + n = n->next(); + } +} + + +void FreeList::RepairLists(Heap* heap) { + RepairFreeList(heap, small_list_); + RepairFreeList(heap, medium_list_); + RepairFreeList(heap, large_list_); + RepairFreeList(heap, huge_list_); +} + + +// After we have booted, we have created a map which represents free space +// on the heap. If there was already a free list then the elements on it +// were created with the wrong FreeSpaceMap (normally NULL), so we need to +// fix them. +void PagedSpace::RepairFreeListsAfterBoot() { + free_list_.RepairLists(heap()); +} + + // You have to call this last, since the implementation from PagedSpace // doesn't know that memory was 'promised' to large object space. bool LargeObjectSpace::ReserveSpace(int bytes) { @@ -2320,10 +2391,13 @@ void PagedSpace::EvictEvacuationCandidatesFromFreeLists() { HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) { // Allocation in this space has failed. - // If there are unswept pages advance lazy sweeper then sweep one page before - // allocating a new page. - if (first_unswept_page_->is_valid()) { - AdvanceSweeper(size_in_bytes); + // If there are unswept pages advance lazy sweeper a bounded number of times + // until we find a size_in_bytes contiguous piece of memory + const int kMaxSweepingTries = 5; + bool sweeping_complete = false; + + for (int i = 0; i < kMaxSweepingTries && !sweeping_complete; i++) { + sweeping_complete = AdvanceSweeper(size_in_bytes); // Retry the free list allocation. HeapObject* object = free_list_.Allocate(size_in_bytes); @@ -2521,25 +2595,27 @@ void FixedSpace::PrepareForMarkCompact() { // ----------------------------------------------------------------------------- // MapSpace implementation +// TODO(mvstanton): this is weird...the compiler can't make a vtable unless +// there is at least one non-inlined virtual function. I would prefer to hide +// the VerifyObject definition behind VERIFY_HEAP. -#ifdef DEBUG void MapSpace::VerifyObject(HeapObject* object) { // The object should be a map or a free-list node. - ASSERT(object->IsMap() || object->IsFreeSpace()); + CHECK(object->IsMap() || object->IsFreeSpace()); } -#endif // ----------------------------------------------------------------------------- // GlobalPropertyCellSpace implementation +// TODO(mvstanton): this is weird...the compiler can't make a vtable unless +// there is at least one non-inlined virtual function. I would prefer to hide +// the VerifyObject definition behind VERIFY_HEAP. -#ifdef DEBUG void CellSpace::VerifyObject(HeapObject* object) { // The object should be a global object property cell or a free-list node. - ASSERT(object->IsJSGlobalPropertyCell() || + CHECK(object->IsJSGlobalPropertyCell() || object->map() == heap()->two_pointer_filler_map()); } -#endif // ----------------------------------------------------------------------------- @@ -2649,18 +2725,31 @@ MaybeObject* LargeObjectSpace::AllocateRaw(int object_size, HeapObject* object = page->GetObject(); -#ifdef DEBUG - // Make the object consistent so the heap can be vefified in OldSpaceStep. - reinterpret_cast<Object**>(object->address())[0] = - heap()->fixed_array_map(); - reinterpret_cast<Object**>(object->address())[1] = Smi::FromInt(0); -#endif + if (Heap::ShouldZapGarbage()) { + // Make the object consistent so the heap can be verified in OldSpaceStep. + // We only need to do this in debug builds or if verify_heap is on. + reinterpret_cast<Object**>(object->address())[0] = + heap()->fixed_array_map(); + reinterpret_cast<Object**>(object->address())[1] = Smi::FromInt(0); + } heap()->incremental_marking()->OldSpaceStep(object_size); return object; } +size_t LargeObjectSpace::CommittedPhysicalMemory() { + if (!VirtualMemory::HasLazyCommits()) return CommittedMemory(); + size_t size = 0; + LargePage* current = first_page_; + while (current != NULL) { + size += current->CommittedPhysicalMemory(); + current = current->next_page(); + } + return size; +} + + // GC support MaybeObject* LargeObjectSpace::FindObject(Address a) { LargePage* page = FindPage(a); @@ -2699,7 +2788,8 @@ void LargeObjectSpace::FreeUnmarkedObjects() { MarkBit mark_bit = Marking::MarkBitFrom(object); if (mark_bit.Get()) { mark_bit.Clear(); - MemoryChunk::IncrementLiveBytesFromGC(object->address(), -object->Size()); + Page::FromAddress(object->address())->ResetProgressBar(); + Page::FromAddress(object->address())->ResetLiveBytes(); previous = current; current = current->next_page(); } else { @@ -2753,7 +2843,7 @@ bool LargeObjectSpace::Contains(HeapObject* object) { } -#ifdef DEBUG +#ifdef VERIFY_HEAP // We do not assume that the large object iterator works, because it depends // on the invariants we are checking during verification. void LargeObjectSpace::Verify() { @@ -2764,18 +2854,18 @@ void LargeObjectSpace::Verify() { // object area start. HeapObject* object = chunk->GetObject(); Page* page = Page::FromAddress(object->address()); - ASSERT(object->address() == page->area_start()); + CHECK(object->address() == page->area_start()); // The first word should be a map, and we expect all map pointers to be // in map space. Map* map = object->map(); - ASSERT(map->IsMap()); - ASSERT(heap()->map_space()->Contains(map)); + CHECK(map->IsMap()); + CHECK(heap()->map_space()->Contains(map)); // We have only code, sequential strings, external strings // (sequential strings that have been morphed into external // strings), fixed arrays, and byte arrays in large object space. - ASSERT(object->IsCode() || object->IsSeqString() || + CHECK(object->IsCode() || object->IsSeqString() || object->IsExternalString() || object->IsFixedArray() || object->IsFixedDoubleArray() || object->IsByteArray()); @@ -2794,15 +2884,17 @@ void LargeObjectSpace::Verify() { Object* element = array->get(j); if (element->IsHeapObject()) { HeapObject* element_object = HeapObject::cast(element); - ASSERT(heap()->Contains(element_object)); - ASSERT(element_object->map()->IsMap()); + CHECK(heap()->Contains(element_object)); + CHECK(element_object->map()->IsMap()); } } } } } +#endif +#ifdef DEBUG void LargeObjectSpace::Print() { LargeObjectIterator it(this); for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h index 6602c899df..56f629e02f 100644 --- a/deps/v8/src/spaces.h +++ b/deps/v8/src/spaces.h @@ -100,9 +100,6 @@ class Isolate; #define ASSERT_OBJECT_ALIGNED(address) \ ASSERT((OffsetFrom(address) & kObjectAlignmentMask) == 0) -#define ASSERT_MAP_ALIGNED(address) \ - ASSERT((OffsetFrom(address) & kMapAlignmentMask) == 0) - #define ASSERT_OBJECT_SIZE(size) \ ASSERT((0 < size) && (size <= Page::kMaxNonCodeHeapObjectSize)) @@ -284,7 +281,9 @@ class Bitmap { bool IsClean() { for (int i = 0; i < CellsCount(); i++) { - if (cells()[i] != 0) return false; + if (cells()[i] != 0) { + return false; + } } return true; } @@ -373,6 +372,11 @@ class MemoryChunk { return addr >= area_start() && addr <= area_end(); } + // Every n write barrier invocations we go to runtime even though + // we could have handled it in generated code. This lets us check + // whether we have hit the limit and should do some more marking. + static const int kWriteBarrierCounterGranularity = 500; + enum MemoryChunkFlags { IS_EXECUTABLE, ABOUT_TO_BE_FREED, @@ -393,6 +397,12 @@ class MemoryChunk { WAS_SWEPT_PRECISELY, WAS_SWEPT_CONSERVATIVELY, + // Large objects can have a progress bar in their page header. These object + // are scanned in increments and will be kept black while being scanned. + // Even if the mutator writes to them they will be kept black and a white + // to grey transition is performed in the value. + HAS_PROGRESS_BAR, + // Last flag, keep at bottom. NUM_MEMORY_CHUNK_FLAGS }; @@ -468,6 +478,38 @@ class MemoryChunk { return live_byte_count_; } + int write_barrier_counter() { + return static_cast<int>(write_barrier_counter_); + } + + void set_write_barrier_counter(int counter) { + write_barrier_counter_ = counter; + } + + int progress_bar() { + ASSERT(IsFlagSet(HAS_PROGRESS_BAR)); + return progress_bar_; + } + + void set_progress_bar(int progress_bar) { + ASSERT(IsFlagSet(HAS_PROGRESS_BAR)); + progress_bar_ = progress_bar; + } + + void ResetProgressBar() { + if (IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) { + set_progress_bar(0); + ClearFlag(MemoryChunk::HAS_PROGRESS_BAR); + } + } + + bool IsLeftOfProgressBar(Object** slot) { + Address slot_address = reinterpret_cast<Address>(slot); + ASSERT(slot_address > this->address()); + return (slot_address - (this->address() + kObjectStartOffset)) < + progress_bar(); + } + static void IncrementLiveBytesFromGC(Address address, int by) { MemoryChunk::FromAddress(address)->IncrementLiveBytes(by); } @@ -488,11 +530,14 @@ class MemoryChunk { static const size_t kSlotsBufferOffset = kLiveBytesOffset + kIntSize; - static const size_t kHeaderSize = + static const size_t kWriteBarrierCounterOffset = kSlotsBufferOffset + kPointerSize + kPointerSize; + static const size_t kHeaderSize = + kWriteBarrierCounterOffset + kPointerSize + kIntSize + kIntSize; + static const int kBodyOffset = - CODE_POINTER_ALIGN(MAP_POINTER_ALIGN(kHeaderSize + Bitmap::kSize)); + CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize); // The start offset of the object area in a page. Aligned to both maps and // code alignment to be suitable for both. Also aligned to 32 words because @@ -601,6 +646,13 @@ class MemoryChunk { return static_cast<int>(area_end() - area_start()); } + // Approximate amount of physical memory committed for this chunk. + size_t CommittedPhysicalMemory() { + return high_water_mark_; + } + + static inline void UpdateHighWaterMark(Address mark); + protected: MemoryChunk* next_chunk_; MemoryChunk* prev_chunk_; @@ -625,6 +677,13 @@ class MemoryChunk { int live_byte_count_; SlotsBuffer* slots_buffer_; SkipList* skip_list_; + intptr_t write_barrier_counter_; + // Used by the incremental marker to keep track of the scanning progress in + // large objects that have a progress bar and are scanned in increments. + int progress_bar_; + // Assuming the initial allocation on a page is sequential, + // count highest number of bytes ever allocated on the page. + int high_water_mark_; static MemoryChunk* Initialize(Heap* heap, Address base, @@ -790,14 +849,6 @@ class Space : public Malloced { virtual void Print() = 0; #endif - // After calling this we can allocate a certain number of bytes using only - // linear allocation (with a LinearAllocationScope and an AlwaysAllocateScope) - // without using freelists or causing a GC. This is used by partial - // snapshots. It returns true of space was reserved or false if a GC is - // needed. For paged spaces the space requested must include the space wasted - // at the end of each when allocating linearly. - virtual bool ReserveSpace(int bytes) = 0; - private: Heap* heap_; AllocationSpace id_; @@ -1318,6 +1369,11 @@ class FreeListNode: public HeapObject { inline void Zap(); + static inline FreeListNode* cast(MaybeObject* maybe) { + ASSERT(!maybe->IsFailure()); + return reinterpret_cast<FreeListNode*>(maybe); + } + private: static const int kNextOffset = POINTER_SIZE_ALIGN(FreeSpace::kHeaderSize); @@ -1380,6 +1436,9 @@ class FreeList BASE_EMBEDDED { bool IsVeryLong(); #endif + // Used after booting the VM. + void RepairLists(Heap* heap); + struct SizeStats { intptr_t Total() { return small_size_ + medium_size_ + large_size_ + huge_size_; @@ -1460,6 +1519,10 @@ class PagedSpace : public Space { // linear in the number of objects in the page. It may be slow. MUST_USE_RESULT MaybeObject* FindObject(Address addr); + // During boot the free_space_map is created, and afterwards we may need + // to write it into the free list nodes that were already created. + virtual void RepairFreeListsAfterBoot(); + // Prepares for a mark-compact GC. virtual void PrepareForMarkCompact(); @@ -1470,6 +1533,9 @@ class PagedSpace : public Space { // spaces this equals the capacity. intptr_t CommittedMemory() { return Capacity(); } + // Approximate amount of physical memory committed for this space. + size_t CommittedPhysicalMemory(); + // Sets the capacity, the available space and the wasted space to zero. // The stats are rebuilt during sweeping by adding each page to the // capacity and the size when it is encountered. As free spaces are @@ -1530,6 +1596,7 @@ class PagedSpace : public Space { void SetTop(Address top, Address limit) { ASSERT(top == limit || Page::FromAddress(top) == Page::FromAddress(limit - 1)); + MemoryChunk::UpdateHighWaterMark(allocation_info_.top); allocation_info_.top = top; allocation_info_.limit = limit; } @@ -1551,19 +1618,21 @@ class PagedSpace : public Space { // The dummy page that anchors the linked list of pages. Page* anchor() { return &anchor_; } -#ifdef DEBUG - // Print meta info and objects in this space. - virtual void Print(); - +#ifdef VERIFY_HEAP // Verify integrity of this space. virtual void Verify(ObjectVisitor* visitor); - // Reports statistics for the space - void ReportStatistics(); - // Overridden by subclasses to verify space-specific object // properties (e.g., only maps or free-list nodes are in map space). virtual void VerifyObject(HeapObject* obj) {} +#endif + +#ifdef DEBUG + // Print meta info and objects in this space. + virtual void Print(); + + // Reports statistics for the space + void ReportStatistics(); // Report code object related statistics void CollectCodeStatistics(); @@ -1911,9 +1980,12 @@ class SemiSpace : public Space { NewSpacePage* first_page() { return anchor_.next_page(); } NewSpacePage* current_page() { return current_page_; } +#ifdef VERIFY_HEAP + virtual void Verify(); +#endif + #ifdef DEBUG virtual void Print(); - virtual void Verify(); // Validate a range of of addresses in a SemiSpace. // The "from" address must be on a page prior to the "to" address, // in the linked page order, or it must be earlier on the same page. @@ -1936,6 +2008,9 @@ class SemiSpace : public Space { static void Swap(SemiSpace* from, SemiSpace* to); + // Approximate amount of physical memory committed for this space. + size_t CommittedPhysicalMemory(); + private: // Flips the semispace between being from-space and to-space. // Copies the flags into the masked positions on all pages in the space. @@ -2133,6 +2208,9 @@ class NewSpace : public Space { return Capacity(); } + // Approximate amount of physical memory committed for this space. + size_t CommittedPhysicalMemory(); + // Return the available bytes without growing. intptr_t Available() { return Capacity() - Size(); @@ -2238,9 +2316,12 @@ class NewSpace : public Space { template <typename StringType> inline void ShrinkStringAtAllocationBoundary(String* string, int len); -#ifdef DEBUG +#ifdef VERIFY_HEAP // Verify the active semispace. virtual void Verify(); +#endif + +#ifdef DEBUG // Print the active semispace. virtual void Print() { to_space_.Print(); } #endif @@ -2359,11 +2440,9 @@ class FixedSpace : public PagedSpace { FixedSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id, - int object_size_in_bytes, - const char* name) + int object_size_in_bytes) : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE), - object_size_in_bytes_(object_size_in_bytes), - name_(name) { + object_size_in_bytes_(object_size_in_bytes) { page_extra_ = Page::kNonCodeObjectAreaSize % object_size_in_bytes; } @@ -2380,9 +2459,6 @@ class FixedSpace : public PagedSpace { private: // The size of objects in this space. int object_size_in_bytes_; - - // The name of this space. - const char* name_; }; @@ -2393,7 +2469,7 @@ class MapSpace : public FixedSpace { public: // Creates a map space object with a maximum capacity. MapSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id) - : FixedSpace(heap, max_capacity, id, Map::kSize, "map"), + : FixedSpace(heap, max_capacity, id, Map::kSize), max_map_space_pages_(kMaxMapPageIndex - 1) { } @@ -2410,9 +2486,7 @@ class MapSpace : public FixedSpace { } protected: -#ifdef DEBUG virtual void VerifyObject(HeapObject* obj); -#endif private: static const int kMapsPerPage = Page::kNonCodeObjectAreaSize / Map::kSize; @@ -2436,7 +2510,7 @@ class CellSpace : public FixedSpace { public: // Creates a property cell space object with a maximum capacity. CellSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id) - : FixedSpace(heap, max_capacity, id, JSGlobalPropertyCell::kSize, "cell") + : FixedSpace(heap, max_capacity, id, JSGlobalPropertyCell::kSize) {} virtual int RoundSizeDownToObjectAlignment(int size) { @@ -2448,9 +2522,7 @@ class CellSpace : public FixedSpace { } protected: -#ifdef DEBUG virtual void VerifyObject(HeapObject* obj); -#endif public: TRACK_MEMORY("CellSpace") @@ -2500,6 +2572,9 @@ class LargeObjectSpace : public Space { return Size(); } + // Approximate amount of physical memory committed for this space. + size_t CommittedPhysicalMemory(); + int PageCount() { return page_count_; } @@ -2529,8 +2604,11 @@ class LargeObjectSpace : public Space { LargePage* first_page() { return first_page_; } -#ifdef DEBUG +#ifdef VERIFY_HEAP virtual void Verify(); +#endif + +#ifdef DEBUG virtual void Print(); void ReportStatistics(); void CollectCodeStatistics(); diff --git a/deps/v8/src/store-buffer.cc b/deps/v8/src/store-buffer.cc index 385215573d..66488ae504 100644 --- a/deps/v8/src/store-buffer.cc +++ b/deps/v8/src/store-buffer.cc @@ -372,7 +372,7 @@ void StoreBuffer::GCPrologue() { } -#ifdef DEBUG +#ifdef VERIFY_HEAP static void DummyScavengePointer(HeapObject** p, HeapObject* o) { // Do nothing. } @@ -415,7 +415,7 @@ void StoreBuffer::VerifyPointers(LargeObjectSpace* space) { void StoreBuffer::Verify() { -#ifdef DEBUG +#ifdef VERIFY_HEAP VerifyPointers(heap_->old_pointer_space(), &StoreBuffer::FindPointersToNewSpaceInRegion); VerifyPointers(heap_->map_space(), @@ -427,9 +427,11 @@ void StoreBuffer::Verify() { void StoreBuffer::GCEpilogue() { during_gc_ = false; +#ifdef VERIFY_HEAP if (FLAG_verify_heap) { Verify(); } +#endif } diff --git a/deps/v8/src/store-buffer.h b/deps/v8/src/store-buffer.h index 951a9ca2bc..79046d1540 100644 --- a/deps/v8/src/store-buffer.h +++ b/deps/v8/src/store-buffer.h @@ -195,7 +195,7 @@ class StoreBuffer { void IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback); -#ifdef DEBUG +#ifdef VERIFY_HEAP void VerifyPointers(PagedSpace* space, RegionCallback region_callback); void VerifyPointers(LargeObjectSpace* space); #endif @@ -210,8 +210,7 @@ class StoreBufferRebuildScope { explicit StoreBufferRebuildScope(Heap* heap, StoreBuffer* store_buffer, StoreBufferCallback callback) - : heap_(heap), - store_buffer_(store_buffer), + : store_buffer_(store_buffer), stored_state_(store_buffer->store_buffer_rebuilding_enabled_), stored_callback_(store_buffer->callback_) { store_buffer_->store_buffer_rebuilding_enabled_ = true; @@ -226,7 +225,6 @@ class StoreBufferRebuildScope { } private: - Heap* heap_; StoreBuffer* store_buffer_; bool stored_state_; StoreBufferCallback stored_callback_; diff --git a/deps/v8/src/string-stream.cc b/deps/v8/src/string-stream.cc index 51aa2bb329..30519b5610 100644 --- a/deps/v8/src/string-stream.cc +++ b/deps/v8/src/string-stream.cc @@ -348,9 +348,12 @@ void StringStream::PrintUsingMap(JSObject* js_object) { Add("<Invalid map>\n"); return; } + int real_size = map->NumberOfOwnDescriptors(); DescriptorArray* descs = map->instance_descriptors(); for (int i = 0; i < descs->number_of_descriptors(); i++) { - if (descs->GetType(i) == FIELD) { + PropertyDetails details = descs->GetDetails(i); + if (details.descriptor_index() > real_size) continue; + if (details.type() == FIELD) { Object* key = descs->GetKey(i); if (key->IsString() || key->IsNumber()) { int len = 3; diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index 6115930b6c..badfad3536 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -186,6 +186,9 @@ function StringMatch(regexp) { } var subject = TO_STRING_INLINE(this); if (IS_REGEXP(regexp)) { + // Emulate RegExp.prototype.exec's side effect in step 5, even though + // value is discarded. + ToInteger(regexp.lastIndex); if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0); %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); // lastMatchInfo is defined in regexp.js. @@ -227,6 +230,9 @@ function StringReplace(search, replace) { // Delegate to one of the regular expression variants if necessary. if (IS_REGEXP(search)) { + // Emulate RegExp.prototype.exec's side effect in step 5, even though + // value is discarded. + ToInteger(search.lastIndex); %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); if (IS_SPEC_FUNCTION(replace)) { if (search.global) { @@ -451,7 +457,10 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { var matchInfo = DoRegExpExec(regexp, subject, 0); - if (IS_NULL(matchInfo)) return subject; + if (IS_NULL(matchInfo)) { + regexp.lastIndex = 0; + return subject; + } var index = matchInfo[CAPTURE0]; var result = SubString(subject, 0, index); var endOfMatch = matchInfo[CAPTURE1]; @@ -801,6 +810,7 @@ function StringTrimRight() { var static_charcode_array = new InternalArray(4); + // ECMA-262, section 15.5.3.2 function StringFromCharCode(code) { var n = %_ArgumentsLength(); @@ -809,17 +819,24 @@ function StringFromCharCode(code) { return %_StringCharFromCode(code & 0xffff); } - // NOTE: This is not super-efficient, but it is necessary because we - // want to avoid converting to numbers from within the virtual - // machine. Maybe we can find another way of doing this? - var codes = static_charcode_array; - for (var i = 0; i < n; i++) { + var one_byte = %NewString(n, NEW_ONE_BYTE_STRING); + var i; + for (i = 0; i < n; i++) { var code = %_Arguments(i); - if (!%_IsSmi(code)) code = ToNumber(code); - codes[i] = code; + if (!%_IsSmi(code)) code = ToNumber(code) & 0xffff; + if (code > 0x7f) break; + %_OneByteSeqStringSetChar(one_byte, i, code); + } + if (i == n) return one_byte; + one_byte = %TruncateString(one_byte, i); + + var two_byte = %NewString(n - i, NEW_TWO_BYTE_STRING); + for (var j = 0; i < n; i++, j++) { + var code = %_Arguments(i); + if (!%_IsSmi(code)) code = ToNumber(code) & 0xffff; + %_TwoByteSeqStringSetChar(two_byte, j, code); } - codes.length = n; - return %StringFromCharCodeArray(codes); + return one_byte + two_byte; } diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc index 411914719c..bfed6bbac7 100644 --- a/deps/v8/src/stub-cache.cc +++ b/deps/v8/src/stub-cache.cc @@ -120,7 +120,8 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name, // name specific if there are global objects involved. Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::NONEXISTENT); - Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); LoadStubCompiler compiler(isolate_); @@ -136,10 +137,11 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name, Handle<Code> StubCache::ComputeLoadField(Handle<String> name, Handle<JSObject> receiver, Handle<JSObject> holder, - int field_index) { + PropertyIndex field_index) { ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::FIELD); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); LoadStubCompiler compiler(isolate_); @@ -160,7 +162,8 @@ Handle<Code> StubCache::ComputeLoadCallback(Handle<String> name, ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CALLBACKS); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); LoadStubCompiler compiler(isolate_); @@ -180,7 +183,8 @@ Handle<Code> StubCache::ComputeLoadViaGetter(Handle<String> name, ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CALLBACKS); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); LoadStubCompiler compiler(isolate_); @@ -200,7 +204,8 @@ Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name, ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CONSTANT_FUNCTION); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); LoadStubCompiler compiler(isolate_); @@ -219,7 +224,8 @@ Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name, ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::INTERCEPTOR); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); LoadStubCompiler compiler(isolate_); @@ -245,7 +251,8 @@ Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name, ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::NORMAL); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); LoadStubCompiler compiler(isolate_); @@ -261,11 +268,12 @@ Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name, Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name, Handle<JSObject> receiver, Handle<JSObject> holder, - int field_index) { + PropertyIndex field_index) { ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::FIELD); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); KeyedLoadStubCompiler compiler(isolate_); @@ -285,7 +293,8 @@ Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name, ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CONSTANT_FUNCTION); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); KeyedLoadStubCompiler compiler(isolate_); @@ -304,7 +313,8 @@ Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name, ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::INTERCEPTOR); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); KeyedLoadStubCompiler compiler(isolate_); @@ -324,7 +334,8 @@ Handle<Code> StubCache::ComputeKeyedLoadCallback( ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); KeyedLoadStubCompiler compiler(isolate_); @@ -341,7 +352,8 @@ Handle<Code> StubCache::ComputeKeyedLoadArrayLength(Handle<String> name, Handle<JSArray> receiver) { Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); KeyedLoadStubCompiler compiler(isolate_); @@ -358,7 +370,7 @@ Handle<Code> StubCache::ComputeKeyedLoadStringLength(Handle<String> name, Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS); Handle<Map> map(receiver->map()); - Handle<Object> probe(map->FindInCodeCache(*name, flags)); + Handle<Object> probe(map->FindInCodeCache(*name, flags), isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); KeyedLoadStubCompiler compiler(isolate_); @@ -375,7 +387,8 @@ Handle<Code> StubCache::ComputeKeyedLoadFunctionPrototype( Handle<JSFunction> receiver) { Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); KeyedLoadStubCompiler compiler(isolate_); @@ -396,7 +409,8 @@ Handle<Code> StubCache::ComputeStoreField(Handle<String> name, (transition.is_null()) ? Code::FIELD : Code::MAP_TRANSITION; Code::Flags flags = Code::ComputeMonomorphicFlags( Code::STORE_IC, type, strict_mode); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); StoreStubCompiler compiler(isolate_, strict_mode); @@ -438,7 +452,7 @@ Handle<Code> StubCache::ComputeKeyedLoadOrStoreElement( UNREACHABLE(); break; } - Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); Handle<Code> code; @@ -490,7 +504,8 @@ Handle<Code> StubCache::ComputeStoreGlobal(Handle<String> name, StrictModeFlag strict_mode) { Code::Flags flags = Code::ComputeMonomorphicFlags( Code::STORE_IC, Code::NORMAL, strict_mode); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); StoreStubCompiler compiler(isolate_, strict_mode); @@ -510,7 +525,8 @@ Handle<Code> StubCache::ComputeStoreCallback(Handle<String> name, ASSERT(v8::ToCData<Address>(callback->setter()) != 0); Code::Flags flags = Code::ComputeMonomorphicFlags( Code::STORE_IC, Code::CALLBACKS, strict_mode); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); StoreStubCompiler compiler(isolate_, strict_mode); @@ -530,7 +546,8 @@ Handle<Code> StubCache::ComputeStoreViaSetter(Handle<String> name, StrictModeFlag strict_mode) { Code::Flags flags = Code::ComputeMonomorphicFlags( Code::STORE_IC, Code::CALLBACKS, strict_mode); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); StoreStubCompiler compiler(isolate_, strict_mode); @@ -548,7 +565,8 @@ Handle<Code> StubCache::ComputeStoreInterceptor(Handle<String> name, StrictModeFlag strict_mode) { Code::Flags flags = Code::ComputeMonomorphicFlags( Code::STORE_IC, Code::INTERCEPTOR, strict_mode); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); StoreStubCompiler compiler(isolate_, strict_mode); @@ -568,7 +586,8 @@ Handle<Code> StubCache::ComputeKeyedStoreField(Handle<String> name, (transition.is_null()) ? Code::FIELD : Code::MAP_TRANSITION; Code::Flags flags = Code::ComputeMonomorphicFlags( Code::KEYED_STORE_IC, type, strict_mode); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); KeyedStoreStubCompiler compiler(isolate(), strict_mode, @@ -610,7 +629,8 @@ Handle<Code> StubCache::ComputeCallConstant(int argc, Code::Flags flags = Code::ComputeMonomorphicFlags(kind, Code::CONSTANT_FUNCTION, extra_state, cache_holder, argc); - Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); @@ -632,7 +652,7 @@ Handle<Code> StubCache::ComputeCallField(int argc, Handle<String> name, Handle<Object> object, Handle<JSObject> holder, - int index) { + PropertyIndex index) { // Compute the check type and the map. InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object, *holder); @@ -648,7 +668,8 @@ Handle<Code> StubCache::ComputeCallField(int argc, Code::Flags flags = Code::ComputeMonomorphicFlags(kind, Code::FIELD, extra_state, cache_holder, argc); - Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); @@ -685,7 +706,8 @@ Handle<Code> StubCache::ComputeCallInterceptor(int argc, Code::Flags flags = Code::ComputeMonomorphicFlags(kind, Code::INTERCEPTOR, extra_state, cache_holder, argc); - Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder); @@ -715,7 +737,8 @@ Handle<Code> StubCache::ComputeCallGlobal(int argc, Code::Flags flags = Code::ComputeMonomorphicFlags(kind, Code::NORMAL, extra_state, cache_holder, argc); - Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags)); + Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags), + isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder); @@ -747,10 +770,8 @@ Code* StubCache::FindCallInitialize(int argc, CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT); Code::Flags flags = Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc); - - // Use raw_unchecked... so we don't get assert failures during GC. UnseededNumberDictionary* dictionary = - isolate()->heap()->raw_unchecked_non_monomorphic_cache(); + isolate()->heap()->non_monomorphic_cache(); int entry = dictionary->FindEntry(isolate(), flags); ASSERT(entry != -1); Object* code = dictionary->ValueAt(entry); @@ -1541,6 +1562,7 @@ int CallOptimization::GetPrototypeDepthOfExpectedType( while (!object.is_identical_to(holder)) { if (object->IsInstanceOf(*expected_receiver_type_)) return depth; object = Handle<JSObject>(JSObject::cast(object->GetPrototype())); + if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth; ++depth; } if (holder->IsInstanceOf(*expected_receiver_type_)) return depth; diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h index 005c537ab1..f858e4722a 100644 --- a/deps/v8/src/stub-cache.h +++ b/deps/v8/src/stub-cache.h @@ -83,7 +83,7 @@ class StubCache { Handle<Code> ComputeLoadField(Handle<String> name, Handle<JSObject> receiver, Handle<JSObject> holder, - int field_index); + PropertyIndex field_index); Handle<Code> ComputeLoadCallback(Handle<String> name, Handle<JSObject> receiver, @@ -117,7 +117,7 @@ class StubCache { Handle<Code> ComputeKeyedLoadField(Handle<String> name, Handle<JSObject> receiver, Handle<JSObject> holder, - int field_index); + PropertyIndex field_index); Handle<Code> ComputeKeyedLoadCallback(Handle<String> name, Handle<JSObject> receiver, @@ -193,7 +193,7 @@ class StubCache { Handle<String> name, Handle<Object> object, Handle<JSObject> holder, - int index); + PropertyIndex index); Handle<Code> ComputeCallConstant(int argc, Code::Kind, @@ -453,7 +453,7 @@ class StubCompiler BASE_EMBEDDED { Register dst, Register src, Handle<JSObject> holder, - int index); + PropertyIndex index); static void GenerateLoadArrayLength(MacroAssembler* masm, Register receiver, @@ -540,7 +540,7 @@ class StubCompiler BASE_EMBEDDED { Register scratch1, Register scratch2, Register scratch3, - int index, + PropertyIndex index, Handle<String> name, Label* miss); @@ -611,7 +611,7 @@ class LoadStubCompiler: public StubCompiler { Handle<Code> CompileLoadField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name); Handle<Code> CompileLoadCallback(Handle<String> name, @@ -654,7 +654,7 @@ class KeyedLoadStubCompiler: public StubCompiler { Handle<Code> CompileLoadField(Handle<String> name, Handle<JSObject> object, Handle<JSObject> holder, - int index); + PropertyIndex index); Handle<Code> CompileLoadCallback(Handle<String> name, Handle<JSObject> object, @@ -803,7 +803,7 @@ class CallStubCompiler: public StubCompiler { Handle<Code> CompileCallField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name); Handle<Code> CompileCallConstant(Handle<Object> object, diff --git a/deps/v8/src/token.h b/deps/v8/src/token.h index 3036e5512a..863ba62857 100644 --- a/deps/v8/src/token.h +++ b/deps/v8/src/token.h @@ -99,6 +99,7 @@ namespace internal { T(SHL, "<<", 11) \ T(SAR, ">>", 11) \ T(SHR, ">>>", 11) \ + T(ROR, "rotate right", 11) /* only used by Crankshaft */ \ T(ADD, "+", 12) \ T(SUB, "-", 12) \ T(MUL, "*", 13) \ diff --git a/deps/v8/src/transitions-inl.h b/deps/v8/src/transitions-inl.h index 385bdd1199..cfaa99d737 100644 --- a/deps/v8/src/transitions-inl.h +++ b/deps/v8/src/transitions-inl.h @@ -69,12 +69,14 @@ void TransitionArray::ClearElementsTransition() { bool TransitionArray::HasElementsTransition() { - return get(kElementsTransitionIndex) != Smi::FromInt(0); + return IsFullTransitionArray() && + get(kElementsTransitionIndex) != Smi::FromInt(0); } void TransitionArray::set_elements_transition(Map* transition_map, WriteBarrierMode mode) { + ASSERT(IsFullTransitionArray()); Heap* heap = GetHeap(); WRITE_FIELD(this, kElementsTransitionOffset, transition_map); CONDITIONAL_WRITE_BARRIER( @@ -82,26 +84,6 @@ void TransitionArray::set_elements_transition(Map* transition_map, } -DescriptorArray* TransitionArray::descriptors() { - return DescriptorArray::cast(get(kDescriptorsIndex)); -} - - -void TransitionArray::set_descriptors(DescriptorArray* descriptors, - WriteBarrierMode mode) { - Heap* heap = GetHeap(); - WRITE_FIELD(this, kDescriptorsOffset, descriptors); - CONDITIONAL_WRITE_BARRIER( - heap, this, kDescriptorsOffset, descriptors, mode); -} - - -Object** TransitionArray::GetDescriptorsSlot() { - return HeapObject::RawField(reinterpret_cast<HeapObject*>(this), - kDescriptorsOffset); -} - - Object* TransitionArray::back_pointer_storage() { return get(kBackPointerStorageIndex); } @@ -117,12 +99,13 @@ void TransitionArray::set_back_pointer_storage(Object* back_pointer, bool TransitionArray::HasPrototypeTransitions() { - Object* prototype_transitions = get(kPrototypeTransitionsIndex); - return prototype_transitions != Smi::FromInt(0); + return IsFullTransitionArray() && + get(kPrototypeTransitionsIndex) != Smi::FromInt(0); } FixedArray* TransitionArray::GetPrototypeTransitions() { + ASSERT(IsFullTransitionArray()); Object* prototype_transitions = get(kPrototypeTransitionsIndex); return FixedArray::cast(prototype_transitions); } @@ -136,7 +119,7 @@ HeapObject* TransitionArray::UncheckedPrototypeTransitions() { void TransitionArray::SetPrototypeTransitions(FixedArray* transitions, WriteBarrierMode mode) { - ASSERT(this != NULL); + ASSERT(IsFullTransitionArray()); ASSERT(transitions->IsFixedArray()); Heap* heap = GetHeap(); WRITE_FIELD(this, kPrototypeTransitionsOffset, transitions); @@ -152,6 +135,7 @@ Object** TransitionArray::GetPrototypeTransitionsSlot() { Object** TransitionArray::GetKeySlot(int transition_number) { + ASSERT(!IsSimpleTransition()); ASSERT(transition_number < number_of_transitions()); return HeapObject::RawField( reinterpret_cast<HeapObject*>(this), @@ -160,24 +144,39 @@ Object** TransitionArray::GetKeySlot(int transition_number) { String* TransitionArray::GetKey(int transition_number) { + if (IsSimpleTransition()) { + Map* target = GetTarget(kSimpleTransitionIndex); + int descriptor = target->LastAdded(); + String* key = target->instance_descriptors()->GetKey(descriptor); + return key; + } ASSERT(transition_number < number_of_transitions()); return String::cast(get(ToKeyIndex(transition_number))); } void TransitionArray::SetKey(int transition_number, String* key) { + ASSERT(!IsSimpleTransition()); ASSERT(transition_number < number_of_transitions()); set(ToKeyIndex(transition_number), key); } Map* TransitionArray::GetTarget(int transition_number) { + if (IsSimpleTransition()) { + ASSERT(transition_number == kSimpleTransitionIndex); + return Map::cast(get(kSimpleTransitionTarget)); + } ASSERT(transition_number < number_of_transitions()); return Map::cast(get(ToTargetIndex(transition_number))); } void TransitionArray::SetTarget(int transition_number, Map* value) { + if (IsSimpleTransition()) { + ASSERT(transition_number == kSimpleTransitionIndex); + return set(kSimpleTransitionTarget, value); + } ASSERT(transition_number < number_of_transitions()); set(ToTargetIndex(transition_number), value); } @@ -192,20 +191,22 @@ PropertyDetails TransitionArray::GetTargetDetails(int transition_number) { int TransitionArray::Search(String* name) { - return internal::Search(this, name); + if (IsSimpleTransition()) { + String* key = GetKey(kSimpleTransitionIndex); + if (key->Equals(name)) return kSimpleTransitionIndex; + return kNotFound; + } + return internal::Search<ALL_ENTRIES>(this, name); } -void TransitionArray::Set(int transition_number, - String* key, - Map* target, - const WhitenessWitness&) { - NoIncrementalWriteBarrierSet(this, - ToKeyIndex(transition_number), - key); - NoIncrementalWriteBarrierSet(this, - ToTargetIndex(transition_number), - target); +void TransitionArray::NoIncrementalWriteBarrierSet(int transition_number, + String* key, + Map* target) { + FixedArray::NoIncrementalWriteBarrierSet( + this, ToKeyIndex(transition_number), key); + FixedArray::NoIncrementalWriteBarrierSet( + this, ToTargetIndex(transition_number), target); } diff --git a/deps/v8/src/transitions.cc b/deps/v8/src/transitions.cc index 6f8b2fec5a..56b6caf3db 100644 --- a/deps/v8/src/transitions.cc +++ b/deps/v8/src/transitions.cc @@ -35,28 +35,33 @@ namespace v8 { namespace internal { -MaybeObject* TransitionArray::Allocate(int number_of_transitions) { +static MaybeObject* AllocateRaw(int length) { Heap* heap = Isolate::Current()->heap(); - // Use FixedArray to not use DescriptorArray::cast on incomplete object. + + // Use FixedArray to not use TransitionArray::cast on incomplete object. FixedArray* array; - MaybeObject* maybe_array = - heap->AllocateFixedArray(ToKeyIndex(number_of_transitions)); + MaybeObject* maybe_array = heap->AllocateFixedArray(length); if (!maybe_array->To(&array)) return maybe_array; + return array; +} + +MaybeObject* TransitionArray::Allocate(int number_of_transitions) { + FixedArray* array; + MaybeObject* maybe_array = AllocateRaw(ToKeyIndex(number_of_transitions)); + if (!maybe_array->To(&array)) return maybe_array; array->set(kElementsTransitionIndex, Smi::FromInt(0)); array->set(kPrototypeTransitionsIndex, Smi::FromInt(0)); return array; } -void TransitionArray::CopyFrom(TransitionArray* origin, - int origin_transition, - int target_transition, - const WhitenessWitness& witness) { - Set(target_transition, - origin->GetKey(origin_transition), - origin->GetTarget(origin_transition), - witness); +void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin, + int origin_transition, + int target_transition) { + NoIncrementalWriteBarrierSet(target_transition, + origin->GetKey(origin_transition), + origin->GetTarget(origin_transition)); } @@ -65,15 +70,39 @@ static bool InsertionPointFound(String* key1, String* key2) { } -MaybeObject* TransitionArray::NewWith(String* name, Map* target) { +MaybeObject* TransitionArray::NewWith(SimpleTransitionFlag flag, + String* key, + Map* target, + Object* back_pointer) { TransitionArray* result; + MaybeObject* maybe_result; + + if (flag == SIMPLE_TRANSITION) { + maybe_result = AllocateRaw(kSimpleTransitionSize); + if (!maybe_result->To(&result)) return maybe_result; + result->set(kSimpleTransitionTarget, target); + } else { + maybe_result = Allocate(1); + if (!maybe_result->To(&result)) return maybe_result; + result->NoIncrementalWriteBarrierSet(0, key, target); + } + result->set_back_pointer_storage(back_pointer); + return result; +} - MaybeObject* maybe_array = TransitionArray::Allocate(1); - if (!maybe_array->To(&result)) return maybe_array; - FixedArray::WhitenessWitness witness(result); +MaybeObject* TransitionArray::ExtendToFullTransitionArray() { + ASSERT(!IsFullTransitionArray()); + int nof = number_of_transitions(); + TransitionArray* result; + MaybeObject* maybe_result = Allocate(nof); + if (!maybe_result->To(&result)) return maybe_result; + + if (nof == 1) { + result->NoIncrementalWriteBarrierCopyFrom(this, kSimpleTransitionIndex, 0); + } - result->Set(0, name, target, witness); + result->set_back_pointer_storage(back_pointer_storage()); return result; } @@ -99,28 +128,31 @@ MaybeObject* TransitionArray::CopyInsert(String* name, Map* target) { result->SetPrototypeTransitions(GetPrototypeTransitions()); } - FixedArray::WhitenessWitness witness(result); - if (insertion_index != kNotFound) { for (int i = 0; i < number_of_transitions; ++i) { - if (i != insertion_index) result->CopyFrom(this, i, i, witness); + if (i != insertion_index) { + result->NoIncrementalWriteBarrierCopyFrom(this, i, i); + } } - result->Set(insertion_index, name, target, witness); + result->NoIncrementalWriteBarrierSet(insertion_index, name, target); return result; } insertion_index = 0; for (; insertion_index < number_of_transitions; ++insertion_index) { if (InsertionPointFound(GetKey(insertion_index), name)) break; - result->CopyFrom(this, insertion_index, insertion_index, witness); + result->NoIncrementalWriteBarrierCopyFrom( + this, insertion_index, insertion_index); } - result->Set(insertion_index, name, target, witness); + result->NoIncrementalWriteBarrierSet(insertion_index, name, target); for (; insertion_index < number_of_transitions; ++insertion_index) { - result->CopyFrom(this, insertion_index, insertion_index + 1, witness); + result->NoIncrementalWriteBarrierCopyFrom( + this, insertion_index, insertion_index + 1); } + result->set_back_pointer_storage(back_pointer_storage()); return result; } diff --git a/deps/v8/src/transitions.h b/deps/v8/src/transitions.h index 63e52badcd..0a660261c5 100644 --- a/deps/v8/src/transitions.h +++ b/deps/v8/src/transitions.h @@ -39,13 +39,22 @@ namespace internal { // TransitionArrays are fixed arrays used to hold map transitions for property, -// constant, and element changes. -// The format of the these objects is: -// [0] Descriptor array -// [1] Undefined or back pointer map -// [2] Smi(0) or elements transition map -// [3] Smi(0) or fixed array of prototype transitions -// [4] First transition +// constant, and element changes. They can either be simple transition arrays +// that store a single property transition, or a full transition array that has +// space for elements transitions, prototype transitions and multiple property +// transitons. The details related to property transitions are accessed in the +// descriptor array of the target map. In the case of a simple transition, the +// key is also read from the descriptor array of the target map. +// +// The simple format of the these objects is: +// [0] Undefined or back pointer map +// [1] Single transition +// +// The full format is: +// [0] Undefined or back pointer map +// [1] Smi(0) or elements transition map +// [2] Smi(0) or fixed array of prototype transitions +// [3] First transition // [length() - kTransitionSize] Last transition class TransitionArray: public FixedArray { public: @@ -71,11 +80,6 @@ class TransitionArray: public FixedArray { inline bool HasElementsTransition(); inline void ClearElementsTransition(); - inline DescriptorArray* descriptors(); - inline void set_descriptors(DescriptorArray* descriptors, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Object** GetDescriptorsSlot(); - inline Object* back_pointer_storage(); inline void set_back_pointer_storage( Object* back_pointer, @@ -91,7 +95,7 @@ class TransitionArray: public FixedArray { // Returns the number of transitions in the array. int number_of_transitions() { - ASSERT(length() >= kFirstIndex); + if (IsSimpleTransition()) return 1; int len = length(); return len <= kFirstIndex ? 0 : (len - kFirstIndex) / kTransitionSize; } @@ -99,7 +103,13 @@ class TransitionArray: public FixedArray { inline int number_of_entries() { return number_of_transitions(); } // Allocate a new transition array with a single entry. - static MUST_USE_RESULT MaybeObject* NewWith(String* name, Map* target); + static MUST_USE_RESULT MaybeObject* NewWith( + SimpleTransitionFlag flag, + String* key, + Map* target, + Object* back_pointer); + + MUST_USE_RESULT MaybeObject* ExtendToFullTransitionArray(); // Copy the transition array, inserting a new transition. // TODO(verwaest): This should not cause an existing transition to be @@ -107,10 +117,9 @@ class TransitionArray: public FixedArray { MUST_USE_RESULT MaybeObject* CopyInsert(String* name, Map* target); // Copy a single transition from the origin array. - inline void CopyFrom(TransitionArray* origin, - int origin_transition, - int target_transition, - const WhitenessWitness& witness); + inline void NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin, + int origin_transition, + int target_transition); // Search a transition for a given property name. inline int Search(String* name); @@ -118,28 +127,37 @@ class TransitionArray: public FixedArray { // Allocates a TransitionArray. MUST_USE_RESULT static MaybeObject* Allocate(int number_of_transitions); + bool IsSimpleTransition() { return length() == kSimpleTransitionSize; } + bool IsFullTransitionArray() { return length() >= kFirstIndex; } + // Casting. static inline TransitionArray* cast(Object* obj); // Constant for denoting key was not found. static const int kNotFound = -1; - static const int kDescriptorsIndex = 0; - static const int kBackPointerStorageIndex = 1; - static const int kElementsTransitionIndex = 2; - static const int kPrototypeTransitionsIndex = 3; - static const int kFirstIndex = 4; + static const int kBackPointerStorageIndex = 0; - // Layout transition array header. - static const int kDescriptorsOffset = FixedArray::kHeaderSize; - static const int kBackPointerStorageOffset = kDescriptorsOffset + - kPointerSize; + // Layout for full transition arrays. + static const int kElementsTransitionIndex = 1; + static const int kPrototypeTransitionsIndex = 2; + static const int kFirstIndex = 3; + + // Layout for simple transition arrays. + static const int kSimpleTransitionTarget = 1; + static const int kSimpleTransitionSize = 2; + static const int kSimpleTransitionIndex = 0; + STATIC_ASSERT(kSimpleTransitionIndex != kNotFound); + + static const int kBackPointerStorageOffset = FixedArray::kHeaderSize; + + // Layout for the full transition array header. static const int kElementsTransitionOffset = kBackPointerStorageOffset + kPointerSize; static const int kPrototypeTransitionsOffset = kElementsTransitionOffset + kPointerSize; - // Layout of map transition. + // Layout of map transition entries in full transition arrays. static const int kTransitionKey = 0; static const int kTransitionTarget = 1; static const int kTransitionSize = 2; @@ -153,7 +171,7 @@ class TransitionArray: public FixedArray { #endif #ifdef DEBUG - bool IsSortedNoDuplicates(); + bool IsSortedNoDuplicates(int valid_entries = -1); bool IsConsistentWithBackPointers(Map* current_map); bool IsEqualTo(TransitionArray* other); #endif @@ -176,10 +194,9 @@ class TransitionArray: public FixedArray { kTransitionTarget; } - inline void Set(int transition_number, - String* key, - Map* target, - const WhitenessWitness&); + inline void NoIncrementalWriteBarrierSet(int transition_number, + String* key, + Map* target); DISALLOW_IMPLICIT_CONSTRUCTORS(TransitionArray); }; diff --git a/deps/v8/src/type-info.cc b/deps/v8/src/type-info.cc index bc6a46b4b6..7a9a5de809 100644 --- a/deps/v8/src/type-info.cc +++ b/deps/v8/src/type-info.cc @@ -79,7 +79,7 @@ static uint32_t IdToKey(TypeFeedbackId ast_id) { Handle<Object> TypeFeedbackOracle::GetInfo(TypeFeedbackId ast_id) { int entry = dictionary_->FindEntry(IdToKey(ast_id)); return entry != UnseededNumberDictionary::kNotFound - ? Handle<Object>(dictionary_->ValueAt(entry)) + ? Handle<Object>(dictionary_->ValueAt(entry), isolate_) : Handle<Object>::cast(isolate_->factory()->undefined_value()); } @@ -312,43 +312,53 @@ bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) { } -TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) { - Handle<Object> object = GetInfo(expr->CompareOperationFeedbackId()); - TypeInfo unknown = TypeInfo::Unknown(); - if (!object->IsCode()) return unknown; - Handle<Code> code = Handle<Code>::cast(object); - if (!code->is_compare_ic_stub()) return unknown; - - CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); +static TypeInfo TypeFromCompareType(CompareIC::State state) { switch (state) { case CompareIC::UNINITIALIZED: // Uninitialized means never executed. return TypeInfo::Uninitialized(); - case CompareIC::SMIS: + case CompareIC::SMI: return TypeInfo::Smi(); - case CompareIC::HEAP_NUMBERS: + case CompareIC::HEAP_NUMBER: return TypeInfo::Number(); - case CompareIC::SYMBOLS: - case CompareIC::STRINGS: + case CompareIC::SYMBOL: + return TypeInfo::Symbol(); + case CompareIC::STRING: return TypeInfo::String(); - case CompareIC::OBJECTS: + case CompareIC::OBJECT: case CompareIC::KNOWN_OBJECTS: // TODO(kasperl): We really need a type for JS objects here. return TypeInfo::NonPrimitive(); case CompareIC::GENERIC: default: - return unknown; + return TypeInfo::Unknown(); } } -bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) { +void TypeFeedbackOracle::CompareType(CompareOperation* expr, + TypeInfo* left_type, + TypeInfo* right_type, + TypeInfo* overall_type) { Handle<Object> object = GetInfo(expr->CompareOperationFeedbackId()); - if (!object->IsCode()) return false; + TypeInfo unknown = TypeInfo::Unknown(); + if (!object->IsCode()) { + *left_type = *right_type = *overall_type = unknown; + return; + } Handle<Code> code = Handle<Code>::cast(object); - if (!code->is_compare_ic_stub()) return false; - CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); - return state == CompareIC::SYMBOLS; + if (!code->is_compare_ic_stub()) { + *left_type = *right_type = *overall_type = unknown; + return; + } + + int stub_minor_key = code->stub_info(); + CompareIC::State left_state, right_state, handler_state; + ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state, + &handler_state, NULL); + *left_type = TypeFromCompareType(left_state); + *right_type = TypeFromCompareType(right_state); + *overall_type = TypeFromCompareType(handler_state); } @@ -357,7 +367,7 @@ Handle<Map> TypeFeedbackOracle::GetCompareMap(CompareOperation* expr) { if (!object->IsCode()) return Handle<Map>::null(); Handle<Code> code = Handle<Code>::cast(object); if (!code->is_compare_ic_stub()) return Handle<Map>::null(); - CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); + CompareIC::State state = ICCompareStub::CompareState(code->stub_info()); if (state != CompareIC::KNOWN_OBJECTS) { return Handle<Map>::null(); } @@ -388,55 +398,44 @@ TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) { } -TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) { +static TypeInfo TypeFromBinaryOpType(BinaryOpIC::TypeInfo binary_type) { + switch (binary_type) { + // Uninitialized means never executed. + case BinaryOpIC::UNINITIALIZED: return TypeInfo::Uninitialized(); + case BinaryOpIC::SMI: return TypeInfo::Smi(); + case BinaryOpIC::INT32: return TypeInfo::Integer32(); + case BinaryOpIC::HEAP_NUMBER: return TypeInfo::Double(); + case BinaryOpIC::ODDBALL: return TypeInfo::Unknown(); + case BinaryOpIC::STRING: return TypeInfo::String(); + case BinaryOpIC::GENERIC: return TypeInfo::Unknown(); + } + UNREACHABLE(); + return TypeInfo::Unknown(); +} + + +void TypeFeedbackOracle::BinaryType(BinaryOperation* expr, + TypeInfo* left, + TypeInfo* right, + TypeInfo* result) { Handle<Object> object = GetInfo(expr->BinaryOperationFeedbackId()); TypeInfo unknown = TypeInfo::Unknown(); - if (!object->IsCode()) return unknown; + if (!object->IsCode()) { + *left = *right = *result = unknown; + return; + } Handle<Code> code = Handle<Code>::cast(object); if (code->is_binary_op_stub()) { - BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>( - code->binary_op_type()); - BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>( - code->binary_op_result_type()); - - switch (type) { - case BinaryOpIC::UNINITIALIZED: - // Uninitialized means never executed. - return TypeInfo::Uninitialized(); - case BinaryOpIC::SMI: - switch (result_type) { - case BinaryOpIC::UNINITIALIZED: - if (expr->op() == Token::DIV) { - return TypeInfo::Double(); - } - return TypeInfo::Smi(); - case BinaryOpIC::SMI: - return TypeInfo::Smi(); - case BinaryOpIC::INT32: - return TypeInfo::Integer32(); - case BinaryOpIC::HEAP_NUMBER: - return TypeInfo::Double(); - default: - return unknown; - } - case BinaryOpIC::INT32: - if (expr->op() == Token::DIV || - result_type == BinaryOpIC::HEAP_NUMBER) { - return TypeInfo::Double(); - } - return TypeInfo::Integer32(); - case BinaryOpIC::HEAP_NUMBER: - return TypeInfo::Double(); - case BinaryOpIC::BOTH_STRING: - return TypeInfo::String(); - case BinaryOpIC::STRING: - case BinaryOpIC::GENERIC: - return unknown; - default: - return unknown; - } + BinaryOpIC::TypeInfo left_type, right_type, result_type; + BinaryOpStub::decode_types_from_minor_key(code->stub_info(), &left_type, + &right_type, &result_type); + *left = TypeFromBinaryOpType(left_type); + *right = TypeFromBinaryOpType(right_type); + *result = TypeFromBinaryOpType(result_type); + return; } - return unknown; + // Not a binary op stub. + *left = *right = *result = unknown; } @@ -447,28 +446,8 @@ TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) { Handle<Code> code = Handle<Code>::cast(object); if (!code->is_compare_ic_stub()) return unknown; - CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); - switch (state) { - case CompareIC::UNINITIALIZED: - // Uninitialized means never executed. - // TODO(fschneider): Introduce a separate value for never-executed ICs. - return unknown; - case CompareIC::SMIS: - return TypeInfo::Smi(); - case CompareIC::STRINGS: - return TypeInfo::String(); - case CompareIC::SYMBOLS: - return TypeInfo::Symbol(); - case CompareIC::HEAP_NUMBERS: - return TypeInfo::Number(); - case CompareIC::OBJECTS: - case CompareIC::KNOWN_OBJECTS: - // TODO(kasperl): We really need a type for JS objects here. - return TypeInfo::NonPrimitive(); - case CompareIC::GENERIC: - default: - return unknown; - } + CompareIC::State state = ICCompareStub::CompareState(code->stub_info()); + return TypeFromCompareType(state); } @@ -479,9 +458,14 @@ TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) { Handle<Code> code = Handle<Code>::cast(object); if (!code->is_binary_op_stub()) return unknown; - BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>( - code->binary_op_type()); - switch (type) { + BinaryOpIC::TypeInfo left_type, right_type, unused_result_type; + BinaryOpStub::decode_types_from_minor_key(code->stub_info(), &left_type, + &right_type, &unused_result_type); + // CountOperations should always have +1 or -1 as their right input. + ASSERT(right_type == BinaryOpIC::SMI || + right_type == BinaryOpIC::UNINITIALIZED); + + switch (left_type) { case BinaryOpIC::UNINITIALIZED: case BinaryOpIC::SMI: return TypeInfo::Smi(); @@ -489,7 +473,6 @@ TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) { return TypeInfo::Integer32(); case BinaryOpIC::HEAP_NUMBER: return TypeInfo::Double(); - case BinaryOpIC::BOTH_STRING: case BinaryOpIC::STRING: case BinaryOpIC::GENERIC: return unknown; diff --git a/deps/v8/src/type-info.h b/deps/v8/src/type-info.h index 00d88c2afc..8b2ec49310 100644 --- a/deps/v8/src/type-info.h +++ b/deps/v8/src/type-info.h @@ -204,6 +204,7 @@ class TypeInfo { kNonPrimitive = 0x40, // 1000000 kUninitialized = 0x7f // 1111111 }; + explicit inline TypeInfo(Type t) : type_(t) { } Type type_; @@ -287,9 +288,14 @@ class TypeFeedbackOracle: public ZoneObject { // Get type information for arithmetic operations and compares. TypeInfo UnaryType(UnaryOperation* expr); - TypeInfo BinaryType(BinaryOperation* expr); - TypeInfo CompareType(CompareOperation* expr); - bool IsSymbolCompare(CompareOperation* expr); + void BinaryType(BinaryOperation* expr, + TypeInfo* left, + TypeInfo* right, + TypeInfo* result); + void CompareType(CompareOperation* expr, + TypeInfo* left_type, + TypeInfo* right_type, + TypeInfo* overall_type); Handle<Map> GetCompareMap(CompareOperation* expr); TypeInfo SwitchType(CaseClause* clause); TypeInfo IncrementType(CountOperation* expr); diff --git a/deps/v8/src/uri.js b/deps/v8/src/uri.js index b195f3da79..1de22f8aeb 100644 --- a/deps/v8/src/uri.js +++ b/deps/v8/src/uri.js @@ -165,11 +165,11 @@ function URIDecodeOctets(octets, result, index) { throw new $URIError("URI malformed"); } if (value < 0x10000) { - result[index++] = value; + %_TwoByteSeqStringSetChar(result, index++, value); return index; } else { - result[index++] = (value >> 10) + 0xd7c0; - result[index++] = (value & 0x3ff) + 0xdc00; + %_TwoByteSeqStringSetChar(result, index++, (value >> 10) + 0xd7c0); + %_TwoByteSeqStringSetChar(result, index++, (value & 0x3ff) + 0xdc00); return index; } } @@ -178,43 +178,72 @@ function URIDecodeOctets(octets, result, index) { // ECMA-262, section 15.1.3 function Encode(uri, unescape) { var uriLength = uri.length; - // We are going to pass result to %StringFromCharCodeArray - // which does not expect any getters/setters installed - // on the incoming array. - var result = new InternalArray(uriLength); + var array = new InternalArray(uriLength); var index = 0; for (var k = 0; k < uriLength; k++) { var cc1 = uri.charCodeAt(k); if (unescape(cc1)) { - result[index++] = cc1; + array[index++] = cc1; } else { if (cc1 >= 0xDC00 && cc1 <= 0xDFFF) throw new $URIError("URI malformed"); if (cc1 < 0xD800 || cc1 > 0xDBFF) { - index = URIEncodeSingle(cc1, result, index); + index = URIEncodeSingle(cc1, array, index); } else { k++; if (k == uriLength) throw new $URIError("URI malformed"); var cc2 = uri.charCodeAt(k); if (cc2 < 0xDC00 || cc2 > 0xDFFF) throw new $URIError("URI malformed"); - index = URIEncodePair(cc1, cc2, result, index); + index = URIEncodePair(cc1, cc2, array, index); } } } - return %StringFromCharCodeArray(result); + + var result = %NewString(array.length, NEW_ONE_BYTE_STRING); + for (var i = 0; i < array.length; i++) { + %_OneByteSeqStringSetChar(result, i, array[i]); + } + return result; } // ECMA-262, section 15.1.3 function Decode(uri, reserved) { var uriLength = uri.length; - // We are going to pass result to %StringFromCharCodeArray - // which does not expect any getters/setters installed - // on the incoming array. - var result = new InternalArray(uriLength); + var one_byte = %NewString(uriLength, NEW_ONE_BYTE_STRING); var index = 0; - for (var k = 0; k < uriLength; k++) { - var ch = uri.charAt(k); - if (ch == '%') { + var k = 0; + + // Optimistically assume ascii string. + for ( ; k < uriLength; k++) { + var code = uri.charCodeAt(k); + if (code == 37) { // '%' + if (k + 2 >= uriLength) throw new $URIError("URI malformed"); + var cc = URIHexCharsToCharCode(uri.charCodeAt(k+1), uri.charCodeAt(k+2)); + if (cc >> 7) break; // Assumption wrong, two byte string. + if (reserved(cc)) { + %_OneByteSeqStringSetChar(one_byte, index++, 37); // '%'. + %_OneByteSeqStringSetChar(one_byte, index++, uri.charCodeAt(k+1)); + %_OneByteSeqStringSetChar(one_byte, index++, uri.charCodeAt(k+2)); + } else { + %_OneByteSeqStringSetChar(one_byte, index++, cc); + } + k += 2; + } else { + if (code > 0x7f) break; // Assumption wrong, two byte string. + %_OneByteSeqStringSetChar(one_byte, index++, code); + } + } + + one_byte = %TruncateString(one_byte, index); + if (k == uriLength) return one_byte; + + // Write into two byte string. + var two_byte = %NewString(uriLength - k, NEW_TWO_BYTE_STRING); + index = 0; + + for ( ; k < uriLength; k++) { + var code = uri.charCodeAt(k); + if (code == 37) { // '%' if (k + 2 >= uriLength) throw new $URIError("URI malformed"); var cc = URIHexCharsToCharCode(uri.charCodeAt(++k), uri.charCodeAt(++k)); if (cc >> 7) { @@ -229,22 +258,21 @@ function Decode(uri, reserved) { octets[i] = URIHexCharsToCharCode(uri.charCodeAt(++k), uri.charCodeAt(++k)); } - index = URIDecodeOctets(octets, result, index); + index = URIDecodeOctets(octets, two_byte, index); + } else if (reserved(cc)) { + %_TwoByteSeqStringSetChar(two_byte, index++, 37); // '%'. + %_TwoByteSeqStringSetChar(two_byte, index++, uri.charCodeAt(k - 1)); + %_TwoByteSeqStringSetChar(two_byte, index++, uri.charCodeAt(k)); } else { - if (reserved(cc)) { - result[index++] = 37; // Char code of '%'. - result[index++] = uri.charCodeAt(k - 1); - result[index++] = uri.charCodeAt(k); - } else { - result[index++] = cc; - } + %_TwoByteSeqStringSetChar(two_byte, index++, cc); } } else { - result[index++] = ch.charCodeAt(0); + %_TwoByteSeqStringSetChar(two_byte, index++, code); } } - result.length = index; - return %StringFromCharCodeArray(result); + + two_byte = %TruncateString(two_byte, index); + return one_byte + two_byte; } diff --git a/deps/v8/src/utils.h b/deps/v8/src/utils.h index dc3a171c8d..e03f96f6e5 100644 --- a/deps/v8/src/utils.h +++ b/deps/v8/src/utils.h @@ -862,7 +862,11 @@ class EmbeddedContainer { public: EmbeddedContainer() : elems_() { } - int length() { return NumElements; } + int length() const { return NumElements; } + const ElementType& operator[](int i) const { + ASSERT(i < length()); + return elems_[i]; + } ElementType& operator[](int i) { ASSERT(i < length()); return elems_[i]; @@ -876,7 +880,12 @@ class EmbeddedContainer { template<typename ElementType> class EmbeddedContainer<ElementType, 0> { public: - int length() { return 0; } + int length() const { return 0; } + const ElementType& operator[](int i) const { + UNREACHABLE(); + static ElementType t = 0; + return t; + } ElementType& operator[](int i) { UNREACHABLE(); static ElementType t = 0; @@ -974,7 +983,7 @@ class EnumSet { T Mask(E element) const { // The strange typing in ASSERT is necessary to avoid stupid warnings, see: // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43680 - ASSERT(element < static_cast<int>(sizeof(T) * CHAR_BIT)); + ASSERT(static_cast<int>(element) < static_cast<int>(sizeof(T) * CHAR_BIT)); return 1 << element; } diff --git a/deps/v8/src/v8-counters.cc b/deps/v8/src/v8-counters.cc index 3f83dffcae..4107dd3e48 100644 --- a/deps/v8/src/v8-counters.cc +++ b/deps/v8/src/v8-counters.cc @@ -86,17 +86,6 @@ Counters::Counters() { size_of_FIXED_ARRAY_##name##_ = size_of_FIXED_ARRAY_##name; FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC) #undef SC - - StatsCounter state_counters[] = { -#define COUNTER_NAME(name) \ - { "c:V8.State" #name, NULL, false }, - STATE_TAG_LIST(COUNTER_NAME) -#undef COUNTER_NAME - }; - - for (int i = 0; i < kSlidingStateWindowCounterCount; ++i) { - state_counters_[i] = state_counters[i]; - } } void Counters::ResetHistograms() { diff --git a/deps/v8/src/v8-counters.h b/deps/v8/src/v8-counters.h index fad3454812..986e6dd6bb 100644 --- a/deps/v8/src/v8-counters.h +++ b/deps/v8/src/v8-counters.h @@ -50,7 +50,6 @@ namespace internal { HT(compile_eval, V8.CompileEval) \ HT(compile_lazy, V8.CompileLazy) - #define HISTOGRAM_PERCENTAGE_LIST(HP) \ HP(external_fragmentation_total, \ V8.MemoryExternalFragmentationTotal) \ @@ -374,16 +373,9 @@ class Counters { kSizeOfFIXED_ARRAY__##name, FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(COUNTER_ID) #undef COUNTER_ID -#define COUNTER_ID(name) k_##name, - STATE_TAG_LIST(COUNTER_ID) -#undef COUNTER_ID stats_counter_count }; - StatsCounter* state_counters(StateTag state) { - return &state_counters_[state]; - } - void ResetHistograms(); private: @@ -426,15 +418,6 @@ class Counters { FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC) #undef SC - enum { -#define COUNTER_ID(name) __##name, - STATE_TAG_LIST(COUNTER_ID) -#undef COUNTER_ID - kSlidingStateWindowCounterCount - }; - - // Sliding state window counters. - StatsCounter state_counters_[kSlidingStateWindowCounterCount]; friend class Isolate; DISALLOW_IMPLICIT_CONSTRUCTORS(Counters); diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc index 2407037b32..b5aad90220 100644 --- a/deps/v8/src/v8.cc +++ b/deps/v8/src/v8.cc @@ -38,6 +38,7 @@ #include "hydrogen.h" #include "lithium-allocator.h" #include "log.h" +#include "objects.h" #include "once.h" #include "platform.h" #include "runtime-profiler.h" @@ -114,6 +115,7 @@ void V8::TearDown() { ElementsAccessor::TearDown(); LOperand::TearDownCaches(); + ExternalReference::TearDownMathExpData(); RegisteredExtension::UnregisterAll(); is_running_ = false; @@ -216,14 +218,22 @@ void V8::RemoveCallCompletedCallback(CallCompletedCallback callback) { void V8::FireCallCompletedCallback(Isolate* isolate) { - if (call_completed_callbacks_ == NULL) return; + bool has_call_completed_callbacks = call_completed_callbacks_ != NULL; + bool observer_delivery_pending = + FLAG_harmony_observation && isolate->observer_delivery_pending(); + if (!has_call_completed_callbacks && !observer_delivery_pending) return; HandleScopeImplementer* handle_scope_implementer = isolate->handle_scope_implementer(); if (!handle_scope_implementer->CallDepthIsZero()) return; // Fire callbacks. Increase call depth to prevent recursive callbacks. handle_scope_implementer->IncrementCallDepth(); - for (int i = 0; i < call_completed_callbacks_->length(); i++) { - call_completed_callbacks_->at(i)(); + if (observer_delivery_pending) { + JSObject::DeliverChangeRecords(isolate); + } + if (has_call_completed_callbacks) { + for (int i = 0; i < call_completed_callbacks_->length(); i++) { + call_completed_callbacks_->at(i)(); + } } handle_scope_implementer->DecrementCallDepth(); } diff --git a/deps/v8/src/v8conversions.cc b/deps/v8/src/v8conversions.cc index bf175e50b5..c6755d593c 100644 --- a/deps/v8/src/v8conversions.cc +++ b/deps/v8/src/v8conversions.cc @@ -84,7 +84,7 @@ double StringToDouble(UnicodeCache* unicode_cache, String* str, int flags, double empty_string_val) { StringShape shape(str); if (shape.IsSequentialAscii()) { - const char* begin = SeqAsciiString::cast(str)->GetChars(); + const char* begin = SeqOneByteString::cast(str)->GetChars(); const char* end = begin + str->length(); return InternalStringToDouble(unicode_cache, begin, end, flags, empty_string_val); @@ -109,7 +109,7 @@ double StringToInt(UnicodeCache* unicode_cache, int radix) { StringShape shape(str); if (shape.IsSequentialAscii()) { - const char* begin = SeqAsciiString::cast(str)->GetChars(); + const char* begin = SeqOneByteString::cast(str)->GetChars(); const char* end = begin + str->length(); return InternalStringToInt(unicode_cache, begin, end, radix); } else if (shape.IsSequentialTwoByte()) { diff --git a/deps/v8/src/v8globals.h b/deps/v8/src/v8globals.h index 3d214f8dd3..5920d33aa8 100644 --- a/deps/v8/src/v8globals.h +++ b/deps/v8/src/v8globals.h @@ -52,15 +52,6 @@ const intptr_t kPointerAlignmentMask = kPointerAlignment - 1; 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; -#else -const intptr_t kMapAlignmentBits = kObjectAlignmentBits + 3; -#endif -const intptr_t kMapAlignment = (1 << kMapAlignmentBits); -const intptr_t kMapAlignmentMask = kMapAlignment - 1; - // Desired alignment for generated code is 32 bytes (to improve cache line // utilization). const int kCodeAlignmentBits = 5; @@ -360,20 +351,13 @@ struct AccessorDescriptor { // VMState object leaves a state by popping the current state from the // stack. -#define STATE_TAG_LIST(V) \ - V(JS) \ - V(GC) \ - V(COMPILER) \ - V(PARALLEL_COMPILER_PROLOGUE) \ - V(OTHER) \ - V(EXTERNAL) - enum StateTag { -#define DEF_STATE_TAG(name) name, - STATE_TAG_LIST(DEF_STATE_TAG) -#undef DEF_STATE_TAG - // Pseudo-types. - state_tag_count + JS, + GC, + COMPILER, + PARALLEL_COMPILER, + OTHER, + EXTERNAL }; @@ -396,10 +380,6 @@ enum StateTag { #define POINTER_SIZE_ALIGN(value) \ (((value) + kPointerAlignmentMask) & ~kPointerAlignmentMask) -// MAP_POINTER_ALIGN returns the value aligned as a map pointer. -#define MAP_POINTER_ALIGN(value) \ - (((value) + kMapAlignmentMask) & ~kMapAlignmentMask) - // CODE_POINTER_ALIGN returns the value aligned as a generated code segment. #define CODE_POINTER_ALIGN(value) \ (((value) + kCodeAlignmentMask) & ~kCodeAlignmentMask) @@ -425,6 +405,13 @@ enum StateTag { #endif +enum CpuImplementer { + UNKNOWN_IMPLEMENTER, + ARM_IMPLEMENTER, + QUALCOMM_IMPLEMENTER +}; + + // Feature flags bit positions. They are mostly based on the CPUID spec. // (We assign CPUID itself to one of the currently reserved bits -- // feel free to change this if needed.) @@ -438,6 +425,9 @@ enum CpuFeature { SSE4_1 = 32 + 19, // x86 VFP3 = 1, // ARM ARMv7 = 2, // ARM VFP2 = 3, // ARM + SUDIV = 4, // ARM + UNALIGNED_ACCESSES = 5, // ARM + MOVW_MOVT_IMMEDIATE_LOADS = 6, // ARM SAHF = 0, // x86 FPU = 1}; // MIPS @@ -486,11 +476,19 @@ enum VariableMode { CONST, // declared via 'const' declarations - LET, // declared via 'let' declarations + LET, // declared via 'let' declarations (first lexical) CONST_HARMONY, // declared via 'const' declarations in harmony mode + MODULE, // declared via 'module' declaration (last lexical) + // Variables introduced by the compiler: + INTERNAL, // like VAR, but not user-visible (may or may not + // be in a context) + + TEMPORARY, // temporary variables (not user-visible), never + // in a context + DYNAMIC, // always require dynamic lookup (we don't know // the declaration) @@ -498,16 +496,10 @@ enum VariableMode { // variable is global unless it has been shadowed // by an eval-introduced variable - DYNAMIC_LOCAL, // requires dynamic lookup, but we know that the + DYNAMIC_LOCAL // requires dynamic lookup, but we know that the // variable is local and where it is unless it // has been shadowed by an eval-introduced // variable - - INTERNAL, // like VAR, but not user-visible (may or may not - // be in a context) - - TEMPORARY // temporary variables (not user-visible), never - // in a context }; @@ -517,17 +509,17 @@ inline bool IsDynamicVariableMode(VariableMode mode) { inline bool IsDeclaredVariableMode(VariableMode mode) { - return mode >= VAR && mode <= CONST_HARMONY; + return mode >= VAR && mode <= MODULE; } inline bool IsLexicalVariableMode(VariableMode mode) { - return mode >= LET && mode <= CONST_HARMONY; + return mode >= LET && mode <= MODULE; } inline bool IsImmutableVariableMode(VariableMode mode) { - return mode == CONST || mode == CONST_HARMONY; + return mode == CONST || (mode >= CONST_HARMONY && mode <= MODULE); } diff --git a/deps/v8/src/v8natives.js b/deps/v8/src/v8natives.js index e2e642941e..e8752c84b8 100644 --- a/deps/v8/src/v8natives.js +++ b/deps/v8/src/v8natives.js @@ -60,7 +60,17 @@ function InstallFunctions(object, attributes, functions) { %ToFastProperties(object); } -// Prevents changes to the prototype of a built-infunction. + +// Helper function to install a getter only property. +function InstallGetter(object, name, getter) { + %FunctionSetName(getter, name); + %FunctionRemovePrototype(getter); + %DefineOrRedefineAccessorProperty(object, name, getter, null, DONT_ENUM); + %SetNativeFlag(getter); +} + + +// Prevents changes to the prototype of a built-in function. // The "prototype" property of the function object is made non-configurable, // and the prototype object is made non-extensible. The latter prevents // changing the __proto__ property. @@ -960,7 +970,7 @@ function ToStringArray(obj, trap) { } var n = ToUint32(obj.length); var array = new $Array(n); - var names = {}; // TODO(rossberg): use sets once they are ready. + var names = { __proto__: null }; // TODO(rossberg): use sets once ready. for (var index = 0; index < n; index++) { var s = ToString(obj[index]); if (%HasLocalProperty(names, s)) { @@ -1015,7 +1025,7 @@ function ObjectGetOwnPropertyNames(obj) { } // Property names are expected to be unique strings. - var propertySet = {}; + var propertySet = { __proto__: null }; var j = 0; for (var i = 0; i < propertyNames.length; ++i) { var name = ToString(propertyNames[i]); @@ -1056,7 +1066,7 @@ function ObjectDefineProperty(obj, p, attributes) { // Clone the attributes object for protection. // TODO(rossberg): not spec'ed yet, so not sure if this should involve // non-own properties as it does (or non-enumerable ones, as it doesn't?). - var attributesClone = {}; + var attributesClone = { __proto__: null }; for (var a in attributes) { attributesClone[a] = attributes[a]; } @@ -1403,11 +1413,7 @@ function NumberToString(radix) { // ECMA-262 section 15.7.4.3 function NumberToLocaleString() { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["Number.prototype.toLocaleString"]); - } - return this.toString(); + return %_CallFunction(this, NumberToString); } @@ -1424,50 +1430,76 @@ function NumberValueOf() { // ECMA-262 section 15.7.4.5 function NumberToFixed(fractionDigits) { + var x = this; + if (!IS_NUMBER(this)) { + if (!IS_NUMBER_WRAPPER(this)) { + throw MakeTypeError("incompatible_method_receiver", + ["Number.prototype.toFixed", this]); + } + // Get the value of this number in case it's an object. + x = %_ValueOf(this); + } var f = TO_INTEGER(fractionDigits); + if (f < 0 || f > 20) { throw new $RangeError("toFixed() digits argument must be between 0 and 20"); } - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["Number.prototype.toFixed"]); - } - var x = ToNumber(this); + + if (NUMBER_IS_NAN(x)) return "NaN"; + if (x == 1/0) return "Infinity"; + if (x == -1/0) return "-Infinity"; + return %NumberToFixed(x, f); } // ECMA-262 section 15.7.4.6 function NumberToExponential(fractionDigits) { - var f = -1; - if (!IS_UNDEFINED(fractionDigits)) { - f = TO_INTEGER(fractionDigits); - if (f < 0 || f > 20) { - throw new $RangeError( - "toExponential() argument must be between 0 and 20"); + var x = this; + if (!IS_NUMBER(this)) { + if (!IS_NUMBER_WRAPPER(this)) { + throw MakeTypeError("incompatible_method_receiver", + ["Number.prototype.toExponential", this]); } + // Get the value of this number in case it's an object. + x = %_ValueOf(this); } - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["Number.prototype.toExponential"]); + var f = IS_UNDEFINED(fractionDigits) ? void 0 : TO_INTEGER(fractionDigits); + + if (NUMBER_IS_NAN(x)) return "NaN"; + if (x == 1/0) return "Infinity"; + if (x == -1/0) return "-Infinity"; + + if (IS_UNDEFINED(f)) { + f = -1; // Signal for runtime function that f is not defined. + } else if (f < 0 || f > 20) { + throw new $RangeError("toExponential() argument must be between 0 and 20"); } - var x = ToNumber(this); return %NumberToExponential(x, f); } // ECMA-262 section 15.7.4.7 function NumberToPrecision(precision) { - if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { - throw MakeTypeError("called_on_null_or_undefined", - ["Number.prototype.toPrecision"]); + var x = this; + if (!IS_NUMBER(this)) { + if (!IS_NUMBER_WRAPPER(this)) { + throw MakeTypeError("incompatible_method_receiver", + ["Number.prototype.toPrecision", this]); + } + // Get the value of this number in case it's an object. + x = %_ValueOf(this); } if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this)); var p = TO_INTEGER(precision); + + if (NUMBER_IS_NAN(x)) return "NaN"; + if (x == 1/0) return "Infinity"; + if (x == -1/0) return "-Infinity"; + if (p < 1 || p > 21) { throw new $RangeError("toPrecision() argument must be between 1 and 21"); } - var x = ToNumber(this); return %NumberToPrecision(x, p); } diff --git a/deps/v8/src/variables.cc b/deps/v8/src/variables.cc index 0416f3a390..9161217917 100644 --- a/deps/v8/src/variables.cc +++ b/deps/v8/src/variables.cc @@ -41,8 +41,9 @@ const char* Variable::Mode2String(VariableMode mode) { switch (mode) { case VAR: return "VAR"; case CONST: return "CONST"; - case CONST_HARMONY: return "CONST_HARMONY"; case LET: return "LET"; + case CONST_HARMONY: return "CONST_HARMONY"; + case MODULE: return "MODULE"; case DYNAMIC: return "DYNAMIC"; case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL"; case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL"; @@ -84,7 +85,8 @@ Variable::Variable(Scope* scope, bool Variable::IsGlobalObjectProperty() const { // Temporaries are never global, they must always be allocated in the // activation frame. - return mode_ != TEMPORARY && !IsLexicalVariableMode(mode_) + return (IsDynamicVariableMode(mode_) || + (IsDeclaredVariableMode(mode_) && !IsLexicalVariableMode(mode_))) && scope_ != NULL && scope_->is_global_scope(); } diff --git a/deps/v8/src/variables.h b/deps/v8/src/variables.h index ba26b80472..bb35ee88b5 100644 --- a/deps/v8/src/variables.h +++ b/deps/v8/src/variables.h @@ -130,8 +130,8 @@ class Variable: public ZoneObject { bool is_arguments() const { return kind_ == ARGUMENTS; } // True if the variable is named eval and not known to be shadowed. - bool is_possibly_eval() const { - return IsVariable(FACTORY->eval_symbol()); + bool is_possibly_eval(Isolate* isolate) const { + return IsVariable(isolate->factory()->eval_symbol()); } Variable* local_if_not_shadowed() const { diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index c8c8fc30b0..61cf9ea271 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 13 -#define BUILD_NUMBER 7 -#define PATCH_LEVEL 4 +#define MINOR_VERSION 15 +#define BUILD_NUMBER 11 +#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/vm-state-inl.h b/deps/v8/src/vm-state-inl.h index 384940dfa5..bc481605fb 100644 --- a/deps/v8/src/vm-state-inl.h +++ b/deps/v8/src/vm-state-inl.h @@ -47,8 +47,8 @@ inline const char* StateToString(StateTag state) { return "GC"; case COMPILER: return "COMPILER"; - case PARALLEL_COMPILER_PROLOGUE: - return "PARALLEL_COMPILER_PROLOGUE"; + case PARALLEL_COMPILER: + return "PARALLEL_COMPILER"; case OTHER: return "OTHER"; case EXTERNAL: @@ -67,6 +67,10 @@ VMState::VMState(Isolate* isolate, StateTag tag) LOG(isolate, UncheckedStringEvent("From", StateToString(previous_tag_))); } + if (FLAG_log_timer_events) { + LOG(isolate, ExternalSwitch(previous_tag_, tag)); + } + isolate_->SetCurrentVMState(tag); } @@ -80,6 +84,10 @@ VMState::~VMState() { UncheckedStringEvent("To", StateToString(previous_tag_))); } + if (FLAG_log_timer_events) { + LOG(isolate_, ExternalSwitch(isolate_->current_vm_state(), previous_tag_)); + } + isolate_->SetCurrentVMState(previous_tag_); } diff --git a/deps/v8/src/x64/assembler-x64-inl.h b/deps/v8/src/x64/assembler-x64-inl.h index f3940e8255..f86417469f 100644 --- a/deps/v8/src/x64/assembler-x64-inl.h +++ b/deps/v8/src/x64/assembler-x64-inl.h @@ -42,6 +42,9 @@ namespace internal { // Implementation of Assembler +static const byte kCallOpcode = 0xE8; + + void Assembler::emitl(uint32_t x) { Memory::uint32_at(pc_) = x; pc_ += sizeof(uint32_t); @@ -195,6 +198,12 @@ void Assembler::set_target_address_at(Address pc, Address target) { CPU::FlushICache(pc, sizeof(int32_t)); } + +Address Assembler::target_address_from_return_address(Address pc) { + return pc - kCallTargetAddressOffset; +} + + Handle<Object> Assembler::code_target_object_handle_at(Address pc) { return code_targets_[Memory::int32_at(pc)]; } @@ -211,6 +220,12 @@ void RelocInfo::apply(intptr_t delta) { } else if (IsCodeTarget(rmode_)) { Memory::int32_at(pc_) -= static_cast<int32_t>(delta); CPU::FlushICache(pc_, sizeof(int32_t)); + } else if (rmode_ == CODE_AGE_SEQUENCE) { + if (*pc_ == kCallOpcode) { + int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1); + *p -= static_cast<int32_t>(delta); // Relocate entry. + CPU::FlushICache(p, sizeof(uint32_t)); + } } } @@ -349,6 +364,21 @@ bool RelocInfo::IsPatchedDebugBreakSlotSequence() { } +Code* RelocInfo::code_age_stub() { + ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); + ASSERT(*pc_ == kCallOpcode); + return Code::GetCodeFromTargetAddress( + Assembler::target_address_at(pc_ + 1)); +} + + +void RelocInfo::set_code_age_stub(Code* stub) { + ASSERT(*pc_ == kCallOpcode); + ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); + Assembler::set_target_address_at(pc_ + 1, stub->instruction_start()); +} + + Address RelocInfo::call_address() { ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence())); @@ -402,6 +432,8 @@ void RelocInfo::Visit(ObjectVisitor* visitor) { } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { visitor->VisitExternalReference(this); CPU::FlushICache(pc_, sizeof(Address)); + } else if (RelocInfo::IsCodeAgeSequence(mode)) { + visitor->VisitCodeAgeSequence(this); #ifdef ENABLE_DEBUGGER_SUPPORT // TODO(isolates): Get a cached isolate below. } else if (((RelocInfo::IsJSReturn(mode) && @@ -430,6 +462,8 @@ void RelocInfo::Visit(Heap* heap) { } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { StaticVisitor::VisitExternalReference(this); CPU::FlushICache(pc_, sizeof(Address)); + } else if (RelocInfo::IsCodeAgeSequence(mode)) { + StaticVisitor::VisitCodeAgeSequence(heap, this); #ifdef ENABLE_DEBUGGER_SUPPORT } else if (heap->isolate()->debug()->has_break_points() && ((RelocInfo::IsJSReturn(mode) && diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc index 862a735579..370cb02a36 100644 --- a/deps/v8/src/x64/assembler-x64.cc +++ b/deps/v8/src/x64/assembler-x64.cc @@ -346,50 +346,20 @@ bool Operand::AddressUsesRegister(Register reg) const { static void InitCoverageLog(); #endif -Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size) - : AssemblerBase(arg_isolate), +Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) + : AssemblerBase(isolate, buffer, buffer_size), code_targets_(100), - positions_recorder_(this), - emit_debug_code_(FLAG_debug_code), - predictable_code_size_(false) { - if (buffer == NULL) { - // Do our own buffer management. - if (buffer_size <= kMinimalBufferSize) { - buffer_size = kMinimalBufferSize; - - if (isolate() != NULL && isolate()->assembler_spare_buffer() != NULL) { - buffer = isolate()->assembler_spare_buffer(); - isolate()->set_assembler_spare_buffer(NULL); - } - } - if (buffer == NULL) { - buffer_ = NewArray<byte>(buffer_size); - } else { - buffer_ = static_cast<byte*>(buffer); - } - buffer_size_ = buffer_size; - own_buffer_ = true; - } else { - // Use externally provided buffer instead. - ASSERT(buffer_size > 0); - buffer_ = static_cast<byte*>(buffer); - buffer_size_ = buffer_size; - own_buffer_ = false; - } - + positions_recorder_(this) { // Clear the buffer in debug mode unless it was provided by the // caller in which case we can't be sure it's okay to overwrite // existing code in it. #ifdef DEBUG if (own_buffer_) { - memset(buffer_, 0xCC, buffer_size); // int3 + memset(buffer_, 0xCC, buffer_size_); // int3 } #endif - // Set up buffer pointers. - ASSERT(buffer_ != NULL); - pc_ = buffer_; - reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); + reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); #ifdef GENERATED_CODE_COVERAGE @@ -398,19 +368,6 @@ Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size) } -Assembler::~Assembler() { - if (own_buffer_) { - if (isolate() != NULL && - isolate()->assembler_spare_buffer() == NULL && - buffer_size_ == kMinimalBufferSize) { - isolate()->set_assembler_spare_buffer(buffer_); - } else { - DeleteArray(buffer_); - } - } -} - - void Assembler::GetCode(CodeDesc* desc) { // Finalize code (at this point overflow() may be true, but the gap ensures // that we are still not overlapping instructions and relocation info). @@ -1238,13 +1195,13 @@ void Assembler::j(Condition cc, Label* L, Label::Distance distance) { // Determine whether we can use 1-byte offsets for backwards branches, // which have a max range of 128 bytes. - // We also need to check the predictable_code_size_ flag here, because - // on x64, when the full code generator recompiles code for debugging, some - // places need to be padded out to a certain size. The debugger is keeping - // track of how often it did this so that it can adjust return addresses on - // the stack, but if the size of jump instructions can also change, that's - // not enough and the calculated offsets would be incorrect. - if (is_int8(offs - short_size) && !predictable_code_size_) { + // We also need to check predictable_code_size() flag here, because on x64, + // when the full code generator recompiles code for debugging, some places + // need to be padded out to a certain size. The debugger is keeping track of + // how often it did this so that it can adjust return addresses on the + // stack, but if the size of jump instructions can also change, that's not + // enough and the calculated offsets would be incorrect. + if (is_int8(offs - short_size) && !predictable_code_size()) { // 0111 tttn #8-bit disp. emit(0x70 | cc); emit((offs - short_size) & 0xFF); @@ -1301,7 +1258,7 @@ void Assembler::jmp(Label* L, Label::Distance distance) { if (L->is_bound()) { int offs = L->pos() - pc_offset() - 1; ASSERT(offs <= 0); - if (is_int8(offs - short_size) && !predictable_code_size_) { + if (is_int8(offs - short_size) && !predictable_code_size()) { // 1110 1011 #8-bit disp. emit(0xEB); emit((offs - short_size) & 0xFF); @@ -2850,6 +2807,16 @@ void Assembler::addsd(XMMRegister dst, XMMRegister src) { } +void Assembler::addsd(XMMRegister dst, const Operand& src) { + EnsureSpace ensure_space(this); + emit(0xF2); + emit_optional_rex_32(dst, src); + emit(0x0F); + emit(0x58); + emit_sse_operand(dst, src); +} + + void Assembler::mulsd(XMMRegister dst, XMMRegister src) { EnsureSpace ensure_space(this); emit(0xF2); @@ -2860,6 +2827,16 @@ void Assembler::mulsd(XMMRegister dst, XMMRegister src) { } +void Assembler::mulsd(XMMRegister dst, const Operand& src) { + EnsureSpace ensure_space(this); + emit(0xF2); + emit_optional_rex_32(dst, src); + emit(0x0F); + emit(0x59); + emit_sse_operand(dst, src); +} + + void Assembler::subsd(XMMRegister dst, XMMRegister src) { EnsureSpace ensure_space(this); emit(0xF2); @@ -3047,7 +3024,8 @@ void Assembler::RecordComment(const char* msg, bool force) { const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask | - 1 << RelocInfo::INTERNAL_REFERENCE; + 1 << RelocInfo::INTERNAL_REFERENCE | + 1 << RelocInfo::CODE_AGE_SEQUENCE; bool RelocInfo::IsCodedSpecially() { diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h index e00b403199..24c8df368f 100644 --- a/deps/v8/src/x64/assembler-x64.h +++ b/deps/v8/src/x64/assembler-x64.h @@ -556,15 +556,7 @@ class Assembler : public AssemblerBase { // is too small, a fatal error occurs. No deallocation of the buffer is done // upon destruction of the assembler. Assembler(Isolate* isolate, void* buffer, int buffer_size); - ~Assembler(); - - // Overrides the default provided by FLAG_debug_code. - void set_emit_debug_code(bool value) { emit_debug_code_ = value; } - - // Avoids using instructions that vary in size in unpredictable ways between - // the snapshot and the running VM. This is needed by the full compiler so - // that it can recompile code with debug support and fix the PC. - void set_predictable_code_size(bool value) { predictable_code_size_ = value; } + virtual ~Assembler() { } // GetCode emits any pending (non-emitted) code and fills the descriptor // desc. GetCode() is idempotent; it returns the same result if no other @@ -581,6 +573,10 @@ class Assembler : public AssemblerBase { static inline Address target_address_at(Address pc); static inline void set_target_address_at(Address pc, Address target); + // Return the code target address at a call site from the return address + // of that call in the instruction stream. + static inline Address target_address_from_return_address(Address pc); + // This sets the branch destination (which is in the instruction on x64). // This is for calls and branches within generated code. inline static void deserialization_set_special_target_at( @@ -620,6 +616,7 @@ class Assembler : public AssemblerBase { static const int kCallInstructionLength = 13; static const int kJSReturnSequenceLength = 13; static const int kShortCallInstructionLength = 5; + static const int kPatchDebugBreakSlotReturnOffset = 4; // The debug break slot must be able to contain a call instruction. static const int kDebugBreakSlotLength = kCallInstructionLength; @@ -1016,6 +1013,14 @@ class Assembler : public AssemblerBase { shift(dst, imm8, 0x1); } + void rorl(Register dst, Immediate imm8) { + shift_32(dst, imm8, 0x1); + } + + void rorl_cl(Register dst) { + shift_32(dst, 0x1); + } + // Shifts dst:src left by cl bits, affecting only dst. void shld(Register dst, Register src); @@ -1358,8 +1363,10 @@ class Assembler : public AssemblerBase { void cvtsd2siq(Register dst, XMMRegister src); void addsd(XMMRegister dst, XMMRegister src); + void addsd(XMMRegister dst, const Operand& src); void subsd(XMMRegister dst, XMMRegister src); void mulsd(XMMRegister dst, XMMRegister src); + void mulsd(XMMRegister dst, const Operand& src); void divsd(XMMRegister dst, XMMRegister src); void andpd(XMMRegister dst, XMMRegister src); @@ -1411,8 +1418,6 @@ class Assembler : public AssemblerBase { void db(uint8_t data); void dd(uint32_t data); - int pc_offset() const { return static_cast<int>(pc_ - buffer_); } - PositionsRecorder* positions_recorder() { return &positions_recorder_; } // Check if there is less than kGap bytes available in the buffer. @@ -1431,15 +1436,10 @@ class Assembler : public AssemblerBase { // Avoid overflows for displacements etc. static const int kMaximalBufferSize = 512*MB; - static const int kMinimalBufferSize = 4*KB; byte byte_at(int pos) { return buffer_[pos]; } void set_byte_at(int pos, byte value) { buffer_[pos] = value; } - protected: - bool emit_debug_code() const { return emit_debug_code_; } - bool predictable_code_size() const { return predictable_code_size_; } - private: byte* addr_at(int pos) { return buffer_ + pos; } uint32_t long_at(int pos) { @@ -1627,24 +1627,12 @@ class Assembler : public AssemblerBase { friend class EnsureSpace; friend class RegExpMacroAssemblerX64; - // Code buffer: - // The buffer into which code and relocation info are generated. - byte* buffer_; - int buffer_size_; - // True if the assembler owns the buffer, false if buffer is external. - bool own_buffer_; - // code generation - byte* pc_; // the program counter; moves forward RelocInfoWriter reloc_info_writer; List< Handle<Code> > code_targets_; PositionsRecorder positions_recorder_; - - bool emit_debug_code_; - bool predictable_code_size_; - friend class PositionsRecorder; }; diff --git a/deps/v8/src/x64/builtins-x64.cc b/deps/v8/src/x64/builtins-x64.cc index 9e4153a868..ed0ec684fc 100644 --- a/deps/v8/src/x64/builtins-x64.cc +++ b/deps/v8/src/x64/builtins-x64.cc @@ -606,6 +606,46 @@ void Builtins::Generate_LazyRecompile(MacroAssembler* masm) { } +static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) { + // For now, we are relying on the fact that make_code_young doesn't do any + // garbage collection which allows us to save/restore the registers without + // worrying about which of them contain pointers. We also don't build an + // internal frame to make the code faster, since we shouldn't have to do stack + // crawls in MakeCodeYoung. This seems a bit fragile. + + // Re-execute the code that was patched back to the young age when + // the stub returns. + __ subq(Operand(rsp, 0), Immediate(5)); + __ Pushad(); +#ifdef _WIN64 + __ movq(rcx, Operand(rsp, kNumSafepointRegisters * kPointerSize)); +#else + __ movq(rdi, Operand(rsp, kNumSafepointRegisters * kPointerSize)); +#endif + { // NOLINT + FrameScope scope(masm, StackFrame::MANUAL); + __ PrepareCallCFunction(1); + __ CallCFunction( + ExternalReference::get_make_code_young_function(masm->isolate()), 1); + } + __ Popad(); + __ ret(0); +} + + +#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \ +void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \ + MacroAssembler* masm) { \ + GenerateMakeCodeYoungAgainCommon(masm); \ +} \ +void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \ + MacroAssembler* masm) { \ + GenerateMakeCodeYoungAgainCommon(masm); \ +} +CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR) +#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR + + static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, Deoptimizer::BailoutType type) { // Enter an internal frame. diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 3fa93b2983..970571840b 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -637,6 +637,10 @@ void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { class FloatingPointHelper : public AllStatic { public: + enum ConvertUndefined { + CONVERT_UNDEFINED_TO_ZERO, + BAILOUT_ON_UNDEFINED + }; // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. // If the operands are not both numbers, jump to not_numbers. // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. @@ -672,7 +676,8 @@ class FloatingPointHelper : public AllStatic { Register scratch2, Register scratch3, Label* on_success, - Label* on_not_smis); + Label* on_not_smis, + ConvertUndefined convert_undefined); }; @@ -997,16 +1002,15 @@ void UnaryOpStub::PrintName(StringStream* stream) { } +void BinaryOpStub::Initialize() {} + + void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { __ pop(rcx); // Save return address. __ push(rdx); __ push(rax); // Left and right arguments are now on top. - // Push this stub's key. Although the operation and the type info are - // encoded into the key, the encoding is opaque, so push them too. __ Push(Smi::FromInt(MinorKey())); - __ Push(Smi::FromInt(op_)); - __ Push(Smi::FromInt(operands_type_)); __ push(rcx); // Push return address. @@ -1015,69 +1019,16 @@ void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { __ TailCallExternalReference( ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()), - 5, + 3, 1); } -void BinaryOpStub::Generate(MacroAssembler* masm) { - // Explicitly allow generation of nested stubs. It is safe here because - // generation code does not use any raw pointers. - AllowStubCallsScope allow_stub_calls(masm, true); - - switch (operands_type_) { - case BinaryOpIC::UNINITIALIZED: - GenerateTypeTransition(masm); - break; - case BinaryOpIC::SMI: - GenerateSmiStub(masm); - break; - case BinaryOpIC::INT32: - UNREACHABLE(); - // The int32 case is identical to the Smi case. We avoid creating this - // ic state on x64. - break; - case BinaryOpIC::HEAP_NUMBER: - GenerateHeapNumberStub(masm); - break; - case BinaryOpIC::ODDBALL: - GenerateOddballStub(masm); - break; - case BinaryOpIC::BOTH_STRING: - GenerateBothStringStub(masm); - break; - case BinaryOpIC::STRING: - GenerateStringStub(masm); - break; - case BinaryOpIC::GENERIC: - GenerateGeneric(masm); - break; - default: - UNREACHABLE(); - } -} - - -void BinaryOpStub::PrintName(StringStream* stream) { - const char* op_name = Token::Name(op_); - const char* overwrite_name; - switch (mode_) { - case NO_OVERWRITE: overwrite_name = "Alloc"; break; - case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; - case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; - default: overwrite_name = "UnknownOverwrite"; break; - } - stream->Add("BinaryOpStub_%s_%s_%s", - op_name, - overwrite_name, - BinaryOpIC::GetName(operands_type_)); -} - - -void BinaryOpStub::GenerateSmiCode( +static void BinaryOpStub_GenerateSmiCode( MacroAssembler* masm, Label* slow, - SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { + BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results, + Token::Value op) { // Arguments to BinaryOpStub are in rdx and rax. const Register left = rdx; @@ -1086,9 +1037,9 @@ void BinaryOpStub::GenerateSmiCode( // We only generate heapnumber answers for overflowing calculations // for the four basic arithmetic operations and logical right shift by 0. bool generate_inline_heapnumber_results = - (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) && - (op_ == Token::ADD || op_ == Token::SUB || - op_ == Token::MUL || op_ == Token::DIV || op_ == Token::SHR); + (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) && + (op == Token::ADD || op == Token::SUB || + op == Token::MUL || op == Token::DIV || op == Token::SHR); // Smi check of both operands. If op is BIT_OR, the check is delayed // until after the OR operation. @@ -1096,7 +1047,7 @@ void BinaryOpStub::GenerateSmiCode( Label use_fp_on_smis; Label fail; - if (op_ != Token::BIT_OR) { + if (op != Token::BIT_OR) { Comment smi_check_comment(masm, "-- Smi check arguments"); __ JumpIfNotBothSmi(left, right, ¬_smis); } @@ -1105,7 +1056,7 @@ void BinaryOpStub::GenerateSmiCode( __ bind(&smi_values); // Perform the operation. Comment perform_smi(masm, "-- Perform smi operation"); - switch (op_) { + switch (op) { case Token::ADD: ASSERT(right.is(rax)); __ SmiAdd(right, right, left, &use_fp_on_smis); // ADD is commutative. @@ -1177,7 +1128,7 @@ void BinaryOpStub::GenerateSmiCode( // operations on known smis (e.g., if the result of the operation // overflowed the smi range). __ bind(&use_fp_on_smis); - if (op_ == Token::DIV || op_ == Token::MOD) { + if (op == Token::DIV || op == Token::MOD) { // Restore left and right to rdx and rax. __ movq(rdx, rcx); __ movq(rax, rbx); @@ -1186,12 +1137,12 @@ void BinaryOpStub::GenerateSmiCode( if (generate_inline_heapnumber_results) { __ AllocateHeapNumber(rcx, rbx, slow); Comment perform_float(masm, "-- Perform float operation on smis"); - if (op_ == Token::SHR) { + if (op == Token::SHR) { __ SmiToInteger32(left, left); __ cvtqsi2sd(xmm0, left); } else { FloatingPointHelper::LoadSSE2SmiOperands(masm); - switch (op_) { + switch (op) { case Token::ADD: __ addsd(xmm0, xmm1); break; case Token::SUB: __ subsd(xmm0, xmm1); break; case Token::MUL: __ mulsd(xmm0, xmm1); break; @@ -1214,31 +1165,50 @@ void BinaryOpStub::GenerateSmiCode( // values that could be smi. __ bind(¬_smis); Comment done_comment(masm, "-- Enter non-smi code"); + FloatingPointHelper::ConvertUndefined convert_undefined = + FloatingPointHelper::BAILOUT_ON_UNDEFINED; + // This list must be in sync with BinaryOpPatch() behavior in ic.cc. + if (op == Token::BIT_AND || + op == Token::BIT_OR || + op == Token::BIT_XOR || + op == Token::SAR || + op == Token::SHL || + op == Token::SHR) { + convert_undefined = FloatingPointHelper::CONVERT_UNDEFINED_TO_ZERO; + } FloatingPointHelper::NumbersToSmis(masm, left, right, rbx, rdi, rcx, - &smi_values, &fail); + &smi_values, &fail, convert_undefined); __ jmp(&smi_values); __ bind(&fail); } -void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm, - Label* allocation_failure, - Label* non_numeric_failure) { - switch (op_) { +static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, + Label* alloc_failure, + OverwriteMode mode); + + +static void BinaryOpStub_GenerateFloatingPointCode(MacroAssembler* masm, + Label* allocation_failure, + Label* non_numeric_failure, + Token::Value op, + OverwriteMode mode) { + switch (op) { case Token::ADD: case Token::SUB: case Token::MUL: case Token::DIV: { FloatingPointHelper::LoadSSE2UnknownOperands(masm, non_numeric_failure); - switch (op_) { + 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(); } - GenerateHeapResultAllocation(masm, allocation_failure); + BinaryOpStub_GenerateHeapResultAllocation( + masm, allocation_failure, mode); __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); __ ret(0); break; @@ -1259,7 +1229,7 @@ void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm, __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); FloatingPointHelper::LoadAsIntegers(masm, non_numeric_failure, heap_number_map); - switch (op_) { + switch (op) { case Token::BIT_OR: __ orl(rax, rcx); break; case Token::BIT_AND: __ andl(rax, rcx); break; case Token::BIT_XOR: __ xorl(rax, rcx); break; @@ -1283,7 +1253,7 @@ void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm, // Logical shift right can produce an unsigned int32 that is not // an int32, and so is not in the smi range. Allocate a heap number // in that case. - if (op_ == Token::SHR) { + if (op == Token::SHR) { __ bind(&non_smi_shr_result); Label allocation_failed; __ movl(rbx, rax); // rbx holds result value (uint32 value as int64). @@ -1297,11 +1267,9 @@ void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm, &allocation_failed, TAG_OBJECT); // Set the map. - if (FLAG_debug_code) { - __ AbortIfNotRootValue(heap_number_map, - Heap::kHeapNumberMapRootIndex, - "HeapNumberMap register clobbered."); - } + __ AssertRootValue(heap_number_map, + Heap::kHeapNumberMapRootIndex, + "HeapNumberMap register clobbered."); __ movq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); __ cvtqsi2sd(xmm0, rbx); @@ -1322,12 +1290,12 @@ void BinaryOpStub::GenerateFloatingPointCode(MacroAssembler* masm, // No fall-through from this generated code. if (FLAG_debug_code) { __ Abort("Unexpected fall-through in " - "BinaryStub::GenerateFloatingPointCode."); + "BinaryStub_GenerateFloatingPointCode."); } } -void BinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { +void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { ASSERT(op_ == Token::ADD); Label left_not_string, call_runtime; @@ -1358,58 +1326,17 @@ void BinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { } -void BinaryOpStub::GenerateCallRuntimeCode(MacroAssembler* masm) { - GenerateRegisterArgsPush(masm); - switch (op_) { - case Token::ADD: - __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); - break; - case Token::SUB: - __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); - break; - case Token::MUL: - __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); - break; - case Token::DIV: - __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); - break; - case Token::MOD: - __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); - break; - case Token::BIT_OR: - __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); - break; - case Token::BIT_AND: - __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); - break; - case Token::BIT_XOR: - __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); - break; - case Token::SAR: - __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); - break; - case Token::SHL: - __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); - break; - case Token::SHR: - __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); - break; - default: - UNREACHABLE(); - } -} - - void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { Label call_runtime; if (result_type_ == BinaryOpIC::UNINITIALIZED || result_type_ == BinaryOpIC::SMI) { // Only allow smi results. - GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS, op_); } else { // Allow heap number result and don't make a transition if a heap number // cannot be allocated. - GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); } // Code falls through if the result is not returned as either a smi or heap @@ -1418,24 +1345,22 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { if (call_runtime.is_linked()) { __ bind(&call_runtime); - GenerateCallRuntimeCode(masm); + GenerateRegisterArgsPush(masm); + GenerateCallRuntime(masm); } } -void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { - ASSERT(operands_type_ == BinaryOpIC::STRING); - ASSERT(op_ == Token::ADD); - GenerateStringAddCode(masm); - // Try to add arguments as strings, otherwise, transition to the generic - // BinaryOpIC type. - GenerateTypeTransition(masm); +void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { + // The int32 case is identical to the Smi case. We avoid creating this + // ic state on x64. + UNREACHABLE(); } void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { Label call_runtime; - ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); + ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING); ASSERT(op_ == Token::ADD); // If both arguments are strings, call the string add stub. // Otherwise, do a transition. @@ -1469,7 +1394,7 @@ void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { if (op_ == Token::ADD) { // Handle string addition here, because it is the only operation // that does not do a ToNumber conversion on the operands. - GenerateStringAddCode(masm); + GenerateAddStrings(masm); } // Convert oddball arguments to numbers. @@ -1496,39 +1421,79 @@ void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { } +static void BinaryOpStub_CheckSmiInput(MacroAssembler* masm, + Register input, + Label* fail) { + Label ok; + __ JumpIfSmi(input, &ok, Label::kNear); + Register heap_number_map = r8; + Register scratch1 = r9; + Register scratch2 = r10; + // HeapNumbers containing 32bit integer values are also allowed. + __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); + __ cmpq(FieldOperand(input, HeapObject::kMapOffset), heap_number_map); + __ j(not_equal, fail); + __ movsd(xmm0, FieldOperand(input, HeapNumber::kValueOffset)); + // Convert, convert back, and compare the two doubles' bits. + __ cvttsd2siq(scratch2, xmm0); + __ cvtlsi2sd(xmm1, scratch2); + __ movq(scratch1, xmm0); + __ movq(scratch2, xmm1); + __ cmpq(scratch1, scratch2); + __ j(not_equal, fail); + __ bind(&ok); +} + + void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { Label gc_required, not_number; - GenerateFloatingPointCode(masm, &gc_required, ¬_number); + + // It could be that only SMIs have been seen at either the left + // or the right operand. For precise type feedback, patch the IC + // again if this changes. + if (left_type_ == BinaryOpIC::SMI) { + BinaryOpStub_CheckSmiInput(masm, rdx, ¬_number); + } + if (right_type_ == BinaryOpIC::SMI) { + BinaryOpStub_CheckSmiInput(masm, rax, ¬_number); + } + + BinaryOpStub_GenerateFloatingPointCode( + masm, &gc_required, ¬_number, op_, mode_); __ bind(¬_number); GenerateTypeTransition(masm); __ bind(&gc_required); - GenerateCallRuntimeCode(masm); + GenerateRegisterArgsPush(masm); + GenerateCallRuntime(masm); } void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { Label call_runtime, call_string_add_or_runtime; - GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); + BinaryOpStub_GenerateSmiCode( + masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); - GenerateFloatingPointCode(masm, &call_runtime, &call_string_add_or_runtime); + BinaryOpStub_GenerateFloatingPointCode( + masm, &call_runtime, &call_string_add_or_runtime, op_, mode_); __ bind(&call_string_add_or_runtime); if (op_ == Token::ADD) { - GenerateStringAddCode(masm); + GenerateAddStrings(masm); } __ bind(&call_runtime); - GenerateCallRuntimeCode(masm); + GenerateRegisterArgsPush(masm); + GenerateCallRuntime(masm); } -void BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, - Label* alloc_failure) { +static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, + Label* alloc_failure, + OverwriteMode mode) { Label skip_allocation; - OverwriteMode mode = mode_; switch (mode) { case OVERWRITE_LEFT: { // If the argument in rdx is already an object, we skip the @@ -2024,17 +1989,21 @@ void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm, Register scratch2, Register scratch3, Label* on_success, - Label* on_not_smis) { + Label* on_not_smis, + ConvertUndefined convert_undefined) { Register heap_number_map = scratch3; Register smi_result = scratch1; - Label done; + Label done, maybe_undefined_first, maybe_undefined_second, first_done; __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); Label first_smi; __ JumpIfSmi(first, &first_smi, Label::kNear); __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map); - __ j(not_equal, on_not_smis); + __ j(not_equal, + (convert_undefined == CONVERT_UNDEFINED_TO_ZERO) + ? &maybe_undefined_first + : on_not_smis); // Convert HeapNumber to smi if possible. __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset)); __ movq(scratch2, xmm0); @@ -2047,14 +2016,15 @@ void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm, __ j(not_equal, on_not_smis); __ Integer32ToSmi(first, smi_result); + __ bind(&first_done); __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done); __ bind(&first_smi); - if (FLAG_debug_code) { - // Second should be non-smi if we get here. - __ AbortIfSmi(second); - } + __ AssertNotSmi(second); __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map); - __ j(not_equal, on_not_smis); + __ j(not_equal, + (convert_undefined == CONVERT_UNDEFINED_TO_ZERO) + ? &maybe_undefined_second + : on_not_smis); // Convert second to smi, if possible. __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset)); __ movq(scratch2, xmm0); @@ -2067,8 +2037,25 @@ void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm, if (on_success != NULL) { __ jmp(on_success); } else { - __ bind(&done); + __ jmp(&done); + } + + __ bind(&maybe_undefined_first); + __ CompareRoot(first, Heap::kUndefinedValueRootIndex); + __ j(not_equal, on_not_smis); + __ xor_(first, first); + __ jmp(&first_done); + + __ bind(&maybe_undefined_second); + __ CompareRoot(second, Heap::kUndefinedValueRootIndex); + __ j(not_equal, on_not_smis); + __ xor_(second, second); + if (on_success != NULL) { + __ jmp(on_success); } + // Else: fall through. + + __ bind(&done); } @@ -2234,7 +2221,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X) __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X) - __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X) + __ faddp(1); // 2^(X-rnd(X)), rnd(X) // FSCALE calculates st(0) * 2^st(1) __ fscale(); // 2^X, rnd(X) __ fstp(1); @@ -2262,21 +2249,28 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ movsd(double_scratch2, double_result); // Load double_exponent with 1. // Get absolute value of exponent. - Label no_neg, while_true, no_multiply; + Label no_neg, while_true, while_false; __ testl(scratch, scratch); __ j(positive, &no_neg, Label::kNear); __ negl(scratch); __ bind(&no_neg); - __ bind(&while_true); + __ j(zero, &while_false, Label::kNear); __ shrl(scratch, Immediate(1)); - __ j(not_carry, &no_multiply, Label::kNear); - __ mulsd(double_result, double_scratch); - __ bind(&no_multiply); + // Above condition means CF==0 && ZF==0. This means that the + // bit that has been shifted out is 0 and the result is not 0. + __ j(above, &while_true, Label::kNear); + __ movsd(double_result, double_scratch); + __ j(zero, &while_false, Label::kNear); + __ bind(&while_true); + __ shrl(scratch, Immediate(1)); __ mulsd(double_scratch, double_scratch); + __ j(above, &while_true, Label::kNear); + __ mulsd(double_result, double_scratch); __ j(not_zero, &while_true); + __ bind(&while_false); // If the exponent is negative, return 1/result. __ testl(exponent, exponent); __ j(greater, &done); @@ -2602,7 +2596,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { __ bind(&runtime); __ Integer32ToSmi(rcx, rcx); __ movq(Operand(rsp, 1 * kPointerSize), rcx); // Patch argument count. - __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); + __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); } @@ -3020,8 +3014,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // r15: original subject string __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. __ j(zero, &setup_two_byte, Label::kNear); - __ lea(arg4, FieldOperand(rdi, r14, times_1, SeqAsciiString::kHeaderSize)); - __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize)); + __ lea(arg4, FieldOperand(rdi, r14, times_1, SeqOneByteString::kHeaderSize)); + __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqOneByteString::kHeaderSize)); __ jmp(&setup_rest, Label::kNear); __ bind(&setup_two_byte); __ lea(arg4, FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); @@ -3161,7 +3155,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { } __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); STATIC_ASSERT(kTwoByteStringTag == 0); __ testb(rbx, Immediate(kStringEncodingMask)); @@ -3235,14 +3229,14 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { // Set length. __ Integer32ToSmi(rdx, rbx); __ movq(FieldOperand(rcx, FixedArray::kLengthOffset), rdx); - // Fill contents of fixed-array with the-hole. - __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); + // Fill contents of fixed-array with undefined. + __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); __ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize)); - // Fill fixed array elements with hole. + // Fill fixed array elements with undefined. // rax: JSArray. // rbx: Number of elements in array that remains to be filled, as int32. // rcx: Start of elements in FixedArray. - // rdx: the hole. + // rdx: undefined. Label loop; __ testl(rbx, rbx); __ bind(&loop); @@ -3376,30 +3370,59 @@ static int NegativeComparisonResult(Condition cc) { } -void CompareStub::Generate(MacroAssembler* masm) { - ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); +static void CheckInputType(MacroAssembler* masm, + Register input, + CompareIC::State expected, + Label* fail) { + Label ok; + if (expected == CompareIC::SMI) { + __ JumpIfNotSmi(input, fail); + } else if (expected == CompareIC::HEAP_NUMBER) { + __ JumpIfSmi(input, &ok); + __ CompareMap(input, masm->isolate()->factory()->heap_number_map(), NULL); + __ j(not_equal, fail); + } + // We could be strict about symbol/string here, but as long as + // hydrogen doesn't care, the stub doesn't have to care either. + __ bind(&ok); +} + + +static void BranchIfNonSymbol(MacroAssembler* masm, + Label* label, + Register object, + Register scratch) { + __ JumpIfSmi(object, label); + __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset)); + __ movzxbq(scratch, + FieldOperand(scratch, Map::kInstanceTypeOffset)); + // Ensure that no non-strings have the symbol bit set. + STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); + STATIC_ASSERT(kSymbolTag != 0); + __ testb(scratch, Immediate(kIsSymbolMask)); + __ j(zero, label); +} + +void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { Label check_unequal_objects, done; + Condition cc = GetCondition(); Factory* factory = masm->isolate()->factory(); - // Compare two smis if required. - if (include_smi_compare_) { - Label non_smi, smi_done; - __ JumpIfNotBothSmi(rax, rdx, &non_smi); - __ subq(rdx, rax); - __ j(no_overflow, &smi_done); - __ not_(rdx); // Correct sign in case of overflow. rdx cannot be 0 here. - __ bind(&smi_done); - __ movq(rax, rdx); - __ ret(0); - __ bind(&non_smi); - } else if (FLAG_debug_code) { - Label ok; - __ JumpIfNotSmi(rdx, &ok); - __ JumpIfNotSmi(rax, &ok); - __ Abort("CompareStub: smi operands"); - __ bind(&ok); - } + Label miss; + CheckInputType(masm, rdx, left_, &miss); + CheckInputType(masm, rax, right_, &miss); + + // Compare two smis. + Label non_smi, smi_done; + __ JumpIfNotBothSmi(rax, rdx, &non_smi); + __ subq(rdx, rax); + __ j(no_overflow, &smi_done); + __ not_(rdx); // Correct sign in case of overflow. rdx cannot be 0 here. + __ bind(&smi_done); + __ movq(rax, rdx); + __ ret(0); + __ bind(&non_smi); // The compare stub returns a positive, negative, or zero 64-bit integer // value in rax, corresponding to result of comparing the two inputs. @@ -3412,66 +3435,58 @@ void CompareStub::Generate(MacroAssembler* masm) { __ cmpq(rax, rdx); __ j(not_equal, ¬_identical, Label::kNear); - if (cc_ != equal) { + if (cc != equal) { // Check for undefined. undefined OP undefined is false even though // undefined == undefined. Label check_for_nan; __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); __ j(not_equal, &check_for_nan, Label::kNear); - __ Set(rax, NegativeComparisonResult(cc_)); + __ Set(rax, NegativeComparisonResult(cc)); __ ret(0); __ bind(&check_for_nan); } // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), // so we do the second best thing - test it ourselves. - // Note: if cc_ != equal, never_nan_nan_ is not used. - // We cannot set rax to EQUAL until just before return because - // rax must be unchanged on jump to not_identical. - if (never_nan_nan_ && (cc_ == equal)) { - __ Set(rax, EQUAL); - __ ret(0); - } else { - Label heap_number; - // If it's not a heap number, then return equal for (in)equality operator. - __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), - factory->heap_number_map()); - __ j(equal, &heap_number, Label::kNear); - if (cc_ != equal) { - // Call runtime on identical objects. Otherwise return equal. - __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); - __ j(above_equal, ¬_identical, Label::kNear); - } - __ Set(rax, EQUAL); - __ ret(0); + Label heap_number; + // If it's not a heap number, then return equal for (in)equality operator. + __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), + factory->heap_number_map()); + __ j(equal, &heap_number, Label::kNear); + if (cc != equal) { + // Call runtime on identical objects. Otherwise return equal. + __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); + __ j(above_equal, ¬_identical, Label::kNear); + } + __ Set(rax, EQUAL); + __ ret(0); - __ bind(&heap_number); - // It is a heap number, so return equal if it's not NaN. - // For NaN, return 1 for every condition except greater and - // greater-equal. Return -1 for them, so the comparison yields - // false for all conditions except not-equal. - __ Set(rax, EQUAL); - __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); - __ ucomisd(xmm0, xmm0); - __ setcc(parity_even, rax); - // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs. - if (cc_ == greater_equal || cc_ == greater) { - __ neg(rax); - } - __ ret(0); + __ bind(&heap_number); + // It is a heap number, so return equal if it's not NaN. + // For NaN, return 1 for every condition except greater and + // greater-equal. Return -1 for them, so the comparison yields + // false for all conditions except not-equal. + __ Set(rax, EQUAL); + __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); + __ ucomisd(xmm0, xmm0); + __ setcc(parity_even, rax); + // rax is 0 for equal non-NaN heapnumbers, 1 for NaNs. + if (cc == greater_equal || cc == greater) { + __ neg(rax); } + __ ret(0); __ bind(¬_identical); } - if (cc_ == equal) { // Both strict and non-strict. + if (cc == equal) { // Both strict and non-strict. Label slow; // Fallthrough label. // If we're doing a strict equality comparison, we don't have to do // type conversion, so we generate code to do fast comparison for objects // and oddballs. Non-smi numbers and strings still go through the usual // slow-case code. - if (strict_) { + if (strict()) { // If either is a Smi (we know that not both are), then they can only // be equal if the other is a HeapNumber. If so, use the slow case. { @@ -3523,40 +3538,38 @@ void CompareStub::Generate(MacroAssembler* masm) { } // Generate the number comparison code. - if (include_number_compare_) { - Label non_number_comparison; - Label unordered; - FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); - __ xorl(rax, rax); - __ xorl(rcx, rcx); - __ ucomisd(xmm0, xmm1); - - // Don't base result on EFLAGS when a NaN is involved. - __ j(parity_even, &unordered, Label::kNear); - // Return a result of -1, 0, or 1, based on EFLAGS. - __ setcc(above, rax); - __ setcc(below, rcx); - __ subq(rax, rcx); - __ ret(0); + Label non_number_comparison; + Label unordered; + FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); + __ xorl(rax, rax); + __ xorl(rcx, rcx); + __ ucomisd(xmm0, xmm1); - // If one of the numbers was NaN, then the result is always false. - // The cc is never not-equal. - __ bind(&unordered); - ASSERT(cc_ != not_equal); - if (cc_ == less || cc_ == less_equal) { - __ Set(rax, 1); - } else { - __ Set(rax, -1); - } - __ ret(0); + // Don't base result on EFLAGS when a NaN is involved. + __ j(parity_even, &unordered, Label::kNear); + // Return a result of -1, 0, or 1, based on EFLAGS. + __ setcc(above, rax); + __ setcc(below, rcx); + __ subq(rax, rcx); + __ ret(0); - // The number comparison code did not provide a valid result. - __ bind(&non_number_comparison); + // If one of the numbers was NaN, then the result is always false. + // The cc is never not-equal. + __ bind(&unordered); + ASSERT(cc != not_equal); + if (cc == less || cc == less_equal) { + __ Set(rax, 1); + } else { + __ Set(rax, -1); } + __ ret(0); + + // The number comparison code did not provide a valid result. + __ bind(&non_number_comparison); // Fast negative check for symbol-to-symbol equality. Label check_for_strings; - if (cc_ == equal) { + if (cc == equal) { BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister); BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister); @@ -3572,7 +3585,7 @@ void CompareStub::Generate(MacroAssembler* masm) { rdx, rax, rcx, rbx, &check_unequal_objects); // Inline comparison of ASCII strings. - if (cc_ == equal) { + if (cc == equal) { StringCompareStub::GenerateFlatAsciiStringEquals(masm, rdx, rax, @@ -3593,7 +3606,7 @@ void CompareStub::Generate(MacroAssembler* masm) { #endif __ bind(&check_unequal_objects); - if (cc_ == equal && !strict_) { + if (cc == equal && !strict()) { // Not strict equality. Objects are unequal if // they are both JSObjects and not undetectable, // and their pointers are different. @@ -3633,11 +3646,11 @@ void CompareStub::Generate(MacroAssembler* masm) { // Figure out which native to call and setup the arguments. Builtins::JavaScript builtin; - if (cc_ == equal) { - builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; + if (cc == equal) { + builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; } else { builtin = Builtins::COMPARE; - __ Push(Smi::FromInt(NegativeComparisonResult(cc_))); + __ Push(Smi::FromInt(NegativeComparisonResult(cc))); } // Restore return address on the stack. @@ -3646,22 +3659,9 @@ void CompareStub::Generate(MacroAssembler* masm) { // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) // tagged as a small integer. __ InvokeBuiltin(builtin, JUMP_FUNCTION); -} - -void CompareStub::BranchIfNonSymbol(MacroAssembler* masm, - Label* label, - Register object, - Register scratch) { - __ JumpIfSmi(object, label); - __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset)); - __ movzxbq(scratch, - FieldOperand(scratch, Map::kInstanceTypeOffset)); - // Ensure that no non-strings have the symbol bit set. - STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); - STATIC_ASSERT(kSymbolTag != 0); - __ testb(scratch, Immediate(kIsSymbolMask)); - __ j(zero, label); + __ bind(&miss); + GenerateMiss(masm); } @@ -4419,44 +4419,6 @@ Register InstanceofStub::left() { return no_reg; } Register InstanceofStub::right() { return no_reg; } -int CompareStub::MinorKey() { - // Encode the three parameters in a unique 16 bit value. To avoid duplicate - // stubs the never NaN NaN condition is only taken into account if the - // condition is equals. - ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); - ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); - return ConditionField::encode(static_cast<unsigned>(cc_)) - | RegisterField::encode(false) // lhs_ and rhs_ are not used - | StrictField::encode(strict_) - | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) - | IncludeNumberCompareField::encode(include_number_compare_) - | IncludeSmiCompareField::encode(include_smi_compare_); -} - - -// Unfortunately you have to run without snapshots to see most of these -// names in the profile since most compare stubs end up in the snapshot. -void CompareStub::PrintName(StringStream* stream) { - ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); - const char* cc_name; - switch (cc_) { - case less: cc_name = "LT"; break; - case greater: cc_name = "GT"; break; - case less_equal: cc_name = "LE"; break; - case greater_equal: cc_name = "GE"; break; - case equal: cc_name = "EQ"; break; - case not_equal: cc_name = "NE"; break; - default: cc_name = "UnknownCondition"; break; - } - bool is_equality = cc_ == equal || cc_ == not_equal; - stream->Add("CompareStub_%s", cc_name); - if (strict_ && is_equality) stream->Add("_STRICT"); - if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); - if (!include_number_compare_) stream->Add("_NO_NUMBER"); - if (!include_smi_compare_) stream->Add("_NO_SMI"); -} - - // ------------------------------------------------------------------------- // StringCharCodeAtGenerator @@ -4694,8 +4656,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { &call_runtime); // Get the two characters forming the sub string. - __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); - __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); + __ movzxbq(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); + __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); // Try to lookup two character string in symbol table. If it is not found // just allocate a new one. @@ -4711,11 +4673,11 @@ void StringAddStub::Generate(MacroAssembler* masm) { // rbx - first byte: first character // rbx - second byte: *maybe* second character // Make sure that the second byte of rbx contains the second character. - __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); + __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); __ shll(rcx, Immediate(kBitsPerByte)); __ orl(rbx, rcx); // Write both characters to the new string. - __ movw(FieldOperand(rax, SeqAsciiString::kHeaderSize), rbx); + __ movw(FieldOperand(rax, SeqOneByteString::kHeaderSize), rbx); __ IncrementCounter(counters->string_add_native(), 1); __ ret(2 * kPointerSize); @@ -4738,7 +4700,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { Label non_ascii, allocated, ascii_data; __ movl(rcx, r8); __ and_(rcx, r9); - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ testl(rcx, Immediate(kStringEncodingMask)); __ j(zero, &non_ascii); @@ -4763,11 +4725,6 @@ void StringAddStub::Generate(MacroAssembler* masm) { // r9: second instance type. __ testb(rcx, Immediate(kAsciiDataHintMask)); __ j(not_zero, &ascii_data); - __ xor_(r8, r9); - STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); - __ andb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); - __ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag)); - __ j(equal, &ascii_data); // Allocate a two byte cons string. __ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime); __ jmp(&allocated); @@ -4797,8 +4754,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ movq(rcx, FieldOperand(rax, ExternalString::kResourceDataOffset)); __ jmp(&first_prepared, Label::kNear); __ bind(&first_is_sequential); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ lea(rcx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); + __ lea(rcx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); __ bind(&first_prepared); // Check whether both strings have same encoding. @@ -4818,8 +4775,8 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ movq(rdx, FieldOperand(rdx, ExternalString::kResourceDataOffset)); __ jmp(&second_prepared, Label::kNear); __ bind(&second_is_sequential); - STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ lea(rdx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); + STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); + __ lea(rdx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); __ bind(&second_prepared); Label non_ascii_string_add_flat_result; @@ -4835,7 +4792,7 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime); // rax: result string // Locate first character of result. - __ lea(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); + __ lea(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); // rcx: first char of first string // rbx: first character of result // r14: length of first string @@ -5108,7 +5065,7 @@ void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, temp, temp, &next_probe[i]); // Check if the two characters match. - __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); + __ movl(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize)); __ andl(temp, Immediate(0x0000ffff)); __ cmpl(chars, temp); __ j(equal, &found_in_symbol_table); @@ -5286,7 +5243,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { // string's encoding is wrong because we always have to recheck encoding of // the newly created string's parent anyways due to externalized strings. Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ testb(rbx, Immediate(kStringEncodingMask)); __ j(zero, &two_byte_slice, Label::kNear); @@ -5326,11 +5283,11 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ j(not_zero, &runtime); __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); __ bind(&sequential_string); - STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); + STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); __ testb(rbx, Immediate(kStringEncodingMask)); __ j(zero, &two_byte_sequential); @@ -5343,10 +5300,10 @@ void SubStringStub::Generate(MacroAssembler* masm) { { // Locate character of sub string start. SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1); __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, - SeqAsciiString::kHeaderSize - kHeapObjectTag)); + SeqOneByteString::kHeaderSize - kHeapObjectTag)); } // Locate first character of result. - __ lea(rdi, FieldOperand(rax, SeqAsciiString::kHeaderSize)); + __ lea(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); // rax: result string // rcx: result length @@ -5368,7 +5325,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { { // Locate character of sub string start. SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2); __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, - SeqAsciiString::kHeaderSize - kHeapObjectTag)); + SeqOneByteString::kHeaderSize - kHeapObjectTag)); } // Locate first character of result. __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); @@ -5508,9 +5465,9 @@ void StringCompareStub::GenerateAsciiCharsCompareLoop( // doesn't need an additional compare. __ SmiToInteger32(length, length); __ lea(left, - FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); + FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize)); __ lea(right, - FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); + FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize)); __ neg(length); Register index = length; // index = -length; @@ -5566,7 +5523,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) { void ICCompareStub::GenerateSmis(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::SMIS); + ASSERT(state_ == CompareIC::SMI); Label miss; __ JumpIfNotBothSmi(rdx, rax, &miss, Label::kNear); @@ -5578,7 +5535,7 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) { __ subq(rdx, rax); __ j(no_overflow, &done, Label::kNear); // Correct sign of result in case of overflow. - __ SmiNot(rdx, rdx); + __ not_(rdx); __ bind(&done); __ movq(rax, rdx); } @@ -5590,23 +5547,41 @@ void ICCompareStub::GenerateSmis(MacroAssembler* masm) { void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::HEAP_NUMBERS); + ASSERT(state_ == CompareIC::HEAP_NUMBER); Label generic_stub; Label unordered, maybe_undefined1, maybe_undefined2; Label miss; - Condition either_smi = masm->CheckEitherSmi(rax, rdx); - __ j(either_smi, &generic_stub, Label::kNear); - __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx); + if (left_ == CompareIC::SMI) { + __ JumpIfNotSmi(rdx, &miss); + } + if (right_ == CompareIC::SMI) { + __ JumpIfNotSmi(rax, &miss); + } + + // Load left and right operand. + Label done, left, left_smi, right_smi; + __ JumpIfSmi(rax, &right_smi, Label::kNear); + __ CompareMap(rax, masm->isolate()->factory()->heap_number_map(), NULL); __ j(not_equal, &maybe_undefined1, Label::kNear); - __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); + __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); + __ jmp(&left, Label::kNear); + __ bind(&right_smi); + __ SmiToInteger32(rcx, rax); // Can't clobber rax yet. + __ cvtlsi2sd(xmm1, rcx); + + __ bind(&left); + __ JumpIfSmi(rdx, &left_smi, Label::kNear); + __ CompareMap(rdx, masm->isolate()->factory()->heap_number_map(), NULL); __ j(not_equal, &maybe_undefined2, Label::kNear); - - // Load left and right operand __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); - __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); + __ jmp(&done); + __ bind(&left_smi); + __ SmiToInteger32(rcx, rdx); // Can't clobber rdx yet. + __ cvtlsi2sd(xmm0, rcx); + __ bind(&done); // Compare operands __ ucomisd(xmm0, xmm1); @@ -5622,14 +5597,16 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { __ ret(0); __ bind(&unordered); - CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); __ bind(&generic_stub); + ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC, + CompareIC::GENERIC); __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); __ bind(&maybe_undefined1); if (Token::IsOrderedRelationalCompareOp(op_)) { __ Cmp(rax, masm->isolate()->factory()->undefined_value()); __ j(not_equal, &miss); + __ JumpIfSmi(rdx, &unordered); __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); __ j(not_equal, &maybe_undefined2, Label::kNear); __ jmp(&unordered); @@ -5647,7 +5624,7 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::SYMBOLS); + ASSERT(state_ == CompareIC::SYMBOL); ASSERT(GetCondition() == equal); // Registers containing left and right operands respectively. @@ -5690,7 +5667,7 @@ void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { void ICCompareStub::GenerateStrings(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::STRINGS); + ASSERT(state_ == CompareIC::STRING); Label miss; bool equality = Token::IsEqualityOp(op_); @@ -5776,7 +5753,7 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) { void ICCompareStub::GenerateObjects(MacroAssembler* masm) { - ASSERT(state_ == CompareIC::OBJECTS); + ASSERT(state_ == CompareIC::OBJECT); Label miss; Condition either_smi = masm->CheckEitherSmi(rdx, rax); __ j(either_smi, &miss, Label::kNear); @@ -5922,8 +5899,7 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, ASSERT(!name.is(r0)); ASSERT(!name.is(r1)); - // Assert that name contains a string. - if (FLAG_debug_code) __ AbortIfNotString(name); + __ AssertString(name); __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); __ decl(r0); @@ -6137,6 +6113,11 @@ void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { } +bool CodeStub::CanUseFPRegisters() { + return true; // Always have SSE2 on x64. +} + + // Takes the input in 3 registers: address_ value_ and object_. A pointer to // the value has just been written into the object, now this stub makes sure // we keep the GC informed. The word in the object where the value has been @@ -6233,13 +6214,8 @@ void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { ASSERT(!address.is(arg1)); __ Move(address, regs_.address()); __ Move(arg1, regs_.object()); - if (mode == INCREMENTAL_COMPACTION) { - // TODO(gc) Can we just set address arg2 in the beginning? - __ Move(arg2, address); - } else { - ASSERT(mode == INCREMENTAL); - __ movq(arg2, Operand(address, 0)); - } + // TODO(gc) Can we just set address arg2 in the beginning? + __ Move(arg2, address); __ LoadAddress(arg3, ExternalReference::isolate_address()); int argument_count = 3; @@ -6269,6 +6245,17 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker( Label need_incremental; Label need_incremental_pop_object; + __ movq(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask)); + __ and_(regs_.scratch0(), regs_.object()); + __ movq(regs_.scratch1(), + Operand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset)); + __ subq(regs_.scratch1(), Immediate(1)); + __ movq(Operand(regs_.scratch0(), + MemoryChunk::kWriteBarrierCounterOffset), + regs_.scratch1()); + __ j(negative, &need_incremental); + // Let's look at the color of the object: If it is not black we don't have // to inform the incremental marker. __ JumpIfBlack(regs_.object(), diff --git a/deps/v8/src/x64/code-stubs-x64.h b/deps/v8/src/x64/code-stubs-x64.h index 6a1a18f830..ab8ea76c8f 100644 --- a/deps/v8/src/x64/code-stubs-x64.h +++ b/deps/v8/src/x64/code-stubs-x64.h @@ -79,13 +79,6 @@ class StoreBufferOverflowStub: public CodeStub { }; -// Flag that indicates how to generate code for the stub GenericBinaryOpStub. -enum GenericBinaryFlags { - NO_GENERIC_BINARY_FLAGS = 0, - NO_SMI_CODE_IN_STUB = 1 << 0 // Omit smi code in stub. -}; - - class UnaryOpStub: public CodeStub { public: UnaryOpStub(Token::Value op, @@ -157,95 +150,6 @@ class UnaryOpStub: public CodeStub { }; -class BinaryOpStub: public CodeStub { - public: - BinaryOpStub(Token::Value op, OverwriteMode mode) - : op_(op), - mode_(mode), - operands_type_(BinaryOpIC::UNINITIALIZED), - result_type_(BinaryOpIC::UNINITIALIZED) { - ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); - } - - BinaryOpStub( - int key, - BinaryOpIC::TypeInfo operands_type, - BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED) - : op_(OpBits::decode(key)), - mode_(ModeBits::decode(key)), - operands_type_(operands_type), - result_type_(result_type) { } - - private: - enum SmiCodeGenerateHeapNumberResults { - ALLOW_HEAPNUMBER_RESULTS, - NO_HEAPNUMBER_RESULTS - }; - - Token::Value op_; - OverwriteMode mode_; - - // Operand type information determined at runtime. - BinaryOpIC::TypeInfo operands_type_; - BinaryOpIC::TypeInfo result_type_; - - virtual void PrintName(StringStream* stream); - - // Minor key encoding in 15 bits RRRTTTOOOOOOOMM. - class ModeBits: public BitField<OverwriteMode, 0, 2> {}; - class OpBits: public BitField<Token::Value, 2, 7> {}; - class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 9, 3> {}; - class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 12, 3> {}; - - Major MajorKey() { return BinaryOp; } - int MinorKey() { - return OpBits::encode(op_) - | ModeBits::encode(mode_) - | OperandTypeInfoBits::encode(operands_type_) - | ResultTypeInfoBits::encode(result_type_); - } - - void Generate(MacroAssembler* masm); - void GenerateGeneric(MacroAssembler* masm); - void GenerateSmiCode(MacroAssembler* masm, - Label* slow, - SmiCodeGenerateHeapNumberResults heapnumber_results); - void GenerateFloatingPointCode(MacroAssembler* masm, - Label* allocation_failure, - Label* non_numeric_failure); - void GenerateStringAddCode(MacroAssembler* masm); - void GenerateCallRuntimeCode(MacroAssembler* masm); - void GenerateLoadArguments(MacroAssembler* masm); - void GenerateReturn(MacroAssembler* masm); - void GenerateUninitializedStub(MacroAssembler* masm); - void GenerateSmiStub(MacroAssembler* masm); - void GenerateInt32Stub(MacroAssembler* masm); - void GenerateHeapNumberStub(MacroAssembler* masm); - void GenerateOddballStub(MacroAssembler* masm); - void GenerateStringStub(MacroAssembler* masm); - void GenerateBothStringStub(MacroAssembler* masm); - void GenerateGenericStub(MacroAssembler* masm); - - void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure); - void GenerateRegisterArgsPush(MacroAssembler* masm); - void GenerateTypeTransition(MacroAssembler* masm); - void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); - - virtual int GetCodeKind() { return Code::BINARY_OP_IC; } - - virtual InlineCacheState GetICState() { - return BinaryOpIC::ToState(operands_type_); - } - - virtual void FinishCode(Handle<Code> code) { - code->set_binary_op_type(operands_type_); - code->set_binary_op_result_type(result_type_); - } - - friend class CodeGenerator; -}; - - class StringHelper : public AllStatic { public: // Generate code for copying characters using a simple loop. This should only diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index 2924810c1e..7954604e99 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -99,6 +99,36 @@ UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { } +UnaryMathFunction CreateExpFunction() { + if (!FLAG_fast_math) return &exp; + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == NULL) return &exp; + ExternalReference::InitializeMathExpData(); + + MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); + // xmm0: raw double input. + XMMRegister input = xmm0; + XMMRegister result = xmm1; + __ push(rax); + __ push(rbx); + + MathExpGenerator::EmitMathExp(&masm, input, result, xmm2, rax, rbx); + + __ pop(rbx); + __ pop(rax); + __ movsd(xmm0, result); + __ Ret(); + + CodeDesc desc; + masm.GetCode(&desc); + + CPU::FlushICache(buffer, actual_size); + OS::ProtectCode(buffer, actual_size); + return FUNCTION_CAST<UnaryMathFunction>(buffer); +} + + UnaryMathFunction CreateSqrtFunction() { size_t actual_size; // Allocate buffer in executable space. @@ -551,7 +581,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, // Dispatch on the encoding: ASCII or two-byte. Label ascii; __ bind(&seq_string); - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ testb(result, Immediate(kStringEncodingMask)); __ j(not_zero, &ascii, Label::kNear); @@ -571,12 +601,167 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, __ movzxbl(result, FieldOperand(string, index, times_1, - SeqAsciiString::kHeaderSize)); + SeqOneByteString::kHeaderSize)); + __ bind(&done); +} + + +void SeqStringSetCharGenerator::Generate(MacroAssembler* masm, + String::Encoding encoding, + Register string, + Register index, + Register value) { + if (FLAG_debug_code) { + __ Check(masm->CheckSmi(index), "Non-smi index"); + __ Check(masm->CheckSmi(value), "Non-smi value"); + + __ SmiCompare(index, FieldOperand(string, String::kLengthOffset)); + __ Check(less, "Index is too large"); + + __ SmiCompare(index, Smi::FromInt(0)); + __ Check(greater_equal, "Index is negative"); + + __ push(value); + __ movq(value, FieldOperand(string, HeapObject::kMapOffset)); + __ movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset)); + + __ andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask)); + static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; + static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; + __ cmpq(value, Immediate(encoding == String::ONE_BYTE_ENCODING + ? one_byte_seq_type : two_byte_seq_type)); + __ Check(equal, "Unexpected string type"); + __ pop(value); + } + + __ SmiToInteger32(value, value); + __ SmiToInteger32(index, index); + if (encoding == String::ONE_BYTE_ENCODING) { + __ movb(FieldOperand(string, index, times_1, SeqString::kHeaderSize), + value); + } else { + __ movw(FieldOperand(string, index, times_2, SeqString::kHeaderSize), + value); + } +} + + +void MathExpGenerator::EmitMathExp(MacroAssembler* masm, + XMMRegister input, + XMMRegister result, + XMMRegister double_scratch, + Register temp1, + Register temp2) { + ASSERT(!input.is(result)); + ASSERT(!input.is(double_scratch)); + ASSERT(!result.is(double_scratch)); + ASSERT(!temp1.is(temp2)); + ASSERT(ExternalReference::math_exp_constants(0).address() != NULL); + + Label done; + + __ movq(kScratchRegister, ExternalReference::math_exp_constants(0)); + __ movsd(double_scratch, Operand(kScratchRegister, 0 * kDoubleSize)); + __ xorpd(result, result); + __ ucomisd(double_scratch, input); + __ j(above_equal, &done); + __ ucomisd(input, Operand(kScratchRegister, 1 * kDoubleSize)); + __ movsd(result, Operand(kScratchRegister, 2 * kDoubleSize)); + __ j(above_equal, &done); + __ movsd(double_scratch, Operand(kScratchRegister, 3 * kDoubleSize)); + __ movsd(result, Operand(kScratchRegister, 4 * kDoubleSize)); + __ mulsd(double_scratch, input); + __ addsd(double_scratch, result); + __ movq(temp2, double_scratch); + __ subsd(double_scratch, result); + __ movsd(result, Operand(kScratchRegister, 6 * kDoubleSize)); + __ lea(temp1, Operand(temp2, 0x1ff800)); + __ and_(temp2, Immediate(0x7ff)); + __ shr(temp1, Immediate(11)); + __ mulsd(double_scratch, Operand(kScratchRegister, 5 * kDoubleSize)); + __ movq(kScratchRegister, ExternalReference::math_exp_log_table()); + __ shl(temp1, Immediate(52)); + __ or_(temp1, Operand(kScratchRegister, temp2, times_8, 0)); + __ movq(kScratchRegister, ExternalReference::math_exp_constants(0)); + __ subsd(double_scratch, input); + __ movsd(input, double_scratch); + __ subsd(result, double_scratch); + __ mulsd(input, double_scratch); + __ mulsd(result, input); + __ movq(input, temp1); + __ mulsd(result, Operand(kScratchRegister, 7 * kDoubleSize)); + __ subsd(result, double_scratch); + __ addsd(result, Operand(kScratchRegister, 8 * kDoubleSize)); + __ mulsd(result, input); + __ bind(&done); } #undef __ + +static const int kNoCodeAgeSequenceLength = 6; + +static byte* GetNoCodeAgeSequence(uint32_t* length) { + static bool initialized = false; + static byte sequence[kNoCodeAgeSequenceLength]; + *length = kNoCodeAgeSequenceLength; + if (!initialized) { + // The sequence of instructions that is patched out for aging code is the + // following boilerplate stack-building prologue that is found both in + // FUNCTION and OPTIMIZED_FUNCTION code: + CodePatcher patcher(sequence, kNoCodeAgeSequenceLength); + patcher.masm()->push(rbp); + patcher.masm()->movq(rbp, rsp); + patcher.masm()->push(rsi); + patcher.masm()->push(rdi); + initialized = true; + } + return sequence; +} + + +bool Code::IsYoungSequence(byte* sequence) { + uint32_t young_length; + byte* young_sequence = GetNoCodeAgeSequence(&young_length); + bool result = (!memcmp(sequence, young_sequence, young_length)); + ASSERT(result || *sequence == kCallOpcode); + return result; +} + + +void Code::GetCodeAgeAndParity(byte* sequence, Age* age, + MarkingParity* parity) { + if (IsYoungSequence(sequence)) { + *age = kNoAge; + *parity = NO_MARKING_PARITY; + } else { + sequence++; // Skip the kCallOpcode byte + Address target_address = sequence + *reinterpret_cast<int*>(sequence) + + Assembler::kCallTargetAddressOffset; + Code* stub = GetCodeFromTargetAddress(target_address); + GetCodeAgeAndParity(stub, age, parity); + } +} + + +void Code::PatchPlatformCodeAge(byte* sequence, + Code::Age age, + MarkingParity parity) { + uint32_t young_length; + byte* young_sequence = GetNoCodeAgeSequence(&young_length); + if (age == kNoAge) { + memcpy(sequence, young_sequence, young_length); + CPU::FlushICache(sequence, young_length); + } else { + Code* stub = GetCodeAgeStub(age, parity); + CodePatcher patcher(sequence, young_length); + patcher.masm()->call(stub->instruction_start()); + patcher.masm()->nop(); + } +} + + } } // namespace v8::internal #endif // V8_TARGET_ARCH_X64 diff --git a/deps/v8/src/x64/codegen-x64.h b/deps/v8/src/x64/codegen-x64.h index 2e80751033..d444095213 100644 --- a/deps/v8/src/x64/codegen-x64.h +++ b/deps/v8/src/x64/codegen-x64.h @@ -39,7 +39,6 @@ class CompilationInfo; enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; - // ------------------------------------------------------------------------- // CodeGenerator @@ -84,6 +83,20 @@ class StringCharLoadGenerator : public AllStatic { DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator); }; + +class MathExpGenerator : public AllStatic { + public: + static void EmitMathExp(MacroAssembler* masm, + XMMRegister input, + XMMRegister result, + XMMRegister double_scratch, + Register temp1, + Register temp2); + + private: + DISALLOW_COPY_AND_ASSIGN(MathExpGenerator); +}; + } } // namespace v8::internal #endif // V8_X64_CODEGEN_X64_H_ diff --git a/deps/v8/src/x64/deoptimizer-x64.cc b/deps/v8/src/x64/deoptimizer-x64.cc index 0502502ab0..c8fdfce26b 100644 --- a/deps/v8/src/x64/deoptimizer-x64.cc +++ b/deps/v8/src/x64/deoptimizer-x64.cc @@ -104,19 +104,7 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { // ignore all slots that might have been recorded on it. isolate->heap()->mark_compact_collector()->InvalidateCode(code); - // Iterate over all the functions which share the same code object - // and make them use unoptimized version. - Context* context = function->context()->native_context(); - Object* element = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); - SharedFunctionInfo* shared = function->shared(); - while (!element->IsUndefined()) { - JSFunction* func = JSFunction::cast(element); - // Grab element before code replacement as ReplaceCode alters the list. - element = func->next_function_link(); - if (func->code() == code) { - func->ReplaceCode(shared->code()); - } - } + ReplaceCodeForRelatedFunctions(function, code); if (FLAG_trace_deopt) { PrintF("[forced deoptimization: "); @@ -128,8 +116,6 @@ 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; @@ -141,31 +127,26 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, Address call_target_address = pc_after - kIntSize; ASSERT_EQ(check_code->entry(), Assembler::target_address_at(call_target_address)); - // The stack check code matches the pattern: + // The back edge bookkeeping code matches the pattern: // - // cmp rsp, <limit> - // jae ok + // add <profiling_counter>, <-delta> + // jns ok // call <stack guard> // test rax, <loop nesting depth> // ok: ... // // We will patch away the branch so the code is: // - // cmp rsp, <limit> ;; Not changed + // add <profiling_counter>, <-delta> ;; Not changed // nop // nop // call <on-stack replacment> // test rax, <loop nesting depth> // ok: // - 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)); + ASSERT_EQ(kJnsInstruction, *(call_target_address - 3)); + ASSERT_EQ(kJnsOffset, *(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, @@ -188,13 +169,8 @@ void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code, 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; - } + *(call_target_address - 3) = kJnsInstruction; + *(call_target_address - 2) = kJnsOffset; Assembler::set_target_address_at(call_target_address, check_code->entry()); diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index 78e1dec513..68773e96e2 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -119,7 +119,7 @@ void FullCodeGenerator::Generate() { handler_table_ = isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell( - Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget))); + Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); @@ -152,6 +152,7 @@ void FullCodeGenerator::Generate() { // the frame (that is done below). FrameScope frame_scope(masm_, StackFrame::MANUAL); + info->set_prologue_offset(masm_->pc_offset()); __ push(rbp); // Caller's frame pointer. __ movq(rbp, rsp); __ push(rsi); // Callee's context. @@ -324,34 +325,27 @@ void FullCodeGenerator::EmitProfilingCounterReset() { } -void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, - Label* back_edge_target) { - Comment cmnt(masm_, "[ Stack check"); +void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, + Label* back_edge_target) { + Comment cmnt(masm_, "[ Back edge bookkeeping"); Label ok; - 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 / kBackEdgeDistanceUnit)); - } - 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); + 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 / kBackEdgeDistanceUnit)); } + EmitProfilingCounterDecrement(weight); + __ j(positive, &ok, Label::kNear); + InterruptStub 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. - RecordStackCheck(stmt->OsrEntryId()); + RecordBackEdge(stmt->OsrEntryId()); // Loop stack checks can be patched to perform on-stack replacement. In // order to decide whether or not to perform OSR we embed the loop depth @@ -360,9 +354,7 @@ void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt, ASSERT(loop_depth() > 0); __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker))); - if (FLAG_count_based_interrupts) { - EmitProfilingCounterReset(); - } + EmitProfilingCounterReset(); __ bind(&ok); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); @@ -759,8 +751,7 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { - // The variable in the declaration always resides in the current function - // context. + // The variable in the declaration always resides in the current context. ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); if (generate_debug_code_) { // Check that we're not inside a with or catch context. @@ -891,33 +882,32 @@ void FullCodeGenerator::VisitFunctionDeclaration( void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { - VariableProxy* proxy = declaration->proxy(); - Variable* variable = proxy->var(); - Handle<JSModule> instance = declaration->module()->interface()->Instance(); - ASSERT(!instance.is_null()); + Variable* variable = declaration->proxy()->var(); + ASSERT(variable->location() == Variable::CONTEXT); + ASSERT(variable->interface()->IsFrozen()); - switch (variable->location()) { - case Variable::UNALLOCATED: { - Comment cmnt(masm_, "[ ModuleDeclaration"); - globals_->Add(variable->name(), zone()); - globals_->Add(instance, zone()); - Visit(declaration->module()); - break; - } + Comment cmnt(masm_, "[ ModuleDeclaration"); + EmitDebugCheckDeclarationContext(variable); - case Variable::CONTEXT: { - Comment cmnt(masm_, "[ ModuleDeclaration"); - EmitDebugCheckDeclarationContext(variable); - __ Move(ContextOperand(rsi, variable->index()), instance); - Visit(declaration->module()); - break; - } + // Load instance object. + __ LoadContext(rax, scope_->ContextChainLength(scope_->GlobalScope())); + __ movq(rax, ContextOperand(rax, variable->interface()->Index())); + __ movq(rax, ContextOperand(rax, Context::EXTENSION_INDEX)); - case Variable::PARAMETER: - case Variable::LOCAL: - case Variable::LOOKUP: - UNREACHABLE(); - } + // Assign it. + __ movq(ContextOperand(rsi, variable->index()), rax); + // We know that we have written a module, which is not a smi. + __ RecordWriteContextSlot(rsi, + Context::SlotOffset(variable->index()), + rax, + rcx, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS); + + // Traverse into body. + Visit(declaration->module()); } @@ -959,6 +949,14 @@ void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { } +void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) { + // Call the runtime to declare the modules. + __ Push(descriptions); + __ CallRuntime(Runtime::kDeclareModules, 1); + // Return value is ignored. +} + + void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { Comment cmnt(masm_, "[ SwitchStatement"); Breakable nested_statement(this, stmt); @@ -1214,7 +1212,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ bind(loop_statement.continue_label()); __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1)); - EmitStackCheck(stmt, &loop); + EmitBackEdgeBookkeeping(stmt, &loop); __ jmp(&loop); // Remove the pointers stored on the stack. @@ -1368,9 +1366,9 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, } else if (var->mode() == DYNAMIC_LOCAL) { Variable* local = var->local_if_not_shadowed(); __ movq(rax, ContextSlotOperandCheckExtensions(local, slow)); - if (local->mode() == CONST || - local->mode() == CONST_HARMONY || - local->mode() == LET) { + if (local->mode() == LET || + local->mode() == CONST || + local->mode() == CONST_HARMONY) { __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); __ j(not_equal, done); if (local->mode() == CONST) { @@ -2118,37 +2116,15 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { ASSERT(prop != NULL); ASSERT(prop->key()->AsLiteral() != NULL); - // If the assignment starts a block of assignments to the same object, - // change to slow case to avoid the quadratic behavior of repeatedly - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - // Record source code position before IC call. SetSourcePosition(expr->position()); __ Move(rcx, prop->key()->AsLiteral()->handle()); - if (expr->ends_initialization_block()) { - __ movq(rdx, Operand(rsp, 0)); - } else { - __ pop(rdx); - } + __ pop(rdx); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ push(rax); // Result of assignment, saved even if not needed. - __ push(Operand(rsp, kPointerSize)); // Receiver is under value. - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(rax); - __ Drop(1); - } PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(rax); } @@ -2157,23 +2133,8 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { // Assignment to a property, using a keyed store IC. - // If the assignment starts a block of assignments to the same object, - // change to slow case to avoid the quadratic behavior of repeatedly - // adding fast properties. - if (expr->starts_initialization_block()) { - __ push(result_register()); - // Receiver is now under the key and value. - __ push(Operand(rsp, 2 * kPointerSize)); - __ CallRuntime(Runtime::kToSlowProperties, 1); - __ pop(result_register()); - } - __ pop(rcx); - if (expr->ends_initialization_block()) { - __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later. - } else { - __ pop(rdx); - } + __ pop(rdx); // Record source code position before IC call. SetSourcePosition(expr->position()); Handle<Code> ic = is_classic_mode() @@ -2181,15 +2142,6 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId()); - // If the assignment ends an initialization block, revert to fast case. - if (expr->ends_initialization_block()) { - __ pop(rdx); - __ push(rax); // Result of assignment, saved even if not needed. - __ push(rdx); - __ CallRuntime(Runtime::kToFastProperties, 1); - __ pop(rax); - } - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(rax); } @@ -2346,7 +2298,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { VariableProxy* proxy = callee->AsVariableProxy(); Property* property = callee->AsProperty(); - if (proxy != NULL && proxy->var()->is_possibly_eval()) { + if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { // In a call to eval, we first call %ResolvePossiblyDirectEval to // resolve the function we need to call and the receiver of the call. // Then we call the resolved function using the given arguments. @@ -2626,7 +2578,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - if (generate_debug_code_) __ AbortIfSmi(rax); + __ AssertNotSmi(rax); // Check whether this map has already been checked to be safe for default // valueOf. @@ -2642,22 +2594,28 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ j(equal, if_false); // Look for valueOf symbol in the descriptor array, and indicate false if - // found. The type is not checked, so if it is a transition it is a false - // negative. + // found. Since we omit an enumeration index check, if it is added via a + // transition that shares its descriptor array, this is a false positive. + Label entry, loop, done; + + // Skip loop if no descriptors are valid. + __ NumberOfOwnDescriptors(rcx, rbx); + __ cmpq(rcx, Immediate(0)); + __ j(equal, &done); + __ LoadInstanceDescriptors(rbx, rbx); - __ movq(rcx, FieldOperand(rbx, FixedArray::kLengthOffset)); - // rbx: descriptor array - // rcx: length of descriptor array + // rbx: descriptor array. + // rcx: valid entries in the descriptor array. // Calculate the end of the descriptor array. + __ imul(rcx, rcx, Immediate(DescriptorArray::kDescriptorSize)); SmiIndex index = masm_->SmiToIndex(rdx, rcx, kPointerSizeLog2); __ lea(rcx, Operand( - rbx, index.reg, index.scale, FixedArray::kHeaderSize)); + rbx, index.reg, index.scale, DescriptorArray::kFirstOffset)); // Calculate location of the first key name. __ addq(rbx, Immediate(DescriptorArray::kFirstOffset)); // Loop through all the keys in the descriptor array. If one of these is the // symbol valueOf the result is false. - Label entry, loop; __ jmp(&entry); __ bind(&loop); __ movq(rdx, FieldOperand(rbx, 0)); @@ -2668,10 +2626,11 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ cmpq(rbx, rcx); __ j(not_equal, &loop); + __ bind(&done); // Reload map as register rbx was used as temporary above. __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); - // If a valueOf property is not found on the object check that it's + // If a valueOf property is not found on the object check that its // prototype is the un-modified String prototype. If not result is false. __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset)); __ testq(rcx, Immediate(kSmiTagMask)); @@ -2848,7 +2807,7 @@ void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); __ bind(&exit); - if (generate_debug_code_) __ AbortIfNotSmi(rax); + __ AssertSmi(rax); context()->Plug(rax); } @@ -3079,6 +3038,38 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) { } +void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { + ZoneList<Expression*>* args = expr->arguments(); + ASSERT_EQ(3, args->length()); + + VisitForStackValue(args->at(1)); // index + VisitForStackValue(args->at(2)); // value + __ pop(rcx); + __ pop(rbx); + VisitForAccumulatorValue(args->at(0)); // string + + static const String::Encoding encoding = String::ONE_BYTE_ENCODING; + SeqStringSetCharGenerator::Generate(masm_, encoding, rax, rbx, rcx); + context()->Plug(rax); +} + + +void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { + ZoneList<Expression*>* args = expr->arguments(); + ASSERT_EQ(3, args->length()); + + VisitForStackValue(args->at(1)); // index + VisitForStackValue(args->at(2)); // value + __ pop(rcx); + __ pop(rbx); + VisitForAccumulatorValue(args->at(0)); // string + + static const String::Encoding encoding = String::TWO_BYTE_ENCODING; + SeqStringSetCharGenerator::Generate(masm_, encoding, rax, rbx, rcx); + context()->Plug(rax); +} + + void FullCodeGenerator::EmitMathPow(CallRuntime* expr) { // Load the arguments on the stack and call the runtime function. ZoneList<Expression*>* args = expr->arguments(); @@ -3498,7 +3489,7 @@ void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) { ASSERT(args->length() == 1); VisitForAccumulatorValue(args->at(0)); - __ AbortIfNotString(rax); + __ AssertString(rax); __ movl(rax, FieldOperand(rax, String::kHashFieldOffset)); ASSERT(String::kHashShift >= kSmiTagSize); @@ -3590,10 +3581,10 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); __ andb(scratch, Immediate( kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); - __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag)); + __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag)); __ j(not_equal, &bailout); __ AddSmiField(string_length, - FieldOperand(string, SeqAsciiString::kLengthOffset)); + FieldOperand(string, SeqOneByteString::kLengthOffset)); __ j(overflow, &bailout); __ incl(index); __ cmpl(index, array_length); @@ -3629,7 +3620,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); __ andb(scratch, Immediate( kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); - __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag)); + __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag)); __ j(not_equal, &bailout); // Live registers: @@ -3640,7 +3631,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { // Add (separator length times (array_length - 1)) to string_length. __ SmiToInteger32(scratch, - FieldOperand(string, SeqAsciiString::kLengthOffset)); + FieldOperand(string, SeqOneByteString::kLengthOffset)); __ decl(index); __ imull(scratch, index); __ j(overflow, &bailout); @@ -3653,10 +3644,10 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ AllocateAsciiString(result_pos, string_length, scratch, index, string, &bailout); __ movq(result_operand, result_pos); - __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize)); + __ lea(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize)); __ movq(string, separator_operand); - __ SmiCompare(FieldOperand(string, SeqAsciiString::kLengthOffset), + __ SmiCompare(FieldOperand(string, SeqOneByteString::kLengthOffset), Smi::FromInt(1)); __ j(equal, &one_char_separator); __ j(greater, &long_separator); @@ -3682,7 +3673,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ SmiToInteger32(string_length, FieldOperand(string, String::kLengthOffset)); __ lea(string, - FieldOperand(string, SeqAsciiString::kHeaderSize)); + FieldOperand(string, SeqOneByteString::kHeaderSize)); __ CopyBytes(result_pos, string, string_length); __ incl(index); __ bind(&loop_1_condition); @@ -3700,7 +3691,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ bind(&one_char_separator); // Get the separator ASCII character value. // Register "string" holds the separator. - __ movzxbl(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize)); + __ movzxbl(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize)); __ Set(index, 0); // Jump into the loop after the code that copies the separator, so the first // element is not preceded by a separator @@ -3726,7 +3717,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ SmiToInteger32(string_length, FieldOperand(string, String::kLengthOffset)); __ lea(string, - FieldOperand(string, SeqAsciiString::kHeaderSize)); + FieldOperand(string, SeqOneByteString::kHeaderSize)); __ CopyBytes(result_pos, string, string_length); __ incl(index); __ cmpl(index, array_length_operand); @@ -3751,7 +3742,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ SmiToInteger32(scratch, FieldOperand(string, String::kLengthOffset)); __ lea(string, - FieldOperand(string, SeqAsciiString::kHeaderSize)); + FieldOperand(string, SeqOneByteString::kHeaderSize)); __ movq(separator_operand, string); // Jump into the loop after the code that copies the separator, so the first @@ -3777,7 +3768,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) { __ SmiToInteger32(string_length, FieldOperand(string, String::kLengthOffset)); __ lea(string, - FieldOperand(string, SeqAsciiString::kHeaderSize)); + FieldOperand(string, SeqOneByteString::kHeaderSize)); __ CopyBytes(result_pos, string, string_length); __ incq(index); __ j(not_equal, &loop_3); // Loop while (index < 0). @@ -4095,13 +4086,9 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { SetSourcePosition(expr->position()); // Call stub for +1/-1. + __ movq(rdx, rax); + __ Move(rax, Smi::FromInt(1)); BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); - if (expr->op() == Token::INC) { - __ Move(rdx, Smi::FromInt(1)); - } else { - __ movq(rdx, rax); - __ Move(rax, Smi::FromInt(1)); - } CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountBinOpFeedbackId()); patch_site.EmitPatchInfo(); __ bind(&done); @@ -4320,29 +4307,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { default: { VisitForAccumulatorValue(expr->right()); - Condition cc = no_condition; - switch (op) { - case Token::EQ_STRICT: - case Token::EQ: - cc = equal; - break; - case Token::LT: - cc = less; - break; - case Token::GT: - cc = greater; - break; - case Token::LTE: - cc = less_equal; - break; - case Token::GTE: - cc = greater_equal; - break; - case Token::IN: - case Token::INSTANCEOF: - default: - UNREACHABLE(); - } + Condition cc = CompareIC::ComputeCondition(op); __ pop(rdx); bool inline_smi_code = ShouldInlineSmiCase(op); diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc index 0fd8a40036..641e243300 100644 --- a/deps/v8/src/x64/ic-x64.cc +++ b/deps/v8/src/x64/ic-x64.cc @@ -623,6 +623,123 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { } +static void KeyedStoreGenerateGenericHelper( + MacroAssembler* masm, + Label* fast_object, + Label* fast_double, + Label* slow, + KeyedStoreCheckMap check_map, + KeyedStoreIncrementLength increment_length) { + Label transition_smi_elements; + Label finish_object_store, non_double_value, transition_double_elements; + Label fast_double_without_map_check; + // Fast case: Do the store, could be either Object or double. + __ bind(fast_object); + // rax: value + // rbx: receiver's elements array (a FixedArray) + // rcx: index + // rdx: receiver (a JSArray) + // r9: map of receiver + if (check_map == kCheckMap) { + __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); + __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); + __ j(not_equal, fast_double); + } + // Smi stores don't require further checks. + Label non_smi_value; + __ JumpIfNotSmi(rax, &non_smi_value); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ leal(rdi, Operand(rcx, 1)); + __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); + } + // It's irrelevant whether array is smi-only or not when writing a smi. + __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), + rax); + __ ret(0); + + __ bind(&non_smi_value); + // Writing a non-smi, check whether array allows non-smi elements. + // r9: receiver's map + __ CheckFastObjectElements(r9, &transition_smi_elements); + + __ bind(&finish_object_store); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ leal(rdi, Operand(rcx, 1)); + __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); + } + __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), + rax); + __ movq(rdx, rax); // Preserve the value which is returned. + __ RecordWriteArray( + rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); + __ ret(0); + + __ bind(fast_double); + if (check_map == kCheckMap) { + // Check for fast double array case. If this fails, call through to the + // runtime. + // rdi: elements array's map + __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); + __ j(not_equal, slow); + } + __ bind(&fast_double_without_map_check); + __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0, + &transition_double_elements); + if (increment_length == kIncrementLength) { + // Add 1 to receiver->length. + __ leal(rdi, Operand(rcx, 1)); + __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); + } + __ ret(0); + + __ bind(&transition_smi_elements); + __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); + + // Transition the array appropriately depending on the value type. + __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset)); + __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex); + __ j(not_equal, &non_double_value); + + // Value is a double. Transition FAST_SMI_ELEMENTS -> + // FAST_DOUBLE_ELEMENTS and complete the store. + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_DOUBLE_ELEMENTS, + rbx, + rdi, + slow); + ElementsTransitionGenerator::GenerateSmiToDouble(masm, slow); + __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); + __ jmp(&fast_double_without_map_check); + + __ bind(&non_double_value); + // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_ELEMENTS, + rbx, + rdi, + slow); + ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); + __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); + + __ bind(&transition_double_elements); + // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a + // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and + // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS + __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); + __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, + FAST_ELEMENTS, + rbx, + rdi, + slow); + ElementsTransitionGenerator::GenerateDoubleToObject(masm, slow); + __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); + __ jmp(&finish_object_store); +} + + void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, StrictModeFlag strict_mode) { // ----------- S t a t e ------------- @@ -631,11 +748,9 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // -- rdx : receiver // -- rsp[0] : return address // ----------------------------------- - Label slow, slow_with_tagged_index, fast, array, extra, check_extra_double; - Label fast_object_with_map_check, fast_object_without_map_check; - Label fast_double_with_map_check, fast_double_without_map_check; - Label transition_smi_elements, finish_object_store, non_double_value; - Label transition_double_elements; + Label slow, slow_with_tagged_index, fast_object, fast_object_grow; + Label fast_double, fast_double_grow; + Label array, extra, check_if_double_array; // Check that the object isn't a smi. __ JumpIfSmi(rdx, &slow_with_tagged_index); @@ -666,7 +781,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // rax: value // rbx: FixedArray // rcx: index - __ j(above, &fast_object_with_map_check); + __ j(above, &fast_object); // Slow case: call runtime. __ bind(&slow); @@ -690,18 +805,14 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, // Increment index to get new length. __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); - __ j(not_equal, &check_extra_double); - __ leal(rdi, Operand(rcx, 1)); - __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); - __ jmp(&fast_object_without_map_check); + __ j(not_equal, &check_if_double_array); + __ jmp(&fast_object_grow); - __ bind(&check_extra_double); + __ bind(&check_if_double_array); // rdi: elements array's map __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); __ j(not_equal, &slow); - __ leal(rdi, Operand(rcx, 1)); - __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi); - __ jmp(&fast_double_without_map_check); + __ jmp(&fast_double_grow); // Array case: Get the length and the elements array from the JS // array. Check that the array is in fast mode (and writable); if it @@ -717,92 +828,10 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx); __ j(below_equal, &extra); - // Fast case: Do the store. - __ bind(&fast_object_with_map_check); - // rax: value - // rbx: receiver's elements array (a FixedArray) - // rcx: index - // rdx: receiver (a JSArray) - __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); - __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex); - __ j(not_equal, &fast_double_with_map_check); - __ bind(&fast_object_without_map_check); - // Smi stores don't require further checks. - Label non_smi_value; - __ JumpIfNotSmi(rax, &non_smi_value); - // It's irrelevant whether array is smi-only or not when writing a smi. - __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), - rax); - __ ret(0); - - __ bind(&non_smi_value); - // Writing a non-smi, check whether array allows non-smi elements. - // r9: receiver's map - __ CheckFastObjectElements(r9, &transition_smi_elements); - __ bind(&finish_object_store); - __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize), - rax); - __ movq(rdx, rax); // Preserve the value which is returned. - __ RecordWriteArray( - rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); - __ ret(0); - - __ bind(&fast_double_with_map_check); - // Check for fast double array case. If this fails, call through to the - // runtime. - // rdi: elements array's map - __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex); - __ j(not_equal, &slow); - __ bind(&fast_double_without_map_check); - // If the value is a number, store it as a double in the FastDoubleElements - // array. - __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0, - &transition_double_elements); - __ ret(0); - - __ bind(&transition_smi_elements); - __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); - - // Transition the array appropriately depending on the value type. - __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset)); - __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex); - __ j(not_equal, &non_double_value); - - // Value is a double. Transition FAST_SMI_ELEMENTS -> - // FAST_DOUBLE_ELEMENTS and complete the store. - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS, - rbx, - rdi, - &slow); - ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow); - __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); - __ jmp(&fast_double_without_map_check); - - __ bind(&non_double_value); - // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_ELEMENTS, - rbx, - rdi, - &slow); - ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); - __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); - - __ bind(&transition_double_elements); - // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a - // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and - // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS - __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); - __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, - FAST_ELEMENTS, - rbx, - rdi, - &slow); - ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow); - __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); - __ jmp(&finish_object_store); + KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, + &slow, kCheckMap, kDontIncrementLength); + KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, + &slow, kDontCheckMap, kIncrementLength); } @@ -1700,7 +1729,7 @@ Condition CompareIC::ComputeCondition(Token::Value op) { } -static bool HasInlinedSmiCode(Address address) { +bool CompareIC::HasInlinedSmiCode(Address address) { // The address of the instruction following the call. Address test_instruction_address = address + Assembler::kCallTargetAddressOffset; @@ -1711,39 +1740,6 @@ static bool HasInlinedSmiCode(Address address) { } -void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { - HandleScope scope; - Handle<Code> rewritten; - State previous_state = GetState(); - - State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y); - if (state == GENERIC) { - CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); - rewritten = stub.GetCode(); - } else { - ICCompareStub stub(op_, state); - if (state == KNOWN_OBJECTS) { - stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map())); - } - rewritten = stub.GetCode(); - } - set_target(*rewritten); - -#ifdef DEBUG - if (FLAG_trace_ic) { - PrintF("[CompareIC (%s->%s)#%s]\n", - GetStateName(previous_state), - GetStateName(state), - Token::Name(op_)); - } -#endif - - // Activate inlined smi code. - if (previous_state == UNINITIALIZED) { - PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); - } -} - void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) { // The address of the instruction following the call. Address test_instruction_address = diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index a07564ed24..c69b27c445 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -143,6 +143,7 @@ bool LCodeGen::GeneratePrologue() { __ bind(&ok); } + info()->set_prologue_offset(masm_->pc_offset()); __ push(rbp); // Caller's frame pointer. __ movq(rbp, rsp); __ push(rsi); // Callee's context. @@ -232,7 +233,30 @@ bool LCodeGen::GenerateBody() { } if (emit_instructions) { - Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); + if (FLAG_code_comments) { + HValue* hydrogen = instr->hydrogen_value(); + if (hydrogen != NULL) { + if (hydrogen->IsChange()) { + HValue* changed_value = HChange::cast(hydrogen)->value(); + int use_id = 0; + const char* use_mnemo = "dead"; + if (hydrogen->UseCount() >= 1) { + HValue* use_value = hydrogen->uses().value(); + use_id = use_value->id(); + use_mnemo = use_value->Mnemonic(); + } + Comment(";;; @%d: %s. <of #%d %s for #%d %s>", + current_instruction_, instr->Mnemonic(), + changed_value->id(), changed_value->Mnemonic(), + use_id, use_mnemo); + } else { + Comment(";;; @%d: %s. <#%d>", current_instruction_, + instr->Mnemonic(), hydrogen->id()); + } + } else { + Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); + } + } instr->CompileToNative(this); } } @@ -351,7 +375,9 @@ Operand LCodeGen::ToOperand(LOperand* op) const { void LCodeGen::WriteTranslation(LEnvironment* environment, - Translation* translation) { + Translation* translation, + int* arguments_index, + int* arguments_count) { if (environment == NULL) return; // The translation includes one command per value in the environment. @@ -359,7 +385,17 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, // The output frame height does not include the parameters. int height = translation_size - environment->parameter_count(); - WriteTranslation(environment->outer(), translation); + // Function parameters are arguments to the outermost environment. The + // arguments index points to the first element of a sequence of tagged + // values on the stack that represent the arguments. This needs to be + // kept in sync with the LArgumentsElements implementation. + *arguments_index = -environment->parameter_count(); + *arguments_count = environment->parameter_count(); + + WriteTranslation(environment->outer(), + translation, + arguments_index, + arguments_count); int closure_id = *info()->closure() != *environment->closure() ? DefineDeoptimizationLiteral(environment->closure()) : Translation::kSelfLiteralId; @@ -385,6 +421,17 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); break; } + + // Inlined frames which push their arguments cause the index to be + // bumped and a new stack area to be used for materialization. + if (environment->entry() != NULL && + environment->entry()->arguments_pushed()) { + *arguments_index = *arguments_index < 0 + ? GetStackSlotCount() + : *arguments_index + *arguments_count; + *arguments_count = environment->entry()->arguments_count() + 1; + } + for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); // spilled_registers_ and spilled_double_registers_ are either @@ -396,7 +443,9 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, AddToTranslation(translation, environment->spilled_registers()[value->index()], environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } else if ( value->IsDoubleRegister() && environment->spilled_double_registers()[value->index()] != NULL) { @@ -405,14 +454,18 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation, environment->spilled_double_registers()[value->index()], false, - false); + false, + *arguments_index, + *arguments_count); } } AddToTranslation(translation, value, environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } } @@ -420,12 +473,14 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, void LCodeGen::AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32) { + bool is_uint32, + int arguments_index, + int arguments_count) { if (op == NULL) { // TODO(twuerthinger): Introduce marker operands to indicate that this value // is not present and must be reconstructed from the deoptimizer. Currently // this is only used for the arguments object. - translation->StoreArgumentsObject(); + translation->StoreArgumentsObject(arguments_index, arguments_count); } else if (op->IsStackSlot()) { if (is_tagged) { translation->StoreStackSlot(op->index()); @@ -531,15 +586,16 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, int frame_count = 0; int jsframe_count = 0; + int args_index = 0; + int args_count = 0; for (LEnvironment* e = environment; e != NULL; e = e->outer()) { ++frame_count; if (e->frame_type() == JS_FUNCTION) { ++jsframe_count; } } - Translation translation(&translations_, frame_count, jsframe_count, - environment->zone()); - WriteTranslation(environment, &translation); + Translation translation(&translations_, frame_count, jsframe_count, zone()); + WriteTranslation(environment, &translation, &args_index, &args_count); int deoptimization_index = deoptimizations_.length(); int pc_offset = masm()->pc_offset(); environment->Register(deoptimization_index, @@ -786,7 +842,7 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { void LCodeGen::DoModI(LModI* instr) { if (instr->hydrogen()->HasPowerOf2Divisor()) { - Register dividend = ToRegister(instr->InputAt(0)); + Register dividend = ToRegister(instr->left()); int32_t divisor = HConstant::cast(instr->hydrogen()->right())->Integer32Value(); @@ -810,8 +866,8 @@ void LCodeGen::DoModI(LModI* instr) { __ bind(&done); } else { Label done, remainder_eq_dividend, slow, do_subtraction, both_positive; - Register left_reg = ToRegister(instr->InputAt(0)); - Register right_reg = ToRegister(instr->InputAt(1)); + Register left_reg = ToRegister(instr->left()); + Register right_reg = ToRegister(instr->right()); Register result_reg = ToRegister(instr->result()); ASSERT(left_reg.is(rax)); @@ -841,7 +897,7 @@ void LCodeGen::DoModI(LModI* instr) { __ j(less, &remainder_eq_dividend, Label::kNear); // Check if the divisor is a PowerOfTwo integer. - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); __ movl(scratch, right_reg); __ subl(scratch, Immediate(1)); __ testl(scratch, right_reg); @@ -898,10 +954,10 @@ void LCodeGen::DoModI(LModI* instr) { void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { - ASSERT(instr->InputAt(1)->IsConstantOperand()); + ASSERT(instr->right()->IsConstantOperand()); - const Register dividend = ToRegister(instr->InputAt(0)); - int32_t divisor = ToInteger32(LConstantOperand::cast(instr->InputAt(1))); + const Register dividend = ToRegister(instr->left()); + int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); const Register result = ToRegister(instr->result()); switch (divisor) { @@ -946,7 +1002,7 @@ void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { __ sarl(result, Immediate(power)); } } else { - Register reg1 = ToRegister(instr->TempAt(0)); + Register reg1 = ToRegister(instr->temp()); Register reg2 = ToRegister(instr->result()); // Find b which: 2^b < divisor_abs < 2^(b+1). @@ -981,11 +1037,48 @@ void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { void LCodeGen::DoDivI(LDivI* instr) { - LOperand* right = instr->InputAt(1); + if (instr->hydrogen()->HasPowerOf2Divisor()) { + Register dividend = ToRegister(instr->left()); + int32_t divisor = + HConstant::cast(instr->hydrogen()->right())->Integer32Value(); + int32_t test_value = 0; + int32_t power = 0; + + if (divisor > 0) { + test_value = divisor - 1; + power = WhichPowerOf2(divisor); + } else { + // Check for (0 / -x) that will produce negative zero. + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { + __ testl(dividend, dividend); + DeoptimizeIf(zero, instr->environment()); + } + // Check for (kMinInt / -1). + if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { + __ cmpl(dividend, Immediate(kMinInt)); + DeoptimizeIf(zero, instr->environment()); + } + test_value = - divisor - 1; + power = WhichPowerOf2(-divisor); + } + + if (test_value != 0) { + // Deoptimize if remainder is not 0. + __ testl(dividend, Immediate(test_value)); + DeoptimizeIf(not_zero, instr->environment()); + __ sarl(dividend, Immediate(power)); + } + + if (divisor < 0) __ negl(dividend); + + return; + } + + LOperand* right = instr->right(); ASSERT(ToRegister(instr->result()).is(rax)); - ASSERT(ToRegister(instr->InputAt(0)).is(rax)); - ASSERT(!ToRegister(instr->InputAt(1)).is(rax)); - ASSERT(!ToRegister(instr->InputAt(1)).is(rdx)); + ASSERT(ToRegister(instr->left()).is(rax)); + ASSERT(!ToRegister(instr->right()).is(rax)); + ASSERT(!ToRegister(instr->right()).is(rdx)); Register left_reg = rax; @@ -1006,7 +1099,7 @@ void LCodeGen::DoDivI(LDivI* instr) { __ bind(&left_not_zero); } - // Check for (-kMinInt / -1). + // Check for (kMinInt / -1). if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { Label left_not_min_int; __ cmpl(left_reg, Immediate(kMinInt)); @@ -1027,8 +1120,8 @@ void LCodeGen::DoDivI(LDivI* instr) { void LCodeGen::DoMulI(LMulI* instr) { - Register left = ToRegister(instr->InputAt(0)); - LOperand* right = instr->InputAt(1); + Register left = ToRegister(instr->left()); + LOperand* right = instr->right(); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { __ movl(kScratchRegister, left); @@ -1093,8 +1186,11 @@ void LCodeGen::DoMulI(LMulI* instr) { __ testl(left, left); __ j(not_zero, &done, Label::kNear); if (right->IsConstantOperand()) { - if (ToInteger32(LConstantOperand::cast(right)) <= 0) { + if (ToInteger32(LConstantOperand::cast(right)) < 0) { DeoptimizeIf(no_condition, instr->environment()); + } else if (ToInteger32(LConstantOperand::cast(right)) == 0) { + __ cmpl(kScratchRegister, Immediate(0)); + DeoptimizeIf(less, instr->environment()); } } else if (right->IsStackSlot()) { __ orl(kScratchRegister, ToOperand(right)); @@ -1110,8 +1206,8 @@ void LCodeGen::DoMulI(LMulI* instr) { void LCodeGen::DoBitI(LBitI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); ASSERT(left->IsRegister()); @@ -1167,14 +1263,17 @@ void LCodeGen::DoBitI(LBitI* instr) { void LCodeGen::DoShiftI(LShiftI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); ASSERT(left->IsRegister()); if (right->IsRegister()) { ASSERT(ToRegister(right).is(rcx)); switch (instr->op()) { + case Token::ROR: + __ rorl_cl(ToRegister(left)); + break; case Token::SAR: __ sarl_cl(ToRegister(left)); break; @@ -1196,6 +1295,11 @@ void LCodeGen::DoShiftI(LShiftI* instr) { int value = ToInteger32(LConstantOperand::cast(right)); uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); switch (instr->op()) { + case Token::ROR: + if (shift_count != 0) { + __ rorl(ToRegister(left), Immediate(shift_count)); + } + break; case Token::SAR: if (shift_count != 0) { __ sarl(ToRegister(left), Immediate(shift_count)); @@ -1223,8 +1327,8 @@ void LCodeGen::DoShiftI(LShiftI* instr) { void LCodeGen::DoSubI(LSubI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); if (right->IsConstantOperand()) { @@ -1258,7 +1362,7 @@ void LCodeGen::DoConstantD(LConstantD* instr) { if (int_val == 0) { __ xorps(res, res); } else { - Register tmp = ToRegister(instr->TempAt(0)); + Register tmp = ToRegister(instr->temp()); __ Set(tmp, int_val); __ movq(res, tmp); } @@ -1278,28 +1382,28 @@ void LCodeGen::DoConstantT(LConstantT* instr) { void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ movq(result, FieldOperand(array, JSArray::kLengthOffset)); } void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ movq(result, FieldOperand(array, FixedArrayBase::kLengthOffset)); } void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) { Register result = ToRegister(instr->result()); - Register map = ToRegister(instr->InputAt(0)); + Register map = ToRegister(instr->value()); __ EnumLength(result, map); } void LCodeGen::DoElementsKind(LElementsKind* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); // Load map into |result|. __ movq(result, FieldOperand(input, HeapObject::kMapOffset)); @@ -1312,7 +1416,7 @@ void LCodeGen::DoElementsKind(LElementsKind* instr) { void LCodeGen::DoValueOf(LValueOf* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); ASSERT(input.is(result)); Label done; @@ -1329,7 +1433,7 @@ void LCodeGen::DoValueOf(LValueOf* instr) { void LCodeGen::DoDateField(LDateField* instr) { - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->date()); Register result = ToRegister(instr->result()); Smi* index = instr->index(); Label runtime, done, not_date_object; @@ -1370,15 +1474,24 @@ void LCodeGen::DoDateField(LDateField* instr) { } +void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { + SeqStringSetCharGenerator::Generate(masm(), + instr->encoding(), + ToRegister(instr->string()), + ToRegister(instr->index()), + ToRegister(instr->value())); +} + + void LCodeGen::DoBitNotI(LBitNotI* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->Equals(instr->result())); __ not_(ToRegister(input)); } void LCodeGen::DoThrow(LThrow* instr) { - __ push(ToRegister(instr->InputAt(0))); + __ push(ToRegister(instr->value())); CallRuntime(Runtime::kThrow, 1, instr); if (FLAG_debug_code) { @@ -1389,8 +1502,8 @@ void LCodeGen::DoThrow(LThrow* instr) { void LCodeGen::DoAddI(LAddI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); if (right->IsConstantOperand()) { @@ -1409,8 +1522,8 @@ void LCodeGen::DoAddI(LAddI* instr) { void LCodeGen::DoMathMinMax(LMathMinMax* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); ASSERT(left->Equals(instr->result())); HMathMinMax::Operation operation = instr->hydrogen()->operation(); if (instr->hydrogen()->representation().IsInteger32()) { @@ -1475,8 +1588,8 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) { void LCodeGen::DoArithmeticD(LArithmeticD* instr) { - XMMRegister left = ToDoubleRegister(instr->InputAt(0)); - XMMRegister right = ToDoubleRegister(instr->InputAt(1)); + XMMRegister left = ToDoubleRegister(instr->left()); + XMMRegister right = ToDoubleRegister(instr->right()); XMMRegister result = ToDoubleRegister(instr->result()); // All operations except MOD are computed in-place. ASSERT(instr->op() == Token::MOD || left.is(result)); @@ -1510,8 +1623,8 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { void LCodeGen::DoArithmeticT(LArithmeticT* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(rdx)); - ASSERT(ToRegister(instr->InputAt(1)).is(rax)); + ASSERT(ToRegister(instr->left()).is(rdx)); + ASSERT(ToRegister(instr->right()).is(rax)); ASSERT(ToRegister(instr->result()).is(rax)); BinaryOpStub stub(instr->op(), NO_OVERWRITE); @@ -1555,17 +1668,17 @@ void LCodeGen::DoBranch(LBranch* instr) { Representation r = instr->hydrogen()->value()->representation(); if (r.IsInteger32()) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); __ testl(reg, reg); EmitBranch(true_block, false_block, not_zero); } else if (r.IsDouble()) { - XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); + XMMRegister reg = ToDoubleRegister(instr->value()); __ xorps(xmm0, xmm0); __ ucomisd(reg, xmm0); EmitBranch(true_block, false_block, not_equal); } else { ASSERT(r.IsTagged()); - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); HType type = instr->hydrogen()->value()->type(); if (type.IsBoolean()) { __ CompareRoot(reg, Heap::kTrueValueRootIndex); @@ -1702,8 +1815,8 @@ inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); Condition cc = TokenToCondition(instr->op(), instr->is_double()); @@ -1750,8 +1863,8 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); - Register right = ToRegister(instr->InputAt(1)); + Register left = ToRegister(instr->left()); + Register right = ToRegister(instr->right()); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -1761,7 +1874,7 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); + Register left = ToRegister(instr->left()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1771,7 +1884,7 @@ void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); int false_block = chunk_->LookupDestination(instr->false_block_id()); // If the expression is known to be untagged or a smi, then it's definitely @@ -1801,7 +1914,7 @@ void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { __ JumpIfSmi(reg, false_label); // Check for undetectable objects by looking in the bit field in // the map. The object has already been smi checked. - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); __ testb(FieldOperand(scratch, Map::kBitFieldOffset), Immediate(1 << Map::kIsUndetectable)); @@ -1836,7 +1949,7 @@ Condition LCodeGen::EmitIsObject(Register input, void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1860,8 +1973,8 @@ Condition LCodeGen::EmitIsString(Register input, void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1878,11 +1991,11 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { int false_block = chunk_->LookupDestination(instr->false_block_id()); Condition is_smi; - if (instr->InputAt(0)->IsRegister()) { - Register input = ToRegister(instr->InputAt(0)); + if (instr->value()->IsRegister()) { + Register input = ToRegister(instr->value()); is_smi = masm()->CheckSmi(input); } else { - Operand input = ToOperand(instr->InputAt(0)); + Operand input = ToOperand(instr->value()); is_smi = masm()->CheckSmi(input); } EmitBranch(true_block, false_block, is_smi); @@ -1890,8 +2003,8 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register input = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1940,7 +2053,7 @@ static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1955,10 +2068,10 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); - __ AbortIfNotString(input); + __ AssertString(input); __ movl(result, FieldOperand(input, String::kHashFieldOffset)); ASSERT(String::kHashShift >= kSmiTagSize); @@ -1968,7 +2081,7 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { void LCodeGen::DoHasCachedArrayIndexAndBranch( LHasCachedArrayIndexAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2048,9 +2161,9 @@ void LCodeGen::EmitClassOfTest(Label* is_true, void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); - Register temp2 = ToRegister(instr->TempAt(1)); + Register input = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); + Register temp2 = ToRegister(instr->temp2()); Handle<String> class_name = instr->hydrogen()->class_name(); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -2066,7 +2179,7 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); int true_block = instr->true_block_id(); int false_block = instr->false_block_id(); @@ -2077,8 +2190,8 @@ void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { void LCodeGen::DoInstanceOf(LInstanceOf* instr) { InstanceofStub stub(InstanceofStub::kNoFlags); - __ push(ToRegister(instr->InputAt(0))); - __ push(ToRegister(instr->InputAt(1))); + __ push(ToRegister(instr->left())); + __ push(ToRegister(instr->right())); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); Label true_value, done; __ testq(rax, rax); @@ -2112,7 +2225,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr); Label done, false_result; - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->value()); // A Smi is not an instance of anything. __ JumpIfSmi(object, &false_result); @@ -2122,7 +2235,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { // instanceof stub. Label cache_miss; // Use a temp register to avoid memory operands with variable lengths. - Register map = ToRegister(instr->TempAt(0)); + Register map = ToRegister(instr->temp()); __ movq(map, FieldOperand(object, HeapObject::kMapOffset)); __ bind(deferred->map_check()); // Label for calculating code patching. Handle<JSGlobalPropertyCell> cache_cell = @@ -2165,7 +2278,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck); InstanceofStub stub(flags); - __ push(ToRegister(instr->InputAt(0))); + __ push(ToRegister(instr->value())); __ PushHeapObject(instr->function()); static const int kAdditionalDelta = 10; @@ -2265,7 +2378,7 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { // it as no longer deleted. We deoptimize in that case. if (instr->hydrogen()->RequiresHoleCheck()) { // We have a temp because CompareRoot might clobber kScratchRegister. - Register cell = ToRegister(instr->TempAt(0)); + Register cell = ToRegister(instr->temp()); ASSERT(!value.is(cell)); __ movq(cell, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL); __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex); @@ -2333,7 +2446,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { SmiCheck check_needed = type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; int offset = Context::SlotOffset(instr->slot_index()); - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); __ RecordWriteContextSlot(context, offset, value, @@ -2348,7 +2461,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->object()); Register result = ToRegister(instr->result()); if (instr->hydrogen()->is_in_object()) { __ movq(result, FieldOperand(object, instr->hydrogen()->offset())); @@ -2520,7 +2633,7 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->object()); __ movq(result, FieldOperand(input, JSObject::kElementsOffset)); if (FLAG_debug_code) { Label done, ok, fail; @@ -2556,7 +2669,7 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) { void LCodeGen::DoLoadExternalArrayPointer( LLoadExternalArrayPointer* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->object()); __ movq(result, FieldOperand(input, ExternalPixelArray::kExternalPointerOffset)); } @@ -2566,29 +2679,27 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { Register arguments = ToRegister(instr->arguments()); Register length = ToRegister(instr->length()); Register result = ToRegister(instr->result()); - + // There are two words between the frame pointer and the last argument. + // Subtracting from length accounts for one of them add one more. if (instr->index()->IsRegister()) { __ subl(length, ToRegister(instr->index())); } else { __ subl(length, ToOperand(instr->index())); } - DeoptimizeIf(below_equal, instr->environment()); - - // There are two words between the frame pointer and the last argument. - // Subtracting from length accounts for one of them add one more. __ movq(result, Operand(arguments, length, times_pointer_size, kPointerSize)); } -void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { - Register result = ToRegister(instr->result()); +void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { + ElementsKind elements_kind = instr->elements_kind(); LOperand* key = instr->key(); if (!key->IsConstantOperand()) { Register key_reg = ToRegister(key); - // Even though the HLoad/StoreKeyedFastElement instructions force the input - // representation for the key to be an integer, the input gets replaced - // during bound check elimination with the index argument to the bounds - // check, which can be tagged, so that case must be handled here, too. + // Even though the HLoad/StoreKeyed (in this case) instructions force + // the input representation for the key to be an integer, the input + // gets replaced during bound check elimination with the index argument + // to the bounds check, which can be tagged, so that case must be + // handled here, too. if (instr->hydrogen()->key()->representation().IsTagged()) { __ SmiToInteger64(key_reg, key_reg); } else if (instr->hydrogen()->IsDehoisted()) { @@ -2597,35 +2708,68 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { __ movsxlq(key_reg, key_reg); } } + Operand operand(BuildFastArrayOperand( + instr->elements(), + key, + elements_kind, + 0, + instr->additional_index())); - // Load the result. - __ movq(result, - BuildFastArrayOperand(instr->elements(), - key, - FAST_ELEMENTS, - FixedArray::kHeaderSize - kHeapObjectTag, - instr->additional_index())); - - // Check for the hole value. - if (instr->hydrogen()->RequiresHoleCheck()) { - if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { - Condition smi = __ CheckSmi(result); - DeoptimizeIf(NegateCondition(smi), instr->environment()); - } else { - __ CompareRoot(result, Heap::kTheHoleValueRootIndex); - DeoptimizeIf(equal, instr->environment()); + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { + XMMRegister result(ToDoubleRegister(instr->result())); + __ movss(result, operand); + __ cvtss2sd(result, result); + } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { + __ movsd(ToDoubleRegister(instr->result()), operand); + } else { + Register result(ToRegister(instr->result())); + switch (elements_kind) { + case EXTERNAL_BYTE_ELEMENTS: + __ movsxbq(result, operand); + break; + case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: + case EXTERNAL_PIXEL_ELEMENTS: + __ movzxbq(result, operand); + break; + case EXTERNAL_SHORT_ELEMENTS: + __ movsxwq(result, operand); + break; + case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: + __ movzxwq(result, operand); + break; + case EXTERNAL_INT_ELEMENTS: + __ movsxlq(result, operand); + break; + case EXTERNAL_UNSIGNED_INT_ELEMENTS: + __ movl(result, operand); + if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { + __ testl(result, result); + DeoptimizeIf(negative, instr->environment()); + } + break; + case EXTERNAL_FLOAT_ELEMENTS: + case EXTERNAL_DOUBLE_ELEMENTS: + case FAST_ELEMENTS: + case FAST_SMI_ELEMENTS: + case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + case DICTIONARY_ELEMENTS: + case NON_STRICT_ARGUMENTS_ELEMENTS: + UNREACHABLE(); + break; } } } -void LCodeGen::DoLoadKeyedFastDoubleElement( - LLoadKeyedFastDoubleElement* instr) { +void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { XMMRegister result(ToDoubleRegister(instr->result())); LOperand* key = instr->key(); if (!key->IsConstantOperand()) { Register key_reg = ToRegister(key); - // Even though the HLoad/StoreKeyedFastElement instructions force the input + // Even though the HLoad/StoreKeyed instructions force the input // representation for the key to be an integer, the input gets replaced // during bound check elimination with the index argument to the bounds // check, which can be tagged, so that case must be handled here, too. @@ -2661,6 +2805,57 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( } +void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { + Register result = ToRegister(instr->result()); + LOperand* key = instr->key(); + if (!key->IsConstantOperand()) { + Register key_reg = ToRegister(key); + // Even though the HLoad/StoreKeyedFastElement instructions force + // the input representation for the key to be an integer, the input + // gets replaced during bound check elimination with the index + // argument to the bounds check, which can be tagged, so that + // case must be handled here, too. + if (instr->hydrogen()->key()->representation().IsTagged()) { + __ SmiToInteger64(key_reg, key_reg); + } else if (instr->hydrogen()->IsDehoisted()) { + // Sign extend key because it could be a 32 bit negative value + // and the dehoisted address computation happens in 64 bits + __ movsxlq(key_reg, key_reg); + } + } + + // Load the result. + __ movq(result, + BuildFastArrayOperand(instr->elements(), + key, + FAST_ELEMENTS, + FixedArray::kHeaderSize - kHeapObjectTag, + instr->additional_index())); + + // Check for the hole value. + if (instr->hydrogen()->RequiresHoleCheck()) { + if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { + Condition smi = __ CheckSmi(result); + DeoptimizeIf(NegateCondition(smi), instr->environment()); + } else { + __ CompareRoot(result, Heap::kTheHoleValueRootIndex); + DeoptimizeIf(equal, instr->environment()); + } + } +} + + +void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { + if (instr->is_external()) { + DoLoadKeyedExternalArray(instr); + } else if (instr->hydrogen()->representation().IsDouble()) { + DoLoadKeyedFixedDoubleArray(instr); + } else { + DoLoadKeyedFixedArray(instr); + } +} + + Operand LCodeGen::BuildFastArrayOperand( LOperand* elements_pointer, LOperand* key, @@ -2687,80 +2882,6 @@ Operand LCodeGen::BuildFastArrayOperand( } -void LCodeGen::DoLoadKeyedSpecializedArrayElement( - LLoadKeyedSpecializedArrayElement* instr) { - ElementsKind elements_kind = instr->elements_kind(); - LOperand* key = instr->key(); - if (!key->IsConstantOperand()) { - Register key_reg = ToRegister(key); - // Even though the HLoad/StoreKeyedFastElement instructions force the input - // representation for the key to be an integer, the input gets replaced - // during bound check elimination with the index argument to the bounds - // check, which can be tagged, so that case must be handled here, too. - if (instr->hydrogen()->key()->representation().IsTagged()) { - __ SmiToInteger64(key_reg, key_reg); - } else if (instr->hydrogen()->IsDehoisted()) { - // Sign extend key because it could be a 32 bit negative value - // and the dehoisted address computation happens in 64 bits - __ movsxlq(key_reg, key_reg); - } - } - Operand operand(BuildFastArrayOperand( - instr->external_pointer(), - key, - elements_kind, - 0, - instr->additional_index())); - - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { - XMMRegister result(ToDoubleRegister(instr->result())); - __ movss(result, operand); - __ cvtss2sd(result, result); - } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { - __ movsd(ToDoubleRegister(instr->result()), operand); - } else { - Register result(ToRegister(instr->result())); - switch (elements_kind) { - case EXTERNAL_BYTE_ELEMENTS: - __ movsxbq(result, operand); - break; - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - case EXTERNAL_PIXEL_ELEMENTS: - __ movzxbq(result, operand); - break; - case EXTERNAL_SHORT_ELEMENTS: - __ movsxwq(result, operand); - break; - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ movzxwq(result, operand); - break; - case EXTERNAL_INT_ELEMENTS: - __ movsxlq(result, operand); - break; - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ movl(result, operand); - if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { - __ testl(result, result); - DeoptimizeIf(negative, instr->environment()); - } - break; - case EXTERNAL_FLOAT_ELEMENTS: - case EXTERNAL_DOUBLE_ELEMENTS: - case FAST_ELEMENTS: - case FAST_SMI_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - case DICTIONARY_ELEMENTS: - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNREACHABLE(); - break; - } - } -} - - void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(rdx)); ASSERT(ToRegister(instr->key()).is(rax)); @@ -2804,10 +2925,10 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { Label done; // If no arguments adaptor frame the number of arguments is fixed. - if (instr->InputAt(0)->IsRegister()) { - __ cmpq(rbp, ToRegister(instr->InputAt(0))); + if (instr->elements()->IsRegister()) { + __ cmpq(rbp, ToRegister(instr->elements())); } else { - __ cmpq(rbp, ToOperand(instr->InputAt(0))); + __ cmpq(rbp, ToOperand(instr->elements())); } __ movl(result, Immediate(scope()->num_parameters())); __ j(equal, &done, Label::kNear); @@ -2915,7 +3036,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { - LOperand* argument = instr->InputAt(0); + LOperand* argument = instr->value(); EmitPushTaggedOperand(argument); } @@ -3025,7 +3146,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { - Register input_reg = ToRegister(instr->InputAt(0)); + Register input_reg = ToRegister(instr->value()); __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), Heap::kHeapNumberMapRootIndex); DeoptimizeIf(not_equal, instr->environment()); @@ -3077,7 +3198,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { - Register input_reg = ToRegister(instr->InputAt(0)); + Register input_reg = ToRegister(instr->value()); __ testl(input_reg, input_reg); Label is_positive; __ j(not_sign, &is_positive); @@ -3102,12 +3223,12 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { LUnaryMathOperation* instr_; }; - ASSERT(instr->InputAt(0)->Equals(instr->result())); + ASSERT(instr->value()->Equals(instr->result())); Representation r = instr->hydrogen()->value()->representation(); if (r.IsDouble()) { XMMRegister scratch = xmm0; - XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + XMMRegister input_reg = ToDoubleRegister(instr->value()); __ xorps(scratch, scratch); __ subsd(scratch, input_reg); __ andpd(input_reg, scratch); @@ -3116,7 +3237,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { } else { // Tagged case. DeferredMathAbsTaggedHeapNumber* deferred = new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr); - Register input_reg = ToRegister(instr->InputAt(0)); + Register input_reg = ToRegister(instr->value()); // Smi check. __ JumpIfNotSmi(input_reg, deferred->entry()); __ SmiToInteger32(input_reg, input_reg); @@ -3130,7 +3251,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { XMMRegister xmm_scratch = xmm0; Register output_reg = ToRegister(instr->result()); - XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + XMMRegister input_reg = ToDoubleRegister(instr->value()); if (CpuFeatures::IsSupported(SSE4_1)) { CpuFeatures::Scope scope(SSE4_1); @@ -3189,7 +3310,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { const XMMRegister xmm_scratch = xmm0; Register output_reg = ToRegister(instr->result()); - XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + XMMRegister input_reg = ToDoubleRegister(instr->value()); Label done; // xmm_scratch = 0.5 @@ -3234,7 +3355,7 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { - XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + XMMRegister input_reg = ToDoubleRegister(instr->value()); ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); __ sqrtsd(input_reg, input_reg); } @@ -3242,7 +3363,7 @@ void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { XMMRegister xmm_scratch = xmm0; - XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + XMMRegister input_reg = ToDoubleRegister(instr->value()); ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); // Note that according to ECMA-262 15.8.2.13: @@ -3283,11 +3404,11 @@ void LCodeGen::DoPower(LPower* instr) { #else Register exponent = rdi; #endif - ASSERT(!instr->InputAt(1)->IsRegister() || - ToRegister(instr->InputAt(1)).is(exponent)); - ASSERT(!instr->InputAt(1)->IsDoubleRegister() || - ToDoubleRegister(instr->InputAt(1)).is(xmm1)); - ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2)); + ASSERT(!instr->right()->IsRegister() || + ToRegister(instr->right()).is(exponent)); + ASSERT(!instr->right()->IsDoubleRegister() || + ToDoubleRegister(instr->right()).is(xmm1)); + ASSERT(ToDoubleRegister(instr->left()).is(xmm2)); ASSERT(ToDoubleRegister(instr->result()).is(xmm3)); if (exponent_type.IsTagged()) { @@ -3329,10 +3450,10 @@ void LCodeGen::DoRandom(LRandom* instr) { // Choose the right register for the first argument depending on // calling convention. #ifdef _WIN64 - ASSERT(ToRegister(instr->InputAt(0)).is(rcx)); + ASSERT(ToRegister(instr->global_object()).is(rcx)); Register global_object = rcx; #else - ASSERT(ToRegister(instr->InputAt(0)).is(rdi)); + ASSERT(ToRegister(instr->global_object()).is(rdi)); Register global_object = rdi; #endif @@ -3399,6 +3520,16 @@ void LCodeGen::DoDeferredRandom(LRandom* instr) { } +void LCodeGen::DoMathExp(LMathExp* instr) { + XMMRegister input = ToDoubleRegister(instr->value()); + XMMRegister result = ToDoubleRegister(instr->result()); + Register temp1 = ToRegister(instr->temp1()); + Register temp2 = ToRegister(instr->temp2()); + + MathExpGenerator::EmitMathExp(masm(), input, result, xmm0, temp1, temp2); +} + + void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); TranscendentalCacheStub stub(TranscendentalCache::LOG, @@ -3547,7 +3678,7 @@ void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { void LCodeGen::DoCallNew(LCallNew* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(rdi)); + ASSERT(ToRegister(instr->constructor()).is(rdi)); ASSERT(ToRegister(instr->result()).is(rax)); CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); @@ -3571,7 +3702,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { __ Move(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); } else { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); __ Move(kScratchRegister, instr->transition()); __ movq(FieldOperand(object, HeapObject::kMapOffset), kScratchRegister); // Update the write barrier for the map field. @@ -3592,7 +3723,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { if (instr->is_in_object()) { __ movq(FieldOperand(object, offset), value); if (instr->hydrogen()->NeedsWriteBarrier()) { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); // Update the write barrier for the object for in-object properties. __ RecordWriteField(object, offset, @@ -3603,7 +3734,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { check_needed); } } else { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); __ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset)); __ movq(FieldOperand(temp, offset), value); if (instr->hydrogen()->NeedsWriteBarrier()) { @@ -3633,70 +3764,6 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { } -void LCodeGen::DoStoreKeyedSpecializedArrayElement( - LStoreKeyedSpecializedArrayElement* instr) { - ElementsKind elements_kind = instr->elements_kind(); - LOperand* key = instr->key(); - if (!key->IsConstantOperand()) { - Register key_reg = ToRegister(key); - // Even though the HLoad/StoreKeyedFastElement instructions force the input - // representation for the key to be an integer, the input gets replaced - // during bound check elimination with the index argument to the bounds - // check, which can be tagged, so that case must be handled here, too. - if (instr->hydrogen()->key()->representation().IsTagged()) { - __ SmiToInteger64(key_reg, key_reg); - } else if (instr->hydrogen()->IsDehoisted()) { - // Sign extend key because it could be a 32 bit negative value - // and the dehoisted address computation happens in 64 bits - __ movsxlq(key_reg, key_reg); - } - } - Operand operand(BuildFastArrayOperand( - instr->external_pointer(), - key, - elements_kind, - 0, - instr->additional_index())); - - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { - XMMRegister value(ToDoubleRegister(instr->value())); - __ cvtsd2ss(value, value); - __ movss(operand, value); - } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { - __ movsd(operand, ToDoubleRegister(instr->value())); - } else { - Register value(ToRegister(instr->value())); - switch (elements_kind) { - case EXTERNAL_PIXEL_ELEMENTS: - case EXTERNAL_BYTE_ELEMENTS: - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ movb(operand, value); - break; - case EXTERNAL_SHORT_ELEMENTS: - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ movw(operand, value); - break; - case EXTERNAL_INT_ELEMENTS: - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ movl(operand, value); - break; - case EXTERNAL_FLOAT_ELEMENTS: - case EXTERNAL_DOUBLE_ELEMENTS: - case FAST_ELEMENTS: - case FAST_SMI_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - case DICTIONARY_ELEMENTS: - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNREACHABLE(); - break; - } - } -} - - void LCodeGen::DeoptIfTaggedButNotSmi(LEnvironment* environment, HValue* value, LOperand* operand) { @@ -3721,9 +3788,8 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { instr->index()); if (instr->length()->IsRegister()) { Register reg = ToRegister(instr->length()); - if (FLAG_debug_code && - !instr->hydrogen()->length()->representation().IsTagged()) { - __ AbortIfNotZeroExtended(reg); + if (!instr->hydrogen()->length()->representation().IsTagged()) { + __ AssertZeroExtended(reg); } if (instr->index()->IsConstantOperand()) { int constant_index = @@ -3735,9 +3801,8 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { } } else { Register reg2 = ToRegister(instr->index()); - if (FLAG_debug_code && - !instr->hydrogen()->index()->representation().IsTagged()) { - __ AbortIfNotZeroExtended(reg2); + if (!instr->hydrogen()->index()->representation().IsTagged()) { + __ AssertZeroExtended(reg2); } __ cmpq(reg, reg2); } @@ -3759,16 +3824,16 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { } -void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { - Register value = ToRegister(instr->value()); - Register elements = ToRegister(instr->object()); +void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { + ElementsKind elements_kind = instr->elements_kind(); LOperand* key = instr->key(); if (!key->IsConstantOperand()) { Register key_reg = ToRegister(key); - // Even though the HLoad/StoreKeyedFastElement instructions force the input - // representation for the key to be an integer, the input gets replaced - // during bound check elimination with the index argument to the bounds - // check, which can be tagged, so that case must be handled here, too. + // Even though the HLoad/StoreKeyedFastElement instructions force + // the input representation for the key to be an integer, the input + // gets replaced during bound check elimination with the index + // argument to the bounds check, which can be tagged, so that case + // must be handled here, too. if (instr->hydrogen()->key()->representation().IsTagged()) { __ SmiToInteger64(key_reg, key_reg); } else if (instr->hydrogen()->IsDehoisted()) { @@ -3777,45 +3842,62 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { __ movsxlq(key_reg, key_reg); } } + Operand operand(BuildFastArrayOperand( + instr->elements(), + key, + elements_kind, + 0, + instr->additional_index())); - Operand operand = - BuildFastArrayOperand(instr->object(), - key, - FAST_ELEMENTS, - FixedArray::kHeaderSize - kHeapObjectTag, - instr->additional_index()); - - if (instr->hydrogen()->NeedsWriteBarrier()) { - ASSERT(!instr->key()->IsConstantOperand()); - HType type = instr->hydrogen()->value()->type(); - SmiCheck check_needed = - type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; - // Compute address of modified element and store it into key register. - Register key_reg(ToRegister(key)); - __ lea(key_reg, operand); - __ movq(Operand(key_reg, 0), value); - __ RecordWrite(elements, - key_reg, - value, - kSaveFPRegs, - EMIT_REMEMBERED_SET, - check_needed); + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { + XMMRegister value(ToDoubleRegister(instr->value())); + __ cvtsd2ss(value, value); + __ movss(operand, value); + } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { + __ movsd(operand, ToDoubleRegister(instr->value())); } else { - __ movq(operand, value); + Register value(ToRegister(instr->value())); + switch (elements_kind) { + case EXTERNAL_PIXEL_ELEMENTS: + case EXTERNAL_BYTE_ELEMENTS: + case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: + __ movb(operand, value); + break; + case EXTERNAL_SHORT_ELEMENTS: + case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: + __ movw(operand, value); + break; + case EXTERNAL_INT_ELEMENTS: + case EXTERNAL_UNSIGNED_INT_ELEMENTS: + __ movl(operand, value); + break; + case EXTERNAL_FLOAT_ELEMENTS: + case EXTERNAL_DOUBLE_ELEMENTS: + case FAST_ELEMENTS: + case FAST_SMI_ELEMENTS: + case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + case DICTIONARY_ELEMENTS: + case NON_STRICT_ARGUMENTS_ELEMENTS: + UNREACHABLE(); + break; + } } } -void LCodeGen::DoStoreKeyedFastDoubleElement( - LStoreKeyedFastDoubleElement* instr) { +void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { XMMRegister value = ToDoubleRegister(instr->value()); LOperand* key = instr->key(); if (!key->IsConstantOperand()) { Register key_reg = ToRegister(key); - // Even though the HLoad/StoreKeyedFastElement instructions force the input - // representation for the key to be an integer, the input gets replaced - // during bound check elimination with the index argument to the bounds - // check, which can be tagged, so that case must be handled here, too. + // Even though the HLoad/StoreKeyedFastElement instructions force + // the input representation for the key to be an integer, the + // input gets replaced during bound check elimination with the index + // argument to the bounds check, which can be tagged, so that case + // must be handled here, too. if (instr->hydrogen()->key()->representation().IsTagged()) { __ SmiToInteger64(key_reg, key_reg); } else if (instr->hydrogen()->IsDehoisted()) { @@ -3848,6 +3930,66 @@ void LCodeGen::DoStoreKeyedFastDoubleElement( __ movsd(double_store_operand, value); } + +void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { + Register value = ToRegister(instr->value()); + Register elements = ToRegister(instr->elements()); + LOperand* key = instr->key(); + if (!key->IsConstantOperand()) { + Register key_reg = ToRegister(key); + // Even though the HLoad/StoreKeyedFastElement instructions force + // the input representation for the key to be an integer, the + // input gets replaced during bound check elimination with the index + // argument to the bounds check, which can be tagged, so that case + // must be handled here, too. + if (instr->hydrogen()->key()->representation().IsTagged()) { + __ SmiToInteger64(key_reg, key_reg); + } else if (instr->hydrogen()->IsDehoisted()) { + // Sign extend key because it could be a 32 bit negative value + // and the dehoisted address computation happens in 64 bits + __ movsxlq(key_reg, key_reg); + } + } + + Operand operand = + BuildFastArrayOperand(instr->elements(), + key, + FAST_ELEMENTS, + FixedArray::kHeaderSize - kHeapObjectTag, + instr->additional_index()); + + if (instr->hydrogen()->NeedsWriteBarrier()) { + ASSERT(!instr->key()->IsConstantOperand()); + HType type = instr->hydrogen()->value()->type(); + SmiCheck check_needed = + type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; + // Compute address of modified element and store it into key register. + Register key_reg(ToRegister(key)); + __ lea(key_reg, operand); + __ movq(Operand(key_reg, 0), value); + __ RecordWrite(elements, + key_reg, + value, + kSaveFPRegs, + EMIT_REMEMBERED_SET, + check_needed); + } else { + __ movq(operand, value); + } +} + + +void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { + if (instr->is_external()) { + DoStoreKeyedExternalArray(instr); + } else if (instr->hydrogen()->value()->representation().IsDouble()) { + DoStoreKeyedFixedDoubleArray(instr); + } else { + DoStoreKeyedFixedArray(instr); + } +} + + void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(rdx)); ASSERT(ToRegister(instr->key()).is(rcx)); @@ -3862,7 +4004,7 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { Register object_reg = ToRegister(instr->object()); - Register new_map_reg = ToRegister(instr->new_map_reg()); + Register new_map_reg = ToRegister(instr->new_map_temp()); Handle<Map> from_map = instr->original_map(); Handle<Map> to_map = instr->transitioned_map(); @@ -3876,12 +4018,12 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { if (IsSimpleMapChangeTransition(from_kind, to_kind)) { __ movq(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg); // Write barrier. - ASSERT_NE(instr->temp_reg(), NULL); + ASSERT_NE(instr->temp(), NULL); __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, - ToRegister(instr->temp_reg()), kDontSaveFPRegs); + ToRegister(instr->temp()), kDontSaveFPRegs); } else if (IsFastSmiElementsKind(from_kind) && IsFastDoubleElementsKind(to_kind)) { - Register fixed_object_reg = ToRegister(instr->temp_reg()); + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(rdx)); ASSERT(new_map_reg.is(rbx)); __ movq(fixed_object_reg, object_reg); @@ -3889,7 +4031,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { RelocInfo::CODE_TARGET, instr); } else if (IsFastDoubleElementsKind(from_kind) && IsFastObjectElementsKind(to_kind)) { - Register fixed_object_reg = ToRegister(instr->temp_reg()); + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(rdx)); ASSERT(new_map_reg.is(rbx)); __ movq(fixed_object_reg, object_reg); @@ -3956,9 +4098,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { __ push(index); } CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); - if (FLAG_debug_code) { - __ AbortIfNotSmi(rax); - } + __ AssertSmi(rax); __ SmiToInteger32(rax, rax); __ StoreToSafepointRegisterSlot(result, rax); } @@ -4020,7 +4160,7 @@ void LCodeGen::DoStringLength(LStringLength* instr) { void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() || input->IsStackSlot()); LOperand* output = instr->result(); ASSERT(output->IsDoubleRegister()); @@ -4033,9 +4173,9 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); LOperand* output = instr->result(); - LOperand* temp = instr->TempAt(0); + LOperand* temp = instr->temp(); __ LoadUint32(ToDoubleRegister(output), ToRegister(input), @@ -4044,7 +4184,7 @@ void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { void LCodeGen::DoNumberTagI(LNumberTagI* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() && input->Equals(instr->result())); Register reg = ToRegister(input); @@ -4065,7 +4205,7 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { LNumberTagU* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() && input->Equals(instr->result())); Register reg = ToRegister(input); @@ -4079,7 +4219,7 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) { void LCodeGen::DoDeferredNumberTagU(LNumberTagU* instr) { Label slow; - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); Register tmp = reg.is(rax) ? rcx : rax; // Preserve the value of all registers. @@ -4126,9 +4266,9 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { LNumberTagD* instr_; }; - XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + XMMRegister input_reg = ToDoubleRegister(instr->value()); Register reg = ToRegister(instr->result()); - Register tmp = ToRegister(instr->TempAt(0)); + Register tmp = ToRegister(instr->temp()); DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); if (FLAG_inline_new) { @@ -4159,23 +4299,21 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { void LCodeGen::DoSmiTag(LSmiTag* instr) { - ASSERT(instr->InputAt(0)->Equals(instr->result())); - Register input = ToRegister(instr->InputAt(0)); + ASSERT(instr->value()->Equals(instr->result())); + Register input = ToRegister(instr->value()); ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); __ Integer32ToSmi(input, input); } void LCodeGen::DoSmiUntag(LSmiUntag* instr) { - ASSERT(instr->InputAt(0)->Equals(instr->result())); - Register input = ToRegister(instr->InputAt(0)); + ASSERT(instr->value()->Equals(instr->result())); + Register input = ToRegister(instr->value()); if (instr->needs_check()) { Condition is_smi = __ CheckSmi(input); DeoptimizeIf(NegateCondition(is_smi), instr->environment()); } else { - if (FLAG_debug_code) { - __ AbortIfNotSmi(input); - } + __ AssertSmi(input); } __ SmiToInteger32(input, input); } @@ -4233,7 +4371,7 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { Label done, heap_number; - Register input_reg = ToRegister(instr->InputAt(0)); + Register input_reg = ToRegister(instr->value()); // Heap number map check. __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), @@ -4259,7 +4397,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { // Deoptimize if we don't have a heap number. DeoptimizeIf(not_equal, instr->environment()); - XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0)); + XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); __ cvttsd2si(input_reg, xmm0); __ cvtlsi2sd(xmm_temp, input_reg); @@ -4289,7 +4427,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { LTaggedToI* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); ASSERT(input->Equals(instr->result())); @@ -4302,7 +4440,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); LOperand* result = instr->result(); ASSERT(result->IsDoubleRegister()); @@ -4318,7 +4456,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { void LCodeGen::DoDoubleToI(LDoubleToI* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsDoubleRegister()); LOperand* result = instr->result(); ASSERT(result->IsRegister()); @@ -4358,21 +4496,21 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { void LCodeGen::DoCheckSmi(LCheckSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); Condition cc = masm()->CheckSmi(ToRegister(input)); DeoptimizeIf(NegateCondition(cc), instr->environment()); } void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); Condition cc = masm()->CheckSmi(ToRegister(input)); DeoptimizeIf(cc, instr->environment()); } void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); @@ -4444,7 +4582,7 @@ void LCodeGen::DoCheckMapCommon(Register reg, void LCodeGen::DoCheckMaps(LCheckMaps* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); Register reg = ToRegister(input); @@ -4464,8 +4602,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) { void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { XMMRegister value_reg = ToDoubleRegister(instr->unclamped()); Register result_reg = ToRegister(instr->result()); - Register temp_reg = ToRegister(instr->TempAt(0)); - __ ClampDoubleToUint8(value_reg, xmm0, result_reg, temp_reg); + __ ClampDoubleToUint8(value_reg, xmm0, result_reg); } @@ -4479,8 +4616,7 @@ void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) { void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { ASSERT(instr->unclamped()->Equals(instr->result())); Register input_reg = ToRegister(instr->unclamped()); - Register temp_reg = ToRegister(instr->TempAt(0)); - XMMRegister temp_xmm_reg = ToDoubleRegister(instr->TempAt(1)); + XMMRegister temp_xmm_reg = ToDoubleRegister(instr->temp_xmm()); Label is_smi, done, heap_number; __ JumpIfSmi(input_reg, &is_smi); @@ -4500,7 +4636,7 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { // Heap number __ bind(&heap_number); __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); - __ ClampDoubleToUint8(xmm0, temp_xmm_reg, input_reg, temp_reg); + __ ClampDoubleToUint8(xmm0, temp_xmm_reg, input_reg); __ jmp(&done, Label::kNear); // smi @@ -4513,7 +4649,8 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { - Register reg = ToRegister(instr->TempAt(0)); + ASSERT(instr->temp()->Equals(instr->result())); + Register reg = ToRegister(instr->temp()); Handle<JSObject> holder = instr->holder(); Handle<JSObject> current_prototype = instr->prototype(); @@ -4552,7 +4689,7 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { new(zone()) DeferredAllocateObject(this, instr); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); Handle<JSFunction> constructor = instr->hydrogen()->constructor(); Handle<Map> initial_map(constructor->initial_map()); int instance_size = initial_map->instance_size(); @@ -4585,7 +4722,7 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { __ movq(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset)); if (FLAG_debug_code) { - __ AbortIfSmi(map); + __ AssertNotSmi(map); __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset), Immediate(instance_size >> kPointerSizeLog2)); __ Assert(equal, "Unexpected instance size"); @@ -4854,7 +4991,7 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { void LCodeGen::DoToFastProperties(LToFastProperties* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(rax)); + ASSERT(ToRegister(instr->value()).is(rax)); __ push(rax); CallRuntime(Runtime::kToFastProperties, 1, instr); } @@ -4931,7 +5068,7 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); EmitPushTaggedOperand(input); CallRuntime(Runtime::kTypeof, 1, instr); } @@ -4955,7 +5092,7 @@ void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); Label* true_label = chunk_->GetAssemblyLabel(true_block); @@ -5041,7 +5178,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); diff --git a/deps/v8/src/x64/lithium-codegen-x64.h b/deps/v8/src/x64/lithium-codegen-x64.h index c12f4e8b24..e068f14b5a 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.h +++ b/deps/v8/src/x64/lithium-codegen-x64.h @@ -117,7 +117,10 @@ class LCodeGen BASE_EMBEDDED { void DoGap(LGap* instr); // Emit frame translation commands for an environment. - void WriteTranslation(LEnvironment* environment, Translation* translation); + void WriteTranslation(LEnvironment* environment, + Translation* translation, + int* arguments_index, + int* arguments_count); // Declare methods that deal with the individual node types. #define DECLARE_DO(type) void Do##type(L##type* node); @@ -225,7 +228,9 @@ class LCodeGen BASE_EMBEDDED { void AddToTranslation(Translation* translation, LOperand* op, bool is_tagged, - bool is_uint32); + bool is_uint32, + int arguments_index, + int arguments_count); void PopulateDeoptimizationData(Handle<Code> code); int DefineDeoptimizationLiteral(Handle<Object> literal); @@ -330,6 +335,12 @@ class LCodeGen BASE_EMBEDDED { }; void EnsureSpaceForLazyDeopt(int space_needed); + void DoLoadKeyedExternalArray(LLoadKeyed* instr); + void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); + void DoLoadKeyedFixedArray(LLoadKeyed* instr); + void DoStoreKeyedExternalArray(LStoreKeyed* instr); + void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); + void DoStoreKeyedFixedArray(LStoreKeyed* instr); Zone* zone_; LPlatformChunk* const chunk_; diff --git a/deps/v8/src/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc index bee1854448..81228cef8c 100644 --- a/deps/v8/src/x64/lithium-x64.cc +++ b/deps/v8/src/x64/lithium-x64.cc @@ -179,6 +179,7 @@ const char* LArithmeticT::Mnemonic() const { case Token::BIT_AND: return "bit-and-t"; case Token::BIT_OR: return "bit-or-t"; case Token::BIT_XOR: return "bit-xor-t"; + case Token::ROR: return "ror-t"; case Token::SHL: return "sal-t"; case Token::SAR: return "sar-t"; case Token::SHR: return "shr-t"; @@ -196,22 +197,22 @@ void LGoto::PrintDataTo(StringStream* stream) { void LBranch::PrintDataTo(StringStream* stream) { stream->Add("B%d | B%d on ", true_block_id(), false_block_id()); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); } void LCmpIDAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - InputAt(0)->PrintTo(stream); + left()->PrintTo(stream); stream->Add(" %s ", Token::String(op())); - InputAt(1)->PrintTo(stream); + right()->PrintTo(stream); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); } void LIsNilAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(kind() == kStrictEquality ? " === " : " == "); stream->Add(nil() == kNullValue ? "null" : "undefined"); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); @@ -220,57 +221,57 @@ void LIsNilAndBranch::PrintDataTo(StringStream* stream) { void LIsObjectAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_object("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsStringAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_string("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_smi("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_undetectable("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LStringCompareAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if string_compare("); - InputAt(0)->PrintTo(stream); - InputAt(1)->PrintTo(stream); + left()->PrintTo(stream); + right()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_instance_type("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_cached_array_index("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if class_of_test("); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(), true_block_id(), @@ -280,7 +281,7 @@ void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); stream->Add(" == \"%s\" then B%d else B%d", *hydrogen()->type_literal()->ToCString(), true_block_id(), false_block_id()); @@ -294,26 +295,31 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) { void LUnaryMathOperation::PrintDataTo(StringStream* stream) { stream->Add("/%s ", hydrogen()->OpName()); - InputAt(0)->PrintTo(stream); + value()->PrintTo(stream); +} + + +void LMathExp::PrintDataTo(StringStream* stream) { + value()->PrintTo(stream); } void LLoadContextSlot::PrintDataTo(StringStream* stream) { - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); stream->Add("[%d]", slot_index()); } void LStoreContextSlot::PrintDataTo(StringStream* stream) { - InputAt(0)->PrintTo(stream); + context()->PrintTo(stream); stream->Add("[%d] <- ", slot_index()); - InputAt(1)->PrintTo(stream); + value()->PrintTo(stream); } void LInvokeFunction::PrintDataTo(StringStream* stream) { stream->Add("= "); - InputAt(0)->PrintTo(stream); + function()->PrintTo(stream); stream->Add(" #%d / ", arity()); } @@ -342,7 +348,7 @@ void LCallKnownGlobal::PrintDataTo(StringStream* stream) { void LCallNew::PrintDataTo(StringStream* stream) { stream->Add("= "); - InputAt(0)->PrintTo(stream); + constructor()->PrintTo(stream); stream->Add(" #%d / ", arity()); } @@ -394,20 +400,27 @@ void LStoreNamedGeneric::PrintDataTo(StringStream* stream) { } -void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) { - object()->PrintTo(stream); +void LLoadKeyed::PrintDataTo(StringStream* stream) { + elements()->PrintTo(stream); stream->Add("["); key()->PrintTo(stream); - stream->Add("] <- "); - value()->PrintTo(stream); + if (hydrogen()->IsDehoisted()) { + stream->Add(" + %d]", additional_index()); + } else { + stream->Add("]"); + } } -void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) { +void LStoreKeyed::PrintDataTo(StringStream* stream) { elements()->PrintTo(stream); stream->Add("["); key()->PrintTo(stream); - stream->Add("] <- "); + if (hydrogen()->IsDehoisted()) { + stream->Add(" + %d] <-", additional_index()); + } else { + stream->Add("] <- "); + } value()->PrintTo(stream); } @@ -865,6 +878,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment( argument_count_, value_count, outer, + hydrogen_env->entry(), zone()); int argument_index = *argument_index_accumulator; for (int i = 0; i < value_count; ++i) { @@ -1037,6 +1051,14 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { LOperand* input = UseFixedDouble(instr->value(), xmm1); LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input); return MarkAsCall(DefineFixedDouble(result, xmm1), instr); + } else if (op == kMathExp) { + ASSERT(instr->representation().IsDouble()); + ASSERT(instr->value()->representation().IsDouble()); + LOperand* value = UseTempRegister(instr->value()); + LOperand* temp1 = TempRegister(); + LOperand* temp2 = TempRegister(); + LMathExp* result = new(zone()) LMathExp(value, temp1, temp2); + return DefineAsRegister(result); } else { LOperand* input = UseRegisterAtStart(instr->value()); LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input); @@ -1108,6 +1130,11 @@ LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) { } +LInstruction* LChunkBuilder::DoRor(HRor* instr) { + return DoShift(Token::ROR, instr); +} + + LInstruction* LChunkBuilder::DoShr(HShr* instr) { return DoShift(Token::SHR, instr); } @@ -1158,6 +1185,13 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { if (instr->representation().IsDouble()) { return DoArithmeticD(Token::DIV, instr); } else if (instr->representation().IsInteger32()) { + if (instr->HasPowerOf2Divisor()) { + ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero)); + LOperand* value = UseRegisterAtStart(instr->left()); + LDivI* div = + new(zone()) LDivI(value, UseOrConstant(instr->right()), NULL); + return AssignEnvironment(DefineSameAsFirst(div)); + } // The temporary operand is necessary to ensure that right is not allocated // into rdx. LOperand* temp = FixedTemp(rdx); @@ -1391,7 +1425,7 @@ LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) { LInstruction* LChunkBuilder::DoCompareIDAndBranch( HCompareIDAndBranch* instr) { - Representation r = instr->GetInputRepresentation(); + Representation r = instr->representation(); if (r.IsInteger32()) { ASSERT(instr->left()->representation().IsInteger32()); ASSERT(instr->right()->representation().IsInteger32()); @@ -1554,6 +1588,17 @@ LInstruction* LChunkBuilder::DoDateField(HDateField* instr) { } +LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { + LOperand* string = UseRegister(instr->string()); + LOperand* index = UseRegister(instr->index()); + ASSERT(rcx.is_byte_register()); + LOperand* value = UseFixed(instr->value(), rcx); + LSeqStringSetChar* result = + new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value); + return DefineSameAsFirst(result); +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LOperand* value = UseRegisterOrConstantAtStart(instr->index()); LOperand* length = Use(instr->length()); @@ -1666,9 +1711,9 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { - LOperand* temp = TempRegister(); + LUnallocated* temp = TempRegister(); LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp); - return AssignEnvironment(result); + return AssignEnvironment(Define(result, temp)); } @@ -1696,8 +1741,7 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { Representation input_rep = value->representation(); LOperand* reg = UseRegister(value); if (input_rep.IsDouble()) { - return DefineAsRegister(new(zone()) LClampDToUint8(reg, - TempRegister())); + return DefineAsRegister(new(zone()) LClampDToUint8(reg)); } else if (input_rep.IsInteger32()) { return DefineSameAsFirst(new(zone()) LClampIToUint8(reg)); } else { @@ -1705,7 +1749,6 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { // Register allocator doesn't (yet) support allocation of double // temps. Reserve xmm1 explicitly. LClampTToUint8* result = new(zone()) LClampTToUint8(reg, - TempRegister(), FixedTemp(xmm1)); return AssignEnvironment(DefineSameAsFirst(result)); } @@ -1844,63 +1887,37 @@ LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( } -LInstruction* LChunkBuilder::DoLoadKeyedFastElement( - HLoadKeyedFastElement* instr) { - ASSERT(instr->representation().IsTagged()); +LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { ASSERT(instr->key()->representation().IsInteger32() || instr->key()->representation().IsTagged()); - LOperand* obj = UseRegisterAtStart(instr->object()); - bool clobbers_key = instr->key()->representation().IsTagged(); - LOperand* key = clobbers_key - ? UseTempRegister(instr->key()) - : UseRegisterOrConstantAtStart(instr->key()); - LLoadKeyedFastElement* result = - new(zone()) LLoadKeyedFastElement(obj, key); - if (instr->RequiresHoleCheck()) AssignEnvironment(result); - return DefineAsRegister(result); -} - - -LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement( - HLoadKeyedFastDoubleElement* instr) { - ASSERT(instr->representation().IsDouble()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - LOperand* elements = UseRegisterAtStart(instr->elements()); + ElementsKind elements_kind = instr->elements_kind(); bool clobbers_key = instr->key()->representation().IsTagged(); LOperand* key = clobbers_key ? UseTempRegister(instr->key()) : UseRegisterOrConstantAtStart(instr->key()); - LLoadKeyedFastDoubleElement* result = - new(zone()) LLoadKeyedFastDoubleElement(elements, key); - return AssignEnvironment(DefineAsRegister(result)); -} + LLoadKeyed* result = NULL; + if (!instr->is_external()) { + LOperand* obj = UseRegisterAtStart(instr->elements()); + result = new(zone()) LLoadKeyed(obj, key); + } else { + ASSERT( + (instr->representation().IsInteger32() && + (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && + (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || + (instr->representation().IsDouble() && + ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || + (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); + LOperand* external_pointer = UseRegister(instr->elements()); + result = new(zone()) LLoadKeyed(external_pointer, key); + } -LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( - HLoadKeyedSpecializedArrayElement* instr) { - ElementsKind elements_kind = instr->elements_kind(); - ASSERT( - (instr->representation().IsInteger32() && - (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && - (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || - (instr->representation().IsDouble() && - ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || - (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - LOperand* external_pointer = UseRegister(instr->external_pointer()); - bool clobbers_key = instr->key()->representation().IsTagged(); - LOperand* key = clobbers_key - ? UseTempRegister(instr->key()) - : UseRegisterOrConstantAtStart(instr->key()); - LLoadKeyedSpecializedArrayElement* result = - new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key); - LInstruction* load_instr = DefineAsRegister(result); + DefineAsRegister(result); + bool can_deoptimize = instr->RequiresHoleCheck() || + (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS); // An unsigned int array load might overflow and cause a deopt, make sure it // has an environment. - return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ? - AssignEnvironment(load_instr) : load_instr; + return can_deoptimize ? AssignEnvironment(result) : result; } @@ -1913,71 +1930,52 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { } -LInstruction* LChunkBuilder::DoStoreKeyedFastElement( - HStoreKeyedFastElement* instr) { - bool needs_write_barrier = instr->NeedsWriteBarrier(); - ASSERT(instr->value()->representation().IsTagged()); - ASSERT(instr->object()->representation().IsTagged()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* obj = UseTempRegister(instr->object()); - LOperand* val = needs_write_barrier - ? UseTempRegister(instr->value()) - : UseRegisterAtStart(instr->value()); - bool clobbers_key = needs_write_barrier || - instr->key()->representation().IsTagged(); - LOperand* key = clobbers_key - ? UseTempRegister(instr->key()) - : UseRegisterOrConstantAtStart(instr->key()); - return new(zone()) LStoreKeyedFastElement(obj, key, val); -} - - -LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement( - HStoreKeyedFastDoubleElement* instr) { - ASSERT(instr->value()->representation().IsDouble()); - ASSERT(instr->elements()->representation().IsTagged()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* elements = UseRegisterAtStart(instr->elements()); - LOperand* val = UseTempRegister(instr->value()); +LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { + ElementsKind elements_kind = instr->elements_kind(); bool clobbers_key = instr->key()->representation().IsTagged(); - LOperand* key = clobbers_key - ? UseTempRegister(instr->key()) - : UseRegisterOrConstantAtStart(instr->key()); - return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val); -} + if (!instr->is_external()) { + ASSERT(instr->elements()->representation().IsTagged()); + bool needs_write_barrier = instr->NeedsWriteBarrier(); + LOperand* object = NULL; + LOperand* key = NULL; + LOperand* val = NULL; + + if (instr->value()->representation().IsDouble()) { + object = UseRegisterAtStart(instr->elements()); + val = UseTempRegister(instr->value()); + key = clobbers_key ? UseTempRegister(instr->key()) + : UseRegisterOrConstantAtStart(instr->key()); + } else { + ASSERT(instr->value()->representation().IsTagged()); + object = UseTempRegister(instr->elements()); + val = needs_write_barrier ? UseTempRegister(instr->value()) + : UseRegisterAtStart(instr->value()); + key = (clobbers_key || needs_write_barrier) + ? UseTempRegister(instr->key()) + : UseRegisterOrConstantAtStart(instr->key()); + } + + return new(zone()) LStoreKeyed(object, key, val); + } -LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( - HStoreKeyedSpecializedArrayElement* instr) { - ElementsKind elements_kind = instr->elements_kind(); ASSERT( (instr->value()->representation().IsInteger32() && (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || (instr->value()->representation().IsDouble() && ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || - (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); - ASSERT(instr->external_pointer()->representation().IsExternal()); - ASSERT(instr->key()->representation().IsInteger32() || - instr->key()->representation().IsTagged()); - - LOperand* external_pointer = UseRegister(instr->external_pointer()); + (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); + ASSERT(instr->elements()->representation().IsExternal()); bool val_is_temp_register = elements_kind == EXTERNAL_PIXEL_ELEMENTS || elements_kind == EXTERNAL_FLOAT_ELEMENTS; - LOperand* val = val_is_temp_register - ? UseTempRegister(instr->value()) + LOperand* val = val_is_temp_register ? UseTempRegister(instr->value()) : UseRegister(instr->value()); - bool clobbers_key = instr->key()->representation().IsTagged(); - LOperand* key = clobbers_key - ? UseTempRegister(instr->key()) + LOperand* key = clobbers_key ? UseTempRegister(instr->key()) : UseRegisterOrConstantAtStart(instr->key()); - return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer, - key, val); + LOperand* external_pointer = UseRegister(instr->elements()); + return new(zone()) LStoreKeyed(external_pointer, key, val); } @@ -2127,6 +2125,7 @@ LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) { LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) { + ASSERT(argument_count_ == 0); allocator_->MarkAsOsrEntry(); current_block_->last_environment()->set_ast_id(instr->ast_id()); return AssignEnvironment(new(zone()) LOsrEntry); @@ -2165,12 +2164,10 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { - LOperand* arguments = UseRegister(instr->arguments()); + LOperand* args = UseRegister(instr->arguments()); LOperand* length = UseTempRegister(instr->length()); LOperand* index = Use(instr->index()); - LAccessArgumentsAt* result = - new(zone()) LAccessArgumentsAt(arguments, length, index); - return AssignEnvironment(DefineAsRegister(result)); + return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index)); } @@ -2205,7 +2202,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { env->set_ast_id(instr->ast_id()); env->Drop(instr->pop_count()); - for (int i = 0; i < instr->values()->length(); ++i) { + for (int i = instr->values()->length() - 1; i >= 0; --i) { HValue* value = instr->values()->at(i); if (instr->HasAssignedIndexAt(i)) { env->Bind(instr->GetAssignedIndexAt(i), value); @@ -2254,6 +2251,7 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { if (instr->arguments_var() != NULL) { inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject()); } + inner->set_entry(instr); current_block_->UpdateEnvironment(inner); chunk_->AddInlinedClosure(instr->closure()); return NULL; @@ -2265,7 +2263,7 @@ LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { HEnvironment* env = current_block_->last_environment(); - if (instr->arguments_pushed()) { + if (env->entry()->arguments_pushed()) { int argument_count = env->arguments_environment()->parameter_count(); pop = new(zone()) LDrop(argument_count); argument_count_ -= argument_count; diff --git a/deps/v8/src/x64/lithium-x64.h b/deps/v8/src/x64/lithium-x64.h index 84d05c051a..4a909a1f2e 100644 --- a/deps/v8/src/x64/lithium-x64.h +++ b/deps/v8/src/x64/lithium-x64.h @@ -126,13 +126,12 @@ class LCodeGen; V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ - V(LoadKeyedFastDoubleElement) \ - V(LoadKeyedFastElement) \ + V(LoadKeyed) \ V(LoadKeyedGeneric) \ - V(LoadKeyedSpecializedArrayElement) \ V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ + V(MathExp) \ V(MathFloorOfDiv) \ V(MathMinMax) \ V(ModI) \ @@ -150,6 +149,7 @@ class LCodeGen; V(Random) \ V(RegExpLiteral) \ V(Return) \ + V(SeqStringSetChar) \ V(ShiftI) \ V(SmiTag) \ V(SmiUntag) \ @@ -157,10 +157,8 @@ class LCodeGen; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ - V(StoreKeyedFastDoubleElement) \ - V(StoreKeyedFastElement) \ + V(StoreKeyed) \ V(StoreKeyedGeneric) \ - V(StoreKeyedSpecializedArrayElement) \ V(StoreNamedField) \ V(StoreNamedGeneric) \ V(StringAdd) \ @@ -262,9 +260,6 @@ class LInstruction: public ZoneObject { virtual bool HasResult() const = 0; virtual LOperand* result() = 0; - virtual int TempCount() = 0; - virtual LOperand* TempAt(int i) = 0; - LOperand* FirstInput() { return InputAt(0); } LOperand* Output() { return HasResult() ? result() : NULL; } @@ -278,6 +273,10 @@ class LInstruction: public ZoneObject { virtual int InputCount() = 0; virtual LOperand* InputAt(int i) = 0; + friend class TempIterator; + virtual int TempCount() = 0; + virtual LOperand* TempAt(int i) = 0; + LEnvironment* environment_; SetOncePointer<LPointerMap> pointer_map_; HValue* hydrogen_value_; @@ -297,18 +296,18 @@ class LTemplateInstruction: public LInstruction { void set_result(LOperand* operand) { results_[0] = operand; } LOperand* result() { return results_[0]; } - LOperand* InputAt(int i) { return inputs_[i]; } - - int TempCount() { return T; } - LOperand* TempAt(int i) { return temps_[i]; } - protected: EmbeddedContainer<LOperand*, R> results_; EmbeddedContainer<LOperand*, I> inputs_; EmbeddedContainer<LOperand*, T> temps_; private: + // Iterator support. virtual int InputCount() { return I; } + virtual LOperand* InputAt(int i) { return inputs_[i]; } + + virtual int TempCount() { return T; } + virtual LOperand* TempAt(int i) { return temps_[i]; } }; @@ -475,10 +474,10 @@ class LWrapReceiver: public LTemplateInstruction<1, 2, 0> { inputs_[1] = function; } - DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver") - LOperand* receiver() { return inputs_[0]; } LOperand* function() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver") }; @@ -494,12 +493,12 @@ class LApplyArguments: public LTemplateInstruction<1, 4, 0> { inputs_[3] = elements; } - DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments") - LOperand* function() { return inputs_[0]; } LOperand* receiver() { return inputs_[1]; } LOperand* length() { return inputs_[2]; } LOperand* elements() { return inputs_[3]; } + + DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments") }; @@ -511,12 +510,12 @@ class LAccessArgumentsAt: public LTemplateInstruction<1, 3, 0> { inputs_[2] = index; } - DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at") - LOperand* arguments() { return inputs_[0]; } LOperand* length() { return inputs_[1]; } LOperand* index() { return inputs_[2]; } + DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at") + virtual void PrintDataTo(StringStream* stream); }; @@ -527,6 +526,8 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = elements; } + LOperand* elements() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length") }; @@ -546,6 +547,10 @@ class LModI: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i") DECLARE_HYDROGEN_ACCESSOR(Mod) }; @@ -559,6 +564,10 @@ class LDivI: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i") DECLARE_HYDROGEN_ACCESSOR(Div) }; @@ -574,6 +583,10 @@ class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> { temps_[0] = temp; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv, "math-floor-of-div") DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv) }; @@ -586,6 +599,9 @@ class LMulI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i") DECLARE_HYDROGEN_ACCESSOR(Mul) }; @@ -598,12 +614,15 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch) Token::Value op() const { return hydrogen()->token(); } bool is_double() const { - return hydrogen()->GetInputRepresentation().IsDouble(); + return hydrogen()->representation().IsDouble(); } virtual void PrintDataTo(StringStream* stream); @@ -616,6 +635,8 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation") DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation) @@ -624,6 +645,25 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 0> { }; +class LMathExp: public LTemplateInstruction<1, 1, 2> { + public: + LMathExp(LOperand* value, LOperand* temp1, LOperand* temp2) { + inputs_[0] = value; + temps_[0] = temp1; + temps_[1] = temp2; + ExternalReference::InitializeMathExpData(); + } + + LOperand* value() { return inputs_[0]; } + LOperand* temp1() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp") + + virtual void PrintDataTo(StringStream* stream); +}; + + class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { public: LCmpObjectEqAndBranch(LOperand* left, LOperand* right) { @@ -631,6 +671,9 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch") }; @@ -642,6 +685,8 @@ class LCmpConstantEqAndBranch: public LControlInstruction<1, 0> { inputs_[0] = left; } + LOperand* left() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CmpConstantEqAndBranch, "cmp-constant-eq-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareConstantEqAndBranch) @@ -655,6 +700,9 @@ class LIsNilAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch, "is-nil-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsNilAndBranch) @@ -671,6 +719,8 @@ class LIsObjectAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch) @@ -685,6 +735,9 @@ class LIsStringAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch) @@ -698,6 +751,8 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch) @@ -712,6 +767,9 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, "is-undetectable-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch) @@ -727,6 +785,9 @@ class LStringCompareAndBranch: public LControlInstruction<2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch, "string-compare-and-branch") DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch) @@ -743,6 +804,8 @@ class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch, "has-instance-type-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch) @@ -757,6 +820,8 @@ class LGetCachedArrayIndex: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex, "get-cached-array-index") DECLARE_HYDROGEN_ACCESSOR(GetCachedArrayIndex) }; @@ -768,6 +833,8 @@ class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch, "has-cached-array-index-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch) @@ -784,6 +851,10 @@ class LClassOfTestAndBranch: public LControlInstruction<1, 2> { temps_[1] = temp2; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + LOperand* temp2() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch") DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) @@ -799,6 +870,9 @@ class LCmpT: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t") DECLARE_HYDROGEN_ACCESSOR(CompareGeneric) @@ -827,6 +901,9 @@ class LInstanceOf: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of") }; @@ -838,6 +915,9 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal, "instance-of-known-global") DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) @@ -877,6 +957,9 @@ class LBitI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + Token::Value op() const { return hydrogen()->op(); } DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i") @@ -893,7 +976,8 @@ class LShiftI: public LTemplateInstruction<1, 2, 0> { } Token::Value op() const { return op_; } - + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } bool can_deopt() const { return can_deopt_; } DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i") @@ -911,6 +995,9 @@ class LSubI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i") DECLARE_HYDROGEN_ACCESSOR(Sub) }; @@ -930,6 +1017,9 @@ class LConstantD: public LTemplateInstruction<1, 0, 1> { explicit LConstantD(LOperand* temp) { temps_[0] = temp; } + + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d") DECLARE_HYDROGEN_ACCESSOR(Constant) @@ -952,6 +1042,8 @@ class LBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_HYDROGEN_ACCESSOR(Branch) @@ -965,6 +1057,8 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareMap) @@ -986,6 +1080,8 @@ class LJSArrayLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) }; @@ -997,6 +1093,8 @@ class LFixedArrayBaseLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength, "fixed-array-base-length") DECLARE_HYDROGEN_ACCESSOR(FixedArrayBaseLength) @@ -1009,6 +1107,8 @@ class LMapEnumLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(MapEnumLength, "map-enum-length") }; @@ -1019,6 +1119,8 @@ class LElementsKind: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ElementsKind, "elements-kind") DECLARE_HYDROGEN_ACCESSOR(ElementsKind) }; @@ -1030,6 +1132,8 @@ class LValueOf: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value-of") DECLARE_HYDROGEN_ACCESSOR(ValueOf) }; @@ -1041,22 +1145,49 @@ class LDateField: public LTemplateInstruction<1, 1, 0> { inputs_[0] = date; } + LOperand* date() { return inputs_[0]; } + Smi* index() const { return index_; } + DECLARE_CONCRETE_INSTRUCTION(ValueOf, "date-field") DECLARE_HYDROGEN_ACCESSOR(ValueOf) - Smi* index() const { return index_; } - private: Smi* index_; }; +class LSeqStringSetChar: public LTemplateInstruction<1, 3, 0> { + public: + LSeqStringSetChar(String::Encoding encoding, + LOperand* string, + LOperand* index, + LOperand* value) : encoding_(encoding) { + inputs_[0] = string; + inputs_[1] = index; + inputs_[2] = value; + } + + String::Encoding encoding() { return encoding_; } + LOperand* string() { return inputs_[0]; } + LOperand* index() { return inputs_[1]; } + LOperand* value() { return inputs_[2]; } + + DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char") + DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar) + + private: + String::Encoding encoding_; +}; + + class LThrow: public LTemplateInstruction<0, 1, 0> { public: explicit LThrow(LOperand* value) { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Throw, "throw") }; @@ -1067,6 +1198,8 @@ class LBitNotI: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") }; @@ -1078,6 +1211,9 @@ class LAddI: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i") DECLARE_HYDROGEN_ACCESSOR(Add) }; @@ -1090,6 +1226,9 @@ class LMathMinMax: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max") DECLARE_HYDROGEN_ACCESSOR(MathMinMax) }; @@ -1102,6 +1241,9 @@ class LPower: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(Power, "power") DECLARE_HYDROGEN_ACCESSOR(Power) }; @@ -1113,6 +1255,8 @@ class LRandom: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } + LOperand* global_object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Random, "random") DECLARE_HYDROGEN_ACCESSOR(Random) }; @@ -1127,6 +1271,8 @@ class LArithmeticD: public LTemplateInstruction<1, 2, 0> { } Token::Value op() const { return op_; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } virtual Opcode opcode() const { return LInstruction::kArithmeticD; } virtual void CompileToNative(LCodeGen* generator); @@ -1145,12 +1291,14 @@ class LArithmeticT: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } + Token::Value op() const { return op_; } + LOperand* left() { return inputs_[0]; } + LOperand* right() { return inputs_[1]; } + virtual Opcode opcode() const { return LInstruction::kArithmeticT; } virtual void CompileToNative(LCodeGen* generator); virtual const char* Mnemonic() const; - Token::Value op() const { return op_; } - private: Token::Value op_; }; @@ -1162,6 +1310,8 @@ class LReturn: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Return, "return") }; @@ -1172,6 +1322,8 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field") DECLARE_HYDROGEN_ACCESSOR(LoadNamedField) }; @@ -1223,6 +1375,8 @@ class LLoadElements: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements") }; @@ -1233,61 +1387,33 @@ class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> { inputs_[0] = object; } + LOperand* object() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer, "load-external-array-pointer") }; -class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { +class LLoadKeyed: public LTemplateInstruction<1, 2, 0> { public: - LLoadKeyedFastElement(LOperand* elements, LOperand* key) { + LLoadKeyed(LOperand* elements, LOperand* key) { inputs_[0] = elements; inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement) - - LOperand* elements() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - + DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") + DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) -class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> { - public: - LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) { - inputs_[0] = elements; - inputs_[1] = key; + bool is_external() const { + return hydrogen()->is_external(); } - - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement, - "load-keyed-fast-double-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement) - LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + virtual void PrintDataTo(StringStream* stream); uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - -class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> { - public: - LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) { - inputs_[0] = external_pointer; - inputs_[1] = key; - } - - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement, - "load-keyed-specialized-array-element") - DECLARE_HYDROGEN_ACCESSOR(LoadKeyedSpecializedArrayElement) - - LOperand* external_pointer() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } - uint32_t additional_index() const { return hydrogen()->index_offset(); } }; @@ -1334,10 +1460,11 @@ class LStoreGlobalCell: public LTemplateInstruction<0, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell, "store-global-cell") DECLARE_HYDROGEN_ACCESSOR(StoreGlobalCell) - - LOperand* value() { return inputs_[0]; } }; @@ -1349,12 +1476,13 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> { inputs_[1] = value; } + LOperand* global_object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic") DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric) - LOperand* global_object() { return InputAt(0); } Handle<Object> name() const { return hydrogen()->name(); } - LOperand* value() { return InputAt(1); } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; @@ -1365,10 +1493,11 @@ class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } + LOperand* context() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot") DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot) - LOperand* context() { return InputAt(0); } int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); @@ -1383,11 +1512,13 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 1> { temps_[0] = temp; } + LOperand* context() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot") DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot) - LOperand* context() { return InputAt(0); } - LOperand* value() { return InputAt(1); } int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); @@ -1400,6 +1531,8 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument") }; @@ -1436,9 +1569,9 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> { inputs_[0] = context; } - DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context") + LOperand* context() { return inputs_[0]; } - LOperand* context() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(OuterContext, "outer-context") }; @@ -1461,9 +1594,9 @@ class LGlobalReceiver: public LTemplateInstruction<1, 1, 0> { inputs_[0] = global_object; } - DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver") + LOperand* global() { return inputs_[0]; } - LOperand* global() { return InputAt(0); } + DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global-receiver") }; @@ -1485,11 +1618,11 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> { inputs_[0] = function; } + LOperand* function() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function") DECLARE_HYDROGEN_ACCESSOR(InvokeFunction) - LOperand* function() { return inputs_[0]; } - virtual void PrintDataTo(StringStream* stream); int arity() const { return hydrogen()->argument_count() - 1; } @@ -1570,6 +1703,8 @@ class LCallNew: public LTemplateInstruction<1, 1, 0> { inputs_[0] = constructor; } + LOperand* constructor() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new") DECLARE_HYDROGEN_ACCESSOR(CallNew) @@ -1595,6 +1730,8 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double") }; @@ -1606,6 +1743,9 @@ class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double") }; @@ -1616,6 +1756,8 @@ class LNumberTagI: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i") }; @@ -1627,6 +1769,9 @@ class LNumberTagU: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u") }; @@ -1638,6 +1783,9 @@ class LNumberTagD: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d") }; @@ -1649,6 +1797,8 @@ class LDoubleToI: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -1664,6 +1814,9 @@ class LTaggedToI: public LTemplateInstruction<1, 1, 1> { temps_[0] = temp; } + LOperand* value() { return inputs_[0]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -1677,6 +1830,8 @@ class LSmiTag: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag") }; @@ -1687,6 +1842,8 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag") DECLARE_HYDROGEN_ACCESSOR(Change); }; @@ -1699,10 +1856,11 @@ class LSmiUntag: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } - DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag") - + LOperand* value() { return inputs_[0]; } bool needs_check() const { return needs_check_; } + DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag") + private: bool needs_check_; }; @@ -1716,14 +1874,15 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { temps_[0] = temp; } + LOperand* object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field") DECLARE_HYDROGEN_ACCESSOR(StoreNamedField) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* value() { return inputs_[1]; } - Handle<Object> name() const { return hydrogen()->name(); } bool is_in_object() { return hydrogen()->is_in_object(); } int offset() { return hydrogen()->offset(); } @@ -1738,88 +1897,42 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> { inputs_[1] = value; } + LOperand* object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } + DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic") DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* value() { return inputs_[1]; } Handle<Object> name() const { return hydrogen()->name(); } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; -class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> { +class LStoreKeyed: public LTemplateInstruction<0, 3, 0> { public: - LStoreKeyedFastElement(LOperand* obj, LOperand* key, LOperand* val) { - inputs_[0] = obj; + LStoreKeyed(LOperand* object, LOperand* key, LOperand* value) { + inputs_[0] = object; inputs_[1] = key; - inputs_[2] = val; + inputs_[2] = value; } - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement, - "store-keyed-fast-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastElement) - - virtual void PrintDataTo(StringStream* stream); - - LOperand* object() { return inputs_[0]; } + bool is_external() const { return hydrogen()->is_external(); } + LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; + ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } - -class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> { - public: - LStoreKeyedFastDoubleElement(LOperand* elements, - LOperand* key, - LOperand* val) { - inputs_[0] = elements; - inputs_[1] = key; - inputs_[2] = val; - } - - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement, - "store-keyed-fast-double-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement) + DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed") + DECLARE_HYDROGEN_ACCESSOR(StoreKeyed) virtual void PrintDataTo(StringStream* stream); - - LOperand* elements() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } - bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } uint32_t additional_index() const { return hydrogen()->index_offset(); } }; -class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> { - public: - LStoreKeyedSpecializedArrayElement(LOperand* external_pointer, - LOperand* key, - LOperand* val) { - inputs_[0] = external_pointer; - inputs_[1] = key; - inputs_[2] = val; - } - - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement, - "store-keyed-specialized-array-element") - DECLARE_HYDROGEN_ACCESSOR(StoreKeyedSpecializedArrayElement) - - LOperand* external_pointer() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } - ElementsKind elements_kind() const { - return hydrogen()->elements_kind(); - } - uint32_t additional_index() const { return hydrogen()->index_offset(); } -}; - - class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { public: LStoreKeyedGeneric(LOperand* object, LOperand* key, LOperand* value) { @@ -1828,14 +1941,15 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { inputs_[2] = value; } + LOperand* object() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } + LOperand* value() { return inputs_[2]; } + DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic") DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* key() { return inputs_[1]; } - LOperand* value() { return inputs_[2]; } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; @@ -1844,21 +1958,22 @@ class LTransitionElementsKind: public LTemplateInstruction<1, 1, 2> { public: LTransitionElementsKind(LOperand* object, LOperand* new_map_temp, - LOperand* temp_reg) { + LOperand* temp) { inputs_[0] = object; temps_[0] = new_map_temp; - temps_[1] = temp_reg; + temps_[1] = temp; } + LOperand* object() { return inputs_[0]; } + LOperand* new_map_temp() { return temps_[0]; } + LOperand* temp() { return temps_[1]; } + DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind, "transition-elements-kind") DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind) virtual void PrintDataTo(StringStream* stream); - LOperand* object() { return inputs_[0]; } - LOperand* new_map_reg() { return temps_[0]; } - LOperand* temp_reg() { return temps_[1]; } Handle<Map> original_map() { return hydrogen()->original_map(); } Handle<Map> transitioned_map() { return hydrogen()->transitioned_map(); } }; @@ -1871,11 +1986,11 @@ class LStringAdd: public LTemplateInstruction<1, 2, 0> { inputs_[1] = right; } - DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add") - DECLARE_HYDROGEN_ACCESSOR(StringAdd) - LOperand* left() { return inputs_[0]; } LOperand* right() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add") + DECLARE_HYDROGEN_ACCESSOR(StringAdd) }; @@ -1886,11 +2001,11 @@ class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> { inputs_[1] = index; } - DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at") - DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt) - LOperand* string() { return inputs_[0]; } LOperand* index() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at") + DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt) }; @@ -1900,10 +2015,10 @@ class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> { inputs_[0] = char_code; } + LOperand* char_code() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code") DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode) - - LOperand* char_code() { return inputs_[0]; } }; @@ -1913,10 +2028,10 @@ class LStringLength: public LTemplateInstruction<1, 1, 0> { inputs_[0] = string; } + LOperand* string() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length") DECLARE_HYDROGEN_ACCESSOR(StringLength) - - LOperand* string() { return inputs_[0]; } }; @@ -1926,7 +2041,7 @@ class LCheckFunction: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } - LOperand* value() { return InputAt(0); } + LOperand* value() { return inputs_[0]; } DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") DECLARE_HYDROGEN_ACCESSOR(CheckFunction) @@ -1939,6 +2054,8 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type") DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType) }; @@ -1950,17 +2067,21 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps") DECLARE_HYDROGEN_ACCESSOR(CheckMaps) }; -class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> { +class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> { public: explicit LCheckPrototypeMaps(LOperand* temp) { temps_[0] = temp; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) @@ -1975,15 +2096,16 @@ class LCheckSmi: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi") }; -class LClampDToUint8: public LTemplateInstruction<1, 1, 1> { +class LClampDToUint8: public LTemplateInstruction<1, 1, 0> { public: - LClampDToUint8(LOperand* value, LOperand* temp) { - inputs_[0] = value; - temps_[0] = temp; + explicit LClampDToUint8(LOperand* unclamped) { + inputs_[0] = unclamped; } LOperand* unclamped() { return inputs_[0]; } @@ -1994,8 +2116,8 @@ class LClampDToUint8: public LTemplateInstruction<1, 1, 1> { class LClampIToUint8: public LTemplateInstruction<1, 1, 0> { public: - explicit LClampIToUint8(LOperand* value) { - inputs_[0] = value; + explicit LClampIToUint8(LOperand* unclamped) { + inputs_[0] = unclamped; } LOperand* unclamped() { return inputs_[0]; } @@ -2004,17 +2126,16 @@ class LClampIToUint8: public LTemplateInstruction<1, 1, 0> { }; -class LClampTToUint8: public LTemplateInstruction<1, 1, 2> { +class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { public: - LClampTToUint8(LOperand* value, - LOperand* temp, - LOperand* temp2) { - inputs_[0] = value; - temps_[0] = temp; - temps_[1] = temp2; + LClampTToUint8(LOperand* unclamped, + LOperand* temp_xmm) { + inputs_[0] = unclamped; + temps_[0] = temp_xmm; } LOperand* unclamped() { return inputs_[0]; } + LOperand* temp_xmm() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8, "clamp-t-to-uint8") }; @@ -2026,6 +2147,8 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi") }; @@ -2036,6 +2159,8 @@ class LAllocateObject: public LTemplateInstruction<1, 0, 1> { temps_[0] = temp; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(AllocateObject, "allocate-object") DECLARE_HYDROGEN_ACCESSOR(AllocateObject) }; @@ -2084,6 +2209,8 @@ class LToFastProperties: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties") DECLARE_HYDROGEN_ACCESSOR(ToFastProperties) }; @@ -2095,6 +2222,8 @@ class LTypeof: public LTemplateInstruction<1, 1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof") }; @@ -2105,6 +2234,8 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> { inputs_[0] = value; } + LOperand* value() { return inputs_[0]; } + DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch") DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch) @@ -2120,6 +2251,8 @@ class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { temps_[0] = temp; } + LOperand* temp() { return temps_[0]; } + DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch, "is-construct-call-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsConstructCallAndBranch) @@ -2133,10 +2266,10 @@ class LDeleteProperty: public LTemplateInstruction<1, 2, 0> { inputs_[1] = key; } - DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") - LOperand* object() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + + DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") }; diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index 1b0f2fa2d4..4e4f2c572c 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -396,9 +396,7 @@ void MacroAssembler::RecordWrite(Register object, ASSERT(!object.is(value)); ASSERT(!object.is(address)); ASSERT(!value.is(address)); - if (emit_debug_code()) { - AbortIfSmi(object); - } + AssertNotSmi(object); if (remembered_set_action == OMIT_REMEMBERED_SET && !FLAG_incremental_marking) { @@ -722,11 +720,28 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address, movq(prev_next_address_reg, Operand(base_reg, kNextOffset)); movq(prev_limit_reg, Operand(base_reg, kLimitOffset)); addl(Operand(base_reg, kLevelOffset), Immediate(1)); + + if (FLAG_log_timer_events) { + FrameScope frame(this, StackFrame::MANUAL); + PushSafepointRegisters(); + PrepareCallCFunction(0); + CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0); + PopSafepointRegisters(); + } + // Call the api function! movq(rax, reinterpret_cast<int64_t>(function_address), RelocInfo::RUNTIME_ENTRY); call(rax); + if (FLAG_log_timer_events) { + FrameScope frame(this, StackFrame::MANUAL); + PushSafepointRegisters(); + PrepareCallCFunction(0); + CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0); + PopSafepointRegisters(); + } + #if defined(_WIN64) && !defined(__MINGW64__) // rax keeps a pointer to v8::Handle, unpack it. movq(rax, Operand(rax, 0)); @@ -1115,18 +1130,14 @@ void MacroAssembler::SmiTest(Register src) { void MacroAssembler::SmiCompare(Register smi1, Register smi2) { - if (emit_debug_code()) { - AbortIfNotSmi(smi1); - AbortIfNotSmi(smi2); - } + AssertSmi(smi1); + AssertSmi(smi2); cmpq(smi1, smi2); } void MacroAssembler::SmiCompare(Register dst, Smi* src) { - if (emit_debug_code()) { - AbortIfNotSmi(dst); - } + AssertSmi(dst); Cmp(dst, src); } @@ -1143,27 +1154,21 @@ void MacroAssembler::Cmp(Register dst, Smi* src) { void MacroAssembler::SmiCompare(Register dst, const Operand& src) { - if (emit_debug_code()) { - AbortIfNotSmi(dst); - AbortIfNotSmi(src); - } + AssertSmi(dst); + AssertSmi(src); cmpq(dst, src); } void MacroAssembler::SmiCompare(const Operand& dst, Register src) { - if (emit_debug_code()) { - AbortIfNotSmi(dst); - AbortIfNotSmi(src); - } + AssertSmi(dst); + AssertSmi(src); cmpq(dst, src); } void MacroAssembler::SmiCompare(const Operand& dst, Smi* src) { - if (emit_debug_code()) { - AbortIfNotSmi(dst); - } + AssertSmi(dst); cmpl(Operand(dst, kSmiShift / kBitsPerByte), Immediate(src->value())); } @@ -2213,16 +2218,19 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings( // Check that both are flat ASCII strings. ASSERT(kNotStringTag != 0); const int kFlatAsciiStringMask = - kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; + kIsNotStringMask | kStringEncodingMask | kAsciiDataHintMask | + kStringRepresentationMask; const int kFlatAsciiStringTag = ASCII_STRING_TYPE; andl(scratch1, Immediate(kFlatAsciiStringMask)); andl(scratch2, Immediate(kFlatAsciiStringMask)); // Interleave the bits to check both scratch1 and scratch2 in one test. - ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3)); - lea(scratch1, Operand(scratch1, scratch2, times_8, 0)); + ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 8)); + ASSERT_EQ(ASCII_STRING_TYPE, ASCII_STRING_TYPE & kFlatAsciiStringMask); + shl(scratch1, Immediate(8)); + orl(scratch1, scratch2); cmpl(scratch1, - Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3))); + Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 8))); j(not_equal, on_fail, near_jump); } @@ -2240,7 +2248,7 @@ void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii( kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; andl(scratch, Immediate(kFlatAsciiStringMask)); - cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kAsciiStringTag)); + cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kOneByteStringTag)); j(not_equal, failure, near_jump); } @@ -2258,17 +2266,19 @@ void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii( // Check that both are flat ASCII strings. ASSERT(kNotStringTag != 0); - const int kFlatAsciiStringMask = - kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; + const int kFlatAsciiStringMask = kIsNotStringMask | kStringRepresentationMask + | kStringEncodingMask | kAsciiDataHintTag; const int kFlatAsciiStringTag = ASCII_STRING_TYPE; andl(scratch1, Immediate(kFlatAsciiStringMask)); andl(scratch2, Immediate(kFlatAsciiStringMask)); // Interleave the bits to check both scratch1 and scratch2 in one test. - ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3)); - lea(scratch1, Operand(scratch1, scratch2, times_8, 0)); + ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 8)); + ASSERT_EQ(ASCII_STRING_TYPE, ASCII_STRING_TYPE & kFlatAsciiStringMask); + shl(scratch1, Immediate(8)); + orl(scratch1, scratch2); cmpl(scratch1, - Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 3))); + Immediate(kFlatAsciiStringTag + (kFlatAsciiStringTag << 8))); j(not_equal, on_fail, near_jump); } @@ -2781,7 +2791,8 @@ void MacroAssembler::StoreNumberToDoubleElements( Register elements, Register index, XMMRegister xmm_scratch, - Label* fail) { + Label* fail, + int elements_offset) { Label smi_value, is_nan, maybe_nan, not_nan, have_double_value, done; JumpIfSmi(maybe_number, &smi_value, Label::kNear); @@ -2800,7 +2811,8 @@ void MacroAssembler::StoreNumberToDoubleElements( bind(¬_nan); movsd(xmm_scratch, FieldOperand(maybe_number, HeapNumber::kValueOffset)); bind(&have_double_value); - movsd(FieldOperand(elements, index, times_8, FixedDoubleArray::kHeaderSize), + movsd(FieldOperand(elements, index, times_8, + FixedDoubleArray::kHeaderSize - elements_offset), xmm_scratch); jmp(&done); @@ -2823,7 +2835,8 @@ void MacroAssembler::StoreNumberToDoubleElements( // Preserve original value. SmiToInteger32(kScratchRegister, maybe_number); cvtlsi2sd(xmm_scratch, kScratchRegister); - movsd(FieldOperand(elements, index, times_8, FixedDoubleArray::kHeaderSize), + movsd(FieldOperand(elements, index, times_8, + FixedDoubleArray::kHeaderSize - elements_offset), xmm_scratch); bind(&done); } @@ -2880,16 +2893,24 @@ void MacroAssembler::ClampUint8(Register reg) { void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg, XMMRegister temp_xmm_reg, - Register result_reg, - Register temp_reg) { + Register result_reg) { Label done; - Set(result_reg, 0); + Label conv_failure; xorps(temp_xmm_reg, temp_xmm_reg); - ucomisd(input_reg, temp_xmm_reg); - j(below, &done, Label::kNear); cvtsd2si(result_reg, input_reg); testl(result_reg, Immediate(0xFFFFFF00)); j(zero, &done, Label::kNear); + cmpl(result_reg, Immediate(0x80000000)); + j(equal, &conv_failure, Label::kNear); + movl(result_reg, Immediate(0)); + setcc(above, result_reg); + subl(result_reg, Immediate(1)); + andl(result_reg, Immediate(255)); + jmp(&done, Label::kNear); + bind(&conv_failure); + Set(result_reg, 0); + ucomisd(input_reg, temp_xmm_reg); + j(below, &done, Label::kNear); Set(result_reg, 255); bind(&done); } @@ -2917,19 +2938,13 @@ void MacroAssembler::LoadUint32(XMMRegister dst, void MacroAssembler::LoadInstanceDescriptors(Register map, Register descriptors) { - Register temp = descriptors; - movq(temp, FieldOperand(map, Map::kTransitionsOrBackPointerOffset)); + movq(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); +} - Label ok, fail; - CheckMap(temp, - isolate()->factory()->fixed_array_map(), - &fail, - DONT_DO_SMI_CHECK); - movq(descriptors, FieldOperand(temp, TransitionArray::kDescriptorsOffset)); - jmp(&ok); - bind(&fail); - Move(descriptors, isolate()->factory()->empty_descriptor_array()); - bind(&ok); + +void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { + movq(dst, FieldOperand(map, Map::kBitField3Offset)); + DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); } @@ -2956,61 +2971,75 @@ void MacroAssembler::DispatchMap(Register obj, } -void MacroAssembler::AbortIfNotNumber(Register object) { - Label ok; - Condition is_smi = CheckSmi(object); - j(is_smi, &ok, Label::kNear); - Cmp(FieldOperand(object, HeapObject::kMapOffset), - isolate()->factory()->heap_number_map()); - Assert(equal, "Operand not a number"); - bind(&ok); +void MacroAssembler::AssertNumber(Register object) { + if (emit_debug_code()) { + Label ok; + Condition is_smi = CheckSmi(object); + j(is_smi, &ok, Label::kNear); + Cmp(FieldOperand(object, HeapObject::kMapOffset), + isolate()->factory()->heap_number_map()); + Check(equal, "Operand is not a number"); + bind(&ok); + } } -void MacroAssembler::AbortIfSmi(Register object) { - Condition is_smi = CheckSmi(object); - Assert(NegateCondition(is_smi), "Operand is a smi"); +void MacroAssembler::AssertNotSmi(Register object) { + if (emit_debug_code()) { + Condition is_smi = CheckSmi(object); + Check(NegateCondition(is_smi), "Operand is a smi"); + } } -void MacroAssembler::AbortIfNotSmi(Register object) { - Condition is_smi = CheckSmi(object); - Assert(is_smi, "Operand is not a smi"); +void MacroAssembler::AssertSmi(Register object) { + if (emit_debug_code()) { + Condition is_smi = CheckSmi(object); + Check(is_smi, "Operand is not a smi"); + } } -void MacroAssembler::AbortIfNotSmi(const Operand& object) { - Condition is_smi = CheckSmi(object); - Assert(is_smi, "Operand is not a smi"); +void MacroAssembler::AssertSmi(const Operand& object) { + if (emit_debug_code()) { + Condition is_smi = CheckSmi(object); + Check(is_smi, "Operand is not a smi"); + } } -void MacroAssembler::AbortIfNotZeroExtended(Register int32_register) { - ASSERT(!int32_register.is(kScratchRegister)); - movq(kScratchRegister, 0x100000000l, RelocInfo::NONE); - cmpq(kScratchRegister, int32_register); - Assert(above_equal, "32 bit value in register is not zero-extended"); +void MacroAssembler::AssertZeroExtended(Register int32_register) { + if (emit_debug_code()) { + ASSERT(!int32_register.is(kScratchRegister)); + movq(kScratchRegister, 0x100000000l, RelocInfo::NONE); + cmpq(kScratchRegister, int32_register); + Check(above_equal, "32 bit value in register is not zero-extended"); + } } -void MacroAssembler::AbortIfNotString(Register object) { - testb(object, Immediate(kSmiTagMask)); - Assert(not_equal, "Operand is not a string"); - push(object); - movq(object, FieldOperand(object, HeapObject::kMapOffset)); - CmpInstanceType(object, FIRST_NONSTRING_TYPE); - pop(object); - Assert(below, "Operand is not a string"); +void MacroAssembler::AssertString(Register object) { + if (emit_debug_code()) { + testb(object, Immediate(kSmiTagMask)); + Check(not_equal, "Operand is a smi and not a string"); + push(object); + movq(object, FieldOperand(object, HeapObject::kMapOffset)); + CmpInstanceType(object, FIRST_NONSTRING_TYPE); + pop(object); + Check(below, "Operand is not a string"); + } } -void MacroAssembler::AbortIfNotRootValue(Register src, - Heap::RootListIndex root_value_index, - const char* message) { - ASSERT(!src.is(kScratchRegister)); - LoadRoot(kScratchRegister, root_value_index); - cmpq(src, kScratchRegister); - Check(equal, message); +void MacroAssembler::AssertRootValue(Register src, + Heap::RootListIndex root_value_index, + const char* message) { + if (emit_debug_code()) { + ASSERT(!src.is(kScratchRegister)); + LoadRoot(kScratchRegister, root_value_index); + cmpq(src, kScratchRegister); + Check(equal, message); + } } @@ -3953,7 +3982,7 @@ void MacroAssembler::AllocateAsciiString(Register result, Label* gc_required) { // Calculate the number of bytes needed for the characters in the string while // observing object alignment. - const int kHeaderAlignment = SeqAsciiString::kHeaderSize & + const int kHeaderAlignment = SeqOneByteString::kHeaderSize & kObjectAlignmentMask; movl(scratch1, length); ASSERT(kCharSize == 1); @@ -3964,7 +3993,7 @@ void MacroAssembler::AllocateAsciiString(Register result, } // Allocate ASCII string in new space. - AllocateInNewSpace(SeqAsciiString::kHeaderSize, + AllocateInNewSpace(SeqOneByteString::kHeaderSize, times_1, scratch1, result, @@ -4499,7 +4528,7 @@ void MacroAssembler::EnsureNotWhite( bind(¬_external); // Sequential string, either ASCII or UC16. - ASSERT(kAsciiStringTag == 0x04); + ASSERT(kOneByteStringTag == 0x04); and_(length, Immediate(kStringEncodingMask)); xor_(length, Immediate(kStringEncodingMask)); addq(length, Immediate(0x04)); diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index 5268fe2a2e..0d8d6f2cca 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -895,7 +895,8 @@ class MacroAssembler: public Assembler { Register elements, Register index, XMMRegister xmm_scratch, - Label* fail); + Label* fail, + int elements_offset = 0); // Compare an object's map with the specified map and its transitioned // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. FLAGS are set with @@ -942,43 +943,45 @@ class MacroAssembler: public Assembler { void ClampDoubleToUint8(XMMRegister input_reg, XMMRegister temp_xmm_reg, - Register result_reg, - Register temp_reg); + Register result_reg); void LoadUint32(XMMRegister dst, Register src, XMMRegister scratch); void LoadInstanceDescriptors(Register map, Register descriptors); void EnumLength(Register dst, Register map); + void NumberOfOwnDescriptors(Register dst, Register map); template<typename Field> void DecodeField(Register reg) { - static const int full_shift = Field::kShift + kSmiShift; - static const int low_mask = Field::kMask >> Field::kShift; - shr(reg, Immediate(full_shift)); - and_(reg, Immediate(low_mask)); + static const int shift = Field::kShift + kSmiShift; + static const int mask = Field::kMask >> Field::kShift; + shr(reg, Immediate(shift)); + and_(reg, Immediate(mask)); + shl(reg, Immediate(kSmiShift)); } - // Abort execution if argument is not a number. Used in debug code. - void AbortIfNotNumber(Register object); + // Abort execution if argument is not a number, enabled via --debug-code. + void AssertNumber(Register object); - // Abort execution if argument is a smi. Used in debug code. - void AbortIfSmi(Register object); + // Abort execution if argument is a smi, enabled via --debug-code. + void AssertNotSmi(Register object); - // Abort execution if argument is not a smi. Used in debug code. - void AbortIfNotSmi(Register object); - void AbortIfNotSmi(const Operand& object); + // Abort execution if argument is not a smi, enabled via --debug-code. + void AssertSmi(Register object); + void AssertSmi(const Operand& object); // Abort execution if a 64 bit register containing a 32 bit payload does not - // have zeros in the top 32 bits. - void AbortIfNotZeroExtended(Register reg); + // have zeros in the top 32 bits, enabled via --debug-code. + void AssertZeroExtended(Register reg); - // Abort execution if argument is a string. Used in debug code. - void AbortIfNotString(Register object); + // Abort execution if argument is not a string, enabled via --debug-code. + void AssertString(Register object); - // Abort execution if argument is not the root value with the given index. - void AbortIfNotRootValue(Register src, - Heap::RootListIndex root_value_index, - const char* message); + // Abort execution if argument is not the root value with the given index, + // enabled via --debug-code. + void AssertRootValue(Register src, + Heap::RootListIndex root_value_index, + const char* message); // --------------------------------------------------------------------------- // Exception handling diff --git a/deps/v8/src/x64/regexp-macro-assembler-x64.cc b/deps/v8/src/x64/regexp-macro-assembler-x64.cc index 86f7bfe6ca..6cb87e899e 100644 --- a/deps/v8/src/x64/regexp-macro-assembler-x64.cc +++ b/deps/v8/src/x64/regexp-macro-assembler-x64.cc @@ -1305,7 +1305,7 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address, Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); // Current string. - bool is_ascii = subject->IsAsciiRepresentationUnderneath(); + bool is_ascii = subject->IsOneByteRepresentationUnderneath(); ASSERT(re_code->instruction_start() <= *return_address); ASSERT(*return_address <= @@ -1336,7 +1336,7 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address, } // String might have changed. - if (subject_tmp->IsAsciiRepresentation() != is_ascii) { + if (subject_tmp->IsOneByteRepresentation() != is_ascii) { // If we changed between an ASCII and an UC16 string, the specialized // code cannot be used, and we need to restart regexp matching from // scratch (including, potentially, compiling a new version of the code). diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index cd71086eec..683aa9d409 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -350,18 +350,23 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, Register dst, Register src, Handle<JSObject> holder, - int index) { - // Adjust for the number of properties stored in the holder. - index -= holder->map()->inobject_properties(); - if (index < 0) { - // Get the property straight out of the holder. - int offset = holder->map()->instance_size() + (index * kPointerSize); + PropertyIndex index) { + if (index.is_header_index()) { + int offset = index.header_index() * kPointerSize; __ movq(dst, FieldOperand(src, offset)); } else { - // Calculate the offset into the properties array. - int offset = index * kPointerSize + FixedArray::kHeaderSize; - __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset)); - __ movq(dst, FieldOperand(dst, offset)); + // Adjust for the number of properties stored in the holder. + int slot = index.field_index() - holder->map()->inobject_properties(); + if (slot < 0) { + // Get the property straight out of the holder. + int offset = holder->map()->instance_size() + (slot * kPointerSize); + __ movq(dst, FieldOperand(src, offset)); + } else { + // Calculate the offset into the properties array. + int offset = slot * kPointerSize + FixedArray::kHeaderSize; + __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset)); + __ movq(dst, FieldOperand(dst, offset)); + } } } @@ -1013,7 +1018,7 @@ void StubCompiler::GenerateLoadField(Handle<JSObject> object, Register scratch1, Register scratch2, Register scratch3, - int index, + PropertyIndex index, Handle<String> name, Label* miss) { // Check that the receiver isn't a smi. @@ -1388,7 +1393,7 @@ void CallStubCompiler::GenerateMissBranch() { Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name) { // ----------- S t a t e ------------- // rcx : function name @@ -1482,7 +1487,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( Label call_builtin; if (argc == 1) { // Otherwise fall through to call builtin. - Label attempt_to_grow_elements, with_write_barrier; + Label attempt_to_grow_elements, with_write_barrier, check_double; // Get the elements array of the object. __ movq(rdi, FieldOperand(rdx, JSArray::kElementsOffset)); @@ -1490,7 +1495,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( // Check that the elements are in fast mode and writable. __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset), factory()->fixed_array_map()); - __ j(not_equal, &call_builtin); + __ j(not_equal, &check_double); // Get the array's length into rax and calculate new length. __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset)); @@ -1521,6 +1526,34 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( __ Integer32ToSmi(rax, rax); // Return new length as smi. __ ret((argc + 1) * kPointerSize); + __ bind(&check_double); + + // Check that the elements are in double mode. + __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset), + factory()->fixed_double_array_map()); + __ j(not_equal, &call_builtin); + + // Get the array's length into rax and calculate new length. + __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset)); + STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue); + __ addl(rax, Immediate(argc)); + + // Get the elements' length into rcx. + __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); + + // Check if we could survive without allocation. + __ cmpl(rax, rcx); + __ j(greater, &call_builtin); + + __ movq(rcx, Operand(rsp, argc * kPointerSize)); + __ StoreNumberToDoubleElements( + rcx, rdi, rax, xmm0, &call_builtin, argc * kDoubleSize); + + // Save new length. + __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); + __ Integer32ToSmi(rax, rax); // Return new length as smi. + __ ret((argc + 1) * kPointerSize); + __ bind(&with_write_barrier); __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); @@ -1532,6 +1565,9 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( // In case of fast smi-only, convert to fast object, otherwise bail out. __ bind(¬_fast_object); __ CheckFastSmiElements(rbx, &call_builtin); + __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset), + factory()->heap_number_map()); + __ j(equal, &call_builtin); // rdx: receiver // rbx: map @@ -2780,7 +2816,7 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name, Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object, Handle<JSObject> holder, - int index, + PropertyIndex index, Handle<String> name) { // ----------- S t a t e ------------- // -- rax : receiver @@ -2973,7 +3009,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal( Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name, Handle<JSObject> receiver, Handle<JSObject> holder, - int index) { + PropertyIndex index) { // ----------- S t a t e ------------- // -- rax : key // -- rdx : receiver @@ -3240,6 +3276,7 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( #endif // Load the initial map and verify that it is in fact a map. + // rdi: constructor __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); // Will both indicate a NULL and a Smi. STATIC_ASSERT(kSmiTag == 0); @@ -3249,18 +3286,22 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( #ifdef DEBUG // Cannot construct functions this way. - // rdi: constructor // rbx: initial map __ CmpInstanceType(rbx, JS_FUNCTION_TYPE); - __ Assert(not_equal, "Function constructed by construct stub."); + __ Check(not_equal, "Function constructed by construct stub."); #endif // Now allocate the JSObject in new space. - // rdi: constructor // rbx: initial map + ASSERT(function->has_initial_map()); + int instance_size = function->initial_map()->instance_size(); +#ifdef DEBUG __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset)); __ shl(rcx, Immediate(kPointerSizeLog2)); - __ AllocateInNewSpace(rcx, rdx, rcx, no_reg, + __ cmpq(rcx, Immediate(instance_size)); + __ Check(equal, "Instance size of initial map changed."); +#endif + __ AllocateInNewSpace(instance_size, rdx, rcx, no_reg, &generic_stub_call, NO_ALLOCATION_FLAGS); // Allocated the JSObject, now initialize the fields and add the heap tag. @@ -3306,7 +3347,6 @@ Handle<Code> ConstructStubCompiler::CompileConstructStub( } // Fill the unused in-object property fields with undefined. - ASSERT(function->has_initial_map()); for (int i = shared->this_property_assignments_count(); i < function->initial_map()->inobject_properties(); i++) { @@ -3986,7 +4026,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( // -- rsp[0] : return address // ----------------------------------- Label miss_force_generic, transition_elements_kind, finish_store; - Label grow, slow, check_capacity; + Label grow, slow, check_capacity, restore_key_transition_elements_kind; // This stub is meant to be tail-jumped to, the receiver must already // have been verified by the caller to not be a smi. @@ -4015,7 +4055,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ bind(&finish_store); __ SmiToInteger32(rcx, rcx); __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, - &transition_elements_kind); + &restore_key_transition_elements_kind); __ ret(0); // Handle store cache miss, replacing the ic with the generic stub. @@ -4024,9 +4064,10 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); - __ bind(&transition_elements_kind); + __ bind(&restore_key_transition_elements_kind); // Restore smi-tagging of rcx. __ Integer32ToSmi(rcx, rcx); + __ bind(&transition_elements_kind); Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss(); __ jmp(ic_miss, RelocInfo::CODE_TARGET); @@ -4067,6 +4108,16 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ Move(FieldOperand(rdi, FixedDoubleArray::kLengthOffset), Smi::FromInt(JSArray::kPreallocatedArrayElements)); + // Increment the length of the array. + __ SmiToInteger32(rcx, rcx); + __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, + &restore_key_transition_elements_kind); + + __ movq(r8, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE); + for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { + __ movq(FieldOperand(rdi, FixedDoubleArray::OffsetOfElementAt(i)), r8); + } + // Install the new backing store in the JSArray. __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi); __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx, @@ -4075,7 +4126,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); + __ ret(0); __ bind(&check_capacity); // rax: value diff --git a/deps/v8/test/benchmarks/testcfg.py b/deps/v8/test/benchmarks/testcfg.py index ab9d40fec5..5bbad7ac1b 100644 --- a/deps/v8/test/benchmarks/testcfg.py +++ b/deps/v8/test/benchmarks/testcfg.py @@ -30,6 +30,11 @@ import test import os from os.path import join, split +def GetSuite(name, root): + # Not implemented. + return None + + def IsNumber(string): try: float(string) diff --git a/deps/v8/test/cctest/cctest.gyp b/deps/v8/test/cctest/cctest.gyp index 7624d5b5d6..80eecfd031 100644 --- a/deps/v8/test/cctest/cctest.gyp +++ b/deps/v8/test/cctest/cctest.gyp @@ -79,6 +79,7 @@ 'test-lockers.cc', 'test-log.cc', 'test-mark-compact.cc', + 'test-object-observe.cc', 'test-parsing.cc', 'test-platform-tls.cc', 'test-profile-generator.cc', @@ -187,7 +188,7 @@ '<(generated_file)', ], 'action': [ - '<(python)', + 'python', '../../tools/js2c.py', '<@(_outputs)', 'TEST', # type diff --git a/deps/v8/test/cctest/cctest.h b/deps/v8/test/cctest/cctest.h index 0b93562216..88cb9b8c5d 100644 --- a/deps/v8/test/cctest/cctest.h +++ b/deps/v8/test/cctest/cctest.h @@ -214,4 +214,43 @@ static inline v8::Local<v8::Value> CompileRun(const char* source) { } +// Helper function that compiles and runs the source with given origin. +static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source, + const char* origin_url, + int line_number, + int column_number) { + v8::ScriptOrigin origin(v8::String::New(origin_url), + v8::Integer::New(line_number), + v8::Integer::New(column_number)); + return v8::Script::Compile(v8::String::New(source), &origin)->Run(); +} + + +// Pick a slightly different port to allow tests to be run in parallel. +static inline int FlagDependentPortOffset() { + return ::v8::internal::FLAG_crankshaft == false ? 100 : + ::v8::internal::FLAG_always_opt ? 200 : 0; +} + + +// Helper function that simulates a fill new-space in the heap. +static inline void SimulateFullSpace(v8::internal::NewSpace* space) { + int new_linear_size = static_cast<int>( + *space->allocation_limit_address() - *space->allocation_top_address()); + v8::internal::MaybeObject* maybe = space->AllocateRaw(new_linear_size); + v8::internal::FreeListNode* node = v8::internal::FreeListNode::cast(maybe); + node->set_size(space->heap(), new_linear_size); +} + + +// Helper function that simulates a full old-space in the heap. +static inline void SimulateFullSpace(v8::internal::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(); +} + + #endif // ifndef CCTEST_H_ diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index df2c520567..ab59e3356f 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -68,11 +68,6 @@ test-api/OutOfMemoryNested: SKIP # BUG(355): Test crashes on ARM. test-log/ProfLazyMode: SKIP -# BUG(945): Tests using Socket cannot be run in parallel. -test-debug/DebuggerAgent: SKIP -test-debug/DebuggerAgentProtocolOverflowHeader: SKIP -test-sockets/Socket: SKIP - # BUG(1075): Unresolved crashes. test-serialize/Deserialize: SKIP test-serialize/DeserializeFromSecondSerializationAndRunScript2: SKIP @@ -90,7 +85,5 @@ test-log/ProfLazyMode: SKIP # platform-tls.h does not contain an ANDROID-related header. test-platform-tls/FastTLS: SKIP -# BUG(945): Tests using Socket cannot be run in parallel. -test-debug/DebuggerAgent: SKIP -test-debug/DebuggerAgentProtocolOverflowHeader: SKIP -test-sockets/Socket: SKIP +# This test times out. +test-threads/ThreadJoinSelf: SKIP diff --git a/deps/v8/test/cctest/test-accessors.cc b/deps/v8/test/cctest/test-accessors.cc index 0b342ff3d9..d44503534f 100644 --- a/deps/v8/test/cctest/test-accessors.cc +++ b/deps/v8/test/cctest/test-accessors.cc @@ -453,3 +453,29 @@ THREADED_TEST(HandleScopeSegment) { "result;"))->Run(); CHECK_EQ(100, result->Int32Value()); } + + +v8::Handle<v8::Array> JSONStringifyEnumerator(const AccessorInfo& info) { + v8::Handle<v8::Array> array = v8::Array::New(1); + array->Set(0, v8_str("regress")); + return array; +} + + +v8::Handle<v8::Value> JSONStringifyGetter(Local<String> name, + const AccessorInfo& info) { + return v8_str("crbug-161028"); +} + + +THREADED_TEST(JSONStringifyNamedInterceptorObject) { + v8::HandleScope scope; + LocalContext env; + + v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); + obj->SetNamedPropertyHandler( + JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator); + env->Global()->Set(v8_str("obj"), obj->NewInstance()); + v8::Handle<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}"); + CHECK(CompileRun("JSON.stringify(obj)")->Equals(expected)); +} diff --git a/deps/v8/test/cctest/test-alloc.cc b/deps/v8/test/cctest/test-alloc.cc index 50e60da271..bbae5ebd3e 100644 --- a/deps/v8/test/cctest/test-alloc.cc +++ b/deps/v8/test/cctest/test-alloc.cc @@ -34,34 +34,13 @@ using namespace v8::internal; -// Also used in test-heap.cc test cases. -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(); Heap* heap = Isolate::Current()->heap(); // New space. - NewSpace* new_space = heap->new_space(); - static const int kNewSpaceFillerSize = ByteArray::SizeFor(0); - while (new_space->Available() > kNewSpaceFillerSize) { - int available_before = static_cast<int>(new_space->Available()); - CHECK(!heap->AllocateByteArray(0)->IsFailure()); - if (available_before == new_space->Available()) { - // It seems that we are avoiding new space allocations when - // allocation is forced, so no need to fill up new space - // in order to make the test harder. - break; - } - } + SimulateFullSpace(heap->new_space()); CHECK(!heap->AllocateByteArray(100)->IsFailure()); CHECK(!heap->AllocateFixedArray(100, NOT_TENURED)->IsFailure()); @@ -76,7 +55,7 @@ static MaybeObject* AllocateAfterFailures() { // Old data space. SimulateFullSpace(heap->old_data_space()); - CHECK(!heap->AllocateRawAsciiString(100, TENURED)->IsFailure()); + CHECK(!heap->AllocateRawOneByteString(100, TENURED)->IsFailure()); // Old pointer space. SimulateFullSpace(heap->old_pointer_space()); @@ -100,6 +79,7 @@ static MaybeObject* AllocateAfterFailures() { CHECK(!heap->AllocateMap(JS_OBJECT_TYPE, instance_size)->IsFailure()); // Test that we can allocate in old pointer space and code space. + SimulateFullSpace(heap->code_space()); CHECK(!heap->AllocateFixedArray(100, TENURED)->IsFailure()); CHECK(!heap->CopyCode(Isolate::Current()->builtins()->builtin( Builtins::kIllegal))->IsFailure()); @@ -155,10 +135,10 @@ TEST(StressJS) { FACTORY->NewStringFromAscii(Vector<const char>("get", 3)); ASSERT(instance_descriptors->IsEmpty()); - Handle<DescriptorArray> new_descriptors = FACTORY->NewDescriptorArray(1); + Handle<DescriptorArray> new_descriptors = FACTORY->NewDescriptorArray(0, 1); v8::internal::DescriptorArray::WhitenessWitness witness(*new_descriptors); - v8::internal::Map::SetDescriptors(map, new_descriptors); + map->set_instance_descriptors(*new_descriptors); CallbacksDescriptor d(*name, *foreign, diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 1e12652c0a..0a5583bb94 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -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. +// We want to test our deprecated API entries, too. +#define V8_DISABLE_DEPRECATIONS 1 + #include <limits.h> #ifndef WIN32 @@ -404,6 +407,10 @@ THREADED_TEST(ScriptUsingStringResource) { CHECK(source->IsExternal()); CHECK_EQ(resource, static_cast<TestResource*>(source->GetExternalStringResource())); + String::Encoding encoding = String::UNKNOWN_ENCODING; + CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), + source->GetExternalStringResourceBase(&encoding)); + CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); CHECK_EQ(0, dispose_count); } @@ -419,9 +426,16 @@ THREADED_TEST(ScriptUsingAsciiStringResource) { { v8::HandleScope scope; LocalContext env; - Local<String> source = - String::NewExternal(new TestAsciiResource(i::StrDup(c_source), - &dispose_count)); + TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source), + &dispose_count); + Local<String> source = String::NewExternal(resource); + CHECK(source->IsExternalAscii()); + CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), + source->GetExternalAsciiStringResource()); + String::Encoding encoding = String::UNKNOWN_ENCODING; + CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), + source->GetExternalStringResourceBase(&encoding)); + CHECK_EQ(String::ASCII_ENCODING, encoding); Local<Script> script = Script::Compile(source); Local<Value> value = script->Run(); CHECK(value->IsNumber()); @@ -445,6 +459,11 @@ THREADED_TEST(ScriptMakingExternalString) { // Trigger GCs so that the newly allocated string moves to old gen. HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now + CHECK_EQ(source->IsExternal(), false); + CHECK_EQ(source->IsExternalAscii(), false); + String::Encoding encoding = String::UNKNOWN_ENCODING; + CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding)); + CHECK_EQ(String::ASCII_ENCODING, encoding); bool success = source->MakeExternal(new TestResource(two_byte_source, &dispose_count)); CHECK(success); @@ -607,6 +626,8 @@ THREADED_TEST(UsingExternalAsciiString) { THREADED_TEST(ScavengeExternalString) { + i::FLAG_stress_compaction = false; + i::FLAG_gc_global = false; int dispose_count = 0; bool in_new_space = false; { @@ -627,6 +648,8 @@ THREADED_TEST(ScavengeExternalString) { THREADED_TEST(ScavengeExternalAsciiString) { + i::FLAG_stress_compaction = false; + i::FLAG_gc_global = false; int dispose_count = 0; bool in_new_space = false; { @@ -953,22 +976,33 @@ THREADED_TEST(FindInstanceInPrototypeChain) { THREADED_TEST(TinyInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + int32_t value = 239; Local<v8::Integer> value_obj = v8::Integer::New(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::New(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } THREADED_TEST(BigSmiInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + int32_t value = i::Smi::kMaxValue; // We cannot add one to a Smi::kMaxValue without wrapping. if (i::kSmiValueSize < 32) { CHECK(i::Smi::IsValid(value)); CHECK(!i::Smi::IsValid(value + 1)); + Local<v8::Integer> value_obj = v8::Integer::New(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::New(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } } @@ -976,6 +1010,8 @@ THREADED_TEST(BigSmiInteger) { THREADED_TEST(BigInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + // We cannot add one to a Smi::kMaxValue without wrapping. if (i::kSmiValueSize < 32) { // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. @@ -984,8 +1020,12 @@ THREADED_TEST(BigInteger) { static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); CHECK(value > i::Smi::kMaxValue); CHECK(!i::Smi::IsValid(value)); + Local<v8::Integer> value_obj = v8::Integer::New(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::New(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } } @@ -993,42 +1033,66 @@ THREADED_TEST(BigInteger) { THREADED_TEST(TinyUnsignedInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + uint32_t value = 239; + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::NewFromUnsigned(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } THREADED_TEST(BigUnsignedSmiInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); CHECK(i::Smi::IsValid(value)); CHECK(!i::Smi::IsValid(value + 1)); + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::NewFromUnsigned(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } THREADED_TEST(BigUnsignedInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); CHECK(!i::Smi::IsValid(value)); + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::NewFromUnsigned(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } THREADED_TEST(OutOfSignedRangeUnsignedInteger) { v8::HandleScope scope; LocalContext env; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; uint32_t value = INT32_MAX_AS_UINT + 1; CHECK(value > INT32_MAX_AS_UINT); // No overflow. + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + + value_obj = v8::Integer::NewFromUnsigned(value, isolate); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); } @@ -1999,6 +2063,99 @@ THREADED_TEST(InternalFieldsNativePointersAndExternal) { } +static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj, + void* value) { + CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); + obj->SetPointerInInternalField(0, value); + HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); + CHECK_EQ(value, obj->GetPointerFromInternalField(0)); +} + + +THREADED_TEST(InternalFieldsAlignedPointers) { + v8::HandleScope scope; + LocalContext env; + + Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); + Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); + instance_templ->SetInternalFieldCount(1); + Local<v8::Object> obj = templ->GetFunction()->NewInstance(); + CHECK_EQ(1, obj->InternalFieldCount()); + + CheckAlignedPointerInInternalField(obj, NULL); + + int* heap_allocated = new int[100]; + CheckAlignedPointerInInternalField(obj, heap_allocated); + delete[] heap_allocated; + + int stack_allocated[100]; + CheckAlignedPointerInInternalField(obj, stack_allocated); + + void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); + CheckAlignedPointerInInternalField(obj, huge); +} + + +static void CheckAlignedPointerInEmbedderData(LocalContext* env, + int index, + void* value) { + CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); + (*env)->SetAlignedPointerInEmbedderData(index, value); + HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); + CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index)); +} + + +static void* AlignedTestPointer(int i) { + return reinterpret_cast<void*>(i * 1234); +} + + +THREADED_TEST(EmbedderDataAlignedPointers) { + v8::HandleScope scope; + LocalContext env; + + CheckAlignedPointerInEmbedderData(&env, 0, NULL); + + int* heap_allocated = new int[100]; + CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated); + delete[] heap_allocated; + + int stack_allocated[100]; + CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated); + + void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); + CheckAlignedPointerInEmbedderData(&env, 3, huge); + + // Test growing of the embedder data's backing store. + for (int i = 0; i < 100; i++) { + env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); + } + HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); + for (int i = 0; i < 100; i++) { + CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); + } +} + + +static void CheckEmbedderData(LocalContext* env, + int index, + v8::Handle<Value> data) { + (*env)->SetEmbedderData(index, data); + CHECK((*env)->GetEmbedderData(index)->StrictEquals(data)); +} + +THREADED_TEST(EmbedderData) { + v8::HandleScope scope; + LocalContext env; + + CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps")); + CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog.")); + CheckEmbedderData(&env, 1, v8::Number::New(1.2345)); + CheckEmbedderData(&env, 0, v8::Boolean::New(true)); +} + + THREADED_TEST(IdentityHash) { v8::HandleScope scope; LocalContext env; @@ -2192,6 +2349,24 @@ THREADED_TEST(GlobalHandle) { } CHECK_EQ(global->Length(), 3); global.Dispose(); + + { + v8::HandleScope scope; + Local<String> str = v8_str("str"); + global = v8::Persistent<String>::New(str); + } + CHECK_EQ(global->Length(), 3); + global.Dispose(v8::Isolate::GetCurrent()); +} + + +THREADED_TEST(LocalHandle) { + v8::HandleScope scope; + v8::Local<String> local = v8::Local<String>::New(v8_str("str")); + CHECK_EQ(local->Length(), 3); + + local = v8::Local<String>::New(v8::Isolate::GetCurrent(), v8_str("str")); + CHECK_EQ(local->Length(), 3); } @@ -2312,23 +2487,41 @@ THREADED_TEST(ApiObjectGroupsCycle) { Persistent<Object> g2s2; Persistent<Object> g3s1; Persistent<Object> g3s2; + Persistent<Object> g4s1; + Persistent<Object> g4s2; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); { HandleScope scope; g1s1 = Persistent<Object>::New(Object::New()); g1s2 = Persistent<Object>::New(Object::New()); g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + CHECK(g1s1.IsWeak()); + CHECK(g1s2.IsWeak()); g2s1 = Persistent<Object>::New(Object::New()); g2s2 = Persistent<Object>::New(Object::New()); g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + CHECK(g2s1.IsWeak()); + CHECK(g2s2.IsWeak()); g3s1 = Persistent<Object>::New(Object::New()); g3s2 = Persistent<Object>::New(Object::New()); g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + CHECK(g3s1.IsWeak()); + CHECK(g3s2.IsWeak()); + + g4s1 = Persistent<Object>::New(Object::New()); + g4s2 = Persistent<Object>::New(Object::New()); + g4s1.MakeWeak(isolate, + reinterpret_cast<void*>(&counter), &WeakPointerCallback); + g4s2.MakeWeak(isolate, + reinterpret_cast<void*>(&counter), &WeakPointerCallback); + CHECK(g4s1.IsWeak(isolate)); + CHECK(g4s2.IsWeak(isolate)); } Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root. @@ -2342,13 +2535,17 @@ THREADED_TEST(ApiObjectGroupsCycle) { Persistent<Value> g2_objects[] = { g2s1, g2s2 }; Persistent<Value> g2_children[] = { g3s1 }; Persistent<Value> g3_objects[] = { g3s1, g3s2 }; - Persistent<Value> g3_children[] = { g1s1 }; + Persistent<Value> g3_children[] = { g4s1 }; + Persistent<Value> g4_objects[] = { g4s1, g4s2 }; + Persistent<Value> g4_children[] = { g1s1 }; V8::AddObjectGroup(g1_objects, 2); V8::AddImplicitReferences(g1s1, g1_children, 1); V8::AddObjectGroup(g2_objects, 2); V8::AddImplicitReferences(g2s1, g2_children, 1); V8::AddObjectGroup(g3_objects, 2); V8::AddImplicitReferences(g3s1, g3_children, 1); + V8::AddObjectGroup(isolate, g4_objects, 2); + V8::AddImplicitReferences(g4s1, g4_children, 1); } // Do a single full GC HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); @@ -2366,17 +2563,117 @@ THREADED_TEST(ApiObjectGroupsCycle) { Persistent<Value> g2_objects[] = { g2s1, g2s2 }; Persistent<Value> g2_children[] = { g3s1 }; Persistent<Value> g3_objects[] = { g3s1, g3s2 }; - Persistent<Value> g3_children[] = { g1s1 }; + Persistent<Value> g3_children[] = { g4s1 }; + Persistent<Value> g4_objects[] = { g4s1, g4s2 }; + Persistent<Value> g4_children[] = { g1s1 }; V8::AddObjectGroup(g1_objects, 2); V8::AddImplicitReferences(g1s1, g1_children, 1); V8::AddObjectGroup(g2_objects, 2); V8::AddImplicitReferences(g2s1, g2_children, 1); V8::AddObjectGroup(g3_objects, 2); V8::AddImplicitReferences(g3s1, g3_children, 1); + V8::AddObjectGroup(g4_objects, 2); + V8::AddImplicitReferences(g4s1, g4_children, 1); } HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); + // All objects should be gone. 9 global handles in total. + CHECK_EQ(9, counter.NumberOfWeakCalls()); +} + + +// TODO(mstarzinger): This should be a THREADED_TEST but causes failures +// on the buildbots, so was made non-threaded for the time being. +TEST(ApiObjectGroupsCycleForScavenger) { + i::FLAG_stress_compaction = false; + i::FLAG_gc_global = false; + HandleScope scope; + LocalContext env; + + WeakCallCounter counter(1234); + + Persistent<Object> g1s1; + Persistent<Object> g1s2; + Persistent<Object> g2s1; + Persistent<Object> g2s2; + Persistent<Object> g3s1; + Persistent<Object> g3s2; + + { + HandleScope scope; + g1s1 = Persistent<Object>::New(Object::New()); + g1s2 = Persistent<Object>::New(Object::New()); + g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + + g2s1 = Persistent<Object>::New(Object::New()); + g2s2 = Persistent<Object>::New(Object::New()); + g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + + g3s1 = Persistent<Object>::New(Object::New()); + g3s2 = Persistent<Object>::New(Object::New()); + g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + } + + // Make a root. + Persistent<Object> root = Persistent<Object>::New(g1s1); + root.MarkPartiallyDependent(); + + // Connect groups. We're building the following cycle: + // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other + // groups. + { + g1s1.MarkPartiallyDependent(); + g1s2.MarkPartiallyDependent(); + g2s1.MarkPartiallyDependent(); + g2s2.MarkPartiallyDependent(); + g3s1.MarkPartiallyDependent(); + g3s2.MarkPartiallyDependent(); + Persistent<Value> g1_objects[] = { g1s1, g1s2 }; + Persistent<Value> g2_objects[] = { g2s1, g2s2 }; + Persistent<Value> g3_objects[] = { g3s1, g3s2 }; + V8::AddObjectGroup(g1_objects, 2); + g1s1->Set(v8_str("x"), g2s1); + V8::AddObjectGroup(g2_objects, 2); + g2s1->Set(v8_str("x"), g3s1); + V8::AddObjectGroup(g3_objects, 2); + g3s1->Set(v8_str("x"), g1s1); + } + + HEAP->CollectGarbage(i::NEW_SPACE); + + // All objects should be alive. + CHECK_EQ(0, counter.NumberOfWeakCalls()); + + // Weaken the root. + root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback); + root.MarkPartiallyDependent(); + + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + // Groups are deleted, rebuild groups. + { + g1s1.MarkPartiallyDependent(isolate); + g1s2.MarkPartiallyDependent(isolate); + g2s1.MarkPartiallyDependent(isolate); + g2s2.MarkPartiallyDependent(isolate); + g3s1.MarkPartiallyDependent(isolate); + g3s2.MarkPartiallyDependent(isolate); + Persistent<Value> g1_objects[] = { g1s1, g1s2 }; + Persistent<Value> g2_objects[] = { g2s1, g2s2 }; + Persistent<Value> g3_objects[] = { g3s1, g3s2 }; + V8::AddObjectGroup(g1_objects, 2); + g1s1->Set(v8_str("x"), g2s1); + V8::AddObjectGroup(g2_objects, 2); + g2s1->Set(v8_str("x"), g3s1); + V8::AddObjectGroup(g3_objects, 2); + g3s1->Set(v8_str("x"), g1s1); + } + + HEAP->CollectGarbage(i::NEW_SPACE); + // All objects should be gone. 7 global handles in total. CHECK_EQ(7, counter.NumberOfWeakCalls()); } @@ -2395,23 +2692,34 @@ THREADED_TEST(ScriptException) { } +TEST(TryCatchCustomException) { + v8::HandleScope scope; + LocalContext env; + v8::TryCatch try_catch; + CompileRun("function CustomError() { this.a = 'b'; }" + "(function f() { throw new CustomError(); })();"); + CHECK(try_catch.HasCaught()); + CHECK(try_catch.Exception()->ToObject()-> + Get(v8_str("a"))->Equals(v8_str("b"))); +} + + bool message_received; -static void check_message(v8::Handle<v8::Message> message, - v8::Handle<Value> data) { - CHECK_EQ(5.76, data->NumberValue()); +static void check_message_0(v8::Handle<v8::Message> message, + v8::Handle<Value> data) { CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); CHECK_EQ(7.56, message->GetScriptData()->NumberValue()); message_received = true; } -THREADED_TEST(MessageHandlerData) { +THREADED_TEST(MessageHandler0) { message_received = false; v8::HandleScope scope; CHECK(!message_received); - v8::V8::AddMessageListener(check_message, v8_num(5.76)); + v8::V8::AddMessageListener(check_message_0); LocalContext context; v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("6.75")); @@ -2421,7 +2729,56 @@ THREADED_TEST(MessageHandlerData) { script->Run(); CHECK(message_received); // clear out the message listener - v8::V8::RemoveMessageListeners(check_message); + v8::V8::RemoveMessageListeners(check_message_0); +} + + +static void check_message_1(v8::Handle<v8::Message> message, + v8::Handle<Value> data) { + CHECK(data->IsNumber()); + CHECK_EQ(1337, data->Int32Value()); + message_received = true; +} + + +TEST(MessageHandler1) { + message_received = false; + v8::HandleScope scope; + CHECK(!message_received); + v8::V8::AddMessageListener(check_message_1); + LocalContext context; + CompileRun("throw 1337;"); + CHECK(message_received); + // clear out the message listener + v8::V8::RemoveMessageListeners(check_message_1); +} + + +static void check_message_2(v8::Handle<v8::Message> message, + v8::Handle<Value> data) { + LocalContext context; + CHECK(data->IsObject()); + v8::Local<v8::Value> hidden_property = + v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key")); + CHECK(v8_str("hidden value")->Equals(hidden_property)); + message_received = true; +} + + +TEST(MessageHandler2) { + message_received = false; + v8::HandleScope scope; + CHECK(!message_received); + v8::V8::AddMessageListener(check_message_2); + LocalContext context; + v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error")); + v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"), + v8_str("hidden value")); + context->Global()->Set(v8_str("error"), error); + CompileRun("throw error;"); + CHECK(message_received); + // clear out the message listener + v8::V8::RemoveMessageListeners(check_message_2); } @@ -3062,7 +3419,7 @@ TEST(APIThrowMessageOverwrittenToString) { "Number.prototype.toString = function() { return 'Whoops'; };" "ReferenceError.prototype.toString = Object.prototype.toString;"); CompileRun("asdf;"); - v8::V8::RemoveMessageListeners(check_message); + v8::V8::RemoveMessageListeners(check_reference_error_message); } @@ -3109,7 +3466,7 @@ TEST(APIThrowMessage) { LocalContext context(0, templ); CompileRun("ThrowFromC();"); CHECK(message_received); - v8::V8::RemoveMessageListeners(check_message); + v8::V8::RemoveMessageListeners(receive_message); } @@ -3127,7 +3484,7 @@ TEST(APIThrowMessageAndVerboseTryCatch) { CHECK(try_catch.HasCaught()); CHECK(result.IsEmpty()); CHECK(message_received); - v8::V8::RemoveMessageListeners(check_message); + v8::V8::RemoveMessageListeners(receive_message); } @@ -3399,6 +3756,30 @@ THREADED_TEST(TryCatchAndFinally) { } +static void TryCatchNestedHelper(int depth) { + if (depth > 0) { + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + TryCatchNestedHelper(depth - 1); + CHECK(try_catch.HasCaught()); + try_catch.ReThrow(); + } else { + v8::ThrowException(v8_str("back")); + } +} + + +TEST(TryCatchNested) { + v8::V8::Initialize(); + v8::HandleScope scope; + LocalContext context; + v8::TryCatch try_catch; + TryCatchNestedHelper(5); + CHECK(try_catch.HasCaught()); + CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back")); +} + + THREADED_TEST(Equality) { v8::HandleScope scope; LocalContext context; @@ -5092,7 +5473,6 @@ TEST(RegexpOutOfMemory) { static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message, v8::Handle<Value> data) { - CHECK_EQ(v8::Undefined(), data); CHECK(message->GetScriptResourceName()->IsUndefined()); CHECK_EQ(v8::Undefined(), message->GetScriptResourceName()); message->GetLineNumber(); @@ -5204,18 +5584,28 @@ THREADED_TEST(IndependentWeakHandle) { v8::Persistent<Context> context = Context::New(); Context::Scope context_scope(context); - v8::Persistent<v8::Object> object_a; + v8::Persistent<v8::Object> object_a, object_b; { v8::HandleScope handle_scope; object_a = v8::Persistent<v8::Object>::New(v8::Object::New()); + object_b = v8::Persistent<v8::Object>::New(v8::Object::New()); } + v8::Isolate* isolate = v8::Isolate::GetCurrent(); bool object_a_disposed = false; + bool object_b_disposed = false; object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag); + object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag); + CHECK(!object_a.IsIndependent()); + CHECK(!object_b.IsIndependent(isolate)); object_a.MarkIndependent(); + object_b.MarkIndependent(isolate); + CHECK(object_a.IsIndependent()); + CHECK(object_b.IsIndependent(isolate)); HEAP->PerformScavenge(); CHECK(object_a_disposed); + CHECK(object_b_disposed); } @@ -7739,12 +8129,8 @@ THREADED_TEST(ShadowObject) { Local<ObjectTemplate> proto = t->PrototypeTemplate(); Local<ObjectTemplate> instance = t->InstanceTemplate(); - // Only allow calls of f on instances of t. - Local<v8::Signature> signature = v8::Signature::New(t); proto->Set(v8_str("f"), - v8::FunctionTemplate::New(ShadowFunctionCallback, - Local<Value>(), - signature)); + v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>())); proto->Set(v8_str("x"), v8_num(12)); instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); @@ -9609,6 +9995,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9639,6 +10026,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9675,6 +10063,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9711,6 +10100,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9750,6 +10140,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9812,6 +10203,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); CHECK(!templ.IsEmpty()); LocalContext context; @@ -9839,6 +10231,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); CHECK(!templ.IsEmpty()); LocalContext context; @@ -9871,6 +10264,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) { v8::Signature::New(fun_templ)); v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); CHECK(!templ.IsEmpty()); LocalContext context; @@ -9897,6 +10291,42 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) { CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); } +THREADED_TEST(CallICFastApi_SimpleSignature_TypeError) { + v8::HandleScope scope; + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); + v8::Handle<v8::FunctionTemplate> method_templ = + v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, + v8_str("method_data"), + v8::Signature::New(fun_templ)); + v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); + proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); + v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); + CHECK(!templ.IsEmpty()); + LocalContext context; + v8::Handle<v8::Function> fun = fun_templ->GetFunction(); + GenerateSomeGarbage(); + context->Global()->Set(v8_str("o"), fun->NewInstance()); + v8::TryCatch try_catch; + CompileRun( + "o.foo = 17;" + "var receiver = {};" + "receiver.__proto__ = o;" + "var result = 0;" + "var saved_result = 0;" + "for (var i = 0; i < 100; i++) {" + " result = receiver.method(41);" + " if (i == 50) {" + " saved_result = result;" + " receiver = Object.create(receiver);" + " }" + "}"); + CHECK(try_catch.HasCaught()); + CHECK_EQ(v8_str("TypeError: Illegal invocation"), + try_catch.Exception()->ToString()); + CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); +} + v8::Handle<Value> keyed_call_ic_function; @@ -10824,18 +11254,21 @@ TEST(DontLeakGlobalObjects) { { v8::HandleScope scope; LocalContext context; } + v8::V8::ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); { v8::HandleScope scope; LocalContext context; v8_compile("Date")->Run(); } + v8::V8::ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); { v8::HandleScope scope; LocalContext context; v8_compile("/aaa/")->Run(); } + v8::V8::ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); { v8::HandleScope scope; @@ -10844,6 +11277,7 @@ TEST(DontLeakGlobalObjects) { LocalContext context(&extensions); v8_compile("gc();")->Run(); } + v8::V8::ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); } } @@ -11044,6 +11478,7 @@ static void RunLoopInNewEnv() { TEST(SetFunctionEntryHook) { i::FLAG_allow_natives_syntax = true; + i::FLAG_use_inlining = false; // Test setting and resetting the entry hook. // Nulling it should always succeed. @@ -11176,10 +11611,6 @@ static void event_handler(const v8::JitCodeEvent* event) { } -// Implemented in the test-alloc.cc test suite. -void SimulateFullSpace(i::PagedSpace* space); - - static bool MatchPointers(void* key1, void* key2) { return key1 == key2; } @@ -12301,7 +12732,7 @@ static void MorphAString(i::String* string, AsciiVectorResource* ascii_resource, UC16VectorResource* uc16_resource) { CHECK(i::StringShape(string).IsExternal()); - if (string->IsAsciiRepresentation()) { + if (string->IsOneByteRepresentation()) { // Check old map is not symbol or long. CHECK(string->map() == HEAP->external_ascii_string_map()); // Morph external string to be TwoByte string. @@ -14436,6 +14867,89 @@ TEST(SourceURLInStackTrace) { } +v8::Handle<Value> AnalyzeStackOfInlineScriptWithSourceURL( + const v8::Arguments& args) { + v8::HandleScope scope; + v8::Handle<v8::StackTrace> stackTrace = + v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); + CHECK_EQ(4, stackTrace->GetFrameCount()); + v8::Handle<v8::String> url = v8_str("url"); + for (int i = 0; i < 3; i++) { + v8::Handle<v8::String> name = + stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); + CHECK(!name.IsEmpty()); + CHECK_EQ(url, name); + } + return v8::Undefined(); +} + + +TEST(InlineScriptWithSourceURLInStackTrace) { + v8::HandleScope scope; + Local<ObjectTemplate> templ = ObjectTemplate::New(); + templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"), + v8::FunctionTemplate::New( + AnalyzeStackOfInlineScriptWithSourceURL)); + LocalContext context(0, templ); + + const char *source = + "function outer() {\n" + "function bar() {\n" + " AnalyzeStackOfInlineScriptWithSourceURL();\n" + "}\n" + "function foo() {\n" + "\n" + " bar();\n" + "}\n" + "foo();\n" + "}\n" + "outer()\n" + "//@ sourceURL=source_url"; + CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined()); +} + + +v8::Handle<Value> AnalyzeStackOfDynamicScriptWithSourceURL( + const v8::Arguments& args) { + v8::HandleScope scope; + v8::Handle<v8::StackTrace> stackTrace = + v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); + CHECK_EQ(4, stackTrace->GetFrameCount()); + v8::Handle<v8::String> url = v8_str("source_url"); + for (int i = 0; i < 3; i++) { + v8::Handle<v8::String> name = + stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); + CHECK(!name.IsEmpty()); + CHECK_EQ(url, name); + } + return v8::Undefined(); +} + + +TEST(DynamicWithSourceURLInStackTrace) { + v8::HandleScope scope; + Local<ObjectTemplate> templ = ObjectTemplate::New(); + templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"), + v8::FunctionTemplate::New( + AnalyzeStackOfDynamicScriptWithSourceURL)); + LocalContext context(0, templ); + + const char *source = + "function outer() {\n" + "function bar() {\n" + " AnalyzeStackOfDynamicScriptWithSourceURL();\n" + "}\n" + "function foo() {\n" + "\n" + " bar();\n" + "}\n" + "foo();\n" + "}\n" + "outer()\n" + "//@ sourceURL=source_url"; + CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined()); +} + static void CreateGarbageInOldSpace() { v8::HandleScope scope; i::AlwaysAllocateScope always_allocate; @@ -14623,11 +15137,12 @@ THREADED_TEST(GetHeapStatistics) { class VisitorImpl : public v8::ExternalResourceVisitor { public: - VisitorImpl(TestResource* r1, TestResource* r2) - : resource1_(r1), - resource2_(r2), - found_resource1_(false), - found_resource2_(false) {} + explicit VisitorImpl(TestResource** resource) { + for (int i = 0; i < 4; i++) { + resource_[i] = resource[i]; + found_resource_[i] = false; + } + } virtual ~VisitorImpl() {} virtual void VisitExternalString(v8::Handle<v8::String> string) { if (!string->IsExternal()) { @@ -14637,25 +15152,22 @@ class VisitorImpl : public v8::ExternalResourceVisitor { v8::String::ExternalStringResource* resource = string->GetExternalStringResource(); CHECK(resource); - if (resource1_ == resource) { - CHECK(!found_resource1_); - found_resource1_ = true; - } - if (resource2_ == resource) { - CHECK(!found_resource2_); - found_resource2_ = true; + for (int i = 0; i < 4; i++) { + if (resource_[i] == resource) { + CHECK(!found_resource_[i]); + found_resource_[i] = true; + } } } void CheckVisitedResources() { - CHECK(found_resource1_); - CHECK(found_resource2_); + for (int i = 0; i < 4; i++) { + CHECK(found_resource_[i]); + } } private: - v8::String::ExternalStringResource* resource1_; - v8::String::ExternalStringResource* resource2_; - bool found_resource1_; - bool found_resource2_; + v8::String::ExternalStringResource* resource_[4]; + bool found_resource_[4]; }; TEST(VisitExternalStrings) { @@ -14663,16 +15175,33 @@ TEST(VisitExternalStrings) { LocalContext env; const char* string = "Some string"; uint16_t* two_byte_string = AsciiToTwoByteString(string); - TestResource* resource1 = new TestResource(two_byte_string); - v8::Local<v8::String> string1 = v8::String::NewExternal(resource1); - TestResource* resource2 = new TestResource(two_byte_string); - v8::Local<v8::String> string2 = v8::String::NewExternal(resource2); - - // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7 + TestResource* resource[4]; + resource[0] = new TestResource(two_byte_string); + v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]); + resource[1] = new TestResource(two_byte_string); + v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]); + + // Externalized symbol. + resource[2] = new TestResource(two_byte_string); + v8::Local<v8::String> string2 = v8::String::NewSymbol(string); + CHECK(string2->MakeExternal(resource[2])); + + // Symbolized External. + resource[3] = new TestResource(AsciiToTwoByteString("Some other string")); + v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]); + HEAP->CollectAllAvailableGarbage(); // Tenure string. + // Turn into a symbol. + i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3); + CHECK(!HEAP->LookupSymbol(*string3_i)->IsFailure()); + CHECK(string3_i->IsSymbol()); + + // We need to add usages for string* to avoid warnings in GCC 4.7 + CHECK(string0->IsExternal()); CHECK(string1->IsExternal()); CHECK(string2->IsExternal()); + CHECK(string3->IsExternal()); - VisitorImpl visitor(resource1, resource2); + VisitorImpl visitor(resource); v8::V8::VisitExternalResources(&visitor); visitor.CheckVisitedResources(); } @@ -14907,6 +15436,7 @@ TEST(Regress528) { context->Exit(); } context.Dispose(); + v8::V8::ContextDisposedNotification(); for (gc_count = 1; gc_count < 10; gc_count++) { other_context->Enter(); CompileRun(source_exception); @@ -15361,13 +15891,13 @@ THREADED_TEST(TwoByteStringInAsciiCons) { CHECK(result->IsString()); i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); int length = string->length(); - CHECK(string->IsAsciiRepresentation()); + CHECK(string->IsOneByteRepresentation()); FlattenString(string); i::Handle<i::String> flat_string = FlattenGetString(string); - CHECK(string->IsAsciiRepresentation()); - CHECK(flat_string->IsAsciiRepresentation()); + CHECK(string->IsOneByteRepresentation()); + CHECK(flat_string->IsOneByteRepresentation()); // Create external resource. uint16_t* uc16_buffer = new uint16_t[length + 1]; @@ -15386,7 +15916,7 @@ THREADED_TEST(TwoByteStringInAsciiCons) { // ASCII characters). This is a valid sequence of steps, and it can happen // in real pages. - CHECK(string->IsAsciiRepresentation()); + CHECK(string->IsOneByteRepresentation()); i::ConsString* cons = i::ConsString::cast(*string); CHECK_EQ(0, cons->second()->length()); CHECK(cons->first()->IsTwoByteRepresentation()); @@ -16073,6 +16603,45 @@ TEST(DontDeleteCellLoadICAPI) { } +class Visitor42 : public v8::PersistentHandleVisitor { + public: + explicit Visitor42(v8::Persistent<v8::Object> object) + : counter_(0), object_(object) { } + + virtual void VisitPersistentHandle(Persistent<Value> value, + uint16_t class_id) { + if (class_id == 42) { + CHECK(value->IsObject()); + v8::Persistent<v8::Object> visited = + v8::Persistent<v8::Object>::Cast(value); + CHECK_EQ(42, visited.WrapperClassId()); + CHECK_EQ(object_, visited); + ++counter_; + } + } + + int counter_; + v8::Persistent<v8::Object> object_; +}; + + +TEST(PersistentHandleVisitor) { + v8::HandleScope scope; + LocalContext context; + v8::Persistent<v8::Object> object = + v8::Persistent<v8::Object>::New(v8::Object::New()); + CHECK_EQ(0, object.WrapperClassId()); + object.SetWrapperClassId(42); + CHECK_EQ(42, object.WrapperClassId()); + + Visitor42 visitor(object); + v8::V8::VisitHandlesWithClassIds(&visitor); + CHECK_EQ(1, visitor.counter_); + + object.Dispose(); +} + + TEST(RegExp) { v8::HandleScope scope; LocalContext context; @@ -16508,6 +17077,24 @@ THREADED_TEST(AllowCodeGenFromStrings) { } +TEST(SetErrorMessageForCodeGenFromStrings) { + v8::HandleScope scope; + LocalContext context; + TryCatch try_catch; + + Handle<String> message = v8_str("Message") ; + Handle<String> expected_message = v8_str("Uncaught EvalError: Message"); + V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); + context->AllowCodeGenerationFromStrings(false); + context->SetErrorMessageForCodeGenerationFromStrings(message); + Handle<Value> result = CompileRun("eval('42')"); + CHECK(result.IsEmpty()); + CHECK(try_catch.HasCaught()); + Handle<String> actual_message = try_catch.Message()->Get(); + CHECK(expected_message->Equals(actual_message)); +} + + static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) { return v8::Undefined(); } @@ -17445,6 +18032,16 @@ THREADED_TEST(Regress149912) { } +THREADED_TEST(Regress157124) { + v8::HandleScope scope; + LocalContext context; + Local<ObjectTemplate> templ = ObjectTemplate::New(); + Local<Object> obj = templ->NewInstance(); + obj->GetIdentityHash(); + obj->DeleteHiddenValue(v8_str("Bug")); +} + + #ifndef WIN32 class ThreadInterruptTest { public: @@ -17496,7 +18093,6 @@ class ThreadInterruptTest { private: ThreadInterruptTest* test_; - struct sigaction sa_; }; i::Semaphore* sem_; diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc index cdab1b95ce..adec13b662 100644 --- a/deps/v8/test/cctest/test-assembler-arm.cc +++ b/deps/v8/test/cctest/test-assembler-arm.cc @@ -259,6 +259,8 @@ TEST(4) { __ vadd(d5, d6, d7); __ vstr(d5, r4, OFFSET_OF(T, c)); + __ vmla(d5, d6, d7); + __ vmov(r2, r3, d5); __ vmov(d4, r2, r3); __ vstr(d4, r4, OFFSET_OF(T, b)); @@ -347,7 +349,7 @@ TEST(4) { CHECK_EQ(1.0, t.e); CHECK_EQ(1.000000059604644775390625, t.d); CHECK_EQ(4.25, t.c); - CHECK_EQ(4.25, t.b); + CHECK_EQ(8.375, t.b); CHECK_EQ(1.5, t.a); } } diff --git a/deps/v8/test/cctest/test-compiler.cc b/deps/v8/test/cctest/test-compiler.cc index 961c94bff0..807adbf7f4 100644 --- a/deps/v8/test/cctest/test-compiler.cc +++ b/deps/v8/test/cctest/test-compiler.cc @@ -68,15 +68,9 @@ v8::Handle<v8::Value> PrintExtension::Print(const v8::Arguments& args) { for (int i = 0; i < args.Length(); i++) { if (i != 0) printf(" "); v8::HandleScope scope; - v8::Handle<v8::Value> arg = args[i]; - v8::Handle<v8::String> string_obj = arg->ToString(); - if (string_obj.IsEmpty()) return string_obj; - int length = string_obj->Length(); - uint16_t* string = NewArray<uint16_t>(length + 1); - string_obj->Write(string); - for (int j = 0; j < length; j++) - printf("%lc", static_cast<wchar_t>(string[j])); - DeleteArray(string); + v8::String::Utf8Value str(args[i]); + if (*str == NULL) return v8::Undefined(); + printf("%s", *str); } printf("\n"); return v8::Undefined(); @@ -106,10 +100,11 @@ static MaybeObject* GetGlobalProperty(const char* name) { static void SetGlobalProperty(const char* name, Object* value) { + Isolate* isolate = Isolate::Current(); Handle<Object> object(value); Handle<String> symbol = FACTORY->LookupAsciiSymbol(name); Handle<JSObject> global(Isolate::Current()->context()->global_object()); - SetProperty(global, symbol, object, NONE, kNonStrictMode); + SetProperty(isolate, global, symbol, object, NONE, kNonStrictMode); } diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index 234b6df722..941fa688d5 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -27,6 +27,9 @@ #ifdef ENABLE_DEBUGGER_SUPPORT +// TODO(svenpanne): Do not use Context::GetData and Context::SetData. +#define V8_DISABLE_DEPRECATIONS 1 + #include <stdlib.h> #include "v8.h" @@ -143,7 +146,8 @@ class DebugLocalContext { inline v8::Context* operator*() { return *context_; } inline bool IsReady() { return !context_.IsEmpty(); } void ExposeDebug() { - v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug(); + v8::internal::Isolate* isolate = v8::internal::Isolate::Current(); + v8::internal::Debug* debug = isolate->debug(); // Expose the debug context global object in the global object for testing. debug->Load(); debug->debug_context()->set_security_token( @@ -153,7 +157,7 @@ class DebugLocalContext { v8::Utils::OpenHandle(*context_->Global()))); Handle<v8::internal::String> debug_string = FACTORY->LookupAsciiSymbol("debug"); - SetProperty(global, debug_string, + SetProperty(isolate, global, debug_string, Handle<Object>(debug->debug_context()->global_proxy()), DONT_ENUM, ::v8::internal::kNonStrictMode); } @@ -2381,7 +2385,7 @@ TEST(DebuggerStatementBreakpoint) { } -// Thest that the evaluation of expressions when a break point is hit generates +// Test that the evaluation of expressions when a break point is hit generates // the correct results. TEST(DebugEvaluate) { v8::HandleScope scope; @@ -2497,6 +2501,98 @@ TEST(DebugEvaluate) { CheckDebuggerUnloaded(); } + +int debugEventCount = 0; +static void CheckDebugEvent(const v8::Debug::EventDetails& eventDetails) { + if (eventDetails.GetEvent() == v8::Break) ++debugEventCount; +} + +// Test that the conditional breakpoints work event if code generation from +// strings is prohibited in the debugee context. +TEST(ConditionalBreakpointWithCodeGenerationDisallowed) { + v8::HandleScope scope; + DebugLocalContext env; + env.ExposeDebug(); + + v8::Debug::SetDebugEventListener2(CheckDebugEvent); + + v8::Local<v8::Function> foo = CompileFunction(&env, + "function foo(x) {\n" + " var s = 'String value2';\n" + " return s + x;\n" + "}", + "foo"); + + // Set conditional breakpoint with condition 'true'. + CompileRun("debug.Debug.setBreakPoint(foo, 2, 0, 'true')"); + + debugEventCount = 0; + env->AllowCodeGenerationFromStrings(false); + foo->Call(env->Global(), 0, NULL); + CHECK_EQ(1, debugEventCount); + + v8::Debug::SetDebugEventListener2(NULL); + CheckDebuggerUnloaded(); +} + + +bool checkedDebugEvals = true; +v8::Handle<v8::Function> checkGlobalEvalFunction; +v8::Handle<v8::Function> checkFrameEvalFunction; +static void CheckDebugEval(const v8::Debug::EventDetails& eventDetails) { + if (eventDetails.GetEvent() == v8::Break) { + ++debugEventCount; + v8::HandleScope handleScope; + + v8::Handle<v8::Value> args[] = { eventDetails.GetExecutionState() }; + CHECK(checkGlobalEvalFunction->Call( + eventDetails.GetEventContext()->Global(), 1, args)->IsTrue()); + CHECK(checkFrameEvalFunction->Call( + eventDetails.GetEventContext()->Global(), 1, args)->IsTrue()); + } +} + +// Test that the evaluation of expressions when a break point is hit generates +// the correct results in case code generation from strings is disallowed in the +// debugee context. +TEST(DebugEvaluateWithCodeGenerationDisallowed) { + v8::HandleScope scope; + DebugLocalContext env; + env.ExposeDebug(); + + v8::Debug::SetDebugEventListener2(CheckDebugEval); + + v8::Local<v8::Function> foo = CompileFunction(&env, + "var global = 'Global';\n" + "function foo(x) {\n" + " var local = 'Local';\n" + " debugger;\n" + " return local + x;\n" + "}", + "foo"); + checkGlobalEvalFunction = CompileFunction(&env, + "function checkGlobalEval(exec_state) {\n" + " return exec_state.evaluateGlobal('global').value() === 'Global';\n" + "}", + "checkGlobalEval"); + + checkFrameEvalFunction = CompileFunction(&env, + "function checkFrameEval(exec_state) {\n" + " return exec_state.frame(0).evaluate('local').value() === 'Local';\n" + "}", + "checkFrameEval"); + debugEventCount = 0; + env->AllowCodeGenerationFromStrings(false); + foo->Call(env->Global(), 0, NULL); + CHECK_EQ(1, debugEventCount); + + checkGlobalEvalFunction.Clear(); + checkFrameEvalFunction.Clear(); + v8::Debug::SetDebugEventListener2(NULL); + CheckDebuggerUnloaded(); +} + + // Copies a C string to a 16-bit string. Does not check for buffer overflow. // Does not use the V8 engine to convert strings, so it can be used // in any thread. Returns the length of the string. @@ -4026,15 +4122,12 @@ TEST(StepWithException) { TEST(DebugBreak) { +#ifdef VERIFY_HEAP + i::FLAG_verify_heap = true; +#endif v8::HandleScope scope; DebugLocalContext env; - // This test should be run with option --verify-heap. As --verify-heap is - // only available in debug mode only check for it in that case. -#ifdef DEBUG - CHECK(v8::internal::FLAG_verify_heap); -#endif - // Register a debug event listener which sets the break flag and counts. v8::Debug::SetDebugEventListener(DebugEventBreak); @@ -5833,9 +5926,9 @@ TEST(DebuggerAgent) { i::Debugger* debugger = i::Isolate::Current()->debugger(); // Make sure these ports is not used by other tests to allow tests to run in // parallel. - const int kPort1 = 5858; - const int kPort2 = 5857; - const int kPort3 = 5856; + const int kPort1 = 5858 + FlagDependentPortOffset(); + const int kPort2 = 5857 + FlagDependentPortOffset(); + const int kPort3 = 5856 + FlagDependentPortOffset(); // Make a string with the port2 number. const int kPortBufferLen = 6; @@ -5934,7 +6027,7 @@ void DebuggerAgentProtocolServerThread::Run() { TEST(DebuggerAgentProtocolOverflowHeader) { // Make sure this port is not used by other tests to allow tests to run in // parallel. - const int kPort = 5860; + const int kPort = 5860 + FlagDependentPortOffset(); static const char* kLocalhost = "localhost"; // Make a string with the port number. diff --git a/deps/v8/test/cctest/test-decls.cc b/deps/v8/test/cctest/test-decls.cc index 6fc601213c..824c4e764a 100644 --- a/deps/v8/test/cctest/test-decls.cc +++ b/deps/v8/test/cctest/test-decls.cc @@ -190,7 +190,8 @@ v8::Handle<Integer> DeclarationContext::HandleQuery(Local<String> key, DeclarationContext* DeclarationContext::GetInstance(const AccessorInfo& info) { - return static_cast<DeclarationContext*>(External::Unwrap(info.Data())); + void* value = External::Cast(*info.Data())->Value(); + return static_cast<DeclarationContext*>(value); } @@ -734,7 +735,7 @@ class SimpleContext { }; -TEST(MultiScriptConflicts) { +TEST(CrossScriptReferences) { HandleScope scope; { SimpleContext context; @@ -772,135 +773,70 @@ TEST(MultiScriptConflicts) { context.Check("function x() { return 7 }; x", EXPECT_EXCEPTION); } +} + +TEST(CrossScriptReferencesHarmony) { i::FLAG_use_strict = true; i::FLAG_harmony_scoping = true; + i::FLAG_harmony_modules = true; - { SimpleContext context; - context.Check("var x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("x", - EXPECT_RESULT, Number::New(1)); - context.Check("this.x", - EXPECT_RESULT, Number::New(1)); - } - - { SimpleContext context; - context.Check("function x() { return 4 }; x()", - EXPECT_RESULT, Number::New(4)); - context.Check("x()", - EXPECT_RESULT, Number::New(4)); - context.Check("this.x()", - EXPECT_RESULT, Number::New(4)); - } + HandleScope scope; - { SimpleContext context; - context.Check("let x = 2; x", - EXPECT_RESULT, Number::New(2)); - context.Check("x", - EXPECT_RESULT, Number::New(2)); - // TODO(rossberg): The current ES6 draft spec does not reflect lexical - // bindings on the global object. However, this will probably change, in - // which case we reactivate the following test. - // context.Check("this.x", - // EXPECT_RESULT, Number::New(2)); - } + const char* decs[] = { + "var x = 1; x", "x", "this.x", + "function x() { return 1 }; x()", "x()", "this.x()", + "let x = 1; x", "x", "this.x", + "const x = 1; x", "x", "this.x", + "module x { export let a = 1 }; x.a", "x.a", "this.x.a", + NULL + }; - { SimpleContext context; - context.Check("const x = 3; x", - EXPECT_RESULT, Number::New(3)); - context.Check("x", - EXPECT_RESULT, Number::New(3)); + for (int i = 0; decs[i] != NULL; i += 3) { + SimpleContext context; + context.Check(decs[i], EXPECT_RESULT, Number::New(1)); + context.Check(decs[i+1], EXPECT_RESULT, Number::New(1)); // TODO(rossberg): The current ES6 draft spec does not reflect lexical // bindings on the global object. However, this will probably change, in // which case we reactivate the following test. - // context.Check("this.x", - // EXPECT_RESULT, Number::New(3)); - } - - // TODO(rossberg): All of the below should actually be errors in Harmony. - - { SimpleContext context; - context.Check("var x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("let x = 2; x", - EXPECT_RESULT, Number::New(2)); - } - - { SimpleContext context; - context.Check("var x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("const x = 2; x", - EXPECT_RESULT, Number::New(2)); - } - - { SimpleContext context; - context.Check("function x() { return 1 }; x()", - EXPECT_RESULT, Number::New(1)); - context.Check("let x = 2; x", - EXPECT_RESULT, Number::New(2)); - } - - { SimpleContext context; - context.Check("function x() { return 1 }; x()", - EXPECT_RESULT, Number::New(1)); - context.Check("const x = 2; x", - EXPECT_RESULT, Number::New(2)); - } - - { SimpleContext context; - context.Check("let x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("var x = 2; x", - EXPECT_ERROR); - } - - { SimpleContext context; - context.Check("let x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("let x = 2; x", - EXPECT_ERROR); - } - - { SimpleContext context; - context.Check("let x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("const x = 2; x", - EXPECT_ERROR); + if (i/3 < 2) context.Check(decs[i+2], EXPECT_RESULT, Number::New(1)); } +} - { SimpleContext context; - context.Check("let x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("function x() { return 2 }; x()", - EXPECT_ERROR); - } - { SimpleContext context; - context.Check("const x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("var x = 2; x", - EXPECT_ERROR); - } +TEST(CrossScriptConflicts) { + i::FLAG_use_strict = true; + i::FLAG_harmony_scoping = true; + i::FLAG_harmony_modules = true; - { SimpleContext context; - context.Check("const x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("let x = 2; x", - EXPECT_ERROR); - } + HandleScope scope; - { SimpleContext context; - context.Check("const x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("const x = 2; x", - EXPECT_ERROR); - } + const char* firsts[] = { + "var x = 1; x", + "function x() { return 1 }; x()", + "let x = 1; x", + "const x = 1; x", + "module x { export let a = 1 }; x.a", + NULL + }; + const char* seconds[] = { + "var x = 2; x", + "function x() { return 2 }; x()", + "let x = 2; x", + "const x = 2; x", + "module x { export let a = 2 }; x.a", + NULL + }; - { SimpleContext context; - context.Check("const x = 1; x", - EXPECT_RESULT, Number::New(1)); - context.Check("function x() { return 2 }; x()", - EXPECT_ERROR); + for (int i = 0; firsts[i] != NULL; ++i) { + for (int j = 0; seconds[j] != NULL; ++j) { + SimpleContext context; + context.Check(firsts[i], EXPECT_RESULT, Number::New(1)); + // TODO(rossberg): All tests should actually be errors in Harmony, + // but we currently do not detect the cases where the first declaration + // is not lexical. + context.Check(seconds[j], + i < 2 ? EXPECT_RESULT : EXPECT_ERROR, Number::New(2)); + } } } diff --git a/deps/v8/test/cctest/test-dictionary.cc b/deps/v8/test/cctest/test-dictionary.cc index 00e38333fc..2acd4e664e 100644 --- a/deps/v8/test/cctest/test-dictionary.cc +++ b/deps/v8/test/cctest/test-dictionary.cc @@ -114,7 +114,8 @@ TEST(ObjectHashSetCausesGC) { // Simulate a full heap so that generating an identity hash code // in subsequent calls will request GC. - FLAG_gc_interval = 0; + SimulateFullSpace(HEAP->new_space()); + SimulateFullSpace(HEAP->old_pointer_space()); // Calling Contains() should not cause GC ever. CHECK(!table->Contains(*key)); @@ -143,7 +144,8 @@ TEST(ObjectHashTableCausesGC) { // Simulate a full heap so that generating an identity hash code // in subsequent calls will request GC. - FLAG_gc_interval = 0; + SimulateFullSpace(HEAP->new_space()); + SimulateFullSpace(HEAP->old_pointer_space()); // Calling Lookup() should not cause GC ever. CHECK(table->Lookup(*key)->IsTheHole()); diff --git a/deps/v8/test/cctest/test-disasm-arm.cc b/deps/v8/test/cctest/test-disasm-arm.cc index 3a2d9e8361..0ac3c5a946 100644 --- a/deps/v8/test/cctest/test-disasm-arm.cc +++ b/deps/v8/test/cctest/test-disasm-arm.cc @@ -547,6 +547,11 @@ TEST(Vfp) { "ec860a20 vstmia r6, {s0-s31}"); COMPARE(vldm(ia, r7, s0, s31), "ec970a20 vldmia r7, {s0-s31}"); + + COMPARE(vmla(d2, d1, d0), + "ee012b00 vmla.f64 d2, d1, d0"); + COMPARE(vmla(d6, d4, d5, cc), + "3e046b05 vmla.f64cc d6, d4, d5"); } VERIFY_RUN(); @@ -753,4 +758,3 @@ TEST(LoadStore) { VERIFY_RUN(); } - diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index 1004104dd9..4a65344aa8 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -1015,7 +1015,6 @@ class TestRetainedObjectInfo : public v8::RetainedObjectInfo { private: bool disposed_; - int category_; int hash_; const char* group_label_; const char* label_; @@ -1228,6 +1227,33 @@ TEST(DeleteHeapSnapshot) { } +class NameResolver : public v8::HeapProfiler::ObjectNameResolver { + public: + virtual const char* GetName(v8::Handle<v8::Object> object) { + return "Global object name"; + } +}; + +TEST(GlobalObjectName) { + v8::HandleScope scope; + LocalContext env; + + CompileRun("document = { URL:\"abcdefgh\" };"); + + NameResolver name_resolver; + const v8::HeapSnapshot* snapshot = + v8::HeapProfiler::TakeSnapshot(v8_str("document"), + v8::HeapSnapshot::kFull, + NULL, + &name_resolver); + const v8::HeapGraphNode* global = GetGlobalObject(snapshot); + CHECK_NE(NULL, global); + CHECK_EQ("Object / Global object name" , + const_cast<i::HeapEntry*>( + reinterpret_cast<const i::HeapEntry*>(global))->name()); +} + + TEST(DocumentURL) { v8::HandleScope scope; LocalContext env; @@ -1670,13 +1696,14 @@ TEST(MapHasDescriptorsAndTransitions) { const v8::HeapGraphNode* global_object = GetProperty(global, v8::HeapGraphEdge::kProperty, "obj"); CHECK_NE(NULL, global_object); + const v8::HeapGraphNode* map = GetProperty(global_object, v8::HeapGraphEdge::kInternal, "map"); CHECK_NE(NULL, map); - const v8::HeapGraphNode* descriptors = - GetProperty(map, v8::HeapGraphEdge::kInternal, "descriptors"); - CHECK_NE(NULL, descriptors); - const v8::HeapGraphNode* transitions = - GetProperty(map, v8::HeapGraphEdge::kInternal, "transitions"); - CHECK_NE(NULL, transitions); + const v8::HeapGraphNode* own_descriptors = GetProperty( + map, v8::HeapGraphEdge::kInternal, "descriptors"); + CHECK_NE(NULL, own_descriptors); + const v8::HeapGraphNode* own_transitions = GetProperty( + map, v8::HeapGraphEdge::kInternal, "transitions"); + CHECK_EQ(NULL, own_transitions); } diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index 64ceccf806..93ac211687 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -23,6 +23,21 @@ static void InitializeVM() { } +// Go through all incremental marking steps in one swoop. +static void SimulateIncrementalMarking() { + IncrementalMarking* marking = HEAP->incremental_marking(); + CHECK(marking->IsMarking() || marking->IsStopped()); + if (marking->IsStopped()) { + marking->Start(); + } + CHECK(marking->IsMarking()); + while (!marking->IsComplete()) { + marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); + } + CHECK(marking->IsComplete()); +} + + static void CheckMap(Map* map, int type, int instance_size) { CHECK(map->IsHeapObject()); #ifdef DEBUG @@ -400,9 +415,10 @@ TEST(WeakGlobalHandlesMark) { h2 = global_handles->Create(*u); } + // Make sure the objects are promoted. HEAP->CollectGarbage(OLD_POINTER_SPACE); HEAP->CollectGarbage(NEW_SPACE); - // Make sure the object is promoted. + CHECK(!HEAP->InNewSpace(*h1) && !HEAP->InNewSpace(*h2)); global_handles->MakeWeak(h2.location(), reinterpret_cast<void*>(1234), @@ -410,7 +426,8 @@ TEST(WeakGlobalHandlesMark) { CHECK(!GlobalHandles::IsNearDeath(h1.location())); CHECK(!GlobalHandles::IsNearDeath(h2.location())); - HEAP->CollectGarbage(OLD_POINTER_SPACE); + // Incremental marking potentially marked handles before they turned weak. + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); CHECK((*h1)->IsString()); @@ -942,9 +959,9 @@ TEST(Regression39128) { TEST(TestCodeFlushing) { - i::FLAG_allow_natives_syntax = true; // If we do not flush code this test is invalid. if (!FLAG_flush_code) return; + i::FLAG_allow_natives_syntax = true; InitializeVM(); v8::HandleScope scope; const char* source = "function foo() {" @@ -967,18 +984,16 @@ TEST(TestCodeFlushing) { Handle<JSFunction> function(JSFunction::cast(func_value)); CHECK(function->shared()->is_compiled()); - // TODO(1609) Currently incremental marker does not support code flushing. + // The code will survive at least two GCs. HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - CHECK(function->shared()->is_compiled()); - HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + // Simulate several GCs that use full marking. + const int kAgingThreshold = 6; + for (int i = 0; i < kAgingThreshold; i++) { + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + } // foo should no longer be in the compilation cache CHECK(!function->shared()->is_compiled() || function->IsOptimized()); @@ -990,6 +1005,199 @@ TEST(TestCodeFlushing) { } +TEST(TestCodeFlushingIncremental) { + // If we do not flush code this test is invalid. + if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return; + i::FLAG_allow_natives_syntax = true; + InitializeVM(); + v8::HandleScope scope; + const char* source = "function foo() {" + " var x = 42;" + " var y = 42;" + " var z = x + y;" + "};" + "foo()"; + Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); + + // This compile will add the code to the compilation cache. + { v8::HandleScope scope; + CompileRun(source); + } + + // Check function is compiled. + Object* func_value = Isolate::Current()->context()->global_object()-> + GetProperty(*foo_name)->ToObjectChecked(); + CHECK(func_value->IsJSFunction()); + Handle<JSFunction> function(JSFunction::cast(func_value)); + CHECK(function->shared()->is_compiled()); + + // The code will survive at least two GCs. + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + CHECK(function->shared()->is_compiled()); + + // Simulate several GCs that use incremental marking. + const int kAgingThreshold = 6; + for (int i = 0; i < kAgingThreshold; i++) { + SimulateIncrementalMarking(); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + } + CHECK(!function->shared()->is_compiled() || function->IsOptimized()); + CHECK(!function->is_compiled() || function->IsOptimized()); + + // This compile will compile the function again. + { v8::HandleScope scope; + CompileRun("foo();"); + } + + // Simulate several GCs that use incremental marking but make sure + // the loop breaks once the function is enqueued as a candidate. + for (int i = 0; i < kAgingThreshold; i++) { + SimulateIncrementalMarking(); + if (!function->next_function_link()->IsUndefined()) break; + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + } + + // Force optimization while incremental marking is active and while + // the function is enqueued as a candidate. + { v8::HandleScope scope; + CompileRun("%OptimizeFunctionOnNextCall(foo); foo();"); + } + + // Simulate one final GC to make sure the candidate queue is sane. + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + CHECK(function->shared()->is_compiled() || !function->IsOptimized()); + CHECK(function->is_compiled() || !function->IsOptimized()); +} + + +TEST(TestCodeFlushingIncrementalScavenge) { + // If we do not flush code this test is invalid. + if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return; + i::FLAG_allow_natives_syntax = true; + InitializeVM(); + v8::HandleScope scope; + const char* source = "var foo = function() {" + " var x = 42;" + " var y = 42;" + " var z = x + y;" + "};" + "foo();" + "var bar = function() {" + " var x = 23;" + "};" + "bar();"; + Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); + Handle<String> bar_name = FACTORY->LookupAsciiSymbol("bar"); + + // Perfrom one initial GC to enable code flushing. + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + + // This compile will add the code to the compilation cache. + { v8::HandleScope scope; + CompileRun(source); + } + + // Check functions are compiled. + Object* func_value = Isolate::Current()->context()->global_object()-> + GetProperty(*foo_name)->ToObjectChecked(); + CHECK(func_value->IsJSFunction()); + Handle<JSFunction> function(JSFunction::cast(func_value)); + CHECK(function->shared()->is_compiled()); + Object* func_value2 = Isolate::Current()->context()->global_object()-> + GetProperty(*bar_name)->ToObjectChecked(); + CHECK(func_value2->IsJSFunction()); + Handle<JSFunction> function2(JSFunction::cast(func_value2)); + CHECK(function2->shared()->is_compiled()); + + // Clear references to functions so that one of them can die. + { v8::HandleScope scope; + CompileRun("foo = 0; bar = 0;"); + } + + // Bump the code age so that flushing is triggered while the function + // object is still located in new-space. + const int kAgingThreshold = 6; + for (int i = 0; i < kAgingThreshold; i++) { + function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2)); + function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2)); + } + + // Simulate incremental marking so that the functions are enqueued as + // code flushing candidates. Then kill one of the functions. Finally + // perform a scavenge while incremental marking is still running. + SimulateIncrementalMarking(); + *function2.location() = NULL; + HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking"); + + // Simulate one final GC to make sure the candidate queue is sane. + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + CHECK(!function->shared()->is_compiled() || function->IsOptimized()); + CHECK(!function->is_compiled() || function->IsOptimized()); +} + + +TEST(TestCodeFlushingIncrementalAbort) { + // If we do not flush code this test is invalid. + if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return; + i::FLAG_allow_natives_syntax = true; + InitializeVM(); + v8::HandleScope scope; + const char* source = "function foo() {" + " var x = 42;" + " var y = 42;" + " var z = x + y;" + "};" + "foo()"; + Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); + + // This compile will add the code to the compilation cache. + { v8::HandleScope scope; + CompileRun(source); + } + + // Check function is compiled. + Object* func_value = Isolate::Current()->context()->global_object()-> + GetProperty(*foo_name)->ToObjectChecked(); + CHECK(func_value->IsJSFunction()); + Handle<JSFunction> function(JSFunction::cast(func_value)); + CHECK(function->shared()->is_compiled()); + + // The code will survive at least two GCs. + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + CHECK(function->shared()->is_compiled()); + + // Bump the code age so that flushing is triggered. + const int kAgingThreshold = 6; + for (int i = 0; i < kAgingThreshold; i++) { + function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2)); + } + + // Simulate incremental marking so that the function is enqueued as + // code flushing candidate. + SimulateIncrementalMarking(); + + // Enable the debugger and add a breakpoint while incremental marking + // is running so that incremental marking aborts and code flushing is + // disabled. + int position = 0; + Handle<Object> breakpoint_object(Smi::FromInt(0)); + ISOLATE->debug()->SetBreakPoint(function, breakpoint_object, &position); + ISOLATE->debug()->ClearAllBreakPoints(); + + // Force optimization now that code flushing is disabled. + { v8::HandleScope scope; + CompileRun("%OptimizeFunctionOnNextCall(foo); foo();"); + } + + // Simulate one final GC to make sure the candidate queue is sane. + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + CHECK(function->shared()->is_compiled() || !function->IsOptimized()); + CHECK(function->is_compiled() || !function->IsOptimized()); +} + + // Count the number of native contexts in the weak list of native contexts. int CountNativeContexts() { int count = 0; @@ -1019,6 +1227,10 @@ static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) { TEST(TestInternalWeakLists) { v8::V8::Initialize(); + // Some flags turn Scavenge collections into Mark-sweep collections + // and hence are incompatible with this test case. + if (FLAG_gc_global || FLAG_stress_compaction) return; + static const int kNumTestContexts = 10; v8::HandleScope scope; @@ -1067,6 +1279,7 @@ TEST(TestInternalWeakLists) { } // Mark compact handles the weak references. + ISOLATE->compilation_cache()->Clear(); HEAP->CollectAllGarbage(Heap::kNoGCFlags); CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); @@ -1246,7 +1459,9 @@ TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { - size_of_objects_2 += obj->Size(); + if (!obj->IsFreeSpace()) { + size_of_objects_2 += obj->Size(); + } } // Delta must be within 5% of the larger result. // TODO(gc): Tighten this up by distinguishing between byte @@ -1275,7 +1490,6 @@ static void FillUpNewSpace(NewSpace* new_space) { // that the scavenger does not undo the filling. v8::HandleScope scope; AlwaysAllocateScope always_allocate; - LinearAllocationScope allocate_linearly; intptr_t available = new_space->EffectiveCapacity() - new_space->Size(); intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1; for (intptr_t i = 0; i < number_of_fillers; i++) { @@ -1397,6 +1611,7 @@ TEST(LeakNativeContextViaMap) { ctx2->Exit(); ctx1->Exit(); ctx1.Dispose(); + v8::V8::ContextDisposedNotification(); } HEAP->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1434,6 +1649,7 @@ TEST(LeakNativeContextViaFunction) { ctx2->Exit(); ctx1->Exit(); ctx1.Dispose(); + v8::V8::ContextDisposedNotification(); } HEAP->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1469,6 +1685,7 @@ TEST(LeakNativeContextViaMapKeyed) { ctx2->Exit(); ctx1->Exit(); ctx1.Dispose(); + v8::V8::ContextDisposedNotification(); } HEAP->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1508,6 +1725,7 @@ TEST(LeakNativeContextViaMapProto) { ctx2->Exit(); ctx1->Exit(); ctx1.Dispose(); + v8::V8::ContextDisposedNotification(); } HEAP->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1519,11 +1737,13 @@ TEST(LeakNativeContextViaMapProto) { TEST(InstanceOfStubWriteBarrier) { i::FLAG_allow_natives_syntax = true; -#ifdef DEBUG +#ifdef VERIFY_HEAP i::FLAG_verify_heap = true; #endif + InitializeVM(); if (!i::V8::UseCrankshaft()) return; + if (i::FLAG_force_marking_deque_overflows) return; v8::HandleScope outer_scope; { @@ -1609,10 +1829,11 @@ TEST(PrototypeTransitionClearing) { // Make sure next prototype is placed on an old-space evacuation candidate. Handle<JSObject> prototype; PagedSpace* space = HEAP->old_pointer_space(); - do { + { + AlwaysAllocateScope always_allocate; + SimulateFullSpace(space); prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED); - } while (space->FirstPage() == space->LastPage() || - !space->LastPage()->Contains(prototype->address())); + } // Add a prototype on an evacuation candidate and verify that transition // clearing correctly records slots in prototype transition array. @@ -1630,9 +1851,10 @@ TEST(PrototypeTransitionClearing) { TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) { i::FLAG_allow_natives_syntax = true; -#ifdef DEBUG +#ifdef VERIFY_HEAP i::FLAG_verify_heap = true; #endif + InitializeVM(); if (!i::V8::UseCrankshaft()) return; v8::HandleScope outer_scope; @@ -1685,9 +1907,10 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) { TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) { i::FLAG_allow_natives_syntax = true; -#ifdef DEBUG +#ifdef VERIFY_HEAP i::FLAG_verify_heap = true; #endif + InitializeVM(); if (!i::V8::UseCrankshaft()) return; v8::HandleScope outer_scope; @@ -1729,9 +1952,10 @@ TEST(OptimizedAllocationAlwaysInNewSpace) { i::FLAG_allow_natives_syntax = true; InitializeVM(); if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return; + if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope; - FillUpNewSpace(HEAP->new_space()); + SimulateFullSpace(HEAP->new_space()); AlwaysAllocateScope always_allocate; v8::Local<v8::Value> res = CompileRun( "function c(x) {" @@ -1758,19 +1982,6 @@ static int CountMapTransitions(Map* map) { } -// Go through all incremental marking steps in one swoop. -static void SimulateIncrementalMarking() { - IncrementalMarking* marking = HEAP->incremental_marking(); - CHECK(marking->IsStopped()); - marking->Start(); - CHECK(marking->IsMarking()); - while (!marking->IsComplete()) { - marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); - } - CHECK(marking->IsComplete()); -} - - // Test that map transitions are cleared and maps are collected with // incremental marking as well. TEST(Regress1465) { @@ -1895,10 +2106,6 @@ TEST(Regress2143b) { } -// Implemented in the test-alloc.cc test suite. -void SimulateFullSpace(PagedSpace* space); - - TEST(ReleaseOverReservedPages) { i::FLAG_trace_gc = true; // The optimizer can allocate stuff, messing up the test. @@ -1921,7 +2128,7 @@ TEST(ReleaseOverReservedPages) { // Triggering one GC will cause a lot of garbage to be discovered but // even spread across all allocated pages. HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation"); - CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages()); + CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages()); // Triggering subsequent GCs should cause at least half of the pages // to be released to the OS after at most two cycles. @@ -1930,8 +2137,13 @@ TEST(ReleaseOverReservedPages) { HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2"); CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2); - // Triggering a last-resort GC should cause all pages to be released - // to the OS so that other processes can seize the memory. + // Triggering a last-resort GC should cause all pages to be released to the + // OS so that other processes can seize the memory. If we get a failure here + // where there are 2 pages left instead of 1, then we should increase the + // size of the first page a little in SizeOfFirstPage in spaces.cc. The + // first page should be small in order to reduce memory used when the VM + // boots, but if the 20 small arrays don't fit on the first page then that's + // an indication that it is too small. HEAP->CollectAllAvailableGarbage("triggered really hard"); CHECK_EQ(1, old_pointer_space->CountTotalPages()); } @@ -1947,27 +2159,22 @@ TEST(Regress2237) { v8::HandleScope inner_scope; const char* c = "This text is long enough to trigger sliced strings."; Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c)); - CHECK(s->IsSeqAsciiString()); + CHECK(s->IsSeqOneByteString()); CHECK(HEAP->InNewSpace(*s)); // Generate a sliced string that is based on the above parent and // lives in old-space. - FillUpNewSpace(HEAP->new_space()); + SimulateFullSpace(HEAP->new_space()); AlwaysAllocateScope always_allocate; - Handle<String> t; - // TODO(mstarzinger): Unfortunately FillUpNewSpace() still leaves - // some slack, so we need to allocate a few sliced strings. - for (int i = 0; i < 16; i++) { - t = FACTORY->NewProperSubString(s, 5, 35); - } + Handle<String> t = FACTORY->NewProperSubString(s, 5, 35); CHECK(t->IsSlicedString()); CHECK(!HEAP->InNewSpace(*t)); *slice.location() = *t.location(); } - CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString()); + CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString()); HEAP->CollectAllGarbage(Heap::kNoGCFlags); - CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString()); + CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString()); } @@ -2102,8 +2309,6 @@ TEST(IncrementalMarkingPreservesMonomorhpicIC) { Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); CHECK(ic_before->ic_state() == MONOMORPHIC); - // Fire context dispose notification. - v8::V8::ContextDisposedNotification(); SimulateIncrementalMarking(); HEAP->CollectAllGarbage(Heap::kNoGCFlags); @@ -2209,19 +2414,13 @@ class SourceResource: public v8::String::ExternalAsciiStringResource { }; -TEST(ReleaseStackTraceData) { +void ReleaseStackTraceDataTest(const char* source) { // Test that the data retained by the Error.stack accessor is released // after the first time the accessor is fired. We use external string // to check whether the data is being released since the external string // resource's callback is fired when the external string is GC'ed. InitializeVM(); v8::HandleScope scope; - static const char* source = "var error = 1; " - "try { " - " throw new Error(); " - "} catch (e) { " - " error = e; " - "} "; SourceResource* resource = new SourceResource(i::StrDup(source)); { v8::HandleScope scope; @@ -2233,15 +2432,32 @@ TEST(ReleaseStackTraceData) { // External source is being retained by the stack trace. CHECK(!resource->IsDisposed()); - CompileRun("error.stack; error.stack;"); + CompileRun("error.stack;"); HEAP->CollectAllAvailableGarbage(); // External source has been released. CHECK(resource->IsDisposed()); - delete resource; } +TEST(ReleaseStackTraceData) { + static const char* source1 = "var error = null; " + /* Normal Error */ "try { " + " throw new Error(); " + "} catch (e) { " + " error = e; " + "} "; + static const char* source2 = "var error = null; " + /* Stack overflow */ "try { " + " (function f() { f(); })(); " + "} catch (e) { " + " error = e; " + "} "; + ReleaseStackTraceDataTest(source1); + ReleaseStackTraceDataTest(source2); +} + + TEST(Regression144230) { InitializeVM(); v8::HandleScope scope; @@ -2299,3 +2515,63 @@ TEST(Regression144230) { USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode)); CompileRun("call();"); } + + +TEST(Regress159140) { + i::FLAG_allow_natives_syntax = true; + i::FLAG_flush_code_incrementally = true; + InitializeVM(); + v8::HandleScope scope; + + // Perform one initial GC to enable code flushing. + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + + // Prepare several closures that are all eligible for code flushing + // because all reachable ones are not optimized. Make sure that the + // optimized code object is directly reachable through a handle so + // that it is marked black during incremental marking. + Handle<Code> code; + { + HandleScope inner_scope; + CompileRun("function h(x) {}" + "function mkClosure() {" + " return function(x) { return x + 1; };" + "}" + "var f = mkClosure();" + "var g = mkClosure();" + "f(1); f(2);" + "g(1); g(2);" + "h(1); h(2);" + "%OptimizeFunctionOnNextCall(f); f(3);" + "%OptimizeFunctionOnNextCall(h); h(3);"); + + Handle<JSFunction> f = + v8::Utils::OpenHandle( + *v8::Handle<v8::Function>::Cast( + v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); + CHECK(f->is_compiled()); + CompileRun("f = null;"); + + Handle<JSFunction> g = + v8::Utils::OpenHandle( + *v8::Handle<v8::Function>::Cast( + v8::Context::GetCurrent()->Global()->Get(v8_str("g")))); + CHECK(g->is_compiled()); + const int kAgingThreshold = 6; + for (int i = 0; i < kAgingThreshold; i++) { + g->code()->MakeOlder(static_cast<MarkingParity>(i % 2)); + } + + code = inner_scope.CloseAndEscape(Handle<Code>(f->code())); + } + + // Simulate incremental marking so that the functions are enqueued as + // code flushing candidates. Then optimize one function. Finally + // finish the GC to complete code flushing. + SimulateIncrementalMarking(); + CompileRun("%OptimizeFunctionOnNextCall(g); g(3);"); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + + // Unoptimized code is missing and the deoptimizer will go ballistic. + CompileRun("g('bozo');"); +} diff --git a/deps/v8/test/cctest/test-lockers.cc b/deps/v8/test/cctest/test-lockers.cc index 5035f87642..57f7178493 100644 --- a/deps/v8/test/cctest/test-lockers.cc +++ b/deps/v8/test/cctest/test-lockers.cc @@ -59,9 +59,9 @@ using ::v8::V8; class KangarooThread : public v8::internal::Thread { public: KangarooThread(v8::Isolate* isolate, - v8::Handle<v8::Context> context, int value) + v8::Handle<v8::Context> context) : Thread("KangarooThread"), - isolate_(isolate), context_(context), value_(value) { + isolate_(isolate), context_(context) { } void Run() { @@ -90,7 +90,6 @@ class KangarooThread : public v8::internal::Thread { private: v8::Isolate* isolate_; Persistent<v8::Context> context_; - int value_; }; // Migrates an isolate from one thread to another @@ -106,7 +105,7 @@ TEST(KangarooIsolates) { CHECK_EQ(isolate, v8::internal::Isolate::Current()); CompileRun("function getValue() { return 30; }"); } - KangarooThread thread1(isolate, context, 1); + KangarooThread thread1(isolate, context); thread1.Start(); thread1.Join(); } diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc index 6f2324dbb8..892a542229 100644 --- a/deps/v8/test/cctest/test-log.cc +++ b/deps/v8/test/cctest/test-log.cc @@ -392,7 +392,7 @@ TEST(LogCallbacks) { i::EmbeddedVector<char, 100> ref_data; i::OS::SNPrintF(ref_data, - "code-creation,Callback,0x%" V8PRIxPTR ",1,\"method1\"\0", + "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"method1\"\0", ObjMethod1); CHECK_NE(NULL, StrNStr(log.start(), ref_data.start(), log.length())); @@ -435,21 +435,21 @@ TEST(LogAccessorCallbacks) { EmbeddedVector<char, 100> prop1_getter_record; i::OS::SNPrintF(prop1_getter_record, - "code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop1\"", + "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"get prop1\"", Prop1Getter); CHECK_NE(NULL, StrNStr(log.start(), prop1_getter_record.start(), log.length())); EmbeddedVector<char, 100> prop1_setter_record; i::OS::SNPrintF(prop1_setter_record, - "code-creation,Callback,0x%" V8PRIxPTR ",1,\"set prop1\"", + "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"set prop1\"", Prop1Setter); CHECK_NE(NULL, StrNStr(log.start(), prop1_setter_record.start(), log.length())); EmbeddedVector<char, 100> prop2_getter_record; i::OS::SNPrintF(prop2_getter_record, - "code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop2\"", + "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"get prop2\"", Prop2Getter); CHECK_NE(NULL, StrNStr(log.start(), prop2_getter_record.start(), log.length())); diff --git a/deps/v8/test/cctest/test-mark-compact.cc b/deps/v8/test/cctest/test-mark-compact.cc index 18c63b2fd0..69abd8d680 100644 --- a/deps/v8/test/cctest/test-mark-compact.cc +++ b/deps/v8/test/cctest/test-mark-compact.cc @@ -311,6 +311,7 @@ static void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) { } TEST(ObjectGroups) { + FLAG_incremental_marking = false; InitializeVM(); GlobalHandles* global_handles = Isolate::Current()->global_handles(); @@ -545,9 +546,9 @@ TEST(BootUpMemoryUse) { } } else { if (v8::internal::Snapshot::IsEnabled()) { - CHECK_LE(delta, 2600 * 1024); // 2484. + CHECK_LE(delta, 2500 * 1024); // 2400. } else { - CHECK_LE(delta, 2950 * 1024); // 2844 + CHECK_LE(delta, 2860 * 1024); // 2760. } } } diff --git a/deps/v8/test/cctest/test-object-observe.cc b/deps/v8/test/cctest/test-object-observe.cc new file mode 100644 index 0000000000..25e5557a89 --- /dev/null +++ b/deps/v8/test/cctest/test-object-observe.cc @@ -0,0 +1,280 @@ +// 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. + +#include "v8.h" + +#include "cctest.h" + +using namespace v8; + +namespace { +// Need to create a new isolate when FLAG_harmony_observation is on. +class HarmonyIsolate { + public: + HarmonyIsolate() { + i::FLAG_harmony_observation = true; + isolate_ = Isolate::New(); + isolate_->Enter(); + } + + ~HarmonyIsolate() { + isolate_->Exit(); + isolate_->Dispose(); + } + + private: + Isolate* isolate_; +}; +} + +TEST(PerIsolateState) { + HarmonyIsolate isolate; + HandleScope scope; + LocalContext context1; + CompileRun( + "var count = 0;" + "var calls = 0;" + "var observer = function(records) { count = records.length; calls++ };" + "var obj = {};" + "Object.observe(obj, observer);"); + Handle<Value> observer = CompileRun("observer"); + Handle<Value> obj = CompileRun("obj"); + Handle<Value> notify_fun1 = CompileRun( + "(function() { obj.foo = 'bar'; })"); + Handle<Value> notify_fun2; + { + LocalContext context2; + context2->Global()->Set(String::New("obj"), obj); + notify_fun2 = CompileRun( + "(function() { obj.foo = 'baz'; })"); + } + Handle<Value> notify_fun3; + { + LocalContext context3; + context3->Global()->Set(String::New("obj"), obj); + notify_fun3 = CompileRun( + "(function() { obj.foo = 'bat'; })"); + } + { + LocalContext context4; + context4->Global()->Set(String::New("observer"), observer); + context4->Global()->Set(String::New("fun1"), notify_fun1); + context4->Global()->Set(String::New("fun2"), notify_fun2); + context4->Global()->Set(String::New("fun3"), notify_fun3); + CompileRun("fun1(); fun2(); fun3(); Object.deliverChangeRecords(observer)"); + } + CHECK_EQ(1, CompileRun("calls")->Int32Value()); + CHECK_EQ(3, CompileRun("count")->Int32Value()); +} + +TEST(EndOfMicrotaskDelivery) { + HarmonyIsolate isolate; + HandleScope scope; + LocalContext context; + CompileRun( + "var obj = {};" + "var count = 0;" + "var observer = function(records) { count = records.length };" + "Object.observe(obj, observer);" + "obj.foo = 'bar';"); + CHECK_EQ(1, CompileRun("count")->Int32Value()); +} + +TEST(DeliveryOrdering) { + HarmonyIsolate isolate; + HandleScope scope; + LocalContext context; + CompileRun( + "var obj1 = {};" + "var obj2 = {};" + "var ordering = [];" + "function observer2() { ordering.push(2); };" + "function observer1() { ordering.push(1); };" + "function observer3() { ordering.push(3); };" + "Object.observe(obj1, observer1);" + "Object.observe(obj1, observer2);" + "Object.observe(obj1, observer3);" + "obj1.foo = 'bar';"); + CHECK_EQ(3, CompileRun("ordering.length")->Int32Value()); + CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value()); + CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); + CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value()); + CompileRun( + "ordering = [];" + "Object.observe(obj2, observer3);" + "Object.observe(obj2, observer2);" + "Object.observe(obj2, observer1);" + "obj2.foo = 'baz'"); + CHECK_EQ(3, CompileRun("ordering.length")->Int32Value()); + CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value()); + CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); + CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value()); +} + +TEST(DeliveryOrderingReentrant) { + HarmonyIsolate isolate; + HandleScope scope; + LocalContext context; + CompileRun( + "var obj = {};" + "var reentered = false;" + "var ordering = [];" + "function observer1() { ordering.push(1); };" + "function observer2() {" + " if (!reentered) {" + " obj.foo = 'baz';" + " reentered = true;" + " }" + " ordering.push(2);" + "};" + "function observer3() { ordering.push(3); };" + "Object.observe(obj, observer1);" + "Object.observe(obj, observer2);" + "Object.observe(obj, observer3);" + "obj.foo = 'bar';"); + CHECK_EQ(5, CompileRun("ordering.length")->Int32Value()); + CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value()); + CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); + CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value()); + // Note that we re-deliver to observers 1 and 2, while observer3 + // already received the second record during the first round. + CHECK_EQ(1, CompileRun("ordering[3]")->Int32Value()); + CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); +} + +TEST(DeliveryOrderingDeliverChangeRecords) { + HarmonyIsolate isolate; + HandleScope scope; + LocalContext context; + CompileRun( + "var obj = {};" + "var ordering = [];" + "function observer1() { ordering.push(1); if (!obj.b) obj.b = true };" + "function observer2() { ordering.push(2); };" + "Object.observe(obj, observer1);" + "Object.observe(obj, observer2);" + "obj.a = 1;" + "Object.deliverChangeRecords(observer2);"); + CHECK_EQ(4, CompileRun("ordering.length")->Int32Value()); + // First, observer2 is called due to deliverChangeRecords + CHECK_EQ(2, CompileRun("ordering[0]")->Int32Value()); + // Then, observer1 is called when the stack unwinds + CHECK_EQ(1, CompileRun("ordering[1]")->Int32Value()); + // observer1's mutation causes both 1 and 2 to be reactivated, + // with 1 having priority. + CHECK_EQ(1, CompileRun("ordering[2]")->Int32Value()); + CHECK_EQ(2, CompileRun("ordering[3]")->Int32Value()); +} + +TEST(ObjectHashTableGrowth) { + HarmonyIsolate isolate; + HandleScope scope; + // Initializing this context sets up initial hash tables. + LocalContext context; + Handle<Value> obj = CompileRun("obj = {};"); + Handle<Value> observer = CompileRun( + "var ran = false;" + "(function() { ran = true })"); + { + // As does initializing this context. + LocalContext context2; + context2->Global()->Set(String::New("obj"), obj); + context2->Global()->Set(String::New("observer"), observer); + CompileRun( + "var objArr = [];" + // 100 objects should be enough to make the hash table grow + // (and thus relocate). + "for (var i = 0; i < 100; ++i) {" + " objArr.push({});" + " Object.observe(objArr[objArr.length-1], function(){});" + "}" + "Object.observe(obj, observer);"); + } + // obj is now marked "is_observed", but our map has moved. + CompileRun("obj.foo = 'bar'"); + CHECK(CompileRun("ran")->BooleanValue()); +} + +TEST(GlobalObjectObservation) { + HarmonyIsolate isolate; + HandleScope scope; + LocalContext context; + Handle<Object> global_proxy = context->Global(); + Handle<Object> inner_global = global_proxy->GetPrototype().As<Object>(); + CompileRun( + "var records = [];" + "var global = this;" + "Object.observe(global, function(r) { [].push.apply(records, r) });" + "global.foo = 'hello';"); + CHECK_EQ(1, CompileRun("records.length")->Int32Value()); + CHECK(global_proxy->StrictEquals(CompileRun("records[0].object"))); + + // Detached, mutating the proxy has no effect. + context->DetachGlobal(); + CompileRun("global.bar = 'goodbye';"); + CHECK_EQ(1, CompileRun("records.length")->Int32Value()); + + // Mutating the global object directly still has an effect... + CompileRun("this.bar = 'goodbye';"); + CHECK_EQ(2, CompileRun("records.length")->Int32Value()); + CHECK(inner_global->StrictEquals(CompileRun("records[1].object"))); + + // Reattached, back to global proxy. + context->ReattachGlobal(global_proxy); + CompileRun("global.baz = 'again';"); + CHECK_EQ(3, CompileRun("records.length")->Int32Value()); + CHECK(global_proxy->StrictEquals(CompileRun("records[2].object"))); + + // Attached to a different context, should not leak mutations + // to the old context. + context->DetachGlobal(); + { + LocalContext context2; + context2->DetachGlobal(); + context2->ReattachGlobal(global_proxy); + CompileRun( + "var records2 = [];" + "Object.observe(this, function(r) { [].push.apply(records2, r) });" + "this.bat = 'context2';"); + CHECK_EQ(1, CompileRun("records2.length")->Int32Value()); + CHECK(global_proxy->StrictEquals(CompileRun("records2[0].object"))); + } + CHECK_EQ(3, CompileRun("records.length")->Int32Value()); + + // Attaching by passing to Context::New + { + // Delegates to Context::New + LocalContext context3(NULL, Handle<ObjectTemplate>(), global_proxy); + CompileRun( + "var records3 = [];" + "Object.observe(this, function(r) { [].push.apply(records3, r) });" + "this.qux = 'context3';"); + CHECK_EQ(1, CompileRun("records3.length")->Int32Value()); + CHECK(global_proxy->StrictEquals(CompileRun("records3[0].object"))); + } + CHECK_EQ(3, CompileRun("records.length")->Int32Value()); +} diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc index 717c66519f..ed480cd0d0 100755 --- a/deps/v8/test/cctest/test-parsing.cc +++ b/deps/v8/test/cctest/test-parsing.cc @@ -1041,6 +1041,31 @@ TEST(ScopePositions) { } +i::Handle<i::String> FormatMessage(i::ScriptDataImpl* data) { + i::Handle<i::String> format = v8::Utils::OpenHandle( + *v8::String::New(data->BuildMessage())); + i::Vector<const char*> args = data->BuildArgs(); + i::Handle<i::JSArray> args_array = FACTORY->NewJSArray(args.length()); + for (int i = 0; i < args.length(); i++) { + i::JSArray::SetElement(args_array, + i, + v8::Utils::OpenHandle(*v8::String::New(args[i])), + NONE, + i::kNonStrictMode); + } + i::Handle<i::JSObject> builtins(i::Isolate::Current()->js_builtins_object()); + i::Handle<i::Object> format_fun = + i::GetProperty(builtins, "FormatMessage"); + i::Handle<i::Object> arg_handles[] = { format, args_array }; + bool has_exception = false; + i::Handle<i::Object> result = + i::Execution::Call(format_fun, builtins, 2, arg_handles, &has_exception); + CHECK(!has_exception); + CHECK(result->IsString()); + return i::Handle<i::String>::cast(result); +} + + void TestParserSync(i::Handle<i::String> source, int flags) { uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit(); bool harmony_scoping = ((i::kLanguageModeMask & flags) == i::EXTENDED_MODE); @@ -1067,53 +1092,50 @@ void TestParserSync(i::Handle<i::String> source, int flags) { i::FunctionLiteral* function = parser.ParseProgram(); i::FLAG_harmony_scoping = save_harmony_scoping; - i::String* type_string = NULL; + // Check that preparsing fails iff parsing fails. if (function == NULL) { // Extract exception from the parser. - i::Handle<i::String> type_symbol = FACTORY->LookupAsciiSymbol("type"); CHECK(i::Isolate::Current()->has_pending_exception()); i::MaybeObject* maybe_object = i::Isolate::Current()->pending_exception(); i::JSObject* exception = NULL; CHECK(maybe_object->To(&exception)); + i::Handle<i::JSObject> exception_handle(exception); + i::Handle<i::String> message_string = + i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message")); - // Get the type string. - maybe_object = exception->GetProperty(*type_symbol); - CHECK(maybe_object->To(&type_string)); - } - - // Check that preparsing fails iff parsing fails. - if (data.has_error() && function != NULL) { - i::OS::Print( - "Preparser failed on:\n" - "\t%s\n" - "with error:\n" - "\t%s\n" - "However, the parser succeeded", - *source->ToCString(), data.BuildMessage()); - CHECK(false); - } else if (!data.has_error() && function == NULL) { - i::OS::Print( - "Parser failed on:\n" - "\t%s\n" - "with error:\n" - "\t%s\n" - "However, the preparser succeeded", - *source->ToCString(), *type_string->ToCString()); - CHECK(false); - } - - // Check that preparser and parser produce the same error. - if (function == NULL) { - if (!type_string->IsEqualTo(i::CStrVector(data.BuildMessage()))) { + if (!data.has_error()) { + i::OS::Print( + "Parser failed on:\n" + "\t%s\n" + "with error:\n" + "\t%s\n" + "However, the preparser succeeded", + *source->ToCString(), *message_string->ToCString()); + CHECK(false); + } + // Check that preparser and parser produce the same error. + i::Handle<i::String> preparser_message = FormatMessage(&data); + if (!message_string->Equals(*preparser_message)) { i::OS::Print( "Expected parser and preparser to produce the same error on:\n" "\t%s\n" "However, found the following error messages\n" "\tparser: %s\n" "\tpreparser: %s\n", - *source->ToCString(), *type_string->ToCString(), data.BuildMessage()); + *source->ToCString(), + *message_string->ToCString(), + *preparser_message->ToCString()); CHECK(false); } + } else if (data.has_error()) { + i::OS::Print( + "Preparser failed on:\n" + "\t%s\n" + "with error:\n" + "\t%s\n" + "However, the parser succeeded", + *source->ToCString(), *FormatMessage(&data)->ToCString()); + CHECK(false); } } diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index e433b925e8..726108d270 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -759,7 +759,7 @@ TEST(MacroAssemblerNativeSuccess) { int captures[4] = {42, 37, 87, 117}; Handle<String> input = factory->NewStringFromAscii(CStrVector("foofoo")); - Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); + Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input); const byte* start_adr = reinterpret_cast<const byte*>(seq_input->GetCharsAddress()); @@ -805,7 +805,7 @@ TEST(MacroAssemblerNativeSimple) { int captures[4] = {42, 37, 87, 117}; Handle<String> input = factory->NewStringFromAscii(CStrVector("foofoo")); - Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); + Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input); Address start_adr = seq_input->GetCharsAddress(); NativeRegExpMacroAssembler::Result result = @@ -823,7 +823,7 @@ TEST(MacroAssemblerNativeSimple) { CHECK_EQ(-1, captures[3]); input = factory->NewStringFromAscii(CStrVector("barbarbar")); - seq_input = Handle<SeqAsciiString>::cast(input); + seq_input = Handle<SeqOneByteString>::cast(input); start_adr = seq_input->GetCharsAddress(); result = Execute(*code, @@ -924,7 +924,7 @@ TEST(MacroAssemblerNativeBacktrack) { Handle<Code> code = Handle<Code>::cast(code_object); Handle<String> input = factory->NewStringFromAscii(CStrVector("foofoo")); - Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); + Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input); Address start_adr = seq_input->GetCharsAddress(); NativeRegExpMacroAssembler::Result result = @@ -967,7 +967,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) { Handle<Code> code = Handle<Code>::cast(code_object); Handle<String> input = factory->NewStringFromAscii(CStrVector("fooofo")); - Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); + Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input); Address start_adr = seq_input->GetCharsAddress(); int output[4]; @@ -1072,7 +1072,7 @@ TEST(MacroAssemblernativeAtStart) { Handle<Code> code = Handle<Code>::cast(code_object); Handle<String> input = factory->NewStringFromAscii(CStrVector("foobar")); - Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); + Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input); Address start_adr = seq_input->GetCharsAddress(); NativeRegExpMacroAssembler::Result result = @@ -1133,7 +1133,7 @@ TEST(MacroAssemblerNativeBackRefNoCase) { Handle<String> input = factory->NewStringFromAscii(CStrVector("aBcAbCABCxYzab")); - Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); + Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input); Address start_adr = seq_input->GetCharsAddress(); int output[4]; @@ -1234,7 +1234,7 @@ TEST(MacroAssemblerNativeRegisters) { // String long enough for test (content doesn't matter). Handle<String> input = factory->NewStringFromAscii(CStrVector("foofoofoofoofoo")); - Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); + Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input); Address start_adr = seq_input->GetCharsAddress(); int output[6]; @@ -1278,7 +1278,7 @@ TEST(MacroAssemblerStackOverflow) { // String long enough for test (content doesn't matter). Handle<String> input = factory->NewStringFromAscii(CStrVector("dummy")); - Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); + Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input); Address start_adr = seq_input->GetCharsAddress(); NativeRegExpMacroAssembler::Result result = @@ -1325,7 +1325,7 @@ TEST(MacroAssemblerNativeLotsOfRegisters) { // String long enough for test (content doesn't matter). Handle<String> input = factory->NewStringFromAscii(CStrVector("sample text")); - Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); + Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input); Address start_adr = seq_input->GetCharsAddress(); int captures[2]; diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc index c4654868aa..8279182497 100644 --- a/deps/v8/test/cctest/test-serialize.cc +++ b/deps/v8/test/cctest/test-serialize.cc @@ -196,8 +196,7 @@ class FileByteSink : public SnapshotByteSink { int data_space_used, int code_space_used, int map_space_used, - int cell_space_used, - int large_space_used); + int cell_space_used); private: FILE* fp_; @@ -211,8 +210,7 @@ void FileByteSink::WriteSpaceUsed( int data_space_used, int code_space_used, int map_space_used, - int cell_space_used, - int large_space_used) { + int cell_space_used) { int file_name_length = StrLength(file_name_) + 10; Vector<char> name = Vector<char>::New(file_name_length + 1); OS::SNPrintF(name, "%s.size", file_name_); @@ -224,7 +222,6 @@ void FileByteSink::WriteSpaceUsed( fprintf(fp, "code %d\n", code_space_used); fprintf(fp, "map %d\n", map_space_used); fprintf(fp, "cell %d\n", cell_space_used); - fprintf(fp, "large %d\n", large_space_used); fclose(fp); } @@ -233,6 +230,15 @@ static bool WriteToFile(const char* snapshot_file) { FileByteSink file(snapshot_file); StartupSerializer ser(&file); ser.Serialize(); + + file.WriteSpaceUsed( + ser.CurrentAllocationAddress(NEW_SPACE), + ser.CurrentAllocationAddress(OLD_POINTER_SPACE), + ser.CurrentAllocationAddress(OLD_DATA_SPACE), + ser.CurrentAllocationAddress(CODE_SPACE), + ser.CurrentAllocationAddress(MAP_SPACE), + ser.CurrentAllocationAddress(CELL_SPACE)); + return true; } @@ -279,7 +285,7 @@ static void Deserialize() { static void SanityCheck() { v8::HandleScope scope; -#ifdef DEBUG +#ifdef VERIFY_HEAP HEAP->Verify(); #endif CHECK(Isolate::Current()->global_object()->IsJSObject()); @@ -384,7 +390,6 @@ TEST(PartialSerialization) { env.Dispose(); FileByteSink startup_sink(startup_name.start()); - startup_name.Dispose(); StartupSerializer startup_serializer(&startup_sink); startup_serializer.SerializeStrongReferences(); @@ -392,26 +397,35 @@ TEST(PartialSerialization) { PartialSerializer p_ser(&startup_serializer, &partial_sink); p_ser.Serialize(&raw_foo); startup_serializer.SerializeWeakReferences(); + partial_sink.WriteSpaceUsed( p_ser.CurrentAllocationAddress(NEW_SPACE), p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE), p_ser.CurrentAllocationAddress(OLD_DATA_SPACE), p_ser.CurrentAllocationAddress(CODE_SPACE), p_ser.CurrentAllocationAddress(MAP_SPACE), - p_ser.CurrentAllocationAddress(CELL_SPACE), - p_ser.CurrentAllocationAddress(LO_SPACE)); + p_ser.CurrentAllocationAddress(CELL_SPACE)); + + startup_sink.WriteSpaceUsed( + startup_serializer.CurrentAllocationAddress(NEW_SPACE), + startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE), + startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE), + startup_serializer.CurrentAllocationAddress(CODE_SPACE), + startup_serializer.CurrentAllocationAddress(MAP_SPACE), + startup_serializer.CurrentAllocationAddress(CELL_SPACE)); + startup_name.Dispose(); } } -static void ReserveSpaceForPartialSnapshot(const char* file_name) { +static void ReserveSpaceForSnapshot(Deserializer* deserializer, + const char* file_name) { int file_name_length = StrLength(file_name) + 10; Vector<char> name = Vector<char>::New(file_name_length + 1); OS::SNPrintF(name, "%s.size", file_name); FILE* fp = OS::FOpen(name.start(), "r"); name.Dispose(); int new_size, pointer_size, data_size, code_size, map_size, cell_size; - int large_size; #ifdef _MSC_VER // Avoid warning about unsafe fscanf from MSVC. // Please note that this is only fine if %c and %s are not being used. @@ -423,18 +437,16 @@ static void ReserveSpaceForPartialSnapshot(const char* file_name) { CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size)); CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size)); CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size)); - CHECK_EQ(1, fscanf(fp, "large %d\n", &large_size)); #ifdef _MSC_VER #undef fscanf #endif fclose(fp); - HEAP->ReserveSpace(new_size, - pointer_size, - data_size, - code_size, - map_size, - cell_size, - large_size); + deserializer->set_reservation(NEW_SPACE, new_size); + deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size); + deserializer->set_reservation(OLD_DATA_SPACE, data_size); + deserializer->set_reservation(CODE_SPACE, code_size); + deserializer->set_reservation(MAP_SPACE, map_size); + deserializer->set_reservation(CELL_SPACE, cell_size); } @@ -448,7 +460,6 @@ DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { startup_name.Dispose(); const char* file_name = FLAG_testing_serialization_file; - ReserveSpaceForPartialSnapshot(file_name); int snapshot_size = 0; byte* snapshot = ReadBytes(file_name, &snapshot_size); @@ -457,18 +468,19 @@ DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { { SnapshotByteSource source(snapshot, snapshot_size); Deserializer deserializer(&source); + ReserveSpaceForSnapshot(&deserializer, file_name); deserializer.DeserializePartial(&root); CHECK(root->IsString()); } v8::HandleScope handle_scope; Handle<Object> root_handle(root); - ReserveSpaceForPartialSnapshot(file_name); Object* root2; { SnapshotByteSource source(snapshot, snapshot_size); Deserializer deserializer(&source); + ReserveSpaceForSnapshot(&deserializer, file_name); deserializer.DeserializePartial(&root2); CHECK(root2->IsString()); CHECK(*root_handle == root2); @@ -506,7 +518,6 @@ TEST(ContextSerialization) { env.Dispose(); FileByteSink startup_sink(startup_name.start()); - startup_name.Dispose(); StartupSerializer startup_serializer(&startup_sink); startup_serializer.SerializeStrongReferences(); @@ -514,14 +525,23 @@ TEST(ContextSerialization) { PartialSerializer p_ser(&startup_serializer, &partial_sink); p_ser.Serialize(&raw_context); startup_serializer.SerializeWeakReferences(); + partial_sink.WriteSpaceUsed( p_ser.CurrentAllocationAddress(NEW_SPACE), p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE), p_ser.CurrentAllocationAddress(OLD_DATA_SPACE), p_ser.CurrentAllocationAddress(CODE_SPACE), p_ser.CurrentAllocationAddress(MAP_SPACE), - p_ser.CurrentAllocationAddress(CELL_SPACE), - p_ser.CurrentAllocationAddress(LO_SPACE)); + p_ser.CurrentAllocationAddress(CELL_SPACE)); + + startup_sink.WriteSpaceUsed( + startup_serializer.CurrentAllocationAddress(NEW_SPACE), + startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE), + startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE), + startup_serializer.CurrentAllocationAddress(CODE_SPACE), + startup_serializer.CurrentAllocationAddress(MAP_SPACE), + startup_serializer.CurrentAllocationAddress(CELL_SPACE)); + startup_name.Dispose(); } } @@ -536,7 +556,6 @@ DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { startup_name.Dispose(); const char* file_name = FLAG_testing_serialization_file; - ReserveSpaceForPartialSnapshot(file_name); int snapshot_size = 0; byte* snapshot = ReadBytes(file_name, &snapshot_size); @@ -545,18 +564,19 @@ DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { { SnapshotByteSource source(snapshot, snapshot_size); Deserializer deserializer(&source); + ReserveSpaceForSnapshot(&deserializer, file_name); deserializer.DeserializePartial(&root); CHECK(root->IsContext()); } v8::HandleScope handle_scope; Handle<Object> root_handle(root); - ReserveSpaceForPartialSnapshot(file_name); Object* root2; { SnapshotByteSource source(snapshot, snapshot_size); Deserializer deserializer(&source); + ReserveSpaceForSnapshot(&deserializer, file_name); deserializer.DeserializePartial(&root2); CHECK(root2->IsContext()); CHECK(*root_handle != root2); @@ -565,120 +585,6 @@ DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { } -TEST(LinearAllocation) { - v8::V8::Initialize(); - int new_space_max = 512 * KB; - int paged_space_max = Page::kMaxNonCodeHeapObjectSize; - int code_space_max = HEAP->code_space()->AreaSize(); - - for (int size = 1000; size < 5 * MB; size += size >> 1) { - size &= ~8; // Round. - int new_space_size = (size < new_space_max) ? size : new_space_max; - int paged_space_size = (size < paged_space_max) ? size : paged_space_max; - HEAP->ReserveSpace( - new_space_size, - paged_space_size, // Old pointer space. - paged_space_size, // Old data space. - HEAP->code_space()->RoundSizeDownToObjectAlignment(code_space_max), - HEAP->map_space()->RoundSizeDownToObjectAlignment(paged_space_size), - HEAP->cell_space()->RoundSizeDownToObjectAlignment(paged_space_size), - size); // Large object space. - LinearAllocationScope linear_allocation_scope; - DisallowAllocationFailure disallow_allocation_failure; - const int kSmallFixedArrayLength = 4; - const int kSmallFixedArraySize = - FixedArray::kHeaderSize + kSmallFixedArrayLength * kPointerSize; - const int kSmallStringLength = 16; - const int kSmallStringSize = - (SeqAsciiString::kHeaderSize + kSmallStringLength + - kObjectAlignmentMask) & ~kObjectAlignmentMask; - const int kMapSize = Map::kSize; - - Object* new_last = NULL; - for (int i = 0; - i + kSmallFixedArraySize <= new_space_size; - i += kSmallFixedArraySize) { - Object* obj = - HEAP->AllocateFixedArray(kSmallFixedArrayLength)->ToObjectChecked(); - if (new_last != NULL) { - CHECK(reinterpret_cast<char*>(obj) == - reinterpret_cast<char*>(new_last) + kSmallFixedArraySize); - } - new_last = obj; - } - - Object* pointer_last = NULL; - for (int i = 0; - i + kSmallFixedArraySize <= paged_space_size; - i += kSmallFixedArraySize) { - Object* obj = HEAP->AllocateFixedArray(kSmallFixedArrayLength, - TENURED)->ToObjectChecked(); - int old_page_fullness = i % Page::kPageSize; - int page_fullness = (i + kSmallFixedArraySize) % Page::kPageSize; - if (page_fullness < old_page_fullness || - page_fullness > HEAP->old_pointer_space()->AreaSize()) { - i = RoundUp(i, Page::kPageSize); - pointer_last = NULL; - } - if (pointer_last != NULL) { - CHECK(reinterpret_cast<char*>(obj) == - reinterpret_cast<char*>(pointer_last) + kSmallFixedArraySize); - } - pointer_last = obj; - } - - Object* data_last = NULL; - for (int i = 0; - i + kSmallStringSize <= paged_space_size; - i += kSmallStringSize) { - Object* obj = HEAP->AllocateRawAsciiString(kSmallStringLength, - TENURED)->ToObjectChecked(); - int old_page_fullness = i % Page::kPageSize; - int page_fullness = (i + kSmallStringSize) % Page::kPageSize; - if (page_fullness < old_page_fullness || - page_fullness > HEAP->old_data_space()->AreaSize()) { - i = RoundUp(i, Page::kPageSize); - data_last = NULL; - } - if (data_last != NULL) { - CHECK(reinterpret_cast<char*>(obj) == - reinterpret_cast<char*>(data_last) + kSmallStringSize); - } - data_last = obj; - } - - Object* map_last = NULL; - for (int i = 0; i + kMapSize <= paged_space_size; i += kMapSize) { - Object* obj = HEAP->AllocateMap(JS_OBJECT_TYPE, - 42 * kPointerSize)->ToObjectChecked(); - int old_page_fullness = i % Page::kPageSize; - int page_fullness = (i + kMapSize) % Page::kPageSize; - if (page_fullness < old_page_fullness || - page_fullness > HEAP->map_space()->AreaSize()) { - i = RoundUp(i, Page::kPageSize); - map_last = NULL; - } - if (map_last != NULL) { - CHECK(reinterpret_cast<char*>(obj) == - reinterpret_cast<char*>(map_last) + kMapSize); - } - map_last = obj; - } - - if (size > Page::kMaxNonCodeHeapObjectSize) { - // Support for reserving space in large object space is not there yet, - // but using an always-allocate scope is fine for now. - AlwaysAllocateScope always; - int large_object_array_length = - (size - FixedArray::kHeaderSize) / kPointerSize; - Object* obj = HEAP->AllocateFixedArray(large_object_array_length, - TENURED)->ToObjectChecked(); - CHECK(!obj->IsFailure()); - } - } -} - - TEST(TestThatAlwaysSucceeds) { } diff --git a/deps/v8/test/cctest/test-sockets.cc b/deps/v8/test/cctest/test-sockets.cc index ad7354002f..2f7941c6ed 100644 --- a/deps/v8/test/cctest/test-sockets.cc +++ b/deps/v8/test/cctest/test-sockets.cc @@ -124,7 +124,7 @@ static void SendAndReceive(int port, char *data, int len) { TEST(Socket) { // Make sure this port is not used by other tests to allow tests to run in // parallel. - static const int kPort = 5859; + static const int kPort = 5859 + FlagDependentPortOffset(); bool ok; diff --git a/deps/v8/test/cctest/test-weakmaps.cc b/deps/v8/test/cctest/test-weakmaps.cc index 7bba7b6486..7c98c573c3 100644 --- a/deps/v8/test/cctest/test-weakmaps.cc +++ b/deps/v8/test/cctest/test-weakmaps.cc @@ -193,9 +193,10 @@ TEST(Regress2060a) { // other strong paths are correctly recorded in the slots buffer. TEST(Regress2060b) { FLAG_always_compact = true; -#ifdef DEBUG +#ifdef VERIFY_HEAP FLAG_verify_heap = true; #endif + LocalContext context; v8::HandleScope scope; Handle<JSFunction> function = diff --git a/deps/v8/test/cctest/testcfg.py b/deps/v8/test/cctest/testcfg.py index 532edfc26d..69a5db2044 100644 --- a/deps/v8/test/cctest/testcfg.py +++ b/deps/v8/test/cctest/testcfg.py @@ -25,11 +25,70 @@ # (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 test import os -from os.path import join, dirname, exists -import platform -import utils +import shutil + +from testrunner.local import commands +from testrunner.local import testsuite +from testrunner.local import utils +from testrunner.objects import testcase + + +class CcTestSuite(testsuite.TestSuite): + + def __init__(self, name, root): + super(CcTestSuite, self).__init__(name, root) + self.serdes_dir = os.path.normpath( + os.path.join(root, "..", "..", "out", ".serdes")) + if os.path.exists(self.serdes_dir): + shutil.rmtree(self.serdes_dir, True) + os.makedirs(self.serdes_dir) + + def ListTests(self, context): + if utils.IsWindows(): + shell += '.exe' + shell = os.path.abspath(os.path.join(context.shell_dir, self.shell())) + output = commands.Execute([context.command_prefix, + shell, + '--list', + context.extra_flags]) + if output.exit_code != 0: + print output.stdout + print output.stderr + return [] + tests = [] + for test_desc in output.stdout.strip().split(): + raw_test, dependency = test_desc.split('<') + if dependency != '': + dependency = raw_test.split('/')[0] + '/' + dependency + else: + dependency = None + test = testcase.TestCase(self, raw_test, dependency=dependency) + tests.append(test) + tests.sort() + return tests + + def GetFlagsForTestCase(self, testcase, context): + testname = testcase.path.split(os.path.sep)[-1] + serialization_file = os.path.join(self.serdes_dir, "serdes_" + testname) + serialization_file += ''.join(testcase.flags).replace('-', '_') + return (testcase.flags + [testcase.path] + context.mode_flags + + ["--testing_serialization_file=" + serialization_file]) + + def shell(self): + return "cctest" + + +def GetSuite(name, root): + return CcTestSuite(name, root) + + +# Deprecated definitions below. +# TODO(jkummerow): Remove when SCons is no longer supported. + + +from os.path import exists, join, normpath +import test class CcTestCase(test.TestCase): diff --git a/deps/v8/test/es5conform/testcfg.py b/deps/v8/test/es5conform/testcfg.py index b6a17d9b69..7de990d387 100644 --- a/deps/v8/test/es5conform/testcfg.py +++ b/deps/v8/test/es5conform/testcfg.py @@ -31,6 +31,11 @@ import os from os.path import join, exists +def GetSuite(name, root): + # Not implemented. + return None + + HARNESS_FILES = ['sth.js'] diff --git a/deps/v8/test/message/testcfg.py b/deps/v8/test/message/testcfg.py index 9cb58264e0..1b788d561c 100644 --- a/deps/v8/test/message/testcfg.py +++ b/deps/v8/test/message/testcfg.py @@ -25,13 +25,93 @@ # (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 test +import itertools import os -from os.path import join, dirname, exists, basename, isdir import re +from testrunner.local import testsuite +from testrunner.local import utils +from testrunner.objects import testcase + + FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)") + +class MessageTestSuite(testsuite.TestSuite): + def __init__(self, name, root): + super(MessageTestSuite, self).__init__(name, root) + + def ListTests(self, context): + tests = [] + for dirname, dirs, files in os.walk(self.root): + for dotted in [x for x in dirs if x.startswith('.')]: + dirs.remove(dotted) + dirs.sort() + files.sort() + for filename in files: + if filename.endswith(".js"): + testname = join(dirname[len(self.root) + 1:], filename[:-3]) + test = testcase.TestCase(self, testname) + tests.append(test) + return tests + + def GetFlagsForTestCase(self, testcase, context): + source = self.GetSourceForTest(testcase) + result = [] + flags_match = re.findall(FLAGS_PATTERN, source) + for match in flags_match: + result += match.strip().split() + result += context.mode_flags + result.append(os.path.join(self.root, testcase.path + ".js")) + return testcase.flags + result + + def GetSourceForTest(self, testcase): + filename = os.path.join(self.root, testcase.path + self.suffix()) + with open(filename) as f: + return f.read() + + def _IgnoreLine(self, string): + """Ignore empty lines, valgrind output and Android output.""" + if not string: return True + return (string.startswith("==") or string.startswith("**") or + string.startswith("ANDROID")) + + def IsFailureOutput(self, output, testpath): + expected_path = os.path.join(self.root, testpath + ".out") + expected_lines = [] + # Can't use utils.ReadLinesFrom() here because it strips whitespace. + with open(expected_path) as f: + for line in f: + if line.startswith("#") or not line.strip(): continue + expected_lines.append(line) + raw_lines = output.stdout.splitlines() + actual_lines = [ s for s in raw_lines if not self._IgnoreLine(s) ] + env = { "basename": os.path.basename(testpath + ".js") } + if len(expected_lines) != len(actual_lines): + return True + for (expected, actual) in itertools.izip(expected_lines, actual_lines): + pattern = re.escape(expected.rstrip() % env) + pattern = pattern.replace("\\*", ".*") + pattern = "^%s$" % pattern + if not re.match(pattern, actual): + return True + return False + + def StripOutputForTransmit(self, testcase): + pass + + +def GetSuite(name, root): + return MessageTestSuite(name, root) + + +# Deprecated definitions below. +# TODO(jkummerow): Remove when SCons is no longer supported. + + +import test +from os.path import join, exists, basename, isdir + class MessageTestCase(test.TestCase): def __init__(self, path, file, expected, mode, context, config): diff --git a/deps/v8/test/message/try-catch-finally-no-message.out b/deps/v8/test/message/try-catch-finally-no-message.out index d85fc7d027..f59f5c6a67 100644 --- a/deps/v8/test/message/try-catch-finally-no-message.out +++ b/deps/v8/test/message/try-catch-finally-no-message.out @@ -1,26 +1,26 @@ -// Copyright 2008 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. +# Copyright 2008 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. diff --git a/deps/v8/test/mjsunit/array-bounds-check-removal.js b/deps/v8/test/mjsunit/array-bounds-check-removal.js index 0ab3096326..df7988bdaa 100644 --- a/deps/v8/test/mjsunit/array-bounds-check-removal.js +++ b/deps/v8/test/mjsunit/array-bounds-check-removal.js @@ -29,6 +29,29 @@ var a = new Int32Array(1024); +// Test that we do not assert if the accessed index has not an int32 rep. +var v = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +function test_do_not_assert_on_non_int32(vector, base) { + var r = 0; + var a1 = base + 1; + var a2 = base + 2; + var a3 = base + 3; + var a4 = base + 4; + if (a1 == 2) { + r += vector[a1]; + r += vector[a4]; + r += vector[a2]; + r += vector[a3]; + } + return r; +} +test_do_not_assert_on_non_int32(v,1); +test_do_not_assert_on_non_int32(v,1); +test_do_not_assert_on_non_int32(v,"a"); +test_do_not_assert_on_non_int32(v,"a"); +%OptimizeFunctionOnNextCall(test_do_not_assert_on_non_int32); +test_do_not_assert_on_non_int32(v,0); + function test_base(base,cond) { a[base + 1] = 1; a[base + 4] = 2; diff --git a/deps/v8/test/mjsunit/array-natives-elements.js b/deps/v8/test/mjsunit/array-natives-elements.js new file mode 100644 index 0000000000..96a8cb5d19 --- /dev/null +++ b/deps/v8/test/mjsunit/array-natives-elements.js @@ -0,0 +1,307 @@ +// 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 --smi-only-arrays +// Flags: --noparallel-recompilation + +// Test element kind of objects. +// Since --smi-only-arrays affects builtins, its default setting at compile time +// sticks if built with snapshot. If --smi-only-arrays is deactivated by +// default, only a no-snapshot build actually has smi-only arrays enabled in +// this test case. Depending on whether smi-only arrays are actually enabled, +// this test takes the appropriate code path to check smi-only arrays. + +support_smi_only_arrays = %HasFastSmiElements([1,2,3,4,5,6,7,8,9,10]); + +if (support_smi_only_arrays) { + print("Tests include smi-only arrays."); +} else { + print("Tests do NOT include smi-only arrays."); +} + +// IC and Crankshaft support for smi-only elements in dynamic array literals. +function get(foo) { return foo; } // Used to generate dynamic values. + +function array_natives_test() { + + // Ensure small array literals start in specific element kind mode. + assertTrue(%HasFastSmiElements([])); + assertTrue(%HasFastSmiElements([1])); + assertTrue(%HasFastSmiElements([1,2])); + assertTrue(%HasFastDoubleElements([1.1])); + assertTrue(%HasFastDoubleElements([1.1,2])); + + // Push + var a0 = [1, 2, 3]; + assertTrue(%HasFastSmiElements(a0)); + a0.push(4); + assertTrue(%HasFastSmiElements(a0)); + a0.push(1.3); + assertTrue(%HasFastDoubleElements(a0)); + a0.push(1.5); + assertTrue(%HasFastDoubleElements(a0)); + a0.push({}); + assertTrue(%HasFastObjectElements(a0)); + a0.push({}); + assertTrue(%HasFastObjectElements(a0)); + assertEquals([1,2,3,4,1.3,1.5,{},{}], a0); + + // Concat + var a1; + a1 = [1,2,3].concat([]); + assertTrue(%HasFastSmiElements(a1)); + assertEquals([1,2,3], a1); + a1 = [1,2,3].concat([4,5,6]); + assertTrue(%HasFastSmiElements(a1)); + assertEquals([1,2,3,4,5,6], a1); + a1 = [1,2,3].concat([4,5,6], [7,8,9]); + assertTrue(%HasFastSmiElements(a1)); + assertEquals([1,2,3,4,5,6,7,8,9], a1); + a1 = [1.1,2,3].concat([]); + assertTrue(%HasFastDoubleElements(a1)); + assertEquals([1.1,2,3], a1); + a1 = [1,2,3].concat([1.1, 2]); + assertTrue(%HasFastDoubleElements(a1)); + assertEquals([1,2,3,1.1,2], a1); + a1 = [1.1,2,3].concat([1, 2]); + assertTrue(%HasFastDoubleElements(a1)); + assertEquals([1.1,2,3,1,2], a1); + a1 = [1.1,2,3].concat([1.2, 2]); + assertTrue(%HasFastDoubleElements(a1)); + assertEquals([1.1,2,3,1.2,2], a1); + + a1 = [1,2,3].concat([{}]); + assertTrue(%HasFastObjectElements(a1)); + assertEquals([1,2,3,{}], a1); + a1 = [1.1,2,3].concat([{}]); + assertTrue(%HasFastObjectElements(a1)); + assertEquals([1.1,2,3,{}], a1); + a1 = [{}].concat([1,2,3]); + assertTrue(%HasFastObjectElements(a1)); + assertEquals([{},1,2,3], a1); + a1 = [{}].concat([1.1,2,3]); + assertTrue(%HasFastObjectElements(a1)); + assertEquals([{},1.1,2,3], a1); + + // Slice + var a2 = [1,2,3]; + assertTrue(%HasFastSmiElements(a2.slice())); + assertTrue(%HasFastSmiElements(a2.slice(1))); + assertTrue(%HasFastSmiElements(a2.slice(1, 2))); + assertEquals([1,2,3], a2.slice()); + assertEquals([2,3], a2.slice(1)); + assertEquals([2], a2.slice(1,2)); + a2 = [1.1,2,3]; + assertTrue(%HasFastDoubleElements(a2.slice())); + assertTrue(%HasFastDoubleElements(a2.slice(1))); + assertTrue(%HasFastDoubleElements(a2.slice(1, 2))); + assertEquals([1.1,2,3], a2.slice()); + assertEquals([2,3], a2.slice(1)); + assertEquals([2], a2.slice(1,2)); + a2 = [{},2,3]; + assertTrue(%HasFastObjectElements(a2.slice())); + assertTrue(%HasFastObjectElements(a2.slice(1))); + assertTrue(%HasFastObjectElements(a2.slice(1, 2))); + assertEquals([{},2,3], a2.slice()); + assertEquals([2,3], a2.slice(1)); + assertEquals([2], a2.slice(1,2)); + + // Splice + var a3 = [1,2,3]; + var a3r; + a3r = a3.splice(0, 0); + assertTrue(%HasFastSmiElements(a3r)); + assertTrue(%HasFastSmiElements(a3)); + assertEquals([], a3r); + assertEquals([1, 2, 3], a3); + a3 = [1,2,3]; + a3r = a3.splice(0, 1); + assertTrue(%HasFastSmiElements(a3r)); + assertTrue(%HasFastSmiElements(a3)); + assertEquals([1], a3r); + assertEquals([2, 3], a3); + a3 = [1,2,3]; + a3r = a3.splice(0, 0, 2); + assertTrue(%HasFastSmiElements(a3r)); + assertTrue(%HasFastSmiElements(a3)); + assertEquals([], a3r); + assertEquals([2, 1, 2, 3], a3); + a3 = [1,2,3]; + a3r = a3.splice(0, 1, 2); + assertTrue(%HasFastSmiElements(a3r)); + assertTrue(%HasFastSmiElements(a3)); + assertEquals([1], a3r); + assertEquals([2, 2, 3], a3); + + a3 = [1.1,2,3]; + a3r = a3.splice(0, 0); + assertTrue(%HasFastDoubleElements(a3r)); + assertTrue(%HasFastDoubleElements(a3)); + assertEquals([], a3r); + assertEquals([1.1, 2, 3], a3); + a3 = [1.1,2,3]; + a3r = a3.splice(0, 1); + assertTrue(%HasFastDoubleElements(a3r)); + assertTrue(%HasFastDoubleElements(a3)); + assertEquals([1.1], a3r); + assertEquals([2, 3], a3); + a3 = [1.1,2,3]; + a3r = a3.splice(0, 0, 2); + // Commented out since handled in js, which takes the best fit. + // assertTrue(%HasFastDoubleElements(a3r)); + assertTrue(%HasFastSmiElements(a3r)); + assertTrue(%HasFastDoubleElements(a3)); + assertEquals([], a3r); + assertEquals([2, 1.1, 2, 3], a3); + a3 = [1.1,2,3]; + a3r = a3.splice(0, 1, 2); + assertTrue(%HasFastDoubleElements(a3r)); + assertTrue(%HasFastDoubleElements(a3)); + assertEquals([1.1], a3r); + assertEquals([2, 2, 3], a3); + a3 = [1.1,2,3]; + a3r = a3.splice(0, 0, 2.1); + // Commented out since handled in js, which takes the best fit. + // assertTrue(%HasFastDoubleElements(a3r)); + assertTrue(%HasFastSmiElements(a3r)); + assertTrue(%HasFastDoubleElements(a3)); + assertEquals([], a3r); + assertEquals([2.1, 1.1, 2, 3], a3); + a3 = [1.1,2,3]; + a3r = a3.splice(0, 1, 2.2); + assertTrue(%HasFastDoubleElements(a3r)); + assertTrue(%HasFastDoubleElements(a3)); + assertEquals([1.1], a3r); + assertEquals([2.2, 2, 3], a3); + a3 = [1,2,3]; + a3r = a3.splice(0, 0, 2.1); + // Commented out since handled in js, which takes the best fit. + // assertTrue(%HasFastDoubleElements(a3r)); + assertTrue(%HasFastSmiElements(a3r)); + assertTrue(%HasFastDoubleElements(a3)); + assertEquals([], a3r); + assertEquals([2.1, 1, 2, 3], a3); + a3 = [1,2,3]; + a3r = a3.splice(0, 1, 2.2); + assertTrue(%HasFastDoubleElements(a3r)); + assertTrue(%HasFastDoubleElements(a3)); + assertEquals([1], a3r); + assertEquals([2.2, 2, 3], a3); + + a3 = [{},2,3]; + a3r = a3.splice(0, 0); + assertTrue(%HasFastObjectElements(a3r)); + assertTrue(%HasFastObjectElements(a3)); + assertEquals([], a3r); + assertEquals([{}, 2, 3], a3); + a3 = [1,2,{}]; + a3r = a3.splice(0, 1); + assertTrue(%HasFastObjectElements(a3r)); + assertTrue(%HasFastObjectElements(a3)); + assertEquals([1], a3r); + assertEquals([2, {}], a3); + a3 = [1,2,3]; + a3r = a3.splice(0, 0, {}); + assertTrue(%HasFastObjectElements(a3r)); + assertTrue(%HasFastObjectElements(a3)); + assertEquals([], a3r); + assertEquals([{}, 1, 2, 3], a3); + a3 = [1,2,3]; + a3r = a3.splice(0, 1, {}); + assertTrue(%HasFastObjectElements(a3r)); + assertTrue(%HasFastObjectElements(a3)); + assertEquals([1], a3r); + assertEquals([{}, 2, 3], a3); + + a3 = [1.1,2,3]; + a3r = a3.splice(0, 0, {}); + assertTrue(%HasFastObjectElements(a3r)); + assertTrue(%HasFastObjectElements(a3)); + assertEquals([], a3r); + assertEquals([{}, 1.1, 2, 3], a3); + a3 = [1.1,2,3]; + a3r = a3.splice(0, 1, {}); + assertTrue(%HasFastObjectElements(a3r)); + assertTrue(%HasFastObjectElements(a3)); + assertEquals([1.1], a3r); + assertEquals([{}, 2, 3], a3); + + // Pop + var a4 = [1,2,3]; + assertEquals(3, a4.pop()); + assertTrue(%HasFastSmiElements(a4)); + a4 = [1.1,2,3]; + assertEquals(3, a4.pop()); + assertTrue(%HasFastDoubleElements(a4)); + a4 = [{},2,3]; + assertEquals(3, a4.pop()); + assertTrue(%HasFastObjectElements(a4)); + + // Shift + var a4 = [1,2,3]; + assertEquals(1, a4.shift()); + assertTrue(%HasFastSmiElements(a4)); + a4 = [1.1,2,3]; + assertEquals(1.1, a4.shift()); + assertTrue(%HasFastDoubleElements(a4)); + a4 = [{},2,3]; + assertEquals({}, a4.shift()); + assertTrue(%HasFastObjectElements(a4)); + + // Unshift + var a4 = [1,2,3]; + a4.unshift(1); + assertTrue(%HasFastSmiElements(a4)); + assertEquals([1,1,2,3], a4); + a4 = [1,2,3]; + a4.unshift(1.1); + // TODO(verwaest): We'll want to support double unshifting as well. + // assertTrue(%HasFastDoubleElements(a4)); + assertTrue(%HasFastObjectElements(a4)); + assertEquals([1.1,1,2,3], a4); + a4 = [1.1,2,3]; + a4.unshift(1); + // assertTrue(%HasFastDoubleElements(a4)); + assertTrue(%HasFastObjectElements(a4)); + assertEquals([1,1.1,2,3], a4); + a4 = [{},2,3]; + a4.unshift(1); + assertTrue(%HasFastObjectElements(a4)); + assertEquals([1,{},2,3], a4); + a4 = [{},2,3]; + a4.unshift(1.1); + assertTrue(%HasFastObjectElements(a4)); + assertEquals([1.1,{},2,3], a4); +} + +if (support_smi_only_arrays) { + for (var i = 0; i < 3; i++) { + array_natives_test(); + } + %OptimizeFunctionOnNextCall(array_natives_test); + array_natives_test(); +} diff --git a/deps/v8/test/mjsunit/array-reduce.js b/deps/v8/test/mjsunit/array-reduce.js index 1e96188265..429f34808d 100755 --- a/deps/v8/test/mjsunit/array-reduce.js +++ b/deps/v8/test/mjsunit/array-reduce.js @@ -418,8 +418,8 @@ try { exception = true; assertTrue(e instanceof TypeError, "reduce callback not a function not throwing TypeError"); - assertEquals("called_non_callable", e.type, - "reduce non function TypeError type"); + assertTrue(e.message.indexOf(" is not a function") >= 0, + "reduce non function TypeError type"); } assertTrue(exception); @@ -430,8 +430,8 @@ try { exception = true; assertTrue(e instanceof TypeError, "reduceRight callback not a function not throwing TypeError"); - assertEquals("called_non_callable", e.type, - "reduceRight non function TypeError type"); + assertTrue(e.message.indexOf(" is not a function") >= 0, + "reduceRight non function TypeError type"); } assertTrue(exception); @@ -442,7 +442,7 @@ try { exception = true; assertTrue(e instanceof TypeError, "reduce no initial value not throwing TypeError"); - assertEquals("reduce_no_initial", e.type, + assertEquals("Reduce of empty array with no initial value", e.message, "reduce no initial TypeError type"); } assertTrue(exception); @@ -454,7 +454,7 @@ try { exception = true; assertTrue(e instanceof TypeError, "reduceRight no initial value not throwing TypeError"); - assertEquals("reduce_no_initial", e.type, + assertEquals("Reduce of empty array with no initial value", e.message, "reduceRight no initial TypeError type"); } assertTrue(exception); @@ -466,7 +466,7 @@ try { exception = true; assertTrue(e instanceof TypeError, "reduce sparse no initial value not throwing TypeError"); - assertEquals("reduce_no_initial", e.type, + assertEquals("Reduce of empty array with no initial value", e.message, "reduce no initial TypeError type"); } assertTrue(exception); @@ -478,7 +478,7 @@ try { exception = true; assertTrue(e instanceof TypeError, "reduceRight sparse no initial value not throwing TypeError"); - assertEquals("reduce_no_initial", e.type, + assertEquals("Reduce of empty array with no initial value", e.message, "reduceRight no initial TypeError type"); } assertTrue(exception); diff --git a/deps/v8/test/mjsunit/array-slice.js b/deps/v8/test/mjsunit/array-slice.js index 5ae31dc527..ae0e3bc1ef 100644 --- a/deps/v8/test/mjsunit/array-slice.js +++ b/deps/v8/test/mjsunit/array-slice.js @@ -290,3 +290,15 @@ func('a', 'b', 'c'); })(); + +// Check slicing of holey objects with elements in the prototype +(function() { + function f() { + delete arguments[1]; + arguments.__proto__[1] = 5; + var result = Array.prototype.slice.call(arguments); + delete arguments.__proto__[1]; + assertEquals([1,5,3], result); + } + f(1,2,3); +})(); diff --git a/deps/v8/test/mjsunit/array-store-and-grow.js b/deps/v8/test/mjsunit/array-store-and-grow.js index 131d4ebc51..88f3db8f64 100644 --- a/deps/v8/test/mjsunit/array-store-and-grow.js +++ b/deps/v8/test/mjsunit/array-store-and-grow.js @@ -99,7 +99,10 @@ array_store_5(a, 1, 0.5); a = makeCOW(); array_store_5(a, 1, 0.5); assertEquals(0.5, a[1]); -assertEquals(0.5, array_store_5([], 1, 0.5)); +a = []; +assertEquals(0.5, array_store_5(a, 1, 0.5)); +assertEquals(undefined, a[0]); +assertEquals(0.5, a[1]); function array_store_6(a,b,c) { return (a[b] = c); diff --git a/deps/v8/test/mjsunit/bugs/bug-2337.js b/deps/v8/test/mjsunit/bugs/bug-2337.js new file mode 100644 index 0000000000..ebf7621c45 --- /dev/null +++ b/deps/v8/test/mjsunit/bugs/bug-2337.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: --expose-debug-as debug --expose-gc + +// If one callback causes a GC then the other callbacks don't take place. + +var f = eval("(function f() { return 42; })"); +var f2 = eval("(function f2() { return 43; })"); + +Debug = debug.Debug; + +var called = 0; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.ScriptCollected) { + if (called != 2) { + called++; + gc(); + } + } +}; + +Debug.scripts(); +Debug.setListener(listener); +f = void 0; +f2 = void 0; +gc(); +assertTrue(called == 2); diff --git a/deps/v8/test/mjsunit/compiler/inline-arguments.js b/deps/v8/test/mjsunit/compiler/inline-arguments.js index 572340ab6b..df1bd2214d 100644 --- a/deps/v8/test/mjsunit/compiler/inline-arguments.js +++ b/deps/v8/test/mjsunit/compiler/inline-arguments.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 +// Flags: --allow-natives-syntax --max-opt-count=100 function A() { } @@ -157,9 +157,8 @@ function test_toarr(toarr) { test_toarr(toarr1); test_toarr(toarr2); + // Test that arguments access from inlined function uses correct values. -// TODO(mstarzinger): Tests disabled, see bug 2261 -/* (function () { function inner(x, y) { "use strict"; @@ -204,4 +203,66 @@ test_toarr(toarr2); %OptimizeFunctionOnNextCall(outer); assertEquals(2, outer(1, 2)); })(); -*/ + + +// Test inlining and deoptimization of functions accessing and modifying +// the arguments object in strict mode with mismatched arguments count. +(function () { + "use strict"; + function test(outerCount, middleCount, innerCount) { + var forceDeopt = { deopt:false }; + function inner(x,y) { + x = 0; y = 0; + forceDeopt.deopt; + assertSame(innerCount, arguments.length); + for (var i = 0; i < arguments.length; i++) { + assertSame(30 + i, arguments[i]); + } + } + + function middle(x,y) { + x = 0; y = 0; + if (innerCount == 1) inner(30); + if (innerCount == 2) inner(30, 31); + if (innerCount == 3) inner(30, 31, 32); + assertSame(middleCount, arguments.length); + for (var i = 0; i < arguments.length; i++) { + assertSame(20 + i, arguments[i]); + } + } + + function outer(x,y) { + x = 0; y = 0; + if (middleCount == 1) middle(20); + if (middleCount == 2) middle(20, 21); + if (middleCount == 3) middle(20, 21, 22); + assertSame(outerCount, arguments.length); + for (var i = 0; i < arguments.length; i++) { + assertSame(10 + i, arguments[i]); + } + } + + for (var step = 0; step < 4; step++) { + if (outerCount == 1) outer(10); + if (outerCount == 2) outer(10, 11); + if (outerCount == 3) outer(10, 11, 12); + if (step == 1) %OptimizeFunctionOnNextCall(outer); + if (step == 2) delete forceDeopt.deopt; + } + + %DeoptimizeFunction(outer); + %DeoptimizeFunction(middle); + %DeoptimizeFunction(inner); + %ClearFunctionTypeFeedback(outer); + %ClearFunctionTypeFeedback(middle); + %ClearFunctionTypeFeedback(inner); + } + + for (var a = 1; a <= 3; a++) { + for (var b = 1; b <= 3; b++) { + for (var c = 1; c <= 3; c++) { + test(a,b,c); + } + } + } +})(); diff --git a/deps/v8/test/mjsunit/compiler/multiply-add.js b/deps/v8/test/mjsunit/compiler/multiply-add.js new file mode 100644 index 0000000000..2b4304e845 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/multiply-add.js @@ -0,0 +1,69 @@ +// 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 expressions that can be computed with a multiply-add instruction. + +function f(a, b, c) { + return a * b + c; +} + +function g(a, b, c) { + return a + b * c; +} + +function h(a, b, c, d) { + return a * b + c * d; +} + +assertEquals(5, f(1, 2, 3)); +assertEquals(5, f(1, 2, 3)); +%OptimizeFunctionOnNextCall(f); +assertEquals(5, f(1, 2, 3)); +assertEquals("2foo", f(1, 2, "foo")); +assertEquals(5.41, f(1.1, 2.1, 3.1)); +assertEquals(5.41, f(1.1, 2.1, 3.1)); +%OptimizeFunctionOnNextCall(f); +assertEquals(5.41, f(1.1, 2.1, 3.1)); + +assertEquals(7, g(1, 2, 3)); +assertEquals(7, g(1, 2, 3)); +%OptimizeFunctionOnNextCall(g); +assertEquals(7, g(1, 2, 3)); +assertEquals(8.36, g(1.1, 2.2, 3.3)); +assertEquals(8.36, g(1.1, 2.2, 3.3)); +%OptimizeFunctionOnNextCall(g); +assertEquals(8.36, g(1.1, 2.2, 3.3)); + +assertEquals(14, h(1, 2, 3, 4)); +assertEquals(14, h(1, 2, 3, 4)); +%OptimizeFunctionOnNextCall(h); +assertEquals(14, h(1, 2, 3, 4)); +assertEquals(15.02, h(1.1, 2.1, 3.1, 4.1)); +assertEquals(15.02, h(1.1, 2.1, 3.1, 4.1)); +%OptimizeFunctionOnNextCall(h); +assertEquals(15.02, h(1.1, 2.1, 3.1, 4.1)); diff --git a/deps/v8/test/mjsunit/compiler/proto-chain-load.js b/deps/v8/test/mjsunit/compiler/proto-chain-load.js new file mode 100644 index 0000000000..60c6431d2b --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/proto-chain-load.js @@ -0,0 +1,44 @@ +// 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 HLoadNamedField on the proto chain. + +var obj4 = Object.create(null, { f4: {value: 4} }); +var obj3 = Object.create(obj4, { f3: {value: 3} }); +var obj2 = Object.create(obj3, { f2: {value: 2} }); +var obj1 = Object.create(obj2, { f1: {value: 1} }); +var obj0 = Object.create(obj1, { f0: {value: 0} }); + +function get4(obj) { return obj.f4; } + +assertEquals(4, get4(obj0)); +assertEquals(4, get4(obj0)); +%OptimizeFunctionOnNextCall(get4); +assertEquals(4, get4(obj0)); +assertEquals(4, get4(obj0)); diff --git a/deps/v8/test/mjsunit/compiler/regress-gvn.js b/deps/v8/test/mjsunit/compiler/regress-gvn.js index 358daf7117..01b1aa9a60 100644 --- a/deps/v8/test/mjsunit/compiler/regress-gvn.js +++ b/deps/v8/test/mjsunit/compiler/regress-gvn.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: --noalways-opt +// Flags: --noalways-opt --allow-natives-syntax // // Regression test for global value numbering. @@ -39,10 +39,11 @@ function test(a) { var a = new Array(); -var n = 100000000; +var n = 100; var result = 0; for (var i = 0; i < n; ++i) { + if (i == 10) %OptimizeFunctionOnNextCall(test); a[0] = 0; result += test(a); } diff --git a/deps/v8/test/mjsunit/compiler/regress-or.js b/deps/v8/test/mjsunit/compiler/regress-or.js index 89f78025f1..939f2c3ffa 100644 --- a/deps/v8/test/mjsunit/compiler/regress-or.js +++ b/deps/v8/test/mjsunit/compiler/regress-or.js @@ -25,6 +25,8 @@ // (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 deoptimization inside short-circuited expressions. function f1(x) { var c = "fail"; @@ -36,7 +38,8 @@ function f1(x) { function g1() { try { return 1; } finally {} } -for (var i=0; i<10000000; i++) f1(42); +for (var i = 0; i < 5; i++) f1(42); +%OptimizeFunctionOnNextCall(f1); assertEquals(-1, f1(0)); assertEquals(-43, f1(42)); @@ -52,6 +55,7 @@ function f2(x) { function g2() { try { return 0; } finally {} } -for (var i=0; i<10000000; i++) f2(42); +for (var i = 0; i < 5; i++) f2(42); +%OptimizeFunctionOnNextCall(f2); assertEquals(-1, f2("")); diff --git a/deps/v8/test/mjsunit/compiler/rotate.js b/deps/v8/test/mjsunit/compiler/rotate.js new file mode 100644 index 0000000000..14fe9da3e6 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/rotate.js @@ -0,0 +1,224 @@ +// 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 shift operations that can be replaced by rotate operation. + +function SideEffect() { + with ({}) { } // not inlinable +} + +function Twenty() { + SideEffect(); + return 20; +} + +function Twelve() { + SideEffect(); + return 12; +} + + +function ROR(x, sa) { + return (x >>> sa) | (x << (32 - sa)); +} + +function ROR1(x, sa) { + return (x >>> sa) | (x << (32 - sa)); +} + +function ROR2(x, sa) { + return (x >>> (32 - sa)) | (x << (sa)); +} + +function ROR3(x, sa) { + return (x << (32 - sa)) | (x >>> sa); +} + +function ROR4(x, sa) { + return (x << (sa)) | (x >>> (32 - sa)); +} + +assertEquals(1 << ((2 % 32)), ROR(1, 30)); +assertEquals(1 << ((2 % 32)), ROR(1, 30)); +%OptimizeFunctionOnNextCall(ROR); +assertEquals(1 << ((2 % 32)), ROR(1, 30)); + +assertEquals(0xF0000FFF | 0, ROR1(0x0000FFFF, 4)); +assertEquals(0xF0000FFF | 0, ROR1(0x0000FFFF, 4)); +%OptimizeFunctionOnNextCall(ROR1); +assertEquals(0xF0000FFF | 0, ROR1(0x0000FFFF, 4)); + +assertEquals(0x0FFFF000 | 0, ROR1(0x0000FFFF, 20)); +assertEquals(0x0FFFF000 | 0, ROR1(0x0000FFFF, 20)); +%OptimizeFunctionOnNextCall(ROR1); +assertEquals(0x0FFFF000 | 0, ROR1(0x0000FFFF, 20)); + +assertEquals(0x0FFFF000 | 0, ROR1(0x0000FFFF, Twenty())); +assertEquals(0x0FFFF000 | 0, ROR1(0x0000FFFF, Twenty())); +%OptimizeFunctionOnNextCall(ROR1); +assertEquals(0x0FFFF000 | 0, ROR1(0x0000FFFF, Twenty())); + +for (var i = 0; i <= 100; i++) { + assertEquals(0xFFFFFFFF | 0, ROR1(0xFFFFFFFF, i)); + assertEquals(0xFFFFFFFF | 0, ROR1(0xFFFFFFFF, i)); + %OptimizeFunctionOnNextCall(ROR1); + assertEquals(0xFFFFFFFF | 0, ROR1(0xFFFFFFFF, i)); +} + +for (var i = 0; i <= 100; i++) { + assertEquals(-1, ROR1(-1, i)); + assertEquals(-1, ROR1(-1, i)); + %OptimizeFunctionOnNextCall(ROR1); + assertEquals(-1, ROR1(-1, i)); +} + +for (var i = 0; i <= 100; i++) { + assertEquals(1 << (32 - (i % 32)), ROR1(1, i)); + assertEquals(1 << (32 - (i % 32)), ROR1(1, i)); + %OptimizeFunctionOnNextCall(ROR1); + assertEquals(1 << (32 - (i % 32)), ROR1(1, i)); +} + +for (var i = 0; i <= 100; i++) { + assertEquals(1 << (32 - (i % 32)), ROR1(1.4, i)); + assertEquals(1 << (32 - (i % 32)), ROR1(1.4, i)); + %OptimizeFunctionOnNextCall(ROR1); + assertEquals(1 << (32 - (i % 32)), ROR1(1.4, i)); +} + + + +assertEquals(0xF0000FFF | 0, ROR2(0x0000FFFF, 28)); +assertEquals(0xF0000FFF | 0, ROR2(0x0000FFFF, 28)); +%OptimizeFunctionOnNextCall(ROR2); +assertEquals(0xF0000FFF | 0, ROR2(0x0000FFFF, 28)); + +assertEquals(0x0FFFF000 | 0, ROR2(0x0000FFFF, 12)); +assertEquals(0x0FFFF000 | 0, ROR2(0x0000FFFF, 12)); +%OptimizeFunctionOnNextCall(ROR2); +assertEquals(0x0FFFF000 | 0, ROR2(0x0000FFFF, 12)); + +assertEquals(0x0FFFF000 | 0, ROR2(0x0000FFFF, Twelve())); +assertEquals(0x0FFFF000 | 0, ROR2(0x0000FFFF, Twelve())); +%OptimizeFunctionOnNextCall(ROR2); +assertEquals(0x0FFFF000 | 0, ROR2(0x0000FFFF, Twelve())); + +for (var i = 0; i <= 100; i++) { + assertEquals(0xFFFFFFFF | 0, ROR2(0xFFFFFFFF, i)); + assertEquals(0xFFFFFFFF | 0, ROR2(0xFFFFFFFF, i)); + %OptimizeFunctionOnNextCall(ROR2); + assertEquals(0xFFFFFFFF | 0, ROR2(0xFFFFFFFF, i)); +} + +for (var i = 0; i <= 100; i++) { + assertEquals(-1, ROR2(-1, i)); + assertEquals(-1, ROR2(-1, i)); + %OptimizeFunctionOnNextCall(ROR2); + assertEquals(-1, ROR2(-1, i)); +} + +for (var i = 0; i <= 100; i++) { + assertEquals(1 << ((i % 32)), ROR2(1, i)); + assertEquals(1 << ((i % 32)), ROR2(1, i)); + %OptimizeFunctionOnNextCall(ROR2); + assertEquals(1 << ((i % 32)), ROR2(1, i)); +} + +assertEquals(0xF0000FFF | 0, ROR3(0x0000FFFF, 4)); +assertEquals(0xF0000FFF | 0, ROR3(0x0000FFFF, 4)); +%OptimizeFunctionOnNextCall(ROR3); +assertEquals(0xF0000FFF | 0, ROR3(0x0000FFFF, 4)); + +assertEquals(0x0FFFF000 | 0, ROR3(0x0000FFFF, 20)); +assertEquals(0x0FFFF000 | 0, ROR3(0x0000FFFF, 20)); +%OptimizeFunctionOnNextCall(ROR3); +assertEquals(0x0FFFF000 | 0, ROR3(0x0000FFFF, 20)); + +assertEquals(0x0FFFF000 | 0, ROR3(0x0000FFFF, Twenty())); +assertEquals(0x0FFFF000 | 0, ROR3(0x0000FFFF, Twenty())); +%OptimizeFunctionOnNextCall(ROR3); +assertEquals(0x0FFFF000 | 0, ROR3(0x0000FFFF, Twenty())); + +for (var i = 0; i <= 100; i++) { + assertEquals(0xFFFFFFFF | 0, ROR3(0xFFFFFFFF, i)); + assertEquals(0xFFFFFFFF | 0, ROR3(0xFFFFFFFF, i)); + %OptimizeFunctionOnNextCall(ROR3); + assertEquals(0xFFFFFFFF | 0, ROR3(0xFFFFFFFF, i)); +} + +for (var i = 0; i <= 100; i++) { + assertEquals(-1, ROR3(-1, i)); + assertEquals(-1, ROR3(-1, i)); + %OptimizeFunctionOnNextCall(ROR3); + assertEquals(-1, ROR3(-1, i)); +} + +for (var i = 0; i <= 100; i++) { + assertEquals(1 << (32 - (i % 32)), ROR3(1, i)); + assertEquals(1 << (32 - (i % 32)), ROR3(1, i)); + %OptimizeFunctionOnNextCall(ROR3); + assertEquals(1 << (32 - (i % 32)), ROR3(1, i)); +} + +assertEquals(0xF0000FFF | 0, ROR4(0x0000FFFF, 28)); +assertEquals(0xF0000FFF | 0, ROR4(0x0000FFFF, 28)); +%OptimizeFunctionOnNextCall(ROR4); +assertEquals(0xF0000FFF | 0, ROR4(0x0000FFFF, 28)); + +assertEquals(0x0FFFF000 | 0, ROR4(0x0000FFFF, 12)); +assertEquals(0x0FFFF000 | 0, ROR4(0x0000FFFF, 12)); +%OptimizeFunctionOnNextCall(ROR4); +assertEquals(0x0FFFF000 | 0, ROR4(0x0000FFFF, 12)); + +assertEquals(0x0FFFF000 | 0, ROR4(0x0000FFFF, Twelve())); +assertEquals(0x0FFFF000 | 0, ROR4(0x0000FFFF, Twelve())); +%OptimizeFunctionOnNextCall(ROR4); +assertEquals(0x0FFFF000 | 0, ROR4(0x0000FFFF, Twelve())); + +for (var i = 0; i <= 100; i++) { + assertEquals(0xFFFFFFFF | 0, ROR4(0xFFFFFFFF, i)); + assertEquals(0xFFFFFFFF | 0, ROR4(0xFFFFFFFF, i)); + %OptimizeFunctionOnNextCall(ROR4); + assertEquals(0xFFFFFFFF | 0, ROR4(0xFFFFFFFF, i)); +} + +for (var i = 0; i <= 100; i++) { + assertEquals(-1, ROR4(-1, i)); + assertEquals(-1, ROR4(-1, i)); + %OptimizeFunctionOnNextCall(ROR4); + assertEquals(-1, ROR4(-1, i)); +} + +for (var i = 0; i <= 100; i++) { + assertEquals(1 << ((i % 32)), ROR4(1, i)); + assertEquals(1 << ((i % 32)), ROR4(1, i)); + %OptimizeFunctionOnNextCall(ROR4); + assertEquals(1 << ((i % 32)), ROR4(1, i)); +} + diff --git a/deps/v8/test/mjsunit/d8-os.js b/deps/v8/test/mjsunit/d8-os.js index 239938cd16..f6b98396e5 100644 --- a/deps/v8/test/mjsunit/d8-os.js +++ b/deps/v8/test/mjsunit/d8-os.js @@ -129,13 +129,13 @@ if (this.os && os.system) { have_echo = false; } if (have_sleep) { - assertThrows("os.system('sleep', ['2000'], 200);", "sleep 1"); + assertThrows("os.system('sleep', ['2000'], 20);", "sleep 1"); // Check we time out with total time. - assertThrows("os.system('sleep', ['2000'], -1, 200);", "sleep 2"); + assertThrows("os.system('sleep', ['2000'], -1, 20);", "sleep 2"); // Check that -1 means no timeout. - os.system('sleep', ['1'], -1, -1); + os.system('sleep', ['0.1'], -1, -1); } diff --git a/deps/v8/test/mjsunit/debug-liveedit-compile-error.js b/deps/v8/test/mjsunit/debug-liveedit-compile-error.js new file mode 100644 index 0000000000..2fd6aedabf --- /dev/null +++ b/deps/v8/test/mjsunit/debug-liveedit-compile-error.js @@ -0,0 +1,60 @@ +// 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 + +eval("var something1 = 25; \n" + + " function ChooseAnimal() { return 'Cat'; } \n" + + " ChooseAnimal.Helper = function() { return 'Help!'; }\n"); + +assertEquals("Cat", ChooseAnimal()); + +var script = Debug.findScript(ChooseAnimal); + +var orig_animal = "Cat"; +var patch_pos = script.source.indexOf(orig_animal); +var new_animal_patch = "Cap' + ) + 'bara"; + +var change_log = new Array(); +var caught_exception = null; +try { + Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, + orig_animal.length, new_animal_patch, change_log); +} catch (e) { + caught_exception = e; +} + +assertNotNull(caught_exception); +assertEquals("Unexpected token )", + caught_exception.details.syntaxErrorMessage); + +assertEquals(2, caught_exception.details.position.start.line); + + diff --git a/deps/v8/test/mjsunit/debug-liveedit-literals.js b/deps/v8/test/mjsunit/debug-liveedit-literals.js new file mode 100644 index 0000000000..5f9217e833 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-liveedit-literals.js @@ -0,0 +1,94 @@ +// Copyright 2010 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 + +function Test(old_expression, new_expression) { + // Generate several instances of function to test that we correctly fix + // all functions in memory. + var function_instance_number = 11; + eval("var t1 =1;\n" + + "ChooseAnimalArray = [];\n" + + "for (var i = 0; i < function_instance_number; i++) {\n" + + " ChooseAnimalArray.push(\n" + + " function ChooseAnimal() {\n" + + " return " + old_expression + ";\n" + + " });\n" + + "}\n" + + "var t2 =1;\n"); + + for (var i = 0; i < ChooseAnimalArray.length; i++) { + assertEquals("Cat", ChooseAnimalArray[i]()); + } + + var script = Debug.findScript(ChooseAnimalArray[0]); + + var patch_pos = script.source.indexOf(old_expression); + var new_animal_patch = new_expression; + + var change_log = new Array(); + Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, + old_expression.length, new_expression, change_log); + + for (var i = 0; i < ChooseAnimalArray.length; i++) { + assertEquals("Capybara", ChooseAnimalArray[i]()); + } +} + +// Check that old literal boilerplate was reset. +Test("['Cat'][0]", "['Capybara'][0]"); +Test("['Cat'][0]", "{a:'Capybara'}.a"); + +// No literals -> 1 literal. +Test("'Cat'", "['Capybara'][0]"); + +// No literals -> 2 literals. +Test("'Cat'", "['Capy'][0] + {a:'bara'}.a"); + +// 1 literal -> no literals. +Test("['Cat'][0]", "'Capybara'"); + +// 2 literals -> no literals. +Test("['Ca'][0] + {a:'t'}.a", "'Capybara'"); + +// No literals -> regexp. +Test("'Cat'", "(/.A.Y.A.A/i).exec('Capybara')[0]"); + +// Array literal -> regexp. +Test("['Cat'][0]", "(/.A.Y.A.A/i).exec('Capybara')[0]"); + +// Regexp -> object literal. +Test("(/.A./i).exec('Cat')[0]", "{c:'Capybara'}.c"); + +// No literals -> regexp. +Test("'Cat'", "(/.A.Y.A.A/i).exec('Capybara')[0]"); + +// Regexp -> no literals. +Test("(/.A./i).exec('Cat')[0]", "'Capybara'"); diff --git a/deps/v8/test/mjsunit/debug-multiple-breakpoints.js b/deps/v8/test/mjsunit/debug-multiple-breakpoints.js index 1047410112..d8b1d943f4 100644 --- a/deps/v8/test/mjsunit/debug-multiple-breakpoints.js +++ b/deps/v8/test/mjsunit/debug-multiple-breakpoints.js @@ -89,7 +89,7 @@ g(); assertEquals(3, break_point_hit_count); // Finally test with many break points. -test_count = 100; +test_count = 10; bps = new Array(test_count); break_point_hit_count = 0; for (var i = 0; i < test_count; i++) { diff --git a/deps/v8/test/mjsunit/debug-script.js b/deps/v8/test/mjsunit/debug-script.js index d7ffb56958..b9dbc075e9 100644 --- a/deps/v8/test/mjsunit/debug-script.js +++ b/deps/v8/test/mjsunit/debug-script.js @@ -25,9 +25,11 @@ // (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 --expose-gc --noparallel-recompilation +// Flags: --expose-debug-as debug --expose-gc --noparallel-recompilation +// Flags: --send-idle-notification + // Get the Debug object exposed from the debug context global object. -Debug = debug.Debug +Debug = debug.Debug; Date(); RegExp(); diff --git a/deps/v8/test/mjsunit/debug-set-variable-value.js b/deps/v8/test/mjsunit/debug-set-variable-value.js new file mode 100644 index 0000000000..dac8861456 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-set-variable-value.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: --expose-debug-as debug + +// Get the Debug object exposed from the debug context global object. +var Debug = debug.Debug; + +// Accepts a function/closure 'fun' that must have a debugger statement inside. +// A variable 'variable_name' must be initialized before debugger statement +// and returned after the statement. The test will alter variable value when +// on debugger statement and check that returned value reflects the change. +function RunPauseTest(scope_number, variable_name, expected_new_value, fun) { + var old_value = fun(); + + var listener_delegate; + var listener_called = false; + var exception = null; + + function listener_delegate(exec_state) { + var scope = exec_state.frame(0).scope(scope_number); + scope.setVariableValue(variable_name, expected_new_value); + } + + function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + listener_called = true; + listener_delegate(exec_state); + } + } catch (e) { + exception = e; + } + } + + // Add the debug event listener. + Debug.setListener(listener); + + var actual_new_value; + try { + actual_new_value = fun(); + } finally { + Debug.setListener(null); + } + + if (exception != null) { + assertUnreachable("Exception: " + exception); + } + assertTrue(listener_called); + + assertTrue(old_value != actual_new_value); + assertTrue(expected_new_value == actual_new_value); +} + +// Accepts a closure 'fun' that returns a variable from it's outer scope. +// The test changes the value of variable via the handle to function and checks +// that the return value changed accordingly. +function RunClosureTest(scope_number, variable_name, expected_new_value, fun) { + var old_value = fun(); + + var fun_mirror = Debug.MakeMirror(fun); + + var scope = fun_mirror.scope(scope_number); + scope.setVariableValue(variable_name, expected_new_value); + + var actual_new_value = fun(); + + assertTrue(old_value != actual_new_value); + assertTrue(expected_new_value == actual_new_value); +} + +// Test changing variable value when in pause +RunPauseTest(1, 'v1', 5, (function Factory() { + var v1 = 'cat'; + return function() { + debugger; + return v1; + } +})()); + +RunPauseTest(1, 'v2', 11, (function Factory(v2) { + return function() { + debugger; + return v2; + } +})('dog')); + +RunPauseTest(3, 'foo', 77, (function Factory() { + var foo = "capybara"; + return (function() { + var bar = "fish"; + try { + throw {name: "test exception"}; + } catch (e) { + return function() { + debugger; + bar = "beast"; + return foo; + } + } + })(); +})()); + + + +// Test changing variable value in closure by handle +RunClosureTest(0, 'v1', 5, (function Factory() { + var v1 = 'cat'; + return function() { + return v1; + } +})()); + +RunClosureTest(0, 'v2', 11, (function Factory(v2) { + return function() { + return v2; + } +})('dog')); + +RunClosureTest(2, 'foo', 77, (function Factory() { + var foo = "capybara"; + return (function() { + var bar = "fish"; + try { + throw {name: "test exception"}; + } catch (e) { + return function() { + bar = "beast"; + return foo; + } + } + })(); +})()); + + +// Test value description protocol JSON +assertEquals(true, Debug.TestApi.CommandProcessorResolveValue({value: true})); + +assertSame(null, Debug.TestApi.CommandProcessorResolveValue({type: "null"})); +assertSame(undefined, + Debug.TestApi.CommandProcessorResolveValue({type: "undefined"})); + +assertSame("123", Debug.TestApi.CommandProcessorResolveValue( + {type: "string", stringDescription: "123"})); +assertSame(123, Debug.TestApi.CommandProcessorResolveValue( + {type: "number", stringDescription: "123"})); + +assertSame(Number, Debug.TestApi.CommandProcessorResolveValue( + {handle: Debug.MakeMirror(Number).handle()})); +assertSame(RunClosureTest, Debug.TestApi.CommandProcessorResolveValue( + {handle: Debug.MakeMirror(RunClosureTest).handle()})); + diff --git a/deps/v8/test/mjsunit/debug-stepout-scope-part1.js b/deps/v8/test/mjsunit/debug-stepout-scope-part1.js new file mode 100644 index 0000000000..f2f9d91419 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-stepout-scope-part1.js @@ -0,0 +1,190 @@ +// 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: --expose-debug-as debug --expose-natives-as=builtins + +// Check that the ScopeIterator can properly recreate the scope at +// every point when stepping through functions. + +var Debug = debug.Debug; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + // Access scope details. + var scope_count = exec_state.frame().scopeCount(); + for (var i = 0; i < scope_count; i++) { + var scope = exec_state.frame().scope(i); + // assertTrue(scope.isScope()); + scope.scopeType(); + scope.scopeObject(); + } + + // Do steps until we reach the global scope again. + if (true) { + exec_state.prepareStep(Debug.StepAction.StepInMin, 1); + } + } +} + +Debug.setListener(listener); + + +function test1() { + debugger; + with ({x:1}) { + x = 2; + } +} +test1(); + + +function test2() { + if (true) { + with ({}) { + debugger; + } + } else { + with ({}) { + return 10; + } + } +} +test2(); + + +function test3() { + if (true) { + debugger; + } else { + with ({}) { + return 10; + } + } +} +test3(); + + +function test4() { + debugger; + with ({x:1}) x = 1 +} +test4(); + + +function test5() { + debugger; + var dummy = 1; + with ({}) { + with ({}) { + dummy = 2; + } + } + dummy = 3; +} +test5(); + + +function test6() { + debugger; + try { + throw 'stuff'; + } catch (e) { + e = 1; + } +} +test6(); + + +function test7() { + debugger; + function foo() {} +} +test7(); + + +function test8() { + debugger; + (function foo() {})(); +} +test8(); + + +function test10() { + debugger; + with ({}) { + return 10; + } +} +test10(); + + +function test11() { + debugger; + try { + throw 'stuff'; + } catch (e) { + return 10; + } +} +test11(); + + +var prefixes = [ + "debugger; ", + "if (false) { try { throw 0; } catch(x) { return x; } }; debugger; " ]; + + +// Return from function constructed with Function constructor. +var anon = 12; +for (var i = 0; i < prefixes.length; ++i) { + var pre = prefixes[i]; + Function(pre + "return 42")(); + Function(pre + "return 42 ")(); + Function(pre + "return 42;")(); + Function(pre + "return 42; ")(); + Function(pre + "return anon")(); + Function(pre + "return anon ")(); + Function(pre + "return anon;")(); + Function(pre + "return anon; ")(); +} + + +try { + with({}) { + debugger; + eval("{}$%:^"); + } +} catch(e) { + nop(); +} + + +function nop() {} + + +// With block as the last(!) statement in global code. +with ({}) { debugger; }
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/debug-stepout-scope-part2.js b/deps/v8/test/mjsunit/debug-stepout-scope-part2.js new file mode 100644 index 0000000000..121c7b74df --- /dev/null +++ b/deps/v8/test/mjsunit/debug-stepout-scope-part2.js @@ -0,0 +1,83 @@ +// 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: --expose-debug-as debug --expose-natives-as=builtins + +// Check that the ScopeIterator can properly recreate the scope at +// every point when stepping through functions. + +var Debug = debug.Debug; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + // Access scope details. + var scope_count = exec_state.frame().scopeCount(); + for (var i = 0; i < scope_count; i++) { + var scope = exec_state.frame().scope(i); + // assertTrue(scope.isScope()); + scope.scopeType(); + scope.scopeObject(); + } + + // Do steps until we reach the global scope again. + if (true) { + exec_state.prepareStep(Debug.StepAction.StepInMin, 1); + } + } +} + +Debug.setListener(listener); + +var q = 42; +var prefixes = [ "debugger; ", + "if (false) { try { throw 0; } catch(x) { return x; } }; debugger; " ]; +var bodies = [ "1", + "1 ", + "1;", + "1; ", + "q", + "q ", + "q;", + "q; ", + "try { throw 'stuff' } catch (e) { e = 1; }", + "try { throw 'stuff' } catch (e) { e = 1; } ", + "try { throw 'stuff' } catch (e) { e = 1; };", + "try { throw 'stuff' } catch (e) { e = 1; }; " ]; + + +function test9() { + debugger; + for (var i = 0; i < prefixes.length; ++i) { + var pre = prefixes[i]; + for (var j = 0; j < bodies.length; ++j) { + var body = bodies[j]; + eval(pre + body); + eval("'use strict'; " + pre + body); + } + } +} +test9(); diff --git a/deps/v8/test/mjsunit/debug-stepout-scope-part3.js b/deps/v8/test/mjsunit/debug-stepout-scope-part3.js new file mode 100644 index 0000000000..16b085e541 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-stepout-scope-part3.js @@ -0,0 +1,80 @@ +// 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: --expose-debug-as debug --expose-natives-as=builtins + +// Check that the ScopeIterator can properly recreate the scope at +// every point when stepping through functions. + +var Debug = debug.Debug; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + // Access scope details. + var scope_count = exec_state.frame().scopeCount(); + for (var i = 0; i < scope_count; i++) { + var scope = exec_state.frame().scope(i); + // assertTrue(scope.isScope()); + scope.scopeType(); + scope.scopeObject(); + } + + // Do steps until we reach the global scope again. + if (true) { + exec_state.prepareStep(Debug.StepAction.StepInMin, 1); + } + } +} + +Debug.setListener(listener); + +var q = 42; +var prefixes = [ + "debugger; ", + "if (false) { try { throw 0; } catch(x) { return x; } }; debugger; " ]; +var with_bodies = [ "with ({}) {}", + "with ({x:1}) x", + "with ({x:1}) x = 1", + "with ({x:1}) x ", + "with ({x:1}) x = 1 ", + "with ({x:1}) x;", + "with ({x:1}) x = 1;", + "with ({x:1}) x; ", + "with ({x:1}) x = 1; " ]; + + +function test9() { + debugger; + for (var i = 0; i < prefixes.length; ++i) { + var pre = prefixes[i]; + for (var j = 0; j < with_bodies.length; ++j) { + var body = with_bodies[j]; + eval(pre + body); + } + } +} +test9(); diff --git a/deps/v8/test/mjsunit/debug-stepout-scope-part4.js b/deps/v8/test/mjsunit/debug-stepout-scope-part4.js new file mode 100644 index 0000000000..48f43477d7 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-stepout-scope-part4.js @@ -0,0 +1,80 @@ +// 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: --expose-debug-as debug --expose-natives-as=builtins + +// Check that the ScopeIterator can properly recreate the scope at +// every point when stepping through functions. + +var Debug = debug.Debug; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + // Access scope details. + var scope_count = exec_state.frame().scopeCount(); + for (var i = 0; i < scope_count; i++) { + var scope = exec_state.frame().scope(i); + // assertTrue(scope.isScope()); + scope.scopeType(); + scope.scopeObject(); + } + + // Do steps until we reach the global scope again. + if (true) { + exec_state.prepareStep(Debug.StepAction.StepInMin, 1); + } + } +} + +Debug.setListener(listener); + +var q = 42; +var prefixes = [ + "debugger; ", + "if (false) { try { throw 0; } catch(x) { return x; } }; debugger; " ]; +var bodies = [ "1", + "1 ", + "1;", + "1; ", + "q", + "q ", + "q;", + "q; ", + "try { throw 'stuff' } catch (e) { e = 1; }", + "try { throw 'stuff' } catch (e) { e = 1; } ", + "try { throw 'stuff' } catch (e) { e = 1; };", + "try { throw 'stuff' } catch (e) { e = 1; }; " ]; + + +// Test global eval and function constructor. +for (var i = 0; i < prefixes.length; ++i) { + var pre = prefixes[i]; + for (var j = 0; j < bodies.length; ++j) { + var body = bodies[j]; + eval(pre + body); + } +} diff --git a/deps/v8/test/mjsunit/debug-stepout-scope-part5.js b/deps/v8/test/mjsunit/debug-stepout-scope-part5.js new file mode 100644 index 0000000000..f060ec3889 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-stepout-scope-part5.js @@ -0,0 +1,77 @@ +// 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: --expose-debug-as debug --expose-natives-as=builtins + +// Check that the ScopeIterator can properly recreate the scope at +// every point when stepping through functions. + +var Debug = debug.Debug; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + // Access scope details. + var scope_count = exec_state.frame().scopeCount(); + for (var i = 0; i < scope_count; i++) { + var scope = exec_state.frame().scope(i); + // assertTrue(scope.isScope()); + scope.scopeType(); + scope.scopeObject(); + } + + // Do steps until we reach the global scope again. + if (true) { + exec_state.prepareStep(Debug.StepAction.StepInMin, 1); + } + } +} + +Debug.setListener(listener); + +var q = 42; +var prefixes = [ "debugger; ", + "if (false) { try { throw 0; } catch(x) { return x; } }; debugger; " ]; +var with_bodies = [ "with ({}) {}", + "with ({x:1}) x", + "with ({x:1}) x = 1", + "with ({x:1}) x ", + "with ({x:1}) x = 1 ", + "with ({x:1}) x;", + "with ({x:1}) x = 1;", + "with ({x:1}) x; ", + "with ({x:1}) x = 1; " ]; + + +// Test global eval and function constructor. +for (var i = 0; i < prefixes.length; ++i) { + var pre = prefixes[i]; + for (var j = 0; j < with_bodies.length; ++j) { + var body = with_bodies[j]; + eval(pre + body); + Function(pre + body)(); + } +} diff --git a/deps/v8/test/mjsunit/debug-stepout-scope-part6.js b/deps/v8/test/mjsunit/debug-stepout-scope-part6.js new file mode 100644 index 0000000000..f7c8df0bc8 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-stepout-scope-part6.js @@ -0,0 +1,79 @@ +// 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: --expose-debug-as debug --expose-natives-as=builtins + +// Check that the ScopeIterator can properly recreate the scope at +// every point when stepping through functions. + +var Debug = debug.Debug; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + // Access scope details. + var scope_count = exec_state.frame().scopeCount(); + for (var i = 0; i < scope_count; i++) { + var scope = exec_state.frame().scope(i); + // assertTrue(scope.isScope()); + scope.scopeType(); + scope.scopeObject(); + } + + // Do steps until we reach the global scope again. + if (true) { + exec_state.prepareStep(Debug.StepAction.StepInMin, 1); + } + } +} + +Debug.setListener(listener); + +var q = 42; +var prefixes = [ "debugger; ", + "if (false) { try { throw 0; } catch(x) { return x; } }; debugger; " ]; +var bodies = [ "1", + "1 ", + "1;", + "1; ", + "q", + "q ", + "q;", + "q; ", + "try { throw 'stuff' } catch (e) { e = 1; }", + "try { throw 'stuff' } catch (e) { e = 1; } ", + "try { throw 'stuff' } catch (e) { e = 1; };", + "try { throw 'stuff' } catch (e) { e = 1; }; " ]; + + +// Test global eval and function constructor. +for (var i = 0; i < prefixes.length; ++i) { + var pre = prefixes[i]; + for (var j = 0; j < bodies.length; ++j) { + var body = bodies[j]; + eval("'use strict'; " + pre + body); + } +} diff --git a/deps/v8/test/mjsunit/debug-stepout-scope-part7.js b/deps/v8/test/mjsunit/debug-stepout-scope-part7.js new file mode 100644 index 0000000000..4f0c066843 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-stepout-scope-part7.js @@ -0,0 +1,79 @@ +// 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: --expose-debug-as debug --expose-natives-as=builtins + +// Check that the ScopeIterator can properly recreate the scope at +// every point when stepping through functions. + +var Debug = debug.Debug; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + // Access scope details. + var scope_count = exec_state.frame().scopeCount(); + for (var i = 0; i < scope_count; i++) { + var scope = exec_state.frame().scope(i); + // assertTrue(scope.isScope()); + scope.scopeType(); + scope.scopeObject(); + } + + // Do steps until we reach the global scope again. + if (true) { + exec_state.prepareStep(Debug.StepAction.StepInMin, 1); + } + } +} + +Debug.setListener(listener); + +var q = 42; +var prefixes = [ "debugger; ", + "if (false) { try { throw 0; } catch(x) { return x; } }; debugger; " ]; +var bodies = [ "1", + "1 ", + "1;", + "1; ", + "q", + "q ", + "q;", + "q; ", + "try { throw 'stuff' } catch (e) { e = 1; }", + "try { throw 'stuff' } catch (e) { e = 1; } ", + "try { throw 'stuff' } catch (e) { e = 1; };", + "try { throw 'stuff' } catch (e) { e = 1; }; " ]; + + +// Test global eval and function constructor. +for (var i = 0; i < prefixes.length; ++i) { + var pre = prefixes[i]; + for (var j = 0; j < bodies.length; ++j) { + var body = bodies[j]; + Function(pre + body)(); + } +} diff --git a/deps/v8/test/mjsunit/debug-stepout-scope.js b/deps/v8/test/mjsunit/debug-stepout-scope-part8.js index 9c040da932..f91fab5e4d 100644 --- a/deps/v8/test/mjsunit/debug-stepout-scope.js +++ b/deps/v8/test/mjsunit/debug-stepout-scope-part8.js @@ -53,191 +53,6 @@ function listener(event, exec_state, event_data, data) { Debug.setListener(listener); -function test1() { - debugger; - with ({x:1}) { - x = 2; - } -} -test1(); - - -function test2() { - if (true) { - with ({}) { - debugger; - } - } else { - with ({}) { - return 10; - } - } -} -test2(); - - -function test3() { - if (true) { - debugger; - } else { - with ({}) { - return 10; - } - } -} -test3(); - - -function test4() { - debugger; - with ({x:1}) x = 1 -} -test4(); - - -function test5() { - debugger; - var dummy = 1; - with ({}) { - with ({}) { - dummy = 2; - } - } - dummy = 3; -} -test5(); - - -function test6() { - debugger; - try { - throw 'stuff'; - } catch (e) { - e = 1; - } -} -test6(); - - -function test7() { - debugger; - function foo() {} -} -test7(); - - -function test8() { - debugger; - (function foo() {})(); -} -test8(); - - -var q = 42; -var prefixes = [ "debugger; ", - "if (false) { try { throw 0; } catch(x) { return x; } }; debugger; " ]; -var bodies = [ "1", - "1 ", - "1;", - "1; ", - "q", - "q ", - "q;", - "q; ", - "try { throw 'stuff' } catch (e) { e = 1; }", - "try { throw 'stuff' } catch (e) { e = 1; } ", - "try { throw 'stuff' } catch (e) { e = 1; };", - "try { throw 'stuff' } catch (e) { e = 1; }; " ]; -var with_bodies = [ "with ({}) {}", - "with ({x:1}) x", - "with ({x:1}) x = 1", - "with ({x:1}) x ", - "with ({x:1}) x = 1 ", - "with ({x:1}) x;", - "with ({x:1}) x = 1;", - "with ({x:1}) x; ", - "with ({x:1}) x = 1; " ]; - - -function test9() { - debugger; - for (var i = 0; i < prefixes.length; ++i) { - var pre = prefixes[i]; - for (var j = 0; j < bodies.length; ++j) { - var body = bodies[j]; - eval(pre + body); - eval("'use strict'; " + pre + body); - } - for (var j = 0; j < with_bodies.length; ++j) { - var body = with_bodies[j]; - eval(pre + body); - } - } -} -test9(); - - -function test10() { - debugger; - with ({}) { - return 10; - } -} -test10(); - - -function test11() { - debugger; - try { - throw 'stuff'; - } catch (e) { - return 10; - } -} -test11(); - - -// Test global eval and function constructor. -for (var i = 0; i < prefixes.length; ++i) { - var pre = prefixes[i]; - for (var j = 0; j < bodies.length; ++j) { - var body = bodies[j]; - eval(pre + body); - eval("'use strict'; " + pre + body); - Function(pre + body)(); - } - for (var j = 0; j < with_bodies.length; ++j) { - var body = with_bodies[j]; - eval(pre + body); - Function(pre + body)(); - } -} - - -try { - with({}) { - debugger; - eval("{}$%:^"); - } -} catch(e) { - nop(); -} - -// Return from function constructed with Function constructor. -var anon = 12; -for (var i = 0; i < prefixes.length; ++i) { - var pre = prefixes[i]; - Function(pre + "return 42")(); - Function(pre + "return 42 ")(); - Function(pre + "return 42;")(); - Function(pre + "return 42; ")(); - Function(pre + "return anon")(); - Function(pre + "return anon ")(); - Function(pre + "return anon;")(); - Function(pre + "return anon; ")(); -} - - function nop() {} @@ -417,7 +232,3 @@ function stress() { } stress(); - - -// With block as the last(!) statement in global code. -with ({}) { debugger; }
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/delete-non-configurable.js b/deps/v8/test/mjsunit/delete-non-configurable.js new file mode 100644 index 0000000000..8991f43f53 --- /dev/null +++ b/deps/v8/test/mjsunit/delete-non-configurable.js @@ -0,0 +1,74 @@ +// 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. + +// Delete elements of a String object. +var TIPLI = "tipli" +var so = new String(TIPLI); +var length = so.length; + +for (var i = 0; i < length; i++) { + assertFalse(delete so[i]); + assertThrows("'use strict'; delete so[i];", TypeError); + assertFalse(delete so[i.toString()]); + assertThrows("'use strict'; delete so[i.toString()];", TypeError); +} + +assertEquals(length, so.length); +assertEquals(new String(TIPLI), so); + +// Delete elements of an Array. +var arr = new Array(length); + +for (var i = 0; i < length; i++) { + arr[i] = i; + Object.defineProperty(arr, i, { configurable: false }); +} + +for (var i = 0; i < length; i++) { + assertFalse(delete arr[i]); + assertThrows("'use strict'; delete arr[i];", TypeError); + assertFalse(delete arr[i.toString()]); + assertThrows("'use strict'; delete arr[i.toString()];", TypeError); + assertEquals(i, arr[i]); +} + +assertEquals(length, arr.length); +assertTrue(delete arr[length]); + +// Delete an element of an Object. +var INDEX = 28; +var obj = new Object(); + +obj[INDEX] = TIPLI; +Object.defineProperty(obj, INDEX, { configurable: false }); + +assertFalse(delete obj[INDEX]); +assertThrows("'use strict'; delete obj[INDEX];", TypeError); +assertFalse(delete obj[INDEX.toString()]); +assertThrows("'use strict'; delete obj[INDEX.toString()];", TypeError); +assertEquals(TIPLI, obj[INDEX]); +assertTrue(delete arr[INDEX+1]); diff --git a/deps/v8/test/mjsunit/deopt-minus-zero.js b/deps/v8/test/mjsunit/deopt-minus-zero.js new file mode 100644 index 0000000000..ee0983127d --- /dev/null +++ b/deps/v8/test/mjsunit/deopt-minus-zero.js @@ -0,0 +1,56 @@ +// 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 + +/** + * The possible optimization states of a function. Must be in sync with the + * return values of Runtime_GetOptimizationStatus() in runtime.cc! + */ +var OptimizationState = { + YES: 1, + NO: 2, + ALWAYS: 3, + NEVER: 4 +}; + +function mul (a, b) { + return a * b; +} + +mul(-1, -1); +mul(0x80000001|0, -1); +mul(0x80000001|0, -1); +%OptimizeFunctionOnNextCall(mul); +mul(0, -1); +%OptimizeFunctionOnNextCall(mul); +mul(0, -1); + +var raw_optimized = %GetOptimizationStatus(mul); +assertFalse(raw_optimized == OptimizationState.NO); +gc(); + diff --git a/deps/v8/test/mjsunit/elements-kind.js b/deps/v8/test/mjsunit/elements-kind.js index b74a212437..cf9c21605d 100644 --- a/deps/v8/test/mjsunit/elements-kind.js +++ b/deps/v8/test/mjsunit/elements-kind.js @@ -321,8 +321,7 @@ if (support_smi_only_arrays) { assertKind(elements_kind.fast_double, b); var c = a.concat(b); assertEquals([1, 2, 4.5, 5.5], c); - // TODO(1810): Change implementation so that we get DOUBLE elements here? - assertKind(elements_kind.fast, c); + assertKind(elements_kind.fast_double, c); } // Test that Array.push() correctly handles SMI elements. diff --git a/deps/v8/test/mjsunit/elements-length-no-holey.js b/deps/v8/test/mjsunit/elements-length-no-holey.js new file mode 100644 index 0000000000..5bac296e1a --- /dev/null +++ b/deps/v8/test/mjsunit/elements-length-no-holey.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. + +// Flags: --allow-natives-syntax + +a = [1,2,3]; +a.length = 1; +assertFalse(%HasFastHoleyElements(a)); +assertTrue(%HasFastSmiElements(a)); diff --git a/deps/v8/test/mjsunit/elements-transition-hoisting.js b/deps/v8/test/mjsunit/elements-transition-hoisting.js index 5fb3889c6e..017e7ec51f 100644 --- a/deps/v8/test/mjsunit/elements-transition-hoisting.js +++ b/deps/v8/test/mjsunit/elements-transition-hoisting.js @@ -25,8 +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 --smi-only-arrays --expose-gc -// Flags: --noparallel-recompilation +// Flags: --allow-natives-syntax --smi-only-arrays --noparallel-recompilation // Ensure that ElementsKind transitions in various situations are hoisted (or // not hoisted) correctly, don't change the semantics programs and don't trigger @@ -40,11 +39,6 @@ if (support_smi_only_arrays) { print("Tests do NOT include smi-only arrays."); } -// Force existing ICs from previous stress runs to be flushed, otherwise the -// assumptions in this test about when deoptimizations get triggered are not -// valid. -gc(); - if (support_smi_only_arrays) { // Make sure that a simple elements array transitions inside a loop before // stores to an array gets hoisted in a way that doesn't generate a deopt in @@ -66,6 +60,7 @@ if (support_smi_only_arrays) { testDoubleConversion4(new Array(5)); testDoubleConversion4(new Array(5)); assertTrue(2 != %GetOptimizationStatus(testDoubleConversion4)); + %ClearFunctionTypeFeedback(testDoubleConversion4); // Make sure that non-element related map checks that are not preceded by // transitions in a loop still get hoisted in a way that doesn't generate a @@ -91,6 +86,7 @@ if (support_smi_only_arrays) { testExactMapHoisting(new Array(5)); testExactMapHoisting(new Array(5)); assertTrue(2 != %GetOptimizationStatus(testExactMapHoisting)); + %ClearFunctionTypeFeedback(testExactMapHoisting); // Make sure that non-element related map checks do NOT get hoisted if they // depend on an elements transition before them and it's not possible to hoist @@ -122,6 +118,7 @@ if (support_smi_only_arrays) { testExactMapHoisting2(new Array(5)); // Temporarily disabled - see bug 2176. // assertTrue(2 != %GetOptimizationStatus(testExactMapHoisting2)); + %ClearFunctionTypeFeedback(testExactMapHoisting2); // Make sure that non-element related map checks do get hoisted if they use // the transitioned map for the check and all transitions that they depend @@ -150,6 +147,7 @@ if (support_smi_only_arrays) { testExactMapHoisting3(new Array(5)); testExactMapHoisting3(new Array(5)); assertTrue(2 != %GetOptimizationStatus(testExactMapHoisting3)); + %ClearFunctionTypeFeedback(testExactMapHoisting3); function testDominatingTransitionHoisting1(a) { var object = new Object(); @@ -163,6 +161,7 @@ if (support_smi_only_arrays) { } while (--count > 3); } + /* testDominatingTransitionHoisting1(new Array(5)); testDominatingTransitionHoisting1(new Array(5)); // Call twice to make sure // that second store is a @@ -171,7 +170,12 @@ if (support_smi_only_arrays) { %OptimizeFunctionOnNextCall(testDominatingTransitionHoisting1); testDominatingTransitionHoisting1(new Array(5)); testDominatingTransitionHoisting1(new Array(5)); + // TODO(verwaest) With current changes the elements transition gets hoisted + // above the access, causing a deopt. We should update the type of access + // rather than forbid hoisting the transition. assertTrue(2 != %GetOptimizationStatus(testDominatingTransitionHoisting1)); + %ClearFunctionTypeFeedback(testDominatingTransitionHoisting1); + */ function testHoistingWithSideEffect(a) { var object = new Object(); @@ -191,6 +195,7 @@ if (support_smi_only_arrays) { testHoistingWithSideEffect(new Array(5)); testHoistingWithSideEffect(new Array(5)); assertTrue(2 != %GetOptimizationStatus(testHoistingWithSideEffect)); + %ClearFunctionTypeFeedback(testHoistingWithSideEffect); function testStraightLineDupeElinination(a,b,c,d,e,f) { var count = 3; @@ -226,7 +231,8 @@ if (support_smi_only_arrays) { testStraightLineDupeElinination(new Array(5),0,0,0,.5,0); testStraightLineDupeElinination(new Array(5),0,0,0,0,.5); %OptimizeFunctionOnNextCall(testStraightLineDupeElinination); - testStraightLineDupeElinination(new Array(5)); - testStraightLineDupeElinination(new Array(5)); + testStraightLineDupeElinination(new Array(5),0,0,0,0,0); + testStraightLineDupeElinination(new Array(5),0,0,0,0,0); assertTrue(2 != %GetOptimizationStatus(testStraightLineDupeElinination)); + %ClearFunctionTypeFeedback(testStraightLineDupeElinination); } diff --git a/deps/v8/test/mjsunit/error-accessors.js b/deps/v8/test/mjsunit/error-accessors.js new file mode 100644 index 0000000000..9581050240 --- /dev/null +++ b/deps/v8/test/mjsunit/error-accessors.js @@ -0,0 +1,54 @@ +// 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 the message property of error objects is a data property. + +var o; + +// message is constructed using the constructor. +var error1 = new Error("custom message"); +o = {}; +o.__proto__ = error1; + +assertEquals("custom message", + Object.getOwnPropertyDescriptor(error1, "message").value); +o.message = "another message"; +assertEquals("another message", o.message); +assertEquals("custom message", error1.message); + +// message is constructed by the runtime. +var error2; +try { x.x } catch (e) { error2 = e; } +o = {}; +o.__proto__ = error2; + +assertEquals("x is not defined", + Object.getOwnPropertyDescriptor(error2, "message").value); +o.message = "another message"; +assertEquals("another message", o.message); +assertEquals("x is not defined", error2.message); + diff --git a/deps/v8/test/mjsunit/error-constructors.js b/deps/v8/test/mjsunit/error-constructors.js index 107164df56..84c6bbfd0c 100644 --- a/deps/v8/test/mjsunit/error-constructors.js +++ b/deps/v8/test/mjsunit/error-constructors.js @@ -36,10 +36,6 @@ assertFalse(desc['enumerable']); var e = new Error("foobar"); desc = Object.getOwnPropertyDescriptor(e, 'message'); assertFalse(desc['enumerable']); -desc = Object.getOwnPropertyDescriptor(e, 'arguments'); -assertFalse(desc['enumerable']); -desc = Object.getOwnPropertyDescriptor(e, 'type'); -assertFalse(desc['enumerable']); desc = Object.getOwnPropertyDescriptor(e, 'stack'); assertFalse(desc['enumerable']); @@ -57,26 +53,17 @@ for (var v in e) { 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 @@ -86,7 +73,7 @@ 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"]; + var props = ["name", "message", "stack"]; for (var j in props) { errors[i].prototype.__defineGetter__(props[j], fail); } diff --git a/deps/v8/test/mjsunit/function-call.js b/deps/v8/test/mjsunit/function-call.js index 26890ed113..92792ac827 100644 --- a/deps/v8/test/mjsunit/function-call.js +++ b/deps/v8/test/mjsunit/function-call.js @@ -67,8 +67,7 @@ var should_throw_on_null_and_undefined = String.prototype.toLocaleLowerCase, String.prototype.toUpperCase, String.prototype.toLocaleUpperCase, - String.prototype.trim, - Number.prototype.toLocaleString]; + String.prototype.trim]; // Non generic natives do not work on any input other than the specific // type, but since this change will allow call to be invoked with undefined @@ -150,6 +149,11 @@ var reducing_functions = [Array.prototype.reduce, Array.prototype.reduceRight]; +function checkExpectedMessage(e) { + assertTrue(e.message.indexOf("called on null or undefined") >= 0 || + e.message.indexOf("Cannot convert null to object") >= 0); +} + // Test that all natives using the ToObject call throw the right exception. for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) { // Sanity check that all functions are correct @@ -166,8 +170,7 @@ for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) { should_throw_on_null_and_undefined[i].call(null); } catch (e) { exception = true; - assertTrue("called_on_null_or_undefined" == e.type || - "null_to_object" == e.type); + checkExpectedMessage(e); } assertTrue(exception); @@ -176,8 +179,7 @@ for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) { should_throw_on_null_and_undefined[i].call(undefined); } catch (e) { exception = true; - assertTrue("called_on_null_or_undefined" == e.type || - "null_to_object" == e.type); + checkExpectedMessage(e); } assertTrue(exception); @@ -186,8 +188,7 @@ for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) { should_throw_on_null_and_undefined[i].apply(null); } catch (e) { exception = true; - assertTrue("called_on_null_or_undefined" == e.type || - "null_to_object" == e.type); + checkExpectedMessage(e); } assertTrue(exception); @@ -196,8 +197,7 @@ for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) { should_throw_on_null_and_undefined[i].apply(undefined); } catch (e) { exception = true; - assertTrue("called_on_null_or_undefined" == e.type || - "null_to_object" == e.type); + checkExpectedMessage(e); } assertTrue(exception); } @@ -257,8 +257,7 @@ for (var j = 0; j < mapping_functions.length; j++) { null); } catch (e) { exception = true; - assertTrue("called_on_null_or_undefined" == e.type || - "null_to_object" == e.type); + checkExpectedMessage(e); } assertTrue(exception); @@ -269,8 +268,7 @@ for (var j = 0; j < mapping_functions.length; j++) { undefined); } catch (e) { exception = true; - assertTrue("called_on_null_or_undefined" == e.type || - "null_to_object" == e.type); + checkExpectedMessage(e); } assertTrue(exception); } @@ -311,8 +309,7 @@ for (var j = 0; j < reducing_functions.length; j++) { reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]); } catch (e) { exception = true; - assertTrue("called_on_null_or_undefined" == e.type || - "null_to_object" == e.type); + checkExpectedMessage(e); } assertTrue(exception); @@ -321,8 +318,7 @@ for (var j = 0; j < reducing_functions.length; j++) { reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]); } catch (e) { exception = true; - assertTrue("called_on_null_or_undefined" == e.type || - "null_to_object" == e.type); + checkExpectedMessage(e); } assertTrue(exception); } diff --git a/deps/v8/test/mjsunit/fuzz-natives.js b/deps/v8/test/mjsunit/fuzz-natives-part1.js index 225a44d8a5..87f7d0d766 100644 --- a/deps/v8/test/mjsunit/fuzz-natives.js +++ b/deps/v8/test/mjsunit/fuzz-natives-part1.js @@ -147,6 +147,7 @@ var knownProblems = { "PushWithContext": true, "PushCatchContext": true, "PushBlockContext": true, + "PushModuleContext": true, "LazyCompile": true, "LazyRecompile": true, "ParallelRecompile": true, @@ -195,7 +196,13 @@ var knownProblems = { // Only applicable to strings. "_HasCachedArrayIndex": true, - "_GetCachedArrayIndex": true + "_GetCachedArrayIndex": true, + "_OneByteSeqStringSetChar": true, + "_TwoByteSeqStringSetChar": true, + + // Only for debugging parallel recompilation. + "InstallRecompiledCode": true, + "ForceParallelRecompile": true }; var currentlyUncallable = { @@ -205,7 +212,9 @@ var currentlyUncallable = { function testNatives() { var allNatives = %ListNatives(); - for (var i = 0; i < allNatives.length; i++) { + var start = 0; + var stop = (allNatives.length >> 2); + for (var i = start; i < stop; i++) { var nativeInfo = allNatives[i]; var name = nativeInfo[0]; if (name in knownProblems || name in currentlyUncallable) diff --git a/deps/v8/test/mjsunit/fuzz-natives-part2.js b/deps/v8/test/mjsunit/fuzz-natives-part2.js new file mode 100644 index 0000000000..2faad1dcac --- /dev/null +++ b/deps/v8/test/mjsunit/fuzz-natives-part2.js @@ -0,0 +1,229 @@ +// 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 + +var RUN_WITH_ALL_ARGUMENT_ENTRIES = false; +var kOnManyArgumentsRemove = 5; + +function makeArguments() { + var result = [ ]; + result.push(17); + result.push(-31); + result.push(new Array(100)); + result.push(new Array(100003)); + result.push(Number.MIN_VALUE); + result.push("whoops"); + result.push("x"); + result.push({"x": 1, "y": 2}); + var slowCaseObj = {"a": 3, "b": 4, "c": 5}; + delete slowCaseObj.c; + result.push(slowCaseObj); + result.push(function () { return 8; }); + return result; +} + +var kArgObjects = makeArguments().length; + +function makeFunction(name, argc) { + var args = []; + for (var i = 0; i < argc; i++) + args.push("x" + i); + var argsStr = args.join(", "); + return new Function(args.join(", "), "return %" + name + "(" + argsStr + ");"); +} + +function testArgumentCount(name, argc) { + for (var i = 0; i < 10; i++) { + var func = null; + try { + func = makeFunction(name, i); + } catch (e) { + if (e != "SyntaxError: Illegal access") throw e; + } + if (func === null && i == argc) { + throw "unexpected exception"; + } + var args = [ ]; + for (var j = 0; j < i; j++) + args.push(0); + try { + func.apply(void 0, args); + } catch (e) { + // we don't care what happens as long as we don't crash + } + } +} + +function testArgumentTypes(name, argc) { + var type = 0; + var hasMore = true; + var func = makeFunction(name, argc); + while (hasMore) { + var argPool = makeArguments(); + // When we have 5 or more arguments we lower the amount of tests cases + // by randomly removing kOnManyArgumentsRemove entries + var numArguments = RUN_WITH_ALL_ARGUMENT_ENTRIES ? + kArgObjects : kArgObjects-kOnManyArgumentsRemove; + if (argc >= 5 && !RUN_WITH_ALL_ARGUMENT_ENTRIES) { + for (var i = 0; i < kOnManyArgumentsRemove; i++) { + var rand = Math.floor(Math.random() * (kArgObjects - i)); + argPool.splice(rand,1); + } + } + var current = type; + var hasMore = false; + var argList = [ ]; + for (var i = 0; i < argc; i++) { + var index = current % numArguments; + current = (current / numArguments) << 0; + if (index != (numArguments - 1)) + hasMore = true; + argList.push(argPool[index]); + } + try { + func.apply(void 0, argList); + } catch (e) { + // we don't care what happens as long as we don't crash + } + type++; + } +} + +var knownProblems = { + "Abort": true, + + // Avoid calling the concat operation, because weird lengths + // may lead to out-of-memory. Ditto for StringBuilderJoin. + "StringBuilderConcat": true, + "StringBuilderJoin": true, + + // These functions use pseudo-stack-pointers and are not robust + // to unexpected integer values. + "DebugEvaluate": true, + + // These functions do nontrivial error checking in recursive calls, + // which means that we have to propagate errors back. + "SetFunctionBreakPoint": true, + "SetScriptBreakPoint": true, + "PrepareStep": true, + + // Too slow. + "DebugReferencedBy": true, + + // Calling disable/enable access checks may interfere with the + // the rest of the tests. + "DisableAccessChecks": true, + "EnableAccessChecks": true, + + // These functions should not be callable as runtime functions. + "NewFunctionContext": true, + "NewArgumentsFast": true, + "NewStrictArgumentsFast": true, + "PushWithContext": true, + "PushCatchContext": true, + "PushBlockContext": true, + "PushModuleContext": true, + "LazyCompile": true, + "LazyRecompile": true, + "ParallelRecompile": true, + "NotifyDeoptimized": true, + "NotifyOSR": true, + "CreateObjectLiteralBoilerplate": true, + "CloneLiteralBoilerplate": true, + "CloneShallowLiteralBoilerplate": true, + "CreateArrayLiteralBoilerplate": true, + "IS_VAR": true, + "ResolvePossiblyDirectEval": true, + "Log": true, + "DeclareGlobals": true, + + "PromoteScheduledException": true, + "DeleteHandleScopeExtensions": true, + + // Vararg with minimum number > 0. + "Call": true, + + // Requires integer arguments to be non-negative. + "Apply": true, + + // That can only be invoked on Array.prototype. + "FinishArrayPrototypeSetup": true, + + "_SwapElements": true, + + // Performance critical functions which cannot afford type checks. + "_IsNativeOrStrictMode": true, + "_CallFunction": true, + + // Tries to allocate based on argument, and (correctly) throws + // out-of-memory if the request is too large. In practice, the + // size will be the number of captures of a RegExp. + "RegExpConstructResult": true, + "_RegExpConstructResult": true, + + // This functions perform some checks compile time (they require one of their + // arguments to be a compile time smi). + "_DateField": true, + "_GetFromCache": true, + + // This function expects its first argument to be a non-smi. + "_IsStringWrapperSafeForDefaultValueOf" : true, + + // Only applicable to strings. + "_HasCachedArrayIndex": true, + "_GetCachedArrayIndex": true, + "_OneByteSeqStringSetChar": true, + "_TwoByteSeqStringSetChar": true, + + // Only for debugging parallel recompilation. + "InstallRecompiledCode": true, + "ForceParallelRecompile": true +}; + +var currentlyUncallable = { + // We need to find a way to test this without breaking the system. + "SystemBreak": true +}; + +function testNatives() { + var allNatives = %ListNatives(); + var start = allNatives.length >> 2; + var stop = (allNatives.length >> 2)*2; + for (var i = start; i < stop; i++) { + var nativeInfo = allNatives[i]; + var name = nativeInfo[0]; + if (name in knownProblems || name in currentlyUncallable) + continue; + print(name); + var argc = nativeInfo[1]; + testArgumentCount(name, argc); + testArgumentTypes(name, argc); + } +} + +testNatives(); diff --git a/deps/v8/test/mjsunit/fuzz-natives-part3.js b/deps/v8/test/mjsunit/fuzz-natives-part3.js new file mode 100644 index 0000000000..ed71d332a0 --- /dev/null +++ b/deps/v8/test/mjsunit/fuzz-natives-part3.js @@ -0,0 +1,229 @@ +// 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 + +var RUN_WITH_ALL_ARGUMENT_ENTRIES = false; +var kOnManyArgumentsRemove = 5; + +function makeArguments() { + var result = [ ]; + result.push(17); + result.push(-31); + result.push(new Array(100)); + result.push(new Array(100003)); + result.push(Number.MIN_VALUE); + result.push("whoops"); + result.push("x"); + result.push({"x": 1, "y": 2}); + var slowCaseObj = {"a": 3, "b": 4, "c": 5}; + delete slowCaseObj.c; + result.push(slowCaseObj); + result.push(function () { return 8; }); + return result; +} + +var kArgObjects = makeArguments().length; + +function makeFunction(name, argc) { + var args = []; + for (var i = 0; i < argc; i++) + args.push("x" + i); + var argsStr = args.join(", "); + return new Function(args.join(", "), "return %" + name + "(" + argsStr + ");"); +} + +function testArgumentCount(name, argc) { + for (var i = 0; i < 10; i++) { + var func = null; + try { + func = makeFunction(name, i); + } catch (e) { + if (e != "SyntaxError: Illegal access") throw e; + } + if (func === null && i == argc) { + throw "unexpected exception"; + } + var args = [ ]; + for (var j = 0; j < i; j++) + args.push(0); + try { + func.apply(void 0, args); + } catch (e) { + // we don't care what happens as long as we don't crash + } + } +} + +function testArgumentTypes(name, argc) { + var type = 0; + var hasMore = true; + var func = makeFunction(name, argc); + while (hasMore) { + var argPool = makeArguments(); + // When we have 5 or more arguments we lower the amount of tests cases + // by randomly removing kOnManyArgumentsRemove entries + var numArguments = RUN_WITH_ALL_ARGUMENT_ENTRIES ? + kArgObjects : kArgObjects-kOnManyArgumentsRemove; + if (argc >= 5 && !RUN_WITH_ALL_ARGUMENT_ENTRIES) { + for (var i = 0; i < kOnManyArgumentsRemove; i++) { + var rand = Math.floor(Math.random() * (kArgObjects - i)); + argPool.splice(rand,1); + } + } + var current = type; + var hasMore = false; + var argList = [ ]; + for (var i = 0; i < argc; i++) { + var index = current % numArguments; + current = (current / numArguments) << 0; + if (index != (numArguments - 1)) + hasMore = true; + argList.push(argPool[index]); + } + try { + func.apply(void 0, argList); + } catch (e) { + // we don't care what happens as long as we don't crash + } + type++; + } +} + +var knownProblems = { + "Abort": true, + + // Avoid calling the concat operation, because weird lengths + // may lead to out-of-memory. Ditto for StringBuilderJoin. + "StringBuilderConcat": true, + "StringBuilderJoin": true, + + // These functions use pseudo-stack-pointers and are not robust + // to unexpected integer values. + "DebugEvaluate": true, + + // These functions do nontrivial error checking in recursive calls, + // which means that we have to propagate errors back. + "SetFunctionBreakPoint": true, + "SetScriptBreakPoint": true, + "PrepareStep": true, + + // Too slow. + "DebugReferencedBy": true, + + // Calling disable/enable access checks may interfere with the + // the rest of the tests. + "DisableAccessChecks": true, + "EnableAccessChecks": true, + + // These functions should not be callable as runtime functions. + "NewFunctionContext": true, + "NewArgumentsFast": true, + "NewStrictArgumentsFast": true, + "PushWithContext": true, + "PushCatchContext": true, + "PushBlockContext": true, + "PushModuleContext": true, + "LazyCompile": true, + "LazyRecompile": true, + "ParallelRecompile": true, + "NotifyDeoptimized": true, + "NotifyOSR": true, + "CreateObjectLiteralBoilerplate": true, + "CloneLiteralBoilerplate": true, + "CloneShallowLiteralBoilerplate": true, + "CreateArrayLiteralBoilerplate": true, + "IS_VAR": true, + "ResolvePossiblyDirectEval": true, + "Log": true, + "DeclareGlobals": true, + + "PromoteScheduledException": true, + "DeleteHandleScopeExtensions": true, + + // Vararg with minimum number > 0. + "Call": true, + + // Requires integer arguments to be non-negative. + "Apply": true, + + // That can only be invoked on Array.prototype. + "FinishArrayPrototypeSetup": true, + + "_SwapElements": true, + + // Performance critical functions which cannot afford type checks. + "_IsNativeOrStrictMode": true, + "_CallFunction": true, + + // Tries to allocate based on argument, and (correctly) throws + // out-of-memory if the request is too large. In practice, the + // size will be the number of captures of a RegExp. + "RegExpConstructResult": true, + "_RegExpConstructResult": true, + + // This functions perform some checks compile time (they require one of their + // arguments to be a compile time smi). + "_DateField": true, + "_GetFromCache": true, + + // This function expects its first argument to be a non-smi. + "_IsStringWrapperSafeForDefaultValueOf" : true, + + // Only applicable to strings. + "_HasCachedArrayIndex": true, + "_GetCachedArrayIndex": true, + "_OneByteSeqStringSetChar": true, + "_TwoByteSeqStringSetChar": true, + + // Only for debugging parallel recompilation. + "InstallRecompiledCode": true, + "ForceParallelRecompile": true +}; + +var currentlyUncallable = { + // We need to find a way to test this without breaking the system. + "SystemBreak": true +}; + +function testNatives() { + var allNatives = %ListNatives(); + var start = (allNatives.length >> 2)*2; + var stop = (allNatives.length >> 2)*3; + for (var i = start; i < stop; i++) { + var nativeInfo = allNatives[i]; + var name = nativeInfo[0]; + if (name in knownProblems || name in currentlyUncallable) + continue; + print(name); + var argc = nativeInfo[1]; + testArgumentCount(name, argc); + testArgumentTypes(name, argc); + } +} + +testNatives(); diff --git a/deps/v8/test/mjsunit/fuzz-natives-part4.js b/deps/v8/test/mjsunit/fuzz-natives-part4.js new file mode 100644 index 0000000000..1b128d5942 --- /dev/null +++ b/deps/v8/test/mjsunit/fuzz-natives-part4.js @@ -0,0 +1,229 @@ +// 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 + +var RUN_WITH_ALL_ARGUMENT_ENTRIES = false; +var kOnManyArgumentsRemove = 5; + +function makeArguments() { + var result = [ ]; + result.push(17); + result.push(-31); + result.push(new Array(100)); + result.push(new Array(100003)); + result.push(Number.MIN_VALUE); + result.push("whoops"); + result.push("x"); + result.push({"x": 1, "y": 2}); + var slowCaseObj = {"a": 3, "b": 4, "c": 5}; + delete slowCaseObj.c; + result.push(slowCaseObj); + result.push(function () { return 8; }); + return result; +} + +var kArgObjects = makeArguments().length; + +function makeFunction(name, argc) { + var args = []; + for (var i = 0; i < argc; i++) + args.push("x" + i); + var argsStr = args.join(", "); + return new Function(args.join(", "), "return %" + name + "(" + argsStr + ");"); +} + +function testArgumentCount(name, argc) { + for (var i = 0; i < 10; i++) { + var func = null; + try { + func = makeFunction(name, i); + } catch (e) { + if (e != "SyntaxError: Illegal access") throw e; + } + if (func === null && i == argc) { + throw "unexpected exception"; + } + var args = [ ]; + for (var j = 0; j < i; j++) + args.push(0); + try { + func.apply(void 0, args); + } catch (e) { + // we don't care what happens as long as we don't crash + } + } +} + +function testArgumentTypes(name, argc) { + var type = 0; + var hasMore = true; + var func = makeFunction(name, argc); + while (hasMore) { + var argPool = makeArguments(); + // When we have 5 or more arguments we lower the amount of tests cases + // by randomly removing kOnManyArgumentsRemove entries + var numArguments = RUN_WITH_ALL_ARGUMENT_ENTRIES ? + kArgObjects : kArgObjects-kOnManyArgumentsRemove; + if (argc >= 5 && !RUN_WITH_ALL_ARGUMENT_ENTRIES) { + for (var i = 0; i < kOnManyArgumentsRemove; i++) { + var rand = Math.floor(Math.random() * (kArgObjects - i)); + argPool.splice(rand,1); + } + } + var current = type; + var hasMore = false; + var argList = [ ]; + for (var i = 0; i < argc; i++) { + var index = current % numArguments; + current = (current / numArguments) << 0; + if (index != (numArguments - 1)) + hasMore = true; + argList.push(argPool[index]); + } + try { + func.apply(void 0, argList); + } catch (e) { + // we don't care what happens as long as we don't crash + } + type++; + } +} + +var knownProblems = { + "Abort": true, + + // Avoid calling the concat operation, because weird lengths + // may lead to out-of-memory. Ditto for StringBuilderJoin. + "StringBuilderConcat": true, + "StringBuilderJoin": true, + + // These functions use pseudo-stack-pointers and are not robust + // to unexpected integer values. + "DebugEvaluate": true, + + // These functions do nontrivial error checking in recursive calls, + // which means that we have to propagate errors back. + "SetFunctionBreakPoint": true, + "SetScriptBreakPoint": true, + "PrepareStep": true, + + // Too slow. + "DebugReferencedBy": true, + + // Calling disable/enable access checks may interfere with the + // the rest of the tests. + "DisableAccessChecks": true, + "EnableAccessChecks": true, + + // These functions should not be callable as runtime functions. + "NewFunctionContext": true, + "NewArgumentsFast": true, + "NewStrictArgumentsFast": true, + "PushWithContext": true, + "PushCatchContext": true, + "PushBlockContext": true, + "PushModuleContext": true, + "LazyCompile": true, + "LazyRecompile": true, + "ParallelRecompile": true, + "NotifyDeoptimized": true, + "NotifyOSR": true, + "CreateObjectLiteralBoilerplate": true, + "CloneLiteralBoilerplate": true, + "CloneShallowLiteralBoilerplate": true, + "CreateArrayLiteralBoilerplate": true, + "IS_VAR": true, + "ResolvePossiblyDirectEval": true, + "Log": true, + "DeclareGlobals": true, + + "PromoteScheduledException": true, + "DeleteHandleScopeExtensions": true, + + // Vararg with minimum number > 0. + "Call": true, + + // Requires integer arguments to be non-negative. + "Apply": true, + + // That can only be invoked on Array.prototype. + "FinishArrayPrototypeSetup": true, + + "_SwapElements": true, + + // Performance critical functions which cannot afford type checks. + "_IsNativeOrStrictMode": true, + "_CallFunction": true, + + // Tries to allocate based on argument, and (correctly) throws + // out-of-memory if the request is too large. In practice, the + // size will be the number of captures of a RegExp. + "RegExpConstructResult": true, + "_RegExpConstructResult": true, + + // This functions perform some checks compile time (they require one of their + // arguments to be a compile time smi). + "_DateField": true, + "_GetFromCache": true, + + // This function expects its first argument to be a non-smi. + "_IsStringWrapperSafeForDefaultValueOf" : true, + + // Only applicable to strings. + "_HasCachedArrayIndex": true, + "_GetCachedArrayIndex": true, + "_OneByteSeqStringSetChar": true, + "_TwoByteSeqStringSetChar": true, + + // Only for debugging parallel recompilation. + "InstallRecompiledCode": true, + "ForceParallelRecompile": true +}; + +var currentlyUncallable = { + // We need to find a way to test this without breaking the system. + "SystemBreak": true +}; + +function testNatives() { + var allNatives = %ListNatives(); + var start = (allNatives.length >> 2)*3; + var stop = allNatives.length; + for (var i = start; i < stop; i++) { + var nativeInfo = allNatives[i]; + var name = nativeInfo[0]; + if (name in knownProblems || name in currentlyUncallable) + continue; + print(name); + var argc = nativeInfo[1]; + testArgumentCount(name, argc); + testArgumentTypes(name, argc); + } +} + +testNatives(); diff --git a/deps/v8/test/mjsunit/greedy.js b/deps/v8/test/mjsunit/greedy.js index d357f0cad3..8c49e41b9c 100644 --- a/deps/v8/test/mjsunit/greedy.js +++ b/deps/v8/test/mjsunit/greedy.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: --gc-greedy +// Flags: --gc-greedy --noverify-heap function IterativeFib(n) { var f0 = 0, f1 = 1; diff --git a/deps/v8/test/mjsunit/harmony/collections.js b/deps/v8/test/mjsunit/harmony/collections.js index f3db7ea2b7..0219f39364 100644 --- a/deps/v8/test/mjsunit/harmony/collections.js +++ b/deps/v8/test/mjsunit/harmony/collections.js @@ -313,4 +313,60 @@ TestBogusReceivers(bogusReceiversTestSet); // Stress Test // There is a proposed stress-test available at the es-discuss mailing list // which cannot be reasonably automated. Check it out by hand if you like: -// https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html
\ No newline at end of file +// https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html + + +// Set and Map size getters +var setSizeDescriptor = Object.getOwnPropertyDescriptor(Set.prototype, 'size'); +assertEquals(undefined, setSizeDescriptor.value); +assertEquals(undefined, setSizeDescriptor.set); +assertTrue(setSizeDescriptor.get instanceof Function); +assertEquals(undefined, setSizeDescriptor.get.prototype); +assertFalse(setSizeDescriptor.enumerable); +assertTrue(setSizeDescriptor.configurable); + +var s = new Set(); +assertFalse(s.hasOwnProperty('size')); +for (var i = 0; i < 10; i++) { + assertEquals(i, s.size); + s.add(i); +} +for (var i = 9; i >= 0; i--) { + s.delete(i); + assertEquals(i, s.size); +} + + +var mapSizeDescriptor = Object.getOwnPropertyDescriptor(Map.prototype, 'size'); +assertEquals(undefined, mapSizeDescriptor.value); +assertEquals(undefined, mapSizeDescriptor.set); +assertTrue(mapSizeDescriptor.get instanceof Function); +assertEquals(undefined, mapSizeDescriptor.get.prototype); +assertFalse(mapSizeDescriptor.enumerable); +assertTrue(mapSizeDescriptor.configurable); + +var m = new Map(); +assertFalse(m.hasOwnProperty('size')); +for (var i = 0; i < 10; i++) { + assertEquals(i, m.size); + m.set(i, i); +} +for (var i = 9; i >= 0; i--) { + m.delete(i); + assertEquals(i, m.size); +} + +// Test clear +var a = new Set(); +s.add(42); +assertTrue(s.has(42)); +s.clear(); +assertFalse(s.has(42)); +assertEquals(0, s.size); + +var m = new Map(); +m.set(42, true); +assertTrue(m.has(42)); +m.clear(); +assertFalse(m.has(42)); +assertEquals(0, m.size); diff --git a/deps/v8/test/mjsunit/harmony/debug-blockscopes.js b/deps/v8/test/mjsunit/harmony/debug-blockscopes.js index 10aac2dbd4..ca2ab9e5a6 100644 --- a/deps/v8/test/mjsunit/harmony/debug-blockscopes.js +++ b/deps/v8/test/mjsunit/harmony/debug-blockscopes.js @@ -376,7 +376,7 @@ listener_delegate = function(exec_state) { debug.ScopeType.Global], exec_state); CheckScopeContent({x:'y'}, 0, exec_state); // The function scope contains a temporary iteration variable. - CheckScopeContent({x:'y'}, 1, exec_state); + CheckScopeContent({'.for.x':'y'}, 1, exec_state); }; for_loop_1(); EndTest(); @@ -401,7 +401,7 @@ listener_delegate = function(exec_state) { CheckScopeContent({x:3}, 0, exec_state); CheckScopeContent({x:'y'}, 1, exec_state); // The function scope contains a temporary iteration variable. - CheckScopeContent({x:'y'}, 2, exec_state); + CheckScopeContent({'.for.x':'y'}, 2, exec_state); }; for_loop_2(); EndTest(); diff --git a/deps/v8/test/mjsunit/harmony/module-linking.js b/deps/v8/test/mjsunit/harmony/module-linking.js index a4b272f468..3c0f18c37d 100644 --- a/deps/v8/test/mjsunit/harmony/module-linking.js +++ b/deps/v8/test/mjsunit/harmony/module-linking.js @@ -112,7 +112,7 @@ module R { assertThrows(function() { eval("c = -1") }, SyntaxError) assertThrows(function() { R.c = -2 }, TypeError) - // Initialize first bunch or variables. + // Initialize first bunch of variables. export var v = 1 export let l = 2 export const c = 3 diff --git a/deps/v8/test/mjsunit/harmony/module-parsing.js b/deps/v8/test/mjsunit/harmony/module-parsing.js index 03948e31b9..8a9103d132 100644 --- a/deps/v8/test/mjsunit/harmony/module-parsing.js +++ b/deps/v8/test/mjsunit/harmony/module-parsing.js @@ -162,3 +162,29 @@ try {} catch (module) {} module v = 20 + + + +// Check that module declarations are rejected in eval or local scope. + +module M { export let x; } + +assertThrows("export x;", SyntaxError); // It's using eval, so should throw. +assertThrows("export let x;", SyntaxError); +assertThrows("import x from M;", SyntaxError); +assertThrows("module M {};", SyntaxError); + +assertThrows("{ export x; }", SyntaxError); +assertThrows("{ export let x; }", SyntaxError); +assertThrows("{ import x from M; }", SyntaxError); +assertThrows("{ module M {}; }", SyntaxError); + +assertThrows("function f() { export x; }", SyntaxError); +assertThrows("function f() { export let x; }", SyntaxError); +assertThrows("function f() { import x from M; }", SyntaxError); +assertThrows("function f() { module M {}; }", SyntaxError); + +assertThrows("function f() { { export x; } }", SyntaxError); +assertThrows("function f() { { export let x; } }", SyntaxError); +assertThrows("function f() { { import x from M; } }", SyntaxError); +assertThrows("function f() { { module M {}; } }", SyntaxError); diff --git a/deps/v8/test/mjsunit/harmony/object-observe.js b/deps/v8/test/mjsunit/harmony/object-observe.js new file mode 100644 index 0000000000..04dfb967b3 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/object-observe.js @@ -0,0 +1,873 @@ +// 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-observation --harmony-proxies --harmony-collections + +var allObservers = []; +function reset() { + allObservers.forEach(function(observer) { observer.reset(); }); +} + +function stringifyNoThrow(arg) { + try { + return JSON.stringify(arg); + } catch (e) { + return '{<circular reference>}'; + } +} + +function createObserver() { + "use strict"; // So that |this| in callback can be undefined. + + var observer = { + records: undefined, + callbackCount: 0, + reset: function() { + this.records = undefined; + this.callbackCount = 0; + }, + assertNotCalled: function() { + assertEquals(undefined, this.records); + assertEquals(0, this.callbackCount); + }, + assertCalled: function() { + assertEquals(1, this.callbackCount); + }, + assertRecordCount: function(count) { + this.assertCalled(); + assertEquals(count, this.records.length); + }, + assertCallbackRecords: function(recs) { + this.assertRecordCount(recs.length); + for (var i = 0; i < recs.length; i++) { + if ('name' in recs[i]) + recs[i].name = String(recs[i].name); + print(i, stringifyNoThrow(this.records[i]), stringifyNoThrow(recs[i])); + assertSame(this.records[i].object, recs[i].object); + assertEquals('string', typeof recs[i].type); + assertPropertiesEqual(this.records[i], recs[i]); + } + } + }; + + observer.callback = function(r) { + assertEquals(undefined, this); + assertEquals('object', typeof r); + assertTrue(r instanceof Array) + observer.records = r; + observer.callbackCount++; + }; + + observer.reset(); + allObservers.push(observer); + return observer; +} + +var observer = createObserver(); +assertEquals("function", typeof observer.callback); +var obj = {}; + +function frozenFunction() {} +Object.freeze(frozenFunction); +var nonFunction = {}; +var changeRecordWithAccessor = { type: 'foo' }; +var recordCreated = false; +Object.defineProperty(changeRecordWithAccessor, 'name', { + get: function() { + recordCreated = true; + return "bar"; + }, + enumerable: true +}) + +// Object.observe +assertThrows(function() { Object.observe("non-object", observer.callback); }, TypeError); +assertThrows(function() { Object.observe(obj, nonFunction); }, TypeError); +assertThrows(function() { Object.observe(obj, frozenFunction); }, TypeError); +assertEquals(obj, Object.observe(obj, observer.callback)); + +// Object.unobserve +assertThrows(function() { Object.unobserve(4, observer.callback); }, TypeError); +assertThrows(function() { Object.unobserve(obj, nonFunction); }, TypeError); +assertEquals(obj, Object.unobserve(obj, observer.callback)); + +// Object.getNotifier +var notifier = Object.getNotifier(obj); +assertSame(notifier, Object.getNotifier(obj)); +assertEquals(null, Object.getNotifier(Object.freeze({}))); +assertFalse(notifier.hasOwnProperty('notify')); +assertEquals([], Object.keys(notifier)); +var notifyDesc = Object.getOwnPropertyDescriptor(notifier.__proto__, 'notify'); +assertTrue(notifyDesc.configurable); +assertTrue(notifyDesc.writable); +assertFalse(notifyDesc.enumerable); +assertThrows(function() { notifier.notify({}); }, TypeError); +assertThrows(function() { notifier.notify({ type: 4 }); }, TypeError); +var notify = notifier.notify; +assertThrows(function() { notify.call(undefined, { type: 'a' }); }, TypeError); +assertThrows(function() { notify.call(null, { type: 'a' }); }, TypeError); +assertThrows(function() { notify.call(5, { type: 'a' }); }, TypeError); +assertThrows(function() { notify.call('hello', { type: 'a' }); }, TypeError); +assertThrows(function() { notify.call(false, { type: 'a' }); }, TypeError); +assertThrows(function() { notify.call({}, { type: 'a' }); }, TypeError); +assertFalse(recordCreated); +notifier.notify(changeRecordWithAccessor); +assertFalse(recordCreated); // not observed yet + +// Object.deliverChangeRecords +assertThrows(function() { Object.deliverChangeRecords(nonFunction); }, TypeError); + +Object.observe(obj, observer.callback); + +// notify uses to [[CreateOwnProperty]] to create changeRecord; +reset(); +var protoExpandoAccessed = false; +Object.defineProperty(Object.prototype, 'protoExpando', + { + configurable: true, + set: function() { protoExpandoAccessed = true; } + } +); +notifier.notify({ type: 'foo', protoExpando: 'val'}); +assertFalse(protoExpandoAccessed); +delete Object.prototype.protoExpando; +Object.deliverChangeRecords(observer.callback); + +// Multiple records are delivered. +reset(); +notifier.notify({ + type: 'updated', + name: 'foo', + expando: 1 +}); + +notifier.notify({ + object: notifier, // object property is ignored + type: 'deleted', + name: 'bar', + expando2: 'str' +}); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: obj, name: 'foo', type: 'updated', expando: 1 }, + { object: obj, name: 'bar', type: 'deleted', expando2: 'str' } +]); + +// No delivery takes place if no records are pending +reset(); +Object.deliverChangeRecords(observer.callback); +observer.assertNotCalled(); + +// Multiple observation has no effect. +reset(); +Object.observe(obj, observer.callback); +Object.observe(obj, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo', +}); +Object.deliverChangeRecords(observer.callback); +observer.assertCalled(); + +// Observation can be stopped. +reset(); +Object.unobserve(obj, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo', +}); +Object.deliverChangeRecords(observer.callback); +observer.assertNotCalled(); + +// Multiple unobservation has no effect +reset(); +Object.unobserve(obj, observer.callback); +Object.unobserve(obj, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo', +}); +Object.deliverChangeRecords(observer.callback); +observer.assertNotCalled(); + +// Re-observation works and only includes changeRecords after of call. +reset(); +Object.getNotifier(obj).notify({ + type: 'foo', +}); +Object.observe(obj, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo', +}); +records = undefined; +Object.deliverChangeRecords(observer.callback); +observer.assertRecordCount(1); + +// Observing a continuous stream of changes, while itermittantly unobserving. +reset(); +Object.observe(obj, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo', + val: 1 +}); + +Object.unobserve(obj, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo', + val: 2 +}); + +Object.observe(obj, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo', + val: 3 +}); + +Object.unobserve(obj, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo', + val: 4 +}); + +Object.observe(obj, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo', + val: 5 +}); + +Object.unobserve(obj, observer.callback); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: obj, type: 'foo', val: 1 }, + { object: obj, type: 'foo', val: 3 }, + { object: obj, type: 'foo', val: 5 } +]); + +// Observing multiple objects; records appear in order. +reset(); +var obj2 = {}; +var obj3 = {} +Object.observe(obj, observer.callback); +Object.observe(obj3, observer.callback); +Object.observe(obj2, observer.callback); +Object.getNotifier(obj).notify({ + type: 'foo1', +}); +Object.getNotifier(obj2).notify({ + type: 'foo2', +}); +Object.getNotifier(obj3).notify({ + type: 'foo3', +}); +Object.observe(obj3, observer.callback); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: obj, type: 'foo1' }, + { object: obj2, type: 'foo2' }, + { object: obj3, type: 'foo3' } +]); + +// Observing named properties. +reset(); +var obj = {a: 1} +Object.observe(obj, observer.callback); +obj.a = 2; +obj["a"] = 3; +delete obj.a; +obj.a = 4; +obj.a = 4; // ignored +obj.a = 5; +Object.defineProperty(obj, "a", {value: 6}); +Object.defineProperty(obj, "a", {writable: false}); +obj.a = 7; // ignored +Object.defineProperty(obj, "a", {value: 8}); +Object.defineProperty(obj, "a", {value: 7, writable: true}); +Object.defineProperty(obj, "a", {get: function() {}}); +Object.defineProperty(obj, "a", {get: frozenFunction}); +Object.defineProperty(obj, "a", {get: frozenFunction}); // ignored +Object.defineProperty(obj, "a", {get: frozenFunction, set: frozenFunction}); +Object.defineProperty(obj, "a", {set: frozenFunction}); // ignored +Object.defineProperty(obj, "a", {get: undefined, set: frozenFunction}); +delete obj.a; +delete obj.a; +Object.defineProperty(obj, "a", {get: function() {}, configurable: true}); +Object.defineProperty(obj, "a", {value: 9, writable: true}); +obj.a = 10; +delete obj.a; +Object.defineProperty(obj, "a", {value: 11, configurable: true}); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: obj, name: "a", type: "updated", oldValue: 1 }, + { object: obj, name: "a", type: "updated", oldValue: 2 }, + { object: obj, name: "a", type: "deleted", oldValue: 3 }, + { object: obj, name: "a", type: "new" }, + { object: obj, name: "a", type: "updated", oldValue: 4 }, + { object: obj, name: "a", type: "updated", oldValue: 5 }, + { object: obj, name: "a", type: "reconfigured", oldValue: 6 }, + { object: obj, name: "a", type: "updated", oldValue: 6 }, + { object: obj, name: "a", type: "reconfigured", oldValue: 8 }, + { object: obj, name: "a", type: "reconfigured", oldValue: 7 }, + { object: obj, name: "a", type: "reconfigured" }, + { object: obj, name: "a", type: "reconfigured" }, + { object: obj, name: "a", type: "reconfigured" }, + { object: obj, name: "a", type: "deleted" }, + { object: obj, name: "a", type: "new" }, + { object: obj, name: "a", type: "reconfigured" }, + { object: obj, name: "a", type: "updated", oldValue: 9 }, + { object: obj, name: "a", type: "deleted", oldValue: 10 }, + { object: obj, name: "a", type: "new" }, +]); + +// Observing indexed properties. +reset(); +var obj = {'1': 1} +Object.observe(obj, observer.callback); +obj[1] = 2; +obj[1] = 3; +delete obj[1]; +obj[1] = 4; +obj[1] = 4; // ignored +obj[1] = 5; +Object.defineProperty(obj, "1", {value: 6}); +Object.defineProperty(obj, "1", {writable: false}); +obj[1] = 7; // ignored +Object.defineProperty(obj, "1", {value: 8}); +Object.defineProperty(obj, "1", {value: 7, writable: true}); +Object.defineProperty(obj, "1", {get: function() {}}); +Object.defineProperty(obj, "1", {get: frozenFunction}); +Object.defineProperty(obj, "1", {get: frozenFunction}); // ignored +Object.defineProperty(obj, "1", {get: frozenFunction, set: frozenFunction}); +Object.defineProperty(obj, "1", {set: frozenFunction}); // ignored +Object.defineProperty(obj, "1", {get: undefined, set: frozenFunction}); +delete obj[1]; +delete obj[1]; +Object.defineProperty(obj, "1", {get: function() {}, configurable: true}); +Object.defineProperty(obj, "1", {value: 9, writable: true}); +obj[1] = 10; +delete obj[1]; +Object.defineProperty(obj, "1", {value: 11, configurable: true}); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: obj, name: "1", type: "updated", oldValue: 1 }, + { object: obj, name: "1", type: "updated", oldValue: 2 }, + { object: obj, name: "1", type: "deleted", oldValue: 3 }, + { object: obj, name: "1", type: "new" }, + { object: obj, name: "1", type: "updated", oldValue: 4 }, + { object: obj, name: "1", type: "updated", oldValue: 5 }, + { object: obj, name: "1", type: "reconfigured", oldValue: 6 }, + { object: obj, name: "1", type: "updated", oldValue: 6 }, + { object: obj, name: "1", type: "reconfigured", oldValue: 8 }, + { object: obj, name: "1", type: "reconfigured", oldValue: 7 }, + { object: obj, name: "1", type: "reconfigured" }, + { object: obj, name: "1", type: "reconfigured" }, + { object: obj, name: "1", type: "reconfigured" }, + { object: obj, name: "1", type: "deleted" }, + { object: obj, name: "1", type: "new" }, + { object: obj, name: "1", type: "reconfigured" }, + { object: obj, name: "1", type: "updated", oldValue: 9 }, + { object: obj, name: "1", type: "deleted", oldValue: 10 }, + { object: obj, name: "1", type: "new" }, +]); + + +// Test all kinds of objects generically. +function TestObserveConfigurable(obj, prop) { + reset(); + obj[prop] = 1; + Object.observe(obj, observer.callback); + obj[prop] = 2; + obj[prop] = 3; + delete obj[prop]; + obj[prop] = 4; + obj[prop] = 4; // ignored + obj[prop] = 5; + Object.defineProperty(obj, prop, {value: 6}); + Object.defineProperty(obj, prop, {writable: false}); + obj[prop] = 7; // ignored + Object.defineProperty(obj, prop, {value: 8}); + Object.defineProperty(obj, prop, {value: 7, writable: true}); + Object.defineProperty(obj, prop, {get: function() {}}); + Object.defineProperty(obj, prop, {get: frozenFunction}); + Object.defineProperty(obj, prop, {get: frozenFunction}); // ignored + Object.defineProperty(obj, prop, {get: frozenFunction, set: frozenFunction}); + Object.defineProperty(obj, prop, {set: frozenFunction}); // ignored + Object.defineProperty(obj, prop, {get: undefined, set: frozenFunction}); + obj.__defineSetter__(prop, frozenFunction); // ignored + obj.__defineSetter__(prop, function() {}); + obj.__defineGetter__(prop, function() {}); + delete obj[prop]; + delete obj[prop]; // ignored + obj.__defineGetter__(prop, function() {}); + delete obj[prop]; + Object.defineProperty(obj, prop, {get: function() {}, configurable: true}); + Object.defineProperty(obj, prop, {value: 9, writable: true}); + obj[prop] = 10; + delete obj[prop]; + Object.defineProperty(obj, prop, {value: 11, configurable: true}); + Object.deliverChangeRecords(observer.callback); + observer.assertCallbackRecords([ + { object: obj, name: prop, type: "updated", oldValue: 1 }, + { object: obj, name: prop, type: "updated", oldValue: 2 }, + { object: obj, name: prop, type: "deleted", oldValue: 3 }, + { object: obj, name: prop, type: "new" }, + { object: obj, name: prop, type: "updated", oldValue: 4 }, + { object: obj, name: prop, type: "updated", oldValue: 5 }, + { object: obj, name: prop, type: "reconfigured", oldValue: 6 }, + { object: obj, name: prop, type: "updated", oldValue: 6 }, + { object: obj, name: prop, type: "reconfigured", oldValue: 8 }, + { object: obj, name: prop, type: "reconfigured", oldValue: 7 }, + { object: obj, name: prop, type: "reconfigured" }, + { object: obj, name: prop, type: "reconfigured" }, + { object: obj, name: prop, type: "reconfigured" }, + { object: obj, name: prop, type: "reconfigured" }, + { object: obj, name: prop, type: "reconfigured" }, + { object: obj, name: prop, type: "deleted" }, + { object: obj, name: prop, type: "new" }, + { object: obj, name: prop, type: "deleted" }, + { object: obj, name: prop, type: "new" }, + { object: obj, name: prop, type: "reconfigured" }, + { object: obj, name: prop, type: "updated", oldValue: 9 }, + { object: obj, name: prop, type: "deleted", oldValue: 10 }, + { object: obj, name: prop, type: "new" }, + ]); + Object.unobserve(obj, observer.callback); + delete obj[prop]; +} + +function TestObserveNonConfigurable(obj, prop, desc) { + reset(); + obj[prop] = 1; + Object.observe(obj, observer.callback); + obj[prop] = 4; + obj[prop] = 4; // ignored + obj[prop] = 5; + Object.defineProperty(obj, prop, {value: 6}); + Object.defineProperty(obj, prop, {value: 6}); // ignored + Object.defineProperty(obj, prop, {value: 7}); + Object.defineProperty(obj, prop, + {enumerable: desc.enumerable}); // ignored + Object.defineProperty(obj, prop, {writable: false}); + obj[prop] = 7; // ignored + Object.deliverChangeRecords(observer.callback); + observer.assertCallbackRecords([ + { object: obj, name: prop, type: "updated", oldValue: 1 }, + { object: obj, name: prop, type: "updated", oldValue: 4 }, + { object: obj, name: prop, type: "updated", oldValue: 5 }, + { object: obj, name: prop, type: "updated", oldValue: 6 }, + { object: obj, name: prop, type: "reconfigured", oldValue: 7 }, + ]); + Object.unobserve(obj, observer.callback); +} + +function createProxy(create, x) { + var handler = { + getPropertyDescriptor: function(k) { + for (var o = this.target; o; o = Object.getPrototypeOf(o)) { + var desc = Object.getOwnPropertyDescriptor(o, k); + if (desc) return desc; + } + return undefined; + }, + getOwnPropertyDescriptor: function(k) { + return Object.getOwnPropertyDescriptor(this.target, k); + }, + defineProperty: function(k, desc) { + var x = Object.defineProperty(this.target, k, desc); + Object.deliverChangeRecords(this.callback); + return x; + }, + delete: function(k) { + var x = delete this.target[k]; + Object.deliverChangeRecords(this.callback); + return x; + }, + getPropertyNames: function() { + return Object.getOwnPropertyNames(this.target); + }, + target: {isProxy: true}, + callback: function(changeRecords) { + print("callback", stringifyNoThrow(handler.proxy), stringifyNoThrow(got)); + for (var i in changeRecords) { + var got = changeRecords[i]; + var change = {object: handler.proxy, name: got.name, type: got.type}; + if ("oldValue" in got) change.oldValue = got.oldValue; + Object.getNotifier(handler.proxy).notify(change); + } + }, + }; + Object.observe(handler.target, handler.callback); + return handler.proxy = create(handler, x); +} + +var objects = [ + {}, + [], + this, // global object + function(){}, + (function(){ return arguments })(), + (function(){ "use strict"; return arguments })(), + Object(1), Object(true), Object("bla"), + new Date(), + Object, Function, Date, RegExp, + new Set, new Map, new WeakMap, + new ArrayBuffer(10), new Int32Array(5), + createProxy(Proxy.create, null), + createProxy(Proxy.createFunction, function(){}), +]; +var properties = ["a", "1", 1, "length", "prototype"]; + +// Cases that yield non-standard results. +// TODO(observe): ...or don't work yet. +function blacklisted(obj, prop) { + return (obj instanceof Int32Array && prop == 1) || + (obj instanceof Int32Array && prop === "length") || + (obj instanceof ArrayBuffer && prop == 1) || + // TODO(observe): oldValue when reconfiguring array length + (obj instanceof Array && prop === "length") +} + +for (var i in objects) for (var j in properties) { + var obj = objects[i]; + var prop = properties[j]; + if (blacklisted(obj, prop)) continue; + var desc = Object.getOwnPropertyDescriptor(obj, prop); + print("***", typeof obj, stringifyNoThrow(obj), prop); + if (!desc || desc.configurable) + TestObserveConfigurable(obj, prop); + else if (desc.writable) + TestObserveNonConfigurable(obj, prop, desc); +} + + +// Observing array length (including truncation) +reset(); +var arr = ['a', 'b', 'c', 'd']; +var arr2 = ['alpha', 'beta']; +var arr3 = ['hello']; +arr3[2] = 'goodbye'; +arr3.length = 6; +// TODO(adamk): Enable this test case when it can run in a reasonable +// amount of time. +//var slow_arr = new Array(1000000000); +//slow_arr[500000000] = 'hello'; +Object.defineProperty(arr, '0', {configurable: false}); +Object.defineProperty(arr, '2', {get: function(){}}); +Object.defineProperty(arr2, '0', {get: function(){}, configurable: false}); +Object.observe(arr, observer.callback); +Object.observe(arr2, observer.callback); +Object.observe(arr3, observer.callback); +arr.length = 2; +arr.length = 0; +arr.length = 10; +arr2.length = 0; +arr2.length = 1; // no change expected +arr3.length = 0; +Object.defineProperty(arr3, 'length', {value: 5}); +Object.defineProperty(arr3, 'length', {value: 10, writable: false}); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: arr, name: '3', type: 'deleted', oldValue: 'd' }, + { object: arr, name: '2', type: 'deleted' }, + { object: arr, name: 'length', type: 'updated', oldValue: 4 }, + { object: arr, name: '1', type: 'deleted', oldValue: 'b' }, + { object: arr, name: 'length', type: 'updated', oldValue: 2 }, + { object: arr, name: 'length', type: 'updated', oldValue: 1 }, + { object: arr2, name: '1', type: 'deleted', oldValue: 'beta' }, + { object: arr2, name: 'length', type: 'updated', oldValue: 2 }, + { object: arr3, name: '2', type: 'deleted', oldValue: 'goodbye' }, + { object: arr3, name: '0', type: 'deleted', oldValue: 'hello' }, + { object: arr3, name: 'length', type: 'updated', oldValue: 6 }, + { object: arr3, name: 'length', type: 'updated', oldValue: 0 }, + { object: arr3, name: 'length', type: 'updated', oldValue: 5 }, + // TODO(adamk): This record should be merged with the above + { object: arr3, name: 'length', type: 'reconfigured' }, +]); + +// Assignments in loops (checking different IC states). +reset(); +var obj = {}; +Object.observe(obj, observer.callback); +for (var i = 0; i < 5; i++) { + obj["a" + i] = i; +} +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: obj, name: "a0", type: "new" }, + { object: obj, name: "a1", type: "new" }, + { object: obj, name: "a2", type: "new" }, + { object: obj, name: "a3", type: "new" }, + { object: obj, name: "a4", type: "new" }, +]); + +reset(); +var obj = {}; +Object.observe(obj, observer.callback); +for (var i = 0; i < 5; i++) { + obj[i] = i; +} +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: obj, name: "0", type: "new" }, + { object: obj, name: "1", type: "new" }, + { object: obj, name: "2", type: "new" }, + { object: obj, name: "3", type: "new" }, + { object: obj, name: "4", type: "new" }, +]); + +// Adding elements past the end of an array should notify on length +reset(); +var arr = [1, 2, 3]; +Object.observe(arr, observer.callback); +arr[3] = 10; +arr[100] = 20; +Object.defineProperty(arr, '200', {value: 7}); +Object.defineProperty(arr, '400', {get: function(){}}); +arr[50] = 30; // no length change expected +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: arr, name: '3', type: 'new' }, + { object: arr, name: 'length', type: 'updated', oldValue: 3 }, + { object: arr, name: '100', type: 'new' }, + { object: arr, name: 'length', type: 'updated', oldValue: 4 }, + { object: arr, name: '200', type: 'new' }, + { object: arr, name: 'length', type: 'updated', oldValue: 101 }, + { object: arr, name: '400', type: 'new' }, + { object: arr, name: 'length', type: 'updated', oldValue: 201 }, + { object: arr, name: '50', type: 'new' }, +]); + +// Tests for array methods, first on arrays and then on plain objects +// +// === ARRAYS === +// +// Push +reset(); +var array = [1, 2]; +Object.observe(array, observer.callback); +array.push(3, 4); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '2', type: 'new' }, + { object: array, name: 'length', type: 'updated', oldValue: 2 }, + { object: array, name: '3', type: 'new' }, + { object: array, name: 'length', type: 'updated', oldValue: 3 }, +]); + +// Pop +reset(); +var array = [1, 2]; +Object.observe(array, observer.callback); +array.pop(); +array.pop(); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '1', type: 'deleted', oldValue: 2 }, + { object: array, name: 'length', type: 'updated', oldValue: 2 }, + { object: array, name: '0', type: 'deleted', oldValue: 1 }, + { object: array, name: 'length', type: 'updated', oldValue: 1 }, +]); + +// Shift +reset(); +var array = [1, 2]; +Object.observe(array, observer.callback); +array.shift(); +array.shift(); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '0', type: 'updated', oldValue: 1 }, + { object: array, name: '1', type: 'deleted', oldValue: 2 }, + { object: array, name: 'length', type: 'updated', oldValue: 2 }, + { object: array, name: '0', type: 'deleted', oldValue: 2 }, + { object: array, name: 'length', type: 'updated', oldValue: 1 }, +]); + +// Unshift +reset(); +var array = [1, 2]; +Object.observe(array, observer.callback); +array.unshift(3, 4); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '3', type: 'new' }, + { object: array, name: 'length', type: 'updated', oldValue: 2 }, + { object: array, name: '2', type: 'new' }, + { object: array, name: '0', type: 'updated', oldValue: 1 }, + { object: array, name: '1', type: 'updated', oldValue: 2 }, +]); + +// Splice +reset(); +var array = [1, 2, 3]; +Object.observe(array, observer.callback); +array.splice(1, 1, 4, 5); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '3', type: 'new' }, + { object: array, name: 'length', type: 'updated', oldValue: 3 }, + { object: array, name: '1', type: 'updated', oldValue: 2 }, + { object: array, name: '2', type: 'updated', oldValue: 3 }, +]); + +// +// === PLAIN OBJECTS === +// +// Push +reset() +var array = {0: 1, 1: 2, length: 2} +Object.observe(array, observer.callback); +Array.prototype.push.call(array, 3, 4); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '2', type: 'new' }, + { object: array, name: '3', type: 'new' }, + { object: array, name: 'length', type: 'updated', oldValue: 2 }, +]); + +// Pop +reset() +var array = {0: 1, 1: 2, length: 2}; +Object.observe(array, observer.callback); +Array.prototype.pop.call(array); +Array.prototype.pop.call(array); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '1', type: 'deleted', oldValue: 2 }, + { object: array, name: 'length', type: 'updated', oldValue: 2 }, + { object: array, name: '0', type: 'deleted', oldValue: 1 }, + { object: array, name: 'length', type: 'updated', oldValue: 1 }, +]); + +// Shift +reset() +var array = {0: 1, 1: 2, length: 2}; +Object.observe(array, observer.callback); +Array.prototype.shift.call(array); +Array.prototype.shift.call(array); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '0', type: 'updated', oldValue: 1 }, + { object: array, name: '1', type: 'deleted', oldValue: 2 }, + { object: array, name: 'length', type: 'updated', oldValue: 2 }, + { object: array, name: '0', type: 'deleted', oldValue: 2 }, + { object: array, name: 'length', type: 'updated', oldValue: 1 }, +]); + +// Unshift +reset() +var array = {0: 1, 1: 2, length: 2}; +Object.observe(array, observer.callback); +Array.prototype.unshift.call(array, 3, 4); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '3', type: 'new' }, + { object: array, name: '2', type: 'new' }, + { object: array, name: '0', type: 'updated', oldValue: 1 }, + { object: array, name: '1', type: 'updated', oldValue: 2 }, + { object: array, name: 'length', type: 'updated', oldValue: 2 }, +]); + +// Splice +reset() +var array = {0: 1, 1: 2, 2: 3, length: 3}; +Object.observe(array, observer.callback); +Array.prototype.splice.call(array, 1, 1, 4, 5); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '3', type: 'new' }, + { object: array, name: '1', type: 'updated', oldValue: 2 }, + { object: array, name: '2', type: 'updated', oldValue: 3 }, + { object: array, name: 'length', type: 'updated', oldValue: 3 }, +]); + +// Exercise StoreIC_ArrayLength +reset(); +var dummy = {}; +Object.observe(dummy, observer.callback); +Object.unobserve(dummy, observer.callback); +var array = [0]; +Object.observe(array, observer.callback); +array.splice(0, 1); +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: array, name: '0', type: 'deleted', oldValue: 0 }, + { object: array, name: 'length', type: 'updated', oldValue: 1}, +]); + + +// __proto__ +reset(); +var obj = {}; +Object.observe(obj, observer.callback); +var p = {foo: 'yes'}; +var q = {bar: 'no'}; +obj.__proto__ = p; +obj.__proto__ = p; // ignored +obj.__proto__ = null; +obj.__proto__ = q; +// TODO(adamk): Add tests for objects with hidden prototypes +// once we support observing the global object. +Object.deliverChangeRecords(observer.callback); +observer.assertCallbackRecords([ + { object: obj, name: '__proto__', type: 'prototype', + oldValue: Object.prototype }, + { object: obj, name: '__proto__', type: 'prototype', oldValue: p }, + { object: obj, name: '__proto__', type: 'prototype', oldValue: null }, +]); + +// Function.prototype +reset(); +var fun = function(){}; +Object.observe(fun, observer.callback); +var myproto = {foo: 'bar'}; +fun.prototype = myproto; +fun.prototype = 7; +fun.prototype = 7; // ignored +Object.defineProperty(fun, 'prototype', {value: 8}); +Object.deliverChangeRecords(observer.callback); +observer.assertRecordCount(3); +// Manually examine the first record in order to test +// lazy creation of oldValue +assertSame(fun, observer.records[0].object); +assertEquals('prototype', observer.records[0].name); +assertEquals('updated', observer.records[0].type); +// The only existing reference to the oldValue object is in this +// record, so to test that lazy creation happened correctly +// we compare its constructor to our function (one of the invariants +// ensured when creating an object via AllocateFunctionPrototype). +assertSame(fun, observer.records[0].oldValue.constructor); +observer.records.splice(0, 1); +observer.assertCallbackRecords([ + { object: fun, name: 'prototype', type: 'updated', oldValue: myproto }, + { object: fun, name: 'prototype', type: 'updated', oldValue: 7 }, +]); + +// Function.prototype should not be observable except on the object itself +reset(); +var fun = function(){}; +var obj = { __proto__: fun }; +Object.observe(obj, observer.callback); +obj.prototype = 7; +Object.deliverChangeRecords(observer.callback); +observer.assertNotCalled(); diff --git a/deps/v8/test/mjsunit/harmony/proxies-json.js b/deps/v8/test/mjsunit/harmony/proxies-json.js new file mode 100644 index 0000000000..539c5a84cb --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/proxies-json.js @@ -0,0 +1,178 @@ +// 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 + +function testStringify(expected, object) { + // Test fast case that bails out to slow case. + assertEquals(expected, JSON.stringify(object)); + // Test slow case. + assertEquals(expected, JSON.stringify(object, undefined, 0)); +} + +// Test serializing a proxy, function proxy and objects that contain them. +var handler1 = { + get: function(target, name) { + return name.toUpperCase(); + }, + enumerate: function(target) { + return ['a', 'b', 'c']; + }, + getOwnPropertyDescriptor: function(target, name) { + return { enumerable: true }; + } +} + +var proxy1 = Proxy.create(handler1); +testStringify('{"a":"A","b":"B","c":"C"}', proxy1); + +var proxy_fun = Proxy.createFunction(handler1, function() { return 1; }); +testStringify(undefined, proxy_fun); +testStringify('[1,null]', [1, proxy_fun]); + +var parent1a = { b: proxy1 }; +testStringify('{"b":{"a":"A","b":"B","c":"C"}}', parent1a); + +var parent1b = { a: 123, b: proxy1, c: true }; +testStringify('{"a":123,"b":{"a":"A","b":"B","c":"C"},"c":true}', parent1b); + +var parent1c = [123, proxy1, true]; +testStringify('[123,{"a":"A","b":"B","c":"C"},true]', parent1c); + +// Proxy with side effect. +var handler2 = { + get: function(target, name) { + delete parent2.c; + return name.toUpperCase(); + }, + enumerate: function(target) { + return ['a', 'b', 'c']; + }, + getOwnPropertyDescriptor: function(target, name) { + return { enumerable: true }; + } +} + +var proxy2 = Proxy.create(handler2); +var parent2 = { a: "delete", b: proxy2, c: "remove" }; +var expected2 = '{"a":"delete","b":{"a":"A","b":"B","c":"C"}}'; +assertEquals(expected2, JSON.stringify(parent2)); +parent2.c = "remove"; // Revert side effect. +assertEquals(expected2, JSON.stringify(parent2, undefined, 0)); + +// Proxy with a get function that uses the first argument. +var handler3 = { + get: function(target, name) { + if (name == 'valueOf') return function() { return "proxy" }; + return name + "(" + target + ")"; + }, + enumerate: function(target) { + return ['a', 'b', 'c']; + }, + getOwnPropertyDescriptor: function(target, name) { + return { enumerable: true }; + } +} + +var proxy3 = Proxy.create(handler3); +var parent3 = { x: 123, y: proxy3 } +testStringify('{"x":123,"y":{"a":"a(proxy)","b":"b(proxy)","c":"c(proxy)"}}', + parent3); + +// Empty proxy. +var handler4 = { + get: function(target, name) { + return 0; + }, + enumerate: function(target) { + return []; + }, + getOwnPropertyDescriptor: function(target, name) { + return { enumerable: false }; + } +} + +var proxy4 = Proxy.create(handler4); +testStringify('{}', proxy4); +testStringify('{"a":{}}', { a: proxy4 }); + +// Proxy that provides a toJSON function that uses this. +var handler5 = { + get: function(target, name) { + if (name == 'z') return 97000; + return function(key) { return key.charCodeAt(0) + this.z; }; + }, + enumerate: function(target) { + return ['toJSON', 'z']; + }, + getOwnPropertyDescriptor: function(target, name) { + return { enumerable: true }; + } +} + +var proxy5 = Proxy.create(handler5); +testStringify('{"a":97097}', { a: proxy5 }); + +// Proxy that provides a toJSON function that returns undefined. +var handler6 = { + get: function(target, name) { + return function(key) { return undefined; }; + }, + enumerate: function(target) { + return ['toJSON']; + }, + getOwnPropertyDescriptor: function(target, name) { + return { enumerable: true }; + } +} + +var proxy6 = Proxy.create(handler6); +testStringify('[1,null,true]', [1, proxy6, true]); +testStringify('{"a":1,"c":true}', {a: 1, b: proxy6, c: true}); + +// Object containing a proxy that changes the parent's properties. +var handler7 = { + get: function(target, name) { + delete parent7.a; + delete parent7.c; + parent7.e = "5"; + return name.toUpperCase(); + }, + enumerate: function(target) { + return ['a', 'b', 'c']; + }, + getOwnPropertyDescriptor: function(target, name) { + return { enumerable: true }; + } +} + +var proxy7 = Proxy.create(handler7); +var parent7 = { a: "1", b: proxy7, c: "3", d: "4" }; +assertEquals('{"a":"1","b":{"a":"A","b":"B","c":"C"},"d":"4"}', + JSON.stringify(parent7)); +assertEquals('{"b":{"a":"A","b":"B","c":"C"},"d":"4","e":"5"}', + JSON.stringify(parent7)); diff --git a/deps/v8/test/mjsunit/harmony/proxies.js b/deps/v8/test/mjsunit/harmony/proxies.js index 7170ffd9c7..04fc76949e 100644 --- a/deps/v8/test/mjsunit/harmony/proxies.js +++ b/deps/v8/test/mjsunit/harmony/proxies.js @@ -649,6 +649,11 @@ function TestSetForDerived2(create, trap) { TestSetForDerived( function(k) { + // TODO(yangguo): issue 2398 - throwing an error causes formatting of + // the message string, which can be observable through this handler. + // We ignore keys that occur when formatting the message string. + if (k == "toString" || k == "valueOf") return; + key = k; switch (k) { case "p_writable": return {writable: true, configurable: true} diff --git a/deps/v8/test/mjsunit/json-parser-recursive.js b/deps/v8/test/mjsunit/json-parser-recursive.js new file mode 100644 index 0000000000..1e00c83c87 --- /dev/null +++ b/deps/v8/test/mjsunit/json-parser-recursive.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. + +var str = "[1]"; +for (var i = 0; i < 100000; i++) { + str = "[1," + str + "]"; +} + +assertThrows(function() { JSON.parse(str); }, RangeError); diff --git a/deps/v8/test/mjsunit/json-stringify-recursive.js b/deps/v8/test/mjsunit/json-stringify-recursive.js new file mode 100644 index 0000000000..31aa0027c5 --- /dev/null +++ b/deps/v8/test/mjsunit/json-stringify-recursive.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. + +var a = {}; +for (i = 0; i < 10000; i++) { + var current = {}; + current.a = a; + a = current; +} + +function rec(a,b,c,d,e,f,g,h,i,j,k,l,m,n) { + JSON.stringify(a); + rec(a,b,c,d,e,f,g,h,i,j,k,l,m,n); +} + +assertThrows(function() { rec(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4) }, + RangeError); + + +var depth = 10000; +var deepArray = []; +for (var i = 0; i < depth; i++) deepArray = [deepArray]; +assertThrows(function() { JSON.stringify(deepArray); }, RangeError); + + +var deepObject = {}; +for (var i = 0; i < depth; i++) deepObject = { next: deepObject }; +assertThrows(function() { JSON.stringify(deepObject); }, RangeError); diff --git a/deps/v8/test/mjsunit/json.js b/deps/v8/test/mjsunit/json.js index bead376f84..6e91725c7d 100644 --- a/deps/v8/test/mjsunit/json.js +++ b/deps/v8/test/mjsunit/json.js @@ -257,6 +257,42 @@ assertEquals("[1,2,[3,[4],5],6,7]", assertEquals("[2,4,[6,[8],10],12,14]", JSON.stringify([1, 2, [3, [4], 5], 6, 7], DoubleNumbers)); assertEquals('["a","ab","abc"]', JSON.stringify(["a","ab","abc"])); +assertEquals('{"a":1,"c":true}', + JSON.stringify({ a : 1, + b : function() { 1 }, + c : true, + d : function() { 2 } })); +assertEquals('[1,null,true,null]', + JSON.stringify([1, function() { 1 }, true, function() { 2 }])); +assertEquals('"toJSON 123"', + JSON.stringify({ toJSON : function() { return 'toJSON 123'; } })); +assertEquals('{"a":321}', + JSON.stringify({ a : { toJSON : function() { return 321; } } })); +var counter = 0; +assertEquals('{"getter":123}', + JSON.stringify({ get getter() { counter++; return 123; } })); +assertEquals(1, counter); +assertEquals('{"a":"abc","b":"\u1234bc"}', + JSON.stringify({ a : "abc", b : "\u1234bc" })); + + +var a = { a : 1, b : 2 }; +delete a.a; +assertEquals('{"b":2}', JSON.stringify(a)); + +var b = {}; +b.__proto__ = { toJSON : function() { return 321;} }; +assertEquals("321", JSON.stringify(b)); + +var array = [""]; +var expected = '""'; +for (var i = 0; i < 10000; i++) { + array.push(""); + expected = '"",' + expected; +} +expected = '[' + expected + ']'; +assertEquals(expected, JSON.stringify(array)); + var circular = [1, 2, 3]; circular[2] = circular; @@ -428,5 +464,5 @@ var o = JSON.parse('{"__proto__":5}'); assertEquals(Object.prototype, o.__proto__); // __proto__ isn't changed. assertEquals(0, Object.keys(o).length); // __proto__ isn't added as enumerable. - - +var json = '{"stuff before slash\\\\stuff after slash":"whatever"}'; +assertEquals(json, JSON.stringify(JSON.parse(json))); diff --git a/deps/v8/test/mjsunit/json2.js b/deps/v8/test/mjsunit/json2.js new file mode 100644 index 0000000000..4c0b8f58c8 --- /dev/null +++ b/deps/v8/test/mjsunit/json2.js @@ -0,0 +1,153 @@ +// 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 JSON.stringify on the global object. +var a = 12345; +assertTrue(JSON.stringify(this).indexOf('"a":12345') > 0); + +// Test JSON.stringify of array in dictionary mode. +var array_1 = []; +var array_2 = []; +array_1[100000] = 1; +array_2[100000] = function() { return 1; }; +var nulls = ""; +for (var i = 0; i < 100000; i++) { + nulls += 'null,'; +} +expected_1 = '[' + nulls + '1]'; +expected_2 = '[' + nulls + 'null]'; +assertEquals(expected_1, JSON.stringify(array_1)); +assertEquals(expected_2, JSON.stringify(array_2)); + +// Test JSValue with custom prototype. +var num_wrapper = Object(42); +num_wrapper.__proto__ = { __proto__: null, + toString: function() { return true; } }; +assertEquals('1', JSON.stringify(num_wrapper)); + +var str_wrapper = Object('2'); +str_wrapper.__proto__ = { __proto__: null, + toString: function() { return true; } }; +assertEquals('"true"', JSON.stringify(str_wrapper)); + +var bool_wrapper = Object(false); +bool_wrapper.__proto__ = { __proto__: null, + toString: function() { return true; } }; +// Note that toString function is not evaluated here! +assertEquals('false', JSON.stringify(bool_wrapper)); + +// Test getters. +var counter = 0; +var getter_obj = { get getter() { + counter++; + return 123; + } }; +assertEquals('{"getter":123}', JSON.stringify(getter_obj)); +assertEquals(1, counter); + +// Test toJSON function. +var tojson_obj = { toJSON: function() { + counter++; + return [1, 2]; + }, + a: 1}; +assertEquals('[1,2]', JSON.stringify(tojson_obj)); +assertEquals(2, counter); + +// Test that we don't recursively look for the toJSON function. +var tojson_proto_obj = { a: 'fail' }; +tojson_proto_obj.__proto__ = { toJSON: function() { + counter++; + return tojson_obj; + } }; +assertEquals('{"a":1}', JSON.stringify(tojson_proto_obj)); + +// Test toJSON produced by a getter. +var tojson_via_getter = { get toJSON() { + return function(x) { + counter++; + return 321; + }; + }, + a: 1 }; +assertEquals('321', JSON.stringify(tojson_via_getter)); + +// Test toJSON with key. +tojson_obj = { toJSON: function(key) { return key + key; } }; +var tojson_with_key_1 = { a: tojson_obj, b: tojson_obj }; +assertEquals('{"a":"aa","b":"bb"}', JSON.stringify(tojson_with_key_1)); +var tojson_with_key_2 = [ tojson_obj, tojson_obj ]; +assertEquals('["00","11"]', JSON.stringify(tojson_with_key_2)); + +// Test toJSON with exception. +var tojson_ex = { toJSON: function(key) { throw "123" } }; +assertThrows(function() { JSON.stringify(tojson_ex); }); + +// Test toJSON with access to this. +var obj = { toJSON: function(key) { return this.a + key; }, a: "x" }; +assertEquals('{"y":"xy"}', JSON.stringify({y: obj})); + +// Test holes in arrays. +var fast_smi = [1, 2, 3, 4]; +fast_smi.__proto__ = [7, 7, 7, 7]; +delete fast_smi[2]; +assertTrue(%HasFastSmiElements(fast_smi)); +assertEquals("[1,2,7,4]", JSON.stringify(fast_smi)); + +var fast_double = [1.1, 2, 3, 4]; +fast_double.__proto__ = [7, 7, 7, 7]; + +delete fast_double[2]; +assertTrue(%HasFastDoubleElements(fast_double)); +assertEquals("[1.1,2,7,4]", JSON.stringify(fast_double)); + +var fast_obj = [1, 2, {}, {}]; +fast_obj.__proto__ = [7, 7, 7, 7]; + +delete fast_obj[2]; +assertTrue(%HasFastObjectElements(fast_obj)); +assertEquals("[1,2,7,{}]", JSON.stringify(fast_obj)); + +var getter_side_effect = { a: 1, + get b() { + delete this.a; + delete this.c; + this.e = 5; + return 2; + }, + c: 3, + d: 4 }; +assertEquals('{"a":1,"b":2,"d":4}', JSON.stringify(getter_side_effect)); +assertEquals('{"b":2,"d":4,"e":5}', JSON.stringify(getter_side_effect)); + +var non_enum = {}; +non_enum.a = 1; +Object.defineProperty(non_enum, "b", { value: 2, enumerable: false }); +non_enum.c = 3; +assertEquals('{"a":1,"c":3}', JSON.stringify(non_enum)); diff --git a/deps/v8/test/mjsunit/limit-locals.js b/deps/v8/test/mjsunit/limit-locals.js index 22f895c714..a166f30617 100644 --- a/deps/v8/test/mjsunit/limit-locals.js +++ b/deps/v8/test/mjsunit/limit-locals.js @@ -25,7 +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. -// Test that there is a limit of 65535 locals. +// Test that there is a limit of 131071 locals. + +// Flags: --stack-size=1200 function function_with_n_locals(n) { test_prefix = "prefix "; @@ -40,8 +42,6 @@ function function_with_n_locals(n) { assertEquals("prefix 0 suffix", function_with_n_locals(0)); assertEquals("prefix 16000 suffix", function_with_n_locals(16000)); -assertEquals("prefix 32767 suffix", function_with_n_locals(32767)); -assertEquals("prefix 65535 suffix", function_with_n_locals(65535)); +assertEquals("prefix 131071 suffix", function_with_n_locals(131071)); -assertThrows("function_with_n_locals(65536)"); -assertThrows("function_with_n_locals(100000)"); +assertThrows("function_with_n_locals(131072)"); diff --git a/deps/v8/test/mjsunit/manual-parallel-recompile.js b/deps/v8/test/mjsunit/manual-parallel-recompile.js new file mode 100644 index 0000000000..26b160537b --- /dev/null +++ b/deps/v8/test/mjsunit/manual-parallel-recompile.js @@ -0,0 +1,79 @@ +// 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 +// Flags: --parallel-recompilation --manual-parallel-recompilation + +function assertOptimized(fun) { + // This assertion takes --always-opt and --nocrankshaft flags into account. + assertTrue(%GetOptimizationStatus(fun) != 2); +} + +function assertUnoptimized(fun) { + assertTrue(%GetOptimizationStatus(fun) != 1); +} + +function f(x) { + var xx = x * x; + var xxstr = xx.toString(); + return xxstr.length; +} + +function g(x) { + var xxx = Math.sqrt(x) | 0; + var xxxstr = xxx.toString(); + return xxxstr.length; +} + +function k(x) { + return x * x; +} + +f(g(1)); +f(g(2)); +assertUnoptimized(f); +assertUnoptimized(g); + +%ForceParallelRecompile(f); +%ForceParallelRecompile(g); +assertUnoptimized(f); +assertUnoptimized(g); + +var sum = 0; +for (var i = 0; i < 10000; i++) sum += f(i) + g(i); +gc(); + +assertEquals(95274, sum); +assertUnoptimized(f); +assertUnoptimized(g); + +%InstallRecompiledCode(f); +assertOptimized(f); +assertUnoptimized(g); + +%InstallRecompiledCode(g); +assertOptimized(g); diff --git a/deps/v8/test/mjsunit/math-exp-precision.js b/deps/v8/test/mjsunit/math-exp-precision.js new file mode 100644 index 0000000000..ace7edc58c --- /dev/null +++ b/deps/v8/test/mjsunit/math-exp-precision.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. + +// Tests that the --fast-math implementation of Math.exp() has +// reasonable precision. + +function exp(x) { + return Math.exp(x); +} + +var first_call_result = exp(Math.PI); +var second_call_result = exp(Math.PI); + +function assertAlmostEquals(expected, actual, x) { + if (expected == 0 && actual == 0) return; // OK + if (expected == Number.POSITIVE_INFINITY && + actual == Number.POSITIVE_INFINITY) { + return; // OK + } + relative_diff = Math.abs(expected/actual - 1); + assertTrue(relative_diff < 1e-12, "relative difference of " + relative_diff + + " for input " + x); +} + +var increment = Math.PI / 35; // Roughly 0.1, but we want to try many + // different mantissae. +for (var x = -708; x < 710; x += increment) { + var ex = exp(x); + var reference = Math.pow(Math.E, x); + assertAlmostEquals(reference, ex, x); + if (ex > 0 && isFinite(ex)) { + var back = Math.log(ex); + assertAlmostEquals(x, back, x + " (backwards)"); + } +} + +// Make sure optimizing the function does not alter the result. +var last_call_result = exp(Math.PI); +assertEquals(first_call_result, second_call_result); +assertEquals(first_call_result, last_call_result); diff --git a/deps/v8/test/mjsunit/math-floor-of-div-minus-zero.js b/deps/v8/test/mjsunit/math-floor-of-div-minus-zero.js index 2743490847..7349165854 100644 --- a/deps/v8/test/mjsunit/math-floor-of-div-minus-zero.js +++ b/deps/v8/test/mjsunit/math-floor-of-div-minus-zero.js @@ -35,6 +35,7 @@ function test_div_no_deopt_minus_zero() { } test_div_no_deopt_minus_zero(); +test_div_no_deopt_minus_zero(); %OptimizeFunctionOnNextCall(test_div_no_deopt_minus_zero); test_div_no_deopt_minus_zero(); assertTrue(2 != %GetOptimizationStatus(test_div_no_deopt_minus_zero)); diff --git a/deps/v8/test/mjsunit/math-floor.js b/deps/v8/test/mjsunit/math-floor-part1.js index f211ce2e56..313f27236a 100644 --- a/deps/v8/test/mjsunit/math-floor.js +++ b/deps/v8/test/mjsunit/math-floor-part1.js @@ -45,13 +45,6 @@ function zero() { } function test() { - testFloor(0, 0); - testFloor(0, zero()); - testFloor(-0, -0); - testFloor(Infinity, Infinity); - testFloor(-Infinity, -Infinity); - testFloor(NaN, NaN); - // Ensure that a negative zero coming from Math.floor is properly handled // by other operations. function ifloor(x) { @@ -86,74 +79,10 @@ function test() { testFloor(-Number.MAX_VALUE, -Number.MAX_VALUE); testFloor(Infinity, Infinity); testFloor(-Infinity, -Infinity); - - // 2^30 is a smi boundary. - var two_30 = 1 << 30; - - testFloor(two_30, two_30); - testFloor(two_30, two_30 + 0.1); - testFloor(two_30, two_30 + 0.5); - testFloor(two_30, two_30 + 0.7); - - testFloor(two_30 - 1, two_30 - 1); - testFloor(two_30 - 1, two_30 - 1 + 0.1); - testFloor(two_30 - 1, two_30 - 1 + 0.5); - testFloor(two_30 - 1, two_30 - 1 + 0.7); - - testFloor(-two_30, -two_30); - testFloor(-two_30, -two_30 + 0.1); - testFloor(-two_30, -two_30 + 0.5); - testFloor(-two_30, -two_30 + 0.7); - - testFloor(-two_30 + 1, -two_30 + 1); - testFloor(-two_30 + 1, -two_30 + 1 + 0.1); - testFloor(-two_30 + 1, -two_30 + 1 + 0.5); - testFloor(-two_30 + 1, -two_30 + 1 + 0.7); - - // 2^52 is a precision boundary. - var two_52 = (1 << 30) * (1 << 22); - - testFloor(two_52, two_52); - testFloor(two_52, two_52 + 0.1); - assertEquals(two_52, two_52 + 0.5); - testFloor(two_52, two_52 + 0.5); - assertEquals(two_52 + 1, two_52 + 0.7); - testFloor(two_52 + 1, two_52 + 0.7); - - testFloor(two_52 - 1, two_52 - 1); - testFloor(two_52 - 1, two_52 - 1 + 0.1); - testFloor(two_52 - 1, two_52 - 1 + 0.5); - testFloor(two_52 - 1, two_52 - 1 + 0.7); - - testFloor(-two_52, -two_52); - testFloor(-two_52, -two_52 + 0.1); - testFloor(-two_52, -two_52 + 0.5); - testFloor(-two_52, -two_52 + 0.7); - - testFloor(-two_52 + 1, -two_52 + 1); - testFloor(-two_52 + 1, -two_52 + 1 + 0.1); - testFloor(-two_52 + 1, -two_52 + 1 + 0.5); - testFloor(-two_52 + 1, -two_52 + 1 + 0.7); } // Test in a loop to cover the custom IC and GC-related issues. -for (var i = 0; i < 500; i++) { +for (var i = 0; i < 100; i++) { test(); } - - -// Regression test for a bug where a negative zero coming from Math.floor -// was not properly handled by other operations. -function floorsum(i, n) { - var ret = Math.floor(n); - while (--i > 0) { - ret += Math.floor(n); - } - return ret; -} -assertEquals(-0, floorsum(1, -0)); -%OptimizeFunctionOnNextCall(floorsum); -// The optimized function will deopt. Run it with enough iterations to try -// to optimize via OSR (triggering the bug). -assertEquals(-0, floorsum(100000, -0)); diff --git a/deps/v8/test/mjsunit/math-floor-part2.js b/deps/v8/test/mjsunit/math-floor-part2.js new file mode 100644 index 0000000000..b6d51b2bde --- /dev/null +++ b/deps/v8/test/mjsunit/math-floor-part2.js @@ -0,0 +1,76 @@ +// 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: --max-new-space-size=256 --allow-natives-syntax + +var test_id = 0; + +function testFloor(expect, input) { + var test = new Function('n', + '"' + (test_id++) + '";return Math.floor(n)'); + assertEquals(expect, test(input)); + assertEquals(expect, test(input)); + assertEquals(expect, test(input)); + %OptimizeFunctionOnNextCall(test); + assertEquals(expect, test(input)); +} + +function zero() { + var x = 0.5; + return (function() { return x - 0.5; })(); +} + +function test() { + // 2^30 is a smi boundary. + var two_30 = 1 << 30; + + testFloor(two_30, two_30); + testFloor(two_30, two_30 + 0.1); + testFloor(two_30, two_30 + 0.5); + testFloor(two_30, two_30 + 0.7); + + testFloor(two_30 - 1, two_30 - 1); + testFloor(two_30 - 1, two_30 - 1 + 0.1); + testFloor(two_30 - 1, two_30 - 1 + 0.5); + testFloor(two_30 - 1, two_30 - 1 + 0.7); + + testFloor(-two_30, -two_30); + testFloor(-two_30, -two_30 + 0.1); + testFloor(-two_30, -two_30 + 0.5); + testFloor(-two_30, -two_30 + 0.7); + + testFloor(-two_30 + 1, -two_30 + 1); + testFloor(-two_30 + 1, -two_30 + 1 + 0.1); + testFloor(-two_30 + 1, -two_30 + 1 + 0.5); + testFloor(-two_30 + 1, -two_30 + 1 + 0.7); +} + + +// Test in a loop to cover the custom IC and GC-related issues. +for (var i = 0; i < 100; i++) { + test(); +} diff --git a/deps/v8/test/mjsunit/math-floor-part3.js b/deps/v8/test/mjsunit/math-floor-part3.js new file mode 100644 index 0000000000..db25923433 --- /dev/null +++ b/deps/v8/test/mjsunit/math-floor-part3.js @@ -0,0 +1,78 @@ +// 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: --max-new-space-size=256 --allow-natives-syntax + +var test_id = 0; + +function testFloor(expect, input) { + var test = new Function('n', + '"' + (test_id++) + '";return Math.floor(n)'); + assertEquals(expect, test(input)); + assertEquals(expect, test(input)); + assertEquals(expect, test(input)); + %OptimizeFunctionOnNextCall(test); + assertEquals(expect, test(input)); +} + +function zero() { + var x = 0.5; + return (function() { return x - 0.5; })(); +} + +function test() { + // 2^52 is a precision boundary. + var two_52 = (1 << 30) * (1 << 22); + + testFloor(two_52, two_52); + testFloor(two_52, two_52 + 0.1); + assertEquals(two_52, two_52 + 0.5); + testFloor(two_52, two_52 + 0.5); + assertEquals(two_52 + 1, two_52 + 0.7); + testFloor(two_52 + 1, two_52 + 0.7); + + testFloor(two_52 - 1, two_52 - 1); + testFloor(two_52 - 1, two_52 - 1 + 0.1); + testFloor(two_52 - 1, two_52 - 1 + 0.5); + testFloor(two_52 - 1, two_52 - 1 + 0.7); + + testFloor(-two_52, -two_52); + testFloor(-two_52, -two_52 + 0.1); + testFloor(-two_52, -two_52 + 0.5); + testFloor(-two_52, -two_52 + 0.7); + + testFloor(-two_52 + 1, -two_52 + 1); + testFloor(-two_52 + 1, -two_52 + 1 + 0.1); + testFloor(-two_52 + 1, -two_52 + 1 + 0.5); + testFloor(-two_52 + 1, -two_52 + 1 + 0.7); +} + + +// Test in a loop to cover the custom IC and GC-related issues. +for (var i = 0; i < 100; i++) { + test(); +} diff --git a/deps/v8/test/mjsunit/math-floor-part4.js b/deps/v8/test/mjsunit/math-floor-part4.js new file mode 100644 index 0000000000..c633623083 --- /dev/null +++ b/deps/v8/test/mjsunit/math-floor-part4.js @@ -0,0 +1,76 @@ +// 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: --max-new-space-size=256 --allow-natives-syntax + +var test_id = 0; + +function testFloor(expect, input) { + var test = new Function('n', + '"' + (test_id++) + '";return Math.floor(n)'); + assertEquals(expect, test(input)); + assertEquals(expect, test(input)); + assertEquals(expect, test(input)); + %OptimizeFunctionOnNextCall(test); + assertEquals(expect, test(input)); +} + +function zero() { + var x = 0.5; + return (function() { return x - 0.5; })(); +} + +function test() { + testFloor(0, 0); + testFloor(0, zero()); + testFloor(-0, -0); + testFloor(Infinity, Infinity); + testFloor(-Infinity, -Infinity); + testFloor(NaN, NaN); +} + + +// Test in a loop to cover the custom IC and GC-related issues. +for (var i = 0; i < 100; i++) { + test(); +} + + +// Regression test for a bug where a negative zero coming from Math.floor +// was not properly handled by other operations. +function floorsum(i, n) { + var ret = Math.floor(n); + while (--i > 0) { + ret += Math.floor(n); + } + return ret; +} +assertEquals(-0, floorsum(1, -0)); +%OptimizeFunctionOnNextCall(floorsum); +// The optimized function will deopt. Run it with enough iterations to try +// to optimize via OSR (triggering the bug). +assertEquals(-0, floorsum(100000, -0)); diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index 357b33bf08..0bf378b476 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -44,12 +44,13 @@ regress/regress-524: SKIP # Too slow in debug mode with --stress-opt compiler/regress-stacktrace-methods: PASS, SKIP if $mode == debug compiler/regress-funcaller: PASS, SKIP if $mode == debug +regress/regress-2318: PASS, SKIP if $mode == debug regress/regress-create-exception: PASS, SKIP if $mode == debug ############################################################################## -# This one uses a built-in that's only present in debug mode. It takes +# These use a built-in that's only present in debug mode. They take # too long to run in debug mode on ARM and MIPS. -fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm || $arch == android_arm || $arch == mipsel) +fuzz-natives-part*: PASS, SKIP if ($mode == release || $arch == arm || $arch == android_arm || $arch == mipsel) big-object-literal: PASS, SKIP if ($arch == arm || $arch == android_arm) @@ -59,8 +60,14 @@ array-constructor: PASS || TIMEOUT # Very slow on ARM and MIPS, contains no architecture dependent code. unicode-case-overoptimization: PASS, TIMEOUT if ($arch == arm || $arch == android_arm || $arch == mipsel) -# Test Crankshaft compilation time. Expected to take too long in debug mode. -regress/regress-1969: PASS, SKIP if ($mode == debug || $arch == android_arm) +############################################################################## +# This test expects to reach a certain recursion depth, which may not work +# for debug mode. +json-recursive: PASS, (PASS || FAIL) if $mode == debug + +############################################################################## +# Skip long running test that times out in debug mode. +regress/regress-crbug-160010: PASS, SKIP if $mode == debug ############################################################################## # This test sets the umask on a per-process basis and hence cannot be @@ -76,6 +83,7 @@ tools/tickprocessor: PASS, SKIP if ($arch == android_arm || $arch == android_ia3 try: PASS, SKIP if $mode == debug debug-scripts-request: PASS, SKIP if $mode == debug array-constructor: PASS, SKIP if $mode == debug +regress/regress-1122: PASS, SKIP if ($mode == debug && $arch == android_arm) # Flaky test that can hit compilation-time stack overflow in debug mode. unicode-test: PASS, (PASS || FAIL) if $mode == debug @@ -103,11 +111,9 @@ compiler/property-calls: SKIP compiler/recursive-deopt: SKIP compiler/regress-4: SKIP compiler/regress-funcaller: SKIP -compiler/regress-gvn: SKIP compiler/regress-rep-change: SKIP compiler/regress-arguments: SKIP compiler/regress-funarguments: SKIP -compiler/regress-or: SKIP compiler/regress-3249650: SKIP compiler/simple-deopt: SKIP regress/regress-490: SKIP @@ -161,11 +167,9 @@ compiler/property-calls: SKIP compiler/recursive-deopt: SKIP compiler/regress-4: SKIP compiler/regress-funcaller: SKIP -compiler/regress-gvn: SKIP compiler/regress-rep-change: SKIP compiler/regress-arguments: SKIP compiler/regress-funarguments: SKIP -compiler/regress-or: SKIP compiler/regress-3249650: SKIP compiler/simple-deopt: SKIP regress/regress-490: SKIP diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part1.js b/deps/v8/test/mjsunit/mul-exhaustive-part1.js new file mode 100644 index 0000000000..7902cc2e67 --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part1.js @@ -0,0 +1,491 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 0; +f(0, 0); +x = 1; +f(0, 0); +f(1, 1); +x = 2; +f(0, 0); +f(2, 1); +f(4, 2); +x = 3; +f(0, 0); +f(3, 1); +f(6, 2); +f(9, 3); +x = 4; +f(0, 0); +f(4, 1); +f(8, 2); +f(12, 3); +f(16, 4); +x = 5; +f(0, 0); +f(5, 1); +f(10, 2); +f(15, 3); +f(20, 4); +f(25, 5); +x = 7; +f(0, 0); +f(7, 1); +f(14, 2); +f(21, 3); +f(28, 4); +f(35, 5); +f(49, 7); +x = 8; +f(0, 0); +f(8, 1); +f(16, 2); +f(24, 3); +f(32, 4); +f(40, 5); +f(56, 7); +f(64, 8); +x = 9; +f(0, 0); +f(9, 1); +f(18, 2); +f(27, 3); +f(36, 4); +f(45, 5); +f(63, 7); +f(72, 8); +f(81, 9); +x = 15; +f(0, 0); +f(15, 1); +f(30, 2); +f(45, 3); +f(60, 4); +f(75, 5); +f(105, 7); +f(120, 8); +f(135, 9); +f(225, 15); +x = 16; +f(0, 0); +f(16, 1); +f(32, 2); +f(48, 3); +f(64, 4); +f(80, 5); +f(112, 7); +f(128, 8); +f(144, 9); +f(240, 15); +f(256, 16); +x = 17; +f(0, 0); +f(17, 1); +f(34, 2); +f(51, 3); +f(68, 4); +f(85, 5); +f(119, 7); +f(136, 8); +f(153, 9); +f(255, 15); +f(272, 16); +f(289, 17); +x = 31; +f(0, 0); +f(31, 1); +f(62, 2); +f(93, 3); +f(124, 4); +f(155, 5); +f(217, 7); +f(248, 8); +f(279, 9); +f(465, 15); +f(496, 16); +f(527, 17); +f(961, 31); +x = 32; +f(0, 0); +f(32, 1); +f(64, 2); +f(96, 3); +f(128, 4); +f(160, 5); +f(224, 7); +f(256, 8); +f(288, 9); +f(480, 15); +f(512, 16); +f(544, 17); +f(992, 31); +f(1024, 32); +x = 33; +f(0, 0); +f(33, 1); +f(66, 2); +f(99, 3); +f(132, 4); +f(165, 5); +f(231, 7); +f(264, 8); +f(297, 9); +f(495, 15); +f(528, 16); +f(561, 17); +f(1023, 31); +f(1056, 32); +f(1089, 33); +x = 63; +f(0, 0); +f(63, 1); +f(126, 2); +f(189, 3); +f(252, 4); +f(315, 5); +f(441, 7); +f(504, 8); +f(567, 9); +f(945, 15); +f(1008, 16); +f(1071, 17); +f(1953, 31); +f(2016, 32); +f(2079, 33); +f(3969, 63); +x = 64; +f(0, 0); +f(64, 1); +f(128, 2); +f(192, 3); +f(256, 4); +f(320, 5); +f(448, 7); +f(512, 8); +f(576, 9); +f(960, 15); +f(1024, 16); +f(1088, 17); +f(1984, 31); +f(2048, 32); +f(2112, 33); +f(4032, 63); +f(4096, 64); +x = 65; +f(0, 0); +f(65, 1); +f(130, 2); +f(195, 3); +f(260, 4); +f(325, 5); +f(455, 7); +f(520, 8); +f(585, 9); +f(975, 15); +f(1040, 16); +f(1105, 17); +f(2015, 31); +f(2080, 32); +f(2145, 33); +f(4095, 63); +f(4160, 64); +f(4225, 65); +x = 127; +f(0, 0); +f(127, 1); +f(254, 2); +f(381, 3); +f(508, 4); +f(635, 5); +f(889, 7); +f(1016, 8); +f(1143, 9); +f(1905, 15); +f(2032, 16); +f(2159, 17); +f(3937, 31); +f(4064, 32); +f(4191, 33); +f(8001, 63); +f(8128, 64); +f(8255, 65); +f(16129, 127); +x = 128; +f(0, 0); +f(128, 1); +f(256, 2); +f(384, 3); +f(512, 4); +f(640, 5); +f(896, 7); +f(1024, 8); +f(1152, 9); +f(1920, 15); +f(2048, 16); +f(2176, 17); +f(3968, 31); +f(4096, 32); +f(4224, 33); +f(8064, 63); +f(8192, 64); +f(8320, 65); +f(16256, 127); +f(16384, 128); +x = 129; +f(0, 0); +f(129, 1); +f(258, 2); +f(387, 3); +f(516, 4); +f(645, 5); +f(903, 7); +f(1032, 8); +f(1161, 9); +f(1935, 15); +f(2064, 16); +f(2193, 17); +f(3999, 31); +f(4128, 32); +f(4257, 33); +f(8127, 63); +f(8256, 64); +f(8385, 65); +f(16383, 127); +f(16512, 128); +f(16641, 129); +x = 255; +f(0, 0); +f(255, 1); +f(510, 2); +f(765, 3); +f(1020, 4); +f(1275, 5); +f(1785, 7); +f(2040, 8); +f(2295, 9); +f(3825, 15); +f(4080, 16); +f(4335, 17); +f(7905, 31); +f(8160, 32); +f(8415, 33); +f(16065, 63); +f(16320, 64); +f(16575, 65); +f(32385, 127); +f(32640, 128); +f(32895, 129); +f(65025, 255); +x = 256; +f(0, 0); +f(256, 1); +f(512, 2); +f(768, 3); +f(1024, 4); +f(1280, 5); +f(1792, 7); +f(2048, 8); +f(2304, 9); +f(3840, 15); +f(4096, 16); +f(4352, 17); +f(7936, 31); +f(8192, 32); +f(8448, 33); +f(16128, 63); +f(16384, 64); +f(16640, 65); +f(32512, 127); +f(32768, 128); +f(33024, 129); +f(65280, 255); +f(65536, 256); +x = 257; +f(0, 0); +f(257, 1); +f(514, 2); +f(771, 3); +f(1028, 4); +f(1285, 5); +f(1799, 7); +f(2056, 8); +f(2313, 9); +f(3855, 15); +f(4112, 16); +f(4369, 17); +f(7967, 31); +f(8224, 32); +f(8481, 33); +f(16191, 63); +f(16448, 64); +f(16705, 65); +f(32639, 127); +f(32896, 128); +f(33153, 129); +f(65535, 255); +f(65792, 256); +f(66049, 257); +x = 511; +f(0, 0); +f(511, 1); +f(1022, 2); +f(1533, 3); +f(2044, 4); +f(2555, 5); +f(3577, 7); +f(4088, 8); +f(4599, 9); +f(7665, 15); +f(8176, 16); +f(8687, 17); +f(15841, 31); +f(16352, 32); +f(16863, 33); +f(32193, 63); +f(32704, 64); +f(33215, 65); +f(64897, 127); +f(65408, 128); +f(65919, 129); +f(130305, 255); +f(130816, 256); +f(131327, 257); +f(261121, 511); +x = 512; +f(0, 0); +f(512, 1); +f(1024, 2); +f(1536, 3); +f(2048, 4); +f(2560, 5); +f(3584, 7); +f(4096, 8); +f(4608, 9); +f(7680, 15); +f(8192, 16); +f(8704, 17); +f(15872, 31); +f(16384, 32); +f(16896, 33); +f(32256, 63); +f(32768, 64); +f(33280, 65); +f(65024, 127); +f(65536, 128); +f(66048, 129); +f(130560, 255); +f(131072, 256); +f(131584, 257); +f(261632, 511); +f(262144, 512); +x = 513; +f(0, 0); +f(513, 1); +f(1026, 2); +f(1539, 3); +f(2052, 4); +f(2565, 5); +f(3591, 7); +f(4104, 8); +f(4617, 9); +f(7695, 15); +f(8208, 16); +f(8721, 17); +f(15903, 31); +f(16416, 32); +f(16929, 33); +f(32319, 63); +f(32832, 64); +f(33345, 65); +f(65151, 127); +f(65664, 128); +f(66177, 129); +f(130815, 255); +f(131328, 256); +f(131841, 257); +f(262143, 511); +f(262656, 512); +f(263169, 513); +x = 1023; +f(0, 0); +f(1023, 1); +f(2046, 2); +f(3069, 3); +f(4092, 4); +f(5115, 5); +f(7161, 7); +f(8184, 8); +f(9207, 9); +f(15345, 15); +f(16368, 16); +f(17391, 17); +f(31713, 31); +f(32736, 32); +f(33759, 33); +f(64449, 63); +f(65472, 64); +f(66495, 65); +f(129921, 127); +f(130944, 128); +f(131967, 129); +f(260865, 255); +f(261888, 256); +f(262911, 257); +f(522753, 511); +f(523776, 512); +f(524799, 513); +f(1046529, 1023); diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part10.js b/deps/v8/test/mjsunit/mul-exhaustive-part10.js new file mode 100644 index 0000000000..166ec52171 --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part10.js @@ -0,0 +1,470 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 4294967296; +f(0, 0); +f(4294967296, 1); +f(8589934592, 2); +f(12884901888, 3); +f(17179869184, 4); +f(21474836480, 5); +f(30064771072, 7); +f(34359738368, 8); +f(38654705664, 9); +f(64424509440, 15); +f(68719476736, 16); +f(73014444032, 17); +f(133143986176, 31); +f(137438953472, 32); +f(141733920768, 33); +f(270582939648, 63); +f(274877906944, 64); +f(279172874240, 65); +f(545460846592, 127); +f(549755813888, 128); +f(554050781184, 129); +f(1095216660480, 255); +f(1099511627776, 256); +f(1103806595072, 257); +f(2194728288256, 511); +f(2199023255552, 512); +f(2203318222848, 513); +f(4393751543808, 1023); +f(4398046511104, 1024); +f(4402341478400, 1025); +f(8791798054912, 2047); +f(8796093022208, 2048); +f(8800387989504, 2049); +f(17587891077120, 4095); +f(17592186044416, 4096); +f(17596481011712, 4097); +f(35180077121536, 8191); +f(35184372088832, 8192); +f(35188667056128, 8193); +f(70364449210368, 16383); +f(70368744177664, 16384); +f(70373039144960, 16385); +f(140733193388032, 32767); +f(140737488355328, 32768); +f(140741783322624, 32769); +f(281470681743360, 65535); +f(281474976710656, 65536); +f(281479271677952, 65537); +f(562945658454016, 131071); +f(562949953421312, 131072); +f(562954248388608, 131073); +f(1125895611875328, 262143); +f(1125899906842624, 262144); +f(1125904201809920, 262145); +x = 4294967297; +f(0, 0); +f(4294967297, 1); +f(8589934594, 2); +f(12884901891, 3); +f(17179869188, 4); +f(21474836485, 5); +f(30064771079, 7); +f(34359738376, 8); +f(38654705673, 9); +f(64424509455, 15); +f(68719476752, 16); +f(73014444049, 17); +f(133143986207, 31); +f(137438953504, 32); +f(141733920801, 33); +f(270582939711, 63); +f(274877907008, 64); +f(279172874305, 65); +f(545460846719, 127); +f(549755814016, 128); +f(554050781313, 129); +f(1095216660735, 255); +f(1099511628032, 256); +f(1103806595329, 257); +f(2194728288767, 511); +f(2199023256064, 512); +f(2203318223361, 513); +f(4393751544831, 1023); +f(4398046512128, 1024); +f(4402341479425, 1025); +f(8791798056959, 2047); +f(8796093024256, 2048); +f(8800387991553, 2049); +f(17587891081215, 4095); +f(17592186048512, 4096); +f(17596481015809, 4097); +f(35180077129727, 8191); +f(35184372097024, 8192); +f(35188667064321, 8193); +f(70364449226751, 16383); +f(70368744194048, 16384); +f(70373039161345, 16385); +f(140733193420799, 32767); +f(140737488388096, 32768); +f(140741783355393, 32769); +f(281470681808895, 65535); +f(281474976776192, 65536); +f(281479271743489, 65537); +f(562945658585087, 131071); +f(562949953552384, 131072); +f(562954248519681, 131073); +f(1125895612137471, 262143); +f(1125899907104768, 262144); +f(1125904202072065, 262145); +x = 8589934591; +f(0, 0); +f(8589934591, 1); +f(17179869182, 2); +f(25769803773, 3); +f(34359738364, 4); +f(42949672955, 5); +f(60129542137, 7); +f(68719476728, 8); +f(77309411319, 9); +f(128849018865, 15); +f(137438953456, 16); +f(146028888047, 17); +f(266287972321, 31); +f(274877906912, 32); +f(283467841503, 33); +f(541165879233, 63); +f(549755813824, 64); +f(558345748415, 65); +f(1090921693057, 127); +f(1099511627648, 128); +f(1108101562239, 129); +f(2190433320705, 255); +f(2199023255296, 256); +f(2207613189887, 257); +f(4389456576001, 511); +f(4398046510592, 512); +f(4406636445183, 513); +f(8787503086593, 1023); +f(8796093021184, 1024); +f(8804682955775, 1025); +f(17583596107777, 2047); +f(17592186042368, 2048); +f(17600775976959, 2049); +f(35175782150145, 4095); +f(35184372084736, 4096); +f(35192962019327, 4097); +f(70360154234881, 8191); +f(70368744169472, 8192); +f(70377334104063, 8193); +f(140728898404353, 16383); +f(140737488338944, 16384); +f(140746078273535, 16385); +f(281466386743297, 32767); +f(281474976677888, 32768); +f(281483566612479, 32769); +f(562941363421185, 65535); +f(562949953355776, 65536); +f(562958543290367, 65537); +f(1125891316776961, 131071); +f(1125899906711552, 131072); +f(1125908496646143, 131073); +x = 8589934592; +f(0, 0); +f(8589934592, 1); +f(17179869184, 2); +f(25769803776, 3); +f(34359738368, 4); +f(42949672960, 5); +f(60129542144, 7); +f(68719476736, 8); +f(77309411328, 9); +f(128849018880, 15); +f(137438953472, 16); +f(146028888064, 17); +f(266287972352, 31); +f(274877906944, 32); +f(283467841536, 33); +f(541165879296, 63); +f(549755813888, 64); +f(558345748480, 65); +f(1090921693184, 127); +f(1099511627776, 128); +f(1108101562368, 129); +f(2190433320960, 255); +f(2199023255552, 256); +f(2207613190144, 257); +f(4389456576512, 511); +f(4398046511104, 512); +f(4406636445696, 513); +f(8787503087616, 1023); +f(8796093022208, 1024); +f(8804682956800, 1025); +f(17583596109824, 2047); +f(17592186044416, 2048); +f(17600775979008, 2049); +f(35175782154240, 4095); +f(35184372088832, 4096); +f(35192962023424, 4097); +f(70360154243072, 8191); +f(70368744177664, 8192); +f(70377334112256, 8193); +f(140728898420736, 16383); +f(140737488355328, 16384); +f(140746078289920, 16385); +f(281466386776064, 32767); +f(281474976710656, 32768); +f(281483566645248, 32769); +f(562941363486720, 65535); +f(562949953421312, 65536); +f(562958543355904, 65537); +f(1125891316908032, 131071); +f(1125899906842624, 131072); +f(1125908496777216, 131073); +x = 8589934593; +f(0, 0); +f(8589934593, 1); +f(17179869186, 2); +f(25769803779, 3); +f(34359738372, 4); +f(42949672965, 5); +f(60129542151, 7); +f(68719476744, 8); +f(77309411337, 9); +f(128849018895, 15); +f(137438953488, 16); +f(146028888081, 17); +f(266287972383, 31); +f(274877906976, 32); +f(283467841569, 33); +f(541165879359, 63); +f(549755813952, 64); +f(558345748545, 65); +f(1090921693311, 127); +f(1099511627904, 128); +f(1108101562497, 129); +f(2190433321215, 255); +f(2199023255808, 256); +f(2207613190401, 257); +f(4389456577023, 511); +f(4398046511616, 512); +f(4406636446209, 513); +f(8787503088639, 1023); +f(8796093023232, 1024); +f(8804682957825, 1025); +f(17583596111871, 2047); +f(17592186046464, 2048); +f(17600775981057, 2049); +f(35175782158335, 4095); +f(35184372092928, 4096); +f(35192962027521, 4097); +f(70360154251263, 8191); +f(70368744185856, 8192); +f(70377334120449, 8193); +f(140728898437119, 16383); +f(140737488371712, 16384); +f(140746078306305, 16385); +f(281466386808831, 32767); +f(281474976743424, 32768); +f(281483566678017, 32769); +f(562941363552255, 65535); +f(562949953486848, 65536); +f(562958543421441, 65537); +f(1125891317039103, 131071); +f(1125899906973696, 131072); +f(1125908496908289, 131073); +x = 17179869183; +f(0, 0); +f(17179869183, 1); +f(34359738366, 2); +f(51539607549, 3); +f(68719476732, 4); +f(85899345915, 5); +f(120259084281, 7); +f(137438953464, 8); +f(154618822647, 9); +f(257698037745, 15); +f(274877906928, 16); +f(292057776111, 17); +f(532575944673, 31); +f(549755813856, 32); +f(566935683039, 33); +f(1082331758529, 63); +f(1099511627712, 64); +f(1116691496895, 65); +f(2181843386241, 127); +f(2199023255424, 128); +f(2216203124607, 129); +f(4380866641665, 255); +f(4398046510848, 256); +f(4415226380031, 257); +f(8778913152513, 511); +f(8796093021696, 512); +f(8813272890879, 513); +f(17575006174209, 1023); +f(17592186043392, 1024); +f(17609365912575, 1025); +f(35167192217601, 2047); +f(35184372086784, 2048); +f(35201551955967, 2049); +f(70351564304385, 4095); +f(70368744173568, 4096); +f(70385924042751, 4097); +f(140720308477953, 8191); +f(140737488347136, 8192); +f(140754668216319, 8193); +f(281457796825089, 16383); +f(281474976694272, 16384); +f(281492156563455, 16385); +f(562932773519361, 32767); +f(562949953388544, 32768); +f(562967133257727, 32769); +f(1125882726907905, 65535); +f(1125899906777088, 65536); +f(1125917086646271, 65537); +x = 17179869184; +f(0, 0); +f(17179869184, 1); +f(34359738368, 2); +f(51539607552, 3); +f(68719476736, 4); +f(85899345920, 5); +f(120259084288, 7); +f(137438953472, 8); +f(154618822656, 9); +f(257698037760, 15); +f(274877906944, 16); +f(292057776128, 17); +f(532575944704, 31); +f(549755813888, 32); +f(566935683072, 33); +f(1082331758592, 63); +f(1099511627776, 64); +f(1116691496960, 65); +f(2181843386368, 127); +f(2199023255552, 128); +f(2216203124736, 129); +f(4380866641920, 255); +f(4398046511104, 256); +f(4415226380288, 257); +f(8778913153024, 511); +f(8796093022208, 512); +f(8813272891392, 513); +f(17575006175232, 1023); +f(17592186044416, 1024); +f(17609365913600, 1025); +f(35167192219648, 2047); +f(35184372088832, 2048); +f(35201551958016, 2049); +f(70351564308480, 4095); +f(70368744177664, 4096); +f(70385924046848, 4097); +f(140720308486144, 8191); +f(140737488355328, 8192); +f(140754668224512, 8193); +f(281457796841472, 16383); +f(281474976710656, 16384); +f(281492156579840, 16385); +f(562932773552128, 32767); +f(562949953421312, 32768); +f(562967133290496, 32769); +f(1125882726973440, 65535); +f(1125899906842624, 65536); +f(1125917086711808, 65537); +x = 17179869185; +f(0, 0); +f(17179869185, 1); +f(34359738370, 2); +f(51539607555, 3); +f(68719476740, 4); +f(85899345925, 5); +f(120259084295, 7); +f(137438953480, 8); +f(154618822665, 9); +f(257698037775, 15); +f(274877906960, 16); +f(292057776145, 17); +f(532575944735, 31); +f(549755813920, 32); +f(566935683105, 33); +f(1082331758655, 63); +f(1099511627840, 64); +f(1116691497025, 65); +f(2181843386495, 127); +f(2199023255680, 128); +f(2216203124865, 129); +f(4380866642175, 255); +f(4398046511360, 256); +f(4415226380545, 257); +f(8778913153535, 511); +f(8796093022720, 512); +f(8813272891905, 513); +f(17575006176255, 1023); +f(17592186045440, 1024); +f(17609365914625, 1025); +f(35167192221695, 2047); +f(35184372090880, 2048); +f(35201551960065, 2049); +f(70351564312575, 4095); +f(70368744181760, 4096); +f(70385924050945, 4097); +f(140720308494335, 8191); +f(140737488363520, 8192); +f(140754668232705, 8193); +f(281457796857855, 16383); +f(281474976727040, 16384); +f(281492156596225, 16385); +f(562932773584895, 32767); +f(562949953454080, 32768); +f(562967133323265, 32769); +f(1125882727038975, 65535); +f(1125899906908160, 65536); +f(1125917086777345, 65537); diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part2.js b/deps/v8/test/mjsunit/mul-exhaustive-part2.js new file mode 100644 index 0000000000..4c4a123847 --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part2.js @@ -0,0 +1,525 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 1024; +f(0, 0); +f(1024, 1); +f(2048, 2); +f(3072, 3); +f(4096, 4); +f(5120, 5); +f(7168, 7); +f(8192, 8); +f(9216, 9); +f(15360, 15); +f(16384, 16); +f(17408, 17); +f(31744, 31); +f(32768, 32); +f(33792, 33); +f(64512, 63); +f(65536, 64); +f(66560, 65); +f(130048, 127); +f(131072, 128); +f(132096, 129); +f(261120, 255); +f(262144, 256); +f(263168, 257); +f(523264, 511); +f(524288, 512); +f(525312, 513); +f(1047552, 1023); +f(1048576, 1024); +x = 1025; +f(0, 0); +f(1025, 1); +f(2050, 2); +f(3075, 3); +f(4100, 4); +f(5125, 5); +f(7175, 7); +f(8200, 8); +f(9225, 9); +f(15375, 15); +f(16400, 16); +f(17425, 17); +f(31775, 31); +f(32800, 32); +f(33825, 33); +f(64575, 63); +f(65600, 64); +f(66625, 65); +f(130175, 127); +f(131200, 128); +f(132225, 129); +f(261375, 255); +f(262400, 256); +f(263425, 257); +f(523775, 511); +f(524800, 512); +f(525825, 513); +f(1048575, 1023); +f(1049600, 1024); +f(1050625, 1025); +x = 2047; +f(0, 0); +f(2047, 1); +f(4094, 2); +f(6141, 3); +f(8188, 4); +f(10235, 5); +f(14329, 7); +f(16376, 8); +f(18423, 9); +f(30705, 15); +f(32752, 16); +f(34799, 17); +f(63457, 31); +f(65504, 32); +f(67551, 33); +f(128961, 63); +f(131008, 64); +f(133055, 65); +f(259969, 127); +f(262016, 128); +f(264063, 129); +f(521985, 255); +f(524032, 256); +f(526079, 257); +f(1046017, 511); +f(1048064, 512); +f(1050111, 513); +f(2094081, 1023); +f(2096128, 1024); +f(2098175, 1025); +f(4190209, 2047); +x = 2048; +f(0, 0); +f(2048, 1); +f(4096, 2); +f(6144, 3); +f(8192, 4); +f(10240, 5); +f(14336, 7); +f(16384, 8); +f(18432, 9); +f(30720, 15); +f(32768, 16); +f(34816, 17); +f(63488, 31); +f(65536, 32); +f(67584, 33); +f(129024, 63); +f(131072, 64); +f(133120, 65); +f(260096, 127); +f(262144, 128); +f(264192, 129); +f(522240, 255); +f(524288, 256); +f(526336, 257); +f(1046528, 511); +f(1048576, 512); +f(1050624, 513); +f(2095104, 1023); +f(2097152, 1024); +f(2099200, 1025); +f(4192256, 2047); +f(4194304, 2048); +x = 2049; +f(0, 0); +f(2049, 1); +f(4098, 2); +f(6147, 3); +f(8196, 4); +f(10245, 5); +f(14343, 7); +f(16392, 8); +f(18441, 9); +f(30735, 15); +f(32784, 16); +f(34833, 17); +f(63519, 31); +f(65568, 32); +f(67617, 33); +f(129087, 63); +f(131136, 64); +f(133185, 65); +f(260223, 127); +f(262272, 128); +f(264321, 129); +f(522495, 255); +f(524544, 256); +f(526593, 257); +f(1047039, 511); +f(1049088, 512); +f(1051137, 513); +f(2096127, 1023); +f(2098176, 1024); +f(2100225, 1025); +f(4194303, 2047); +f(4196352, 2048); +f(4198401, 2049); +x = 4095; +f(0, 0); +f(4095, 1); +f(8190, 2); +f(12285, 3); +f(16380, 4); +f(20475, 5); +f(28665, 7); +f(32760, 8); +f(36855, 9); +f(61425, 15); +f(65520, 16); +f(69615, 17); +f(126945, 31); +f(131040, 32); +f(135135, 33); +f(257985, 63); +f(262080, 64); +f(266175, 65); +f(520065, 127); +f(524160, 128); +f(528255, 129); +f(1044225, 255); +f(1048320, 256); +f(1052415, 257); +f(2092545, 511); +f(2096640, 512); +f(2100735, 513); +f(4189185, 1023); +f(4193280, 1024); +f(4197375, 1025); +f(8382465, 2047); +f(8386560, 2048); +f(8390655, 2049); +f(16769025, 4095); +x = 4096; +f(0, 0); +f(4096, 1); +f(8192, 2); +f(12288, 3); +f(16384, 4); +f(20480, 5); +f(28672, 7); +f(32768, 8); +f(36864, 9); +f(61440, 15); +f(65536, 16); +f(69632, 17); +f(126976, 31); +f(131072, 32); +f(135168, 33); +f(258048, 63); +f(262144, 64); +f(266240, 65); +f(520192, 127); +f(524288, 128); +f(528384, 129); +f(1044480, 255); +f(1048576, 256); +f(1052672, 257); +f(2093056, 511); +f(2097152, 512); +f(2101248, 513); +f(4190208, 1023); +f(4194304, 1024); +f(4198400, 1025); +f(8384512, 2047); +f(8388608, 2048); +f(8392704, 2049); +f(16773120, 4095); +f(16777216, 4096); +x = 4097; +f(0, 0); +f(4097, 1); +f(8194, 2); +f(12291, 3); +f(16388, 4); +f(20485, 5); +f(28679, 7); +f(32776, 8); +f(36873, 9); +f(61455, 15); +f(65552, 16); +f(69649, 17); +f(127007, 31); +f(131104, 32); +f(135201, 33); +f(258111, 63); +f(262208, 64); +f(266305, 65); +f(520319, 127); +f(524416, 128); +f(528513, 129); +f(1044735, 255); +f(1048832, 256); +f(1052929, 257); +f(2093567, 511); +f(2097664, 512); +f(2101761, 513); +f(4191231, 1023); +f(4195328, 1024); +f(4199425, 1025); +f(8386559, 2047); +f(8390656, 2048); +f(8394753, 2049); +f(16777215, 4095); +f(16781312, 4096); +f(16785409, 4097); +x = 8191; +f(0, 0); +f(8191, 1); +f(16382, 2); +f(24573, 3); +f(32764, 4); +f(40955, 5); +f(57337, 7); +f(65528, 8); +f(73719, 9); +f(122865, 15); +f(131056, 16); +f(139247, 17); +f(253921, 31); +f(262112, 32); +f(270303, 33); +f(516033, 63); +f(524224, 64); +f(532415, 65); +f(1040257, 127); +f(1048448, 128); +f(1056639, 129); +f(2088705, 255); +f(2096896, 256); +f(2105087, 257); +f(4185601, 511); +f(4193792, 512); +f(4201983, 513); +f(8379393, 1023); +f(8387584, 1024); +f(8395775, 1025); +f(16766977, 2047); +f(16775168, 2048); +f(16783359, 2049); +f(33542145, 4095); +f(33550336, 4096); +f(33558527, 4097); +f(67092481, 8191); +x = 8192; +f(0, 0); +f(8192, 1); +f(16384, 2); +f(24576, 3); +f(32768, 4); +f(40960, 5); +f(57344, 7); +f(65536, 8); +f(73728, 9); +f(122880, 15); +f(131072, 16); +f(139264, 17); +f(253952, 31); +f(262144, 32); +f(270336, 33); +f(516096, 63); +f(524288, 64); +f(532480, 65); +f(1040384, 127); +f(1048576, 128); +f(1056768, 129); +f(2088960, 255); +f(2097152, 256); +f(2105344, 257); +f(4186112, 511); +f(4194304, 512); +f(4202496, 513); +f(8380416, 1023); +f(8388608, 1024); +f(8396800, 1025); +f(16769024, 2047); +f(16777216, 2048); +f(16785408, 2049); +f(33546240, 4095); +f(33554432, 4096); +f(33562624, 4097); +f(67100672, 8191); +f(67108864, 8192); +x = 8193; +f(0, 0); +f(8193, 1); +f(16386, 2); +f(24579, 3); +f(32772, 4); +f(40965, 5); +f(57351, 7); +f(65544, 8); +f(73737, 9); +f(122895, 15); +f(131088, 16); +f(139281, 17); +f(253983, 31); +f(262176, 32); +f(270369, 33); +f(516159, 63); +f(524352, 64); +f(532545, 65); +f(1040511, 127); +f(1048704, 128); +f(1056897, 129); +f(2089215, 255); +f(2097408, 256); +f(2105601, 257); +f(4186623, 511); +f(4194816, 512); +f(4203009, 513); +f(8381439, 1023); +f(8389632, 1024); +f(8397825, 1025); +f(16771071, 2047); +f(16779264, 2048); +f(16787457, 2049); +f(33550335, 4095); +f(33558528, 4096); +f(33566721, 4097); +f(67108863, 8191); +f(67117056, 8192); +f(67125249, 8193); +x = 16383; +f(0, 0); +f(16383, 1); +f(32766, 2); +f(49149, 3); +f(65532, 4); +f(81915, 5); +f(114681, 7); +f(131064, 8); +f(147447, 9); +f(245745, 15); +f(262128, 16); +f(278511, 17); +f(507873, 31); +f(524256, 32); +f(540639, 33); +f(1032129, 63); +f(1048512, 64); +f(1064895, 65); +f(2080641, 127); +f(2097024, 128); +f(2113407, 129); +f(4177665, 255); +f(4194048, 256); +f(4210431, 257); +f(8371713, 511); +f(8388096, 512); +f(8404479, 513); +f(16759809, 1023); +f(16776192, 1024); +f(16792575, 1025); +f(33536001, 2047); +f(33552384, 2048); +f(33568767, 2049); +f(67088385, 4095); +f(67104768, 4096); +f(67121151, 4097); +f(134193153, 8191); +f(134209536, 8192); +f(134225919, 8193); +f(268402689, 16383); +x = 16384; +f(0, 0); +f(16384, 1); +f(32768, 2); +f(49152, 3); +f(65536, 4); +f(81920, 5); +f(114688, 7); +f(131072, 8); +f(147456, 9); +f(245760, 15); +f(262144, 16); +f(278528, 17); +f(507904, 31); +f(524288, 32); +f(540672, 33); +f(1032192, 63); +f(1048576, 64); +f(1064960, 65); +f(2080768, 127); +f(2097152, 128); +f(2113536, 129); +f(4177920, 255); +f(4194304, 256); +f(4210688, 257); +f(8372224, 511); +f(8388608, 512); +f(8404992, 513); +f(16760832, 1023); +f(16777216, 1024); +f(16793600, 1025); +f(33538048, 2047); +f(33554432, 2048); +f(33570816, 2049); +f(67092480, 4095); +f(67108864, 4096); +f(67125248, 4097); +f(134201344, 8191); +f(134217728, 8192); +f(134234112, 8193); +f(268419072, 16383); +f(268435456, 16384); diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part3.js b/deps/v8/test/mjsunit/mul-exhaustive-part3.js new file mode 100644 index 0000000000..06e41a1d46 --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part3.js @@ -0,0 +1,532 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 16385; +f(0, 0); +f(16385, 1); +f(32770, 2); +f(49155, 3); +f(65540, 4); +f(81925, 5); +f(114695, 7); +f(131080, 8); +f(147465, 9); +f(245775, 15); +f(262160, 16); +f(278545, 17); +f(507935, 31); +f(524320, 32); +f(540705, 33); +f(1032255, 63); +f(1048640, 64); +f(1065025, 65); +f(2080895, 127); +f(2097280, 128); +f(2113665, 129); +f(4178175, 255); +f(4194560, 256); +f(4210945, 257); +f(8372735, 511); +f(8389120, 512); +f(8405505, 513); +f(16761855, 1023); +f(16778240, 1024); +f(16794625, 1025); +f(33540095, 2047); +f(33556480, 2048); +f(33572865, 2049); +f(67096575, 4095); +f(67112960, 4096); +f(67129345, 4097); +f(134209535, 8191); +f(134225920, 8192); +f(134242305, 8193); +f(268435455, 16383); +f(268451840, 16384); +f(268468225, 16385); +x = 32767; +f(0, 0); +f(32767, 1); +f(65534, 2); +f(98301, 3); +f(131068, 4); +f(163835, 5); +f(229369, 7); +f(262136, 8); +f(294903, 9); +f(491505, 15); +f(524272, 16); +f(557039, 17); +f(1015777, 31); +f(1048544, 32); +f(1081311, 33); +f(2064321, 63); +f(2097088, 64); +f(2129855, 65); +f(4161409, 127); +f(4194176, 128); +f(4226943, 129); +f(8355585, 255); +f(8388352, 256); +f(8421119, 257); +f(16743937, 511); +f(16776704, 512); +f(16809471, 513); +f(33520641, 1023); +f(33553408, 1024); +f(33586175, 1025); +f(67074049, 2047); +f(67106816, 2048); +f(67139583, 2049); +f(134180865, 4095); +f(134213632, 4096); +f(134246399, 4097); +f(268394497, 8191); +f(268427264, 8192); +f(268460031, 8193); +f(536821761, 16383); +f(536854528, 16384); +f(536887295, 16385); +f(1073676289, 32767); +x = 32768; +f(0, 0); +f(32768, 1); +f(65536, 2); +f(98304, 3); +f(131072, 4); +f(163840, 5); +f(229376, 7); +f(262144, 8); +f(294912, 9); +f(491520, 15); +f(524288, 16); +f(557056, 17); +f(1015808, 31); +f(1048576, 32); +f(1081344, 33); +f(2064384, 63); +f(2097152, 64); +f(2129920, 65); +f(4161536, 127); +f(4194304, 128); +f(4227072, 129); +f(8355840, 255); +f(8388608, 256); +f(8421376, 257); +f(16744448, 511); +f(16777216, 512); +f(16809984, 513); +f(33521664, 1023); +f(33554432, 1024); +f(33587200, 1025); +f(67076096, 2047); +f(67108864, 2048); +f(67141632, 2049); +f(134184960, 4095); +f(134217728, 4096); +f(134250496, 4097); +f(268402688, 8191); +f(268435456, 8192); +f(268468224, 8193); +f(536838144, 16383); +f(536870912, 16384); +f(536903680, 16385); +f(1073709056, 32767); +f(1073741824, 32768); +x = 32769; +f(0, 0); +f(32769, 1); +f(65538, 2); +f(98307, 3); +f(131076, 4); +f(163845, 5); +f(229383, 7); +f(262152, 8); +f(294921, 9); +f(491535, 15); +f(524304, 16); +f(557073, 17); +f(1015839, 31); +f(1048608, 32); +f(1081377, 33); +f(2064447, 63); +f(2097216, 64); +f(2129985, 65); +f(4161663, 127); +f(4194432, 128); +f(4227201, 129); +f(8356095, 255); +f(8388864, 256); +f(8421633, 257); +f(16744959, 511); +f(16777728, 512); +f(16810497, 513); +f(33522687, 1023); +f(33555456, 1024); +f(33588225, 1025); +f(67078143, 2047); +f(67110912, 2048); +f(67143681, 2049); +f(134189055, 4095); +f(134221824, 4096); +f(134254593, 4097); +f(268410879, 8191); +f(268443648, 8192); +f(268476417, 8193); +f(536854527, 16383); +f(536887296, 16384); +f(536920065, 16385); +f(1073741823, 32767); +f(1073774592, 32768); +f(1073807361, 32769); +x = 65535; +f(0, 0); +f(65535, 1); +f(131070, 2); +f(196605, 3); +f(262140, 4); +f(327675, 5); +f(458745, 7); +f(524280, 8); +f(589815, 9); +f(983025, 15); +f(1048560, 16); +f(1114095, 17); +f(2031585, 31); +f(2097120, 32); +f(2162655, 33); +f(4128705, 63); +f(4194240, 64); +f(4259775, 65); +f(8322945, 127); +f(8388480, 128); +f(8454015, 129); +f(16711425, 255); +f(16776960, 256); +f(16842495, 257); +f(33488385, 511); +f(33553920, 512); +f(33619455, 513); +f(67042305, 1023); +f(67107840, 1024); +f(67173375, 1025); +f(134150145, 2047); +f(134215680, 2048); +f(134281215, 2049); +f(268365825, 4095); +f(268431360, 4096); +f(268496895, 4097); +f(536797185, 8191); +f(536862720, 8192); +f(536928255, 8193); +f(1073659905, 16383); +f(1073725440, 16384); +f(1073790975, 16385); +f(2147385345, 32767); +f(2147450880, 32768); +f(2147516415, 32769); +f(4294836225, 65535); +x = 65536; +f(0, 0); +f(65536, 1); +f(131072, 2); +f(196608, 3); +f(262144, 4); +f(327680, 5); +f(458752, 7); +f(524288, 8); +f(589824, 9); +f(983040, 15); +f(1048576, 16); +f(1114112, 17); +f(2031616, 31); +f(2097152, 32); +f(2162688, 33); +f(4128768, 63); +f(4194304, 64); +f(4259840, 65); +f(8323072, 127); +f(8388608, 128); +f(8454144, 129); +f(16711680, 255); +f(16777216, 256); +f(16842752, 257); +f(33488896, 511); +f(33554432, 512); +f(33619968, 513); +f(67043328, 1023); +f(67108864, 1024); +f(67174400, 1025); +f(134152192, 2047); +f(134217728, 2048); +f(134283264, 2049); +f(268369920, 4095); +f(268435456, 4096); +f(268500992, 4097); +f(536805376, 8191); +f(536870912, 8192); +f(536936448, 8193); +f(1073676288, 16383); +f(1073741824, 16384); +f(1073807360, 16385); +f(2147418112, 32767); +f(2147483648, 32768); +f(2147549184, 32769); +f(4294901760, 65535); +f(4294967296, 65536); +x = 65537; +f(0, 0); +f(65537, 1); +f(131074, 2); +f(196611, 3); +f(262148, 4); +f(327685, 5); +f(458759, 7); +f(524296, 8); +f(589833, 9); +f(983055, 15); +f(1048592, 16); +f(1114129, 17); +f(2031647, 31); +f(2097184, 32); +f(2162721, 33); +f(4128831, 63); +f(4194368, 64); +f(4259905, 65); +f(8323199, 127); +f(8388736, 128); +f(8454273, 129); +f(16711935, 255); +f(16777472, 256); +f(16843009, 257); +f(33489407, 511); +f(33554944, 512); +f(33620481, 513); +f(67044351, 1023); +f(67109888, 1024); +f(67175425, 1025); +f(134154239, 2047); +f(134219776, 2048); +f(134285313, 2049); +f(268374015, 4095); +f(268439552, 4096); +f(268505089, 4097); +f(536813567, 8191); +f(536879104, 8192); +f(536944641, 8193); +f(1073692671, 16383); +f(1073758208, 16384); +f(1073823745, 16385); +f(2147450879, 32767); +f(2147516416, 32768); +f(2147581953, 32769); +f(4294967295, 65535); +f(4295032832, 65536); +f(4295098369, 65537); +x = 131071; +f(0, 0); +f(131071, 1); +f(262142, 2); +f(393213, 3); +f(524284, 4); +f(655355, 5); +f(917497, 7); +f(1048568, 8); +f(1179639, 9); +f(1966065, 15); +f(2097136, 16); +f(2228207, 17); +f(4063201, 31); +f(4194272, 32); +f(4325343, 33); +f(8257473, 63); +f(8388544, 64); +f(8519615, 65); +f(16646017, 127); +f(16777088, 128); +f(16908159, 129); +f(33423105, 255); +f(33554176, 256); +f(33685247, 257); +f(66977281, 511); +f(67108352, 512); +f(67239423, 513); +f(134085633, 1023); +f(134216704, 1024); +f(134347775, 1025); +f(268302337, 2047); +f(268433408, 2048); +f(268564479, 2049); +f(536735745, 4095); +f(536866816, 4096); +f(536997887, 4097); +f(1073602561, 8191); +f(1073733632, 8192); +f(1073864703, 8193); +f(2147336193, 16383); +f(2147467264, 16384); +f(2147598335, 16385); +f(4294803457, 32767); +f(4294934528, 32768); +f(4295065599, 32769); +f(8589737985, 65535); +f(8589869056, 65536); +f(8590000127, 65537); +f(17179607041, 131071); +x = 131072; +f(0, 0); +f(131072, 1); +f(262144, 2); +f(393216, 3); +f(524288, 4); +f(655360, 5); +f(917504, 7); +f(1048576, 8); +f(1179648, 9); +f(1966080, 15); +f(2097152, 16); +f(2228224, 17); +f(4063232, 31); +f(4194304, 32); +f(4325376, 33); +f(8257536, 63); +f(8388608, 64); +f(8519680, 65); +f(16646144, 127); +f(16777216, 128); +f(16908288, 129); +f(33423360, 255); +f(33554432, 256); +f(33685504, 257); +f(66977792, 511); +f(67108864, 512); +f(67239936, 513); +f(134086656, 1023); +f(134217728, 1024); +f(134348800, 1025); +f(268304384, 2047); +f(268435456, 2048); +f(268566528, 2049); +f(536739840, 4095); +f(536870912, 4096); +f(537001984, 4097); +f(1073610752, 8191); +f(1073741824, 8192); +f(1073872896, 8193); +f(2147352576, 16383); +f(2147483648, 16384); +f(2147614720, 16385); +f(4294836224, 32767); +f(4294967296, 32768); +f(4295098368, 32769); +f(8589803520, 65535); +f(8589934592, 65536); +f(8590065664, 65537); +f(17179738112, 131071); +f(17179869184, 131072); +x = 131073; +f(0, 0); +f(131073, 1); +f(262146, 2); +f(393219, 3); +f(524292, 4); +f(655365, 5); +f(917511, 7); +f(1048584, 8); +f(1179657, 9); +f(1966095, 15); +f(2097168, 16); +f(2228241, 17); +f(4063263, 31); +f(4194336, 32); +f(4325409, 33); +f(8257599, 63); +f(8388672, 64); +f(8519745, 65); +f(16646271, 127); +f(16777344, 128); +f(16908417, 129); +f(33423615, 255); +f(33554688, 256); +f(33685761, 257); +f(66978303, 511); +f(67109376, 512); +f(67240449, 513); +f(134087679, 1023); +f(134218752, 1024); +f(134349825, 1025); +f(268306431, 2047); +f(268437504, 2048); +f(268568577, 2049); +f(536743935, 4095); +f(536875008, 4096); +f(537006081, 4097); +f(1073618943, 8191); +f(1073750016, 8192); +f(1073881089, 8193); +f(2147368959, 16383); +f(2147500032, 16384); +f(2147631105, 16385); +f(4294868991, 32767); +f(4295000064, 32768); +f(4295131137, 32769); +f(8589869055, 65535); +f(8590000128, 65536); +f(8590131201, 65537); +f(17179869183, 131071); +f(17180000256, 131072); +f(17180131329, 131073); diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part4.js b/deps/v8/test/mjsunit/mul-exhaustive-part4.js new file mode 100644 index 0000000000..de9f9835b2 --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part4.js @@ -0,0 +1,509 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 262143; +f(0, 0); +f(262143, 1); +f(524286, 2); +f(786429, 3); +f(1048572, 4); +f(1310715, 5); +f(1835001, 7); +f(2097144, 8); +f(2359287, 9); +f(3932145, 15); +f(4194288, 16); +f(4456431, 17); +f(8126433, 31); +f(8388576, 32); +f(8650719, 33); +f(16515009, 63); +f(16777152, 64); +f(17039295, 65); +f(33292161, 127); +f(33554304, 128); +f(33816447, 129); +f(66846465, 255); +f(67108608, 256); +f(67370751, 257); +f(133955073, 511); +f(134217216, 512); +f(134479359, 513); +f(268172289, 1023); +f(268434432, 1024); +f(268696575, 1025); +f(536606721, 2047); +f(536868864, 2048); +f(537131007, 2049); +f(1073475585, 4095); +f(1073737728, 4096); +f(1073999871, 4097); +f(2147213313, 8191); +f(2147475456, 8192); +f(2147737599, 8193); +f(4294688769, 16383); +f(4294950912, 16384); +f(4295213055, 16385); +f(8589639681, 32767); +f(8589901824, 32768); +f(8590163967, 32769); +f(17179541505, 65535); +f(17179803648, 65536); +f(17180065791, 65537); +f(34359345153, 131071); +f(34359607296, 131072); +f(34359869439, 131073); +f(68718952449, 262143); +x = 262144; +f(0, 0); +f(262144, 1); +f(524288, 2); +f(786432, 3); +f(1048576, 4); +f(1310720, 5); +f(1835008, 7); +f(2097152, 8); +f(2359296, 9); +f(3932160, 15); +f(4194304, 16); +f(4456448, 17); +f(8126464, 31); +f(8388608, 32); +f(8650752, 33); +f(16515072, 63); +f(16777216, 64); +f(17039360, 65); +f(33292288, 127); +f(33554432, 128); +f(33816576, 129); +f(66846720, 255); +f(67108864, 256); +f(67371008, 257); +f(133955584, 511); +f(134217728, 512); +f(134479872, 513); +f(268173312, 1023); +f(268435456, 1024); +f(268697600, 1025); +f(536608768, 2047); +f(536870912, 2048); +f(537133056, 2049); +f(1073479680, 4095); +f(1073741824, 4096); +f(1074003968, 4097); +f(2147221504, 8191); +f(2147483648, 8192); +f(2147745792, 8193); +f(4294705152, 16383); +f(4294967296, 16384); +f(4295229440, 16385); +f(8589672448, 32767); +f(8589934592, 32768); +f(8590196736, 32769); +f(17179607040, 65535); +f(17179869184, 65536); +f(17180131328, 65537); +f(34359476224, 131071); +f(34359738368, 131072); +f(34360000512, 131073); +f(68719214592, 262143); +f(68719476736, 262144); +x = 262145; +f(0, 0); +f(262145, 1); +f(524290, 2); +f(786435, 3); +f(1048580, 4); +f(1310725, 5); +f(1835015, 7); +f(2097160, 8); +f(2359305, 9); +f(3932175, 15); +f(4194320, 16); +f(4456465, 17); +f(8126495, 31); +f(8388640, 32); +f(8650785, 33); +f(16515135, 63); +f(16777280, 64); +f(17039425, 65); +f(33292415, 127); +f(33554560, 128); +f(33816705, 129); +f(66846975, 255); +f(67109120, 256); +f(67371265, 257); +f(133956095, 511); +f(134218240, 512); +f(134480385, 513); +f(268174335, 1023); +f(268436480, 1024); +f(268698625, 1025); +f(536610815, 2047); +f(536872960, 2048); +f(537135105, 2049); +f(1073483775, 4095); +f(1073745920, 4096); +f(1074008065, 4097); +f(2147229695, 8191); +f(2147491840, 8192); +f(2147753985, 8193); +f(4294721535, 16383); +f(4294983680, 16384); +f(4295245825, 16385); +f(8589705215, 32767); +f(8589967360, 32768); +f(8590229505, 32769); +f(17179672575, 65535); +f(17179934720, 65536); +f(17180196865, 65537); +f(34359607295, 131071); +f(34359869440, 131072); +f(34360131585, 131073); +f(68719476735, 262143); +f(68719738880, 262144); +f(68720001025, 262145); +x = 524287; +f(0, 0); +f(524287, 1); +f(1048574, 2); +f(1572861, 3); +f(2097148, 4); +f(2621435, 5); +f(3670009, 7); +f(4194296, 8); +f(4718583, 9); +f(7864305, 15); +f(8388592, 16); +f(8912879, 17); +f(16252897, 31); +f(16777184, 32); +f(17301471, 33); +f(33030081, 63); +f(33554368, 64); +f(34078655, 65); +f(66584449, 127); +f(67108736, 128); +f(67633023, 129); +f(133693185, 255); +f(134217472, 256); +f(134741759, 257); +f(267910657, 511); +f(268434944, 512); +f(268959231, 513); +f(536345601, 1023); +f(536869888, 1024); +f(537394175, 1025); +f(1073215489, 2047); +f(1073739776, 2048); +f(1074264063, 2049); +f(2146955265, 4095); +f(2147479552, 4096); +f(2148003839, 4097); +f(4294434817, 8191); +f(4294959104, 8192); +f(4295483391, 8193); +f(8589393921, 16383); +f(8589918208, 16384); +f(8590442495, 16385); +f(17179312129, 32767); +f(17179836416, 32768); +f(17180360703, 32769); +f(34359148545, 65535); +f(34359672832, 65536); +f(34360197119, 65537); +f(68718821377, 131071); +f(68719345664, 131072); +f(68719869951, 131073); +f(137438167041, 262143); +f(137438691328, 262144); +f(137439215615, 262145); +f(274876858369, 524287); +x = 524288; +f(0, 0); +f(524288, 1); +f(1048576, 2); +f(1572864, 3); +f(2097152, 4); +f(2621440, 5); +f(3670016, 7); +f(4194304, 8); +f(4718592, 9); +f(7864320, 15); +f(8388608, 16); +f(8912896, 17); +f(16252928, 31); +f(16777216, 32); +f(17301504, 33); +f(33030144, 63); +f(33554432, 64); +f(34078720, 65); +f(66584576, 127); +f(67108864, 128); +f(67633152, 129); +f(133693440, 255); +f(134217728, 256); +f(134742016, 257); +f(267911168, 511); +f(268435456, 512); +f(268959744, 513); +f(536346624, 1023); +f(536870912, 1024); +f(537395200, 1025); +f(1073217536, 2047); +f(1073741824, 2048); +f(1074266112, 2049); +f(2146959360, 4095); +f(2147483648, 4096); +f(2148007936, 4097); +f(4294443008, 8191); +f(4294967296, 8192); +f(4295491584, 8193); +f(8589410304, 16383); +f(8589934592, 16384); +f(8590458880, 16385); +f(17179344896, 32767); +f(17179869184, 32768); +f(17180393472, 32769); +f(34359214080, 65535); +f(34359738368, 65536); +f(34360262656, 65537); +f(68718952448, 131071); +f(68719476736, 131072); +f(68720001024, 131073); +f(137438429184, 262143); +f(137438953472, 262144); +f(137439477760, 262145); +f(274877382656, 524287); +f(274877906944, 524288); +x = 524289; +f(0, 0); +f(524289, 1); +f(1048578, 2); +f(1572867, 3); +f(2097156, 4); +f(2621445, 5); +f(3670023, 7); +f(4194312, 8); +f(4718601, 9); +f(7864335, 15); +f(8388624, 16); +f(8912913, 17); +f(16252959, 31); +f(16777248, 32); +f(17301537, 33); +f(33030207, 63); +f(33554496, 64); +f(34078785, 65); +f(66584703, 127); +f(67108992, 128); +f(67633281, 129); +f(133693695, 255); +f(134217984, 256); +f(134742273, 257); +f(267911679, 511); +f(268435968, 512); +f(268960257, 513); +f(536347647, 1023); +f(536871936, 1024); +f(537396225, 1025); +f(1073219583, 2047); +f(1073743872, 2048); +f(1074268161, 2049); +f(2146963455, 4095); +f(2147487744, 4096); +f(2148012033, 4097); +f(4294451199, 8191); +f(4294975488, 8192); +f(4295499777, 8193); +f(8589426687, 16383); +f(8589950976, 16384); +f(8590475265, 16385); +f(17179377663, 32767); +f(17179901952, 32768); +f(17180426241, 32769); +f(34359279615, 65535); +f(34359803904, 65536); +f(34360328193, 65537); +f(68719083519, 131071); +f(68719607808, 131072); +f(68720132097, 131073); +f(137438691327, 262143); +f(137439215616, 262144); +f(137439739905, 262145); +f(274877906943, 524287); +f(274878431232, 524288); +f(274878955521, 524289); +x = 1048575; +f(0, 0); +f(1048575, 1); +f(2097150, 2); +f(3145725, 3); +f(4194300, 4); +f(5242875, 5); +f(7340025, 7); +f(8388600, 8); +f(9437175, 9); +f(15728625, 15); +f(16777200, 16); +f(17825775, 17); +f(32505825, 31); +f(33554400, 32); +f(34602975, 33); +f(66060225, 63); +f(67108800, 64); +f(68157375, 65); +f(133169025, 127); +f(134217600, 128); +f(135266175, 129); +f(267386625, 255); +f(268435200, 256); +f(269483775, 257); +f(535821825, 511); +f(536870400, 512); +f(537918975, 513); +f(1072692225, 1023); +f(1073740800, 1024); +f(1074789375, 1025); +f(2146433025, 2047); +f(2147481600, 2048); +f(2148530175, 2049); +f(4293914625, 4095); +f(4294963200, 4096); +f(4296011775, 4097); +f(8588877825, 8191); +f(8589926400, 8192); +f(8590974975, 8193); +f(17178804225, 16383); +f(17179852800, 16384); +f(17180901375, 16385); +f(34358657025, 32767); +f(34359705600, 32768); +f(34360754175, 32769); +f(68718362625, 65535); +f(68719411200, 65536); +f(68720459775, 65537); +f(137437773825, 131071); +f(137438822400, 131072); +f(137439870975, 131073); +f(274876596225, 262143); +f(274877644800, 262144); +f(274878693375, 262145); +f(549754241025, 524287); +f(549755289600, 524288); +f(549756338175, 524289); +f(1099509530625, 1048575); +x = 1048576; +f(0, 0); +f(1048576, 1); +f(2097152, 2); +f(3145728, 3); +f(4194304, 4); +f(5242880, 5); +f(7340032, 7); +f(8388608, 8); +f(9437184, 9); +f(15728640, 15); +f(16777216, 16); +f(17825792, 17); +f(32505856, 31); +f(33554432, 32); +f(34603008, 33); +f(66060288, 63); +f(67108864, 64); +f(68157440, 65); +f(133169152, 127); +f(134217728, 128); +f(135266304, 129); +f(267386880, 255); +f(268435456, 256); +f(269484032, 257); +f(535822336, 511); +f(536870912, 512); +f(537919488, 513); +f(1072693248, 1023); +f(1073741824, 1024); +f(1074790400, 1025); +f(2146435072, 2047); +f(2147483648, 2048); +f(2148532224, 2049); +f(4293918720, 4095); +f(4294967296, 4096); +f(4296015872, 4097); +f(8588886016, 8191); +f(8589934592, 8192); +f(8590983168, 8193); +f(17178820608, 16383); +f(17179869184, 16384); +f(17180917760, 16385); +f(34358689792, 32767); +f(34359738368, 32768); +f(34360786944, 32769); +f(68718428160, 65535); +f(68719476736, 65536); +f(68720525312, 65537); +f(137437904896, 131071); +f(137438953472, 131072); +f(137440002048, 131073); +f(274876858368, 262143); +f(274877906944, 262144); +f(274878955520, 262145); +f(549754765312, 524287); +f(549755813888, 524288); +f(549756862464, 524289); +f(1099510579200, 1048575); +f(1099511627776, 1048576); diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part5.js b/deps/v8/test/mjsunit/mul-exhaustive-part5.js new file mode 100644 index 0000000000..e92998575b --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part5.js @@ -0,0 +1,505 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 1048577; +f(0, 0); +f(1048577, 1); +f(2097154, 2); +f(3145731, 3); +f(4194308, 4); +f(5242885, 5); +f(7340039, 7); +f(8388616, 8); +f(9437193, 9); +f(15728655, 15); +f(16777232, 16); +f(17825809, 17); +f(32505887, 31); +f(33554464, 32); +f(34603041, 33); +f(66060351, 63); +f(67108928, 64); +f(68157505, 65); +f(133169279, 127); +f(134217856, 128); +f(135266433, 129); +f(267387135, 255); +f(268435712, 256); +f(269484289, 257); +f(535822847, 511); +f(536871424, 512); +f(537920001, 513); +f(1072694271, 1023); +f(1073742848, 1024); +f(1074791425, 1025); +f(2146437119, 2047); +f(2147485696, 2048); +f(2148534273, 2049); +f(4293922815, 4095); +f(4294971392, 4096); +f(4296019969, 4097); +f(8588894207, 8191); +f(8589942784, 8192); +f(8590991361, 8193); +f(17178836991, 16383); +f(17179885568, 16384); +f(17180934145, 16385); +f(34358722559, 32767); +f(34359771136, 32768); +f(34360819713, 32769); +f(68718493695, 65535); +f(68719542272, 65536); +f(68720590849, 65537); +f(137438035967, 131071); +f(137439084544, 131072); +f(137440133121, 131073); +f(274877120511, 262143); +f(274878169088, 262144); +f(274879217665, 262145); +f(549755289599, 524287); +f(549756338176, 524288); +f(549757386753, 524289); +f(1099511627775, 1048575); +f(1099512676352, 1048576); +f(1099513724929, 1048577); +x = 2097151; +f(0, 0); +f(2097151, 1); +f(4194302, 2); +f(6291453, 3); +f(8388604, 4); +f(10485755, 5); +f(14680057, 7); +f(16777208, 8); +f(18874359, 9); +f(31457265, 15); +f(33554416, 16); +f(35651567, 17); +f(65011681, 31); +f(67108832, 32); +f(69205983, 33); +f(132120513, 63); +f(134217664, 64); +f(136314815, 65); +f(266338177, 127); +f(268435328, 128); +f(270532479, 129); +f(534773505, 255); +f(536870656, 256); +f(538967807, 257); +f(1071644161, 511); +f(1073741312, 512); +f(1075838463, 513); +f(2145385473, 1023); +f(2147482624, 1024); +f(2149579775, 1025); +f(4292868097, 2047); +f(4294965248, 2048); +f(4297062399, 2049); +f(8587833345, 4095); +f(8589930496, 4096); +f(8592027647, 4097); +f(17177763841, 8191); +f(17179860992, 8192); +f(17181958143, 8193); +f(34357624833, 16383); +f(34359721984, 16384); +f(34361819135, 16385); +f(68717346817, 32767); +f(68719443968, 32768); +f(68721541119, 32769); +f(137436790785, 65535); +f(137438887936, 65536); +f(137440985087, 65537); +f(274875678721, 131071); +f(274877775872, 131072); +f(274879873023, 131073); +f(549753454593, 262143); +f(549755551744, 262144); +f(549757648895, 262145); +f(1099509006337, 524287); +f(1099511103488, 524288); +f(1099513200639, 524289); +f(2199020109825, 1048575); +f(2199022206976, 1048576); +f(2199024304127, 1048577); +f(4398042316801, 2097151); +x = 2097152; +f(0, 0); +f(2097152, 1); +f(4194304, 2); +f(6291456, 3); +f(8388608, 4); +f(10485760, 5); +f(14680064, 7); +f(16777216, 8); +f(18874368, 9); +f(31457280, 15); +f(33554432, 16); +f(35651584, 17); +f(65011712, 31); +f(67108864, 32); +f(69206016, 33); +f(132120576, 63); +f(134217728, 64); +f(136314880, 65); +f(266338304, 127); +f(268435456, 128); +f(270532608, 129); +f(534773760, 255); +f(536870912, 256); +f(538968064, 257); +f(1071644672, 511); +f(1073741824, 512); +f(1075838976, 513); +f(2145386496, 1023); +f(2147483648, 1024); +f(2149580800, 1025); +f(4292870144, 2047); +f(4294967296, 2048); +f(4297064448, 2049); +f(8587837440, 4095); +f(8589934592, 4096); +f(8592031744, 4097); +f(17177772032, 8191); +f(17179869184, 8192); +f(17181966336, 8193); +f(34357641216, 16383); +f(34359738368, 16384); +f(34361835520, 16385); +f(68717379584, 32767); +f(68719476736, 32768); +f(68721573888, 32769); +f(137436856320, 65535); +f(137438953472, 65536); +f(137441050624, 65537); +f(274875809792, 131071); +f(274877906944, 131072); +f(274880004096, 131073); +f(549753716736, 262143); +f(549755813888, 262144); +f(549757911040, 262145); +f(1099509530624, 524287); +f(1099511627776, 524288); +f(1099513724928, 524289); +f(2199021158400, 1048575); +f(2199023255552, 1048576); +f(2199025352704, 1048577); +f(4398044413952, 2097151); +f(4398046511104, 2097152); +x = 2097153; +f(0, 0); +f(2097153, 1); +f(4194306, 2); +f(6291459, 3); +f(8388612, 4); +f(10485765, 5); +f(14680071, 7); +f(16777224, 8); +f(18874377, 9); +f(31457295, 15); +f(33554448, 16); +f(35651601, 17); +f(65011743, 31); +f(67108896, 32); +f(69206049, 33); +f(132120639, 63); +f(134217792, 64); +f(136314945, 65); +f(266338431, 127); +f(268435584, 128); +f(270532737, 129); +f(534774015, 255); +f(536871168, 256); +f(538968321, 257); +f(1071645183, 511); +f(1073742336, 512); +f(1075839489, 513); +f(2145387519, 1023); +f(2147484672, 1024); +f(2149581825, 1025); +f(4292872191, 2047); +f(4294969344, 2048); +f(4297066497, 2049); +f(8587841535, 4095); +f(8589938688, 4096); +f(8592035841, 4097); +f(17177780223, 8191); +f(17179877376, 8192); +f(17181974529, 8193); +f(34357657599, 16383); +f(34359754752, 16384); +f(34361851905, 16385); +f(68717412351, 32767); +f(68719509504, 32768); +f(68721606657, 32769); +f(137436921855, 65535); +f(137439019008, 65536); +f(137441116161, 65537); +f(274875940863, 131071); +f(274878038016, 131072); +f(274880135169, 131073); +f(549753978879, 262143); +f(549756076032, 262144); +f(549758173185, 262145); +f(1099510054911, 524287); +f(1099512152064, 524288); +f(1099514249217, 524289); +f(2199022206975, 1048575); +f(2199024304128, 1048576); +f(2199026401281, 1048577); +f(4398046511103, 2097151); +f(4398048608256, 2097152); +f(4398050705409, 2097153); +x = 4194303; +f(0, 0); +f(4194303, 1); +f(8388606, 2); +f(12582909, 3); +f(16777212, 4); +f(20971515, 5); +f(29360121, 7); +f(33554424, 8); +f(37748727, 9); +f(62914545, 15); +f(67108848, 16); +f(71303151, 17); +f(130023393, 31); +f(134217696, 32); +f(138411999, 33); +f(264241089, 63); +f(268435392, 64); +f(272629695, 65); +f(532676481, 127); +f(536870784, 128); +f(541065087, 129); +f(1069547265, 255); +f(1073741568, 256); +f(1077935871, 257); +f(2143288833, 511); +f(2147483136, 512); +f(2151677439, 513); +f(4290771969, 1023); +f(4294966272, 1024); +f(4299160575, 1025); +f(8585738241, 2047); +f(8589932544, 2048); +f(8594126847, 2049); +f(17175670785, 4095); +f(17179865088, 4096); +f(17184059391, 4097); +f(34355535873, 8191); +f(34359730176, 8192); +f(34363924479, 8193); +f(68715266049, 16383); +f(68719460352, 16384); +f(68723654655, 16385); +f(137434726401, 32767); +f(137438920704, 32768); +f(137443115007, 32769); +f(274873647105, 65535); +f(274877841408, 65536); +f(274882035711, 65537); +f(549751488513, 131071); +f(549755682816, 131072); +f(549759877119, 131073); +f(1099507171329, 262143); +f(1099511365632, 262144); +f(1099515559935, 262145); +f(2199018536961, 524287); +f(2199022731264, 524288); +f(2199026925567, 524289); +f(4398041268225, 1048575); +f(4398045462528, 1048576); +f(4398049656831, 1048577); +f(8796086730753, 2097151); +f(8796090925056, 2097152); +f(8796095119359, 2097153); +f(17592177655809, 4194303); +x = 4194304; +f(0, 0); +f(4194304, 1); +f(8388608, 2); +f(12582912, 3); +f(16777216, 4); +f(20971520, 5); +f(29360128, 7); +f(33554432, 8); +f(37748736, 9); +f(62914560, 15); +f(67108864, 16); +f(71303168, 17); +f(130023424, 31); +f(134217728, 32); +f(138412032, 33); +f(264241152, 63); +f(268435456, 64); +f(272629760, 65); +f(532676608, 127); +f(536870912, 128); +f(541065216, 129); +f(1069547520, 255); +f(1073741824, 256); +f(1077936128, 257); +f(2143289344, 511); +f(2147483648, 512); +f(2151677952, 513); +f(4290772992, 1023); +f(4294967296, 1024); +f(4299161600, 1025); +f(8585740288, 2047); +f(8589934592, 2048); +f(8594128896, 2049); +f(17175674880, 4095); +f(17179869184, 4096); +f(17184063488, 4097); +f(34355544064, 8191); +f(34359738368, 8192); +f(34363932672, 8193); +f(68715282432, 16383); +f(68719476736, 16384); +f(68723671040, 16385); +f(137434759168, 32767); +f(137438953472, 32768); +f(137443147776, 32769); +f(274873712640, 65535); +f(274877906944, 65536); +f(274882101248, 65537); +f(549751619584, 131071); +f(549755813888, 131072); +f(549760008192, 131073); +f(1099507433472, 262143); +f(1099511627776, 262144); +f(1099515822080, 262145); +f(2199019061248, 524287); +f(2199023255552, 524288); +f(2199027449856, 524289); +f(4398042316800, 1048575); +f(4398046511104, 1048576); +f(4398050705408, 1048577); +f(8796088827904, 2097151); +f(8796093022208, 2097152); +f(8796097216512, 2097153); +f(17592181850112, 4194303); +f(17592186044416, 4194304); +x = 4194305; +f(0, 0); +f(4194305, 1); +f(8388610, 2); +f(12582915, 3); +f(16777220, 4); +f(20971525, 5); +f(29360135, 7); +f(33554440, 8); +f(37748745, 9); +f(62914575, 15); +f(67108880, 16); +f(71303185, 17); +f(130023455, 31); +f(134217760, 32); +f(138412065, 33); +f(264241215, 63); +f(268435520, 64); +f(272629825, 65); +f(532676735, 127); +f(536871040, 128); +f(541065345, 129); +f(1069547775, 255); +f(1073742080, 256); +f(1077936385, 257); +f(2143289855, 511); +f(2147484160, 512); +f(2151678465, 513); +f(4290774015, 1023); +f(4294968320, 1024); +f(4299162625, 1025); +f(8585742335, 2047); +f(8589936640, 2048); +f(8594130945, 2049); +f(17175678975, 4095); +f(17179873280, 4096); +f(17184067585, 4097); +f(34355552255, 8191); +f(34359746560, 8192); +f(34363940865, 8193); +f(68715298815, 16383); +f(68719493120, 16384); +f(68723687425, 16385); +f(137434791935, 32767); +f(137438986240, 32768); +f(137443180545, 32769); +f(274873778175, 65535); +f(274877972480, 65536); +f(274882166785, 65537); +f(549751750655, 131071); +f(549755944960, 131072); +f(549760139265, 131073); +f(1099507695615, 262143); +f(1099511889920, 262144); +f(1099516084225, 262145); +f(2199019585535, 524287); +f(2199023779840, 524288); +f(2199027974145, 524289); +f(4398043365375, 1048575); +f(4398047559680, 1048576); +f(4398051753985, 1048577); +f(8796090925055, 2097151); +f(8796095119360, 2097152); +f(8796099313665, 2097153); +f(17592186044415, 4194303); +f(17592190238720, 4194304); +f(17592194433025, 4194305); diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part6.js b/deps/v8/test/mjsunit/mul-exhaustive-part6.js new file mode 100644 index 0000000000..91cb798a7d --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part6.js @@ -0,0 +1,554 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 8388607; +f(0, 0); +f(8388607, 1); +f(16777214, 2); +f(25165821, 3); +f(33554428, 4); +f(41943035, 5); +f(58720249, 7); +f(67108856, 8); +f(75497463, 9); +f(125829105, 15); +f(134217712, 16); +f(142606319, 17); +f(260046817, 31); +f(268435424, 32); +f(276824031, 33); +f(528482241, 63); +f(536870848, 64); +f(545259455, 65); +f(1065353089, 127); +f(1073741696, 128); +f(1082130303, 129); +f(2139094785, 255); +f(2147483392, 256); +f(2155871999, 257); +f(4286578177, 511); +f(4294966784, 512); +f(4303355391, 513); +f(8581544961, 1023); +f(8589933568, 1024); +f(8598322175, 1025); +f(17171478529, 2047); +f(17179867136, 2048); +f(17188255743, 2049); +f(34351345665, 4095); +f(34359734272, 4096); +f(34368122879, 4097); +f(68711079937, 8191); +f(68719468544, 8192); +f(68727857151, 8193); +f(137430548481, 16383); +f(137438937088, 16384); +f(137447325695, 16385); +f(274869485569, 32767); +f(274877874176, 32768); +f(274886262783, 32769); +f(549747359745, 65535); +f(549755748352, 65536); +f(549764136959, 65537); +f(1099503108097, 131071); +f(1099511496704, 131072); +f(1099519885311, 131073); +f(2199014604801, 262143); +f(2199022993408, 262144); +f(2199031382015, 262145); +f(4398037598209, 524287); +f(4398045986816, 524288); +f(4398054375423, 524289); +f(8796083585025, 1048575); +f(8796091973632, 1048576); +f(8796100362239, 1048577); +f(17592175558657, 2097151); +f(17592183947264, 2097152); +f(17592192335871, 2097153); +f(35184359505921, 4194303); +f(35184367894528, 4194304); +f(35184376283135, 4194305); +f(70368727400449, 8388607); +x = 8388608; +f(0, 0); +f(8388608, 1); +f(16777216, 2); +f(25165824, 3); +f(33554432, 4); +f(41943040, 5); +f(58720256, 7); +f(67108864, 8); +f(75497472, 9); +f(125829120, 15); +f(134217728, 16); +f(142606336, 17); +f(260046848, 31); +f(268435456, 32); +f(276824064, 33); +f(528482304, 63); +f(536870912, 64); +f(545259520, 65); +f(1065353216, 127); +f(1073741824, 128); +f(1082130432, 129); +f(2139095040, 255); +f(2147483648, 256); +f(2155872256, 257); +f(4286578688, 511); +f(4294967296, 512); +f(4303355904, 513); +f(8581545984, 1023); +f(8589934592, 1024); +f(8598323200, 1025); +f(17171480576, 2047); +f(17179869184, 2048); +f(17188257792, 2049); +f(34351349760, 4095); +f(34359738368, 4096); +f(34368126976, 4097); +f(68711088128, 8191); +f(68719476736, 8192); +f(68727865344, 8193); +f(137430564864, 16383); +f(137438953472, 16384); +f(137447342080, 16385); +f(274869518336, 32767); +f(274877906944, 32768); +f(274886295552, 32769); +f(549747425280, 65535); +f(549755813888, 65536); +f(549764202496, 65537); +f(1099503239168, 131071); +f(1099511627776, 131072); +f(1099520016384, 131073); +f(2199014866944, 262143); +f(2199023255552, 262144); +f(2199031644160, 262145); +f(4398038122496, 524287); +f(4398046511104, 524288); +f(4398054899712, 524289); +f(8796084633600, 1048575); +f(8796093022208, 1048576); +f(8796101410816, 1048577); +f(17592177655808, 2097151); +f(17592186044416, 2097152); +f(17592194433024, 2097153); +f(35184363700224, 4194303); +f(35184372088832, 4194304); +f(35184380477440, 4194305); +f(70368735789056, 8388607); +f(70368744177664, 8388608); +x = 8388609; +f(0, 0); +f(8388609, 1); +f(16777218, 2); +f(25165827, 3); +f(33554436, 4); +f(41943045, 5); +f(58720263, 7); +f(67108872, 8); +f(75497481, 9); +f(125829135, 15); +f(134217744, 16); +f(142606353, 17); +f(260046879, 31); +f(268435488, 32); +f(276824097, 33); +f(528482367, 63); +f(536870976, 64); +f(545259585, 65); +f(1065353343, 127); +f(1073741952, 128); +f(1082130561, 129); +f(2139095295, 255); +f(2147483904, 256); +f(2155872513, 257); +f(4286579199, 511); +f(4294967808, 512); +f(4303356417, 513); +f(8581547007, 1023); +f(8589935616, 1024); +f(8598324225, 1025); +f(17171482623, 2047); +f(17179871232, 2048); +f(17188259841, 2049); +f(34351353855, 4095); +f(34359742464, 4096); +f(34368131073, 4097); +f(68711096319, 8191); +f(68719484928, 8192); +f(68727873537, 8193); +f(137430581247, 16383); +f(137438969856, 16384); +f(137447358465, 16385); +f(274869551103, 32767); +f(274877939712, 32768); +f(274886328321, 32769); +f(549747490815, 65535); +f(549755879424, 65536); +f(549764268033, 65537); +f(1099503370239, 131071); +f(1099511758848, 131072); +f(1099520147457, 131073); +f(2199015129087, 262143); +f(2199023517696, 262144); +f(2199031906305, 262145); +f(4398038646783, 524287); +f(4398047035392, 524288); +f(4398055424001, 524289); +f(8796085682175, 1048575); +f(8796094070784, 1048576); +f(8796102459393, 1048577); +f(17592179752959, 2097151); +f(17592188141568, 2097152); +f(17592196530177, 2097153); +f(35184367894527, 4194303); +f(35184376283136, 4194304); +f(35184384671745, 4194305); +f(70368744177663, 8388607); +f(70368752566272, 8388608); +f(70368760954881, 8388609); +x = 16777215; +f(0, 0); +f(16777215, 1); +f(33554430, 2); +f(50331645, 3); +f(67108860, 4); +f(83886075, 5); +f(117440505, 7); +f(134217720, 8); +f(150994935, 9); +f(251658225, 15); +f(268435440, 16); +f(285212655, 17); +f(520093665, 31); +f(536870880, 32); +f(553648095, 33); +f(1056964545, 63); +f(1073741760, 64); +f(1090518975, 65); +f(2130706305, 127); +f(2147483520, 128); +f(2164260735, 129); +f(4278189825, 255); +f(4294967040, 256); +f(4311744255, 257); +f(8573156865, 511); +f(8589934080, 512); +f(8606711295, 513); +f(17163090945, 1023); +f(17179868160, 1024); +f(17196645375, 1025); +f(34342959105, 2047); +f(34359736320, 2048); +f(34376513535, 2049); +f(68702695425, 4095); +f(68719472640, 4096); +f(68736249855, 4097); +f(137422168065, 8191); +f(137438945280, 8192); +f(137455722495, 8193); +f(274861113345, 16383); +f(274877890560, 16384); +f(274894667775, 16385); +f(549739003905, 32767); +f(549755781120, 32768); +f(549772558335, 32769); +f(1099494785025, 65535); +f(1099511562240, 65536); +f(1099528339455, 65537); +f(2199006347265, 131071); +f(2199023124480, 131072); +f(2199039901695, 131073); +f(4398029471745, 262143); +f(4398046248960, 262144); +f(4398063026175, 262145); +f(8796075720705, 524287); +f(8796092497920, 524288); +f(8796109275135, 524289); +f(17592168218625, 1048575); +f(17592184995840, 1048576); +f(17592201773055, 1048577); +f(35184353214465, 2097151); +f(35184369991680, 2097152); +f(35184386768895, 2097153); +f(70368723206145, 4194303); +f(70368739983360, 4194304); +f(70368756760575, 4194305); +f(140737463189505, 8388607); +f(140737479966720, 8388608); +f(140737496743935, 8388609); +f(281474943156225, 16777215); +x = 16777216; +f(0, 0); +f(16777216, 1); +f(33554432, 2); +f(50331648, 3); +f(67108864, 4); +f(83886080, 5); +f(117440512, 7); +f(134217728, 8); +f(150994944, 9); +f(251658240, 15); +f(268435456, 16); +f(285212672, 17); +f(520093696, 31); +f(536870912, 32); +f(553648128, 33); +f(1056964608, 63); +f(1073741824, 64); +f(1090519040, 65); +f(2130706432, 127); +f(2147483648, 128); +f(2164260864, 129); +f(4278190080, 255); +f(4294967296, 256); +f(4311744512, 257); +f(8573157376, 511); +f(8589934592, 512); +f(8606711808, 513); +f(17163091968, 1023); +f(17179869184, 1024); +f(17196646400, 1025); +f(34342961152, 2047); +f(34359738368, 2048); +f(34376515584, 2049); +f(68702699520, 4095); +f(68719476736, 4096); +f(68736253952, 4097); +f(137422176256, 8191); +f(137438953472, 8192); +f(137455730688, 8193); +f(274861129728, 16383); +f(274877906944, 16384); +f(274894684160, 16385); +f(549739036672, 32767); +f(549755813888, 32768); +f(549772591104, 32769); +f(1099494850560, 65535); +f(1099511627776, 65536); +f(1099528404992, 65537); +f(2199006478336, 131071); +f(2199023255552, 131072); +f(2199040032768, 131073); +f(4398029733888, 262143); +f(4398046511104, 262144); +f(4398063288320, 262145); +f(8796076244992, 524287); +f(8796093022208, 524288); +f(8796109799424, 524289); +f(17592169267200, 1048575); +f(17592186044416, 1048576); +f(17592202821632, 1048577); +f(35184355311616, 2097151); +f(35184372088832, 2097152); +f(35184388866048, 2097153); +f(70368727400448, 4194303); +f(70368744177664, 4194304); +f(70368760954880, 4194305); +f(140737471578112, 8388607); +f(140737488355328, 8388608); +f(140737505132544, 8388609); +f(281474959933440, 16777215); +f(281474976710656, 16777216); +x = 16777217; +f(0, 0); +f(16777217, 1); +f(33554434, 2); +f(50331651, 3); +f(67108868, 4); +f(83886085, 5); +f(117440519, 7); +f(134217736, 8); +f(150994953, 9); +f(251658255, 15); +f(268435472, 16); +f(285212689, 17); +f(520093727, 31); +f(536870944, 32); +f(553648161, 33); +f(1056964671, 63); +f(1073741888, 64); +f(1090519105, 65); +f(2130706559, 127); +f(2147483776, 128); +f(2164260993, 129); +f(4278190335, 255); +f(4294967552, 256); +f(4311744769, 257); +f(8573157887, 511); +f(8589935104, 512); +f(8606712321, 513); +f(17163092991, 1023); +f(17179870208, 1024); +f(17196647425, 1025); +f(34342963199, 2047); +f(34359740416, 2048); +f(34376517633, 2049); +f(68702703615, 4095); +f(68719480832, 4096); +f(68736258049, 4097); +f(137422184447, 8191); +f(137438961664, 8192); +f(137455738881, 8193); +f(274861146111, 16383); +f(274877923328, 16384); +f(274894700545, 16385); +f(549739069439, 32767); +f(549755846656, 32768); +f(549772623873, 32769); +f(1099494916095, 65535); +f(1099511693312, 65536); +f(1099528470529, 65537); +f(2199006609407, 131071); +f(2199023386624, 131072); +f(2199040163841, 131073); +f(4398029996031, 262143); +f(4398046773248, 262144); +f(4398063550465, 262145); +f(8796076769279, 524287); +f(8796093546496, 524288); +f(8796110323713, 524289); +f(17592170315775, 1048575); +f(17592187092992, 1048576); +f(17592203870209, 1048577); +f(35184357408767, 2097151); +f(35184374185984, 2097152); +f(35184390963201, 2097153); +f(70368731594751, 4194303); +f(70368748371968, 4194304); +f(70368765149185, 4194305); +f(140737479966719, 8388607); +f(140737496743936, 8388608); +f(140737513521153, 8388609); +f(281474976710655, 16777215); +f(281474993487872, 16777216); +f(281475010265089, 16777217); +x = 33554431; +f(0, 0); +f(33554431, 1); +f(67108862, 2); +f(100663293, 3); +f(134217724, 4); +f(167772155, 5); +f(234881017, 7); +f(268435448, 8); +f(301989879, 9); +f(503316465, 15); +f(536870896, 16); +f(570425327, 17); +f(1040187361, 31); +f(1073741792, 32); +f(1107296223, 33); +f(2113929153, 63); +f(2147483584, 64); +f(2181038015, 65); +f(4261412737, 127); +f(4294967168, 128); +f(4328521599, 129); +f(8556379905, 255); +f(8589934336, 256); +f(8623488767, 257); +f(17146314241, 511); +f(17179868672, 512); +f(17213423103, 513); +f(34326182913, 1023); +f(34359737344, 1024); +f(34393291775, 1025); +f(68685920257, 2047); +f(68719474688, 2048); +f(68753029119, 2049); +f(137405394945, 4095); +f(137438949376, 4096); +f(137472503807, 4097); +f(274844344321, 8191); +f(274877898752, 8192); +f(274911453183, 8193); +f(549722243073, 16383); +f(549755797504, 16384); +f(549789351935, 16385); +f(1099478040577, 32767); +f(1099511595008, 32768); +f(1099545149439, 32769); +f(2198989635585, 65535); +f(2199023190016, 65536); +f(2199056744447, 65537); +f(4398012825601, 131071); +f(4398046380032, 131072); +f(4398079934463, 131073); +f(8796059205633, 262143); +f(8796092760064, 262144); +f(8796126314495, 262145); +f(17592151965697, 524287); +f(17592185520128, 524288); +f(17592219074559, 524289); +f(35184337485825, 1048575); +f(35184371040256, 1048576); +f(35184404594687, 1048577); +f(70368708526081, 2097151); +f(70368742080512, 2097152); +f(70368775634943, 2097153); +f(140737450606593, 4194303); +f(140737484161024, 4194304); +f(140737517715455, 4194305); +f(281474934767617, 8388607); +f(281474968322048, 8388608); +f(281475001876479, 8388609); +f(562949903089665, 16777215); +f(562949936644096, 16777216); +f(562949970198527, 16777217); +f(1125899839733761, 33554431);
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part7.js b/deps/v8/test/mjsunit/mul-exhaustive-part7.js new file mode 100644 index 0000000000..d517225e7c --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part7.js @@ -0,0 +1,497 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 33554432; +f(0, 0); +f(33554432, 1); +f(67108864, 2); +f(100663296, 3); +f(134217728, 4); +f(167772160, 5); +f(234881024, 7); +f(268435456, 8); +f(301989888, 9); +f(503316480, 15); +f(536870912, 16); +f(570425344, 17); +f(1040187392, 31); +f(1073741824, 32); +f(1107296256, 33); +f(2113929216, 63); +f(2147483648, 64); +f(2181038080, 65); +f(4261412864, 127); +f(4294967296, 128); +f(4328521728, 129); +f(8556380160, 255); +f(8589934592, 256); +f(8623489024, 257); +f(17146314752, 511); +f(17179869184, 512); +f(17213423616, 513); +f(34326183936, 1023); +f(34359738368, 1024); +f(34393292800, 1025); +f(68685922304, 2047); +f(68719476736, 2048); +f(68753031168, 2049); +f(137405399040, 4095); +f(137438953472, 4096); +f(137472507904, 4097); +f(274844352512, 8191); +f(274877906944, 8192); +f(274911461376, 8193); +f(549722259456, 16383); +f(549755813888, 16384); +f(549789368320, 16385); +f(1099478073344, 32767); +f(1099511627776, 32768); +f(1099545182208, 32769); +f(2198989701120, 65535); +f(2199023255552, 65536); +f(2199056809984, 65537); +f(4398012956672, 131071); +f(4398046511104, 131072); +f(4398080065536, 131073); +f(8796059467776, 262143); +f(8796093022208, 262144); +f(8796126576640, 262145); +f(17592152489984, 524287); +f(17592186044416, 524288); +f(17592219598848, 524289); +f(35184338534400, 1048575); +f(35184372088832, 1048576); +f(35184405643264, 1048577); +f(70368710623232, 2097151); +f(70368744177664, 2097152); +f(70368777732096, 2097153); +f(140737454800896, 4194303); +f(140737488355328, 4194304); +f(140737521909760, 4194305); +f(281474943156224, 8388607); +f(281474976710656, 8388608); +f(281475010265088, 8388609); +f(562949919866880, 16777215); +f(562949953421312, 16777216); +f(562949986975744, 16777217); +f(1125899873288192, 33554431); +f(1125899906842624, 33554432); +x = 33554433; +f(0, 0); +f(33554433, 1); +f(67108866, 2); +f(100663299, 3); +f(134217732, 4); +f(167772165, 5); +f(234881031, 7); +f(268435464, 8); +f(301989897, 9); +f(503316495, 15); +f(536870928, 16); +f(570425361, 17); +f(1040187423, 31); +f(1073741856, 32); +f(1107296289, 33); +f(2113929279, 63); +f(2147483712, 64); +f(2181038145, 65); +f(4261412991, 127); +f(4294967424, 128); +f(4328521857, 129); +f(8556380415, 255); +f(8589934848, 256); +f(8623489281, 257); +f(17146315263, 511); +f(17179869696, 512); +f(17213424129, 513); +f(34326184959, 1023); +f(34359739392, 1024); +f(34393293825, 1025); +f(68685924351, 2047); +f(68719478784, 2048); +f(68753033217, 2049); +f(137405403135, 4095); +f(137438957568, 4096); +f(137472512001, 4097); +f(274844360703, 8191); +f(274877915136, 8192); +f(274911469569, 8193); +f(549722275839, 16383); +f(549755830272, 16384); +f(549789384705, 16385); +f(1099478106111, 32767); +f(1099511660544, 32768); +f(1099545214977, 32769); +f(2198989766655, 65535); +f(2199023321088, 65536); +f(2199056875521, 65537); +f(4398013087743, 131071); +f(4398046642176, 131072); +f(4398080196609, 131073); +f(8796059729919, 262143); +f(8796093284352, 262144); +f(8796126838785, 262145); +f(17592153014271, 524287); +f(17592186568704, 524288); +f(17592220123137, 524289); +f(35184339582975, 1048575); +f(35184373137408, 1048576); +f(35184406691841, 1048577); +f(70368712720383, 2097151); +f(70368746274816, 2097152); +f(70368779829249, 2097153); +f(140737458995199, 4194303); +f(140737492549632, 4194304); +f(140737526104065, 4194305); +f(281474951544831, 8388607); +f(281474985099264, 8388608); +f(281475018653697, 8388609); +f(562949936644095, 16777215); +f(562949970198528, 16777216); +f(562950003752961, 16777217); +f(1125899906842623, 33554431); +f(1125899940397056, 33554432); +f(1125899973951489, 33554433); +x = 67108863; +f(0, 0); +f(67108863, 1); +f(134217726, 2); +f(201326589, 3); +f(268435452, 4); +f(335544315, 5); +f(469762041, 7); +f(536870904, 8); +f(603979767, 9); +f(1006632945, 15); +f(1073741808, 16); +f(1140850671, 17); +f(2080374753, 31); +f(2147483616, 32); +f(2214592479, 33); +f(4227858369, 63); +f(4294967232, 64); +f(4362076095, 65); +f(8522825601, 127); +f(8589934464, 128); +f(8657043327, 129); +f(17112760065, 255); +f(17179868928, 256); +f(17246977791, 257); +f(34292628993, 511); +f(34359737856, 512); +f(34426846719, 513); +f(68652366849, 1023); +f(68719475712, 1024); +f(68786584575, 1025); +f(137371842561, 2047); +f(137438951424, 2048); +f(137506060287, 2049); +f(274810793985, 4095); +f(274877902848, 4096); +f(274945011711, 4097); +f(549688696833, 8191); +f(549755805696, 8192); +f(549822914559, 8193); +f(1099444502529, 16383); +f(1099511611392, 16384); +f(1099578720255, 16385); +f(2198956113921, 32767); +f(2199023222784, 32768); +f(2199090331647, 32769); +f(4397979336705, 65535); +f(4398046445568, 65536); +f(4398113554431, 65537); +f(8796025782273, 131071); +f(8796092891136, 131072); +f(8796159999999, 131073); +f(17592118673409, 262143); +f(17592185782272, 262144); +f(17592252891135, 262145); +f(35184304455681, 524287); +f(35184371564544, 524288); +f(35184438673407, 524289); +f(70368676020225, 1048575); +f(70368743129088, 1048576); +f(70368810237951, 1048577); +f(140737419149313, 2097151); +f(140737486258176, 2097152); +f(140737553367039, 2097153); +f(281474905407489, 4194303); +f(281474972516352, 4194304); +f(281475039625215, 4194305); +f(562949877923841, 8388607); +f(562949945032704, 8388608); +f(562950012141567, 8388609); +f(1125899822956545, 16777215); +f(1125899890065408, 16777216); +f(1125899957174271, 16777217); +x = 67108864; +f(0, 0); +f(67108864, 1); +f(134217728, 2); +f(201326592, 3); +f(268435456, 4); +f(335544320, 5); +f(469762048, 7); +f(536870912, 8); +f(603979776, 9); +f(1006632960, 15); +f(1073741824, 16); +f(1140850688, 17); +f(2080374784, 31); +f(2147483648, 32); +f(2214592512, 33); +f(4227858432, 63); +f(4294967296, 64); +f(4362076160, 65); +f(8522825728, 127); +f(8589934592, 128); +f(8657043456, 129); +f(17112760320, 255); +f(17179869184, 256); +f(17246978048, 257); +f(34292629504, 511); +f(34359738368, 512); +f(34426847232, 513); +f(68652367872, 1023); +f(68719476736, 1024); +f(68786585600, 1025); +f(137371844608, 2047); +f(137438953472, 2048); +f(137506062336, 2049); +f(274810798080, 4095); +f(274877906944, 4096); +f(274945015808, 4097); +f(549688705024, 8191); +f(549755813888, 8192); +f(549822922752, 8193); +f(1099444518912, 16383); +f(1099511627776, 16384); +f(1099578736640, 16385); +f(2198956146688, 32767); +f(2199023255552, 32768); +f(2199090364416, 32769); +f(4397979402240, 65535); +f(4398046511104, 65536); +f(4398113619968, 65537); +f(8796025913344, 131071); +f(8796093022208, 131072); +f(8796160131072, 131073); +f(17592118935552, 262143); +f(17592186044416, 262144); +f(17592253153280, 262145); +f(35184304979968, 524287); +f(35184372088832, 524288); +f(35184439197696, 524289); +f(70368677068800, 1048575); +f(70368744177664, 1048576); +f(70368811286528, 1048577); +f(140737421246464, 2097151); +f(140737488355328, 2097152); +f(140737555464192, 2097153); +f(281474909601792, 4194303); +f(281474976710656, 4194304); +f(281475043819520, 4194305); +f(562949886312448, 8388607); +f(562949953421312, 8388608); +f(562950020530176, 8388609); +f(1125899839733760, 16777215); +f(1125899906842624, 16777216); +f(1125899973951488, 16777217); +x = 67108865; +f(0, 0); +f(67108865, 1); +f(134217730, 2); +f(201326595, 3); +f(268435460, 4); +f(335544325, 5); +f(469762055, 7); +f(536870920, 8); +f(603979785, 9); +f(1006632975, 15); +f(1073741840, 16); +f(1140850705, 17); +f(2080374815, 31); +f(2147483680, 32); +f(2214592545, 33); +f(4227858495, 63); +f(4294967360, 64); +f(4362076225, 65); +f(8522825855, 127); +f(8589934720, 128); +f(8657043585, 129); +f(17112760575, 255); +f(17179869440, 256); +f(17246978305, 257); +f(34292630015, 511); +f(34359738880, 512); +f(34426847745, 513); +f(68652368895, 1023); +f(68719477760, 1024); +f(68786586625, 1025); +f(137371846655, 2047); +f(137438955520, 2048); +f(137506064385, 2049); +f(274810802175, 4095); +f(274877911040, 4096); +f(274945019905, 4097); +f(549688713215, 8191); +f(549755822080, 8192); +f(549822930945, 8193); +f(1099444535295, 16383); +f(1099511644160, 16384); +f(1099578753025, 16385); +f(2198956179455, 32767); +f(2199023288320, 32768); +f(2199090397185, 32769); +f(4397979467775, 65535); +f(4398046576640, 65536); +f(4398113685505, 65537); +f(8796026044415, 131071); +f(8796093153280, 131072); +f(8796160262145, 131073); +f(17592119197695, 262143); +f(17592186306560, 262144); +f(17592253415425, 262145); +f(35184305504255, 524287); +f(35184372613120, 524288); +f(35184439721985, 524289); +f(70368678117375, 1048575); +f(70368745226240, 1048576); +f(70368812335105, 1048577); +f(140737423343615, 2097151); +f(140737490452480, 2097152); +f(140737557561345, 2097153); +f(281474913796095, 4194303); +f(281474980904960, 4194304); +f(281475048013825, 4194305); +f(562949894701055, 8388607); +f(562949961809920, 8388608); +f(562950028918785, 8388609); +f(1125899856510975, 16777215); +f(1125899923619840, 16777216); +f(1125899990728705, 16777217); +x = 134217727; +f(0, 0); +f(134217727, 1); +f(268435454, 2); +f(402653181, 3); +f(536870908, 4); +f(671088635, 5); +f(939524089, 7); +f(1073741816, 8); +f(1207959543, 9); +f(2013265905, 15); +f(2147483632, 16); +f(2281701359, 17); +f(4160749537, 31); +f(4294967264, 32); +f(4429184991, 33); +f(8455716801, 63); +f(8589934528, 64); +f(8724152255, 65); +f(17045651329, 127); +f(17179869056, 128); +f(17314086783, 129); +f(34225520385, 255); +f(34359738112, 256); +f(34493955839, 257); +f(68585258497, 511); +f(68719476224, 512); +f(68853693951, 513); +f(137304734721, 1023); +f(137438952448, 1024); +f(137573170175, 1025); +f(274743687169, 2047); +f(274877904896, 2048); +f(275012122623, 2049); +f(549621592065, 4095); +f(549755809792, 4096); +f(549890027519, 4097); +f(1099377401857, 8191); +f(1099511619584, 8192); +f(1099645837311, 8193); +f(2198889021441, 16383); +f(2199023239168, 16384); +f(2199157456895, 16385); +f(4397912260609, 32767); +f(4398046478336, 32768); +f(4398180696063, 32769); +f(8795958738945, 65535); +f(8796092956672, 65536); +f(8796227174399, 65537); +f(17592051695617, 131071); +f(17592185913344, 131072); +f(17592320131071, 131073); +f(35184237608961, 262143); +f(35184371826688, 262144); +f(35184506044415, 262145); +f(70368609435649, 524287); +f(70368743653376, 524288); +f(70368877871103, 524289); +f(140737353089025, 1048575); +f(140737487306752, 1048576); +f(140737621524479, 1048577); +f(281474840395777, 2097151); +f(281474974613504, 2097152); +f(281475108831231, 2097153); +f(562949815009281, 4194303); +f(562949949227008, 4194304); +f(562950083444735, 4194305); +f(1125899764236289, 8388607); +f(1125899898454016, 8388608); +f(1125900032671743, 8388609); diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part8.js b/deps/v8/test/mjsunit/mul-exhaustive-part8.js new file mode 100644 index 0000000000..7e5f2851c9 --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part8.js @@ -0,0 +1,526 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 134217728; +f(0, 0); +f(134217728, 1); +f(268435456, 2); +f(402653184, 3); +f(536870912, 4); +f(671088640, 5); +f(939524096, 7); +f(1073741824, 8); +f(1207959552, 9); +f(2013265920, 15); +f(2147483648, 16); +f(2281701376, 17); +f(4160749568, 31); +f(4294967296, 32); +f(4429185024, 33); +f(8455716864, 63); +f(8589934592, 64); +f(8724152320, 65); +f(17045651456, 127); +f(17179869184, 128); +f(17314086912, 129); +f(34225520640, 255); +f(34359738368, 256); +f(34493956096, 257); +f(68585259008, 511); +f(68719476736, 512); +f(68853694464, 513); +f(137304735744, 1023); +f(137438953472, 1024); +f(137573171200, 1025); +f(274743689216, 2047); +f(274877906944, 2048); +f(275012124672, 2049); +f(549621596160, 4095); +f(549755813888, 4096); +f(549890031616, 4097); +f(1099377410048, 8191); +f(1099511627776, 8192); +f(1099645845504, 8193); +f(2198889037824, 16383); +f(2199023255552, 16384); +f(2199157473280, 16385); +f(4397912293376, 32767); +f(4398046511104, 32768); +f(4398180728832, 32769); +f(8795958804480, 65535); +f(8796093022208, 65536); +f(8796227239936, 65537); +f(17592051826688, 131071); +f(17592186044416, 131072); +f(17592320262144, 131073); +f(35184237871104, 262143); +f(35184372088832, 262144); +f(35184506306560, 262145); +f(70368609959936, 524287); +f(70368744177664, 524288); +f(70368878395392, 524289); +f(140737354137600, 1048575); +f(140737488355328, 1048576); +f(140737622573056, 1048577); +f(281474842492928, 2097151); +f(281474976710656, 2097152); +f(281475110928384, 2097153); +f(562949819203584, 4194303); +f(562949953421312, 4194304); +f(562950087639040, 4194305); +f(1125899772624896, 8388607); +f(1125899906842624, 8388608); +f(1125900041060352, 8388609); +x = 134217729; +f(0, 0); +f(134217729, 1); +f(268435458, 2); +f(402653187, 3); +f(536870916, 4); +f(671088645, 5); +f(939524103, 7); +f(1073741832, 8); +f(1207959561, 9); +f(2013265935, 15); +f(2147483664, 16); +f(2281701393, 17); +f(4160749599, 31); +f(4294967328, 32); +f(4429185057, 33); +f(8455716927, 63); +f(8589934656, 64); +f(8724152385, 65); +f(17045651583, 127); +f(17179869312, 128); +f(17314087041, 129); +f(34225520895, 255); +f(34359738624, 256); +f(34493956353, 257); +f(68585259519, 511); +f(68719477248, 512); +f(68853694977, 513); +f(137304736767, 1023); +f(137438954496, 1024); +f(137573172225, 1025); +f(274743691263, 2047); +f(274877908992, 2048); +f(275012126721, 2049); +f(549621600255, 4095); +f(549755817984, 4096); +f(549890035713, 4097); +f(1099377418239, 8191); +f(1099511635968, 8192); +f(1099645853697, 8193); +f(2198889054207, 16383); +f(2199023271936, 16384); +f(2199157489665, 16385); +f(4397912326143, 32767); +f(4398046543872, 32768); +f(4398180761601, 32769); +f(8795958870015, 65535); +f(8796093087744, 65536); +f(8796227305473, 65537); +f(17592051957759, 131071); +f(17592186175488, 131072); +f(17592320393217, 131073); +f(35184238133247, 262143); +f(35184372350976, 262144); +f(35184506568705, 262145); +f(70368610484223, 524287); +f(70368744701952, 524288); +f(70368878919681, 524289); +f(140737355186175, 1048575); +f(140737489403904, 1048576); +f(140737623621633, 1048577); +f(281474844590079, 2097151); +f(281474978807808, 2097152); +f(281475113025537, 2097153); +f(562949823397887, 4194303); +f(562949957615616, 4194304); +f(562950091833345, 4194305); +f(1125899781013503, 8388607); +f(1125899915231232, 8388608); +f(1125900049448961, 8388609); +x = 268435455; +f(0, 0); +f(268435455, 1); +f(536870910, 2); +f(805306365, 3); +f(1073741820, 4); +f(1342177275, 5); +f(1879048185, 7); +f(2147483640, 8); +f(2415919095, 9); +f(4026531825, 15); +f(4294967280, 16); +f(4563402735, 17); +f(8321499105, 31); +f(8589934560, 32); +f(8858370015, 33); +f(16911433665, 63); +f(17179869120, 64); +f(17448304575, 65); +f(34091302785, 127); +f(34359738240, 128); +f(34628173695, 129); +f(68451041025, 255); +f(68719476480, 256); +f(68987911935, 257); +f(137170517505, 511); +f(137438952960, 512); +f(137707388415, 513); +f(274609470465, 1023); +f(274877905920, 1024); +f(275146341375, 1025); +f(549487376385, 2047); +f(549755811840, 2048); +f(550024247295, 2049); +f(1099243188225, 4095); +f(1099511623680, 4096); +f(1099780059135, 4097); +f(2198754811905, 8191); +f(2199023247360, 8192); +f(2199291682815, 8193); +f(4397778059265, 16383); +f(4398046494720, 16384); +f(4398314930175, 16385); +f(8795824553985, 32767); +f(8796092989440, 32768); +f(8796361424895, 32769); +f(17591917543425, 65535); +f(17592185978880, 65536); +f(17592454414335, 65537); +f(35184103522305, 131071); +f(35184371957760, 131072); +f(35184640393215, 131073); +f(70368475480065, 262143); +f(70368743915520, 262144); +f(70369012350975, 262145); +f(140737219395585, 524287); +f(140737487831040, 524288); +f(140737756266495, 524289); +f(281474707226625, 1048575); +f(281474975662080, 1048576); +f(281475244097535, 1048577); +f(562949682888705, 2097151); +f(562949951324160, 2097152); +f(562950219759615, 2097153); +f(1125899634212865, 4194303); +f(1125899902648320, 4194304); +f(1125900171083775, 4194305); +x = 268435456; +f(0, 0); +f(268435456, 1); +f(536870912, 2); +f(805306368, 3); +f(1073741824, 4); +f(1342177280, 5); +f(1879048192, 7); +f(2147483648, 8); +f(2415919104, 9); +f(4026531840, 15); +f(4294967296, 16); +f(4563402752, 17); +f(8321499136, 31); +f(8589934592, 32); +f(8858370048, 33); +f(16911433728, 63); +f(17179869184, 64); +f(17448304640, 65); +f(34091302912, 127); +f(34359738368, 128); +f(34628173824, 129); +f(68451041280, 255); +f(68719476736, 256); +f(68987912192, 257); +f(137170518016, 511); +f(137438953472, 512); +f(137707388928, 513); +f(274609471488, 1023); +f(274877906944, 1024); +f(275146342400, 1025); +f(549487378432, 2047); +f(549755813888, 2048); +f(550024249344, 2049); +f(1099243192320, 4095); +f(1099511627776, 4096); +f(1099780063232, 4097); +f(2198754820096, 8191); +f(2199023255552, 8192); +f(2199291691008, 8193); +f(4397778075648, 16383); +f(4398046511104, 16384); +f(4398314946560, 16385); +f(8795824586752, 32767); +f(8796093022208, 32768); +f(8796361457664, 32769); +f(17591917608960, 65535); +f(17592186044416, 65536); +f(17592454479872, 65537); +f(35184103653376, 131071); +f(35184372088832, 131072); +f(35184640524288, 131073); +f(70368475742208, 262143); +f(70368744177664, 262144); +f(70369012613120, 262145); +f(140737219919872, 524287); +f(140737488355328, 524288); +f(140737756790784, 524289); +f(281474708275200, 1048575); +f(281474976710656, 1048576); +f(281475245146112, 1048577); +f(562949684985856, 2097151); +f(562949953421312, 2097152); +f(562950221856768, 2097153); +f(1125899638407168, 4194303); +f(1125899906842624, 4194304); +f(1125900175278080, 4194305); +x = 268435457; +f(0, 0); +f(268435457, 1); +f(536870914, 2); +f(805306371, 3); +f(1073741828, 4); +f(1342177285, 5); +f(1879048199, 7); +f(2147483656, 8); +f(2415919113, 9); +f(4026531855, 15); +f(4294967312, 16); +f(4563402769, 17); +f(8321499167, 31); +f(8589934624, 32); +f(8858370081, 33); +f(16911433791, 63); +f(17179869248, 64); +f(17448304705, 65); +f(34091303039, 127); +f(34359738496, 128); +f(34628173953, 129); +f(68451041535, 255); +f(68719476992, 256); +f(68987912449, 257); +f(137170518527, 511); +f(137438953984, 512); +f(137707389441, 513); +f(274609472511, 1023); +f(274877907968, 1024); +f(275146343425, 1025); +f(549487380479, 2047); +f(549755815936, 2048); +f(550024251393, 2049); +f(1099243196415, 4095); +f(1099511631872, 4096); +f(1099780067329, 4097); +f(2198754828287, 8191); +f(2199023263744, 8192); +f(2199291699201, 8193); +f(4397778092031, 16383); +f(4398046527488, 16384); +f(4398314962945, 16385); +f(8795824619519, 32767); +f(8796093054976, 32768); +f(8796361490433, 32769); +f(17591917674495, 65535); +f(17592186109952, 65536); +f(17592454545409, 65537); +f(35184103784447, 131071); +f(35184372219904, 131072); +f(35184640655361, 131073); +f(70368476004351, 262143); +f(70368744439808, 262144); +f(70369012875265, 262145); +f(140737220444159, 524287); +f(140737488879616, 524288); +f(140737757315073, 524289); +f(281474709323775, 1048575); +f(281474977759232, 1048576); +f(281475246194689, 1048577); +f(562949687083007, 2097151); +f(562949955518464, 2097152); +f(562950223953921, 2097153); +f(1125899642601471, 4194303); +f(1125899911036928, 4194304); +f(1125900179472385, 4194305); +x = 536870911; +f(0, 0); +f(536870911, 1); +f(1073741822, 2); +f(1610612733, 3); +f(2147483644, 4); +f(2684354555, 5); +f(3758096377, 7); +f(4294967288, 8); +f(4831838199, 9); +f(8053063665, 15); +f(8589934576, 16); +f(9126805487, 17); +f(16642998241, 31); +f(17179869152, 32); +f(17716740063, 33); +f(33822867393, 63); +f(34359738304, 64); +f(34896609215, 65); +f(68182605697, 127); +f(68719476608, 128); +f(69256347519, 129); +f(136902082305, 255); +f(137438953216, 256); +f(137975824127, 257); +f(274341035521, 511); +f(274877906432, 512); +f(275414777343, 513); +f(549218941953, 1023); +f(549755812864, 1024); +f(550292683775, 1025); +f(1098974754817, 2047); +f(1099511625728, 2048); +f(1100048496639, 2049); +f(2198486380545, 4095); +f(2199023251456, 4096); +f(2199560122367, 4097); +f(4397509632001, 8191); +f(4398046502912, 8192); +f(4398583373823, 8193); +f(8795556134913, 16383); +f(8796093005824, 16384); +f(8796629876735, 16385); +f(17591649140737, 32767); +f(17592186011648, 32768); +f(17592722882559, 32769); +f(35183835152385, 65535); +f(35184372023296, 65536); +f(35184908894207, 65537); +f(70368207175681, 131071); +f(70368744046592, 131072); +f(70369280917503, 131073); +f(140736951222273, 262143); +f(140737488093184, 262144); +f(140738024964095, 262145); +f(281474439315457, 524287); +f(281474976186368, 524288); +f(281475513057279, 524289); +f(562949415501825, 1048575); +f(562949952372736, 1048576); +f(562950489243647, 1048577); +f(1125899367874561, 2097151); +f(1125899904745472, 2097152); +f(1125900441616383, 2097153); +x = 536870912; +f(0, 0); +f(536870912, 1); +f(1073741824, 2); +f(1610612736, 3); +f(2147483648, 4); +f(2684354560, 5); +f(3758096384, 7); +f(4294967296, 8); +f(4831838208, 9); +f(8053063680, 15); +f(8589934592, 16); +f(9126805504, 17); +f(16642998272, 31); +f(17179869184, 32); +f(17716740096, 33); +f(33822867456, 63); +f(34359738368, 64); +f(34896609280, 65); +f(68182605824, 127); +f(68719476736, 128); +f(69256347648, 129); +f(136902082560, 255); +f(137438953472, 256); +f(137975824384, 257); +f(274341036032, 511); +f(274877906944, 512); +f(275414777856, 513); +f(549218942976, 1023); +f(549755813888, 1024); +f(550292684800, 1025); +f(1098974756864, 2047); +f(1099511627776, 2048); +f(1100048498688, 2049); +f(2198486384640, 4095); +f(2199023255552, 4096); +f(2199560126464, 4097); +f(4397509640192, 8191); +f(4398046511104, 8192); +f(4398583382016, 8193); +f(8795556151296, 16383); +f(8796093022208, 16384); +f(8796629893120, 16385); +f(17591649173504, 32767); +f(17592186044416, 32768); +f(17592722915328, 32769); +f(35183835217920, 65535); +f(35184372088832, 65536); +f(35184908959744, 65537); +f(70368207306752, 131071); +f(70368744177664, 131072); +f(70369281048576, 131073); +f(140736951484416, 262143); +f(140737488355328, 262144); +f(140738025226240, 262145); +f(281474439839744, 524287); +f(281474976710656, 524288); +f(281475513581568, 524289); +f(562949416550400, 1048575); +f(562949953421312, 1048576); +f(562950490292224, 1048577); +f(1125899369971712, 2097151); +f(1125899906842624, 2097152); +f(1125900443713536, 2097153); diff --git a/deps/v8/test/mjsunit/mul-exhaustive-part9.js b/deps/v8/test/mjsunit/mul-exhaustive-part9.js new file mode 100644 index 0000000000..f329a5a147 --- /dev/null +++ b/deps/v8/test/mjsunit/mul-exhaustive-part9.js @@ -0,0 +1,533 @@ +// Copyright 2008 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 x; + +// Converts a number to string respecting -0. +function stringify(n) { + if ((1 / n) === -Infinity) return "-0"; + return String(n); +} + +function f(expected, y) { + function testEval(string, x, y) { + var mulFunction = Function("x, y", "return " + string); + return mulFunction(x, y); + } + function mulTest(expected, x, y) { + assertEquals(expected, x * y); + assertEquals(expected, testEval(stringify(x) + " * y", x, y)); + assertEquals(expected, testEval("x * " + stringify(y), x, y)); + assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); + } + mulTest(expected, x, y); + mulTest(-expected, -x, y); + mulTest(-expected, x, -y); + mulTest(expected, -x, -y); + if (x === y) return; // Symmetric cases not necessary. + mulTest(expected, y, x); + mulTest(-expected, -y, x); + mulTest(-expected, y, -x); + mulTest(expected, -y, -x); +} + +x = 536870913; +f(0, 0); +f(536870913, 1); +f(1073741826, 2); +f(1610612739, 3); +f(2147483652, 4); +f(2684354565, 5); +f(3758096391, 7); +f(4294967304, 8); +f(4831838217, 9); +f(8053063695, 15); +f(8589934608, 16); +f(9126805521, 17); +f(16642998303, 31); +f(17179869216, 32); +f(17716740129, 33); +f(33822867519, 63); +f(34359738432, 64); +f(34896609345, 65); +f(68182605951, 127); +f(68719476864, 128); +f(69256347777, 129); +f(136902082815, 255); +f(137438953728, 256); +f(137975824641, 257); +f(274341036543, 511); +f(274877907456, 512); +f(275414778369, 513); +f(549218943999, 1023); +f(549755814912, 1024); +f(550292685825, 1025); +f(1098974758911, 2047); +f(1099511629824, 2048); +f(1100048500737, 2049); +f(2198486388735, 4095); +f(2199023259648, 4096); +f(2199560130561, 4097); +f(4397509648383, 8191); +f(4398046519296, 8192); +f(4398583390209, 8193); +f(8795556167679, 16383); +f(8796093038592, 16384); +f(8796629909505, 16385); +f(17591649206271, 32767); +f(17592186077184, 32768); +f(17592722948097, 32769); +f(35183835283455, 65535); +f(35184372154368, 65536); +f(35184909025281, 65537); +f(70368207437823, 131071); +f(70368744308736, 131072); +f(70369281179649, 131073); +f(140736951746559, 262143); +f(140737488617472, 262144); +f(140738025488385, 262145); +f(281474440364031, 524287); +f(281474977234944, 524288); +f(281475514105857, 524289); +f(562949417598975, 1048575); +f(562949954469888, 1048576); +f(562950491340801, 1048577); +f(1125899372068863, 2097151); +f(1125899908939776, 2097152); +f(1125900445810689, 2097153); +x = 1073741823; +f(0, 0); +f(1073741823, 1); +f(2147483646, 2); +f(3221225469, 3); +f(4294967292, 4); +f(5368709115, 5); +f(7516192761, 7); +f(8589934584, 8); +f(9663676407, 9); +f(16106127345, 15); +f(17179869168, 16); +f(18253610991, 17); +f(33285996513, 31); +f(34359738336, 32); +f(35433480159, 33); +f(67645734849, 63); +f(68719476672, 64); +f(69793218495, 65); +f(136365211521, 127); +f(137438953344, 128); +f(138512695167, 129); +f(273804164865, 255); +f(274877906688, 256); +f(275951648511, 257); +f(548682071553, 511); +f(549755813376, 512); +f(550829555199, 513); +f(1098437884929, 1023); +f(1099511626752, 1024); +f(1100585368575, 1025); +f(2197949511681, 2047); +f(2199023253504, 2048); +f(2200096995327, 2049); +f(4396972765185, 4095); +f(4398046507008, 4096); +f(4399120248831, 4097); +f(8795019272193, 8191); +f(8796093014016, 8192); +f(8797166755839, 8193); +f(17591112286209, 16383); +f(17592186028032, 16384); +f(17593259769855, 16385); +f(35183298314241, 32767); +f(35184372056064, 32768); +f(35185445797887, 32769); +f(70367670370305, 65535); +f(70368744112128, 65536); +f(70369817853951, 65537); +f(140736414482433, 131071); +f(140737488224256, 131072); +f(140738561966079, 131073); +f(281473902706689, 262143); +f(281474976448512, 262144); +f(281476050190335, 262145); +f(562948879155201, 524287); +f(562949952897024, 524288); +f(562951026638847, 524289); +f(1125898832052225, 1048575); +f(1125899905794048, 1048576); +f(1125900979535871, 1048577); +x = 1073741824; +f(0, 0); +f(1073741824, 1); +f(2147483648, 2); +f(3221225472, 3); +f(4294967296, 4); +f(5368709120, 5); +f(7516192768, 7); +f(8589934592, 8); +f(9663676416, 9); +f(16106127360, 15); +f(17179869184, 16); +f(18253611008, 17); +f(33285996544, 31); +f(34359738368, 32); +f(35433480192, 33); +f(67645734912, 63); +f(68719476736, 64); +f(69793218560, 65); +f(136365211648, 127); +f(137438953472, 128); +f(138512695296, 129); +f(273804165120, 255); +f(274877906944, 256); +f(275951648768, 257); +f(548682072064, 511); +f(549755813888, 512); +f(550829555712, 513); +f(1098437885952, 1023); +f(1099511627776, 1024); +f(1100585369600, 1025); +f(2197949513728, 2047); +f(2199023255552, 2048); +f(2200096997376, 2049); +f(4396972769280, 4095); +f(4398046511104, 4096); +f(4399120252928, 4097); +f(8795019280384, 8191); +f(8796093022208, 8192); +f(8797166764032, 8193); +f(17591112302592, 16383); +f(17592186044416, 16384); +f(17593259786240, 16385); +f(35183298347008, 32767); +f(35184372088832, 32768); +f(35185445830656, 32769); +f(70367670435840, 65535); +f(70368744177664, 65536); +f(70369817919488, 65537); +f(140736414613504, 131071); +f(140737488355328, 131072); +f(140738562097152, 131073); +f(281473902968832, 262143); +f(281474976710656, 262144); +f(281476050452480, 262145); +f(562948879679488, 524287); +f(562949953421312, 524288); +f(562951027163136, 524289); +f(1125898833100800, 1048575); +f(1125899906842624, 1048576); +f(1125900980584448, 1048577); +x = 1073741825; +f(0, 0); +f(1073741825, 1); +f(2147483650, 2); +f(3221225475, 3); +f(4294967300, 4); +f(5368709125, 5); +f(7516192775, 7); +f(8589934600, 8); +f(9663676425, 9); +f(16106127375, 15); +f(17179869200, 16); +f(18253611025, 17); +f(33285996575, 31); +f(34359738400, 32); +f(35433480225, 33); +f(67645734975, 63); +f(68719476800, 64); +f(69793218625, 65); +f(136365211775, 127); +f(137438953600, 128); +f(138512695425, 129); +f(273804165375, 255); +f(274877907200, 256); +f(275951649025, 257); +f(548682072575, 511); +f(549755814400, 512); +f(550829556225, 513); +f(1098437886975, 1023); +f(1099511628800, 1024); +f(1100585370625, 1025); +f(2197949515775, 2047); +f(2199023257600, 2048); +f(2200096999425, 2049); +f(4396972773375, 4095); +f(4398046515200, 4096); +f(4399120257025, 4097); +f(8795019288575, 8191); +f(8796093030400, 8192); +f(8797166772225, 8193); +f(17591112318975, 16383); +f(17592186060800, 16384); +f(17593259802625, 16385); +f(35183298379775, 32767); +f(35184372121600, 32768); +f(35185445863425, 32769); +f(70367670501375, 65535); +f(70368744243200, 65536); +f(70369817985025, 65537); +f(140736414744575, 131071); +f(140737488486400, 131072); +f(140738562228225, 131073); +f(281473903230975, 262143); +f(281474976972800, 262144); +f(281476050714625, 262145); +f(562948880203775, 524287); +f(562949953945600, 524288); +f(562951027687425, 524289); +f(1125898834149375, 1048575); +f(1125899907891200, 1048576); +f(1125900981633025, 1048577); +x = 2147483647; +f(0, 0); +f(2147483647, 1); +f(4294967294, 2); +f(6442450941, 3); +f(8589934588, 4); +f(10737418235, 5); +f(15032385529, 7); +f(17179869176, 8); +f(19327352823, 9); +f(32212254705, 15); +f(34359738352, 16); +f(36507221999, 17); +f(66571993057, 31); +f(68719476704, 32); +f(70866960351, 33); +f(135291469761, 63); +f(137438953408, 64); +f(139586437055, 65); +f(272730423169, 127); +f(274877906816, 128); +f(277025390463, 129); +f(547608329985, 255); +f(549755813632, 256); +f(551903297279, 257); +f(1097364143617, 511); +f(1099511627264, 512); +f(1101659110911, 513); +f(2196875770881, 1023); +f(2199023254528, 1024); +f(2201170738175, 1025); +f(4395899025409, 2047); +f(4398046509056, 2048); +f(4400193992703, 2049); +f(8793945534465, 4095); +f(8796093018112, 4096); +f(8798240501759, 4097); +f(17590038552577, 8191); +f(17592186036224, 8192); +f(17594333519871, 8193); +f(35182224588801, 16383); +f(35184372072448, 16384); +f(35186519556095, 16385); +f(70366596661249, 32767); +f(70368744144896, 32768); +f(70370891628543, 32769); +f(140735340806145, 65535); +f(140737488289792, 65536); +f(140739635773439, 65537); +f(281472829095937, 131071); +f(281474976579584, 131072); +f(281477124063231, 131073); +f(562947805675521, 262143); +f(562949953159168, 262144); +f(562952100642815, 262145); +f(1125897758834689, 524287); +f(1125899906318336, 524288); +f(1125902053801983, 524289); +x = 2147483648; +f(0, 0); +f(2147483648, 1); +f(4294967296, 2); +f(6442450944, 3); +f(8589934592, 4); +f(10737418240, 5); +f(15032385536, 7); +f(17179869184, 8); +f(19327352832, 9); +f(32212254720, 15); +f(34359738368, 16); +f(36507222016, 17); +f(66571993088, 31); +f(68719476736, 32); +f(70866960384, 33); +f(135291469824, 63); +f(137438953472, 64); +f(139586437120, 65); +f(272730423296, 127); +f(274877906944, 128); +f(277025390592, 129); +f(547608330240, 255); +f(549755813888, 256); +f(551903297536, 257); +f(1097364144128, 511); +f(1099511627776, 512); +f(1101659111424, 513); +f(2196875771904, 1023); +f(2199023255552, 1024); +f(2201170739200, 1025); +f(4395899027456, 2047); +f(4398046511104, 2048); +f(4400193994752, 2049); +f(8793945538560, 4095); +f(8796093022208, 4096); +f(8798240505856, 4097); +f(17590038560768, 8191); +f(17592186044416, 8192); +f(17594333528064, 8193); +f(35182224605184, 16383); +f(35184372088832, 16384); +f(35186519572480, 16385); +f(70366596694016, 32767); +f(70368744177664, 32768); +f(70370891661312, 32769); +f(140735340871680, 65535); +f(140737488355328, 65536); +f(140739635838976, 65537); +f(281472829227008, 131071); +f(281474976710656, 131072); +f(281477124194304, 131073); +f(562947805937664, 262143); +f(562949953421312, 262144); +f(562952100904960, 262145); +f(1125897759358976, 524287); +f(1125899906842624, 524288); +f(1125902054326272, 524289); +x = 2147483649; +f(0, 0); +f(2147483649, 1); +f(4294967298, 2); +f(6442450947, 3); +f(8589934596, 4); +f(10737418245, 5); +f(15032385543, 7); +f(17179869192, 8); +f(19327352841, 9); +f(32212254735, 15); +f(34359738384, 16); +f(36507222033, 17); +f(66571993119, 31); +f(68719476768, 32); +f(70866960417, 33); +f(135291469887, 63); +f(137438953536, 64); +f(139586437185, 65); +f(272730423423, 127); +f(274877907072, 128); +f(277025390721, 129); +f(547608330495, 255); +f(549755814144, 256); +f(551903297793, 257); +f(1097364144639, 511); +f(1099511628288, 512); +f(1101659111937, 513); +f(2196875772927, 1023); +f(2199023256576, 1024); +f(2201170740225, 1025); +f(4395899029503, 2047); +f(4398046513152, 2048); +f(4400193996801, 2049); +f(8793945542655, 4095); +f(8796093026304, 4096); +f(8798240509953, 4097); +f(17590038568959, 8191); +f(17592186052608, 8192); +f(17594333536257, 8193); +f(35182224621567, 16383); +f(35184372105216, 16384); +f(35186519588865, 16385); +f(70366596726783, 32767); +f(70368744210432, 32768); +f(70370891694081, 32769); +f(140735340937215, 65535); +f(140737488420864, 65536); +f(140739635904513, 65537); +f(281472829358079, 131071); +f(281474976841728, 131072); +f(281477124325377, 131073); +f(562947806199807, 262143); +f(562949953683456, 262144); +f(562952101167105, 262145); +f(1125897759883263, 524287); +f(1125899907366912, 524288); +f(1125902054850561, 524289); +x = 4294967295; +f(0, 0); +f(4294967295, 1); +f(8589934590, 2); +f(12884901885, 3); +f(17179869180, 4); +f(21474836475, 5); +f(30064771065, 7); +f(34359738360, 8); +f(38654705655, 9); +f(64424509425, 15); +f(68719476720, 16); +f(73014444015, 17); +f(133143986145, 31); +f(137438953440, 32); +f(141733920735, 33); +f(270582939585, 63); +f(274877906880, 64); +f(279172874175, 65); +f(545460846465, 127); +f(549755813760, 128); +f(554050781055, 129); +f(1095216660225, 255); +f(1099511627520, 256); +f(1103806594815, 257); +f(2194728287745, 511); +f(2199023255040, 512); +f(2203318222335, 513); +f(4393751542785, 1023); +f(4398046510080, 1024); +f(4402341477375, 1025); +f(8791798052865, 2047); +f(8796093020160, 2048); +f(8800387987455, 2049); +f(17587891073025, 4095); +f(17592186040320, 4096); +f(17596481007615, 4097); +f(35180077113345, 8191); +f(35184372080640, 8192); +f(35188667047935, 8193); +f(70364449193985, 16383); +f(70368744161280, 16384); +f(70373039128575, 16385); +f(140733193355265, 32767); +f(140737488322560, 32768); +f(140741783289855, 32769); +f(281470681677825, 65535); +f(281474976645120, 65536); +f(281479271612415, 65537); +f(562945658322945, 131071); +f(562949953290240, 131072); +f(562954248257535, 131073); +f(1125895611613185, 262143); +f(1125899906580480, 262144); +f(1125904201547775, 262145); diff --git a/deps/v8/test/mjsunit/mul-exhaustive.js b/deps/v8/test/mjsunit/mul-exhaustive.js deleted file mode 100644 index 12689db32b..0000000000 --- a/deps/v8/test/mjsunit/mul-exhaustive.js +++ /dev/null @@ -1,4629 +0,0 @@ -// Copyright 2008 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 x; - -// Converts a number to string respecting -0. -function stringify(n) { - if ((1 / n) === -Infinity) return "-0"; - return String(n); -} - -function f(expected, y) { - function testEval(string, x, y) { - var mulFunction = Function("x, y", "return " + string); - return mulFunction(x, y); - } - function mulTest(expected, x, y) { - assertEquals(expected, x * y); - assertEquals(expected, testEval(stringify(x) + " * y", x, y)); - assertEquals(expected, testEval("x * " + stringify(y), x, y)); - assertEquals(expected, testEval(stringify(x) + " * " + stringify(y), x, y)); - } - mulTest(expected, x, y); - mulTest(-expected, -x, y); - mulTest(-expected, x, -y); - mulTest(expected, -x, -y); - if (x === y) return; // Symmetric cases not necessary. - mulTest(expected, y, x); - mulTest(-expected, -y, x); - mulTest(-expected, y, -x); - mulTest(expected, -y, -x); -} - -x = 0; -f(0, 0); -x = 1; -f(0, 0); -f(1, 1); -x = 2; -f(0, 0); -f(2, 1); -f(4, 2); -x = 3; -f(0, 0); -f(3, 1); -f(6, 2); -f(9, 3); -x = 4; -f(0, 0); -f(4, 1); -f(8, 2); -f(12, 3); -f(16, 4); -x = 5; -f(0, 0); -f(5, 1); -f(10, 2); -f(15, 3); -f(20, 4); -f(25, 5); -x = 7; -f(0, 0); -f(7, 1); -f(14, 2); -f(21, 3); -f(28, 4); -f(35, 5); -f(49, 7); -x = 8; -f(0, 0); -f(8, 1); -f(16, 2); -f(24, 3); -f(32, 4); -f(40, 5); -f(56, 7); -f(64, 8); -x = 9; -f(0, 0); -f(9, 1); -f(18, 2); -f(27, 3); -f(36, 4); -f(45, 5); -f(63, 7); -f(72, 8); -f(81, 9); -x = 15; -f(0, 0); -f(15, 1); -f(30, 2); -f(45, 3); -f(60, 4); -f(75, 5); -f(105, 7); -f(120, 8); -f(135, 9); -f(225, 15); -x = 16; -f(0, 0); -f(16, 1); -f(32, 2); -f(48, 3); -f(64, 4); -f(80, 5); -f(112, 7); -f(128, 8); -f(144, 9); -f(240, 15); -f(256, 16); -x = 17; -f(0, 0); -f(17, 1); -f(34, 2); -f(51, 3); -f(68, 4); -f(85, 5); -f(119, 7); -f(136, 8); -f(153, 9); -f(255, 15); -f(272, 16); -f(289, 17); -x = 31; -f(0, 0); -f(31, 1); -f(62, 2); -f(93, 3); -f(124, 4); -f(155, 5); -f(217, 7); -f(248, 8); -f(279, 9); -f(465, 15); -f(496, 16); -f(527, 17); -f(961, 31); -x = 32; -f(0, 0); -f(32, 1); -f(64, 2); -f(96, 3); -f(128, 4); -f(160, 5); -f(224, 7); -f(256, 8); -f(288, 9); -f(480, 15); -f(512, 16); -f(544, 17); -f(992, 31); -f(1024, 32); -x = 33; -f(0, 0); -f(33, 1); -f(66, 2); -f(99, 3); -f(132, 4); -f(165, 5); -f(231, 7); -f(264, 8); -f(297, 9); -f(495, 15); -f(528, 16); -f(561, 17); -f(1023, 31); -f(1056, 32); -f(1089, 33); -x = 63; -f(0, 0); -f(63, 1); -f(126, 2); -f(189, 3); -f(252, 4); -f(315, 5); -f(441, 7); -f(504, 8); -f(567, 9); -f(945, 15); -f(1008, 16); -f(1071, 17); -f(1953, 31); -f(2016, 32); -f(2079, 33); -f(3969, 63); -x = 64; -f(0, 0); -f(64, 1); -f(128, 2); -f(192, 3); -f(256, 4); -f(320, 5); -f(448, 7); -f(512, 8); -f(576, 9); -f(960, 15); -f(1024, 16); -f(1088, 17); -f(1984, 31); -f(2048, 32); -f(2112, 33); -f(4032, 63); -f(4096, 64); -x = 65; -f(0, 0); -f(65, 1); -f(130, 2); -f(195, 3); -f(260, 4); -f(325, 5); -f(455, 7); -f(520, 8); -f(585, 9); -f(975, 15); -f(1040, 16); -f(1105, 17); -f(2015, 31); -f(2080, 32); -f(2145, 33); -f(4095, 63); -f(4160, 64); -f(4225, 65); -x = 127; -f(0, 0); -f(127, 1); -f(254, 2); -f(381, 3); -f(508, 4); -f(635, 5); -f(889, 7); -f(1016, 8); -f(1143, 9); -f(1905, 15); -f(2032, 16); -f(2159, 17); -f(3937, 31); -f(4064, 32); -f(4191, 33); -f(8001, 63); -f(8128, 64); -f(8255, 65); -f(16129, 127); -x = 128; -f(0, 0); -f(128, 1); -f(256, 2); -f(384, 3); -f(512, 4); -f(640, 5); -f(896, 7); -f(1024, 8); -f(1152, 9); -f(1920, 15); -f(2048, 16); -f(2176, 17); -f(3968, 31); -f(4096, 32); -f(4224, 33); -f(8064, 63); -f(8192, 64); -f(8320, 65); -f(16256, 127); -f(16384, 128); -x = 129; -f(0, 0); -f(129, 1); -f(258, 2); -f(387, 3); -f(516, 4); -f(645, 5); -f(903, 7); -f(1032, 8); -f(1161, 9); -f(1935, 15); -f(2064, 16); -f(2193, 17); -f(3999, 31); -f(4128, 32); -f(4257, 33); -f(8127, 63); -f(8256, 64); -f(8385, 65); -f(16383, 127); -f(16512, 128); -f(16641, 129); -x = 255; -f(0, 0); -f(255, 1); -f(510, 2); -f(765, 3); -f(1020, 4); -f(1275, 5); -f(1785, 7); -f(2040, 8); -f(2295, 9); -f(3825, 15); -f(4080, 16); -f(4335, 17); -f(7905, 31); -f(8160, 32); -f(8415, 33); -f(16065, 63); -f(16320, 64); -f(16575, 65); -f(32385, 127); -f(32640, 128); -f(32895, 129); -f(65025, 255); -x = 256; -f(0, 0); -f(256, 1); -f(512, 2); -f(768, 3); -f(1024, 4); -f(1280, 5); -f(1792, 7); -f(2048, 8); -f(2304, 9); -f(3840, 15); -f(4096, 16); -f(4352, 17); -f(7936, 31); -f(8192, 32); -f(8448, 33); -f(16128, 63); -f(16384, 64); -f(16640, 65); -f(32512, 127); -f(32768, 128); -f(33024, 129); -f(65280, 255); -f(65536, 256); -x = 257; -f(0, 0); -f(257, 1); -f(514, 2); -f(771, 3); -f(1028, 4); -f(1285, 5); -f(1799, 7); -f(2056, 8); -f(2313, 9); -f(3855, 15); -f(4112, 16); -f(4369, 17); -f(7967, 31); -f(8224, 32); -f(8481, 33); -f(16191, 63); -f(16448, 64); -f(16705, 65); -f(32639, 127); -f(32896, 128); -f(33153, 129); -f(65535, 255); -f(65792, 256); -f(66049, 257); -x = 511; -f(0, 0); -f(511, 1); -f(1022, 2); -f(1533, 3); -f(2044, 4); -f(2555, 5); -f(3577, 7); -f(4088, 8); -f(4599, 9); -f(7665, 15); -f(8176, 16); -f(8687, 17); -f(15841, 31); -f(16352, 32); -f(16863, 33); -f(32193, 63); -f(32704, 64); -f(33215, 65); -f(64897, 127); -f(65408, 128); -f(65919, 129); -f(130305, 255); -f(130816, 256); -f(131327, 257); -f(261121, 511); -x = 512; -f(0, 0); -f(512, 1); -f(1024, 2); -f(1536, 3); -f(2048, 4); -f(2560, 5); -f(3584, 7); -f(4096, 8); -f(4608, 9); -f(7680, 15); -f(8192, 16); -f(8704, 17); -f(15872, 31); -f(16384, 32); -f(16896, 33); -f(32256, 63); -f(32768, 64); -f(33280, 65); -f(65024, 127); -f(65536, 128); -f(66048, 129); -f(130560, 255); -f(131072, 256); -f(131584, 257); -f(261632, 511); -f(262144, 512); -x = 513; -f(0, 0); -f(513, 1); -f(1026, 2); -f(1539, 3); -f(2052, 4); -f(2565, 5); -f(3591, 7); -f(4104, 8); -f(4617, 9); -f(7695, 15); -f(8208, 16); -f(8721, 17); -f(15903, 31); -f(16416, 32); -f(16929, 33); -f(32319, 63); -f(32832, 64); -f(33345, 65); -f(65151, 127); -f(65664, 128); -f(66177, 129); -f(130815, 255); -f(131328, 256); -f(131841, 257); -f(262143, 511); -f(262656, 512); -f(263169, 513); -x = 1023; -f(0, 0); -f(1023, 1); -f(2046, 2); -f(3069, 3); -f(4092, 4); -f(5115, 5); -f(7161, 7); -f(8184, 8); -f(9207, 9); -f(15345, 15); -f(16368, 16); -f(17391, 17); -f(31713, 31); -f(32736, 32); -f(33759, 33); -f(64449, 63); -f(65472, 64); -f(66495, 65); -f(129921, 127); -f(130944, 128); -f(131967, 129); -f(260865, 255); -f(261888, 256); -f(262911, 257); -f(522753, 511); -f(523776, 512); -f(524799, 513); -f(1046529, 1023); -x = 1024; -f(0, 0); -f(1024, 1); -f(2048, 2); -f(3072, 3); -f(4096, 4); -f(5120, 5); -f(7168, 7); -f(8192, 8); -f(9216, 9); -f(15360, 15); -f(16384, 16); -f(17408, 17); -f(31744, 31); -f(32768, 32); -f(33792, 33); -f(64512, 63); -f(65536, 64); -f(66560, 65); -f(130048, 127); -f(131072, 128); -f(132096, 129); -f(261120, 255); -f(262144, 256); -f(263168, 257); -f(523264, 511); -f(524288, 512); -f(525312, 513); -f(1047552, 1023); -f(1048576, 1024); -x = 1025; -f(0, 0); -f(1025, 1); -f(2050, 2); -f(3075, 3); -f(4100, 4); -f(5125, 5); -f(7175, 7); -f(8200, 8); -f(9225, 9); -f(15375, 15); -f(16400, 16); -f(17425, 17); -f(31775, 31); -f(32800, 32); -f(33825, 33); -f(64575, 63); -f(65600, 64); -f(66625, 65); -f(130175, 127); -f(131200, 128); -f(132225, 129); -f(261375, 255); -f(262400, 256); -f(263425, 257); -f(523775, 511); -f(524800, 512); -f(525825, 513); -f(1048575, 1023); -f(1049600, 1024); -f(1050625, 1025); -x = 2047; -f(0, 0); -f(2047, 1); -f(4094, 2); -f(6141, 3); -f(8188, 4); -f(10235, 5); -f(14329, 7); -f(16376, 8); -f(18423, 9); -f(30705, 15); -f(32752, 16); -f(34799, 17); -f(63457, 31); -f(65504, 32); -f(67551, 33); -f(128961, 63); -f(131008, 64); -f(133055, 65); -f(259969, 127); -f(262016, 128); -f(264063, 129); -f(521985, 255); -f(524032, 256); -f(526079, 257); -f(1046017, 511); -f(1048064, 512); -f(1050111, 513); -f(2094081, 1023); -f(2096128, 1024); -f(2098175, 1025); -f(4190209, 2047); -x = 2048; -f(0, 0); -f(2048, 1); -f(4096, 2); -f(6144, 3); -f(8192, 4); -f(10240, 5); -f(14336, 7); -f(16384, 8); -f(18432, 9); -f(30720, 15); -f(32768, 16); -f(34816, 17); -f(63488, 31); -f(65536, 32); -f(67584, 33); -f(129024, 63); -f(131072, 64); -f(133120, 65); -f(260096, 127); -f(262144, 128); -f(264192, 129); -f(522240, 255); -f(524288, 256); -f(526336, 257); -f(1046528, 511); -f(1048576, 512); -f(1050624, 513); -f(2095104, 1023); -f(2097152, 1024); -f(2099200, 1025); -f(4192256, 2047); -f(4194304, 2048); -x = 2049; -f(0, 0); -f(2049, 1); -f(4098, 2); -f(6147, 3); -f(8196, 4); -f(10245, 5); -f(14343, 7); -f(16392, 8); -f(18441, 9); -f(30735, 15); -f(32784, 16); -f(34833, 17); -f(63519, 31); -f(65568, 32); -f(67617, 33); -f(129087, 63); -f(131136, 64); -f(133185, 65); -f(260223, 127); -f(262272, 128); -f(264321, 129); -f(522495, 255); -f(524544, 256); -f(526593, 257); -f(1047039, 511); -f(1049088, 512); -f(1051137, 513); -f(2096127, 1023); -f(2098176, 1024); -f(2100225, 1025); -f(4194303, 2047); -f(4196352, 2048); -f(4198401, 2049); -x = 4095; -f(0, 0); -f(4095, 1); -f(8190, 2); -f(12285, 3); -f(16380, 4); -f(20475, 5); -f(28665, 7); -f(32760, 8); -f(36855, 9); -f(61425, 15); -f(65520, 16); -f(69615, 17); -f(126945, 31); -f(131040, 32); -f(135135, 33); -f(257985, 63); -f(262080, 64); -f(266175, 65); -f(520065, 127); -f(524160, 128); -f(528255, 129); -f(1044225, 255); -f(1048320, 256); -f(1052415, 257); -f(2092545, 511); -f(2096640, 512); -f(2100735, 513); -f(4189185, 1023); -f(4193280, 1024); -f(4197375, 1025); -f(8382465, 2047); -f(8386560, 2048); -f(8390655, 2049); -f(16769025, 4095); -x = 4096; -f(0, 0); -f(4096, 1); -f(8192, 2); -f(12288, 3); -f(16384, 4); -f(20480, 5); -f(28672, 7); -f(32768, 8); -f(36864, 9); -f(61440, 15); -f(65536, 16); -f(69632, 17); -f(126976, 31); -f(131072, 32); -f(135168, 33); -f(258048, 63); -f(262144, 64); -f(266240, 65); -f(520192, 127); -f(524288, 128); -f(528384, 129); -f(1044480, 255); -f(1048576, 256); -f(1052672, 257); -f(2093056, 511); -f(2097152, 512); -f(2101248, 513); -f(4190208, 1023); -f(4194304, 1024); -f(4198400, 1025); -f(8384512, 2047); -f(8388608, 2048); -f(8392704, 2049); -f(16773120, 4095); -f(16777216, 4096); -x = 4097; -f(0, 0); -f(4097, 1); -f(8194, 2); -f(12291, 3); -f(16388, 4); -f(20485, 5); -f(28679, 7); -f(32776, 8); -f(36873, 9); -f(61455, 15); -f(65552, 16); -f(69649, 17); -f(127007, 31); -f(131104, 32); -f(135201, 33); -f(258111, 63); -f(262208, 64); -f(266305, 65); -f(520319, 127); -f(524416, 128); -f(528513, 129); -f(1044735, 255); -f(1048832, 256); -f(1052929, 257); -f(2093567, 511); -f(2097664, 512); -f(2101761, 513); -f(4191231, 1023); -f(4195328, 1024); -f(4199425, 1025); -f(8386559, 2047); -f(8390656, 2048); -f(8394753, 2049); -f(16777215, 4095); -f(16781312, 4096); -f(16785409, 4097); -x = 8191; -f(0, 0); -f(8191, 1); -f(16382, 2); -f(24573, 3); -f(32764, 4); -f(40955, 5); -f(57337, 7); -f(65528, 8); -f(73719, 9); -f(122865, 15); -f(131056, 16); -f(139247, 17); -f(253921, 31); -f(262112, 32); -f(270303, 33); -f(516033, 63); -f(524224, 64); -f(532415, 65); -f(1040257, 127); -f(1048448, 128); -f(1056639, 129); -f(2088705, 255); -f(2096896, 256); -f(2105087, 257); -f(4185601, 511); -f(4193792, 512); -f(4201983, 513); -f(8379393, 1023); -f(8387584, 1024); -f(8395775, 1025); -f(16766977, 2047); -f(16775168, 2048); -f(16783359, 2049); -f(33542145, 4095); -f(33550336, 4096); -f(33558527, 4097); -f(67092481, 8191); -x = 8192; -f(0, 0); -f(8192, 1); -f(16384, 2); -f(24576, 3); -f(32768, 4); -f(40960, 5); -f(57344, 7); -f(65536, 8); -f(73728, 9); -f(122880, 15); -f(131072, 16); -f(139264, 17); -f(253952, 31); -f(262144, 32); -f(270336, 33); -f(516096, 63); -f(524288, 64); -f(532480, 65); -f(1040384, 127); -f(1048576, 128); -f(1056768, 129); -f(2088960, 255); -f(2097152, 256); -f(2105344, 257); -f(4186112, 511); -f(4194304, 512); -f(4202496, 513); -f(8380416, 1023); -f(8388608, 1024); -f(8396800, 1025); -f(16769024, 2047); -f(16777216, 2048); -f(16785408, 2049); -f(33546240, 4095); -f(33554432, 4096); -f(33562624, 4097); -f(67100672, 8191); -f(67108864, 8192); -x = 8193; -f(0, 0); -f(8193, 1); -f(16386, 2); -f(24579, 3); -f(32772, 4); -f(40965, 5); -f(57351, 7); -f(65544, 8); -f(73737, 9); -f(122895, 15); -f(131088, 16); -f(139281, 17); -f(253983, 31); -f(262176, 32); -f(270369, 33); -f(516159, 63); -f(524352, 64); -f(532545, 65); -f(1040511, 127); -f(1048704, 128); -f(1056897, 129); -f(2089215, 255); -f(2097408, 256); -f(2105601, 257); -f(4186623, 511); -f(4194816, 512); -f(4203009, 513); -f(8381439, 1023); -f(8389632, 1024); -f(8397825, 1025); -f(16771071, 2047); -f(16779264, 2048); -f(16787457, 2049); -f(33550335, 4095); -f(33558528, 4096); -f(33566721, 4097); -f(67108863, 8191); -f(67117056, 8192); -f(67125249, 8193); -x = 16383; -f(0, 0); -f(16383, 1); -f(32766, 2); -f(49149, 3); -f(65532, 4); -f(81915, 5); -f(114681, 7); -f(131064, 8); -f(147447, 9); -f(245745, 15); -f(262128, 16); -f(278511, 17); -f(507873, 31); -f(524256, 32); -f(540639, 33); -f(1032129, 63); -f(1048512, 64); -f(1064895, 65); -f(2080641, 127); -f(2097024, 128); -f(2113407, 129); -f(4177665, 255); -f(4194048, 256); -f(4210431, 257); -f(8371713, 511); -f(8388096, 512); -f(8404479, 513); -f(16759809, 1023); -f(16776192, 1024); -f(16792575, 1025); -f(33536001, 2047); -f(33552384, 2048); -f(33568767, 2049); -f(67088385, 4095); -f(67104768, 4096); -f(67121151, 4097); -f(134193153, 8191); -f(134209536, 8192); -f(134225919, 8193); -f(268402689, 16383); -x = 16384; -f(0, 0); -f(16384, 1); -f(32768, 2); -f(49152, 3); -f(65536, 4); -f(81920, 5); -f(114688, 7); -f(131072, 8); -f(147456, 9); -f(245760, 15); -f(262144, 16); -f(278528, 17); -f(507904, 31); -f(524288, 32); -f(540672, 33); -f(1032192, 63); -f(1048576, 64); -f(1064960, 65); -f(2080768, 127); -f(2097152, 128); -f(2113536, 129); -f(4177920, 255); -f(4194304, 256); -f(4210688, 257); -f(8372224, 511); -f(8388608, 512); -f(8404992, 513); -f(16760832, 1023); -f(16777216, 1024); -f(16793600, 1025); -f(33538048, 2047); -f(33554432, 2048); -f(33570816, 2049); -f(67092480, 4095); -f(67108864, 4096); -f(67125248, 4097); -f(134201344, 8191); -f(134217728, 8192); -f(134234112, 8193); -f(268419072, 16383); -f(268435456, 16384); -x = 16385; -f(0, 0); -f(16385, 1); -f(32770, 2); -f(49155, 3); -f(65540, 4); -f(81925, 5); -f(114695, 7); -f(131080, 8); -f(147465, 9); -f(245775, 15); -f(262160, 16); -f(278545, 17); -f(507935, 31); -f(524320, 32); -f(540705, 33); -f(1032255, 63); -f(1048640, 64); -f(1065025, 65); -f(2080895, 127); -f(2097280, 128); -f(2113665, 129); -f(4178175, 255); -f(4194560, 256); -f(4210945, 257); -f(8372735, 511); -f(8389120, 512); -f(8405505, 513); -f(16761855, 1023); -f(16778240, 1024); -f(16794625, 1025); -f(33540095, 2047); -f(33556480, 2048); -f(33572865, 2049); -f(67096575, 4095); -f(67112960, 4096); -f(67129345, 4097); -f(134209535, 8191); -f(134225920, 8192); -f(134242305, 8193); -f(268435455, 16383); -f(268451840, 16384); -f(268468225, 16385); -x = 32767; -f(0, 0); -f(32767, 1); -f(65534, 2); -f(98301, 3); -f(131068, 4); -f(163835, 5); -f(229369, 7); -f(262136, 8); -f(294903, 9); -f(491505, 15); -f(524272, 16); -f(557039, 17); -f(1015777, 31); -f(1048544, 32); -f(1081311, 33); -f(2064321, 63); -f(2097088, 64); -f(2129855, 65); -f(4161409, 127); -f(4194176, 128); -f(4226943, 129); -f(8355585, 255); -f(8388352, 256); -f(8421119, 257); -f(16743937, 511); -f(16776704, 512); -f(16809471, 513); -f(33520641, 1023); -f(33553408, 1024); -f(33586175, 1025); -f(67074049, 2047); -f(67106816, 2048); -f(67139583, 2049); -f(134180865, 4095); -f(134213632, 4096); -f(134246399, 4097); -f(268394497, 8191); -f(268427264, 8192); -f(268460031, 8193); -f(536821761, 16383); -f(536854528, 16384); -f(536887295, 16385); -f(1073676289, 32767); -x = 32768; -f(0, 0); -f(32768, 1); -f(65536, 2); -f(98304, 3); -f(131072, 4); -f(163840, 5); -f(229376, 7); -f(262144, 8); -f(294912, 9); -f(491520, 15); -f(524288, 16); -f(557056, 17); -f(1015808, 31); -f(1048576, 32); -f(1081344, 33); -f(2064384, 63); -f(2097152, 64); -f(2129920, 65); -f(4161536, 127); -f(4194304, 128); -f(4227072, 129); -f(8355840, 255); -f(8388608, 256); -f(8421376, 257); -f(16744448, 511); -f(16777216, 512); -f(16809984, 513); -f(33521664, 1023); -f(33554432, 1024); -f(33587200, 1025); -f(67076096, 2047); -f(67108864, 2048); -f(67141632, 2049); -f(134184960, 4095); -f(134217728, 4096); -f(134250496, 4097); -f(268402688, 8191); -f(268435456, 8192); -f(268468224, 8193); -f(536838144, 16383); -f(536870912, 16384); -f(536903680, 16385); -f(1073709056, 32767); -f(1073741824, 32768); -x = 32769; -f(0, 0); -f(32769, 1); -f(65538, 2); -f(98307, 3); -f(131076, 4); -f(163845, 5); -f(229383, 7); -f(262152, 8); -f(294921, 9); -f(491535, 15); -f(524304, 16); -f(557073, 17); -f(1015839, 31); -f(1048608, 32); -f(1081377, 33); -f(2064447, 63); -f(2097216, 64); -f(2129985, 65); -f(4161663, 127); -f(4194432, 128); -f(4227201, 129); -f(8356095, 255); -f(8388864, 256); -f(8421633, 257); -f(16744959, 511); -f(16777728, 512); -f(16810497, 513); -f(33522687, 1023); -f(33555456, 1024); -f(33588225, 1025); -f(67078143, 2047); -f(67110912, 2048); -f(67143681, 2049); -f(134189055, 4095); -f(134221824, 4096); -f(134254593, 4097); -f(268410879, 8191); -f(268443648, 8192); -f(268476417, 8193); -f(536854527, 16383); -f(536887296, 16384); -f(536920065, 16385); -f(1073741823, 32767); -f(1073774592, 32768); -f(1073807361, 32769); -x = 65535; -f(0, 0); -f(65535, 1); -f(131070, 2); -f(196605, 3); -f(262140, 4); -f(327675, 5); -f(458745, 7); -f(524280, 8); -f(589815, 9); -f(983025, 15); -f(1048560, 16); -f(1114095, 17); -f(2031585, 31); -f(2097120, 32); -f(2162655, 33); -f(4128705, 63); -f(4194240, 64); -f(4259775, 65); -f(8322945, 127); -f(8388480, 128); -f(8454015, 129); -f(16711425, 255); -f(16776960, 256); -f(16842495, 257); -f(33488385, 511); -f(33553920, 512); -f(33619455, 513); -f(67042305, 1023); -f(67107840, 1024); -f(67173375, 1025); -f(134150145, 2047); -f(134215680, 2048); -f(134281215, 2049); -f(268365825, 4095); -f(268431360, 4096); -f(268496895, 4097); -f(536797185, 8191); -f(536862720, 8192); -f(536928255, 8193); -f(1073659905, 16383); -f(1073725440, 16384); -f(1073790975, 16385); -f(2147385345, 32767); -f(2147450880, 32768); -f(2147516415, 32769); -f(4294836225, 65535); -x = 65536; -f(0, 0); -f(65536, 1); -f(131072, 2); -f(196608, 3); -f(262144, 4); -f(327680, 5); -f(458752, 7); -f(524288, 8); -f(589824, 9); -f(983040, 15); -f(1048576, 16); -f(1114112, 17); -f(2031616, 31); -f(2097152, 32); -f(2162688, 33); -f(4128768, 63); -f(4194304, 64); -f(4259840, 65); -f(8323072, 127); -f(8388608, 128); -f(8454144, 129); -f(16711680, 255); -f(16777216, 256); -f(16842752, 257); -f(33488896, 511); -f(33554432, 512); -f(33619968, 513); -f(67043328, 1023); -f(67108864, 1024); -f(67174400, 1025); -f(134152192, 2047); -f(134217728, 2048); -f(134283264, 2049); -f(268369920, 4095); -f(268435456, 4096); -f(268500992, 4097); -f(536805376, 8191); -f(536870912, 8192); -f(536936448, 8193); -f(1073676288, 16383); -f(1073741824, 16384); -f(1073807360, 16385); -f(2147418112, 32767); -f(2147483648, 32768); -f(2147549184, 32769); -f(4294901760, 65535); -f(4294967296, 65536); -x = 65537; -f(0, 0); -f(65537, 1); -f(131074, 2); -f(196611, 3); -f(262148, 4); -f(327685, 5); -f(458759, 7); -f(524296, 8); -f(589833, 9); -f(983055, 15); -f(1048592, 16); -f(1114129, 17); -f(2031647, 31); -f(2097184, 32); -f(2162721, 33); -f(4128831, 63); -f(4194368, 64); -f(4259905, 65); -f(8323199, 127); -f(8388736, 128); -f(8454273, 129); -f(16711935, 255); -f(16777472, 256); -f(16843009, 257); -f(33489407, 511); -f(33554944, 512); -f(33620481, 513); -f(67044351, 1023); -f(67109888, 1024); -f(67175425, 1025); -f(134154239, 2047); -f(134219776, 2048); -f(134285313, 2049); -f(268374015, 4095); -f(268439552, 4096); -f(268505089, 4097); -f(536813567, 8191); -f(536879104, 8192); -f(536944641, 8193); -f(1073692671, 16383); -f(1073758208, 16384); -f(1073823745, 16385); -f(2147450879, 32767); -f(2147516416, 32768); -f(2147581953, 32769); -f(4294967295, 65535); -f(4295032832, 65536); -f(4295098369, 65537); -x = 131071; -f(0, 0); -f(131071, 1); -f(262142, 2); -f(393213, 3); -f(524284, 4); -f(655355, 5); -f(917497, 7); -f(1048568, 8); -f(1179639, 9); -f(1966065, 15); -f(2097136, 16); -f(2228207, 17); -f(4063201, 31); -f(4194272, 32); -f(4325343, 33); -f(8257473, 63); -f(8388544, 64); -f(8519615, 65); -f(16646017, 127); -f(16777088, 128); -f(16908159, 129); -f(33423105, 255); -f(33554176, 256); -f(33685247, 257); -f(66977281, 511); -f(67108352, 512); -f(67239423, 513); -f(134085633, 1023); -f(134216704, 1024); -f(134347775, 1025); -f(268302337, 2047); -f(268433408, 2048); -f(268564479, 2049); -f(536735745, 4095); -f(536866816, 4096); -f(536997887, 4097); -f(1073602561, 8191); -f(1073733632, 8192); -f(1073864703, 8193); -f(2147336193, 16383); -f(2147467264, 16384); -f(2147598335, 16385); -f(4294803457, 32767); -f(4294934528, 32768); -f(4295065599, 32769); -f(8589737985, 65535); -f(8589869056, 65536); -f(8590000127, 65537); -f(17179607041, 131071); -x = 131072; -f(0, 0); -f(131072, 1); -f(262144, 2); -f(393216, 3); -f(524288, 4); -f(655360, 5); -f(917504, 7); -f(1048576, 8); -f(1179648, 9); -f(1966080, 15); -f(2097152, 16); -f(2228224, 17); -f(4063232, 31); -f(4194304, 32); -f(4325376, 33); -f(8257536, 63); -f(8388608, 64); -f(8519680, 65); -f(16646144, 127); -f(16777216, 128); -f(16908288, 129); -f(33423360, 255); -f(33554432, 256); -f(33685504, 257); -f(66977792, 511); -f(67108864, 512); -f(67239936, 513); -f(134086656, 1023); -f(134217728, 1024); -f(134348800, 1025); -f(268304384, 2047); -f(268435456, 2048); -f(268566528, 2049); -f(536739840, 4095); -f(536870912, 4096); -f(537001984, 4097); -f(1073610752, 8191); -f(1073741824, 8192); -f(1073872896, 8193); -f(2147352576, 16383); -f(2147483648, 16384); -f(2147614720, 16385); -f(4294836224, 32767); -f(4294967296, 32768); -f(4295098368, 32769); -f(8589803520, 65535); -f(8589934592, 65536); -f(8590065664, 65537); -f(17179738112, 131071); -f(17179869184, 131072); -x = 131073; -f(0, 0); -f(131073, 1); -f(262146, 2); -f(393219, 3); -f(524292, 4); -f(655365, 5); -f(917511, 7); -f(1048584, 8); -f(1179657, 9); -f(1966095, 15); -f(2097168, 16); -f(2228241, 17); -f(4063263, 31); -f(4194336, 32); -f(4325409, 33); -f(8257599, 63); -f(8388672, 64); -f(8519745, 65); -f(16646271, 127); -f(16777344, 128); -f(16908417, 129); -f(33423615, 255); -f(33554688, 256); -f(33685761, 257); -f(66978303, 511); -f(67109376, 512); -f(67240449, 513); -f(134087679, 1023); -f(134218752, 1024); -f(134349825, 1025); -f(268306431, 2047); -f(268437504, 2048); -f(268568577, 2049); -f(536743935, 4095); -f(536875008, 4096); -f(537006081, 4097); -f(1073618943, 8191); -f(1073750016, 8192); -f(1073881089, 8193); -f(2147368959, 16383); -f(2147500032, 16384); -f(2147631105, 16385); -f(4294868991, 32767); -f(4295000064, 32768); -f(4295131137, 32769); -f(8589869055, 65535); -f(8590000128, 65536); -f(8590131201, 65537); -f(17179869183, 131071); -f(17180000256, 131072); -f(17180131329, 131073); -x = 262143; -f(0, 0); -f(262143, 1); -f(524286, 2); -f(786429, 3); -f(1048572, 4); -f(1310715, 5); -f(1835001, 7); -f(2097144, 8); -f(2359287, 9); -f(3932145, 15); -f(4194288, 16); -f(4456431, 17); -f(8126433, 31); -f(8388576, 32); -f(8650719, 33); -f(16515009, 63); -f(16777152, 64); -f(17039295, 65); -f(33292161, 127); -f(33554304, 128); -f(33816447, 129); -f(66846465, 255); -f(67108608, 256); -f(67370751, 257); -f(133955073, 511); -f(134217216, 512); -f(134479359, 513); -f(268172289, 1023); -f(268434432, 1024); -f(268696575, 1025); -f(536606721, 2047); -f(536868864, 2048); -f(537131007, 2049); -f(1073475585, 4095); -f(1073737728, 4096); -f(1073999871, 4097); -f(2147213313, 8191); -f(2147475456, 8192); -f(2147737599, 8193); -f(4294688769, 16383); -f(4294950912, 16384); -f(4295213055, 16385); -f(8589639681, 32767); -f(8589901824, 32768); -f(8590163967, 32769); -f(17179541505, 65535); -f(17179803648, 65536); -f(17180065791, 65537); -f(34359345153, 131071); -f(34359607296, 131072); -f(34359869439, 131073); -f(68718952449, 262143); -x = 262144; -f(0, 0); -f(262144, 1); -f(524288, 2); -f(786432, 3); -f(1048576, 4); -f(1310720, 5); -f(1835008, 7); -f(2097152, 8); -f(2359296, 9); -f(3932160, 15); -f(4194304, 16); -f(4456448, 17); -f(8126464, 31); -f(8388608, 32); -f(8650752, 33); -f(16515072, 63); -f(16777216, 64); -f(17039360, 65); -f(33292288, 127); -f(33554432, 128); -f(33816576, 129); -f(66846720, 255); -f(67108864, 256); -f(67371008, 257); -f(133955584, 511); -f(134217728, 512); -f(134479872, 513); -f(268173312, 1023); -f(268435456, 1024); -f(268697600, 1025); -f(536608768, 2047); -f(536870912, 2048); -f(537133056, 2049); -f(1073479680, 4095); -f(1073741824, 4096); -f(1074003968, 4097); -f(2147221504, 8191); -f(2147483648, 8192); -f(2147745792, 8193); -f(4294705152, 16383); -f(4294967296, 16384); -f(4295229440, 16385); -f(8589672448, 32767); -f(8589934592, 32768); -f(8590196736, 32769); -f(17179607040, 65535); -f(17179869184, 65536); -f(17180131328, 65537); -f(34359476224, 131071); -f(34359738368, 131072); -f(34360000512, 131073); -f(68719214592, 262143); -f(68719476736, 262144); -x = 262145; -f(0, 0); -f(262145, 1); -f(524290, 2); -f(786435, 3); -f(1048580, 4); -f(1310725, 5); -f(1835015, 7); -f(2097160, 8); -f(2359305, 9); -f(3932175, 15); -f(4194320, 16); -f(4456465, 17); -f(8126495, 31); -f(8388640, 32); -f(8650785, 33); -f(16515135, 63); -f(16777280, 64); -f(17039425, 65); -f(33292415, 127); -f(33554560, 128); -f(33816705, 129); -f(66846975, 255); -f(67109120, 256); -f(67371265, 257); -f(133956095, 511); -f(134218240, 512); -f(134480385, 513); -f(268174335, 1023); -f(268436480, 1024); -f(268698625, 1025); -f(536610815, 2047); -f(536872960, 2048); -f(537135105, 2049); -f(1073483775, 4095); -f(1073745920, 4096); -f(1074008065, 4097); -f(2147229695, 8191); -f(2147491840, 8192); -f(2147753985, 8193); -f(4294721535, 16383); -f(4294983680, 16384); -f(4295245825, 16385); -f(8589705215, 32767); -f(8589967360, 32768); -f(8590229505, 32769); -f(17179672575, 65535); -f(17179934720, 65536); -f(17180196865, 65537); -f(34359607295, 131071); -f(34359869440, 131072); -f(34360131585, 131073); -f(68719476735, 262143); -f(68719738880, 262144); -f(68720001025, 262145); -x = 524287; -f(0, 0); -f(524287, 1); -f(1048574, 2); -f(1572861, 3); -f(2097148, 4); -f(2621435, 5); -f(3670009, 7); -f(4194296, 8); -f(4718583, 9); -f(7864305, 15); -f(8388592, 16); -f(8912879, 17); -f(16252897, 31); -f(16777184, 32); -f(17301471, 33); -f(33030081, 63); -f(33554368, 64); -f(34078655, 65); -f(66584449, 127); -f(67108736, 128); -f(67633023, 129); -f(133693185, 255); -f(134217472, 256); -f(134741759, 257); -f(267910657, 511); -f(268434944, 512); -f(268959231, 513); -f(536345601, 1023); -f(536869888, 1024); -f(537394175, 1025); -f(1073215489, 2047); -f(1073739776, 2048); -f(1074264063, 2049); -f(2146955265, 4095); -f(2147479552, 4096); -f(2148003839, 4097); -f(4294434817, 8191); -f(4294959104, 8192); -f(4295483391, 8193); -f(8589393921, 16383); -f(8589918208, 16384); -f(8590442495, 16385); -f(17179312129, 32767); -f(17179836416, 32768); -f(17180360703, 32769); -f(34359148545, 65535); -f(34359672832, 65536); -f(34360197119, 65537); -f(68718821377, 131071); -f(68719345664, 131072); -f(68719869951, 131073); -f(137438167041, 262143); -f(137438691328, 262144); -f(137439215615, 262145); -f(274876858369, 524287); -x = 524288; -f(0, 0); -f(524288, 1); -f(1048576, 2); -f(1572864, 3); -f(2097152, 4); -f(2621440, 5); -f(3670016, 7); -f(4194304, 8); -f(4718592, 9); -f(7864320, 15); -f(8388608, 16); -f(8912896, 17); -f(16252928, 31); -f(16777216, 32); -f(17301504, 33); -f(33030144, 63); -f(33554432, 64); -f(34078720, 65); -f(66584576, 127); -f(67108864, 128); -f(67633152, 129); -f(133693440, 255); -f(134217728, 256); -f(134742016, 257); -f(267911168, 511); -f(268435456, 512); -f(268959744, 513); -f(536346624, 1023); -f(536870912, 1024); -f(537395200, 1025); -f(1073217536, 2047); -f(1073741824, 2048); -f(1074266112, 2049); -f(2146959360, 4095); -f(2147483648, 4096); -f(2148007936, 4097); -f(4294443008, 8191); -f(4294967296, 8192); -f(4295491584, 8193); -f(8589410304, 16383); -f(8589934592, 16384); -f(8590458880, 16385); -f(17179344896, 32767); -f(17179869184, 32768); -f(17180393472, 32769); -f(34359214080, 65535); -f(34359738368, 65536); -f(34360262656, 65537); -f(68718952448, 131071); -f(68719476736, 131072); -f(68720001024, 131073); -f(137438429184, 262143); -f(137438953472, 262144); -f(137439477760, 262145); -f(274877382656, 524287); -f(274877906944, 524288); -x = 524289; -f(0, 0); -f(524289, 1); -f(1048578, 2); -f(1572867, 3); -f(2097156, 4); -f(2621445, 5); -f(3670023, 7); -f(4194312, 8); -f(4718601, 9); -f(7864335, 15); -f(8388624, 16); -f(8912913, 17); -f(16252959, 31); -f(16777248, 32); -f(17301537, 33); -f(33030207, 63); -f(33554496, 64); -f(34078785, 65); -f(66584703, 127); -f(67108992, 128); -f(67633281, 129); -f(133693695, 255); -f(134217984, 256); -f(134742273, 257); -f(267911679, 511); -f(268435968, 512); -f(268960257, 513); -f(536347647, 1023); -f(536871936, 1024); -f(537396225, 1025); -f(1073219583, 2047); -f(1073743872, 2048); -f(1074268161, 2049); -f(2146963455, 4095); -f(2147487744, 4096); -f(2148012033, 4097); -f(4294451199, 8191); -f(4294975488, 8192); -f(4295499777, 8193); -f(8589426687, 16383); -f(8589950976, 16384); -f(8590475265, 16385); -f(17179377663, 32767); -f(17179901952, 32768); -f(17180426241, 32769); -f(34359279615, 65535); -f(34359803904, 65536); -f(34360328193, 65537); -f(68719083519, 131071); -f(68719607808, 131072); -f(68720132097, 131073); -f(137438691327, 262143); -f(137439215616, 262144); -f(137439739905, 262145); -f(274877906943, 524287); -f(274878431232, 524288); -f(274878955521, 524289); -x = 1048575; -f(0, 0); -f(1048575, 1); -f(2097150, 2); -f(3145725, 3); -f(4194300, 4); -f(5242875, 5); -f(7340025, 7); -f(8388600, 8); -f(9437175, 9); -f(15728625, 15); -f(16777200, 16); -f(17825775, 17); -f(32505825, 31); -f(33554400, 32); -f(34602975, 33); -f(66060225, 63); -f(67108800, 64); -f(68157375, 65); -f(133169025, 127); -f(134217600, 128); -f(135266175, 129); -f(267386625, 255); -f(268435200, 256); -f(269483775, 257); -f(535821825, 511); -f(536870400, 512); -f(537918975, 513); -f(1072692225, 1023); -f(1073740800, 1024); -f(1074789375, 1025); -f(2146433025, 2047); -f(2147481600, 2048); -f(2148530175, 2049); -f(4293914625, 4095); -f(4294963200, 4096); -f(4296011775, 4097); -f(8588877825, 8191); -f(8589926400, 8192); -f(8590974975, 8193); -f(17178804225, 16383); -f(17179852800, 16384); -f(17180901375, 16385); -f(34358657025, 32767); -f(34359705600, 32768); -f(34360754175, 32769); -f(68718362625, 65535); -f(68719411200, 65536); -f(68720459775, 65537); -f(137437773825, 131071); -f(137438822400, 131072); -f(137439870975, 131073); -f(274876596225, 262143); -f(274877644800, 262144); -f(274878693375, 262145); -f(549754241025, 524287); -f(549755289600, 524288); -f(549756338175, 524289); -f(1099509530625, 1048575); -x = 1048576; -f(0, 0); -f(1048576, 1); -f(2097152, 2); -f(3145728, 3); -f(4194304, 4); -f(5242880, 5); -f(7340032, 7); -f(8388608, 8); -f(9437184, 9); -f(15728640, 15); -f(16777216, 16); -f(17825792, 17); -f(32505856, 31); -f(33554432, 32); -f(34603008, 33); -f(66060288, 63); -f(67108864, 64); -f(68157440, 65); -f(133169152, 127); -f(134217728, 128); -f(135266304, 129); -f(267386880, 255); -f(268435456, 256); -f(269484032, 257); -f(535822336, 511); -f(536870912, 512); -f(537919488, 513); -f(1072693248, 1023); -f(1073741824, 1024); -f(1074790400, 1025); -f(2146435072, 2047); -f(2147483648, 2048); -f(2148532224, 2049); -f(4293918720, 4095); -f(4294967296, 4096); -f(4296015872, 4097); -f(8588886016, 8191); -f(8589934592, 8192); -f(8590983168, 8193); -f(17178820608, 16383); -f(17179869184, 16384); -f(17180917760, 16385); -f(34358689792, 32767); -f(34359738368, 32768); -f(34360786944, 32769); -f(68718428160, 65535); -f(68719476736, 65536); -f(68720525312, 65537); -f(137437904896, 131071); -f(137438953472, 131072); -f(137440002048, 131073); -f(274876858368, 262143); -f(274877906944, 262144); -f(274878955520, 262145); -f(549754765312, 524287); -f(549755813888, 524288); -f(549756862464, 524289); -f(1099510579200, 1048575); -f(1099511627776, 1048576); -x = 1048577; -f(0, 0); -f(1048577, 1); -f(2097154, 2); -f(3145731, 3); -f(4194308, 4); -f(5242885, 5); -f(7340039, 7); -f(8388616, 8); -f(9437193, 9); -f(15728655, 15); -f(16777232, 16); -f(17825809, 17); -f(32505887, 31); -f(33554464, 32); -f(34603041, 33); -f(66060351, 63); -f(67108928, 64); -f(68157505, 65); -f(133169279, 127); -f(134217856, 128); -f(135266433, 129); -f(267387135, 255); -f(268435712, 256); -f(269484289, 257); -f(535822847, 511); -f(536871424, 512); -f(537920001, 513); -f(1072694271, 1023); -f(1073742848, 1024); -f(1074791425, 1025); -f(2146437119, 2047); -f(2147485696, 2048); -f(2148534273, 2049); -f(4293922815, 4095); -f(4294971392, 4096); -f(4296019969, 4097); -f(8588894207, 8191); -f(8589942784, 8192); -f(8590991361, 8193); -f(17178836991, 16383); -f(17179885568, 16384); -f(17180934145, 16385); -f(34358722559, 32767); -f(34359771136, 32768); -f(34360819713, 32769); -f(68718493695, 65535); -f(68719542272, 65536); -f(68720590849, 65537); -f(137438035967, 131071); -f(137439084544, 131072); -f(137440133121, 131073); -f(274877120511, 262143); -f(274878169088, 262144); -f(274879217665, 262145); -f(549755289599, 524287); -f(549756338176, 524288); -f(549757386753, 524289); -f(1099511627775, 1048575); -f(1099512676352, 1048576); -f(1099513724929, 1048577); -x = 2097151; -f(0, 0); -f(2097151, 1); -f(4194302, 2); -f(6291453, 3); -f(8388604, 4); -f(10485755, 5); -f(14680057, 7); -f(16777208, 8); -f(18874359, 9); -f(31457265, 15); -f(33554416, 16); -f(35651567, 17); -f(65011681, 31); -f(67108832, 32); -f(69205983, 33); -f(132120513, 63); -f(134217664, 64); -f(136314815, 65); -f(266338177, 127); -f(268435328, 128); -f(270532479, 129); -f(534773505, 255); -f(536870656, 256); -f(538967807, 257); -f(1071644161, 511); -f(1073741312, 512); -f(1075838463, 513); -f(2145385473, 1023); -f(2147482624, 1024); -f(2149579775, 1025); -f(4292868097, 2047); -f(4294965248, 2048); -f(4297062399, 2049); -f(8587833345, 4095); -f(8589930496, 4096); -f(8592027647, 4097); -f(17177763841, 8191); -f(17179860992, 8192); -f(17181958143, 8193); -f(34357624833, 16383); -f(34359721984, 16384); -f(34361819135, 16385); -f(68717346817, 32767); -f(68719443968, 32768); -f(68721541119, 32769); -f(137436790785, 65535); -f(137438887936, 65536); -f(137440985087, 65537); -f(274875678721, 131071); -f(274877775872, 131072); -f(274879873023, 131073); -f(549753454593, 262143); -f(549755551744, 262144); -f(549757648895, 262145); -f(1099509006337, 524287); -f(1099511103488, 524288); -f(1099513200639, 524289); -f(2199020109825, 1048575); -f(2199022206976, 1048576); -f(2199024304127, 1048577); -f(4398042316801, 2097151); -x = 2097152; -f(0, 0); -f(2097152, 1); -f(4194304, 2); -f(6291456, 3); -f(8388608, 4); -f(10485760, 5); -f(14680064, 7); -f(16777216, 8); -f(18874368, 9); -f(31457280, 15); -f(33554432, 16); -f(35651584, 17); -f(65011712, 31); -f(67108864, 32); -f(69206016, 33); -f(132120576, 63); -f(134217728, 64); -f(136314880, 65); -f(266338304, 127); -f(268435456, 128); -f(270532608, 129); -f(534773760, 255); -f(536870912, 256); -f(538968064, 257); -f(1071644672, 511); -f(1073741824, 512); -f(1075838976, 513); -f(2145386496, 1023); -f(2147483648, 1024); -f(2149580800, 1025); -f(4292870144, 2047); -f(4294967296, 2048); -f(4297064448, 2049); -f(8587837440, 4095); -f(8589934592, 4096); -f(8592031744, 4097); -f(17177772032, 8191); -f(17179869184, 8192); -f(17181966336, 8193); -f(34357641216, 16383); -f(34359738368, 16384); -f(34361835520, 16385); -f(68717379584, 32767); -f(68719476736, 32768); -f(68721573888, 32769); -f(137436856320, 65535); -f(137438953472, 65536); -f(137441050624, 65537); -f(274875809792, 131071); -f(274877906944, 131072); -f(274880004096, 131073); -f(549753716736, 262143); -f(549755813888, 262144); -f(549757911040, 262145); -f(1099509530624, 524287); -f(1099511627776, 524288); -f(1099513724928, 524289); -f(2199021158400, 1048575); -f(2199023255552, 1048576); -f(2199025352704, 1048577); -f(4398044413952, 2097151); -f(4398046511104, 2097152); -x = 2097153; -f(0, 0); -f(2097153, 1); -f(4194306, 2); -f(6291459, 3); -f(8388612, 4); -f(10485765, 5); -f(14680071, 7); -f(16777224, 8); -f(18874377, 9); -f(31457295, 15); -f(33554448, 16); -f(35651601, 17); -f(65011743, 31); -f(67108896, 32); -f(69206049, 33); -f(132120639, 63); -f(134217792, 64); -f(136314945, 65); -f(266338431, 127); -f(268435584, 128); -f(270532737, 129); -f(534774015, 255); -f(536871168, 256); -f(538968321, 257); -f(1071645183, 511); -f(1073742336, 512); -f(1075839489, 513); -f(2145387519, 1023); -f(2147484672, 1024); -f(2149581825, 1025); -f(4292872191, 2047); -f(4294969344, 2048); -f(4297066497, 2049); -f(8587841535, 4095); -f(8589938688, 4096); -f(8592035841, 4097); -f(17177780223, 8191); -f(17179877376, 8192); -f(17181974529, 8193); -f(34357657599, 16383); -f(34359754752, 16384); -f(34361851905, 16385); -f(68717412351, 32767); -f(68719509504, 32768); -f(68721606657, 32769); -f(137436921855, 65535); -f(137439019008, 65536); -f(137441116161, 65537); -f(274875940863, 131071); -f(274878038016, 131072); -f(274880135169, 131073); -f(549753978879, 262143); -f(549756076032, 262144); -f(549758173185, 262145); -f(1099510054911, 524287); -f(1099512152064, 524288); -f(1099514249217, 524289); -f(2199022206975, 1048575); -f(2199024304128, 1048576); -f(2199026401281, 1048577); -f(4398046511103, 2097151); -f(4398048608256, 2097152); -f(4398050705409, 2097153); -x = 4194303; -f(0, 0); -f(4194303, 1); -f(8388606, 2); -f(12582909, 3); -f(16777212, 4); -f(20971515, 5); -f(29360121, 7); -f(33554424, 8); -f(37748727, 9); -f(62914545, 15); -f(67108848, 16); -f(71303151, 17); -f(130023393, 31); -f(134217696, 32); -f(138411999, 33); -f(264241089, 63); -f(268435392, 64); -f(272629695, 65); -f(532676481, 127); -f(536870784, 128); -f(541065087, 129); -f(1069547265, 255); -f(1073741568, 256); -f(1077935871, 257); -f(2143288833, 511); -f(2147483136, 512); -f(2151677439, 513); -f(4290771969, 1023); -f(4294966272, 1024); -f(4299160575, 1025); -f(8585738241, 2047); -f(8589932544, 2048); -f(8594126847, 2049); -f(17175670785, 4095); -f(17179865088, 4096); -f(17184059391, 4097); -f(34355535873, 8191); -f(34359730176, 8192); -f(34363924479, 8193); -f(68715266049, 16383); -f(68719460352, 16384); -f(68723654655, 16385); -f(137434726401, 32767); -f(137438920704, 32768); -f(137443115007, 32769); -f(274873647105, 65535); -f(274877841408, 65536); -f(274882035711, 65537); -f(549751488513, 131071); -f(549755682816, 131072); -f(549759877119, 131073); -f(1099507171329, 262143); -f(1099511365632, 262144); -f(1099515559935, 262145); -f(2199018536961, 524287); -f(2199022731264, 524288); -f(2199026925567, 524289); -f(4398041268225, 1048575); -f(4398045462528, 1048576); -f(4398049656831, 1048577); -f(8796086730753, 2097151); -f(8796090925056, 2097152); -f(8796095119359, 2097153); -f(17592177655809, 4194303); -x = 4194304; -f(0, 0); -f(4194304, 1); -f(8388608, 2); -f(12582912, 3); -f(16777216, 4); -f(20971520, 5); -f(29360128, 7); -f(33554432, 8); -f(37748736, 9); -f(62914560, 15); -f(67108864, 16); -f(71303168, 17); -f(130023424, 31); -f(134217728, 32); -f(138412032, 33); -f(264241152, 63); -f(268435456, 64); -f(272629760, 65); -f(532676608, 127); -f(536870912, 128); -f(541065216, 129); -f(1069547520, 255); -f(1073741824, 256); -f(1077936128, 257); -f(2143289344, 511); -f(2147483648, 512); -f(2151677952, 513); -f(4290772992, 1023); -f(4294967296, 1024); -f(4299161600, 1025); -f(8585740288, 2047); -f(8589934592, 2048); -f(8594128896, 2049); -f(17175674880, 4095); -f(17179869184, 4096); -f(17184063488, 4097); -f(34355544064, 8191); -f(34359738368, 8192); -f(34363932672, 8193); -f(68715282432, 16383); -f(68719476736, 16384); -f(68723671040, 16385); -f(137434759168, 32767); -f(137438953472, 32768); -f(137443147776, 32769); -f(274873712640, 65535); -f(274877906944, 65536); -f(274882101248, 65537); -f(549751619584, 131071); -f(549755813888, 131072); -f(549760008192, 131073); -f(1099507433472, 262143); -f(1099511627776, 262144); -f(1099515822080, 262145); -f(2199019061248, 524287); -f(2199023255552, 524288); -f(2199027449856, 524289); -f(4398042316800, 1048575); -f(4398046511104, 1048576); -f(4398050705408, 1048577); -f(8796088827904, 2097151); -f(8796093022208, 2097152); -f(8796097216512, 2097153); -f(17592181850112, 4194303); -f(17592186044416, 4194304); -x = 4194305; -f(0, 0); -f(4194305, 1); -f(8388610, 2); -f(12582915, 3); -f(16777220, 4); -f(20971525, 5); -f(29360135, 7); -f(33554440, 8); -f(37748745, 9); -f(62914575, 15); -f(67108880, 16); -f(71303185, 17); -f(130023455, 31); -f(134217760, 32); -f(138412065, 33); -f(264241215, 63); -f(268435520, 64); -f(272629825, 65); -f(532676735, 127); -f(536871040, 128); -f(541065345, 129); -f(1069547775, 255); -f(1073742080, 256); -f(1077936385, 257); -f(2143289855, 511); -f(2147484160, 512); -f(2151678465, 513); -f(4290774015, 1023); -f(4294968320, 1024); -f(4299162625, 1025); -f(8585742335, 2047); -f(8589936640, 2048); -f(8594130945, 2049); -f(17175678975, 4095); -f(17179873280, 4096); -f(17184067585, 4097); -f(34355552255, 8191); -f(34359746560, 8192); -f(34363940865, 8193); -f(68715298815, 16383); -f(68719493120, 16384); -f(68723687425, 16385); -f(137434791935, 32767); -f(137438986240, 32768); -f(137443180545, 32769); -f(274873778175, 65535); -f(274877972480, 65536); -f(274882166785, 65537); -f(549751750655, 131071); -f(549755944960, 131072); -f(549760139265, 131073); -f(1099507695615, 262143); -f(1099511889920, 262144); -f(1099516084225, 262145); -f(2199019585535, 524287); -f(2199023779840, 524288); -f(2199027974145, 524289); -f(4398043365375, 1048575); -f(4398047559680, 1048576); -f(4398051753985, 1048577); -f(8796090925055, 2097151); -f(8796095119360, 2097152); -f(8796099313665, 2097153); -f(17592186044415, 4194303); -f(17592190238720, 4194304); -f(17592194433025, 4194305); -x = 8388607; -f(0, 0); -f(8388607, 1); -f(16777214, 2); -f(25165821, 3); -f(33554428, 4); -f(41943035, 5); -f(58720249, 7); -f(67108856, 8); -f(75497463, 9); -f(125829105, 15); -f(134217712, 16); -f(142606319, 17); -f(260046817, 31); -f(268435424, 32); -f(276824031, 33); -f(528482241, 63); -f(536870848, 64); -f(545259455, 65); -f(1065353089, 127); -f(1073741696, 128); -f(1082130303, 129); -f(2139094785, 255); -f(2147483392, 256); -f(2155871999, 257); -f(4286578177, 511); -f(4294966784, 512); -f(4303355391, 513); -f(8581544961, 1023); -f(8589933568, 1024); -f(8598322175, 1025); -f(17171478529, 2047); -f(17179867136, 2048); -f(17188255743, 2049); -f(34351345665, 4095); -f(34359734272, 4096); -f(34368122879, 4097); -f(68711079937, 8191); -f(68719468544, 8192); -f(68727857151, 8193); -f(137430548481, 16383); -f(137438937088, 16384); -f(137447325695, 16385); -f(274869485569, 32767); -f(274877874176, 32768); -f(274886262783, 32769); -f(549747359745, 65535); -f(549755748352, 65536); -f(549764136959, 65537); -f(1099503108097, 131071); -f(1099511496704, 131072); -f(1099519885311, 131073); -f(2199014604801, 262143); -f(2199022993408, 262144); -f(2199031382015, 262145); -f(4398037598209, 524287); -f(4398045986816, 524288); -f(4398054375423, 524289); -f(8796083585025, 1048575); -f(8796091973632, 1048576); -f(8796100362239, 1048577); -f(17592175558657, 2097151); -f(17592183947264, 2097152); -f(17592192335871, 2097153); -f(35184359505921, 4194303); -f(35184367894528, 4194304); -f(35184376283135, 4194305); -f(70368727400449, 8388607); -x = 8388608; -f(0, 0); -f(8388608, 1); -f(16777216, 2); -f(25165824, 3); -f(33554432, 4); -f(41943040, 5); -f(58720256, 7); -f(67108864, 8); -f(75497472, 9); -f(125829120, 15); -f(134217728, 16); -f(142606336, 17); -f(260046848, 31); -f(268435456, 32); -f(276824064, 33); -f(528482304, 63); -f(536870912, 64); -f(545259520, 65); -f(1065353216, 127); -f(1073741824, 128); -f(1082130432, 129); -f(2139095040, 255); -f(2147483648, 256); -f(2155872256, 257); -f(4286578688, 511); -f(4294967296, 512); -f(4303355904, 513); -f(8581545984, 1023); -f(8589934592, 1024); -f(8598323200, 1025); -f(17171480576, 2047); -f(17179869184, 2048); -f(17188257792, 2049); -f(34351349760, 4095); -f(34359738368, 4096); -f(34368126976, 4097); -f(68711088128, 8191); -f(68719476736, 8192); -f(68727865344, 8193); -f(137430564864, 16383); -f(137438953472, 16384); -f(137447342080, 16385); -f(274869518336, 32767); -f(274877906944, 32768); -f(274886295552, 32769); -f(549747425280, 65535); -f(549755813888, 65536); -f(549764202496, 65537); -f(1099503239168, 131071); -f(1099511627776, 131072); -f(1099520016384, 131073); -f(2199014866944, 262143); -f(2199023255552, 262144); -f(2199031644160, 262145); -f(4398038122496, 524287); -f(4398046511104, 524288); -f(4398054899712, 524289); -f(8796084633600, 1048575); -f(8796093022208, 1048576); -f(8796101410816, 1048577); -f(17592177655808, 2097151); -f(17592186044416, 2097152); -f(17592194433024, 2097153); -f(35184363700224, 4194303); -f(35184372088832, 4194304); -f(35184380477440, 4194305); -f(70368735789056, 8388607); -f(70368744177664, 8388608); -x = 8388609; -f(0, 0); -f(8388609, 1); -f(16777218, 2); -f(25165827, 3); -f(33554436, 4); -f(41943045, 5); -f(58720263, 7); -f(67108872, 8); -f(75497481, 9); -f(125829135, 15); -f(134217744, 16); -f(142606353, 17); -f(260046879, 31); -f(268435488, 32); -f(276824097, 33); -f(528482367, 63); -f(536870976, 64); -f(545259585, 65); -f(1065353343, 127); -f(1073741952, 128); -f(1082130561, 129); -f(2139095295, 255); -f(2147483904, 256); -f(2155872513, 257); -f(4286579199, 511); -f(4294967808, 512); -f(4303356417, 513); -f(8581547007, 1023); -f(8589935616, 1024); -f(8598324225, 1025); -f(17171482623, 2047); -f(17179871232, 2048); -f(17188259841, 2049); -f(34351353855, 4095); -f(34359742464, 4096); -f(34368131073, 4097); -f(68711096319, 8191); -f(68719484928, 8192); -f(68727873537, 8193); -f(137430581247, 16383); -f(137438969856, 16384); -f(137447358465, 16385); -f(274869551103, 32767); -f(274877939712, 32768); -f(274886328321, 32769); -f(549747490815, 65535); -f(549755879424, 65536); -f(549764268033, 65537); -f(1099503370239, 131071); -f(1099511758848, 131072); -f(1099520147457, 131073); -f(2199015129087, 262143); -f(2199023517696, 262144); -f(2199031906305, 262145); -f(4398038646783, 524287); -f(4398047035392, 524288); -f(4398055424001, 524289); -f(8796085682175, 1048575); -f(8796094070784, 1048576); -f(8796102459393, 1048577); -f(17592179752959, 2097151); -f(17592188141568, 2097152); -f(17592196530177, 2097153); -f(35184367894527, 4194303); -f(35184376283136, 4194304); -f(35184384671745, 4194305); -f(70368744177663, 8388607); -f(70368752566272, 8388608); -f(70368760954881, 8388609); -x = 16777215; -f(0, 0); -f(16777215, 1); -f(33554430, 2); -f(50331645, 3); -f(67108860, 4); -f(83886075, 5); -f(117440505, 7); -f(134217720, 8); -f(150994935, 9); -f(251658225, 15); -f(268435440, 16); -f(285212655, 17); -f(520093665, 31); -f(536870880, 32); -f(553648095, 33); -f(1056964545, 63); -f(1073741760, 64); -f(1090518975, 65); -f(2130706305, 127); -f(2147483520, 128); -f(2164260735, 129); -f(4278189825, 255); -f(4294967040, 256); -f(4311744255, 257); -f(8573156865, 511); -f(8589934080, 512); -f(8606711295, 513); -f(17163090945, 1023); -f(17179868160, 1024); -f(17196645375, 1025); -f(34342959105, 2047); -f(34359736320, 2048); -f(34376513535, 2049); -f(68702695425, 4095); -f(68719472640, 4096); -f(68736249855, 4097); -f(137422168065, 8191); -f(137438945280, 8192); -f(137455722495, 8193); -f(274861113345, 16383); -f(274877890560, 16384); -f(274894667775, 16385); -f(549739003905, 32767); -f(549755781120, 32768); -f(549772558335, 32769); -f(1099494785025, 65535); -f(1099511562240, 65536); -f(1099528339455, 65537); -f(2199006347265, 131071); -f(2199023124480, 131072); -f(2199039901695, 131073); -f(4398029471745, 262143); -f(4398046248960, 262144); -f(4398063026175, 262145); -f(8796075720705, 524287); -f(8796092497920, 524288); -f(8796109275135, 524289); -f(17592168218625, 1048575); -f(17592184995840, 1048576); -f(17592201773055, 1048577); -f(35184353214465, 2097151); -f(35184369991680, 2097152); -f(35184386768895, 2097153); -f(70368723206145, 4194303); -f(70368739983360, 4194304); -f(70368756760575, 4194305); -f(140737463189505, 8388607); -f(140737479966720, 8388608); -f(140737496743935, 8388609); -f(281474943156225, 16777215); -x = 16777216; -f(0, 0); -f(16777216, 1); -f(33554432, 2); -f(50331648, 3); -f(67108864, 4); -f(83886080, 5); -f(117440512, 7); -f(134217728, 8); -f(150994944, 9); -f(251658240, 15); -f(268435456, 16); -f(285212672, 17); -f(520093696, 31); -f(536870912, 32); -f(553648128, 33); -f(1056964608, 63); -f(1073741824, 64); -f(1090519040, 65); -f(2130706432, 127); -f(2147483648, 128); -f(2164260864, 129); -f(4278190080, 255); -f(4294967296, 256); -f(4311744512, 257); -f(8573157376, 511); -f(8589934592, 512); -f(8606711808, 513); -f(17163091968, 1023); -f(17179869184, 1024); -f(17196646400, 1025); -f(34342961152, 2047); -f(34359738368, 2048); -f(34376515584, 2049); -f(68702699520, 4095); -f(68719476736, 4096); -f(68736253952, 4097); -f(137422176256, 8191); -f(137438953472, 8192); -f(137455730688, 8193); -f(274861129728, 16383); -f(274877906944, 16384); -f(274894684160, 16385); -f(549739036672, 32767); -f(549755813888, 32768); -f(549772591104, 32769); -f(1099494850560, 65535); -f(1099511627776, 65536); -f(1099528404992, 65537); -f(2199006478336, 131071); -f(2199023255552, 131072); -f(2199040032768, 131073); -f(4398029733888, 262143); -f(4398046511104, 262144); -f(4398063288320, 262145); -f(8796076244992, 524287); -f(8796093022208, 524288); -f(8796109799424, 524289); -f(17592169267200, 1048575); -f(17592186044416, 1048576); -f(17592202821632, 1048577); -f(35184355311616, 2097151); -f(35184372088832, 2097152); -f(35184388866048, 2097153); -f(70368727400448, 4194303); -f(70368744177664, 4194304); -f(70368760954880, 4194305); -f(140737471578112, 8388607); -f(140737488355328, 8388608); -f(140737505132544, 8388609); -f(281474959933440, 16777215); -f(281474976710656, 16777216); -x = 16777217; -f(0, 0); -f(16777217, 1); -f(33554434, 2); -f(50331651, 3); -f(67108868, 4); -f(83886085, 5); -f(117440519, 7); -f(134217736, 8); -f(150994953, 9); -f(251658255, 15); -f(268435472, 16); -f(285212689, 17); -f(520093727, 31); -f(536870944, 32); -f(553648161, 33); -f(1056964671, 63); -f(1073741888, 64); -f(1090519105, 65); -f(2130706559, 127); -f(2147483776, 128); -f(2164260993, 129); -f(4278190335, 255); -f(4294967552, 256); -f(4311744769, 257); -f(8573157887, 511); -f(8589935104, 512); -f(8606712321, 513); -f(17163092991, 1023); -f(17179870208, 1024); -f(17196647425, 1025); -f(34342963199, 2047); -f(34359740416, 2048); -f(34376517633, 2049); -f(68702703615, 4095); -f(68719480832, 4096); -f(68736258049, 4097); -f(137422184447, 8191); -f(137438961664, 8192); -f(137455738881, 8193); -f(274861146111, 16383); -f(274877923328, 16384); -f(274894700545, 16385); -f(549739069439, 32767); -f(549755846656, 32768); -f(549772623873, 32769); -f(1099494916095, 65535); -f(1099511693312, 65536); -f(1099528470529, 65537); -f(2199006609407, 131071); -f(2199023386624, 131072); -f(2199040163841, 131073); -f(4398029996031, 262143); -f(4398046773248, 262144); -f(4398063550465, 262145); -f(8796076769279, 524287); -f(8796093546496, 524288); -f(8796110323713, 524289); -f(17592170315775, 1048575); -f(17592187092992, 1048576); -f(17592203870209, 1048577); -f(35184357408767, 2097151); -f(35184374185984, 2097152); -f(35184390963201, 2097153); -f(70368731594751, 4194303); -f(70368748371968, 4194304); -f(70368765149185, 4194305); -f(140737479966719, 8388607); -f(140737496743936, 8388608); -f(140737513521153, 8388609); -f(281474976710655, 16777215); -f(281474993487872, 16777216); -f(281475010265089, 16777217); -x = 33554431; -f(0, 0); -f(33554431, 1); -f(67108862, 2); -f(100663293, 3); -f(134217724, 4); -f(167772155, 5); -f(234881017, 7); -f(268435448, 8); -f(301989879, 9); -f(503316465, 15); -f(536870896, 16); -f(570425327, 17); -f(1040187361, 31); -f(1073741792, 32); -f(1107296223, 33); -f(2113929153, 63); -f(2147483584, 64); -f(2181038015, 65); -f(4261412737, 127); -f(4294967168, 128); -f(4328521599, 129); -f(8556379905, 255); -f(8589934336, 256); -f(8623488767, 257); -f(17146314241, 511); -f(17179868672, 512); -f(17213423103, 513); -f(34326182913, 1023); -f(34359737344, 1024); -f(34393291775, 1025); -f(68685920257, 2047); -f(68719474688, 2048); -f(68753029119, 2049); -f(137405394945, 4095); -f(137438949376, 4096); -f(137472503807, 4097); -f(274844344321, 8191); -f(274877898752, 8192); -f(274911453183, 8193); -f(549722243073, 16383); -f(549755797504, 16384); -f(549789351935, 16385); -f(1099478040577, 32767); -f(1099511595008, 32768); -f(1099545149439, 32769); -f(2198989635585, 65535); -f(2199023190016, 65536); -f(2199056744447, 65537); -f(4398012825601, 131071); -f(4398046380032, 131072); -f(4398079934463, 131073); -f(8796059205633, 262143); -f(8796092760064, 262144); -f(8796126314495, 262145); -f(17592151965697, 524287); -f(17592185520128, 524288); -f(17592219074559, 524289); -f(35184337485825, 1048575); -f(35184371040256, 1048576); -f(35184404594687, 1048577); -f(70368708526081, 2097151); -f(70368742080512, 2097152); -f(70368775634943, 2097153); -f(140737450606593, 4194303); -f(140737484161024, 4194304); -f(140737517715455, 4194305); -f(281474934767617, 8388607); -f(281474968322048, 8388608); -f(281475001876479, 8388609); -f(562949903089665, 16777215); -f(562949936644096, 16777216); -f(562949970198527, 16777217); -f(1125899839733761, 33554431); -x = 33554432; -f(0, 0); -f(33554432, 1); -f(67108864, 2); -f(100663296, 3); -f(134217728, 4); -f(167772160, 5); -f(234881024, 7); -f(268435456, 8); -f(301989888, 9); -f(503316480, 15); -f(536870912, 16); -f(570425344, 17); -f(1040187392, 31); -f(1073741824, 32); -f(1107296256, 33); -f(2113929216, 63); -f(2147483648, 64); -f(2181038080, 65); -f(4261412864, 127); -f(4294967296, 128); -f(4328521728, 129); -f(8556380160, 255); -f(8589934592, 256); -f(8623489024, 257); -f(17146314752, 511); -f(17179869184, 512); -f(17213423616, 513); -f(34326183936, 1023); -f(34359738368, 1024); -f(34393292800, 1025); -f(68685922304, 2047); -f(68719476736, 2048); -f(68753031168, 2049); -f(137405399040, 4095); -f(137438953472, 4096); -f(137472507904, 4097); -f(274844352512, 8191); -f(274877906944, 8192); -f(274911461376, 8193); -f(549722259456, 16383); -f(549755813888, 16384); -f(549789368320, 16385); -f(1099478073344, 32767); -f(1099511627776, 32768); -f(1099545182208, 32769); -f(2198989701120, 65535); -f(2199023255552, 65536); -f(2199056809984, 65537); -f(4398012956672, 131071); -f(4398046511104, 131072); -f(4398080065536, 131073); -f(8796059467776, 262143); -f(8796093022208, 262144); -f(8796126576640, 262145); -f(17592152489984, 524287); -f(17592186044416, 524288); -f(17592219598848, 524289); -f(35184338534400, 1048575); -f(35184372088832, 1048576); -f(35184405643264, 1048577); -f(70368710623232, 2097151); -f(70368744177664, 2097152); -f(70368777732096, 2097153); -f(140737454800896, 4194303); -f(140737488355328, 4194304); -f(140737521909760, 4194305); -f(281474943156224, 8388607); -f(281474976710656, 8388608); -f(281475010265088, 8388609); -f(562949919866880, 16777215); -f(562949953421312, 16777216); -f(562949986975744, 16777217); -f(1125899873288192, 33554431); -f(1125899906842624, 33554432); -x = 33554433; -f(0, 0); -f(33554433, 1); -f(67108866, 2); -f(100663299, 3); -f(134217732, 4); -f(167772165, 5); -f(234881031, 7); -f(268435464, 8); -f(301989897, 9); -f(503316495, 15); -f(536870928, 16); -f(570425361, 17); -f(1040187423, 31); -f(1073741856, 32); -f(1107296289, 33); -f(2113929279, 63); -f(2147483712, 64); -f(2181038145, 65); -f(4261412991, 127); -f(4294967424, 128); -f(4328521857, 129); -f(8556380415, 255); -f(8589934848, 256); -f(8623489281, 257); -f(17146315263, 511); -f(17179869696, 512); -f(17213424129, 513); -f(34326184959, 1023); -f(34359739392, 1024); -f(34393293825, 1025); -f(68685924351, 2047); -f(68719478784, 2048); -f(68753033217, 2049); -f(137405403135, 4095); -f(137438957568, 4096); -f(137472512001, 4097); -f(274844360703, 8191); -f(274877915136, 8192); -f(274911469569, 8193); -f(549722275839, 16383); -f(549755830272, 16384); -f(549789384705, 16385); -f(1099478106111, 32767); -f(1099511660544, 32768); -f(1099545214977, 32769); -f(2198989766655, 65535); -f(2199023321088, 65536); -f(2199056875521, 65537); -f(4398013087743, 131071); -f(4398046642176, 131072); -f(4398080196609, 131073); -f(8796059729919, 262143); -f(8796093284352, 262144); -f(8796126838785, 262145); -f(17592153014271, 524287); -f(17592186568704, 524288); -f(17592220123137, 524289); -f(35184339582975, 1048575); -f(35184373137408, 1048576); -f(35184406691841, 1048577); -f(70368712720383, 2097151); -f(70368746274816, 2097152); -f(70368779829249, 2097153); -f(140737458995199, 4194303); -f(140737492549632, 4194304); -f(140737526104065, 4194305); -f(281474951544831, 8388607); -f(281474985099264, 8388608); -f(281475018653697, 8388609); -f(562949936644095, 16777215); -f(562949970198528, 16777216); -f(562950003752961, 16777217); -f(1125899906842623, 33554431); -f(1125899940397056, 33554432); -f(1125899973951489, 33554433); -x = 67108863; -f(0, 0); -f(67108863, 1); -f(134217726, 2); -f(201326589, 3); -f(268435452, 4); -f(335544315, 5); -f(469762041, 7); -f(536870904, 8); -f(603979767, 9); -f(1006632945, 15); -f(1073741808, 16); -f(1140850671, 17); -f(2080374753, 31); -f(2147483616, 32); -f(2214592479, 33); -f(4227858369, 63); -f(4294967232, 64); -f(4362076095, 65); -f(8522825601, 127); -f(8589934464, 128); -f(8657043327, 129); -f(17112760065, 255); -f(17179868928, 256); -f(17246977791, 257); -f(34292628993, 511); -f(34359737856, 512); -f(34426846719, 513); -f(68652366849, 1023); -f(68719475712, 1024); -f(68786584575, 1025); -f(137371842561, 2047); -f(137438951424, 2048); -f(137506060287, 2049); -f(274810793985, 4095); -f(274877902848, 4096); -f(274945011711, 4097); -f(549688696833, 8191); -f(549755805696, 8192); -f(549822914559, 8193); -f(1099444502529, 16383); -f(1099511611392, 16384); -f(1099578720255, 16385); -f(2198956113921, 32767); -f(2199023222784, 32768); -f(2199090331647, 32769); -f(4397979336705, 65535); -f(4398046445568, 65536); -f(4398113554431, 65537); -f(8796025782273, 131071); -f(8796092891136, 131072); -f(8796159999999, 131073); -f(17592118673409, 262143); -f(17592185782272, 262144); -f(17592252891135, 262145); -f(35184304455681, 524287); -f(35184371564544, 524288); -f(35184438673407, 524289); -f(70368676020225, 1048575); -f(70368743129088, 1048576); -f(70368810237951, 1048577); -f(140737419149313, 2097151); -f(140737486258176, 2097152); -f(140737553367039, 2097153); -f(281474905407489, 4194303); -f(281474972516352, 4194304); -f(281475039625215, 4194305); -f(562949877923841, 8388607); -f(562949945032704, 8388608); -f(562950012141567, 8388609); -f(1125899822956545, 16777215); -f(1125899890065408, 16777216); -f(1125899957174271, 16777217); -x = 67108864; -f(0, 0); -f(67108864, 1); -f(134217728, 2); -f(201326592, 3); -f(268435456, 4); -f(335544320, 5); -f(469762048, 7); -f(536870912, 8); -f(603979776, 9); -f(1006632960, 15); -f(1073741824, 16); -f(1140850688, 17); -f(2080374784, 31); -f(2147483648, 32); -f(2214592512, 33); -f(4227858432, 63); -f(4294967296, 64); -f(4362076160, 65); -f(8522825728, 127); -f(8589934592, 128); -f(8657043456, 129); -f(17112760320, 255); -f(17179869184, 256); -f(17246978048, 257); -f(34292629504, 511); -f(34359738368, 512); -f(34426847232, 513); -f(68652367872, 1023); -f(68719476736, 1024); -f(68786585600, 1025); -f(137371844608, 2047); -f(137438953472, 2048); -f(137506062336, 2049); -f(274810798080, 4095); -f(274877906944, 4096); -f(274945015808, 4097); -f(549688705024, 8191); -f(549755813888, 8192); -f(549822922752, 8193); -f(1099444518912, 16383); -f(1099511627776, 16384); -f(1099578736640, 16385); -f(2198956146688, 32767); -f(2199023255552, 32768); -f(2199090364416, 32769); -f(4397979402240, 65535); -f(4398046511104, 65536); -f(4398113619968, 65537); -f(8796025913344, 131071); -f(8796093022208, 131072); -f(8796160131072, 131073); -f(17592118935552, 262143); -f(17592186044416, 262144); -f(17592253153280, 262145); -f(35184304979968, 524287); -f(35184372088832, 524288); -f(35184439197696, 524289); -f(70368677068800, 1048575); -f(70368744177664, 1048576); -f(70368811286528, 1048577); -f(140737421246464, 2097151); -f(140737488355328, 2097152); -f(140737555464192, 2097153); -f(281474909601792, 4194303); -f(281474976710656, 4194304); -f(281475043819520, 4194305); -f(562949886312448, 8388607); -f(562949953421312, 8388608); -f(562950020530176, 8388609); -f(1125899839733760, 16777215); -f(1125899906842624, 16777216); -f(1125899973951488, 16777217); -x = 67108865; -f(0, 0); -f(67108865, 1); -f(134217730, 2); -f(201326595, 3); -f(268435460, 4); -f(335544325, 5); -f(469762055, 7); -f(536870920, 8); -f(603979785, 9); -f(1006632975, 15); -f(1073741840, 16); -f(1140850705, 17); -f(2080374815, 31); -f(2147483680, 32); -f(2214592545, 33); -f(4227858495, 63); -f(4294967360, 64); -f(4362076225, 65); -f(8522825855, 127); -f(8589934720, 128); -f(8657043585, 129); -f(17112760575, 255); -f(17179869440, 256); -f(17246978305, 257); -f(34292630015, 511); -f(34359738880, 512); -f(34426847745, 513); -f(68652368895, 1023); -f(68719477760, 1024); -f(68786586625, 1025); -f(137371846655, 2047); -f(137438955520, 2048); -f(137506064385, 2049); -f(274810802175, 4095); -f(274877911040, 4096); -f(274945019905, 4097); -f(549688713215, 8191); -f(549755822080, 8192); -f(549822930945, 8193); -f(1099444535295, 16383); -f(1099511644160, 16384); -f(1099578753025, 16385); -f(2198956179455, 32767); -f(2199023288320, 32768); -f(2199090397185, 32769); -f(4397979467775, 65535); -f(4398046576640, 65536); -f(4398113685505, 65537); -f(8796026044415, 131071); -f(8796093153280, 131072); -f(8796160262145, 131073); -f(17592119197695, 262143); -f(17592186306560, 262144); -f(17592253415425, 262145); -f(35184305504255, 524287); -f(35184372613120, 524288); -f(35184439721985, 524289); -f(70368678117375, 1048575); -f(70368745226240, 1048576); -f(70368812335105, 1048577); -f(140737423343615, 2097151); -f(140737490452480, 2097152); -f(140737557561345, 2097153); -f(281474913796095, 4194303); -f(281474980904960, 4194304); -f(281475048013825, 4194305); -f(562949894701055, 8388607); -f(562949961809920, 8388608); -f(562950028918785, 8388609); -f(1125899856510975, 16777215); -f(1125899923619840, 16777216); -f(1125899990728705, 16777217); -x = 134217727; -f(0, 0); -f(134217727, 1); -f(268435454, 2); -f(402653181, 3); -f(536870908, 4); -f(671088635, 5); -f(939524089, 7); -f(1073741816, 8); -f(1207959543, 9); -f(2013265905, 15); -f(2147483632, 16); -f(2281701359, 17); -f(4160749537, 31); -f(4294967264, 32); -f(4429184991, 33); -f(8455716801, 63); -f(8589934528, 64); -f(8724152255, 65); -f(17045651329, 127); -f(17179869056, 128); -f(17314086783, 129); -f(34225520385, 255); -f(34359738112, 256); -f(34493955839, 257); -f(68585258497, 511); -f(68719476224, 512); -f(68853693951, 513); -f(137304734721, 1023); -f(137438952448, 1024); -f(137573170175, 1025); -f(274743687169, 2047); -f(274877904896, 2048); -f(275012122623, 2049); -f(549621592065, 4095); -f(549755809792, 4096); -f(549890027519, 4097); -f(1099377401857, 8191); -f(1099511619584, 8192); -f(1099645837311, 8193); -f(2198889021441, 16383); -f(2199023239168, 16384); -f(2199157456895, 16385); -f(4397912260609, 32767); -f(4398046478336, 32768); -f(4398180696063, 32769); -f(8795958738945, 65535); -f(8796092956672, 65536); -f(8796227174399, 65537); -f(17592051695617, 131071); -f(17592185913344, 131072); -f(17592320131071, 131073); -f(35184237608961, 262143); -f(35184371826688, 262144); -f(35184506044415, 262145); -f(70368609435649, 524287); -f(70368743653376, 524288); -f(70368877871103, 524289); -f(140737353089025, 1048575); -f(140737487306752, 1048576); -f(140737621524479, 1048577); -f(281474840395777, 2097151); -f(281474974613504, 2097152); -f(281475108831231, 2097153); -f(562949815009281, 4194303); -f(562949949227008, 4194304); -f(562950083444735, 4194305); -f(1125899764236289, 8388607); -f(1125899898454016, 8388608); -f(1125900032671743, 8388609); -x = 134217728; -f(0, 0); -f(134217728, 1); -f(268435456, 2); -f(402653184, 3); -f(536870912, 4); -f(671088640, 5); -f(939524096, 7); -f(1073741824, 8); -f(1207959552, 9); -f(2013265920, 15); -f(2147483648, 16); -f(2281701376, 17); -f(4160749568, 31); -f(4294967296, 32); -f(4429185024, 33); -f(8455716864, 63); -f(8589934592, 64); -f(8724152320, 65); -f(17045651456, 127); -f(17179869184, 128); -f(17314086912, 129); -f(34225520640, 255); -f(34359738368, 256); -f(34493956096, 257); -f(68585259008, 511); -f(68719476736, 512); -f(68853694464, 513); -f(137304735744, 1023); -f(137438953472, 1024); -f(137573171200, 1025); -f(274743689216, 2047); -f(274877906944, 2048); -f(275012124672, 2049); -f(549621596160, 4095); -f(549755813888, 4096); -f(549890031616, 4097); -f(1099377410048, 8191); -f(1099511627776, 8192); -f(1099645845504, 8193); -f(2198889037824, 16383); -f(2199023255552, 16384); -f(2199157473280, 16385); -f(4397912293376, 32767); -f(4398046511104, 32768); -f(4398180728832, 32769); -f(8795958804480, 65535); -f(8796093022208, 65536); -f(8796227239936, 65537); -f(17592051826688, 131071); -f(17592186044416, 131072); -f(17592320262144, 131073); -f(35184237871104, 262143); -f(35184372088832, 262144); -f(35184506306560, 262145); -f(70368609959936, 524287); -f(70368744177664, 524288); -f(70368878395392, 524289); -f(140737354137600, 1048575); -f(140737488355328, 1048576); -f(140737622573056, 1048577); -f(281474842492928, 2097151); -f(281474976710656, 2097152); -f(281475110928384, 2097153); -f(562949819203584, 4194303); -f(562949953421312, 4194304); -f(562950087639040, 4194305); -f(1125899772624896, 8388607); -f(1125899906842624, 8388608); -f(1125900041060352, 8388609); -x = 134217729; -f(0, 0); -f(134217729, 1); -f(268435458, 2); -f(402653187, 3); -f(536870916, 4); -f(671088645, 5); -f(939524103, 7); -f(1073741832, 8); -f(1207959561, 9); -f(2013265935, 15); -f(2147483664, 16); -f(2281701393, 17); -f(4160749599, 31); -f(4294967328, 32); -f(4429185057, 33); -f(8455716927, 63); -f(8589934656, 64); -f(8724152385, 65); -f(17045651583, 127); -f(17179869312, 128); -f(17314087041, 129); -f(34225520895, 255); -f(34359738624, 256); -f(34493956353, 257); -f(68585259519, 511); -f(68719477248, 512); -f(68853694977, 513); -f(137304736767, 1023); -f(137438954496, 1024); -f(137573172225, 1025); -f(274743691263, 2047); -f(274877908992, 2048); -f(275012126721, 2049); -f(549621600255, 4095); -f(549755817984, 4096); -f(549890035713, 4097); -f(1099377418239, 8191); -f(1099511635968, 8192); -f(1099645853697, 8193); -f(2198889054207, 16383); -f(2199023271936, 16384); -f(2199157489665, 16385); -f(4397912326143, 32767); -f(4398046543872, 32768); -f(4398180761601, 32769); -f(8795958870015, 65535); -f(8796093087744, 65536); -f(8796227305473, 65537); -f(17592051957759, 131071); -f(17592186175488, 131072); -f(17592320393217, 131073); -f(35184238133247, 262143); -f(35184372350976, 262144); -f(35184506568705, 262145); -f(70368610484223, 524287); -f(70368744701952, 524288); -f(70368878919681, 524289); -f(140737355186175, 1048575); -f(140737489403904, 1048576); -f(140737623621633, 1048577); -f(281474844590079, 2097151); -f(281474978807808, 2097152); -f(281475113025537, 2097153); -f(562949823397887, 4194303); -f(562949957615616, 4194304); -f(562950091833345, 4194305); -f(1125899781013503, 8388607); -f(1125899915231232, 8388608); -f(1125900049448961, 8388609); -x = 268435455; -f(0, 0); -f(268435455, 1); -f(536870910, 2); -f(805306365, 3); -f(1073741820, 4); -f(1342177275, 5); -f(1879048185, 7); -f(2147483640, 8); -f(2415919095, 9); -f(4026531825, 15); -f(4294967280, 16); -f(4563402735, 17); -f(8321499105, 31); -f(8589934560, 32); -f(8858370015, 33); -f(16911433665, 63); -f(17179869120, 64); -f(17448304575, 65); -f(34091302785, 127); -f(34359738240, 128); -f(34628173695, 129); -f(68451041025, 255); -f(68719476480, 256); -f(68987911935, 257); -f(137170517505, 511); -f(137438952960, 512); -f(137707388415, 513); -f(274609470465, 1023); -f(274877905920, 1024); -f(275146341375, 1025); -f(549487376385, 2047); -f(549755811840, 2048); -f(550024247295, 2049); -f(1099243188225, 4095); -f(1099511623680, 4096); -f(1099780059135, 4097); -f(2198754811905, 8191); -f(2199023247360, 8192); -f(2199291682815, 8193); -f(4397778059265, 16383); -f(4398046494720, 16384); -f(4398314930175, 16385); -f(8795824553985, 32767); -f(8796092989440, 32768); -f(8796361424895, 32769); -f(17591917543425, 65535); -f(17592185978880, 65536); -f(17592454414335, 65537); -f(35184103522305, 131071); -f(35184371957760, 131072); -f(35184640393215, 131073); -f(70368475480065, 262143); -f(70368743915520, 262144); -f(70369012350975, 262145); -f(140737219395585, 524287); -f(140737487831040, 524288); -f(140737756266495, 524289); -f(281474707226625, 1048575); -f(281474975662080, 1048576); -f(281475244097535, 1048577); -f(562949682888705, 2097151); -f(562949951324160, 2097152); -f(562950219759615, 2097153); -f(1125899634212865, 4194303); -f(1125899902648320, 4194304); -f(1125900171083775, 4194305); -x = 268435456; -f(0, 0); -f(268435456, 1); -f(536870912, 2); -f(805306368, 3); -f(1073741824, 4); -f(1342177280, 5); -f(1879048192, 7); -f(2147483648, 8); -f(2415919104, 9); -f(4026531840, 15); -f(4294967296, 16); -f(4563402752, 17); -f(8321499136, 31); -f(8589934592, 32); -f(8858370048, 33); -f(16911433728, 63); -f(17179869184, 64); -f(17448304640, 65); -f(34091302912, 127); -f(34359738368, 128); -f(34628173824, 129); -f(68451041280, 255); -f(68719476736, 256); -f(68987912192, 257); -f(137170518016, 511); -f(137438953472, 512); -f(137707388928, 513); -f(274609471488, 1023); -f(274877906944, 1024); -f(275146342400, 1025); -f(549487378432, 2047); -f(549755813888, 2048); -f(550024249344, 2049); -f(1099243192320, 4095); -f(1099511627776, 4096); -f(1099780063232, 4097); -f(2198754820096, 8191); -f(2199023255552, 8192); -f(2199291691008, 8193); -f(4397778075648, 16383); -f(4398046511104, 16384); -f(4398314946560, 16385); -f(8795824586752, 32767); -f(8796093022208, 32768); -f(8796361457664, 32769); -f(17591917608960, 65535); -f(17592186044416, 65536); -f(17592454479872, 65537); -f(35184103653376, 131071); -f(35184372088832, 131072); -f(35184640524288, 131073); -f(70368475742208, 262143); -f(70368744177664, 262144); -f(70369012613120, 262145); -f(140737219919872, 524287); -f(140737488355328, 524288); -f(140737756790784, 524289); -f(281474708275200, 1048575); -f(281474976710656, 1048576); -f(281475245146112, 1048577); -f(562949684985856, 2097151); -f(562949953421312, 2097152); -f(562950221856768, 2097153); -f(1125899638407168, 4194303); -f(1125899906842624, 4194304); -f(1125900175278080, 4194305); -x = 268435457; -f(0, 0); -f(268435457, 1); -f(536870914, 2); -f(805306371, 3); -f(1073741828, 4); -f(1342177285, 5); -f(1879048199, 7); -f(2147483656, 8); -f(2415919113, 9); -f(4026531855, 15); -f(4294967312, 16); -f(4563402769, 17); -f(8321499167, 31); -f(8589934624, 32); -f(8858370081, 33); -f(16911433791, 63); -f(17179869248, 64); -f(17448304705, 65); -f(34091303039, 127); -f(34359738496, 128); -f(34628173953, 129); -f(68451041535, 255); -f(68719476992, 256); -f(68987912449, 257); -f(137170518527, 511); -f(137438953984, 512); -f(137707389441, 513); -f(274609472511, 1023); -f(274877907968, 1024); -f(275146343425, 1025); -f(549487380479, 2047); -f(549755815936, 2048); -f(550024251393, 2049); -f(1099243196415, 4095); -f(1099511631872, 4096); -f(1099780067329, 4097); -f(2198754828287, 8191); -f(2199023263744, 8192); -f(2199291699201, 8193); -f(4397778092031, 16383); -f(4398046527488, 16384); -f(4398314962945, 16385); -f(8795824619519, 32767); -f(8796093054976, 32768); -f(8796361490433, 32769); -f(17591917674495, 65535); -f(17592186109952, 65536); -f(17592454545409, 65537); -f(35184103784447, 131071); -f(35184372219904, 131072); -f(35184640655361, 131073); -f(70368476004351, 262143); -f(70368744439808, 262144); -f(70369012875265, 262145); -f(140737220444159, 524287); -f(140737488879616, 524288); -f(140737757315073, 524289); -f(281474709323775, 1048575); -f(281474977759232, 1048576); -f(281475246194689, 1048577); -f(562949687083007, 2097151); -f(562949955518464, 2097152); -f(562950223953921, 2097153); -f(1125899642601471, 4194303); -f(1125899911036928, 4194304); -f(1125900179472385, 4194305); -x = 536870911; -f(0, 0); -f(536870911, 1); -f(1073741822, 2); -f(1610612733, 3); -f(2147483644, 4); -f(2684354555, 5); -f(3758096377, 7); -f(4294967288, 8); -f(4831838199, 9); -f(8053063665, 15); -f(8589934576, 16); -f(9126805487, 17); -f(16642998241, 31); -f(17179869152, 32); -f(17716740063, 33); -f(33822867393, 63); -f(34359738304, 64); -f(34896609215, 65); -f(68182605697, 127); -f(68719476608, 128); -f(69256347519, 129); -f(136902082305, 255); -f(137438953216, 256); -f(137975824127, 257); -f(274341035521, 511); -f(274877906432, 512); -f(275414777343, 513); -f(549218941953, 1023); -f(549755812864, 1024); -f(550292683775, 1025); -f(1098974754817, 2047); -f(1099511625728, 2048); -f(1100048496639, 2049); -f(2198486380545, 4095); -f(2199023251456, 4096); -f(2199560122367, 4097); -f(4397509632001, 8191); -f(4398046502912, 8192); -f(4398583373823, 8193); -f(8795556134913, 16383); -f(8796093005824, 16384); -f(8796629876735, 16385); -f(17591649140737, 32767); -f(17592186011648, 32768); -f(17592722882559, 32769); -f(35183835152385, 65535); -f(35184372023296, 65536); -f(35184908894207, 65537); -f(70368207175681, 131071); -f(70368744046592, 131072); -f(70369280917503, 131073); -f(140736951222273, 262143); -f(140737488093184, 262144); -f(140738024964095, 262145); -f(281474439315457, 524287); -f(281474976186368, 524288); -f(281475513057279, 524289); -f(562949415501825, 1048575); -f(562949952372736, 1048576); -f(562950489243647, 1048577); -f(1125899367874561, 2097151); -f(1125899904745472, 2097152); -f(1125900441616383, 2097153); -x = 536870912; -f(0, 0); -f(536870912, 1); -f(1073741824, 2); -f(1610612736, 3); -f(2147483648, 4); -f(2684354560, 5); -f(3758096384, 7); -f(4294967296, 8); -f(4831838208, 9); -f(8053063680, 15); -f(8589934592, 16); -f(9126805504, 17); -f(16642998272, 31); -f(17179869184, 32); -f(17716740096, 33); -f(33822867456, 63); -f(34359738368, 64); -f(34896609280, 65); -f(68182605824, 127); -f(68719476736, 128); -f(69256347648, 129); -f(136902082560, 255); -f(137438953472, 256); -f(137975824384, 257); -f(274341036032, 511); -f(274877906944, 512); -f(275414777856, 513); -f(549218942976, 1023); -f(549755813888, 1024); -f(550292684800, 1025); -f(1098974756864, 2047); -f(1099511627776, 2048); -f(1100048498688, 2049); -f(2198486384640, 4095); -f(2199023255552, 4096); -f(2199560126464, 4097); -f(4397509640192, 8191); -f(4398046511104, 8192); -f(4398583382016, 8193); -f(8795556151296, 16383); -f(8796093022208, 16384); -f(8796629893120, 16385); -f(17591649173504, 32767); -f(17592186044416, 32768); -f(17592722915328, 32769); -f(35183835217920, 65535); -f(35184372088832, 65536); -f(35184908959744, 65537); -f(70368207306752, 131071); -f(70368744177664, 131072); -f(70369281048576, 131073); -f(140736951484416, 262143); -f(140737488355328, 262144); -f(140738025226240, 262145); -f(281474439839744, 524287); -f(281474976710656, 524288); -f(281475513581568, 524289); -f(562949416550400, 1048575); -f(562949953421312, 1048576); -f(562950490292224, 1048577); -f(1125899369971712, 2097151); -f(1125899906842624, 2097152); -f(1125900443713536, 2097153); -x = 536870913; -f(0, 0); -f(536870913, 1); -f(1073741826, 2); -f(1610612739, 3); -f(2147483652, 4); -f(2684354565, 5); -f(3758096391, 7); -f(4294967304, 8); -f(4831838217, 9); -f(8053063695, 15); -f(8589934608, 16); -f(9126805521, 17); -f(16642998303, 31); -f(17179869216, 32); -f(17716740129, 33); -f(33822867519, 63); -f(34359738432, 64); -f(34896609345, 65); -f(68182605951, 127); -f(68719476864, 128); -f(69256347777, 129); -f(136902082815, 255); -f(137438953728, 256); -f(137975824641, 257); -f(274341036543, 511); -f(274877907456, 512); -f(275414778369, 513); -f(549218943999, 1023); -f(549755814912, 1024); -f(550292685825, 1025); -f(1098974758911, 2047); -f(1099511629824, 2048); -f(1100048500737, 2049); -f(2198486388735, 4095); -f(2199023259648, 4096); -f(2199560130561, 4097); -f(4397509648383, 8191); -f(4398046519296, 8192); -f(4398583390209, 8193); -f(8795556167679, 16383); -f(8796093038592, 16384); -f(8796629909505, 16385); -f(17591649206271, 32767); -f(17592186077184, 32768); -f(17592722948097, 32769); -f(35183835283455, 65535); -f(35184372154368, 65536); -f(35184909025281, 65537); -f(70368207437823, 131071); -f(70368744308736, 131072); -f(70369281179649, 131073); -f(140736951746559, 262143); -f(140737488617472, 262144); -f(140738025488385, 262145); -f(281474440364031, 524287); -f(281474977234944, 524288); -f(281475514105857, 524289); -f(562949417598975, 1048575); -f(562949954469888, 1048576); -f(562950491340801, 1048577); -f(1125899372068863, 2097151); -f(1125899908939776, 2097152); -f(1125900445810689, 2097153); -x = 1073741823; -f(0, 0); -f(1073741823, 1); -f(2147483646, 2); -f(3221225469, 3); -f(4294967292, 4); -f(5368709115, 5); -f(7516192761, 7); -f(8589934584, 8); -f(9663676407, 9); -f(16106127345, 15); -f(17179869168, 16); -f(18253610991, 17); -f(33285996513, 31); -f(34359738336, 32); -f(35433480159, 33); -f(67645734849, 63); -f(68719476672, 64); -f(69793218495, 65); -f(136365211521, 127); -f(137438953344, 128); -f(138512695167, 129); -f(273804164865, 255); -f(274877906688, 256); -f(275951648511, 257); -f(548682071553, 511); -f(549755813376, 512); -f(550829555199, 513); -f(1098437884929, 1023); -f(1099511626752, 1024); -f(1100585368575, 1025); -f(2197949511681, 2047); -f(2199023253504, 2048); -f(2200096995327, 2049); -f(4396972765185, 4095); -f(4398046507008, 4096); -f(4399120248831, 4097); -f(8795019272193, 8191); -f(8796093014016, 8192); -f(8797166755839, 8193); -f(17591112286209, 16383); -f(17592186028032, 16384); -f(17593259769855, 16385); -f(35183298314241, 32767); -f(35184372056064, 32768); -f(35185445797887, 32769); -f(70367670370305, 65535); -f(70368744112128, 65536); -f(70369817853951, 65537); -f(140736414482433, 131071); -f(140737488224256, 131072); -f(140738561966079, 131073); -f(281473902706689, 262143); -f(281474976448512, 262144); -f(281476050190335, 262145); -f(562948879155201, 524287); -f(562949952897024, 524288); -f(562951026638847, 524289); -f(1125898832052225, 1048575); -f(1125899905794048, 1048576); -f(1125900979535871, 1048577); -x = 1073741824; -f(0, 0); -f(1073741824, 1); -f(2147483648, 2); -f(3221225472, 3); -f(4294967296, 4); -f(5368709120, 5); -f(7516192768, 7); -f(8589934592, 8); -f(9663676416, 9); -f(16106127360, 15); -f(17179869184, 16); -f(18253611008, 17); -f(33285996544, 31); -f(34359738368, 32); -f(35433480192, 33); -f(67645734912, 63); -f(68719476736, 64); -f(69793218560, 65); -f(136365211648, 127); -f(137438953472, 128); -f(138512695296, 129); -f(273804165120, 255); -f(274877906944, 256); -f(275951648768, 257); -f(548682072064, 511); -f(549755813888, 512); -f(550829555712, 513); -f(1098437885952, 1023); -f(1099511627776, 1024); -f(1100585369600, 1025); -f(2197949513728, 2047); -f(2199023255552, 2048); -f(2200096997376, 2049); -f(4396972769280, 4095); -f(4398046511104, 4096); -f(4399120252928, 4097); -f(8795019280384, 8191); -f(8796093022208, 8192); -f(8797166764032, 8193); -f(17591112302592, 16383); -f(17592186044416, 16384); -f(17593259786240, 16385); -f(35183298347008, 32767); -f(35184372088832, 32768); -f(35185445830656, 32769); -f(70367670435840, 65535); -f(70368744177664, 65536); -f(70369817919488, 65537); -f(140736414613504, 131071); -f(140737488355328, 131072); -f(140738562097152, 131073); -f(281473902968832, 262143); -f(281474976710656, 262144); -f(281476050452480, 262145); -f(562948879679488, 524287); -f(562949953421312, 524288); -f(562951027163136, 524289); -f(1125898833100800, 1048575); -f(1125899906842624, 1048576); -f(1125900980584448, 1048577); -x = 1073741825; -f(0, 0); -f(1073741825, 1); -f(2147483650, 2); -f(3221225475, 3); -f(4294967300, 4); -f(5368709125, 5); -f(7516192775, 7); -f(8589934600, 8); -f(9663676425, 9); -f(16106127375, 15); -f(17179869200, 16); -f(18253611025, 17); -f(33285996575, 31); -f(34359738400, 32); -f(35433480225, 33); -f(67645734975, 63); -f(68719476800, 64); -f(69793218625, 65); -f(136365211775, 127); -f(137438953600, 128); -f(138512695425, 129); -f(273804165375, 255); -f(274877907200, 256); -f(275951649025, 257); -f(548682072575, 511); -f(549755814400, 512); -f(550829556225, 513); -f(1098437886975, 1023); -f(1099511628800, 1024); -f(1100585370625, 1025); -f(2197949515775, 2047); -f(2199023257600, 2048); -f(2200096999425, 2049); -f(4396972773375, 4095); -f(4398046515200, 4096); -f(4399120257025, 4097); -f(8795019288575, 8191); -f(8796093030400, 8192); -f(8797166772225, 8193); -f(17591112318975, 16383); -f(17592186060800, 16384); -f(17593259802625, 16385); -f(35183298379775, 32767); -f(35184372121600, 32768); -f(35185445863425, 32769); -f(70367670501375, 65535); -f(70368744243200, 65536); -f(70369817985025, 65537); -f(140736414744575, 131071); -f(140737488486400, 131072); -f(140738562228225, 131073); -f(281473903230975, 262143); -f(281474976972800, 262144); -f(281476050714625, 262145); -f(562948880203775, 524287); -f(562949953945600, 524288); -f(562951027687425, 524289); -f(1125898834149375, 1048575); -f(1125899907891200, 1048576); -f(1125900981633025, 1048577); -x = 2147483647; -f(0, 0); -f(2147483647, 1); -f(4294967294, 2); -f(6442450941, 3); -f(8589934588, 4); -f(10737418235, 5); -f(15032385529, 7); -f(17179869176, 8); -f(19327352823, 9); -f(32212254705, 15); -f(34359738352, 16); -f(36507221999, 17); -f(66571993057, 31); -f(68719476704, 32); -f(70866960351, 33); -f(135291469761, 63); -f(137438953408, 64); -f(139586437055, 65); -f(272730423169, 127); -f(274877906816, 128); -f(277025390463, 129); -f(547608329985, 255); -f(549755813632, 256); -f(551903297279, 257); -f(1097364143617, 511); -f(1099511627264, 512); -f(1101659110911, 513); -f(2196875770881, 1023); -f(2199023254528, 1024); -f(2201170738175, 1025); -f(4395899025409, 2047); -f(4398046509056, 2048); -f(4400193992703, 2049); -f(8793945534465, 4095); -f(8796093018112, 4096); -f(8798240501759, 4097); -f(17590038552577, 8191); -f(17592186036224, 8192); -f(17594333519871, 8193); -f(35182224588801, 16383); -f(35184372072448, 16384); -f(35186519556095, 16385); -f(70366596661249, 32767); -f(70368744144896, 32768); -f(70370891628543, 32769); -f(140735340806145, 65535); -f(140737488289792, 65536); -f(140739635773439, 65537); -f(281472829095937, 131071); -f(281474976579584, 131072); -f(281477124063231, 131073); -f(562947805675521, 262143); -f(562949953159168, 262144); -f(562952100642815, 262145); -f(1125897758834689, 524287); -f(1125899906318336, 524288); -f(1125902053801983, 524289); -x = 2147483648; -f(0, 0); -f(2147483648, 1); -f(4294967296, 2); -f(6442450944, 3); -f(8589934592, 4); -f(10737418240, 5); -f(15032385536, 7); -f(17179869184, 8); -f(19327352832, 9); -f(32212254720, 15); -f(34359738368, 16); -f(36507222016, 17); -f(66571993088, 31); -f(68719476736, 32); -f(70866960384, 33); -f(135291469824, 63); -f(137438953472, 64); -f(139586437120, 65); -f(272730423296, 127); -f(274877906944, 128); -f(277025390592, 129); -f(547608330240, 255); -f(549755813888, 256); -f(551903297536, 257); -f(1097364144128, 511); -f(1099511627776, 512); -f(1101659111424, 513); -f(2196875771904, 1023); -f(2199023255552, 1024); -f(2201170739200, 1025); -f(4395899027456, 2047); -f(4398046511104, 2048); -f(4400193994752, 2049); -f(8793945538560, 4095); -f(8796093022208, 4096); -f(8798240505856, 4097); -f(17590038560768, 8191); -f(17592186044416, 8192); -f(17594333528064, 8193); -f(35182224605184, 16383); -f(35184372088832, 16384); -f(35186519572480, 16385); -f(70366596694016, 32767); -f(70368744177664, 32768); -f(70370891661312, 32769); -f(140735340871680, 65535); -f(140737488355328, 65536); -f(140739635838976, 65537); -f(281472829227008, 131071); -f(281474976710656, 131072); -f(281477124194304, 131073); -f(562947805937664, 262143); -f(562949953421312, 262144); -f(562952100904960, 262145); -f(1125897759358976, 524287); -f(1125899906842624, 524288); -f(1125902054326272, 524289); -x = 2147483649; -f(0, 0); -f(2147483649, 1); -f(4294967298, 2); -f(6442450947, 3); -f(8589934596, 4); -f(10737418245, 5); -f(15032385543, 7); -f(17179869192, 8); -f(19327352841, 9); -f(32212254735, 15); -f(34359738384, 16); -f(36507222033, 17); -f(66571993119, 31); -f(68719476768, 32); -f(70866960417, 33); -f(135291469887, 63); -f(137438953536, 64); -f(139586437185, 65); -f(272730423423, 127); -f(274877907072, 128); -f(277025390721, 129); -f(547608330495, 255); -f(549755814144, 256); -f(551903297793, 257); -f(1097364144639, 511); -f(1099511628288, 512); -f(1101659111937, 513); -f(2196875772927, 1023); -f(2199023256576, 1024); -f(2201170740225, 1025); -f(4395899029503, 2047); -f(4398046513152, 2048); -f(4400193996801, 2049); -f(8793945542655, 4095); -f(8796093026304, 4096); -f(8798240509953, 4097); -f(17590038568959, 8191); -f(17592186052608, 8192); -f(17594333536257, 8193); -f(35182224621567, 16383); -f(35184372105216, 16384); -f(35186519588865, 16385); -f(70366596726783, 32767); -f(70368744210432, 32768); -f(70370891694081, 32769); -f(140735340937215, 65535); -f(140737488420864, 65536); -f(140739635904513, 65537); -f(281472829358079, 131071); -f(281474976841728, 131072); -f(281477124325377, 131073); -f(562947806199807, 262143); -f(562949953683456, 262144); -f(562952101167105, 262145); -f(1125897759883263, 524287); -f(1125899907366912, 524288); -f(1125902054850561, 524289); -x = 4294967295; -f(0, 0); -f(4294967295, 1); -f(8589934590, 2); -f(12884901885, 3); -f(17179869180, 4); -f(21474836475, 5); -f(30064771065, 7); -f(34359738360, 8); -f(38654705655, 9); -f(64424509425, 15); -f(68719476720, 16); -f(73014444015, 17); -f(133143986145, 31); -f(137438953440, 32); -f(141733920735, 33); -f(270582939585, 63); -f(274877906880, 64); -f(279172874175, 65); -f(545460846465, 127); -f(549755813760, 128); -f(554050781055, 129); -f(1095216660225, 255); -f(1099511627520, 256); -f(1103806594815, 257); -f(2194728287745, 511); -f(2199023255040, 512); -f(2203318222335, 513); -f(4393751542785, 1023); -f(4398046510080, 1024); -f(4402341477375, 1025); -f(8791798052865, 2047); -f(8796093020160, 2048); -f(8800387987455, 2049); -f(17587891073025, 4095); -f(17592186040320, 4096); -f(17596481007615, 4097); -f(35180077113345, 8191); -f(35184372080640, 8192); -f(35188667047935, 8193); -f(70364449193985, 16383); -f(70368744161280, 16384); -f(70373039128575, 16385); -f(140733193355265, 32767); -f(140737488322560, 32768); -f(140741783289855, 32769); -f(281470681677825, 65535); -f(281474976645120, 65536); -f(281479271612415, 65537); -f(562945658322945, 131071); -f(562949953290240, 131072); -f(562954248257535, 131073); -f(1125895611613185, 262143); -f(1125899906580480, 262144); -f(1125904201547775, 262145); -x = 4294967296; -f(0, 0); -f(4294967296, 1); -f(8589934592, 2); -f(12884901888, 3); -f(17179869184, 4); -f(21474836480, 5); -f(30064771072, 7); -f(34359738368, 8); -f(38654705664, 9); -f(64424509440, 15); -f(68719476736, 16); -f(73014444032, 17); -f(133143986176, 31); -f(137438953472, 32); -f(141733920768, 33); -f(270582939648, 63); -f(274877906944, 64); -f(279172874240, 65); -f(545460846592, 127); -f(549755813888, 128); -f(554050781184, 129); -f(1095216660480, 255); -f(1099511627776, 256); -f(1103806595072, 257); -f(2194728288256, 511); -f(2199023255552, 512); -f(2203318222848, 513); -f(4393751543808, 1023); -f(4398046511104, 1024); -f(4402341478400, 1025); -f(8791798054912, 2047); -f(8796093022208, 2048); -f(8800387989504, 2049); -f(17587891077120, 4095); -f(17592186044416, 4096); -f(17596481011712, 4097); -f(35180077121536, 8191); -f(35184372088832, 8192); -f(35188667056128, 8193); -f(70364449210368, 16383); -f(70368744177664, 16384); -f(70373039144960, 16385); -f(140733193388032, 32767); -f(140737488355328, 32768); -f(140741783322624, 32769); -f(281470681743360, 65535); -f(281474976710656, 65536); -f(281479271677952, 65537); -f(562945658454016, 131071); -f(562949953421312, 131072); -f(562954248388608, 131073); -f(1125895611875328, 262143); -f(1125899906842624, 262144); -f(1125904201809920, 262145); -x = 4294967297; -f(0, 0); -f(4294967297, 1); -f(8589934594, 2); -f(12884901891, 3); -f(17179869188, 4); -f(21474836485, 5); -f(30064771079, 7); -f(34359738376, 8); -f(38654705673, 9); -f(64424509455, 15); -f(68719476752, 16); -f(73014444049, 17); -f(133143986207, 31); -f(137438953504, 32); -f(141733920801, 33); -f(270582939711, 63); -f(274877907008, 64); -f(279172874305, 65); -f(545460846719, 127); -f(549755814016, 128); -f(554050781313, 129); -f(1095216660735, 255); -f(1099511628032, 256); -f(1103806595329, 257); -f(2194728288767, 511); -f(2199023256064, 512); -f(2203318223361, 513); -f(4393751544831, 1023); -f(4398046512128, 1024); -f(4402341479425, 1025); -f(8791798056959, 2047); -f(8796093024256, 2048); -f(8800387991553, 2049); -f(17587891081215, 4095); -f(17592186048512, 4096); -f(17596481015809, 4097); -f(35180077129727, 8191); -f(35184372097024, 8192); -f(35188667064321, 8193); -f(70364449226751, 16383); -f(70368744194048, 16384); -f(70373039161345, 16385); -f(140733193420799, 32767); -f(140737488388096, 32768); -f(140741783355393, 32769); -f(281470681808895, 65535); -f(281474976776192, 65536); -f(281479271743489, 65537); -f(562945658585087, 131071); -f(562949953552384, 131072); -f(562954248519681, 131073); -f(1125895612137471, 262143); -f(1125899907104768, 262144); -f(1125904202072065, 262145); -x = 8589934591; -f(0, 0); -f(8589934591, 1); -f(17179869182, 2); -f(25769803773, 3); -f(34359738364, 4); -f(42949672955, 5); -f(60129542137, 7); -f(68719476728, 8); -f(77309411319, 9); -f(128849018865, 15); -f(137438953456, 16); -f(146028888047, 17); -f(266287972321, 31); -f(274877906912, 32); -f(283467841503, 33); -f(541165879233, 63); -f(549755813824, 64); -f(558345748415, 65); -f(1090921693057, 127); -f(1099511627648, 128); -f(1108101562239, 129); -f(2190433320705, 255); -f(2199023255296, 256); -f(2207613189887, 257); -f(4389456576001, 511); -f(4398046510592, 512); -f(4406636445183, 513); -f(8787503086593, 1023); -f(8796093021184, 1024); -f(8804682955775, 1025); -f(17583596107777, 2047); -f(17592186042368, 2048); -f(17600775976959, 2049); -f(35175782150145, 4095); -f(35184372084736, 4096); -f(35192962019327, 4097); -f(70360154234881, 8191); -f(70368744169472, 8192); -f(70377334104063, 8193); -f(140728898404353, 16383); -f(140737488338944, 16384); -f(140746078273535, 16385); -f(281466386743297, 32767); -f(281474976677888, 32768); -f(281483566612479, 32769); -f(562941363421185, 65535); -f(562949953355776, 65536); -f(562958543290367, 65537); -f(1125891316776961, 131071); -f(1125899906711552, 131072); -f(1125908496646143, 131073); -x = 8589934592; -f(0, 0); -f(8589934592, 1); -f(17179869184, 2); -f(25769803776, 3); -f(34359738368, 4); -f(42949672960, 5); -f(60129542144, 7); -f(68719476736, 8); -f(77309411328, 9); -f(128849018880, 15); -f(137438953472, 16); -f(146028888064, 17); -f(266287972352, 31); -f(274877906944, 32); -f(283467841536, 33); -f(541165879296, 63); -f(549755813888, 64); -f(558345748480, 65); -f(1090921693184, 127); -f(1099511627776, 128); -f(1108101562368, 129); -f(2190433320960, 255); -f(2199023255552, 256); -f(2207613190144, 257); -f(4389456576512, 511); -f(4398046511104, 512); -f(4406636445696, 513); -f(8787503087616, 1023); -f(8796093022208, 1024); -f(8804682956800, 1025); -f(17583596109824, 2047); -f(17592186044416, 2048); -f(17600775979008, 2049); -f(35175782154240, 4095); -f(35184372088832, 4096); -f(35192962023424, 4097); -f(70360154243072, 8191); -f(70368744177664, 8192); -f(70377334112256, 8193); -f(140728898420736, 16383); -f(140737488355328, 16384); -f(140746078289920, 16385); -f(281466386776064, 32767); -f(281474976710656, 32768); -f(281483566645248, 32769); -f(562941363486720, 65535); -f(562949953421312, 65536); -f(562958543355904, 65537); -f(1125891316908032, 131071); -f(1125899906842624, 131072); -f(1125908496777216, 131073); -x = 8589934593; -f(0, 0); -f(8589934593, 1); -f(17179869186, 2); -f(25769803779, 3); -f(34359738372, 4); -f(42949672965, 5); -f(60129542151, 7); -f(68719476744, 8); -f(77309411337, 9); -f(128849018895, 15); -f(137438953488, 16); -f(146028888081, 17); -f(266287972383, 31); -f(274877906976, 32); -f(283467841569, 33); -f(541165879359, 63); -f(549755813952, 64); -f(558345748545, 65); -f(1090921693311, 127); -f(1099511627904, 128); -f(1108101562497, 129); -f(2190433321215, 255); -f(2199023255808, 256); -f(2207613190401, 257); -f(4389456577023, 511); -f(4398046511616, 512); -f(4406636446209, 513); -f(8787503088639, 1023); -f(8796093023232, 1024); -f(8804682957825, 1025); -f(17583596111871, 2047); -f(17592186046464, 2048); -f(17600775981057, 2049); -f(35175782158335, 4095); -f(35184372092928, 4096); -f(35192962027521, 4097); -f(70360154251263, 8191); -f(70368744185856, 8192); -f(70377334120449, 8193); -f(140728898437119, 16383); -f(140737488371712, 16384); -f(140746078306305, 16385); -f(281466386808831, 32767); -f(281474976743424, 32768); -f(281483566678017, 32769); -f(562941363552255, 65535); -f(562949953486848, 65536); -f(562958543421441, 65537); -f(1125891317039103, 131071); -f(1125899906973696, 131072); -f(1125908496908289, 131073); -x = 17179869183; -f(0, 0); -f(17179869183, 1); -f(34359738366, 2); -f(51539607549, 3); -f(68719476732, 4); -f(85899345915, 5); -f(120259084281, 7); -f(137438953464, 8); -f(154618822647, 9); -f(257698037745, 15); -f(274877906928, 16); -f(292057776111, 17); -f(532575944673, 31); -f(549755813856, 32); -f(566935683039, 33); -f(1082331758529, 63); -f(1099511627712, 64); -f(1116691496895, 65); -f(2181843386241, 127); -f(2199023255424, 128); -f(2216203124607, 129); -f(4380866641665, 255); -f(4398046510848, 256); -f(4415226380031, 257); -f(8778913152513, 511); -f(8796093021696, 512); -f(8813272890879, 513); -f(17575006174209, 1023); -f(17592186043392, 1024); -f(17609365912575, 1025); -f(35167192217601, 2047); -f(35184372086784, 2048); -f(35201551955967, 2049); -f(70351564304385, 4095); -f(70368744173568, 4096); -f(70385924042751, 4097); -f(140720308477953, 8191); -f(140737488347136, 8192); -f(140754668216319, 8193); -f(281457796825089, 16383); -f(281474976694272, 16384); -f(281492156563455, 16385); -f(562932773519361, 32767); -f(562949953388544, 32768); -f(562967133257727, 32769); -f(1125882726907905, 65535); -f(1125899906777088, 65536); -f(1125917086646271, 65537); -x = 17179869184; -f(0, 0); -f(17179869184, 1); -f(34359738368, 2); -f(51539607552, 3); -f(68719476736, 4); -f(85899345920, 5); -f(120259084288, 7); -f(137438953472, 8); -f(154618822656, 9); -f(257698037760, 15); -f(274877906944, 16); -f(292057776128, 17); -f(532575944704, 31); -f(549755813888, 32); -f(566935683072, 33); -f(1082331758592, 63); -f(1099511627776, 64); -f(1116691496960, 65); -f(2181843386368, 127); -f(2199023255552, 128); -f(2216203124736, 129); -f(4380866641920, 255); -f(4398046511104, 256); -f(4415226380288, 257); -f(8778913153024, 511); -f(8796093022208, 512); -f(8813272891392, 513); -f(17575006175232, 1023); -f(17592186044416, 1024); -f(17609365913600, 1025); -f(35167192219648, 2047); -f(35184372088832, 2048); -f(35201551958016, 2049); -f(70351564308480, 4095); -f(70368744177664, 4096); -f(70385924046848, 4097); -f(140720308486144, 8191); -f(140737488355328, 8192); -f(140754668224512, 8193); -f(281457796841472, 16383); -f(281474976710656, 16384); -f(281492156579840, 16385); -f(562932773552128, 32767); -f(562949953421312, 32768); -f(562967133290496, 32769); -f(1125882726973440, 65535); -f(1125899906842624, 65536); -f(1125917086711808, 65537); -x = 17179869185; -f(0, 0); -f(17179869185, 1); -f(34359738370, 2); -f(51539607555, 3); -f(68719476740, 4); -f(85899345925, 5); -f(120259084295, 7); -f(137438953480, 8); -f(154618822665, 9); -f(257698037775, 15); -f(274877906960, 16); -f(292057776145, 17); -f(532575944735, 31); -f(549755813920, 32); -f(566935683105, 33); -f(1082331758655, 63); -f(1099511627840, 64); -f(1116691497025, 65); -f(2181843386495, 127); -f(2199023255680, 128); -f(2216203124865, 129); -f(4380866642175, 255); -f(4398046511360, 256); -f(4415226380545, 257); -f(8778913153535, 511); -f(8796093022720, 512); -f(8813272891905, 513); -f(17575006176255, 1023); -f(17592186045440, 1024); -f(17609365914625, 1025); -f(35167192221695, 2047); -f(35184372090880, 2048); -f(35201551960065, 2049); -f(70351564312575, 4095); -f(70368744181760, 4096); -f(70385924050945, 4097); -f(140720308494335, 8191); -f(140737488363520, 8192); -f(140754668232705, 8193); -f(281457796857855, 16383); -f(281474976727040, 16384); -f(281492156596225, 16385); -f(562932773584895, 32767); -f(562949953454080, 32768); -f(562967133323265, 32769); -f(1125882727038975, 65535); -f(1125899906908160, 65536); -f(1125917086777345, 65537); diff --git a/deps/v8/test/mjsunit/numops-fuzz-part1.js b/deps/v8/test/mjsunit/numops-fuzz-part1.js new file mode 100644 index 0000000000..8e98ae6323 --- /dev/null +++ b/deps/v8/test/mjsunit/numops-fuzz-part1.js @@ -0,0 +1,1172 @@ +// 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. + +function f() { + var x = 0; + var tmp = 0; + assertEquals(0, x /= (tmp = 798469700.4090232, tmp)); + assertEquals(0, x *= (2714102322.365509)); + assertEquals(0, x *= x); + assertEquals(139516372, x -= (tmp = -139516372, tmp)); + assertEquals(1, x /= (x%(2620399703.344006))); + assertEquals(0, x >>>= x); + assertEquals(-2772151192.8633175, x -= (tmp = 2772151192.8633175, tmp)); + assertEquals(-2786298206.8633175, x -= (14147014)); + assertEquals(1509750523, x |= ((1073767916)-(tmp = 919311632.2789925, tmp))); + assertEquals(2262404051.926751, x += ((752653528.9267509)%x)); + assertEquals(-270926893, x |= (tmp = 1837232194, tmp)); + assertEquals(0.17730273401688765, x /= ((tmp = -2657202795, tmp)-(((((x|(tmp = -1187733892.282897, tmp))-x)<<(556523578))-x)+(-57905508.42881298)))); + assertEquals(122483.56550261026, x *= ((((tmp = 2570017060.15193, tmp)%((-1862621126.9968336)>>x))>>(x>>(tmp = 2388674677, tmp)))>>>(-2919657526.470434))); + assertEquals(0, x ^= x); + assertEquals(0, x <<= (tmp = 2705124845.0455265, tmp)); + assertEquals(0, x &= (-135286835.07069612)); + assertEquals(-0, x *= ((tmp = -165810479.10020828, tmp)|x)); + assertEquals(248741888, x += ((735976871.1308595)<<(-2608055185.0700903))); + assertEquals(139526144, x &= (tmp = -1454301068, tmp)); + assertEquals(-0.047221345672746884, x /= (tmp = -2954726130.994727, tmp)); + assertEquals(0, x <<= (x>>x)); + assertEquals(0, x >>>= ((x+(912111201.488966))-(tmp = 1405800042.6070075, tmp))); + assertEquals(-1663642733, x |= (((-1663642733.5700119)<<(x^x))<<x)); + assertEquals(-914358272, x <<= ((((-308411676)-(-618261840.9113789))%(-68488626.58621716))-x)); + assertEquals(-1996488704, x &= (-1358622641.5848842)); + assertEquals(-345978263, x += (1650510441)); + assertEquals(3, x >>>= (-1106714178.701668)); + assertEquals(1, x %= (((x>>(x>>(tmp = -3052773846.817114, tmp)))*(tmp = 1659218887.379526, tmp))&x)); + assertEquals(-943225672, x += (-943225673)); + assertEquals(-0.41714300120060854, x /= (tmp = 2261156652, tmp)); + assertEquals(0, x >>>= ((3107060934.8863482)<<(tmp = 1902730887, tmp))); + assertEquals(0, x &= x); + assertEquals(1476628, x |= ((tmp = -2782899841.390033, tmp)>>>(2097653770))); + assertEquals(0.0008887648921591833, x /= ((tmp = 1661438264.5253348, tmp)%((tmp = 2555939813, tmp)*(-877024323.6515315)))); + assertEquals(0, x <<= (tmp = -2366551345, tmp)); + assertEquals(0, x &= (tmp = 1742843591, tmp)); + assertEquals(0, x -= x); + assertEquals(4239, x += ((-3183564176.232031)>>>(349622674.1255014))); + assertEquals(-67560, x -= ((2352742295)>>>x)); + assertEquals(-67560, x &= x); + assertEquals(-0.00003219917807302283, x /= (2098190203.699741)); + assertEquals(0, x -= x); + assertEquals(0, x >>= ((((tmp = -869086522.8358297, tmp)/(187820779))-(tmp = -2000970995.1931965, tmp))|(1853528755.6064696))); + assertEquals(0, x >>= (-3040509919)); + assertEquals(0, x %= (((tmp = -2386688049.194946, tmp)<<(tmp = -669711391, tmp))|x)); + assertEquals(0, x %= (tmp = -298431511.4839926, tmp)); + assertEquals(0, x /= (2830845091.2793818)); + assertEquals(0, x /= ((((-2529926178)|x)^((tmp = 2139313707.0894063, tmp)%((-1825768525.0541775)-(-952600362.7758243))))+x)); + assertEquals(NaN, x /= x); + assertEquals(NaN, x -= x); + assertEquals(NaN, x /= (tmp = -432944480, tmp)); + assertEquals(0, x <<= (((((x^((-1777523727)+(2194962794)))>>>(((((-590335134.8224905)%(x*(2198198974)))|(tmp = -2068556796, tmp))/(1060765637))*(-147051676)))/((tmp = -477350113.92686677, tmp)<<((x/(2018712621.0397925))^((tmp = 491163813.3921983, tmp)+(((x|((((x%(1990073256.812654))%((-2024388518.9599915)>>((tmp = 223182187, tmp)*(-722241065))))>>>(tmp = 2517147885.305745, tmp))%(1189996239.11222)))&x)%(-306932860))))))&((tmp = 1117802724.485684, tmp)+((-1391614045)-x)))%((((x>>((2958453447)*x))^(((410825859)|(((tmp = -1119269292.5495896, tmp)>>>(((((((x%(tmp = 648541746.6059314, tmp))*((-2304508480)<<((((x^(1408199888.1454597))|((251623937)|x))/((-382389946.9984102)|(tmp = -2082681143.5893767, tmp)))-(((tmp = 631243472, tmp)>>>(1407556544))/(((x>>>x)>>>(tmp = -6329025.47865057, tmp))>>>(tmp = 948664752.543093, tmp))))))/((((-183248880)>>x)&x)&x))>>x)&(((-978737284.8492057)%(tmp = 2983300011.737006, tmp))&(tmp = 2641937234.2954116, tmp)))<<x)>>(2795416632.9722223)))%((((tmp = -50926632, tmp)/x)&(((tmp = -2510786916, tmp)/x)/(-699755674)))|((((tmp = 1411792593, tmp)>>(924286570.2637128))>>((1609997725)>>(2735658951.0762663)))*(tmp = 726205435, tmp)))))<<(tmp = -2135055357.3156831, tmp)))/(tmp = 1408695065, tmp))^(tmp = -1343267739.8562133, tmp)))); + assertEquals(0, x %= (-437232116)); + assertEquals(-2463314518.2747326, x -= (2463314518.2747326)); + assertEquals(109, x >>= (2401429560)); + assertEquals(-2687641732.0253763, x += (-2687641841.0253763)); + assertEquals(-2336375490019484000, x *= (tmp = 869303174.6678596, tmp)); + assertEquals(5.458650430363785e+36, x *= x); + assertEquals(0, x |= ((((-1676972008.797291)*x)*((tmp = 2606991807, tmp)-x))<<x)); + assertEquals(0, x &= ((-3053393759.3496876)+(-1431008367))); + assertEquals(-856728369, x |= (x-(((((764337872)/x)<<((x|(((tmp = 1409368192.1268077, tmp)+(tmp = -848083676, tmp))|(-2797102463.7915916)))^x))/x)^(tmp = 856728369.0589117, tmp)))); + assertEquals(-0, x %= x); + assertEquals(1116550103, x ^= (-3178417193)); + assertEquals(1116550103, x %= (tmp = -1482481942, tmp)); + assertEquals(133, x >>>= x); + assertEquals(-1.381429241671034e-7, x /= ((tmp = -962771116.8101778, tmp)^x)); + assertEquals(-1092268961, x |= ((tmp = 3202672531, tmp)-((x-(tmp = 845529357, tmp))>>(tmp = -868680593, tmp)))); + assertEquals(-1092268961, x %= (tmp = 2670840415.304719, tmp)); + assertEquals(-122794480, x %= (tmp = 969474481, tmp)); + assertEquals(-297606521542193600, x *= (2423614820)); + assertEquals(72460064, x >>>= (tmp = -1230798655, tmp)); + assertEquals(-203714325373689600, x *= (-2811401400)); + assertEquals(2154914048, x >>>= (((2241377026.001436)/x)+x)); + assertEquals(1177864081, x ^= (tmp = -968513903, tmp)); + assertEquals(35947664, x &= (-2086226758.2704995)); + assertEquals(20795732539020670, x += (x*(578500247))); + assertEquals(-892004992, x >>= x); + assertEquals(-7023661.354330708, x /= ((((((1740714214)%((tmp = -459699286, tmp)+(tmp = -1700187400, tmp)))>>(tmp = -3170295237, tmp))+(tmp = -497509780, tmp))+((1971976144.6197853)+(661992813.6077721)))>>>(-1683802728))); + assertEquals(-1634205696, x <<= x); + assertEquals(-7, x >>= (-3187653764.930914)); + assertEquals(-5.095345981491203, x -= ((tmp = 748315289, tmp)/(tmp = -392887780, tmp))); + assertEquals(1486531570, x &= (1486531570.9300508)); + assertEquals(5670, x >>= (((tmp = -2486758205.26425, tmp)*(732510414))|x)); + assertEquals(5670, x >>= (((-1811879946.2553763)%(1797475764))/(((tmp = -2159923884, tmp)|x)+(tmp = -1774410807, tmp)))); + assertEquals(38, x %= (x>>>x)); + assertEquals(-151134215, x ^= (((tmp = -2593085609.5622163, tmp)+((tmp = -814992345.7516887, tmp)-(534809571)))|(tmp = -232678571, tmp))); + assertEquals(-234881024, x <<= x); + assertEquals(-234881024, x <<= (x>>>x)); + assertEquals(55169095435288580, x *= x); + assertEquals(0, x >>= (tmp = 1176612256, tmp)); + assertEquals(0, x <<= (1321866341.2486475)); + assertEquals(0, x %= (x-(-602577995))); + assertEquals(0, x >>>= (((((tmp = -125628635.79970193, tmp)^(tmp = 1294209955.229382, tmp))&(((tmp = -2353256654.0725203, tmp)|((-1136743028.9425385)|((((950703429.1110399)-(x>>>x))/((((x%(-252705869.21126103))/((tmp = 886957620, tmp)<<(x%((tmp = -1952249741, tmp)*(tmp = -1998149844, tmp)))))|(tmp = 1933366713, tmp))|((tmp = -2957141565, tmp)>>>(tmp = 1408598804, tmp))))+(((((((-2455002047.4910946)%(tmp = -528017836, tmp))&((-2693432769)/(tmp = 2484427670.9045153, tmp)))%(-356969659))-((((((tmp = 3104828644.0753174, tmp)%(x>>>(tmp = 820832137.8175925, tmp)))*((tmp = 763080553.9260503, tmp)+(3173597855)))<<(((-510785437)^x)<<(x|(((x*(x%((tmp = -1391951515, tmp)/x)))-x)|(x-((-522681793.93221474)/((2514619703.2162743)*(2936688324))))))))|x)>>>(-2093210042)))&(763129279.3651779))&x))))-x))%(((-1331164821)&(tmp = 1342684586, tmp))<<(x<<(tmp = 2675008614.588005, tmp))))>>((2625292569.8984914)+(-3185992401)))); + assertEquals(0, x *= (tmp = 671817215.1147974, tmp)); + assertEquals(-1608821121, x ^= ((tmp = 2686146175.04077, tmp)>>>x)); + assertEquals(-0, x %= x); + assertEquals(-0, x /= ((tmp = 286794551.0720866, tmp)|(x%x))); + assertEquals(0, x <<= (x|(tmp = 1095503996.2285218, tmp))); + assertEquals(443296752, x ^= (443296752)); + assertEquals(110824188, x >>= ((184708570)>>(x&x))); + assertEquals(0.7908194935161674, x /= ((((167151154.63381648)&((tmp = -1434120690, tmp)-(tmp = 2346173080, tmp)))/(56656051.87305987))^(140138414))); + assertEquals(-0.9027245492678485, x *= ((tmp = 1724366578, tmp)/(((2979477411)<<(((897038568)>>(tmp = 348960298, tmp))%(281056223.2037884)))^((((-1383133388)-(((-1379748375)-((x>>(x&(tmp = 2456582046, tmp)))>>>(-2923911755.565961)))&x))<<(-2825791731))^(tmp = -1979992970, tmp))))); + assertEquals(0, x &= (2482304279)); + assertEquals(-0, x *= (-2284213673)); + assertEquals(0, x <<= ((2874381218.015819)|x)); + assertEquals(0, x *= (x>>>(tmp = 2172786480, tmp))); + assertEquals(0, x &= (-1638727867.2978938)); + assertEquals(0, x %= ((tmp = -2213947368.285817, tmp)>>x)); + assertEquals(0, x >>>= (tmp = -531324706, tmp)); + assertEquals(0, x %= (tmp = -2338792486, tmp)); + assertEquals(0, x <<= (((tmp = 351012164, tmp)<<(x|((tmp = -3023836638.5337825, tmp)^(-2678806692))))|x)); + assertEquals(0, x %= (x-(tmp = -3220231305.45039, tmp))); + assertEquals(0, x <<= (-2132833261)); + assertEquals(0, x >>>= x); + assertEquals(0, x %= ((2544970469)+(((-2633093458.5911965)&(644108176))-(x>>>(tmp = -949043718, tmp))))); + assertEquals(-2750531265, x += (-2750531265)); + assertEquals(0, x >>= x); + assertEquals(0, x *= ((tmp = 1299005700, tmp)-x)); + assertEquals(0, x >>= x); + assertEquals(-1785515304, x -= (((((-806054462.5563161)/x)>>>x)+(1785515304))|((tmp = 2937069788.9396844, tmp)/x))); + assertEquals(-3810117159.173689, x -= (2024601855.1736891)); + assertEquals(-6.276064139320051, x /= (607087033.3053156)); + assertEquals(134217727, x >>>= (((x%(tmp = 924293127, tmp))^x)|((x>>>(x&((((tmp = -413386639, tmp)/(x>>(tmp = 599075308.8479941, tmp)))^(tmp = -1076703198, tmp))*((tmp = -2239117284, tmp)>>(655036983)))))-x))); + assertEquals(134217727, x %= (tmp = 2452642261.038778, tmp)); + assertEquals(-569504740360507, x *= ((tmp = -1086243941, tmp)>>(tmp = 1850668904.4885683, tmp))); + assertEquals(113378806, x >>>= (tmp = -2558233435, tmp)); + assertEquals(979264375, x -= (((x>>(1950008052))%((2917183569.0209)*(tmp = 1184250640.446752, tmp)))|((((tmp = -691875212, tmp)-(-2872881803))>>(tmp = 44162204.97461021, tmp))^(tmp = 865885647, tmp)))); + assertEquals(-1127813632, x <<= ((((tmp = -2210499281, tmp)>>>x)-(tmp = 2359697240, tmp))-x)); + assertEquals(-1707799657, x ^= (653518231.3995534)); + assertEquals(2916579668449318000, x *= x); + assertEquals(2916579669254640600, x += (x&(tmp = 2986558026.399422, tmp))); + assertEquals(870995175, x ^= (2598813927.8991632)); + assertEquals(870995175, x %= (-2857038782)); + assertEquals(1869503575895591000, x *= (x|(x|(((tmp = 2478650307.4118147, tmp)*((tmp = 2576240847.476932, tmp)>>>x))<<x)))); + assertEquals(-134947790, x |= ((tmp = 1150911808, tmp)*((2847735464)/(-2603172652.929262)))); + assertEquals(-137053182, x -= ((tmp = 2155921819.0929346, tmp)>>>(x-(((-1960937402)-(-1907735074.2875962))%((1827808310)^(tmp = -2788307127, tmp)))))); + assertEquals(-134824702, x |= (((2912578752.2395406)^(x%(((-2585660111.0638976)<<(((((tmp = 747742706, tmp)%(-1630261205))&((((x|(x|(-2619903144.278758)))|((2785710568.8651934)>>((-968301967.5982246)<<(x&x))))>>((x>>>((x>>>(tmp = -1402085797.0310762, tmp))*((tmp = -323729645.2250068, tmp)<<(tmp = 2234667799, tmp))))>>>(-167003745)))>>((924665972.4681011)<<x)))>>>x)<<((((x+x)+x)-(((tmp = 2399203431.0526247, tmp)-(-2872533271))-(((tmp = 914778794.2087344, tmp)-(tmp = 806353942.9502392, tmp))|(((tmp = 262924334.99231672, tmp)&x)|(tmp = -460248836.5602243, tmp)))))/x)))%((-1681000689)/(tmp = -2805054623.654228, tmp)))))*(tmp = 957346233.9619625, tmp))); + assertEquals(-3274838, x %= ((((tmp = 3155450543.3524327, tmp)>>>x)<<(tmp = 2103079652.3410985, tmp))>>x)); + assertEquals(-3274838, x |= ((((tmp = 2148004645.639173, tmp)>>>(tmp = -1285119223, tmp))<<(((((-711596054)>>>(tmp = -2779776371.3473206, tmp))^(((((tmp = -1338880329.383915, tmp)<<((-1245247254.477341)>>x))*(tmp = -2649052844.20065, tmp))>>((1734345880.4600453)%(x/(2723093117.118899))))*(1252918475.3285656)))<<(2911356885))^x))<<(-1019761103))); + assertEquals(1703281954, x &= (((tmp = 1036570471.7412028, tmp)+((tmp = 3043119517, tmp)%(2374310816.8346715)))%(tmp = -2979155076, tmp))); + assertEquals(1741588391, x |= ((tmp = 1230009575.6003838, tmp)>>>(-1247515003.8152597))); + assertEquals(72869474.64782429, x %= (tmp = 1668718916.3521757, tmp)); + assertEquals(770936242.104203, x += (698066767.4563787)); + assertEquals(-0.2820604726420833, x /= (tmp = -2733230342, tmp)); + assertEquals(403480578, x |= ((969730374)&(tmp = 1577889835, tmp))); + assertEquals(-1669557233, x ^= ((-1616812135)+(tmp = -456209292, tmp))); + assertEquals(-1630427, x >>= ((2327783031.1175823)/(226947662.4579488))); + assertEquals(131022, x >>>= ((tmp = -1325018897.2482083, tmp)>>(x&((((((-1588579772.9240348)<<(tmp = -1775580288.356329, tmp))<<(tmp = -1021528325.2075481, tmp))>>((tmp = 2373033451.079956, tmp)*(tmp = 810304612, tmp)))-((tmp = -639152097, tmp)<<(tmp = 513879484, tmp)))&(2593958513))))); + assertEquals(1, x >>= ((3033200222)-x)); + assertEquals(-561146816.4851823, x += (tmp = -561146817.4851823, tmp)); + assertEquals(-4.347990105831158, x /= ((((-1270435902)*x)%((tmp = 637328492.7386824, tmp)-(x>>(-749100689))))%(x+x))); + assertEquals(-1, x >>= x); + assertEquals(1, x *= x); + assertEquals(111316849706694460, x += ((966274056)*(x|(115202150)))); + assertEquals(-1001883840, x >>= x); + assertEquals(-1001883840, x &= x); + assertEquals(-3006880758, x += ((((-2275110637.4054556)/((x+(tmp = -1390035090.4324536, tmp))>>(-5910593)))&(tmp = 378982420, tmp))|(tmp = 2289970378.568629, tmp))); + assertEquals(314474, x >>>= (x>>((tmp = -228007336.31281257, tmp)%(tmp = 1127648013, tmp)))); + assertEquals(-17694827, x ^= ((tmp = 2095133598.1849852, tmp)|(-1978322311))); + assertEquals(1, x /= x); + assertEquals(1, x %= (-2323617209.7531185)); + assertEquals(0, x >>>= (x*(tmp = -1574455400.489434, tmp))); + assertEquals(0, x >>= (3131854684)); + assertEquals(2853609824, x += ((-231012098)-(tmp = -3084621922, tmp))); + assertEquals(8143089027629311000, x *= x); + assertEquals(313052685, x ^= (tmp = 2962303501, tmp)); + assertEquals(4776, x >>= (tmp = 2271457232, tmp)); + assertEquals(0.000002812258572702285, x /= (tmp = 1698279115, tmp)); + assertEquals(0, x >>>= (tmp = 1698465782.0927145, tmp)); + assertEquals(0, x <<= x); + assertEquals(0, x |= ((x<<((-1824760240.3040407)<<(2798263764.39145)))&(tmp = 1795988253.0493627, tmp))); + assertEquals(1782206945, x ^= (-2512760351.7881565)); + assertEquals(7610569113843172000, x *= (((tmp = -44415823.92972565, tmp)&(tmp = 1402483498.9421625, tmp))+(tmp = 2909778666, tmp))); + assertEquals(15221138227873292000, x += (x-(tmp = -186948658.394145, tmp))); + assertEquals(0, x -= x); + assertEquals(-2238823252, x -= ((tmp = 2238823252, tmp)+x)); + assertEquals(0, x -= x); + assertEquals(0, x >>= (2976069570)); + assertEquals(0, x >>= ((tmp = -2358157433, tmp)/x)); + assertEquals(-949967713, x ^= (tmp = -949967713, tmp)); + assertEquals(-1, x >>= x); + assertEquals(-1522291702.1977966, x *= (1522291702.1977966)); + assertEquals(-1522291702, x >>= ((((2290279800)|x)|(1793154434.6798015))&((-1161390929.0766077)>>>x))); + assertEquals(83894274, x &= (tmp = 1571058486, tmp)); + assertEquals(43186847.90522933, x += ((tmp = -1131332988.0947707, tmp)%x)); + assertEquals(0, x >>= (tmp = -1968312707.269359, tmp)); + assertEquals(0, x &= (2507747643.26175)); + assertEquals(0, x %= (tmp = 3190525303.366887, tmp)); + assertEquals(-1968984602, x ^= (((x/(x|(-1607062026.5338054)))<<(tmp = 2207669861.8770065, tmp))+(tmp = 2325982694.956348, tmp))); + assertEquals(554, x >>>= (((tmp = -2302283871.993821, tmp)>>>(-3151835112))|(((((x%(-1534374264))/((731246012)<<(((883830997.1194847)<<(((-1337895080.1937215)/(tmp = 3166402571.8157315, tmp))^(tmp = -1563897595.5799441, tmp)))>>(tmp = -556816951.0537591, tmp))))>>(-2682203577))<<(x/((1654294674.865079)+x)))/((x^(-2189474695.4259806))/(-475915245.7363057))))); + assertEquals(1372586111, x ^= (1372586581)); + assertEquals(1166831229, x -= ((-834168138)&(762573579))); + assertEquals(2333662456, x -= ((x>>x)-x)); + assertEquals(-1961304840, x &= x); + assertEquals(-2130143128, x &= (2982852718.0711775)); + assertEquals(1073741824, x <<= (-1446978661.6426942)); + assertEquals(2097152, x >>>= ((-1424728215)-(((127872198)%(tmp = -2596923298, tmp))&x))); + assertEquals(2097152, x >>>= x); + assertEquals(0, x &= (x/(tmp = -518419194.42994523, tmp))); + assertEquals(0, x >>= ((x/(-1865078245))%(tmp = 2959239210, tmp))); + assertEquals(-0, x *= ((x|(-1721307400))|(-3206147171.9491577))); + assertEquals(0, x >>>= ((-694741143)&(tmp = -2196513947.699142, tmp))); + assertEquals(0, x <<= x); + assertEquals(0, x &= ((tmp = 2037824385.8836646, tmp)+((tmp = 1203034986.4647732, tmp)/(x>>>(((-1374881234)/(899771270.3237157))+((-2296524362.8020077)|(-1529870870))))))); + assertEquals(0, x >>= (tmp = 2770637816, tmp)); + assertEquals(0, x ^= x); + assertEquals(-1861843456, x |= ((632402668)*((x|(tmp = -1032952662.8269436, tmp))|(tmp = 2671272511, tmp)))); + assertEquals(-1861843456, x >>= (((x>>>x)+x)<<(-1600908842))); + assertEquals(-58182608, x >>= (x-(tmp = -2496617861, tmp))); + assertEquals(-3636413, x >>= (tmp = -400700028, tmp)); + assertEquals(-7272826, x += x); + assertEquals(-1, x >>= ((tmp = -3184897005.3614545, tmp)-((-1799843014)|(tmp = 2832132915, tmp)))); + assertEquals(-121800925.94209385, x *= (121800925.94209385)); + assertEquals(-30450232, x >>= (-979274206.6261561)); + assertEquals(-30450232, x >>= (tmp = -1028204832.5078967, tmp)); + assertEquals(-30450232, x |= x); + assertEquals(965888871, x ^= (((((-2157753481.3375635)*((tmp = -1810667184.8165767, tmp)&((tmp = 2503908344.422232, tmp)|x)))>>(x>>(1601560785)))<<x)^(tmp = 943867311.6380403, tmp))); + assertEquals(7546006, x >>>= x); + assertEquals(7546006, x <<= ((tmp = 1388931761.780241, tmp)*(x-(tmp = -1245147647.0070577, tmp)))); + assertEquals(12985628, x += (x&(-1520746354))); + assertEquals(12985628, x &= x); + assertEquals(12985628, x %= (tmp = 308641965, tmp)); + assertEquals(685733278, x |= ((tmp = -1275653544, tmp)-((tmp = -1956798010.3773859, tmp)%(tmp = 2086889575.643448, tmp)))); + assertEquals(679679376, x &= (2860752368)); + assertEquals(1770773904, x |= (x<<(3200659207))); + assertEquals(1224886544, x &= (-585733767.6876519)); + assertEquals(1224886544, x %= ((tmp = -114218494, tmp)-x)); + assertEquals(1208109328, x &= (tmp = 1854361593, tmp)); + assertEquals(18434, x >>>= x); + assertEquals(-349394636955256100, x *= (x*(-1028198742))); + assertEquals(-519536600.7713163, x %= (-1054085356.9120367)); + assertEquals(-1610612736, x ^= ((tmp = -3126078854, tmp)&x)); + assertEquals(-2637321565906333700, x *= (1637464740.5658746)); + assertEquals(-2637321568051070500, x -= ((tmp = -1006718806, tmp)<<(3005848133.106345))); + assertEquals(368168695, x ^= (x^(tmp = 368168695.6881037, tmp))); + assertEquals(43, x >>>= x); + assertEquals(-2081297089, x |= ((167169305.77248895)+(-2248466405.3199244))); + assertEquals(-2474622167, x -= (tmp = 393325078, tmp)); + assertEquals(-135109701, x %= (-1169756233)); + assertEquals(0, x ^= x); + assertEquals(0, x >>= (((((tmp = -164768854, tmp)/(tmp = -1774989993.1909926, tmp))+x)-((-921438912)>>(tmp = -191772028.69249105, tmp)))-(tmp = 558728578.22033, tmp))); + assertEquals(0, x %= (tmp = 2188003745, tmp)); + assertEquals(0, x <<= (((tmp = -999335540, tmp)>>((((325101977)/(tmp = -3036991542, tmp))<<(tmp = -213302488, tmp))+x))|(tmp = -1054204587, tmp))); + assertEquals(0, x &= ((2844053429.4720345)>>>x)); + assertEquals(NaN, x %= x); + assertEquals(NaN, x -= (-1481729275.9118822)); + assertEquals(NaN, x *= (tmp = 1098314618.2397528, tmp)); + assertEquals(-1073741824, x ^= ((tmp = 1718545772, tmp)<<(((tmp = -81058910, tmp)-(2831123087.424368))+(tmp = 576710057.2361784, tmp)))); + assertEquals(-2921155898.4793186, x -= (1847414074.4793184)); + assertEquals(-1295646720, x <<= (2178621744)); + assertEquals(-0.8906779709597907, x /= ((tmp = -2840292585.6837263, tmp)<<(x&((tmp = 892527695.6172305, tmp)>>>x)))); + assertEquals(0, x <<= (((tmp = 3149667213.298993, tmp)>>(tmp = 1679370761.7226725, tmp))^(115417747.21537328))); + assertEquals(0, x |= x); + assertEquals(0, x %= ((-1112849427)>>(-1245508870.7514496))); + assertEquals(0, x &= x); + assertEquals(0, x |= x); + assertEquals(0, x >>>= ((3144100694.930459)>>>(tmp = 2408610503, tmp))); + assertEquals(0, x <<= ((tmp = 2671709754.0318713, tmp)%x)); + assertEquals(0, x >>>= (x|((tmp = -3048578701, tmp)-(674147224)))); + assertEquals(NaN, x %= x); + assertEquals(0, x &= ((tmp = -2084883715, tmp)|(((((-3008427069)+(875536047.4283574))>>>x)%(tmp = -450003426.1091652, tmp))%(((-2956878433.269356)|(x/((((x%((((((x<<(((tmp = -1581063482.510351, tmp)^x)-(tmp = 1364458217, tmp)))^((tmp = 1661446342, tmp)+(1307091014)))/(342270750.9901335))>>>(x&((1760980812.898993)&((tmp = 2878165745.6401143, tmp)/(((tmp = -981178013, tmp)/(-2338761668.29912))>>(-958462630))))))*((1807522840)^((tmp = 1885835034, tmp)^(-2538647938))))*(1673607540.0854697)))%x)>>x)<<x)))<<(853348877.2407281))))); + assertEquals(0, x >>>= x); + assertEquals(-1162790279, x -= (1162790279)); + assertEquals(-1162790279, x >>= (((-490178658)*x)/((((((tmp = -1883861998.6699312, tmp)/(tmp = -2369967345.240594, tmp))+(3142759868.266447))&(508784917.8158537))&x)>>(-2129532322)))); + assertEquals(-1360849740.9829152, x -= (x+(1360849740.9829152))); + assertEquals(1928392181, x ^= (-602670783)); + assertEquals(19478708.898989897, x /= (((-2617861994)>>(tmp = 797256920, tmp))%(-1784987906))); + assertEquals(-8648903.575540157, x *= (((tmp = 673979276, tmp)/(-1517908716))%(x/x))); + assertEquals(-8648903.575540157, x %= ((((643195610.4221292)>>>(tmp = 2342669302, tmp))>>>(tmp = -1682965878, tmp))^((tmp = -208158937.63443017, tmp)>>((907286989)&(x<<(448634893)))))); + assertEquals(1399288769, x ^= (tmp = -1407486728, tmp)); + assertEquals(0, x &= (((1999255838.815517)/(tmp = 564646001, tmp))/(-3075888101.3274765))); + assertEquals(0, x ^= ((-78451711.59404826)%x)); + assertEquals(-1351557131, x |= (2943410165)); + assertEquals(1715626371, x -= (-3067183502)); + assertEquals(71434240, x &= ((-1800066426)<<(((((x<<(-324796375))+x)<<(tmp = 2696824955.735132, tmp))^x)%(tmp = 444916469, tmp)))); + assertEquals(71434240, x >>>= (((x&((x%x)|x))+(tmp = 2226992348.3050146, tmp))<<(-305526260))); + assertEquals(0, x -= (x%(tmp = 582790928.5832802, tmp))); + assertEquals(0, x *= ((x%(1865155340))>>>((x<<(2600488191))^(-308995123)))); + assertEquals(0, x >>= (x&(-3120043868.8531103))); + assertEquals(0, x |= x); + assertEquals(-0, x *= (tmp = -172569944, tmp)); + assertEquals(0, x <<= (-1664372874)); + assertEquals(1377713344.6784928, x += (tmp = 1377713344.6784928, tmp)); + assertEquals(1377713344, x |= x); + assertEquals(-232833282, x |= (tmp = 2685870654, tmp)); + assertEquals(84639, x -= (((((2778531079.998492)%(2029165314))>>>(tmp = -468881172.3729558, tmp))^x)|((x>>>((((x%(3044318992.943596))&(1996754328.2214756))^(1985227172.7485228))%(tmp = -1984848676.1347625, tmp)))|((tmp = 2637662639, tmp)<<x)))); + assertEquals(0, x ^= x); + assertEquals(1237720303, x -= (-1237720303)); + assertEquals(2, x >>= (-2148785379.428976)); + assertEquals(2, x &= (tmp = -3087007874, tmp)); + assertEquals(0, x %= x); + assertEquals(0, x >>>= x); + assertEquals(0, x >>>= x); + assertEquals(0, x += x); + assertEquals(0, x &= (2055693082)); + assertEquals(-1349456492, x += (x^(-1349456492.315998))); + assertEquals(671088640, x <<= (x>>(-2030805724.5472062))); + assertEquals(-417654580004782100, x *= (tmp = -622353822, tmp)); + assertEquals(1538160360, x |= (195983080.56698656)); + assertEquals(733, x >>>= (tmp = 661085269, tmp)); + assertEquals(657, x &= (-1611460943.993404)); + assertEquals(431649, x *= x); + assertEquals(863298, x += x); + assertEquals(0, x &= ((1899423003)/((472439729)>>((tmp = 2903738952, tmp)+(tmp = 2164601630.3456993, tmp))))); + assertEquals(0, x &= (x>>>(tmp = 1939167951.2828958, tmp))); + assertEquals(1557813284, x |= (x-(-1557813284))); + assertEquals(72876068, x &= (662438974.2372154)); + assertEquals(0.6695448637501589, x /= (tmp = 108844189.45702457, tmp)); + assertEquals(0, x -= x); + assertEquals(2944889412, x += (2944889412)); + assertEquals(3787980288, x -= ((((tmp = -2003814373.2301111, tmp)<<x)>>>(tmp = -3088357284.4405823, tmp))-(843090884))); + assertEquals(1, x >>>= (729274079)); + assertEquals(1, x %= (-148002187.33869123)); + assertEquals(3073988415.673201, x *= (tmp = 3073988415.673201, tmp)); + assertEquals(4839166225.673201, x += (tmp = 1765177810, tmp)); + assertEquals(4529373898.673201, x += (-309792327)); + assertEquals(3097903.090496063, x %= (-150875866.51942348)); + assertEquals(1270874112, x <<= ((((((tmp = -960966763.1418135, tmp)>>((((-3208596981.613482)>>>(tmp = 746403937.6913509, tmp))>>>(-2190042854.066803))/(2449323432)))*(-1272232665.791577))<<(-99306767.7209444))^((-1942103828)/((1570981655)/(tmp = 2381666337, tmp))))+(tmp = -1946759395.1558368, tmp))); + assertEquals(1273845956, x |= (tmp = -3197282108.6120167, tmp)); + assertEquals(159230744, x >>= (((tmp = -1036031403.8108604, tmp)>>>(((3084964493)>>((x*x)^x))+(((2980108409.352001)^x)-(tmp = -2501685423.513927, tmp))))&(326263839))); + assertEquals(-370091747145550100, x *= (tmp = -2324248055.674161, tmp)); + assertEquals(143384219.54999557, x /= (tmp = -2581119096, tmp)); + assertEquals(1843396287, x |= (tmp = 1842718767, tmp)); + assertEquals(2.4895593465813803, x /= (740450831)); + assertEquals(2.4895593465813803, x %= ((((((((-3175333618)>>>((tmp = -1403880166, tmp)<<(tmp = -134875360, tmp)))>>>(2721317334.998084))<<(x&(tmp = 2924634208.1484184, tmp)))*((((x>>(tmp = -200319931.15328693, tmp))-(tmp = -495128933, tmp))+((-788052518.6610589)*((((tmp = 107902557, tmp)&(1221562660))%(x<<(((3155498059)*(((tmp = -1354381139.4897022, tmp)^(tmp = 3084557138.332852, tmp))*((((tmp = 1855251464.8464525, tmp)/((-1857403525.2008865)>>x))|x)-(-2061968455.0023944))))*(1917481864.84619))))^(x-(-508176709.52712965)))))+((((x%(-1942063404))+(x%(tmp = 855152281.180481, tmp)))|(-522863804))>>x)))>>>((tmp = -2515550553, tmp)&(((((-801095375)-(tmp = -2298729336.9792976, tmp))^x)/(tmp = 2370468053, tmp))>>(x|(tmp = -900008879, tmp)))))>>>(((tmp = -810295719.9509168, tmp)*((tmp = -1306212963.6226444, tmp)/(((tmp = 3175881540.9514832, tmp)|(-1439142297.819246))+((tmp = -134415617, tmp)|((-245801870)+x)))))>>(tmp = 1889815478, tmp)))-(((tmp = 597031177, tmp)%(858071823.7655672))+((tmp = 2320838665.8243756, tmp)|((938555608)<<(2351739219.6461897)))))); + assertEquals(6.197905740150709, x *= x); + assertEquals(1, x /= x); + assertEquals(0, x >>= (-1639664165.9076233)); + assertEquals(0, x >>= (-3135317748.801177)); + assertEquals(0, x &= (3185479232.5325994)); + assertEquals(-0, x *= ((-119759439.19668174)/(tmp = 2123964608, tmp))); + assertEquals(0, x /= (-1183061929.2827876)); + assertEquals(0, x <<= (-1981831198)); + assertEquals(0, x >>= ((((x<<(((((((-2133752838)&((tmp = -3045157736.9331336, tmp)>>>(x%x)))>>x)%(tmp = 3082217039, tmp))&(tmp = 270770770.97558427, tmp))|((-2212037556)^((((((2089224421)|(tmp = 360979560, tmp))<<x)%((tmp = -1679487690.6940534, tmp)+((173021423)|((tmp = 560900612, tmp)+((244376267.58977115)^x)))))<<(tmp = 2534513699, tmp))^x)))>>>(2915907189.4873834)))+(x*x))%(1637581117))%(tmp = 2363861105.3786244, tmp))); + assertEquals(0, x &= ((-2765495757.873004)&(1727406493))); + assertEquals(NaN, x -= (((((-1419667515.2616255)|x)-(150530256.48022234))%((((x|x)<<x)>>>(x^x))+x))-((-1216384577.3749187)*(495244398)))); + assertEquals(NaN, x += (x^((tmp = 2472035493, tmp)+x))); + assertEquals(NaN, x %= ((tmp = -1753037412.885754, tmp)|((tmp = 2507058310, tmp)<<(1475945705)))); + assertEquals(-1008981005, x |= ((tmp = -1140889842.6099494, tmp)-(tmp = -131908837, tmp))); + assertEquals(999230327.5872104, x -= (tmp = -2008211332.5872104, tmp)); + assertEquals(975810, x >>= (((-1211913874)*x)>>>((-2842129009)>>(x&(tmp = -1410865834, tmp))))); + assertEquals(7623, x >>= ((tmp = -1051327071, tmp)-(((tmp = -237716102.8005445, tmp)|((2938903833.416546)&x))|(((-1831064579)^x)/((tmp = 2999232092, tmp)-(981996301.2875179)))))); + assertEquals(0, x -= x); + assertEquals(0, x %= (x|(tmp = -666201160.5810485, tmp))); + assertEquals(-1347124100, x |= (-1347124100)); + assertEquals(-0, x %= (x&x)); + assertEquals(-661607963, x ^= (tmp = -661607963.3794863, tmp)); + assertEquals(3465, x >>>= (-828119020.8056595)); + assertEquals(-268431991, x -= (((tmp = -1386256352, tmp)^((tmp = 743629575, tmp)%((x*((tmp = -1719517658, tmp)>>(2019516558)))<<((2637317661)|x))))<<(tmp = -51637065, tmp))); + assertEquals(1578876380, x += ((tmp = 1847308371, tmp)&(((((((tmp = 1487934776.1893163, tmp)%(tmp = 1423264469.3137975, tmp))|(((2653260792.5668964)/(-2417905016.043802))>>>(2097411118.4501896)))^x)^(((tmp = -71334226, tmp)|x)>>>(tmp = -2771758874.7696714, tmp)))^((tmp = -1464849031.3240793, tmp)%(tmp = 2349739690.6430283, tmp)))/x))); + assertEquals(3269293934, x += (1690417554)); + assertEquals(4025392608.031957, x -= (((tmp = 268501120.7225704, tmp)<<(tmp = 2841620654.8903794, tmp))+((tmp = 1606704462.8455591, tmp)/((-2601879963)/(tmp = 2966620168.989736, tmp))))); + assertEquals(7, x >>>= (x^(-1913800035))); + assertEquals(1.4326776816275493e-8, x /= ((((tmp = -2703417892, tmp)/x)^((-2693772270.396241)>>>((x-(tmp = 615999818.5666655, tmp))>>((((2308121439.3702726)<<((-1794701502)>>(x+(tmp = -2253406035.972883, tmp))))<<((tmp = -197103799.0624652, tmp)|(629975898)))>>>x))))>>>((tmp = 2833656803, tmp)^(x^(tmp = -1580436025, tmp))))); + assertEquals(0, x >>>= (tmp = 1525372830.2126007, tmp)); + assertEquals(0, x %= ((2354010949.24469)>>>(x<<x))); + assertEquals(0, x ^= (((1112335059.6922574)*(tmp = -1874363935, tmp))&(((((2154894295.8360596)<<x)&(tmp = -270736315.13505507, tmp))&x)>>>(-2205692260.552064)))); + assertEquals(0, x >>>= (x<<((1488533932)*(tmp = 1707754286, tmp)))); + assertEquals(0, x >>= (((tmp = 1232547376.463387, tmp)%((x>>(711691823.1608362))>>>x))>>(((895039781.7478573)*(((((-334946524)&x)*(tmp = -1214529640, tmp))^(tmp = -1586820245, tmp))*(1062595445)))+x))); + assertEquals(0, x *= (1863299863.2631998)); + assertEquals(0, x /= (tmp = 1858428705.1330547, tmp)); + assertEquals(0, x &= x); + assertEquals(611788028, x += (x^(611788028.1510412))); + assertEquals(1, x /= x); + assertEquals(0, x >>= ((tmp = -1617320707.1784317, tmp)-((-2139400380)-(-1402777976)))); + assertEquals(0, x >>= (415866827.34665)); + assertEquals(-1990811897, x -= (tmp = 1990811897, tmp)); + assertEquals(-1990811895, x += ((x>>>(tmp = -2175453282.769696, tmp))&(tmp = -1459450498.7327478, tmp))); + assertEquals(-2377017935.149517, x += (-386206040.1495173)); + assertEquals(1946129845, x |= (tmp = -2890956796.936539, tmp)); + assertEquals(0, x %= x); + assertEquals(0, x <<= (1616188263)); + assertEquals(-1081213596, x ^= (tmp = 3213753700, tmp)); + assertEquals(3213753700, x >>>= (tmp = -3211181312, tmp)); + assertEquals(-1081213596, x &= x); + assertEquals(-1081213583, x ^= (((tmp = 1599988273.4926577, tmp)>>((((-1061394954.6331315)^x)+((-1835761078)*x))+(x%(tmp = -696221869, tmp))))/((tmp = -1156966790.3436491, tmp)^x))); + assertEquals(0, x ^= x); + assertEquals(NaN, x /= x); + assertEquals(NaN, x += (-1257400530.9263027)); + assertEquals(NaN, x /= (753062089)); + assertEquals(NaN, x *= ((tmp = 305418865.57012296, tmp)^(((-2797769706)+((((tmp = -33288276.988654375, tmp)%(tmp = 1242979846, tmp))|(-316574800))-((tmp = -1766083579.4203427, tmp)*(((x*(tmp = -2400342309.2349987, tmp))>>(tmp = 2632061795, tmp))^(tmp = -1001440809, tmp)))))^((((x-(tmp = -1469542637.6925495, tmp))-x)-(3184196890))%(((((((633226688)*((tmp = -2692547856, tmp)>>(((tmp = -1244311756, tmp)>>>x)+((1746013631.405202)>>>(941829464.1962085)))))%(x-x))+(995681795))-(tmp = -3047070551.3642616, tmp))/(1968259705))-((-2853237880)^(tmp = -2746628223.4540343, tmp))))))); + assertEquals(0, x >>= x); + assertEquals(0.5713172378854926, x += (((x+(((x+x)/(tmp = 2642822318, tmp))*(-2590095885.4280834)))|(tmp = -1769210836, tmp))/(tmp = -3096722308.8665104, tmp))); + assertEquals(-0.000002311097780334994, x /= ((2269858877.9010344)>>(-2992512915.984787))); + assertEquals(-0.000002311097780334994, x %= (-1139222821)); + assertEquals(-0.000004622195560669988, x += x); + assertEquals(1, x /= x); + assertEquals(1, x >>>= (((3002169429.6061807)/(-3068577366))>>>((tmp = -1844537620, tmp)%((((tmp = 2087505119, tmp)>>>x)+x)&(2179989542))))); + assertEquals(-534213071, x *= (-534213071)); + assertEquals(-534213077.3716287, x -= (((tmp = -2390432951.154034, tmp)^x)/(-290501980))); + assertEquals(1836305, x >>>= (x&x)); + assertEquals(1836305, x %= ((x|((3070123855)^(49986396)))+((-1863644960.4202995)>>>((tmp = 1886126804.6019692, tmp)^x)))); + assertEquals(28692, x >>>= ((2561362139.491764)>>(((((tmp = -1347469854.7413375, tmp)/(((x|(x+x))^((x^(tmp = -2737413775.4595394, tmp))^x))<<(((tmp = 225344844.07128417, tmp)&x)&(tmp = 145794498, tmp))))*x)<<(1424529187))/((-2924344715)/(tmp = -2125770148, tmp))))); + assertEquals(-2089419535.2717648, x += (-2089448227.2717648)); + assertEquals(18957929, x ^= (tmp = 2186590872, tmp)); + assertEquals(-708972800, x -= (727930729)); + assertEquals(-4198593, x |= (799483455.1885371)); + assertEquals(-1, x >>= (-2330654693.6413193)); + assertEquals(-1, x |= (((tmp = -116877155, tmp)>>>((((tmp = -1677422314.1333556, tmp)/(tmp = -3108738499.0798397, tmp))%((x&(x/x))%((tmp = -695607185.1561592, tmp)-(tmp = 2302449181.622259, tmp))))^(((-1482743646.5604773)^((897705064)>>>x))-(tmp = -2933836669, tmp))))%(((tmp = -2991584625, tmp)|(((x>>x)+(-1101066835))-x))>>(-33192973.819939613)))); + assertEquals(-1, x &= x); + assertEquals(-524288, x <<= (-1177513101.3087924)); + assertEquals(1978770334.9189441, x += (tmp = 1979294622.9189441, tmp)); + assertEquals(901783582, x &= ((-368584615)^(((((-478030699.2647903)<<x)<<x)+(tmp = 708725752, tmp))^((tmp = -3081556856, tmp)/(tmp = 1149958711.0676727, tmp))))); + assertEquals(-1480333211.8654308, x += (tmp = -2382116793.865431, tmp)); + assertEquals(956930239.6783283, x *= ((tmp = 956930239.6783283, tmp)/x)); + assertEquals(1277610.4668602513, x /= ((tmp = 1571029828, tmp)>>(tmp = 2417481141, tmp))); + assertEquals(-1077333228, x ^= (tmp = 3218755006, tmp)); + assertEquals(-50218, x |= (tmp = -1044436526.6435988, tmp)); + assertEquals(-1, x >>= (-154655245.18921852)); + assertEquals(0.00006276207290978003, x *= (((tmp = 2234286992.9800305, tmp)>>(tmp = 2132564046.0696363, tmp))/((((tmp = -2565534644.3428087, tmp)>>>(tmp = 2622809851.043325, tmp))>>>((tmp = 311277386, tmp)&x))-(tmp = -2003980974, tmp)))); + assertEquals(0, x %= x); + assertEquals(1282114076, x += ((((422838227)>>>((tmp = 1024613366.1899053, tmp)-((368275340)<<(((tmp = -3066121318, tmp)+(-2319101378))&x))))^(x>>(tmp = 1920136319.803412, tmp)))^(1282264803.3968434))); + assertEquals(-277097604, x |= (-283585688.9123297)); + assertEquals(553816692, x &= (x&(tmp = 554082036.676608, tmp))); + assertEquals(658505728, x <<= x); + assertEquals(658505728, x &= (x%(2846071230))); + assertEquals(39, x >>= (334728536.5172192)); + assertEquals(0, x -= x); + assertEquals(0, x += x); + assertEquals(0, x &= (tmp = -335285336, tmp)); + assertEquals(0, x <<= (tmp = 1255594828.3430014, tmp)); + assertEquals(0, x %= (-630772751.1248167)); + assertEquals(NaN, x /= ((((x&(tmp = -1576090612, tmp))%x)>>>x)*((-1038073094.2787619)>>>x))); + assertEquals(NaN, x += x); + assertEquals(NaN, x -= (((tmp = -2663887803, tmp)&((x+(-1402421046))/x))/(-2675654483))); + assertEquals(NaN, x %= (x&(tmp = 672002093, tmp))); + assertEquals(0, x |= x); + assertEquals(-2698925754, x += (tmp = -2698925754, tmp)); + assertEquals(-2057748993, x += ((tmp = -2263466497, tmp)^x)); + assertEquals(1, x /= x); + assertEquals(-2769559719.4045835, x -= (2769559720.4045835)); + assertEquals(-1.3964174646069973, x /= (tmp = 1983332198, tmp)); + assertEquals(-2140716624.3964174, x += (tmp = -2140716623, tmp)); + assertEquals(0, x <<= ((2589073007)-(-816764911.8571186))); + assertEquals(-2837097288.161354, x -= (tmp = 2837097288.161354, tmp)); + assertEquals(-1445059927.161354, x += (tmp = 1392037361, tmp)); + assertEquals(155197984, x &= (tmp = -2694712730.924674, tmp)); + assertEquals(155197984, x |= (x>>>(tmp = 69118015.20305443, tmp))); + assertEquals(155197984, x >>>= (((x^(-1353660241))*x)<<(((((x%(tmp = -1905584634, tmp))>>>(tmp = -860171244.5963638, tmp))&(-1084415001.7039547))+(x-(((tmp = 298064661, tmp)>>x)>>((tmp = 378629912.383446, tmp)-(x%x)))))+(((3212580683)/(((((x^x)>>(tmp = -1502887218, tmp))<<x)%(-142779025))|(((tmp = 1361745708, tmp)*(((((tmp = 1797072528.0673332, tmp)+x)%(tmp = 167297609, tmp))%(-287345856.1791787))^(((((((x*(tmp = -640510459.1514752, tmp))<<(x^(tmp = 1387982082.5646644, tmp)))>>(tmp = 2473373497.467914, tmp))^((234025940)*x))+(tmp = 520098202.9546956, tmp))*(x*(tmp = -362929250.1775775, tmp)))^(-2379972900))))*(tmp = -1385817972, tmp))))+(-1788631834))))); + assertEquals(0, x >>= ((tmp = -18671049, tmp)/((tmp = 651261550.6716013, tmp)>>(-58105114.70740628)))); + assertEquals(0, x *= ((((x>>(tmp = 2256492150.737681, tmp))<<(x<<(((-2738910707)&x)<<(1892428322))))*(tmp = 1547934638, tmp))>>((((319464033.7888391)|(((((tmp = 2705641070, tmp)<<((tmp = 1566904759.36666, tmp)*((-682175559.7540412)&(-691692016.3021002))))%(tmp = 1118101737, tmp))|(902774462))<<x))^((tmp = -388997180, tmp)<<(x<<((((((-88462733)+(x>>>x))%x)*(tmp = -20297481.556210756, tmp))>>>(1927423855.1719701))-((2047811185.6278129)-(tmp = 2952219346.72126, tmp))))))|(-1685518403.7513878)))); + assertEquals(0, x /= (tmp = 1858074757.563318, tmp)); + assertEquals(-1351623058, x ^= (-1351623058.4756806)); + assertEquals(1, x /= x); + assertEquals(0, x ^= x); + assertEquals(0, x -= (x&(997878144.9798675))); + assertEquals(-0, x /= (-2769731277)); + assertEquals(0, x >>>= ((-2598508325)>>(-1355571351))); + assertEquals(0, x >>>= x); + assertEquals(0, x -= (x&(tmp = 1672810223, tmp))); + assertEquals(-924449908.1999881, x -= (924449908.1999881)); + assertEquals(-0, x %= x); + assertEquals(-0, x /= (tmp = 2007131382.059545, tmp)); + assertEquals(-0, x += x); + assertEquals(225132064, x += ((((tmp = -2422670578.1260514, tmp)|x)+x)^(1660142894.7066057))); + assertEquals(Infinity, x /= (x-x)); + assertEquals(0, x ^= x); + assertEquals(0, x <<= x); + assertEquals(-2455424946.732606, x -= (2455424946.732606)); + assertEquals(1208029258, x &= ((tmp = 1823728509, tmp)+x)); + assertEquals(1.3682499724725645, x /= ((((tmp = 1267938464.3854322, tmp)%((tmp = 2510853574, tmp)+(((2979355693.866435)-(tmp = 1989726095.7746763, tmp))<<x)))%((-1382092141.1627176)+(((-901799353)+((-2936414080.8254457)>>>(2515004943.0865674)))-(2532799222.353197))))<<(tmp = -2168058960.2694826, tmp))); + assertEquals(0.13799826710735907, x %= ((-1090423235)/(tmp = 2659024727, tmp))); + assertEquals(0, x >>= (1688542889.082693)); + assertEquals(0, x <<= x); + assertEquals(NaN, x %= ((((tmp = 1461037539, tmp)<<((x<<(tmp = 2101282906.5302017, tmp))>>(-2792197742)))%(((x%x)^(((tmp = 1399565526, tmp)^(tmp = 643902, tmp))-((tmp = -1449543738, tmp)|x)))/x))*(x<<(471967867)))); + assertEquals(0, x &= ((tmp = -2121748100.6824129, tmp)>>(tmp = -2817271480.6497793, tmp))); + assertEquals(0, x &= (3169130964.6291866)); + assertEquals(-0, x /= (-2303316806)); + assertEquals(0, x <<= (tmp = 120185946.51617038, tmp)); + assertEquals(449448375, x ^= ((((tmp = -836410266.014014, tmp)/x)&((x>>>(tmp = -2602671283, tmp))+x))+(tmp = 449448375, tmp))); + assertEquals(202003841790140640, x *= x); + assertEquals(202003840800829020, x += (((tmp = -1339865843, tmp)+(tmp = 350554234.15375435, tmp))<<((((((tmp = -1798499687.8208885, tmp)>>(((x-(x^x))|((tmp = 463627396.23932934, tmp)/(2714928060)))&(tmp = 3048222568.1103754, tmp)))&(-3127578553))<<(tmp = -2569797028.8299003, tmp))&x)<<((tmp = 2104393646, tmp)/((tmp = 2314471015.742891, tmp)<<((2704090554.1746845)>>(((tmp = 1935999696, tmp)*(((1348554815)>>>x)>>>(146665093.82445252)))%x))))))); + assertEquals(202003841764125400, x -= (tmp = -963296372.2846234, tmp)); + assertEquals(-413485056, x <<= (tmp = -2474480506.6054573, tmp)); + assertEquals(-3171894580.186845, x += ((tmp = -1261111102, tmp)+(tmp = -1497298422.1868448, tmp))); + assertEquals(17136, x >>= (tmp = 3055058160, tmp)); + assertEquals(17136, x %= (tmp = 1706784063.3577294, tmp)); + assertEquals(17136, x >>= ((tmp = 2161213808, tmp)*x)); + assertEquals(-17136, x /= ((((tmp = -1492618154, tmp)>>x)|(1381949066))>>(tmp = 2014457960, tmp))); + assertEquals(-34272, x += x); + assertEquals(-1498690902, x += (-1498656630)); + assertEquals(-1168674482, x ^= (486325220)); + assertEquals(-1168674482, x <<= ((x^x)*x)); + assertEquals(794521557347068000, x *= (-679848469)); + assertEquals(1.3330392590424505e+26, x *= (tmp = 167778866, tmp)); + assertEquals(0, x <<= (tmp = -2501540637.3664584, tmp)); + assertEquals(0, x >>>= (x-(x*(-890638026.1825848)))); + assertEquals(0, x %= ((-285010538.2813468)&(1314684460.7634423))); + assertEquals(0, x -= x); + assertEquals(0, x *= x); + assertEquals(NaN, x %= (x*(x<<x))); + assertEquals(NaN, x %= (x<<(((tmp = -1763171810.601149, tmp)&(-138151449.18303752))^(x|x)))); + assertEquals(0, x |= (x>>x)); + assertEquals(0, x &= (tmp = 1107152048, tmp)); + assertEquals(0, x >>= (1489117056.8200984)); + assertEquals(518749976, x ^= (518749976.20107937)); + assertEquals(356718654, x += (tmp = -162031322, tmp)); + assertEquals(356718654, x %= (((x>>>((tmp = -373747439.09634733, tmp)*(tmp = 563665566, tmp)))*(tmp = 2853322586.588251, tmp))*((1303537213)%(-2995314284)))); + assertEquals(5573728, x >>= (tmp = -2095997978, tmp)); + assertEquals(5573728, x <<= x); + assertEquals(5573728, x >>= (((((tmp = 1745399178.334154, tmp)<<(tmp = 2647999783.8219824, tmp))^(tmp = 1571286759, tmp))%x)/(2166250345.181711))); + assertEquals(10886, x >>>= ((682837289)+(x*x))); + assertEquals(170, x >>>= x); + assertEquals(169.95167497151652, x -= (((tmp = 527356024.19706845, tmp)+((tmp = 1263164619.2954736, tmp)|(tmp = 2942471886, tmp)))/((3017909419.131321)+(tmp = 2137746252.8006272, tmp)))); + assertEquals(-1915170061, x ^= (tmp = -1915170214, tmp)); + assertEquals(206045792, x &= (((tmp = 887031922, tmp)>>>x)-((-1861922770)|(9633541)))); + assertEquals(-1940321674, x |= (tmp = -2012149162.1817405, tmp)); + assertEquals(-1940321674, x &= x); + assertEquals(1128412272.160699, x += (tmp = 3068733946.160699, tmp)); + assertEquals(0.47486363523180236, x /= (tmp = 2376286976.807289, tmp)); + assertEquals(-1.4931079540252477e-10, x /= (tmp = -3180370407.5892467, tmp)); + assertEquals(0, x |= (((1220765170.5933602)*(884017786))*((x%(tmp = -2538196897.226384, tmp))<<(x^x)))); + assertEquals(-525529894, x += (tmp = -525529894, tmp)); + assertEquals(1621426184, x &= ((3046517714)*(((((-162481040.8033898)+(x/((x&(1489724492))/((x|(tmp = 943542303, tmp))>>>((-1840491388.1365871)<<(2338177232))))))+(((-2268887573.2430763)>>>(((tmp = 2919141667, tmp)+((tmp = 1326295559.692003, tmp)<<(-2256653815)))>>>(((((tmp = 1602731976.7514615, tmp)*(856036244.3730336))^x)>>>((((2846316421.252943)&(915324162))%(tmp = 1144577211.0221815, tmp))%x))*(x*x))))%(tmp = -2641416560, tmp)))*(x+(x>>>x)))>>x))); + assertEquals(1621426184, x %= (tmp = 1898223948, tmp)); + assertEquals(-3.383396676504762, x /= ((tmp = 2211088034.5234556, tmp)^x)); + assertEquals(7120923705.122882, x *= (((((tmp = 2632382342.914504, tmp)/(-615440284.1762738))&(2162453853.6658797))<<(-849038082.5298986))|(tmp = -2104667110.5603983, tmp))); + assertEquals(-1469010887, x &= x); + assertEquals(850767635866964700, x *= (tmp = -579143179.5338116, tmp)); + assertEquals(0, x %= x); + assertEquals(-571457, x |= ((2849326490.8464212)|(tmp = 1450592063, tmp))); + assertEquals(-571457, x &= x); + assertEquals(-0.00018638416434019244, x /= (3066016912.021368)); + assertEquals(0, x <<= (2058262829)); + assertEquals(NaN, x %= ((x|((x%x)>>>x))%((tmp = -2970314895.6974382, tmp)+x))); + assertEquals(NaN, x *= (-698693934.9483855)); + assertEquals(NaN, x += (-100150720.64391875)); + assertEquals(NaN, x %= x); + assertEquals(NaN, x -= (-530301478)); + assertEquals(NaN, x /= (1507673244)); + assertEquals(0, x <<= (x%(tmp = 2977838420.857235, tmp))); + assertEquals(0, x <<= (tmp = 3200877763, tmp)); + assertEquals(0, x <<= (tmp = -2592127060, tmp)); + assertEquals(NaN, x -= (((((((1930632619)*(3018666359))<<((tmp = 2676511886, tmp)&(-2786714482.25468)))%x)-(-633193192))<<((tmp = 403293598, tmp)*(-2765170226)))%x)); + assertEquals(530062092, x |= (tmp = 530062092, tmp)); + assertEquals(129409, x >>>= x); + assertEquals(-152430382316341.78, x *= (-1177896300.229055)); + assertEquals(-304860764632683.56, x += x); + assertEquals(0, x ^= x); + assertEquals(0, x %= (tmp = -63071565.367660046, tmp)); + assertEquals(0, x &= ((((tmp = -1007464338, tmp)<<(x<<((x^(tmp = -726826835, tmp))|x)))>>>x)*(((tmp = 469293335.9161849, tmp)<<(((((tmp = 1035077379, tmp)*(tmp = -555174353.7567515, tmp))&(3109222796.8286266))-(((((x-(tmp = 1128900353.6650414, tmp))|(tmp = 3119921303, tmp))&((-1353827690)&(x%((-924615958)&x))))>>>x)+(tmp = 1167787910, tmp)))+x))%((605363594)>>(1784370958.269381))))); + assertEquals(0, x %= (2953812835.9781704)); + assertEquals(0, x -= x); + assertEquals(0, x <<= x); + assertEquals(-901209266, x += (-901209266)); + assertEquals(-901209266, x &= x); + assertEquals(404, x >>>= (-3195686249)); + assertEquals(824237108, x ^= (824237472)); + assertEquals(497790936.1853996, x /= ((tmp = 1253776028, tmp)/(757207285))); + assertEquals(497790936, x >>>= ((tmp = -2212598336, tmp)<<(x^(1335355792.9363852)))); + assertEquals(0, x %= x); + assertEquals(-2659887352.6415873, x += (tmp = -2659887352.6415873, tmp)); + assertEquals(1635079945, x |= ((x&(1234659380))>>((((tmp = 2694276886.979136, tmp)|x)^((tmp = 132795582, tmp)<<((-1089828902)>>>x)))<<((((tmp = -2098728613.0310376, tmp)<<(x/(tmp = -2253865599, tmp)))*((x+(x>>>((48633053.82579231)-(385301592))))*(tmp = -1847454853.333535, tmp)))/((-540428068.8583717)+x))))); + assertEquals(1, x /= x); + assertEquals(33554432, x <<= ((((2803140769)<<x)|(tmp = -1965793804, tmp))>>>(tmp = -2273336965.575082, tmp))); + assertEquals(67108864, x += x); + assertEquals(9007199254740992, x *= (x+((x>>x)%(2674760854)))); + assertEquals(55369784, x %= (x|(-170725544.20038843))); + assertEquals(55369784, x %= (-1186186787)); + assertEquals(0, x ^= x); + assertEquals(0, x <<= x); + assertEquals(NaN, x /= ((-2968110098)-((x/(x|(((((x|((x&((-130329882)>>>(((-135670650)|(x<<(tmp = 1280371822, tmp)))^x)))-(-1183024707.2230911)))&(-1072829280))>>>(-340696948.41492534))>>>(tmp = 436308526.4938295, tmp))<<(((tmp = 3113787500, tmp)*((2038309320)>>>(-1818917055)))&((2808000707)/(774731251))))))%x))); + assertEquals(0, x |= (x*(tmp = -843074864, tmp))); + assertEquals(0, x &= (tmp = -752261173.8090212, tmp)); + assertEquals(0, x >>>= (tmp = 1532349931.7517128, tmp)); + assertEquals(0, x <<= ((tmp = -8628768, tmp)-((((tmp = 225928543, tmp)%(x>>>(x+x)))^((tmp = -2051536806.5249376, tmp)-x))-((tmp = -2274310376.9964137, tmp)%(tmp = 2251342739, tmp))))); + assertEquals(0, x >>= (1011388449)); + assertEquals(0, x += x); + assertEquals(0, x >>>= x); + assertEquals(-0, x *= ((-1781234179.8663826)>>(((1514201119.9761915)>>(((((1174857164.90042)^(tmp = 1124973934, tmp))^x)+((-1059246013.8834443)<<(2997611138.4876065)))%(((798188010)*(-1428293122))>>>(tmp = -3087267036.8035297, tmp))))<<x))); + assertEquals(1752554372, x ^= (tmp = -2542412924, tmp)); + assertEquals(1752554372, x %= (tmp = 3037553410.2298307, tmp)); + assertEquals(1859383977, x -= (x^(2446603103))); + assertEquals(1183048193, x &= ((tmp = -962336957, tmp)/(x/x))); + assertEquals(67738157, x %= ((((tmp = -1813911745.5223546, tmp)+x)<<(x-(((-1980179168)^x)|x)))|(1913769561.1308007))); + assertEquals(67698724, x &= ((1801574998.3142045)*((tmp = -2057492249, tmp)/((1713854494.72282)>>x)))); + assertEquals(0, x -= x); + assertEquals(-25232836, x -= ((tmp = 25232836, tmp)|x)); + assertEquals(-49, x >>= (x+((tmp = 2201204630.2897243, tmp)|(-1929326509)))); + assertEquals(-1605632, x <<= x); + assertEquals(-165965313, x += (tmp = -164359681, tmp)); + assertEquals(9.220413724941365e-10, x /= (((((tmp = 2579760013.0808706, tmp)*(tmp = -2535370639.9805303, tmp))>>((tmp = 2138199747.0301933, tmp)-(tmp = -2698019325.0972376, tmp)))*(tmp = -425284716, tmp))/((-1951538149.6611228)/(x^(2632919130))))); + assertEquals(0, x &= x); + assertEquals(0, x &= ((-645189137)/(tmp = 800952748, tmp))); + assertEquals(0, x &= (tmp = -1773606925, tmp)); + assertEquals(0, x += x); + assertEquals(0, x >>>= (tmp = 211399355.0741787, tmp)); + assertEquals(0, x <<= ((-1317040231.5737965)/((((((tmp = 838897586.0147077, tmp)|((-1902447594)|(tmp = 404942728.83034873, tmp)))^(2462760692.2907705))%((((((x%(tmp = -2888980287, tmp))<<(-368505224.49609876))-((x>>>(532513369))&(((((((tmp = -1298067543, tmp)^(tmp = -3130435881.100909, tmp))>>x)/(tmp = -3041161992, tmp))>>(x|(-431685991.95776653)))^((tmp = 1031777777, tmp)^((-105610810)>>>((-631433779)>>(tmp = -2577780871.167671, tmp)))))%(tmp = -3170517650.088039, tmp))))-(((tmp = 2175146237.968785, tmp)-((384631158.50508535)>>((893912279.4646157)|(tmp = -1478803924.5338967, tmp))))%(x/(-1089156420))))<<(tmp = -2024709456, tmp))>>x))*(tmp = -1423824994.6993582, tmp))%(tmp = 1739143409, tmp)))); + assertEquals(-1799353648, x |= ((-1799353648.3589036)>>>((((x&(-923571640.1012449))%x)+((tmp = 971885508, tmp)>>((tmp = -2207464428.2123804, tmp)+(-3108177894.0459776))))-(-2048954486.7014258)))); + assertEquals(-3666808032.2958965, x -= (tmp = 1867454384.2958965, tmp)); + assertEquals(-260069478915415100, x *= (tmp = 70925305.23136711, tmp)); + assertEquals(1142096768, x &= (tmp = 1866401706.9144325, tmp)); + assertEquals(1, x >>>= (tmp = 2701377150.5717473, tmp)); + assertEquals(1865946805, x |= (tmp = -2429020492, tmp)); + assertEquals(1424222287, x ^= ((((tmp = 433781338, tmp)>>(x>>>((-2914418422.4829016)/(tmp = 1600920669, tmp))))|(tmp = 588320482.9566053, tmp))>>>((((((x+(tmp = -2556387365.5071325, tmp))+(tmp = -2381889946.1830974, tmp))/(3154278191))>>>(-1069701268.8022757))>>(((tmp = 182049089.28866422, tmp)>>x)>>>(tmp = -447146173, tmp)))/(x-(2103883357.0929923))))); + assertEquals(0, x ^= x); + assertEquals(0, x -= (x%(3036884806))); + assertEquals(0, x >>>= (tmp = -652793480.3870945, tmp)); + assertEquals(0, x += x); + assertEquals(304031003, x ^= ((tmp = -900156495, tmp)^(-666397014.0711515))); + assertEquals(1, x /= x); + assertEquals(-1974501681, x |= (x^(-1974501681.4628205))); + assertEquals(-1.3089278317616264, x /= (((-1723703186.962839)>>>x)|((2061022161.6239533)<<x))); + assertEquals(-1, x |= (tmp = -1987006457, tmp)); + assertEquals(-0.14285714285714285, x /= ((((((x|(-1767793799.7595732))-(-1391656680))<<x)|(x>>(tmp = -2301588485.2811003, tmp)))>>>(((tmp = 1812723993, tmp)>>>((x^(((tmp = -3154100157.951021, tmp)%((tmp = -1254955564.4553523, tmp)-(((x>>>(((-1762886343)*x)*x))*(x^(x*(-750918563.4387553))))*x)))|((x>>x)>>(x<<((((-1766797454.5634143)^(tmp = -2251474340, tmp))-(-787637516.5276759))<<((1390653368)^(-1937605249.245374)))))))|(((tmp = 1156611894, tmp)<<x)<<(x>>((((x+(tmp = 2170166060.881797, tmp))&(x>>>(tmp = -1749295923.1498983, tmp)))>>(((-1014973878)|x)&(1302866805.684057)))*(tmp = 560439074.4002491, tmp))))))|(-2758270803.4510045)))&x)); + assertEquals(0, x |= x); + assertEquals(0, x += ((x>>((x+(tmp = -2776680860.870219, tmp))-(((688502468)<<(((tmp = 475364260.57888806, tmp)<<x)+(329071671)))/(-1097134948))))*(tmp = -1281834214.3416953, tmp))); + assertEquals(0, x *= ((((1159762330)<<(tmp = -1892429200, tmp))%x)<<x)); + assertEquals(0, x >>>= (-770595225)); + assertEquals(NaN, x += (((x>>x)/(tmp = 281621135, tmp))/x)); + assertEquals(0, x >>= (1363890241)); + assertEquals(1639023942.9945002, x += (1639023942.9945002)); + assertEquals(-2568590958567747000, x *= (-1567146697)); + assertEquals(1793554700, x ^= (tmp = 3215813388.405799, tmp)); + assertEquals(437879, x >>= x); + assertEquals(1339485943, x |= (1339220210)); + assertEquals(1, x /= x); + assertEquals(512, x <<= (2509226729.1477118)); + assertEquals(512, x <<= ((x>>(1326274040.7181284))<<(tmp = -760670199, tmp))); + assertEquals(1, x /= (x<<(x^x))); + assertEquals(0, x >>>= (((((1382512625.8298302)&(x>>>x))*(tmp = -815316595, tmp))>>>x)-(-95538051))); + assertEquals(-544344229.3548596, x -= (tmp = 544344229.3548596, tmp)); + assertEquals(-1088688458.7097192, x += x); + assertEquals(-1022850479579041900, x *= (939525418.3104812)); + assertEquals(2069622661, x |= (-2632744187.7721186)); + assertEquals(-1353480538017756400, x -= ((tmp = 1308085980, tmp)*((x>>>(-629663391.5165792))&(tmp = 3182319856.674114, tmp)))); + assertEquals(1.3702811563654176e+27, x *= ((((3061414617.6321163)/(tmp = 2628865442, tmp))+(-1549548261))+(x&((tmp = 809684398, tmp)|(x^(tmp = 801765002, tmp)))))); + assertEquals(0, x >>>= ((-2988504159)&((tmp = -260444190.02252054, tmp)^(2178729442.260293)))); + assertEquals(-1518607002, x -= (tmp = 1518607002, tmp)); + assertEquals(724566016, x <<= (tmp = 1042915731.7055794, tmp)); + assertEquals(707584, x >>>= (-208959862.93305588)); + assertEquals(0, x >>>= (((tmp = 877181764, tmp)>>(-970697753.3318911))%x)); + assertEquals(0, x ^= x); + assertEquals(0, x += x); + assertEquals(0, x <<= x); + assertEquals(0, x /= (x^((x/(-2903618412.4936123))+(tmp = 1169288899, tmp)))); + assertEquals(0, x >>>= x); + assertEquals(-1302645245, x ^= ((1855892732.3544865)+(tmp = 1136429319.5633948, tmp))); + assertEquals(0, x ^= x); + assertEquals(0, x &= (-1384534597.409375)); + assertEquals(-0, x /= (tmp = -680466419.8289509, tmp)); + assertEquals(-0, x *= (318728599.95017374)); + assertEquals(NaN, x %= (x>>(2019695267))); + assertEquals(0, x >>= (tmp = 1280789995, tmp)); + assertEquals(0, x *= (tmp = 2336951458, tmp)); + assertEquals(0, x >>= ((2981466013.758637)%(731947033))); + assertEquals(0, x -= x); + assertEquals(0, x ^= x); + assertEquals(0, x /= ((((3068070149.1452317)>>x)%(((1448965452)*((tmp = -2961594129, tmp)+(1829082104.0681171)))>>(-2331499703)))>>>(tmp = -3206314941.2626476, tmp))); + assertEquals(0, x >>= (x%(1869217101.9823673))); + assertEquals(0, x <<= (x+x)); + assertEquals(0, x >>>= ((1202130282)>>>x)); + assertEquals(0, x += x); + assertEquals(2603245248.6273212, x += (tmp = 2603245248.6273212, tmp)); + assertEquals(-1691864471, x ^= (x>>>(2504513614.117516))); + assertEquals(136835305, x -= ((-1618979896)&(-746953306))); + assertEquals(-2568499564.1261334, x += (tmp = -2705334869.1261334, tmp)); + assertEquals(1038075700, x ^= (1530399136)); + assertEquals(2076151400, x += x); + assertEquals(-524018410.1751909, x -= ((2398973627.175191)-(-201196183))); + assertEquals(0.327110599608614, x /= ((3181340288.602796)&x)); + assertEquals(0.327110599608614, x %= (tmp = -2284484060, tmp)); + assertEquals(0, x |= x); + assertEquals(403217947.5779772, x += (tmp = 403217947.5779772, tmp)); + assertEquals(403217947, x |= x); + assertEquals(-Infinity, x *= ((58693583.845808744)+(((tmp = -1527787016, tmp)*x)/((((2532689893.3191843)/(tmp = 2781746479.850424, tmp))|(((((460850355.9211761)/((((tmp = 626683450, tmp)<<((tmp = 1349974710, tmp)-((tmp = -1349602292, tmp)/(-2199808871.1229663))))>>((x/(-3092436372.3078623))&(tmp = -1190631012.0323825, tmp)))^((-2907082828.4552956)-(tmp = 1858683340.1157017, tmp))))^(-1513755598.5398848))%x)/x))&(1147739260.136806))))); + assertEquals(0, x &= (tmp = -3047356844.109563, tmp)); + assertEquals(637934616, x -= (tmp = -637934616, tmp)); + assertEquals(-1553350083, x ^= (-2056266203.094929)); + assertEquals(-0.13467351026547192, x %= ((tmp = 824736251, tmp)/(2544186314))); + assertEquals(1, x /= x); + assertEquals(1, x |= x); + assertEquals(0, x >>>= (2166609431.9515543)); + assertEquals(0, x <<= (x|(tmp = 121899222.14603412, tmp))); + assertEquals(0, x *= (1300447849.6595674)); + assertEquals(0, x %= (tmp = -2360500865.3944597, tmp)); + assertEquals(0, x %= (tmp = -1693401247, tmp)); + assertEquals(0, x >>= x); + assertEquals(0, x /= (471265307)); + assertEquals(257349748, x ^= (257349748.689448)); + assertEquals(257349748, x &= x); + assertEquals(981, x >>>= (tmp = -1959001422, tmp)); + assertEquals(0, x >>= ((-79932778.18114972)/x)); + assertEquals(0, x <<= (((-2599621472)^(tmp = 662071103, tmp))%(tmp = -2675822640.7641535, tmp))); + assertEquals(0, x &= (tmp = 2582354953.878623, tmp)); + assertEquals(0, x /= ((-953254484)/((-2571632163.376176)-(tmp = -342034471, tmp)))); + assertEquals(0, x <<= ((x-(tmp = -3013057672, tmp))&(tmp = -3204761036, tmp))); + assertEquals(0, x ^= ((x&((515934453)>>>x))/x)); + assertEquals(1, x |= ((-1914707646.2075093)>>>(tmp = -1918045025, tmp))); + assertEquals(-2002844120.8792589, x += (tmp = -2002844121.8792589, tmp)); + assertEquals(573030794, x >>>= (tmp = 1707788162, tmp)); + assertEquals(1.917619109627369, x /= ((1909436830.484202)%((123114323)<<(tmp = -1288988388.6444468, tmp)))); + assertEquals(-1400358045, x |= (-1400358046)); + assertEquals(-2043022529.4273133, x += (tmp = -642664484.4273133, tmp)); + assertEquals(-81408068.86728716, x %= (tmp = -980807230.2800131, tmp)); + assertEquals(0.1436896445024992, x /= (((tmp = 3201789924.913518, tmp)%(tmp = -962242528.6008646, tmp))^((tmp = -338830119.55884504, tmp)*(tmp = -916120166, tmp)))); + assertEquals(0.1436896445024992, x %= (tmp = 2598469263, tmp)); + assertEquals(0, x *= (x-x)); + assertEquals(-1409286144, x += (((-111514798.64745283)|(2372059654))<<(tmp = 175644313, tmp))); + assertEquals(-2393905467.0073113, x += (-984619323.0073113)); + assertEquals(-835111172.0073113, x %= (x^(-765900532.5585573))); + assertEquals(-835111172.0073113, x %= (tmp = -946478116, tmp)); + assertEquals(-100, x >>= ((-1020515908)>>(((x&((x^(169474253.53811646))>>(-221739002)))+x)*((201939882.92880356)/(tmp = -50402570, tmp))))); + assertEquals(2131506964, x &= (tmp = -2163460268, tmp)); + assertEquals(1074275840, x &= ((-1561930379.8719592)*(tmp = -2871750052.876917, tmp))); + assertEquals(-954232605.5377102, x -= (tmp = 2028508445.5377102, tmp)); + assertEquals(-29, x >>= (-279577351.87217045)); + assertEquals(-232, x <<= x); + assertEquals(-70, x |= (215185578)); + assertEquals(-1, x >>= (x>>(-1691303095))); + assertEquals(1, x /= x); + assertEquals(3149465364.2236686, x *= (3149465364.2236686)); + assertEquals(3304787832.3790073, x += (tmp = 155322468.15533853, tmp)); + assertEquals(100068712.23500109, x %= (tmp = 3204719120.1440063, tmp)); + assertEquals(91628864, x &= (tmp = 629090241, tmp)); + assertEquals(-113202292046379710, x *= (-1235443583)); + assertEquals(122, x >>>= (tmp = 3196555256, tmp)); + assertEquals(122, x >>>= (((2226535734)-x)^(2248399036.393125))); + assertEquals(6.904199169070746e-8, x /= (tmp = 1767040564.9149356, tmp)); + assertEquals(-212687449.99999994, x += ((((2244322375)*(((2515994102)^x)>>x))<<(x-(-832407685.3251972)))^(2266670502))); + assertEquals(366515938514778750, x *= (tmp = -1723260768.3940866, tmp)); + assertEquals(366515938514778750, x += ((-1643386193.9159095)/(tmp = 425161225.95316494, tmp))); + assertEquals(654872716.4123061, x /= ((-1377382984)-(tmp = -1937058061.811642, tmp))); + assertEquals(654872716, x &= x); + assertEquals(-86260926.17813063, x -= (tmp = 741133642.1781306, tmp)); + assertEquals(1052176592, x >>>= x); + assertEquals(2020882856, x ^= (-3107796616)); + assertEquals(0, x <<= ((606939871.9812952)|(tmp = -3127138319.1557302, tmp))); + assertEquals(NaN, x -= ((x%((1120711400.2242608)%x))*(tmp = -930171286.7999947, tmp))); + assertEquals(NaN, x %= (3215044180)); + assertEquals(NaN, x %= (tmp = 2882893804.20102, tmp)); + assertEquals(NaN, x %= ((217170359.5778643)^x)); + assertEquals(0, x &= ((-1095125960.9903677)>>(x^(-2227981276)))); + assertEquals(-748549860, x += (-748549860)); + assertEquals(1816208256, x <<= (-610872411.3826082)); + assertEquals(201400576, x &= (((tmp = 1910394603.4836266, tmp)<<x)^x)); + assertEquals(0, x %= x); + assertEquals(NaN, x %= x); + assertEquals(0, x <<= (((((2670901339.6696005)%(2180020861))*((2134469504)/(2237096063.0680027)))*((tmp = 1203829756, tmp)>>((765467065)+(x|(2673651811.9494815)))))<<((-1463378514)|(((x/(tmp = -1075050081, tmp))-((-879974865)+x))>>>(tmp = 2172883926, tmp))))); + assertEquals(433013198, x ^= (433013198.2833413)); + assertEquals(0, x >>= ((((-2404431196)%(x%(tmp = 1443152875.8809233, tmp)))&(x|((1414364997.0517852)/((tmp = -435854369, tmp)+(tmp = 2737625141, tmp)))))|(((tmp = 2241746562.2197237, tmp)^(tmp = -1606928010.1992552, tmp))|((tmp = -3083227418.686173, tmp)>>(tmp = -2717460410, tmp))))); + assertEquals(0, x >>= x); + assertEquals(0, x *= ((tmp = 2302521322, tmp)>>>(((((((tmp = 344089066.9725498, tmp)%(tmp = 1765830559, tmp))-x)|x)^(((-2450263325)/(tmp = 371928405.17475057, tmp))>>>(1330100413.7731652)))^(((173024329)%(tmp = -2927276187, tmp))+(x>>>(-1042229940.308507))))|(((((tmp = 379074096, tmp)+((142762508)-((-2773070834.526266)-(x&((tmp = 57957493, tmp)<<(2189553500))))))+((36991093)+(tmp = 339487168.58069587, tmp)))*(-1257565451))&(tmp = 645233114, tmp))))); + assertEquals(-2644503151.1185284, x += (-2644503151.1185284)); + assertEquals(-5289006302.237057, x += x); + assertEquals(-4008773824.2370567, x -= (tmp = -1280232478, tmp)); + assertEquals(1975449413, x |= ((tmp = 1957832005.4285066, tmp)>>((1681236712.9715524)&(-675823978)))); + assertEquals(-146472960, x <<= (-648510672.5644083)); + assertEquals(-3, x |= (((((x>>>(tmp = 2271744104, tmp))+(tmp = -210058133.30147195, tmp))+(tmp = -2827493425, tmp))/(tmp = 765962538, tmp))%(tmp = 1048631551, tmp))); + assertEquals(1, x /= x); + assertEquals(0, x >>= (1070524782.5154183)); + assertEquals(0, x <<= (462502504)); + assertEquals(0, x %= (540589670.0730014)); + assertEquals(NaN, x %= x); + assertEquals(NaN, x /= ((-1268640098)%x)); + assertEquals(NaN, x %= (1741157613.744652)); + assertEquals(NaN, x += x); + assertEquals(NaN, x %= ((x|(tmp = 1992323492.7000637, tmp))*x)); + assertEquals(NaN, x /= ((tmp = -2271503368.0341196, tmp)>>((tmp = 1224449194, tmp)>>>(tmp = 2976803997, tmp)))); + assertEquals(NaN, x += (tmp = -1078313742.1633894, tmp)); + assertEquals(NaN, x += (-787923311)); + assertEquals(NaN, x %= x); + assertEquals(-1299878219, x ^= (2995089077)); + assertEquals(536887953, x &= ((625660571.2651105)&(x^(((tmp = 950150725.2319129, tmp)+(-2122154205.466675))/(tmp = 1754964696.974752, tmp))))); + assertEquals(4096, x >>>= x); + assertEquals(1, x /= x); + assertEquals(-82508517, x ^= (((-930231800)%(tmp = -423861640.4356506, tmp))+x)); + assertEquals(-82508517, x &= (x&x)); + assertEquals(-479519, x %= ((tmp = 1861364600.595756, tmp)|x)); + assertEquals(479518, x ^= (((x>>(-1539139751.6860313))>>(tmp = -456165734, tmp))|(-2786433531))); + assertEquals(959036, x += x); + assertEquals(29, x >>>= ((tmp = -1049329009.7632706, tmp)^(((((((1117739997)/(((-841179741.4939663)*(-1211599672))>>>((-413696355)%(tmp = -1753423217.2170188, tmp))))<<(tmp = 1599076219.09274, tmp))>>>(-1382960317))^(((x^(tmp = 515115394, tmp))>>>(tmp = -388476217, tmp))>>>(x/x)))^x)<<(136327532.213817)))); + assertEquals(24, x &= (2388755418)); + assertEquals(0, x >>>= (tmp = -405535917, tmp)); + assertEquals(0, x &= (tmp = -1427139674, tmp)); + assertEquals(NaN, x /= (x^((1530470340)%x))); + assertEquals(0, x |= ((x>>(-1429690909.8472774))*((((tmp = 2033516515, tmp)/(1314782862))>>>x)>>(tmp = 1737186497.6441216, tmp)))); + assertEquals(0, x -= x); + assertEquals(0, x %= (3115422786)); + assertEquals(-0, x *= (x+(tmp = -2558930842.267017, tmp))); + assertEquals(NaN, x %= x); + assertEquals(0, x &= (2695531252.254449)); + assertEquals(-613178182, x ^= (-613178182)); + assertEquals(54, x >>>= (x%(((tmp = 2277868389, tmp)^((((tmp = -1143932265.3616111, tmp)^((x&((x-((-2100384445.7850044)|(tmp = 908075129.3456883, tmp)))*x))+(((tmp = 1031013284.0275401, tmp)*((((tmp = -233393205, tmp)>>>(tmp = -111859419, tmp))*(-1199307178))|(tmp = -1998399599, tmp)))>>>((((-731759641.9036775)>>>(tmp = 2147849691, tmp))>>>(tmp = -2121899736, tmp))>>>(x>>>x)))))>>((1900348757.360562)^(tmp = 2726336203.6149445, tmp)))>>>((x*((tmp = -2697628471.0234947, tmp)%((x^(tmp = -2751379613.9474974, tmp))*x)))+(x>>(tmp = 42868998.384643435, tmp)))))+(598988941)))); + assertEquals(34, x &= ((tmp = 2736218794.4991407, tmp)%(2169273288.1339874))); + assertEquals(2.086197133417468, x /= ((tmp = 2176358852.297597, tmp)%x)); + assertEquals(2, x <<= (((tmp = -1767330075, tmp)|(-3107230779.8512735))&x)); + assertEquals(4194304, x <<= (tmp = 1061841749.105744, tmp)); + assertEquals(48609515, x ^= (44415211.320786595)); + assertEquals(48609515, x %= (1308576139)); + assertEquals(23735, x >>>= ((-324667786)-x)); + assertEquals(23735, x <<= ((-1270911229)<<(((((tmp = -882992909.2692418, tmp)+(tmp = 394833767.947718, tmp))-x)<<(702856751))/x))); + assertEquals(-31080872939240, x *= (tmp = -1309495384, tmp)); + assertEquals(-14625.31935626114, x /= ((668084131)+(1457057357))); + assertEquals(-14625.31935626114, x %= (266351304.6585492)); + assertEquals(-12577, x |= (-945583977.619837)); + assertEquals(-4097, x |= ((tmp = -2621808583.2322493, tmp)-(tmp = -2219802863.9072213, tmp))); + assertEquals(-1004843865, x &= ((-1004839768)+((tmp = 2094772311, tmp)/(-1340720370.275643)))); + assertEquals(-31401371, x >>= ((2035921047)>>>((tmp = -1756995278, tmp)>>>(-537713689)))); + assertEquals(1791746374.016472, x -= ((tmp = -1823147745, tmp)-(x/(tmp = -1906333520, tmp)))); + assertEquals(3.7289343120517406, x /= (tmp = 480498240, tmp)); + assertEquals(7.457868624103481, x += x); + assertEquals(234881024, x <<= (-781128807.2532628)); + assertEquals(67108864, x &= (tmp = -2060391332, tmp)); + assertEquals(-605958718, x -= (673067582)); + assertEquals(-605958718, x <<= ((x%x)&((tmp = 1350579401.0801518, tmp)|x))); + assertEquals(-109268090.4715271, x %= (tmp = -496690627.5284729, tmp)); + assertEquals(-109268090, x <<= (((-2004197436.8023896)%((x|((tmp = 271117765.61283946, tmp)-((1595775845.0754795)*(555248692.2512416))))/x))<<x)); + assertEquals(-652725370, x &= (-543590449)); + assertEquals(0.321858133298825, x /= (tmp = -2027990914.2267523, tmp)); + assertEquals(1959498446, x ^= (1959498446)); + assertEquals(1959498446, x &= (x%(tmp = 3155552362.973523, tmp))); + assertEquals(14949, x >>>= ((tmp = 586618136, tmp)>>>(tmp = 699144121.9458897, tmp))); + assertEquals(-28611391568319.285, x *= (tmp = -1913933478.3811147, tmp)); + assertEquals(1680557633, x &= (((tmp = 2606436319.199714, tmp)<<(1575299025.6917372))|((-1092689109)/(735420388)))); + assertEquals(1680361024, x &= ((tmp = 1860756552.2186172, tmp)|(-360434860.1699109))); + assertEquals(820488, x >>>= (1788658731)); + assertEquals(820488, x >>= (-1555444352)); + assertEquals(2104296413, x ^= (2103543509)); + assertEquals(16843328, x &= ((x<<((-2920883149)/(1299091676)))-(((((tmp = 3199460211, tmp)+(-237287821.61504316))&(tmp = -1524515028.3596857, tmp))-(tmp = -700644414.6785603, tmp))+(-180715428.86124516)))); + assertEquals(1326969834, x |= (tmp = -2968063574.793867, tmp)); + assertEquals(0, x %= (x>>>(tmp = 1350490461.0012388, tmp))); + assertEquals(0, x &= ((-2620439260.902854)+x)); + assertEquals(-1775533561, x |= ((-1775533561)|(((x>>>((861896808.2264911)>>>(970216466.6532537)))%x)%(tmp = 2007357223.8893046, tmp)))); + assertEquals(-1775533561, x &= x); + assertEquals(-23058877.415584415, x /= ((tmp = -3002439857, tmp)>>((((x-(tmp = 1583620685.137125, tmp))|x)%(-2568798248.6863875))^x))); + assertEquals(-577.4155844151974, x %= (((-1440361053.047877)+((tmp = 821546785.0910633, tmp)-(((tmp = 1023830881.1444875, tmp)/(-754884477))+(tmp = 651938896.6258571, tmp))))>>(tmp = 346467413.8959185, tmp))); + assertEquals(-1, x >>= (tmp = 2993867511, tmp)); + assertEquals(-1, x |= (tmp = 823150253.4916545, tmp)); + assertEquals(-0, x %= x); + assertEquals(-0, x /= ((tmp = 997969036, tmp)&((((tmp = 928480121, tmp)>>(((-2610875857.086055)>>>(tmp = -2251704283, tmp))|x))+(10781750))>>x))); + assertEquals(0, x >>>= ((tmp = -1872319523, tmp)>>>(-278173884))); + assertEquals(0, x |= (x/(x*x))); + assertEquals(0, x %= ((77912826.10575807)^(tmp = 2770214585.3019757, tmp))); + assertEquals(0, x &= (tmp = 722275824, tmp)); + assertEquals(-1417226266, x |= (tmp = 2877741030.1195555, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x %= (tmp = -1740126105, tmp)); + assertEquals(910709964, x |= (tmp = 910709964, tmp)); + assertEquals(-1744830464, x <<= (tmp = -2445932551.1762686, tmp)); + assertEquals(318767104, x >>>= (tmp = -2465332061.628887, tmp)); + assertEquals(301989888, x &= (-2771167302.022801)); + assertEquals(301989888, x |= x); + assertEquals(37748736, x >>= (tmp = -835820125, tmp)); + assertEquals(1474977371, x ^= (tmp = -2857738661.6610327, tmp)); + assertEquals(470467500, x += (-1004509871)); + assertEquals(0.30466562575942585, x /= (((tmp = 1515955042, tmp)<<(x+((1607647367)-(tmp = 1427642709.697169, tmp))))^x)); + assertEquals(1.0348231148499734e-10, x /= (tmp = 2944132397, tmp)); + assertEquals(0, x >>= (x>>>(tmp = -2847037519.569043, tmp))); + assertEquals(NaN, x /= x); + assertEquals(0, x >>>= (-1817784819.9058492)); + assertEquals(0, x >>= x); + assertEquals(-0, x *= ((tmp = -1387748473, tmp)|(x+(352432111)))); + assertEquals(-0, x *= (((-2591789329)/(tmp = -2144460203, tmp))>>(tmp = -568837912.5033123, tmp))); + assertEquals(0, x <<= (-2963600437.305708)); + assertEquals(0, x &= ((588720662)>>>x)); + assertEquals(1561910729, x += (1561910729)); + assertEquals(0, x ^= x); + assertEquals(-0, x *= (-2722445702)); + assertEquals(0, x &= (tmp = -2738643199.732308, tmp)); + assertEquals(0, x /= (((1859901899.227291)>>>((tmp = -1067365693, tmp)+((-1975435278)|x)))|((1844023313.3719304)&(tmp = -624215417.0227654, tmp)))); + assertEquals(NaN, x %= x); + assertEquals(NaN, x %= (-2852766277)); + assertEquals(0, x <<= (-1482859558)); + assertEquals(0, x >>= x); + assertEquals(-1196775786, x += (tmp = -1196775786, tmp)); + assertEquals(-68176201, x |= ((tmp = 2336517643, tmp)+x)); + assertEquals(0, x ^= x); + assertEquals(0, x <<= x); + assertEquals(0, x >>= (2969141362.868086)); + assertEquals(NaN, x %= x); + assertEquals(0, x >>= ((x-((((tmp = -905994835, tmp)|(tmp = 2850569869.33876, tmp))<<((-2405056608.27147)>>(tmp = 1280271785, tmp)))&(-1942926558)))*(tmp = 707499803.177796, tmp))); + assertEquals(0, x &= ((-697565829.8780258)+((2978584888.549406)%x))); + assertEquals(0, x >>= (748642824.4181392)); + assertEquals(0, x += x); + assertEquals(0, x >>>= (-1701028721)); + assertEquals(92042539, x -= ((-92042539)|(x*(x%(-293705541.00228095))))); + assertEquals(0, x %= x); + assertEquals(0, x >>= x); + assertEquals(0, x %= (-2278672472.458228)); + assertEquals(0, x %= (((-2374117528.0359464)/((tmp = -2809986062, tmp)|(tmp = 895734980, tmp)))&(tmp = 1564711307.41494, tmp))); + assertEquals(0, x >>>= x); + assertEquals(0, x += x); + assertEquals(-0, x /= ((tmp = -2749286790.3666043, tmp)<<(x^(-2966741582.324482)))); + assertEquals(0, x *= x); + assertEquals(0, x >>>= x); + assertEquals(-1882562314, x ^= (2412404982.782115)); + assertEquals(-806620, x %= (((tmp = 1527219936.5232096, tmp)*(-1139841417))>>>(tmp = 201632907.3236668, tmp))); + assertEquals(-1613240, x += x); + assertEquals(-1664766177387640, x *= (1031939561)); + assertEquals(-9.478083550117849e+23, x *= (tmp = 569334221.1571662, tmp)); + assertEquals(-8.462574598319509e+21, x /= ((x-(tmp = -2985531211.114498, tmp))>>(tmp = 174615992.91117632, tmp))); + assertEquals(1638924288, x <<= (((((x>>((-1823401733.4788911)+((tmp = 1362371590, tmp)>>>x)))^(tmp = -56634380, tmp))/(tmp = 2387980757.1540084, tmp))%((((tmp = -3175469977, tmp)^(tmp = -1816794042, tmp))+(232726694))*(tmp = 822706176, tmp)))/(tmp = 1466729893.836311, tmp))); + assertEquals(2686072821796307000, x *= x); + assertEquals(-1007977445.9812208, x /= (-2664814408.800125)); + assertEquals(-1007977445, x &= x); + assertEquals(322314656346249100, x *= (tmp = -319763758.54942775, tmp)); + assertEquals(197436885.26815608, x /= (tmp = 1632494637, tmp)); + assertEquals(-67191339, x |= ((-399580815.1746769)/((1335558363)/(tmp = 224694526, tmp)))); + assertEquals(1229588737, x &= (tmp = 1296763683.5732255, tmp)); + assertEquals(1229588737, x -= ((((1171546503)|((tmp = -2701891308, tmp)%(-2155432197.022206)))/(-306122816.85682726))>>x)); + assertEquals(4162606632, x -= (tmp = -2933017895, tmp)); + assertEquals(1.6487311395551163, x /= (2524733434.1748486)); + assertEquals(-1929308648.9913044, x += (-1929308650.6400356)); + assertEquals(-3858617297.982609, x += x); + assertEquals(788529152, x <<= (x^(1401824663))); + assertEquals(6160384, x >>>= ((((((x>>>x)>>((((x*(tmp = -1958877151, tmp))>>>(1310891043))-(tmp = 564909413.9962088, tmp))%(-175978438)))%x)|((tmp = -1193552419.7837512, tmp)*(tmp = 1508330424.9068346, tmp)))|(1428324616.3303494))-((1828673751)/(tmp = 1281364779, tmp)))); + assertEquals(6160384, x |= x); + assertEquals(1, x /= x); + assertEquals(1, x &= (tmp = -855689741, tmp)); + assertEquals(0, x >>>= x); + assertEquals(-1088569655.3528988, x -= (tmp = 1088569655.3528988, tmp)); + assertEquals(-1088569655, x >>= ((tmp = 2429646226.626727, tmp)<<((-1539293782.4487276)>>(x^((tmp = 1140855945.537702, tmp)+x))))); + assertEquals(-311, x %= ((x/x)<<x)); + assertEquals(1.2007722007722008, x /= (x|(tmp = 448796341.87655175, tmp))); + assertEquals(3, x |= (x+x)); + assertEquals(-9.32416092168023e-10, x /= (-3217447688)); + assertEquals(0, x >>= (615837464.0921166)); + assertEquals(0, x >>>= (tmp = -2993750670.683118, tmp)); + assertEquals(0, x >>>= (x%x)); + assertEquals(1610612736, x ^= ((-1322905256.6770213)<<(-2567950598))); + assertEquals(1693676493, x ^= (83063757.63660407)); + assertEquals(-758030371, x ^= (tmp = -1239274480, tmp)); + assertEquals(-758030371, x %= (tmp = 1961339006, tmp)); + assertEquals(-1509754528, x ^= (tmp = 1960027837, tmp)); + assertEquals(-1509754528, x <<= x); + assertEquals(-1509754528, x -= (((tmp = -50690205.33559728, tmp)/((tmp = -1364565380, tmp)<<(tmp = 2585052504, tmp)))<<(tmp = -2356889596, tmp))); + assertEquals(1, x >>>= (-3204164321)); + assertEquals(1, x *= x); + assertEquals(1114370230.591965, x *= ((tmp = 1114370229.591965, tmp)+x)); + assertEquals(-4.886305275432552, x /= ((-228059887.33344483)%(2841553631.3685856))); + assertEquals(2.358309397373389e-9, x /= (((x*(tmp = 203428818.08174622, tmp))&(x-(((510438355)*x)+x)))+x)); + assertEquals(0, x >>>= ((tmp = 1444810010, tmp)&(tmp = -3135701995.2235208, tmp))); + assertEquals(0, x /= (1865982928.6819582)); + assertEquals(0, x *= x); + assertEquals(2078726016.3772051, x -= (tmp = -2078726016.3772051, tmp)); + assertEquals(1580337898, x ^= ((tmp = -2714629398.447015, tmp)^x)); + assertEquals(1268363034, x -= ((x+((tmp = 1144068248.3834887, tmp)&(-954104940.155973)))<<(tmp = 1270573731.7828264, tmp))); + assertEquals(1744830464, x <<= (((1444869551.7830744)>>>((((x+(tmp = -904688528, tmp))<<x)-((tmp = 121151912.85873199, tmp)/(tmp = -2414150217.66479, tmp)))|(((-472906698)|(3215236833.8417764))+(907737193.9056952))))-((x&(-732223723))|(-221800427.7392578)))); + assertEquals(717338523283226600, x *= (x^(tmp = -2407450097.0604715, tmp))); + assertEquals(402653184, x >>= ((-3191405201.168252)*((tmp = -1941299639.695196, tmp)|(((x>>(((3215741220)>>>x)/(x+x)))^(((tmp = -2144862025.9842231, tmp)|((tmp = -1966913385, tmp)&x))%x))*((tmp = -1124749626.6112225, tmp)/(tmp = 837842574, tmp)))))); + assertEquals(402653184, x &= ((x|x)>>x)); + assertEquals(134217728, x &= ((2720231644.3849487)*x)); + assertEquals(134217726.75839183, x -= ((2438054684.738043)/(((((-984359711)*(x|((tmp = 177559682, tmp)^x)))/(-1253443505))/((2727868438.416792)*(x+((x<<(((tmp = 3023774345, tmp)&(-705699616.0846889))/x))<<x))))^(1963626488.548761)))); + assertEquals(1, x /= x); + assertEquals(245781494, x += ((tmp = 2551445099, tmp)^(2528486814))); + assertEquals(-1474427807, x ^= (-1497868393.342241)); + assertEquals(-1057271682, x += ((((((x>>x)%(-1556081693))|(x/(((1166243186.6325684)-(((tmp = 2870118257.1019487, tmp)/(x+(-69909960)))^(2270610694.671496)))/((1463187204.5849519)-x))))-x)-(x<<(-3077313003)))%x)); + assertEquals(-1065725846, x &= ((tmp = -1808223767, tmp)|(-481628214.3871765))); + assertEquals(-1065725846, x ^= (x&(((tmp = -1785170598, tmp)-(tmp = -2525350446.346484, tmp))/((((((-1783948056)^(tmp = 3027265884.41588, tmp))|((((tmp = 2195362566.2237773, tmp)<<(-2919444619))<<((tmp = -2507253075.2897573, tmp)^(x^((tmp = 1067516137, tmp)+((667737752)^(x*(tmp = -1187604212.7293758, tmp)))))))%(-617406719.5140038)))*(tmp = 511060465.6632478, tmp))*((tmp = 2580189800.752836, tmp)|((((tmp = 2357895660, tmp)%((-814381220)*(x-((x>>>(((x<<x)<<(tmp = 1919573020, tmp))-x))>>>((-2756011312.136148)>>(tmp = -1603458856, tmp))))))/((tmp = -1609199312, tmp)&(-3127643445)))%x)))<<(-2261731798))))); + assertEquals(1.6020307924030301, x /= (tmp = -665234308.2628405, tmp)); + assertEquals(-1120020556.697667, x *= (tmp = -699125486.2321637, tmp)); + assertEquals(-215875188, x -= (((((tmp = -1307845034, tmp)>>>((((-2820720421)^x)-(((x<<x)|(tmp = -3042092997.57406, tmp))+(((-1294857544)+((tmp = -668029108.1487186, tmp)>>(x<<x)))^(912144065.5274727))))^(389671596.2983854)))|(-2774264897.146559))%(x-((tmp = 1378085269, tmp)^x)))+((-1659377450.5247462)&(((1613063452.834885)>>>((-344896580.0694165)>>>((-13450558)+x)))^x)))); + assertEquals(1, x /= x); + assertEquals(0, x >>>= (2355750790)); + assertEquals(1969435421.4409347, x += (1969435421.4409347)); + assertEquals(0, x -= x); + assertEquals(0, x >>>= (((x*((-1022802960.6953495)<<(tmp = -2848428731.8339424, tmp)))^(-1630921485))%(1532937011))); + assertEquals(0, x <<= ((x+((x^(x^(tmp = 2017651860, tmp)))&(((x<<(((tmp = -1913317290.8189478, tmp)|(x-((((x%((tmp = -3035245210, tmp)+(-2270863807)))>>>((-2351852712)*(x^(-2422943296.0239563))))&((((-1578312517)%x)*x)*(-65592270.28452802)))>>>(tmp = 1104329727.2094703, tmp))))-(tmp = -1431159990.3340137, tmp)))&x)|((tmp = -2589292678.801344, tmp)&(x+((((tmp = -2557773457.456996, tmp)>>(451910805.309445))-x)>>(((tmp = -1937832765.7654495, tmp)^x)%x)))))))%x)); + assertEquals(0, x %= (tmp = -626944459, tmp)); + assertEquals(-732310021, x |= (tmp = -732310021, tmp)); + assertEquals(-732310021, x |= x); + assertEquals(671352839, x ^= (x-((-3087309090.7153115)|x))); + assertEquals(134479872, x &= (tmp = 2357183984, tmp)); + assertEquals(18084835973136384, x *= x); + assertEquals(0, x <<= ((1040482277)-(tmp = -357113781.82650447, tmp))); + assertEquals(74957, x |= ((((tmp = -70789345.7489841, tmp)%(tmp = 1415750131, tmp))&x)|((307027314)>>(2284275468)))); + assertEquals(9, x >>>= x); + assertEquals(0, x &= (x&((x*((x*(x%x))%(x>>x)))/x))); + assertEquals(-1872875060, x |= (2422092236.6850452)); + assertEquals(9, x >>>= (-382763684)); + assertEquals(4608, x <<= x); + assertEquals(40.480234260614935, x /= (((((((tmp = 814638767.5666755, tmp)&((tmp = 2081507162, tmp)^(x>>>(1460148331.2229118))))&(tmp = 1187669197.7318723, tmp))<<(412000677.93339765))^((tmp = 556111951, tmp)>>(tmp = -2232569601.292395, tmp)))&(-3006386864))/x)); + assertEquals(32, x &= (-3053435209.383913)); + assertEquals(418357217, x ^= (418357185)); + assertEquals(204275, x >>= ((-1188650337.9010527)^((51494580)%(-2544545273)))); + assertEquals(982392804, x += (((x+(((tmp = -982596937.9757051, tmp)+x)%(-2298479347)))^((((tmp = 1610297674.0732534, tmp)>>>x)*(((x>>(-2746780903.08599))&(-2376190704.247188))^(((20545353)/(tmp = 1468302977, tmp))-(x<<x))))>>(((-1434332028.0447056)/((tmp = 1983686888, tmp)&((tmp = 2324500847, tmp)%(394330230.6163173))))%(((-1129687479.2158055)+((-3127595161)*((-3066570223)&((tmp = 3192134577.4963055, tmp)/(-2697915283.3233275)))))+(-1112243977.5306559)))))|(x&(-2622725228)))); + assertEquals(-2735750653096133600, x *= (-2784782870.9218984)); + assertEquals(-1876329472, x |= ((((((2752866171)<<(-1681590319))/x)>>((tmp = 1451415208, tmp)>>>(1126858636.6634417)))+(((tmp = 2165569430.4844217, tmp)/x)^(((tmp = -1675421843.4364457, tmp)-(-2187743422.2866993))|x)))*x)); + assertEquals(3520612287495799000, x *= x); + assertEquals(-200278016, x |= ((((-2379590931)%((((-1558827450.833285)&x)>>(-665140792))-((tmp = -445783631.05567217, tmp)+(tmp = 93938389.53113222, tmp))))/(3103476273.734701))^x)); + assertEquals(-9178285062592.75, x *= ((2042671875.7211144)%(((tmp = 589269308.0452716, tmp)/x)<<(-130695915.9934752)))); + assertEquals(60048960, x |= (x<<x)); + assertEquals(60048960, x <<= ((((((tmp = -2793966650, tmp)/(-2882180652))&(((x<<((tmp = -384468710, tmp)+(2236162820.9930468)))>>>((((969371919)>>((tmp = -3153268403.2565875, tmp)-((((573811084)/x)^(tmp = -968372697.4844134, tmp))>>>(((-3096129189)>>x)/(tmp = 830228804.6249363, tmp)))))<<(((1243972633.3592157)|x)&((-1687610429)&(tmp = -1945063977.458529, tmp))))<<(((tmp = -217456781.37068868, tmp)-(400259171.68077815))^x)))>>>x))%(((2728450651.300167)/(((-2713666705.089135)%(tmp = 740472459, tmp))^x))|x))^x)*(-2463032364))); + assertEquals(60048960, x %= (tmp = -442107222.9513445, tmp)); + assertEquals(-1573781504, x <<= (960581227)); + assertEquals(1297, x >>>= (tmp = -1692919563, tmp)); + assertEquals(1297, x &= x); + assertEquals(-3113308397155.233, x *= (tmp = -2400391979.3024154, tmp)); + assertEquals(-3115513013486.233, x -= (2204616331)); + assertEquals(-3113809649082.233, x -= (-1703364404)); + assertEquals(0, x >>>= (((-1181206665)-(550946816.586771))|(tmp = -2346300456, tmp))); + assertEquals(0, x %= (tmp = 1649529739.2785435, tmp)); + assertEquals(0, x ^= ((tmp = -2452761827.2870226, tmp)%(((1090281070.5550141)/(tmp = 992149154.6500508, tmp))*(x<<((((((x>>>x)|((tmp = -2410892363, tmp)%(tmp = 2585150431.0231533, tmp)))/x)*(tmp = 1541294271, tmp))+x)&((97566561.77126992)&((((-640933510.1287451)&(((((x>>>((-1821077041)<<((tmp = -1138504062.093695, tmp)-(tmp = -181292160, tmp))))%x)-(x>>((x&(((tmp = 1067551355, tmp)/(x|(1004837864.8550552)))&(x-(-103229639.25084043))))&((tmp = 2064184671.210937, tmp)+((((tmp = -2245728052, tmp)|(1538407002.8365717))+(x<<((x>>((76549490)/(tmp = 628901902.6084052, tmp)))<<((x<<x)^(-1907669184)))))+(-1409123688))))))>>>((((-1911547456.933543)-((-512313175)+((tmp = -2620903017, tmp)^(tmp = 2148757592.244808, tmp))))<<((-1740876865)>>>x))+((tmp = 691314720.9488736, tmp)<<(614057604.4104803))))|(x^((tmp = -3040687.291528702, tmp)/(x^(((x+(-2899641915))^((tmp = -1220211746, tmp)/x))%x))))))^(tmp = 119850608, tmp))%(2091975696)))))))); + assertEquals(291273239, x -= (tmp = -291273239, tmp)); + assertEquals(2206394018, x += (1915120779)); + assertEquals(235641480, x <<= (x&(x&(-1810963865.1415658)))); + assertEquals(28764, x >>= ((tmp = -1927011875, tmp)^((tmp = -1986461808, tmp)|((-868139264.8399222)*((421956566)%(3068424525)))))); + assertEquals(-99780626900900, x *= ((tmp = -1512869526.3223472, tmp)+(tmp = -1956071751, tmp))); + assertEquals(51218520, x &= (((-2353401311)>>>x)-(2216842509))); + assertEquals(51218520, x >>>= ((tmp = -1534539302.6990812, tmp)<<x)); + assertEquals(-2147483648, x <<= (-292608644)); + assertEquals(-2147483648, x |= ((((((x<<((-2981292735)-x))>>((tmp = 2540545320.96558, tmp)&(tmp = -2343790880, tmp)))>>>((((((x^((-172697043.94487858)/((2627260337)>>(2879112814.1247935))))&(tmp = 3000943191, tmp))<<(tmp = 1094830905, tmp))-x)>>>x)>>((((tmp = 3095796200, tmp)^(x|(tmp = 1460377694, tmp)))<<(x^(tmp = -357546193, tmp)))/((2729539495)>>x))))%(tmp = 268894171.74961245, tmp))|(x>>(tmp = 2735650924, tmp)))/(-2197885357.09768))); + assertEquals(-2147483648, x |= x); + assertEquals(-1967162776824578000, x *= (tmp = 916031551, tmp)); + assertEquals(-2147483648, x &= x); + assertEquals(-457743917756973060, x *= (tmp = 213153622, tmp)); + assertEquals(0, x >>>= ((((tmp = 2930076928.480559, tmp)+(x^x))<<(tmp = -1349755597.1280541, tmp))|(x+(2865632849)))); + assertEquals(0, x <<= ((x>>x)-(x>>(-2629977861)))); + assertEquals(0, x <<= x); + assertEquals(NaN, x /= x); + assertEquals(0, x |= x); + assertEquals(0, x >>>= x); + assertEquals(749327478, x |= ((tmp = 749327478, tmp)^(x>>(tmp = 881107862, tmp)))); + assertEquals(1897869364, x += (1148541886)); + assertEquals(463347, x >>>= (tmp = -726431220, tmp)); + assertEquals(-395990542, x += (-396453889)); + assertEquals(-2824792585.1675367, x -= (2428802043.1675367)); + assertEquals(-2147483648, x <<= (tmp = -1420072385.9175675, tmp)); + assertEquals(8388608, x >>>= (-2211390680.488455)); + assertEquals(8388608, x >>= (((x/(x|(((x^(((tmp = -2175960170.8055067, tmp)|((tmp = -1964957385.9669886, tmp)/(tmp = -475033330, tmp)))&((x|((tmp = 1386597019.2014387, tmp)>>((tmp = -2406589229.8801174, tmp)+x)))<<(tmp = -844032843.8415492, tmp))))>>(x^x))|x)))-((x&((tmp = 1858138856, tmp)*(-3156357504)))%x))<<(((2046448340)+x)/(-2645926916)))); + assertEquals(8359470765396279, x *= ((tmp = 871437183.7888144, tmp)-(-125089387.17460155))); + assertEquals(0, x ^= x); + assertEquals(-303039014, x += ((tmp = -2475713214, tmp)|(-372871718.2343409))); + assertEquals(2655126577, x -= (-2958165591)); + assertEquals(1830332793, x ^= (tmp = -212161208, tmp)); + assertEquals(1830332793, x ^= (((2352454407.0126333)<<((((tmp = 3083552367, tmp)/x)-(-1243111279))-((tmp = -1669093976, tmp)%(((-757485455)-(tmp = -116051602, tmp))<<x))))>>(((((-2235071915.9536905)>>(tmp = -1284656185, tmp))-x)>>((-1807028069.7202528)>>>((x%((tmp = -3070857953.311804, tmp)+((tmp = 2759633693.441942, tmp)%((169489938)*(-1582267384)))))<<(x^((tmp = -787578860, tmp)<<x)))))>>((x/(x|(409464362)))-(tmp = -64033017, tmp))))); + assertEquals(397605933.90319204, x %= (tmp = 716363429.548404, tmp)); + assertEquals(186400, x &= (((x%(-1745754586))>>>x)<<(x&(x&((-2163627752)-((1784050895)+(((-2864781121.899456)>>>x)&x))))))); + assertEquals(186400, x %= (tmp = -423209729, tmp)); + assertEquals(186400, x <<= ((x<<(x+(1232575114.4447284)))*x)); + assertEquals(1386299, x ^= ((tmp = -1074209615, tmp)>>>(x>>>((tmp = -1456741008.2654872, tmp)>>((1724761067)>>(-2016103779.9084842)))))); + assertEquals(347302967.20758367, x -= (-345916668.20758367)); + assertEquals(1.9325619389304094, x /= (179711170.03359854)); + assertEquals(-3703324711.628227, x *= (tmp = -1916277371, tmp)); + assertEquals(-920980517031624800, x *= (tmp = 248690187.53332615, tmp)); + assertEquals(0, x &= (((tmp = -2753945953.082594, tmp)*x)-(172907186))); + assertEquals(-0, x /= (((((-2744323543.187253)>>((tmp = 2663112845, tmp)>>(((-121791600)+(x^x))*(2758944252.4214177))))|x)/(tmp = -2746716631.6805267, tmp))-x)); + assertEquals(0, x ^= ((tmp = 983113117, tmp)&((2638307333)+((((tmp = 3076361304.56189, tmp)<<(-2663410588.5895214))%((-1109962112)-(tmp = -2381021732, tmp)))%((tmp = 410559095, tmp)&x))))); + assertEquals(0, x <<= (tmp = 1510895336.5111506, tmp)); + assertEquals(0, x <<= (tmp = -1688348296.2730422, tmp)); + assertEquals(2269471424, x -= (-2269471424)); + assertEquals(-2022580224, x ^= (x%((tmp = 160999480.21415842, tmp)&x))); + assertEquals(-2077171712, x &= (tmp = 3032415014.3817654, tmp)); + assertEquals(270727, x >>>= (2973489165.1553965)); + assertEquals(270727, x |= x); + assertEquals(-1895894537, x |= ((tmp = -1895903118.129186, tmp)|x)); + assertEquals(-1895894537, x -= ((((((((3143124509)>>>(-2866190144.8724117))*((x>>((961021882)*(tmp = 2363055833.8634424, tmp)))/((2032785518)+((2713643671.3420825)>>((-447782997.0173557)*((tmp = 1174918125.3178625, tmp)*((((tmp = -541539365.548115, tmp)%(-359633101))|(1765169562.2880063))+(tmp = -2512371966.374508, tmp))))))))/x)>>(x*((((-847238927.6399388)&(857288850))%(-2427015402))^((2221426567)%(x+x)))))>>>x)<<((tmp = 2009453564.2808268, tmp)>>((2924411494)<<(x>>(tmp = -1240031020.8711805, tmp)))))%(tmp = 3118159353, tmp))); + assertEquals(0, x ^= x); + assertEquals(0, x %= (-30151583)); + assertEquals(-1035186736, x ^= ((tmp = -517593368, tmp)<<(tmp = 3216155585, tmp))); + assertEquals(49740, x >>>= x); + assertEquals(49740, x %= (640223506)); + assertEquals(388, x >>>= ((x>>(tmp = 3161620923.50496, tmp))+(2605183207))); + assertEquals(776, x += x); + assertEquals(-97905, x ^= ((((((tmp = 145447047.8783008, tmp)^(((x>>>(tmp = 3014858214.2409887, tmp))>>>(629911626.132971))>>(((x+((369309637.229408)-x))<<(-2661038814.9204755))*(x+(x%(3025191323.4780884))))))+x)*(-482550691))|(-632782135))/x)); + assertEquals(-97905, x %= ((((-492914681)-((-2508632959.269368)&(tmp = 1209318291, tmp)))>>(-723512989.459533))>>>(((-528429623.985692)&(x^(tmp = -925044503, tmp)))-(-1696531234)))); + assertEquals(9585389025, x *= x); + assertEquals(-715425728, x <<= ((583763091)<<(-1223615295))); + assertEquals(-520093696, x <<= ((tmp = -1891357699.671592, tmp)*(((tmp = 3206095739.5163193, tmp)+(-2908596651.798733))>>>((tmp = -2820415686, tmp)>>(x|((((tmp = -566367675.6250327, tmp)*(-959117054))>>((((-187457085.89686918)*x)*(tmp = -2394776877.5373516, tmp))>>>x))|(((tmp = 80478970.46290505, tmp)<<(tmp = 2173570349.493097, tmp))-(x/((-2896765964)-((x/((tmp = 198741535.7034216, tmp)%(436741457)))%(tmp = 2936044280.0587225, tmp))))))))))); + assertEquals(-2520.5909527086624, x /= ((211290893.06029093)>>(663265322))); + assertEquals(-2520.5909527086624, x %= (x^((1057915688)<<(tmp = 1914820571.1142511, tmp)))); + assertEquals(1, x >>>= (((894963408.7746166)+(tmp = -2888351666, tmp))|x)); + assertEquals(-1989841636629996300, x += ((1424670316.224575)*((-2144149843.0876865)|((((421479301.0983993)|((3082651798)^(tmp = -271906497, tmp)))>>x)+((tmp = -178372083, tmp)%x))))); + assertEquals(17935384255.088326, x /= (((((((tmp = 1168194849.2361898, tmp)>>>(-107316520.53815603))>>>(x^(((x%((x>>>(((-2456622387)/x)&((2124689803)|(((-1130151701)^(2796315158))>>x))))-((-884686033.5491502)>>>((-2371185318.5358763)&x))))+(tmp = 558422989, tmp))|((tmp = -420359120.0596726, tmp)/((-1820568437.0587764)&(2298602280.266465))))))>>(x-((tmp = -1164568978, tmp)^x)))^x)-x)+x)); + assertEquals(134233150, x &= ((x>>(((tmp = 98498118.13041973, tmp)-(804574397))/(tmp = -1564490985.7904541, tmp)))+x)); + assertEquals(4, x >>= (449610809)); + assertEquals(1912543790, x |= (1912543790)); + assertEquals(2487274263, x += (tmp = 574730473, tmp)); + assertEquals(-2140759118, x ^= (tmp = 338055333.9701035, tmp)); + assertEquals(311607367, x += (2452366485)); + assertEquals(9509, x >>= (372113647.84365284)); + assertEquals(-2001075684.1562128, x += (-2001085193.1562128)); + assertEquals(-638703280, x ^= (((tmp = 1096152237, tmp)&x)|((2707404245.0966487)-(((tmp = 1550233654.9691348, tmp)+(tmp = 2008619647, tmp))&((tmp = -2653266325, tmp)+(tmp = -280936332, tmp)))))); + assertEquals(-101811850, x |= (-2250090202)); + assertEquals(-13, x >>= ((-561312810.0218933)|(tmp = 79838949.86521482, tmp))); + assertEquals(-13, x >>= ((tmp = -936543584, tmp)/(1180727664.1746705))); + assertEquals(-1547, x *= (((tmp = 1005197689, tmp)>>>x)>>>(tmp = 34607588, tmp))); + assertEquals(2393209, x *= x); + assertEquals(2393209, x |= x); + assertEquals(0, x >>= (-2691279235.1215696)); + assertEquals(0, x *= (((896175510.4920144)*((((tmp = 1770236555.7788959, tmp)%(537168585.7310632))/x)&(tmp = 1094337576, tmp)))&(((x-x)-x)>>x))); + assertEquals(-1922620126, x ^= (-1922620126)); + assertEquals(3.43481396325761, x /= (tmp = -559745053.6088333, tmp)); + assertEquals(0, x >>= x); + assertEquals(0, x >>>= (tmp = 2106956255.6602135, tmp)); + assertEquals(-1339003770, x ^= ((tmp = 2955963526.960022, tmp)+x)); + assertEquals(-0, x *= ((((tmp = 368669994, tmp)>>>(x*x))<<(tmp = 2355889375, tmp))&(tmp = -2267550563.9174895, tmp))); + assertEquals(0, x >>= (753848520.8946902)); + assertEquals(0, x >>>= x); + assertEquals(0, x %= ((tmp = -2872753234.2257266, tmp)|x)); + assertEquals(NaN, x %= (x>>>(tmp = 890474186.0898918, tmp))); + assertEquals(NaN, x %= ((tmp = 1341133992.284471, tmp)&(tmp = -2979219283.794898, tmp))); + assertEquals(NaN, x += (-2865467651.1743298)); + assertEquals(NaN, x += ((-1424445677)%(x^(tmp = 1150366884, tmp)))); + assertEquals(0, x &= (x+((tmp = 1499426534, tmp)+x))); + assertEquals(0, x |= (((((tmp = -2413914642, tmp)<<((x>>>x)^(1218748804)))+((((-1085643932.2642736)-(-1199134221.533854))>>(tmp = 2148778719, tmp))-((tmp = 1589158782.0040946, tmp)/(tmp = -2485474016.1575155, tmp))))>>>(x>>x))/(2230919719))); + assertEquals(0, x %= ((tmp = -2576387170.517563, tmp)>>>((tmp = -2362334915.919525, tmp)>>>(((3096453582)-(700067891.4834484))^(2396394772.9253683))))); + assertEquals(-1798103432, x ^= (((((tmp = 2396144191, tmp)*(x>>>(1512158325)))&(((-1256228298.5444434)&(((-2963136043.434966)&((tmp = 2472984854, tmp)+(tmp = -454900927, tmp)))%(tmp = 484255852.65332687, tmp)))>>((x%x)-x)))&(tmp = 929723984, tmp))^(tmp = -1798103432.5838807, tmp))); + assertEquals(-2137913344, x &= ((((x|(-2970116473))&(((x/x)/((tmp = 2853070005, tmp)>>>x))%(((tmp = -3123344846, tmp)/((2224296621.6742916)-(tmp = -2246403296.455411, tmp)))+((x&(((x^(x*(2829687641)))+x)&(tmp = 988992521, tmp)))^x))))<<((((-820608336)^(tmp = 2851897085, tmp))>>(tmp = -402427624, tmp))>>>x))-(((x*(((-2287402266.4821453)%(tmp = -520664172.1831205, tmp))^(x/(1875488837))))<<(tmp = 402393637, tmp))&(tmp = 1576638746.3047547, tmp)))); + assertEquals(-2827557853031924000, x *= (tmp = 1322578326.6507945, tmp)); + assertEquals(6.424459501778244e+27, x *= (tmp = -2272087729.3065624, tmp)); + assertEquals(-1586887483, x |= (-1586887483)); + assertEquals(-567868980691736100, x *= (tmp = 357850816, tmp)); + assertEquals(1489101591, x ^= (x%(x|(421921075)))); + assertEquals(-801213804822328000, x *= (x|(-672326904.6888077))); + assertEquals(612257233.6612054, x /= (((tmp = -350127617, tmp)>>>(-1140467595.9752212))<<((x^x)+(-3117914887)))); + assertEquals(19097.231243331422, x /= ((x^(tmp = -570012517, tmp))>>>x)); + assertEquals(0, x >>= ((x%(((-2347648358)%((x-(tmp = -456496327, tmp))|(x^(-1977407615.4582832))))<<(x/(tmp = -2021394626.214082, tmp))))%(tmp = -949323000.2442119, tmp))); + assertEquals(0, x <<= x); + assertEquals(NaN, x %= (x^(x>>(((tmp = 597147546.7701412, tmp)&(((((-972400689.6267757)|(tmp = -2390675341.6367044, tmp))|(tmp = 1890069123.9831812, tmp))<<(((1606974563)-(tmp = -2211617255.8450356, tmp))&((((x+((2433096953)&(-2527357746.681596)))*(tmp = -313956807.55609417, tmp))|((tmp = -2146031047.968496, tmp)/(tmp = 2851650714.68952, tmp)))>>(((tmp = 2630692376.6265225, tmp)-(tmp = -3162222598, tmp))>>((tmp = 1915552466, tmp)*(x>>>(-2413248225.7536864)))))))&(x%((((1218471556)|x)+(tmp = -849693122.6355379, tmp))+x))))>>>(x/((tmp = 689889363, tmp)/x)))))); + assertEquals(0, x >>>= (45649573.23297)); + assertEquals(0, x >>>= (tmp = 1084439432.771266, tmp)); + assertEquals(NaN, x /= x); + assertEquals(NaN, x *= (tmp = 1642750077, tmp)); + assertEquals(0, x >>>= (tmp = -1944001182.0778434, tmp)); + assertEquals(1682573000, x |= (tmp = -2612394296.2858696, tmp)); + assertEquals(3041823595, x -= (((tmp = 720576773, tmp)|(x^(-1068335724.2253149)))>>(x*(-2501017061)))); + assertEquals(6083647190, x += x); + assertEquals(-6536258988089986000, x *= ((tmp = 632312939.6147232, tmp)|((-1621821634)+(((tmp = -2281369913.562131, tmp)&((tmp = -381226774, tmp)|x))&(664399051))))); + assertEquals(4.272268155938712e+37, x *= x); + assertEquals(733271152, x %= (-1345127171)); + assertEquals(847089925, x ^= (tmp = 432620917.57699084, tmp)); + assertEquals(1337073824, x <<= x); + assertEquals(-25810602, x ^= (tmp = 2982414838, tmp)); + assertEquals(-25282209, x |= ((tmp = -2927596922, tmp)>>>(-2404046645.01413))); + assertEquals(639190091919681, x *= x); + assertEquals(173568320, x &= ((((tmp = -718515534.4119437, tmp)&(tmp = 2989263401, tmp))<<x)|((tmp = 537073030.5331153, tmp)-(tmp = 883595389.314624, tmp)))); + assertEquals(0, x -= x); + assertEquals(0, x >>>= (tmp = -1844717424.917882, tmp)); + assertEquals(0, x >>= (tmp = -462881544.2225325, tmp)); + assertEquals(0, x >>= x); + assertEquals(-1868450038, x ^= (2426517258.6111603)); + assertEquals(1, x /= x); + assertEquals(1175936039.4202638, x += (tmp = 1175936038.4202638, tmp)); + assertEquals(-127916015, x ^= ((x/(1841969600.3012052))-(tmp = 1099467723, tmp))); + assertEquals(395713785658171900, x *= (-3093543726)); + assertEquals(395713787128560900, x += (((((-717204758)*(tmp = -588182129.6898501, tmp))-x)+(tmp = 20638023, tmp))^x)); + assertEquals(-962609355, x |= ((x^(-3118556619.912983))<<((tmp = 876126864, tmp)&x))); + assertEquals(-962609355, x %= (tmp = -2079049990, tmp)); +} +f(); diff --git a/deps/v8/test/mjsunit/numops-fuzz-part2.js b/deps/v8/test/mjsunit/numops-fuzz-part2.js new file mode 100644 index 0000000000..51260a4492 --- /dev/null +++ b/deps/v8/test/mjsunit/numops-fuzz-part2.js @@ -0,0 +1,1178 @@ +// 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. + +function f() { + var x = -962609355; + var tmp = 0; + assertEquals(-114583755, x -= (((-2806715240)&(((1961136061.0329285)>>>((2087162059)*x))+((tmp = -1890084022.7631018, tmp)%(tmp = 2137514142.358262, tmp))))+(x<<(tmp = 2991240918, tmp)))); + assertEquals(-425721856, x <<= x); + assertEquals(3778560, x >>>= ((x|(3198503572))>>(1158434541.1099558))); + assertEquals(3778560, x %= (tmp = -2592585378.9592104, tmp)); + assertEquals(624640, x &= (tmp = 2261638192.9864054, tmp)); + assertEquals(1249280, x += x); + assertEquals(1048576, x &= ((tmp = -2144301819.9892588, tmp)^((x-x)<<x))); + assertEquals(2097152, x <<= (x/x)); + assertEquals(5069061551149729, x *= (tmp = 2417116904.8069615, tmp)); + assertEquals(1.4836296666029616e+25, x += ((tmp = 2926833006.7121572, tmp)*x)); + assertEquals(-256, x >>= ((-469330345.3589895)%((x^(((2554170843.4978285)/(2495676674.815263))>>>x))*(-918892963)))); + assertEquals(-134217728, x <<= (x|(((((1687450853.1321645)+(tmp = 2369533014.5803776, tmp))+(tmp = -2613779445, tmp))+(tmp = -2488826226.3733397, tmp))>>(tmp = -220646936.41245174, tmp)))); + assertEquals(704164545131708400, x *= ((-2632786741)+(-2613647956))); + assertEquals(9216, x >>>= (-1925405359.657349)); + assertEquals(4491403261551.008, x *= (tmp = 487348444.1787118, tmp)); + assertEquals(4490606381829.008, x -= (tmp = 796879722, tmp)); + assertEquals(-60294056, x >>= x); + assertEquals(-3193966580.494005, x += (tmp = -3133672524.494005, tmp)); + assertEquals(550500358, x >>>= ((tmp = -2779637628.390116, tmp)-((tmp = 29230786.984039664, tmp)%(tmp = -310649504.7704866, tmp)))); + assertEquals(68812544, x >>= (-1347584797)); + assertEquals(1.2120221595741834e-11, x /= ((2791020260)*((((1964870148.6358237)^x)|(-3082869417))-((x^x)&((1234292117.8790703)<<(-1792461937.2469518)))))); + assertEquals(1.2120221595741834e-11, x %= (x-(2780439348))); + assertEquals(-1421552183, x |= (tmp = -1421552183.5930738, tmp)); + assertEquals(-1420954119, x |= ((((-2547788562.5735893)<<x)%(435385623))>>(x|x))); + assertEquals(1, x /= x); + assertEquals(1, x >>= (x>>>(((2975715011.501709)-(tmp = -1473273552.981069, tmp))/(1654883913.042487)))); + assertEquals(-65382, x ^= ((x/((tmp = -2780026200, tmp)<<x))^(((-2683084424)<<x)>>(-1716245874)))); + assertEquals(1530921106, x &= (1530940914)); + assertEquals(1, x /= x); + assertEquals(0, x >>= x); + assertEquals(0, x /= (tmp = 773741434.1972584, tmp)); + assertEquals(0, x |= x); + assertEquals(0, x <<= (-67977514.99888301)); + assertEquals(0, x %= (2496550482.524729)); + assertEquals(-0, x /= (tmp = -515040417, tmp)); + assertEquals(0, x <<= (-1673460935.2858837)); + assertEquals(-2638209488, x += (-2638209488)); + assertEquals(-2400951839498683400, x *= (910068685)); + assertEquals(1600582036, x ^= (((-1247602308.4812562)>>(((-2393714444.179732)>>>x)%(-778140635.7165127)))+(-1933914727.2268424))); + assertEquals(0, x *= ((x-x)>>(-1270234575))); + assertEquals(0, x >>>= (tmp = 3193676327.493656, tmp)); + assertEquals(0, x ^= (x>>>(1148676785.389884))); + assertEquals(0, x >>= (tmp = -2269181763.8663893, tmp)); + assertEquals(0, x >>= (3149450221)); + assertEquals(0, x >>= (1069630750)); + assertEquals(-625009654, x ^= ((-2143499112)%(-759244728.6214335))); + assertEquals(3583943, x >>>= (-2942645558.1204453)); + assertEquals(1791971, x >>= (x/x)); + assertEquals(223996, x >>= x); + assertEquals(6999, x >>= (tmp = -1051883611.9443719, tmp)); + assertEquals(1459617792, x <<= (-1572314984)); + assertEquals(2622356453.269262, x -= (tmp = -1162738661.2692618, tmp)); + assertEquals(5103676461.269262, x += (2481320008)); + assertEquals(823989684.2692623, x %= (x^(((((1048362966)*((tmp = -2423040747.6233954, tmp)>>>x))*((tmp = 2330818588.4081, tmp)>>(tmp = 103312020.98346841, tmp)))+(tmp = 2264492857.144133, tmp))>>>((tmp = 2523442834, tmp)<<x)))); + assertEquals(0, x >>>= (tmp = -2018700898.531027, tmp)); + assertEquals(NaN, x /= x); + assertEquals(0, x <<= (tmp = -2489442223, tmp)); + assertEquals(0, x >>= ((3045836220)>>>x)); + assertEquals(-1156905149, x ^= (3138062147)); + assertEquals(-0, x %= x); + assertEquals(-3118433907.512866, x -= ((tmp = 1338611238, tmp)-(-1779822669.5128663))); + assertEquals(100679693, x &= (1040565279)); + assertEquals(10136400582574248, x *= x); + assertEquals(0, x %= x); + assertEquals(2400318405, x += (2400318405)); + assertEquals(1.0036190808578471, x /= (((tmp = -2313492253.9889445, tmp)|(x-((tmp = -205459123, tmp)>>x)))+x)); + assertEquals(0, x >>>= (tmp = 882343227.1675215, tmp)); + assertEquals(0, x &= ((tmp = 2307828832.2706165, tmp)^((((((1404388047)<<((807879382)-(-2862921873)))-x)*(tmp = -1897734732, tmp))>>(tmp = 1981888881.2306776, tmp))%x))); + assertEquals(0, x <<= x); + assertEquals(0, x *= (((x*x)*((((2764801384.171454)%(x>>>x))&(384818815))+(x>>(tmp = -1481683516, tmp))))&x)); + assertEquals(0, x >>= (tmp = -2202536436, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x &= (tmp = 15161124, tmp)); + assertEquals(-1586110900, x ^= (-1586110900)); + assertEquals(-1586127952, x -= ((tmp = 560737212, tmp)%((1349529668)>>>(tmp = -1956656528, tmp)))); + assertEquals(-1174945870, x -= ((1178456190)|x)); + assertEquals(1335167624.3422346, x -= (tmp = -2510113494.3422346, tmp)); + assertEquals(1329952126.3422346, x -= (x>>x)); + assertEquals(1, x >>= x); + assertEquals(3, x |= (x<<x)); + assertEquals(3, x -= (x-x)); + assertEquals(-1938525669, x |= (tmp = 2356441625.5128202, tmp)); + assertEquals(-1938525669, x ^= ((tmp = -197149141.3622346, tmp)/(2833823156))); + assertEquals(-2.6292393147661324, x /= (737295254.2254335)); + assertEquals(2925975987.370761, x -= (-2925975990)); + assertEquals(2925975987.370761, x %= (tmp = 3041184582.8197603, tmp)); + assertEquals(-1908068660, x ^= ((tmp = -1380575181, tmp)-(2375164084.8366547))); + assertEquals(-477017165, x >>= (tmp = 2420877826.353099, tmp)); + assertEquals(-477017165, x %= ((tmp = -2919204062.3683634, tmp)-(tmp = -2263328990, tmp))); + assertEquals(-2105539936, x &= ((tmp = -1630795440, tmp)-(x&((933423833)>>(-475069901))))); + assertEquals(-4979480720, x -= (tmp = 2873940784, tmp)); + assertEquals(-4190953472, x -= (x&(tmp = -645918862.9001305, tmp))); + assertEquals(17564091004468855000, x *= x); + assertEquals(-857277134, x |= (tmp = 2363948338, tmp)); + assertEquals(1015632515, x -= (-1872909649)); + assertEquals(-1150380043, x ^= (tmp = -2014853770, tmp)); + assertEquals(1607729152, x <<= ((2194449589)+(x|(tmp = -1470075256.4605722, tmp)))); + assertEquals(1608356496, x |= ((((x|(670426524))<<((-2415862218)>>(tmp = 1572561529.9213061, tmp)))^((-1989566800.3681061)|x))&(2170270618.3401785))); + assertEquals(-1836056576, x <<= (tmp = 2906301296.540217, tmp)); + assertEquals(-2952415961567723500, x *= (tmp = 1608020145, tmp)); + assertEquals(1435500544, x <<= x); + assertEquals(700928, x >>>= (tmp = 2924829771.1804566, tmp)); + assertEquals(0, x <<= ((x^(2410009094))|(((-164334714.18698573)%(x*x))|(tmp = 2182431441.2575436, tmp)))); + assertEquals(-143321285, x ^= (tmp = -143321285, tmp)); + assertEquals(-2, x >>= x); + assertEquals(-1, x >>= (x&(1109737404))); + assertEquals(1, x >>>= x); + assertEquals(0, x ^= x); + assertEquals(-2463707358.165766, x += (-2463707358.165766)); + assertEquals(1831259938, x >>= (((((x-(tmp = 1359448920.5452857, tmp))%(tmp = -104541523, tmp))/((3133289055.9780197)*x))>>x)%x)); + assertEquals(1858895646, x ^= ((tmp = 131424376, tmp)>>(tmp = -396761023, tmp))); + assertEquals(1, x >>= x); + assertEquals(-1888369021, x |= ((tmp = -2038869285.046599, tmp)^((tmp = -1318286592.4250565, tmp)-(tmp = 2825123496, tmp)))); + assertEquals(1036458508, x <<= ((tmp = 2722401450, tmp)/((tmp = 1090712291, tmp)>>((tmp = -2155694696.9755683, tmp)*(tmp = 1661107340, tmp))))); + assertEquals(1, x /= (x%((tmp = -1716050484, tmp)+(tmp = -1683833551.797319, tmp)))); + assertEquals(0, x >>= (tmp = -2899315628, tmp)); + assertEquals(0, x |= x); + assertEquals(0, x >>>= x); + assertEquals(0, x <<= x); + assertEquals(1546062911, x |= (1546062911)); + assertEquals(1546195271, x += ((tmp = -3210667091, tmp)>>(tmp = 1323121165, tmp))); + assertEquals(3092390542, x += x); + assertEquals(-1199626354, x |= (406783756)); + assertEquals(-3650317194584908300, x *= (tmp = 3042878461.625484, tmp)); + assertEquals(-7.650495675092354e+27, x *= (2095844078)); + assertEquals(0, x >>= (tmp = 342617880.3384919, tmp)); + assertEquals(22, x ^= (((tmp = 381409558.9104688, tmp)>>((2823172888.974557)>>x))>>x)); + assertEquals(736383550, x += (736383528)); + assertEquals(0, x %= x); + assertEquals(0, x += x); + assertEquals(-1553157831, x -= (1553157831)); + assertEquals(1838556960, x <<= (3158944357.262641)); + assertEquals(5503285699.188747, x *= ((tmp = 2437440276, tmp)/(814308583.8128904))); + assertEquals(5824889900.188747, x -= (((tmp = 1171445694, tmp)-(tmp = -1584666956, tmp))^(tmp = 1217545373, tmp))); + assertEquals(747032, x >>>= (-89332085)); + assertEquals(747032, x |= (x^(x^(x>>>x)))); + assertEquals(747032, x >>>= ((-1558482440)*((tmp = -2413907480, tmp)+(3003996862.384156)))); + assertEquals(7.747761349084291e+23, x += ((tmp = 518064022.64624584, tmp)*((tmp = 2001951702, tmp)*x))); + assertEquals(0, x <<= (2769324707.5640426)); + assertEquals(NaN, x %= (((((((-2458056470.7717686)&x)>>(tmp = -361831232.42602444, tmp))*(2611108609.6727047))>>>x)/(-1713747021.8431413))*(-1143281532))); + assertEquals(NaN, x %= ((x^((-613836813)*(tmp = -3180432597.0601435, tmp)))%x)); + assertEquals(NaN, x /= ((-1607092857)^x)); + assertEquals(0, x &= (-1190719534)); + assertEquals(0, x >>>= x); + assertEquals(0, x += (x>>(642177579.1580218))); + assertEquals(-3129552333, x += (-3129552333)); + assertEquals(1165414963, x &= x); + assertEquals(2222, x >>= (((tmp = 2606317568, tmp)|x)+(tmp = 1844107136, tmp))); + assertEquals(NaN, x %= ((x^x)<<(x/(((tmp = -1362148700, tmp)&((tmp = 76371048, tmp)<<x))>>>((x^(-2605741153))>>(((tmp = -2131608159.7634726, tmp)|(((2827792229.8004875)|(((-848439251)+(-2576768890.123433))|((tmp = -2617711776, tmp)-((-199980264)&((tmp = -46967951.76266599, tmp)/(-733253537))))))*(tmp = 1820087608, tmp)))>>>(tmp = -3118359396.4298744, tmp))))))); + assertEquals(NaN, x /= ((2144871731)*x)); + assertEquals(NaN, x *= x); + assertEquals(NaN, x %= (tmp = 234811462.08692443, tmp)); + assertEquals(0, x >>>= ((1121416685)|(x^(((tmp = -2905413334, tmp)<<(tmp = -3091554324.030834, tmp))<<x)))); + assertEquals(-55938048, x |= ((tmp = -55938048, tmp)+(x*(tmp = -1518809027.2695136, tmp)))); + assertEquals(-3.3234995678333864e-10, x /= (x*(tmp = -3008876576, tmp))); + assertEquals(0, x <<= (x/((((((-2168824234.2418427)>>(((tmp = 1976810951, tmp)%x)<<(x*(x>>(x%(3146266192))))))%(tmp = 1756971968.122397, tmp))>>>(-2859440157.8352804))/(-1001406.1919288635))>>>(-1358031926)))); + assertEquals(-0, x *= (tmp = -1756000533, tmp)); + assertEquals(-0, x %= (2522761446.869926)); + assertEquals(0, x >>>= (((1087690535)>>>(2741387979))^x)); + assertEquals(0, x -= x); + assertEquals(0, x >>= (-819422694.2188396)); + assertEquals(0, x ^= x); + assertEquals(NaN, x /= x); + assertEquals(0, x &= (tmp = 86627723, tmp)); + assertEquals(0, x += x); + assertEquals(0, x %= (tmp = -2317915475, tmp)); + assertEquals(Infinity, x += (((-3072799584)^(-2487458319))/(((tmp = -3050692353, tmp)&x)>>(-777977292.8500206)))); + assertEquals(Infinity, x += x); + assertEquals(Infinity, x -= (tmp = 484428269, tmp)); + assertEquals(Infinity, x *= x); + assertEquals(Infinity, x /= (2059586218.2278104)); + assertEquals(Infinity, x *= (tmp = 415918523.8350445, tmp)); + assertEquals(-1800869091, x |= (((-1800869091)>>>(x>>>(tmp = -2832575051, tmp)))>>>x)); + assertEquals(6196126991451132000, x *= ((-1467292383.8458765)+(-1973339154.7911158))); + assertEquals(6196126992684649000, x += (1233517421)); + assertEquals(1, x /= x); + assertEquals(-7153809722216516000, x -= (((-2984550787.146106)<<(tmp = 743743974, tmp))*((3155151275)/((-1771412568.8965073)%x)))); + assertEquals(-7153809721471491000, x -= (-745024056)); + assertEquals(5.117699353102001e+37, x *= x); + assertEquals(0, x >>= x); + assertEquals(-0, x *= ((-2651785447.666973)<<(-1124902998))); + assertEquals(-0, x /= (2119202944)); + assertEquals(1042673805.5205957, x -= ((x<<x)-(tmp = 1042673805.5205957, tmp))); + assertEquals(62, x >>>= (tmp = 2769597912.977452, tmp)); + assertEquals(34, x &= ((tmp = -61541150, tmp)%(x^(-943160469)))); + assertEquals(34, x ^= ((-2625482224.4605474)<<(-2277806338.3461556))); + assertEquals(536870912, x <<= ((-2373927426.4757633)^x)); + assertEquals(536870912, x &= x); + assertEquals(512, x >>>= ((-1626769708.310139)<<((tmp = 641796314, tmp)/(721629637.3215691)))); + assertEquals(0, x <<= (-113973033)); + assertEquals(NaN, x /= x); + assertEquals(NaN, x += (-1602711788.2390788)); + assertEquals(NaN, x *= (x%x)); + assertEquals(0, x &= (x<<(x|(x>>((x>>>(x%((1182960050)^(((-220896609)-((((tmp = 1518275435.360103, tmp)/(tmp = -88234820, tmp))^x)/x))>>(3169930777.548236)))))-(tmp = -2912668817.662395, tmp)))))); + assertEquals(0, x *= ((2323969408.7524366)/(((tmp = -3089229853, tmp)>>>((((tmp = -1012580544.5631487, tmp)>>(1138049418.9023373))>>x)&x))*(tmp = 626912001, tmp)))); + assertEquals(0, x >>>= x); + assertEquals(NaN, x /= (x%(-868024322))); + assertEquals(NaN, x /= (tmp = -1749532322, tmp)); + assertEquals(1861918711, x |= (-2433048585.853014)); + assertEquals(1861918711, x >>= (((102451747)>>>((((241651917.47259736)/((((((((1759022236)^(tmp = -2592022722, tmp))+((-1748044969)>>>(704597925)))/(-1639604842))%((1349846853.7345295)<<(-729695861)))/(x>>((tmp = -2654474404.7365866, tmp)>>x)))>>>(((-480356478)|(x%((tmp = -1668269244.6979945, tmp)+(tmp = -2441424458.565183, tmp))))^((1634981212.7598324)>>>(tmp = 122455570.22000062, tmp))))<<x))*((tmp = -1058636137.5037816, tmp)+((2794083757.138838)&((x/(50081370))&x))))/x))/((tmp = -243106636, tmp)<<((x*((tmp = -648475219.5971704, tmp)>>((tmp = -1568913034, tmp)-((tmp = 911458615, tmp)|x))))>>>(tmp = 2714767933.920696, tmp))))); + assertEquals(0, x ^= x); + assertEquals(-2080484602, x |= (((1544771831.4758213)|x)^(-538113039))); + assertEquals(696451072, x <<= (tmp = -1587032689, tmp)); + assertEquals(-162595645, x += (tmp = -859046717, tmp)); + assertEquals(516546456, x >>>= x); + assertEquals(623083588, x += ((-1371850352)^(tmp = -1469933252, tmp))); + assertEquals(92342412, x %= (tmp = -132685294, tmp)); + assertEquals(500272110, x |= ((tmp = 1616032506, tmp)%((tmp = 1589569590.4269853, tmp)|(-972791738.1829333)))); + assertEquals(3247086, x %= (((tmp = 1372216208, tmp)|(-638950076.3387425))&((-2619249161.849716)&(73957896)))); + assertEquals(0, x >>>= (tmp = -1482343462.6911879, tmp)); + assertEquals(1265125662, x ^= (tmp = -3029841634, tmp)); + assertEquals(4941897, x >>>= (-2039728632)); + assertEquals(206857, x &= (tmp = 226962365.45571184, tmp)); + assertEquals(1.0925018562586405e+24, x += ((tmp = 2687424146, tmp)*(((-1998020319)%x)*(-2080331363)))); + assertEquals(-1.755270751212437e+32, x *= (-160665242)); + assertEquals(0, x <<= (3152796521.6427975)); + assertEquals(0, x ^= ((((((tmp = -855001595, tmp)<<(2007525777))-(x-(x-x)))/(3036585090.9701214))&(1827983388))*((tmp = -915604789.0515733, tmp)&(((((tmp = -806628722.7820358, tmp)%x)/(tmp = -2773117447, tmp))|x)<<(((tmp = -2902300974.7300634, tmp)|x)/(-1608133440)))))); + assertEquals(0, x |= ((((((119024954)*(((x^(tmp = 2939514414, tmp))|x)^(x-(tmp = -1597415597.6795669, tmp))))+(((tmp = -182277816.14547157, tmp)<<(((-2983451324.3908825)^(tmp = 1572568307, tmp))+(-1165604960.8619013)))/(x>>((tmp = -2127699399, tmp)>>((x^(((((tmp = -1968667383, tmp)^(tmp = 3120052415.9964113, tmp))|(((x|(((x^((tmp = 2831505153, tmp)<<((-3150506831.547093)+((x%(tmp = 383761651, tmp))%(2856803457)))))+(((tmp = -2426953997, tmp)^(tmp = -2667954801.1010714, tmp))*(tmp = -2707801631, tmp)))&(tmp = 2082935238.794707, tmp)))^((tmp = 697573323.5349133, tmp)-x))%(tmp = 661936357, tmp)))/(-1717944600.261446))>>>((2423776015.0968056)^((-1410322010)|((x<<(tmp = 2935993226, tmp))/(tmp = -1533896392, tmp))))))*(tmp = -596675330, tmp))))))>>>(((2944268153)^(x&(144579050.93126357)))/(-2123810677.2619643)))>>>(1473040195.9009588))*x)); + assertEquals(0, x /= (2877666495)); + assertEquals(2174852514, x -= (tmp = -2174852514, tmp)); + assertEquals(543713128, x >>>= x); + assertEquals(2978128878.939105, x += (tmp = 2434415750.939105, tmp)); + assertEquals(3529591145844655600, x *= (tmp = 1185170719.3753138, tmp)); + assertEquals(659, x >>>= ((((((x<<(((((-425423078)/(((tmp = 160617689.20550323, tmp)&(-1524740325.5003028))%(tmp = -1869426475, tmp)))<<(((x^(-487449247))>>>(tmp = -1962893666.7754712, tmp))%x))*x)>>((tmp = 623413085, tmp)&(x+(((((-2200726309.083274)-(x-x))+x)&(-1304849509))|((((tmp = -431896184, tmp)>>>(x>>(-1932126133)))<<((1078543321.2196498)*(-10761352)))>>(tmp = -2681391737.5003796, tmp)))))))/x)-(tmp = -1768629117, tmp))/(((((tmp = -2320718566.0664535, tmp)%x)+(-2831503351.995921))>>>(-2695416841.3578796))*(943979723)))<<x)|((652520546.7651662)>>(1045534827.6806792)))); + assertEquals(531, x &= (tmp = -293707149, tmp)); + assertEquals(0, x >>= (tmp = -678056747.5701449, tmp)); + assertEquals(1184651529.8021393, x += (tmp = 1184651529.8021393, tmp)); + assertEquals(1721719611, x |= (tmp = 1645413178, tmp)); + assertEquals(-406880257, x |= (tmp = 2268544460, tmp)); + assertEquals(-4194304, x <<= (tmp = -109701322.43455839, tmp)); + assertEquals(17592186044416, x *= x); + assertEquals(0, x ^= (x&x)); + assertEquals(0, x <<= (tmp = 1715401127, tmp)); + assertEquals(-1793087394, x |= (tmp = -1793087394.730585, tmp)); + assertEquals(-2, x >>= x); + assertEquals(263607360.10747814, x += (tmp = 263607362.10747814, tmp)); + assertEquals(1073214955, x |= (893759979.3631718)); + assertEquals(703953930, x -= ((2738450011)%(x^(tmp = 679402836, tmp)))); + assertEquals(1, x >>= (tmp = 2262515165.6670284, tmp)); + assertEquals(0, x >>= (((tmp = 747896494, tmp)^((tmp = -1005070319, tmp)+x))|x)); + assertEquals(0, x >>= ((953612771)>>>(tmp = 3066170923.3875694, tmp))); + assertEquals(-314941454, x -= (x+(((314941454)%(((tmp = 2200222912.9440064, tmp)>>>(2534128736.805429))>>>(x|((747716234)%(((tmp = -252254528, tmp)%(-1553513480.1875453))&x)))))<<x))); + assertEquals(-535686958, x &= (-522809126)); + assertEquals(0.5480312086215239, x /= (tmp = -977475278, tmp)); + assertEquals(-1199953459.6090598, x *= ((-2189571393)+((3186862741.37774)>>(tmp = -2193090564.5026345, tmp)))); + assertEquals(-1199953459.6090598, x %= ((tmp = 2986532440, tmp)*(2685122845))); + assertEquals(-1199953459.6090598, x %= (1951182743.7399902)); + assertEquals(51262285383887820, x *= (-42720228)); + assertEquals(-424776752, x |= x); + assertEquals(166221344210236600, x *= (tmp = -391314598.6158786, tmp)); + assertEquals(-1883425600, x >>= (((tmp = -1020679296, tmp)^((-1416867718)+(-1412351617)))<<(-2743753169))); + assertEquals(0, x &= (x/(-2250026610))); + assertEquals(-1111956501, x ^= (tmp = 3183010795, tmp)); + assertEquals(2012059503, x ^= (tmp = -900369276, tmp)); + assertEquals(15719214, x >>>= (tmp = -3196277049, tmp)); + assertEquals(15719214, x |= x); + assertEquals(100779035, x -= ((-1245802025)^(-2964289852))); + assertEquals(0, x >>= x); + assertEquals(0, x &= (((x<<((2361941389.708063)%x))>>((328256762.09842086)>>>((((tmp = 3094192285, tmp)-(((x>>(tmp = -2920437464, tmp))<<(tmp = -2693021467, tmp))-(x>>>((2410065554)%(x%(tmp = 2487056196.689908, tmp))))))-(tmp = -866314146, tmp))^((1754098471)-((((((-2450740191)-(tmp = 1977885539.6785035, tmp))*((tmp = -1205431332, tmp)>>>x))>>(-870601854))>>(tmp = -301859264, tmp))|((tmp = -2308971516.8301244, tmp)/x))))))&((2307007357)-((tmp = -1518812934, tmp)+(2562270162))))); + assertEquals(0, x <<= x); + assertEquals(-1802124619, x |= (-1802124619)); + assertEquals(-1802124619, x %= ((1617132364.306333)+((1678465962.079633)|((516698570)%(((569813606)*(-1800804098.6270027))%((tmp = 1976706935, tmp)-((tmp = -1830228989.5488424, tmp)>>(((x^((tmp = 1015246068.3791624, tmp)>>x))^((-2171682812.246772)-(tmp = -398330350, tmp)))&x)))))))); + assertEquals(904564673.6237984, x -= (tmp = -2706689292.6237984, tmp)); + assertEquals(818237248768128900, x *= x); + assertEquals(254842325.2585001, x %= (1550087667.9657679)); + assertEquals(-1163919360, x <<= x); + assertEquals(-3.4644526843674166, x /= ((-446801454)+(x>>>(tmp = -2025151870, tmp)))); + assertEquals(0, x &= ((((((((-1739617728)&(x&(((tmp = -2946470036.552597, tmp)/x)*x)))^(-1130501404))>>>x)/((1870230831)>>>(840301398)))%x)/x)/(-2927537567))); + assertEquals(0, x >>= x); + assertEquals(0, x >>>= (x&(x&x))); + assertEquals(0, x &= ((-579614044)-(-756012505.4048488))); + assertEquals(-2970367642, x -= (tmp = 2970367642, tmp)); + assertEquals(-415129376, x ^= (tmp = 2847041926.060355, tmp)); + assertEquals(-1505681312, x &= (tmp = -1225184902.9215767, tmp)); + assertEquals(-3174471329.5807734, x += (-1668790017.5807734)); + assertEquals(-Infinity, x /= (x>>x)); + assertEquals(NaN, x -= x); + assertEquals(0, x ^= (x^(((-1407936301.5682082)<<((x^(((tmp = 3213446217.307076, tmp)|x)|((tmp = 3219810777.3171635, tmp)/(tmp = 1561807400, tmp))))>>>((tmp = 2449910203.0949173, tmp)|((((1954662538.7453175)>>(tmp = -1711636239.9916713, tmp))>>>(tmp = 406219731.214718, tmp))<<(((-907908634.4609842)^((((((tmp = 2408712345, tmp)*(tmp = 1740346634.5154347, tmp))>>(tmp = 715783991, tmp))^(tmp = -655628853.2821262, tmp))%(tmp = 2819143280.434571, tmp))/(-1240412852)))*x)))))/x))); + assertEquals(0, x >>>= x); + assertEquals(0, x <<= x); + assertEquals(0, x >>>= (((-3198075268.8543105)>>(((((x+((tmp = -133461401.50823164, tmp)-((x&(((((tmp = 2617977319, tmp)>>((tmp = -2704719576.8734636, tmp)|((tmp = -977362542.2423751, tmp)<<(x<<(tmp = 3054487697.1441813, tmp)))))>>>((-1635655471)%x))/(-2079513672))%(tmp = 1993563806, tmp)))<<(tmp = -1310524200.6106496, tmp))))%((((-2558804500.7722936)+(tmp = -1641265491, tmp))<<((tmp = -1309608349, tmp)>>>x))/((tmp = -2306644272, tmp)<<x)))*(-2009396162.3063657))+(267343314.3720045))-(-2212612983.661479)))|x)); + assertEquals(NaN, x %= x); + assertEquals(NaN, x *= x); + assertEquals(-824822309, x |= (-824822309)); + assertEquals(-807944741, x |= (((-598067403)*((x&(tmp = 2897778389, tmp))>>>(-1322468310.3699632)))|x)); + assertEquals(90004223.44097246, x /= (((tmp = -481122620, tmp)&x)%((tmp = 1109368524, tmp)/(((-3150568522.633032)<<(tmp = 2923396776, tmp))^(x-((x/x)&(x/(-287976185.1049104)))))))); + assertEquals(0.4521931751193329, x /= (tmp = 199039323, tmp)); + assertEquals(1.8110466604491368e-10, x /= (2496860986.492693)); + assertEquals(0, x |= x); + assertEquals(-1225944576, x += ((tmp = -807700791.631221, tmp)<<((-700782615.4781106)-((((-2954619897)>>>x)<<((tmp = 997657844, tmp)>>>(1227994596)))/((-1234591654.8495834)*((tmp = -191189053.70693636, tmp)+(tmp = -3027659304, tmp))))))); + assertEquals(-1225811383, x |= (-1866233271)); + assertEquals(3069155913, x >>>= (((x/(-99524153.40911508))%(x>>>((((tmp = 2985975640, tmp)/(tmp = 2781516546.2494454, tmp))&(((2234114508)|(((x/(tmp = -1224195047, tmp))<<x)^(x>>>((537884375.5698513)+x))))^((tmp = -2144817497.5089426, tmp)|(-498079183.8178189))))>>>((x+x)&(-3086080103.6460695)))))<<(((tmp = 2151157136, tmp)*x)/(((x/x)>>>(-1149734628.4364533))-((3025445835.654089)+(tmp = 530902725.91127443, tmp)))))); + assertEquals(-1733702568, x ^= (tmp = 776361489.423534, tmp)); + assertEquals(8981504, x &= ((tmp = 2902581847, tmp)*(x-(-2697760560)))); + assertEquals(1153166.8526612986, x -= ((x/(tmp = -1375025594.5027463, tmp))+((3043576689.1538706)%(x+x)))); + assertEquals(3389855, x |= (x+x)); + assertEquals(-488458393.17759943, x += (-491848248.17759943)); + assertEquals(40982867145206920, x *= ((3132857155)|(tmp = -218356553, tmp))); + assertEquals(688, x >>= (((((tmp = 403321821, tmp)+((tmp = 2536984658, tmp)%((tmp = 2759309029.8753624, tmp)|(((tmp = 1994203554.7417293, tmp)^((704660500.434877)*(tmp = 1536292958.2691746, tmp)))+(-164139788)))))/((1205950994.1255205)+x))^((((tmp = 975272146.0133443, tmp)-(150107797))/(-1764309514))^((x>>>(x^(x^x)))+(203250124))))>>>(tmp = 1864959239.512323, tmp))); + assertEquals(10, x >>= ((tmp = 1631996431.9620514, tmp)>>x)); + assertEquals(10, x %= (tmp = 2678904916, tmp)); + assertEquals(335544320, x <<= (tmp = -2759037415.6811256, tmp)); + assertEquals(-153389967, x |= ((tmp = -2411636565, tmp)+(tmp = -2305156154, tmp))); + assertEquals(-1171, x >>= x); + assertEquals(813080576, x &= (((tmp = -65428547, tmp)&(tmp = 3163266999, tmp))<<x)); + assertEquals(4346532303, x += ((tmp = -761515569.0707853, tmp)>>>(((tmp = 143240971.0661509, tmp)<<x)*(x^((tmp = -271697192.8471005, tmp)&x))))); + assertEquals(-863299035, x ^= ((((2663001827.1492147)>>>((x/(((tmp = 482665912, tmp)-(x>>(tmp = 354425840.784659, tmp)))>>((-2012932893)>>>x)))/((tmp = -1354385830.6042836, tmp)>>>(-2149023857))))^((tmp = 585746520, tmp)+(tmp = 756104608, tmp)))^(517529841.184085))); + assertEquals(-997654012, x &= (((tmp = -404836025.15326166, tmp)+((tmp = 3035650114.0402126, tmp)<<((-1308209196)>>(tmp = 693748480, tmp))))<<(((465774671.4458921)<<x)/(1971108057)))); + assertEquals(-320581507110848260, x *= ((x-(tmp = -2266777911.7123194, tmp))^(tmp = -2810021113.304348, tmp))); + assertEquals(-320581508271196300, x += ((-1195215841.5355926)|(x-((2715907107.4276557)+(((-843426980)>>(x&(x%(tmp = -1139279208.34768, tmp))))^x))))); + assertEquals(368031616, x &= x); + assertEquals(368031616, x %= (tmp = 1211767328, tmp)); + assertEquals(-67505614939510744, x *= (tmp = -183423412.56766033, tmp)); + assertEquals(959424552, x >>= ((tmp = -171120122.5083747, tmp)/x)); + assertEquals(30949179.096774194, x /= (((x-((((x&(tmp = -180770090, tmp))<<(((tmp = -2061363045.419958, tmp)*((655711531)^((1205768703)-(tmp = 2468523718.8679857, tmp))))+(-2746704581)))+((-853685888)*(tmp = -2299124234, tmp)))|(tmp = 2429502966, tmp)))|(((-985794986.0232368)>>>(2890862426))%x))>>(tmp = 1005542138.8415397, tmp))); + assertEquals(30949179, x |= x); + assertEquals(30949179, x %= (810126097.6814196)); + assertEquals(120895, x >>= (tmp = 3065886056.1873975, tmp)); + assertEquals(1934320, x <<= (1478650660.7445493)); + assertEquals(0, x >>= (1069658046.2191329)); + assertEquals(NaN, x %= x); + assertEquals(NaN, x %= (x*x)); + assertEquals(NaN, x *= ((((2148513916)+(tmp = -210070225.85489202, tmp))>>(975470028))+((-3060642402)>>x))); + assertEquals(NaN, x *= (2888778384)); + assertEquals(NaN, x -= (294531300.16350067)); + assertEquals(-465620423, x ^= (tmp = -465620423.5891335, tmp)); + assertEquals(1613303808, x &= (-2530649850.1952305)); + assertEquals(2045458658, x |= (tmp = 432158946.5708574, tmp)); + assertEquals(0, x >>>= (2277328255.770018)); + assertEquals(0, x &= (-64904722.41319156)); + assertEquals(0, x >>= x); + assertEquals(3109394857.361766, x += (3109394857.361766)); + assertEquals(1519021650, x ^= ((tmp = -2632472653, tmp)|(tmp = 2161964921.8225584, tmp))); + assertEquals(370854, x >>>= ((1486892931.4564312)-((tmp = 3017755741.9547133, tmp)>>>x))); + assertEquals(1333145110.39802, x -= ((-1051580495.39802)-(tmp = 281193761, tmp))); + assertEquals(0, x ^= x); + assertEquals(0, x |= x); + assertEquals(0, x <<= x); + assertEquals(0, x >>>= x); + assertEquals(799202788.1455135, x -= (tmp = -799202788.1455135, tmp)); + assertEquals(1539080192, x <<= (x%(((((x-x)|(((((x%(959993901))+(tmp = -2647575570.092733, tmp))/(tmp = -2040600976.5104427, tmp))*(x*(tmp = 2785252760, tmp)))>>(-377867259)))/((x&(1549738240.013423))>>>(tmp = -1502185618, tmp)))*x)%(1159283801.0002391)))); + assertEquals(0, x >>= (-268660225)); + assertEquals(-0, x /= (-2795206270.635887)); + assertEquals(0, x >>>= (1869556260.2489955)); + assertEquals(64202212, x ^= ((((tmp = -942983515.5386059, tmp)*(((1057759788)-x)*(tmp = 2038041858, tmp)))>>x)+(tmp = 64202212, tmp))); + assertEquals(2021126977, x -= ((tmp = -2009912898, tmp)^((2240062309)%x))); + assertEquals(4332348265459724000, x *= (tmp = 2143530968, tmp)); + assertEquals(1472, x >>>= ((283380755)<<x)); + assertEquals(-1672370407872, x *= (tmp = -1136121201, tmp)); + assertEquals(338573318, x ^= (tmp = 2329579078.4832354, tmp)); + assertEquals(2377388772.1662374, x -= (tmp = -2038815454.1662374, tmp)); + assertEquals(-1.264761712403516, x /= ((((tmp = -2106209534, tmp)>>((((((tmp = 626190172, tmp)/x)>>>(-824270996.8545206))/((1258369810.9498723)-(tmp = -2947556209, tmp)))^((((366784589.24711144)|(1462064104.828938))-(1571045395.777879))<<(444685689.60103726)))>>(tmp = -2757110357.410516, tmp)))/(x>>>((tmp = 829226010, tmp)>>>(629512715))))|x)); + assertEquals(-2905481691.264762, x -= (2905481690)); + assertEquals(-1710543566.1481905, x -= (-1194938125.1165714)); + assertEquals(-3421087132.296381, x += x); + assertEquals(-884178944, x <<= ((-1820881235)|x)); + assertEquals(-884178944, x &= (x%(tmp = -2298828530, tmp))); + assertEquals(1516503040, x <<= ((tmp = -3039882653, tmp)+((tmp = 1956034508, tmp)<<(x>>(tmp = 280388051, tmp))))); + assertEquals(3033006080, x += x); + assertEquals(846431222.321887, x %= (x+(-1939718651.1609435))); + assertEquals(-846431224, x ^= ((-1742116766.54132)/x)); + assertEquals(1157918728, x &= (tmp = 1966568030, tmp)); + assertEquals(1157918728, x >>>= ((((((tmp = -2392096728.184257, tmp)*(x&(-3051259597.301086)))>>>(((tmp = 1712991918.071982, tmp)*(tmp = -714525951, tmp))-((-1784801647)>>((-1270567991)%(((214272558)/(((-3110194570)|(tmp = 2558910020, tmp))&(-1266294955.717899)))*((2654922400.609189)>>>(tmp = 370485018, tmp)))))))*(((tmp = -2621203138.1838865, tmp)%(858913517))*((tmp = -1564229442.2596471, tmp)>>((tmp = 1898557618, tmp)|(-1282356275)))))*(tmp = -1253508468, tmp))+((-361964404.75944185)|x))); + assertEquals(961668975, x += (-196249753)); + assertEquals(1, x >>= (tmp = 890453053, tmp)); + assertEquals(1, x >>= (((((tmp = 871309275, tmp)/(x>>>((tmp = 2033022083, tmp)&(tmp = -1393761939, tmp))))%((437488665.104565)^(tmp = 2808776860.4572067, tmp)))-((tmp = -359283111.49483967, tmp)<<((tmp = 2985855945, tmp)%(tmp = -596479825.9114966, tmp))))/(-1965528507))); + assertEquals(0, x >>= ((tmp = -1753776989, tmp)%(tmp = 322622654, tmp))); + assertEquals(84411424, x ^= (((x|(x|(tmp = -1617122265, tmp)))&(tmp = -313813263, tmp))&(1472888112.0258927))); + assertEquals(67633184, x &= ((1556833131.0776267)<<(x<<(1501219716.5575724)))); + assertEquals(68002293, x |= (((tmp = 188984203.0350548, tmp)>>>(tmp = 1356052777, tmp))%(x*(tmp = -2944960865, tmp)))); + assertEquals(67108864, x &= (((1046644783.9042064)<<x)+((-2796345632)>>>(((-1913290350.3687286)<<(((((tmp = -2223692353, tmp)>>x)&(x<<(x>>((((tmp = -976850020, tmp)%(tmp = 1379692507, tmp))>>>(1120103052.2077985))>>(tmp = 5592070.612784743, tmp)))))<<(x+((tmp = -3154037212.9764376, tmp)%(((x-(-1961060483.6965141))+(((1920670676)-(2852444470.7530622))/(((1445954602)>>((1353665887)>>(tmp = 111411560.64111042, tmp)))<<x)))+x))))<<((-1773130852.6651905)^((1216129132)>>(1511187313.2680469)))))|((tmp = -1107142147, tmp)|(tmp = -768165441.4956136, tmp)))))); + assertEquals(0, x -= x); + assertEquals(0, x %= (tmp = -1655707538.0778136, tmp)); + assertEquals(-184120712930843900, x += (x+((tmp = -3174410166, tmp)+((tmp = -301807453, tmp)*(tmp = 610060182.1666535, tmp))))); + assertEquals(-54598560, x >>= (-1365351357)); + assertEquals(-6763.94449950446, x /= (((-1953016847)<<((673287269.7002038)%(-558739761)))>>>(tmp = 1607754129, tmp))); + assertEquals(-1, x >>= x); + assertEquals(1, x >>>= x); + assertEquals(0, x >>>= x); + assertEquals(0, x >>= ((-384747983)+((((tmp = -949058352.381772, tmp)>>>(-1920744986))-(-882729639))^((x^((tmp = 2351364046, tmp)<<(((tmp = -3110165747, tmp)^(-1266489735))-((tmp = -371614326, tmp)>>((tmp = -2064968414, tmp)&(-2075036504.617934))))))&(((-2616501739)&(tmp = 2591437335.4029164, tmp))>>x))))); + assertEquals(0, x >>>= ((tmp = 2946468282, tmp)&((-2741453019)>>x))); + assertEquals(0, x -= ((x%(-134700915))&(-1955768279))); + assertEquals(NaN, x /= x); + assertEquals(NaN, x /= (x^(((((((tmp = 3185669685.772061, tmp)>>(tmp = -1973500738, tmp))-(tmp = -87401348.93002152, tmp))>>(tmp = -2813508730, tmp))&(tmp = -778957225, tmp))<<(x-(x&((-2821756608)+(((((tmp = 2475456548, tmp)/(tmp = 997998362, tmp))<<((tmp = -83043634, tmp)|x))%(636120329))%(tmp = -1910213427.7556462, tmp))))))%x))); + assertEquals(0, x &= x); + assertEquals(0, x <<= x); + assertEquals(0, x >>>= (x%x)); + assertEquals(0, x %= (745221113)); + assertEquals(0, x >>>= ((1467615554.7672596)|x)); + assertEquals(0, x /= (tmp = 735317995, tmp)); + assertEquals(-1513001460, x |= (2781965836)); + assertEquals(-1513001460, x |= (x%(1970577124.3780568))); + assertEquals(-0, x %= x); + assertEquals(1864972269, x ^= (-2429995027.840316)); + assertEquals(1226843341, x &= (tmp = -639621923.5135081, tmp)); + assertEquals(1226843339.3171186, x += ((1297620268.272113)/(-771070549))); + assertEquals(76677708, x >>>= (1009134980)); + assertEquals(0, x ^= x); + assertEquals(0, x ^= x); + assertEquals(NaN, x /= x); + assertEquals(716040787, x |= ((1851586229)-(1135545441.3502865))); + assertEquals(1385693184, x <<= x); + assertEquals(1321, x >>= (x^((tmp = -1576632297.0860603, tmp)>>>(405218605)))); + assertEquals(-1319012931, x |= (-1319014243)); + assertEquals(-1319012931, x >>= ((((1689898279.3580785)<<((((x^(x>>>((((tmp = 2635260332, tmp)*(tmp = 2053357650, tmp))*x)*(2856480122.339903))))>>x)&(-2382703000.077593))%(1183918594)))*(tmp = -1670081449, tmp))<<x)); + assertEquals(-528327581.7646315, x %= (tmp = -790685349.2353685, tmp)); + assertEquals(2073431790, x ^= (tmp = 2601800333, tmp)); + assertEquals(-6514722684180, x -= (((tmp = 824141806.0668694, tmp)>>>(((-1865885282.8723454)&(x&(x|((900188006.3757659)>>>(x&x)))))+(2227126244.0526423)))*x)); + assertEquals(1450593, x >>>= ((2157053647)>>(x+(-2934071355.418474)))); + assertEquals(576782336, x <<= ((1054640368.827202)&((tmp = -3182236876.434615, tmp)>>(tmp = 2129856634.0328193, tmp)))); + assertEquals(2950754326, x -= (tmp = -2373971990, tmp)); + assertEquals(738197504, x <<= (1188157369.5988827)); + assertEquals(0, x <<= (x+((tmp = -839533141, tmp)&((((((tmp = -1148768474.7306862, tmp)|(172650299))+(tmp = -2739838654, tmp))/(3132557129))%x)>>>(tmp = -1229961746.2466633, tmp))))); + assertEquals(0, x %= (tmp = -2974207636, tmp)); + assertEquals(0, x %= ((2323482163)>>>x)); + assertEquals(0, x &= (((x/(x+(x>>((tmp = 55935149, tmp)%x))))|((3109182235)>>>(tmp = 1217127738.8831062, tmp)))+((((tmp = -385114910, tmp)*((((((tmp = -2535158574.634239, tmp)&(x+x))<<(-2821692922.43476))&(-776804130.9457026))>>((-1374832535)^(tmp = 2175402162.701251, tmp)))%(-1646995095)))-(x*(tmp = -921556123, tmp)))^(79224621)))); + assertEquals(128935435, x |= ((tmp = 2279459038, tmp)%(tmp = -537630900.5271742, tmp))); + assertEquals(128935435, x /= ((((((x<<(2750024311))-((-1332480769.4784315)&(1418160003)))&(1551783357))<<(((((-2870460218.55027)|((-1958752193.7746758)&(2551525625)))>>>((((tmp = -1698256471, tmp)^(((((((((tmp = -830799466, tmp)+x)-(-111590590))+(tmp = -1105568112.3921182, tmp))/((tmp = -3058577907, tmp)|(((-1944923240.2965696)%(-2884545285))<<(tmp = -1993196044.1645615, tmp))))^(x>>(tmp = -2961488181.3795304, tmp)))&x)*x)|(((tmp = 97259132.88922262, tmp)<<((1601451019.343733)&x))*(x|x))))+((((x>>x)<<x)+(-868409202.2512136))/(((tmp = -2893170791, tmp)-((x|(-853641616))%(((tmp = 549313922, tmp)&(-768036601.6759064))%(tmp = -543862220.9338839, tmp))))-((tmp = 1639851636, tmp)+((2164412959)/(-273028039.941242))))))>>>((((-2382311775.753495)^(-2062191030.2406163))>>>(tmp = -1054563031, tmp))/(-862111938.7009578))))%x)+(-3103170117.625942)))%((tmp = -1144062234, tmp)>>x))>>>(tmp = 1216332814.00042, tmp))); + assertEquals(41.631074722901715, x /= (x&(-2542806180.962227))); + assertEquals(41.631074722901715, x %= (-14003386.556780577)); + assertEquals(8, x &= (x&((-2231622948)%(tmp = 488279963.9445952, tmp)))); + assertEquals(9.002961614252625e-9, x /= ((53802728.56204891)<<(((867697152.3709695)-(538719895.5707034))&(-631307825.4491808)))); + assertEquals(0, x >>= x); + assertEquals(-0, x *= (tmp = -785674989, tmp)); + assertEquals(-0, x += x); + assertEquals(0, x /= (-250703244)); + assertEquals(0, x <<= ((tmp = -661062581.5511999, tmp)|x)); + assertEquals(0, x &= (-1299482308)); + assertEquals(0, x &= ((-399690060)>>>(2448074202.385213))); + assertEquals(0, x &= (2574341201)); + assertEquals(0, x <<= ((x|(((tmp = 2458873162.645012, tmp)+(tmp = -1999705422.8188977, tmp))<<((x^(tmp = -392530472, tmp))>>>x)))&(((tmp = 2463000826.7781224, tmp)|(tmp = 3020656037, tmp))-x))); + assertEquals(1397603760, x += ((tmp = -1359413071, tmp)-(tmp = -2757016831, tmp))); + assertEquals(513823851, x -= (883779909)); + assertEquals(-1765712747, x ^= (2288060670.6797976)); + assertEquals(3117741504918286000, x *= x); + assertEquals(3117741506284045300, x += (1365759456)); + assertEquals(6035555595.597267, x /= (tmp = 516562470, tmp)); + assertEquals(104203275, x &= (tmp = 376835755.32434213, tmp)); + assertEquals(10858322520725624, x *= x); + assertEquals(59458951, x >>>= (153765028)); + assertEquals(49370856, x += ((tmp = -1291276092, tmp)>>x)); + assertEquals(0, x %= x); + assertEquals(0, x += x); + assertEquals(-1494589645, x -= (1494589645)); + assertEquals(-0, x %= x); + assertEquals(0, x <<= (x&((2730708043.467806)<<x))); + assertEquals(0, x /= ((tmp = -1483912394.153527, tmp)>>>((tmp = 1800568769, tmp)^((((((tmp = 1351568510, tmp)>>(tmp = -1337992543.2562337, tmp))>>>(tmp = 2602239360.40513, tmp))*x)%x)+(-2095840128.0700707))))); + assertEquals(-0, x /= ((2363946613)^(tmp = -2227868069, tmp))); + assertEquals(0, x &= ((((2634933507)<<(2798775374.140882))>>>x)>>>(((tmp = 1135200853.6396222, tmp)-(tmp = -1529829490.7007523, tmp))-(((((((((x^((x|(2135742668.591568))-(924230444.8390535)))%(tmp = -2459525610.51898, tmp))+(x&((tmp = 1177231743.809653, tmp)/(tmp = 1743270357.2735395, tmp))))|(((tmp = -1894305017, tmp)^((tmp = 1791704240, tmp)&x))%(-1569751461)))>>>(tmp = -2078321944, tmp))|x)*(((x*(tmp = -163239354, tmp))<<((tmp = 2859087562.694203, tmp)&(-657988325.9410558)))^(2508013840)))-((-243572350)+(x%((-1095206140)+((tmp = 3213566608.942816, tmp)*((2256442613)%((tmp = 1723751298, tmp)^(x-((-1145710681.2693722)|x)))))))))+(1556870627))))); + assertEquals(130883024.97423434, x -= (-130883024.97423434)); + assertEquals(0.046720352789736276, x /= (tmp = 2801413456, tmp)); + assertEquals(1806558189, x |= (tmp = 1806558189.157823, tmp)); + assertEquals(72.40475060062144, x /= (x%((1932591076.531628)>>(1982030182)))); + assertEquals(-1077558321.5975945, x += (tmp = -1077558394.002345, tmp)); + assertEquals(98187, x >>>= x); + assertEquals(97792, x &= (tmp = -1032487404, tmp)); + assertEquals(709197609, x |= (x^(709179177))); + assertEquals(11081212, x >>>= (tmp = 1412940006.169063, tmp)); + assertEquals(11081212, x &= x); + assertEquals(-1920311203, x -= ((tmp = 1931392415, tmp)<<((x%(tmp = -2873576383, tmp))%x))); + assertEquals(-1920311203, x |= (x&(-993884718.2172024))); + assertEquals(-4, x >>= (1409411613.0051966)); + assertEquals(-7947632484, x *= ((-2856731734)^((-1181032235.9132767)-((tmp = 780101930, tmp)+((tmp = -1732707132.6253016, tmp)^x))))); + assertEquals(-2016362769, x ^= (tmp = 2711125619.2455907, tmp)); + assertEquals(-61535, x >>= x); + assertEquals(-124771649, x ^= (tmp = 124726558, tmp)); + assertEquals(-1, x >>= x); + assertEquals(-0, x %= (x*x)); + assertEquals(0, x <<= x); + assertEquals(0, x /= (2444628112)); + assertEquals(0, x <<= ((-38968517.72504854)<<x)); + assertEquals(-1504619917, x |= (tmp = 2790347379, tmp)); + assertEquals(-1504619917, x &= x); + assertEquals(2790347379, x >>>= ((1825218368)<<(-1843582593.2843356))); + assertEquals(7786038495492170000, x *= x); + assertEquals(-11011696, x |= (((tmp = 2931644407.4936504, tmp)-(3077095016.001658))%(tmp = -1731851949, tmp))); + assertEquals(-107866, x %= ((-697845074.1661191)>>(772708134))); + assertEquals(356779149, x ^= (-356884949.503757)); + assertEquals(0, x %= x); + assertEquals(0, x *= ((tmp = 1542291783, tmp)^x)); + assertEquals(0, x += ((tmp = 1105314644.002441, tmp)&x)); + assertEquals(-1005882993, x ^= (-1005882993.0899806)); + assertEquals(-1301065066, x += (tmp = -295182073, tmp)); + assertEquals(-1454702592, x <<= ((-2440858737.390277)&(-1363565201.7888322))); + assertEquals(-201539012492525570, x *= ((((tmp = -1416268089, tmp)|x)-(tmp = 1669129769, tmp))&(x<<((x/(-2614041678.7423654))%x)))); + assertEquals(-2.1995276811535986e+25, x *= (x/(-1846667987.154371))); + assertEquals(0, x |= ((x*(((x>>>((tmp = 1044173034, tmp)>>>((x<<((tmp = -2906412863, tmp)%((tmp = -437401503, tmp)<<(((((x|(2167319070))<<((tmp = 2766179640.1840167, tmp)&(-2372076054)))*(tmp = -241617431.06416297, tmp))*((((((tmp = 2570465382.5574293, tmp)>>>(x/((-2851324509.354545)%x)))>>(((x+((tmp = -614687945, tmp)^x))^((((tmp = 1653437743, tmp)>>x)/(tmp = 3072995069, tmp))>>x))*(((((-290508242)>>((tmp = 2969511554, tmp)<<(tmp = 158176292.95642304, tmp)))<<(32376015))+(tmp = 2391895870.4562025, tmp))*x)))&((((x/(tmp = 365292078.53605413, tmp))>>x)/(1167322811.0008812))|(((tmp = 2487970377.365221, tmp)^x)<<((tmp = 2342607988.711308, tmp)/(((2276081555.340126)-(((tmp = -2571071930, tmp)>>(tmp = -248468735.76550984, tmp))>>>(tmp = -2862254985.608489, tmp)))^(-1312017395))))))<<x)&(2762717852.949236)))+((((-2492896493)&x)<<(-2756272781.4642315))/x)))))*(2405395452))))>>((-1433975206)/((tmp = -2064757738.6740267, tmp)<<((((tmp = -1563531255, tmp)-(-589277532.2110934))<<x)^(2249328237.0923448)))))-x))-(-225624231))); + assertEquals(0, x *= (tmp = 1657982666.2188392, tmp)); + assertEquals(86443387, x |= (tmp = 86443387.25165462, tmp)); + assertEquals(86443387, x %= (-1341731981.702294)); + assertEquals(172886774, x <<= ((-1799840391)&(1011948481.310498))); + assertEquals(-1115684864, x <<= x); + assertEquals(-2098253702059525600, x *= (1880686715.1865616)); + assertEquals(-2098253700213206300, x -= (tmp = -1846319435.0583687, tmp)); + assertEquals(570692096, x &= (((tmp = -1572055366.64332, tmp)%(tmp = 1720120910, tmp))%((x-(912386952.5959761))*(tmp = -1146251719.4027123, tmp)))); + assertEquals(603979776, x <<= ((-329752233.8144052)&(tmp = -368636559, tmp))); + assertEquals(603979776, x <<= x); + assertEquals(364791569817010200, x *= x); + assertEquals(0, x &= ((2074587775.983799)/(tmp = 438856632.76449287, tmp))); + assertEquals(0, x &= (((1509671758)*(tmp = -935801537.7325008, tmp))>>>(((tmp = -1752877566, tmp)<<x)%(tmp = -517163766, tmp)))); + assertEquals(-2031730599, x ^= ((2264285273)&(tmp = -1762662949.014101, tmp))); + assertEquals(-843578945, x %= (-1188151654)); + assertEquals(-2147483648, x <<= x); + assertEquals(-2147483648, x >>= (tmp = -3165079200.229641, tmp)); + assertEquals(-44086313.1323726, x %= ((x%(-254466243.48728585))-((x>>(-457411829.1063688))-((-2606923436.9333453)/x)))); + assertEquals(-44086313, x |= x); + assertEquals(1037812, x >>>= ((tmp = 342497258.9786743, tmp)+(1652928385.8150895))); + assertEquals(-2371695599678100, x *= (tmp = -2285284425, tmp)); + assertEquals(-2371697387004653, x += (tmp = -1787326553.0542095, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x >>= ((x^(tmp = 544039787, tmp))>>>x)); + assertEquals(0, x &= ((x%(((((((tmp = -424572417.1088555, tmp)|(-2381863189))/(tmp = -2007482475.1809125, tmp))&(((((tmp = 311016073, tmp)>>(tmp = -1548839845, tmp))+((-2557740399.7947464)<<(2399113209)))&x)>>>x))%(-297180308.7721617))-(tmp = 860906293, tmp))^x))%(-2740622304))); + assertEquals(4971841192462909000, x += ((tmp = -2723203837.572612, tmp)+((((-2909100706)+(-951999374))|(-3116735764))*(3087123539.422669)))); + assertEquals(-460, x >>= (1081807537.557404)); + assertEquals(2354165127.3906384, x += (tmp = 2354165587.3906384, tmp)); + assertEquals(357.8680960002211, x /= ((((x<<(((x&x)+(1113841407))|((x/(tmp = 384533564, tmp))>>>(-605853882))))%x)&((tmp = 2050375842, tmp)>>>x))>>(((2745147573)^x)<<(x-(900043292))))); + assertEquals(0, x *= (x>>>(-295974954.5058532))); + assertEquals(0, x *= ((-2448592125.815531)*(tmp = -94957474.8986013, tmp))); + assertEquals(0, x &= ((x>>x)^(tmp = -1335129180, tmp))); + assertEquals(395092065, x |= ((3081659156)^(tmp = -1608334475, tmp))); + assertEquals(395092065, x &= x); + assertEquals(-413337639, x += (x^(tmp = -664996071.3641524, tmp))); + assertEquals(-1604423637896759800, x *= (x>>>(tmp = 1242912352.955432, tmp))); + assertEquals(0, x &= ((((((tmp = 651293313, tmp)|(((2541604468.635497)>>>(tmp = 758815817.7145422, tmp))>>>((-1948795647)/x)))&x)/((tmp = -3161497100, tmp)+(782910972.3648237)))>>>x)%(834206255.5560443))); + assertEquals(0, x >>>= (tmp = 125945571, tmp)); + assertEquals(NaN, x -= (x%x)); + assertEquals(NaN, x %= (tmp = 282259853, tmp)); + assertEquals(NaN, x += (tmp = -2081332383, tmp)); + assertEquals(0, x >>>= (((x>>(-2298589097.7522116))|((((x>>>(x-(tmp = 755218194, tmp)))|x)%x)-(tmp = 2206031927, tmp)))>>>((((x&(x-x))^(tmp = 2836686653, tmp))*((x<<(tmp = -1624140906.4099245, tmp))>>>((2942895486)|((x>>>x)>>>(-1586571476)))))|((781668993)+(-1857786909))))); + assertEquals(0, x &= (tmp = -708084218.9248881, tmp)); + assertEquals(0, x %= (1645913394.5625715)); + assertEquals(0, x <<= ((x^((tmp = 1185413900, tmp)*((-2441179733.997965)*(tmp = 2554099020.066989, tmp))))%((1704286567.29923)/x))); + assertEquals(0, x += x); + assertEquals(0, x *= x); + assertEquals(0, x |= (x>>>(139138112.141927))); + assertEquals(0, x >>>= (tmp = 2142326564, tmp)); + assertEquals(0, x |= x); + assertEquals(-0, x /= ((((x+(2817799428))|x)%((1050079768)-(x>>>((1452893834.8981247)|((((tmp = -1737187310.889149, tmp)/(tmp = -362842139, tmp))%(1234225406))%(((x|x)*((-1055695643.739629)-((x-x)*(945954197.676585))))-(tmp = 786185315.346615, tmp)))))))<<(-173891691))); + assertEquals(0, x &= (-2842855092.319309)); + assertEquals(0, x &= ((-3188403836.570895)/x)); + assertEquals(0, x *= (x+x)); + assertEquals(NaN, x /= (x>>>(((tmp = 391037497.68871593, tmp)/((192754032)*(1382659402.5745282)))/((((-2187364928)>>>x)>>(tmp = 2563448665.7594023, tmp))^(tmp = 1500866009.7632217, tmp))))); + assertEquals(NaN, x /= ((tmp = -935036555.2500343, tmp)-(x/(((x&(x^(tmp = -3001352832.5034075, tmp)))^x)/((1122547613)>>x))))); + assertEquals(0, x >>= (tmp = -2951766379.0809536, tmp)); + assertEquals(-632945188, x ^= (-632945188.7188203)); + assertEquals(-632945188, x %= ((((((tmp = -3181527314.82724, tmp)&(2280175415))>>(x^(x|x)))^(tmp = -524233678.52970886, tmp))*x)|((tmp = 1782882786, tmp)>>>(tmp = -592607219, tmp)))); + assertEquals(404189184, x <<= ((tmp = -2761472127, tmp)^(36616299.88780403))); + assertEquals(872651572, x ^= (tmp = 739568436.6252247, tmp)); + assertEquals(13, x >>>= ((tmp = -1033843418.865577, tmp)%(x%(1247263629.0445533)))); + assertEquals(0, x >>>= x); + assertEquals(0, x >>= (3189175317)); + assertEquals(0, x &= (((2391973519.6142406)^((-2950058736.191456)|(x*x)))>>(tmp = 343822384.294345, tmp))); + assertEquals(0, x >>>= (tmp = -2306246544, tmp)); + assertEquals(-1572339598, x ^= ((tmp = 2991380083.337327, tmp)&(tmp = -1361507970, tmp))); + assertEquals(649, x >>>= ((1961407923.4950056)>>(x-(-872821523.7513013)))); + assertEquals(649, x ^= (((x&(tmp = -702931788, tmp))^(((x>>x)|(((tmp = 2710759269, tmp)/(x>>(x*((((((tmp = -2428445134.9555864, tmp)+(-1859938743))%(x<<x))*((236868604)+((tmp = -3066688385, tmp)/(787503572.8839133))))/(tmp = 3215629315, tmp))>>(-1315823020)))))%(1461368627.1293125)))>>>(tmp = -2921804417.5735087, tmp)))/(x>>>(((tmp = 2175260691.824617, tmp)/((-582958935.7628009)-((((((x>>x)|(2590503723.4810824))^(tmp = -1994324549, tmp))-(-684683327))/(tmp = -3133419531, tmp))|(tmp = -328974092.05095506, tmp))))>>(-447624639.4518213))))); + assertEquals(649, x %= ((((1854382717)|(((x+(tmp = 2568081234, tmp))-x)+((tmp = 1043086140, tmp)<<((tmp = 2979118595.0496006, tmp)+((x&(2669577199.852803))/(-2567808445.101112))))))<<((((tmp = -1471092047, tmp)&((-3099138855.21041)-((tmp = -798574377.526715, tmp)&((2255586141)<<(-1069867774)))))>>>(((x*(tmp = -2810255707.781517, tmp))/x)*(2706435744.054121)))^(394262253)))^((844325548.0612085)/(tmp = 1434691648, tmp)))); + assertEquals(823215943.1924392, x += (tmp = 823215294.1924392, tmp)); + assertEquals(536872706, x &= ((-334612686)%((1303605874)|x))); + assertEquals(-30666374.413486242, x += ((tmp = -567539080.4134862, tmp)%(tmp = -1655555936.3195171, tmp))); + assertEquals(-56438727096752984, x *= (tmp = 1840410814, tmp)); + assertEquals(-33200107.984488487, x %= (((tmp = 3007206509, tmp)-(3079337725.6659536))%(1819565202.5011497))); + assertEquals(-1214493182, x ^= (-3060193769)); + assertEquals(-1214493179.1335113, x -= ((-3218099496.595745)/(1122662554))); + assertEquals(-1214493179, x >>= ((-375364195)<<(((tmp = 619439637.8754326, tmp)>>(-1830023279.9486575))&(tmp = -1106180387.2448823, tmp)))); + assertEquals(-303623295, x >>= (-2109241374.3349872)); + assertEquals(-0, x %= x); + assertEquals(0, x |= x); + assertEquals(1917126206, x -= (-1917126206)); + assertEquals(2659779928, x -= (tmp = -742653722, tmp)); + assertEquals(-1635187368, x >>= ((tmp = -674385169, tmp)*((9848362.783326745)|(x*(55220544.00989556))))); + assertEquals(-1981113695, x ^= ((tmp = 392404985, tmp)>>(((x<<((2006207061)<<(tmp = 2558988218, tmp)))*((((tmp = 1789304307.1153054, tmp)/(2538061546))<<(tmp = 556026116, tmp))&((tmp = 1076457999.6424632, tmp)*(tmp = -1822378633.2489474, tmp))))%(((((-1117046924)&((-69013651)%(x&(((-2320327696)/(x&x))-(tmp = 2458222544, tmp)))))>>((-3092360983.0037227)/(-3171415636)))*(((tmp = 2520431213, tmp)<<(1066492762.6149663))+((tmp = 1272200889, tmp)^((1687693123.2295754)+x))))-(-1096823395))))); + assertEquals(-990556848, x >>= x); + assertEquals(981202869119695100, x *= x); + assertEquals(981202869119695100, x -= (x/x)); + assertEquals(0, x ^= (x>>x)); + assertEquals(NaN, x %= x); + assertEquals(0, x ^= x); + assertEquals(0, x *= ((((2980512718)>>>x)<<((x^(-1111233869))>>((2531466092.6036797)>>>(((tmp = -1791229364, tmp)*(-2210950307.206208))%((tmp = -806645443, tmp)<<((((((((tmp = 112334634.26187229, tmp)%(x|((((2154021796.1166573)+x)&((-1047293079.9686966)^(tmp = -1894127139, tmp)))+(tmp = 1910946653.2314827, tmp))))^(293142672.5016146))-x)<<(-1593533039.8718698))+x)>>(x<<(((46359706.50393462)&(tmp = 272146661, tmp))|(tmp = 2117690168, tmp))))%(tmp = -1784737092.4924843, tmp)))))))-(1465796246))); + assertEquals(0, x &= x); + assertEquals(NaN, x %= x); + assertEquals(0, x &= (x+(-1612418456))); + assertEquals(0, x &= ((tmp = -843964311, tmp)/x)); + assertEquals(NaN, x /= x); + assertEquals(NaN, x *= x); + assertEquals(NaN, x += (x>>>(54020240))); + assertEquals(489206868, x |= (489206868)); + assertEquals(489206868, x &= x); + assertEquals(489206848, x &= ((tmp = -1699133906.2361684, tmp)>>(tmp = 2658633814, tmp))); + assertEquals(489206848, x |= x); + assertEquals(1910559006, x -= (tmp = -1421352158, tmp)); + assertEquals(1, x >>= x); + assertEquals(0, x -= x); + assertEquals(0, x %= (x^(tmp = 2745376003.2927403, tmp))); + assertEquals(0, x %= (((tmp = 3199743302.1063356, tmp)^((-1905944176)&(x>>>(187247029.5209098))))<<((x*((-1394648387)*(1252234289)))-(3140049815)))); + assertEquals(0, x <<= (-2567872355)); + assertEquals(0, x %= (tmp = 1057707555.8604916, tmp)); + assertEquals(0, x %= ((tmp = -1877857405.0228279, tmp)>>>(((tmp = 423831184, tmp)*((tmp = -2106757468.324615, tmp)%(tmp = -1197717524.6540637, tmp)))>>(tmp = -93746263.46774769, tmp)))); + assertEquals(0, x |= x); + assertEquals(-0, x *= ((tmp = 1317609776.6323466, tmp)*(tmp = -26959885.89325118, tmp))); + assertEquals(0, x >>= (-1288116122.0091262)); + assertEquals(0, x &= ((370818172.92511404)%((tmp = -528319853.54781747, tmp)*(x/((tmp = -2839758076, tmp)^(x+(((-1258213460.041857)<<(tmp = 302017800.72064054, tmp))|((((tmp = -624254210, tmp)^((-338165065.97507)|((623392964)-x)))>>>x)%(tmp = 2767629843.0643625, tmp))))))))); + assertEquals(0, x >>>= x); + assertEquals(0, x >>>= x); + assertEquals(0, x |= ((-2001549164.1988192)*x)); + assertEquals(0, x -= x); + assertEquals(0, x *= (((((165836842.14390492)*(tmp = -3220002961, tmp))|(-2840620221.747431))%((x/(tmp = 3153915610, tmp))>>>(tmp = 2018941558, tmp)))>>>x)); + assertEquals(-0, x *= (-231994402.93764925)); + assertEquals(0, x <<= x); + assertEquals(0, x %= (tmp = 2702385056.1149964, tmp)); + assertEquals(0, x <<= (tmp = 378459323, tmp)); + assertEquals(0, x >>>= ((x&(x&(((-1014963013)<<(x&((tmp = -3110294840, tmp)|(x+(x<<(1129643420))))))+(1093795819.1853619))))+((((tmp = -2295103369.697398, tmp)&(((370501313.43019223)>>>(2465439579))/x))-x)>>x))); + assertEquals(0, x /= ((tmp = 1779625847, tmp)+(tmp = -662459654.6908865, tmp))); + assertEquals(0, x -= x); + assertEquals(0, x %= ((tmp = 2723291421, tmp)|(277246502.4027958))); + assertEquals(0, x ^= (((-2936270162)>>>((((tmp = -2019015609.1648235, tmp)|(47218153))*(-823685284))+x))&(x<<(x*(x|(((tmp = -941955398, tmp)^(tmp = -2365238993.5300865, tmp))-(778674685))))))); + assertEquals(0, x >>>= x); + assertEquals(NaN, x %= x); + assertEquals(0, x &= (-175235975.8858137)); + assertEquals(-2684493800.1062117, x += (tmp = -2684493800.1062117, tmp)); + assertEquals(-1290806265.6063132, x -= (-1393687534.4998984)); + assertEquals(-1290806265, x >>= (((x>>(tmp = -1710112056.4935386, tmp))*(586227650.2860553))<<(tmp = -2918251533.6052856, tmp))); + assertEquals(23470008, x >>>= x); + assertEquals(1668734969, x |= ((-295560682.9663689)^(x|((((tmp = -1183847364, tmp)&(3135327694))+(1679127747.1406744))-((-1895825528)%((tmp = -3180115006, tmp)+((tmp = 2373812187, tmp)|x))))))); + assertEquals(1744306169, x |= (1188503928.5009093)); + assertEquals(1744306169, x %= (tmp = -2723982401.4997177, tmp)); + assertEquals(3488612338, x += x); + assertEquals(3488612337, x += (((x/(-325849204))>>x)|(-1820624550.9149108))); + assertEquals(-1511119305, x ^= (tmp = 1778506182.2952862, tmp)); + assertEquals(-12211415, x %= (x^(tmp = -54943035, tmp))); + assertEquals(-12211415, x %= ((-1267051884)%(-643566443.0122576))); + assertEquals(-30.84976063258681, x /= (((1052047194)>>>x)&(1495698235.5117269))); + assertEquals(-61.69952126517362, x += x); + assertEquals(-244, x <<= (x^(x+(tmp = -2822258210.076373, tmp)))); + assertEquals(-6652, x &= ((tmp = 2593685093, tmp)>>((((2047688852.4609032)<<((x*(-611076291))*x))^(-2665364024.817528))>>>(165267874)))); + assertEquals(0, x -= x); + assertEquals(0, x /= (2454186758)); + assertEquals(0, x &= (tmp = -2226895206, tmp)); + assertEquals(0, x += x); + assertEquals(-21390701, x += ((-1369004846.0816503)>>(tmp = -2661552634.039692, tmp))); + assertEquals(-0.012568536912921919, x /= (1701924507.856429)); + assertEquals(7.09517966608176e-11, x /= (tmp = -177141911.8955555, tmp)); + assertEquals(0, x >>= (tmp = 231535697, tmp)); + assertEquals(1383687797, x ^= (tmp = -2911279499.568808, tmp)); + assertEquals(1383687797, x %= (tmp = -2258636646.5294995, tmp)); + assertEquals(1319, x >>= ((tmp = -2549411892.8426056, tmp)/(((((1532476676)^(153720871.82640445))+x)/(((2988190456.3206205)&(tmp = -2920873674, tmp))-(((((tmp = -1044518167.0581458, tmp)>>x)-((((tmp = -194701879.13505793, tmp)&(498352051))&((tmp = -2167339635.6529818, tmp)^(((x>>(tmp = 700159851, tmp))*(tmp = 2874921158, tmp))/x)))-((2856128689)|((-1876321441)>>>(2110732915)))))^((((tmp = -193379494.18825436, tmp)/(-3055182489.533142))<<x)+((tmp = -2286109605, tmp)>>(tmp = 698475484.3987849, tmp))))^(3182231653.500364))))|(((tmp = -194670835, tmp)>>>((786780139)%(((2114171416.2305853)^(1703145352.8143656))/x)))>>>((tmp = -3029462067, tmp)>>((67647572.02624655)&(x*(-2394283060)))))))); + assertEquals(13903855, x |= ((tmp = -2515306586, tmp)>>>x)); + assertEquals(54311, x >>>= ((-2413722658)-((tmp = -2159787584, tmp)^(tmp = 949937622.9744623, tmp)))); + assertEquals(108622, x += x); + assertEquals(1250717187, x ^= ((tmp = 842692148, tmp)+(((2649331689.694273)<<x)-(tmp = -2992181273, tmp)))); + assertEquals(4536777, x %= (tmp = 73304730, tmp)); + assertEquals(0, x -= x); + assertEquals(-580081499, x ^= ((tmp = -580081499.0170684, tmp)^(x%(tmp = -1542730817.88261, tmp)))); + assertEquals(-1382738784, x <<= x); + assertEquals(-1382738784, x <<= x); + assertEquals(2912228512, x >>>= (x*(x>>>x))); + assertEquals(-1076374105, x |= (2589443367)); + assertEquals(-0.2818750938197037, x /= (((tmp = -1559525732.9603848, tmp)|(-477068917.5483327))>>>((-688616257)*((((tmp = -1192490153.1226473, tmp)*(-502280624.0265591))<<(-442688727.4881985))%(x+(((((tmp = -2948836853.831935, tmp)-(tmp = -2850398330.910424, tmp))>>>(x>>>(-1947835558)))^x)+(x*x))))))); + assertEquals(2032826546, x |= (tmp = 2032826546.819327, tmp)); + assertEquals(3408404827.14316, x += (tmp = 1375578281.1431599, tmp)); + assertEquals(258183922.14315987, x %= (tmp = 350024545, tmp)); + assertEquals(479694848, x <<= (tmp = -481187157, tmp)); + assertEquals(-2147483648, x <<= (((tmp = -2956588045.472398, tmp)>>>(((tmp = -1838455399.1775856, tmp)&(((((tmp = -637547, tmp)/x)&(x^((-44876328.1767962)+(((-2059598286)-(1071496688))%(tmp = -1492254402, tmp)))))-(x%x))*(x|x)))>>(1226250760)))<<x)); + assertEquals(-2288163338.9020815, x -= (140679690.9020816)); + assertEquals(4954833118513997000, x *= (-2165419327.4906025)); + assertEquals(1578331238, x ^= (-2410854298.2270393)); + assertEquals(-810627292, x += (-2388958530)); + assertEquals(-810627292, x ^= ((1495296640.4087524)/(tmp = 1561790291, tmp))); + assertEquals(657116606535253200, x *= x); + assertEquals(0.675840332689047, x %= (((-1816548473)^(((tmp = -151918689.19451094, tmp)|(1819911186.535233))/((((((1514297447)+(tmp = 856485190.9684253, tmp))&(((1809369464.4363992)<<(493538496))*x))+((x*(x>>(x&(tmp = 222293461, tmp))))>>>(((784519621)|x)^((-580766922)>>(tmp = -947264116, tmp)))))>>>((((2794210354.22964)>>>(((2896952532.0183973)*((x+(tmp = -1813175940, tmp))<<(tmp = -1302618293, tmp)))&x))>>(x-(((x|((1456466890.1952953)*x))^(-169979758.19158387))-(x-x))))>>x))&(tmp = 2671604078.3026733, tmp))))/(-1701675745))); + assertEquals(0.675840332689047, x %= ((tmp = 2421871143, tmp)^x)); + assertEquals(NaN, x %= ((((tmp = 1175526323.433271, tmp)+(tmp = 2813009575.952405, tmp))%((tmp = -3112133516.3303423, tmp)&x))&((((((-424329392)^(tmp = 1430146361, tmp))+x)-(1533557337.268306))%((tmp = -3117619446, tmp)-(-3127129232)))>>>x))); + assertEquals(NaN, x += x); + assertEquals(0, x >>>= ((1710641057.7325037)%(104961723.56541145))); + assertEquals(0, x <<= (tmp = -970072906, tmp)); + assertEquals(0, x *= (87768668)); + assertEquals(-1464968122, x ^= (tmp = -1464968122, tmp)); + assertEquals(-1467983895, x ^= ((tmp = -1204896021, tmp)>>>(((91792661)&(x>>>(((-2364345606)>>>x)*x)))+x))); + assertEquals(2.991581508270506, x /= (-490704963.5591147)); + assertEquals(0, x >>>= x); + assertEquals(0, x >>= ((tmp = 639854873, tmp)%(tmp = 743486160.3597239, tmp))); + assertEquals(0, x <<= (tmp = 1045577245.3403939, tmp)); + assertEquals(0, x >>= ((tmp = -1932462290, tmp)|(tmp = 1629217987, tmp))); + assertEquals(517617438, x ^= ((tmp = 2737789043, tmp)%(tmp = -2220171604.135681, tmp))); + assertEquals(126371, x >>>= ((tmp = 205210223.69909227, tmp)-(tmp = 598118404, tmp))); + assertEquals(918548455, x |= ((918228734.8363427)+(x+x))); + assertEquals(918548455, x |= ((tmp = 599828198, tmp)>>((tmp = -851081330, tmp)|(tmp = -1152596996.8443217, tmp)))); + assertEquals(918548443.7739062, x -= ((tmp = 1497642976.2260938, tmp)%(x>>(tmp = -548469702.5849569, tmp)))); + assertEquals(0.7739062309265137, x %= (x&x)); + assertEquals(2317939163.8239403, x *= (tmp = 2995116296, tmp)); + assertEquals(1014415360, x <<= (-279972114)); + assertEquals(0, x &= ((296810932)/(x*(tmp = -2750499950, tmp)))); + assertEquals(0, x *= (x%((126285451.05086231)>>>(x*(tmp = -2789790532, tmp))))); + assertEquals(0, x >>>= ((975695102.5771483)%(x-((-1011726540)-((tmp = 2223194882, tmp)/x))))); + assertEquals(-1747794584, x |= (-1747794584.3839395)); + assertEquals(-543544679, x %= (tmp = -1204249905, tmp)); + assertEquals(-543544679, x %= (-881024001)); + assertEquals(1, x /= x); + assertEquals(-1879376393, x |= ((tmp = 161643764, tmp)|(tmp = 2281346499.9084272, tmp))); + assertEquals(1.321124264431369, x /= (-1422558379.7061746)); + assertEquals(1, x >>>= (x&(tmp = -963118950.4710281, tmp))); + assertEquals(3, x ^= ((x+x)/x)); + assertEquals(1, x /= x); + assertEquals(1, x &= (2090796073)); + assertEquals(-1284301873, x ^= (((-11041168.146357536)+(tmp = -1273260707.8134556, tmp))+x)); + assertEquals(292559045, x &= (x&((-2401110739)^((tmp = 630802904, tmp)^(((1012634447.0346229)+x)%((tmp = -1240091095, tmp)%(x/(-1483936527)))))))); + assertEquals(0, x %= x); + assertEquals(0, x /= (tmp = 613145428.3653506, tmp)); + assertEquals(0, x /= ((x-(tmp = 3116638456, tmp))*(-973300716))); + assertEquals(0, x %= (tmp = -1794741286.0464535, tmp)); + assertEquals(0, x &= x); + assertEquals(0, x >>= (-551370105.0746605)); + assertEquals(-1471996874, x ^= ((2822970422.2331414)-x)); + assertEquals(-277914313, x |= (tmp = -818980601.2544096, tmp)); + assertEquals(-34, x >>= x); + assertEquals(305422768, x -= (-305422802)); + assertEquals(-2406146240, x += (tmp = -2711569008, tmp)); + assertEquals(1073745408, x &= (tmp = -3046625618, tmp)); + assertEquals(1073745408, x <<= ((-1234108306.7646303)<<((-233519302)|x))); + assertEquals(1073745408, x %= (tmp = 1898831268, tmp)); + assertEquals(1073745408, x <<= (((tmp = 3089406038, tmp)/x)&(-2960027680))); + assertEquals(65536, x >>>= (2858188366)); + assertEquals(128, x >>>= ((-2640257239.857275)%((tmp = -3185405235.3177376, tmp)*x))); + assertEquals(128, x >>>= x); + assertEquals(128, x -= (x&(x-(tmp = -247588018, tmp)))); + assertEquals(81616906825.07776, x *= (tmp = 637632084.57092, tmp)); + assertEquals(78860097686.07776, x -= (((1507215684)^((709254783)+(((x<<x)*((-2890828152.667641)%(2537817529.2041526)))^x)))+(3114024487))); + assertEquals(-2920545695.721283, x += (((tmp = -2555437435, tmp)>>>x)-((2920546109.72129)+x))); + assertEquals(-2879412281.721283, x += ((-1662428756)>>>(tmp = -1928491386.6926208, tmp))); + assertEquals(67403845, x &= (tmp = 2921644117, tmp)); + assertEquals(16850961, x >>>= (((-1039328365)>>>(tmp = -768615112, tmp))<<((1037261855)*(tmp = -2906902831.4797926, tmp)))); + assertEquals(0, x ^= x); + assertEquals(0, x *= ((-2729056530)/((-1776175111)%(1493002300.4604707)))); + assertEquals(0, x *= (tmp = 370696035.22912216, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x |= ((((((tmp = -1541196993, tmp)^x)/(854730380.1799632))/(2879117705.492209))+((((-2892068577)^(-2460614446.1044483))>>>((743413943)<<(-1285280084.4220598)))/(tmp = -1719994579.5141463, tmp)))%(((((tmp = 2522797851.088227, tmp)<<(tmp = 2257160597.1538725, tmp))/(-680406007))&((x>>>(tmp = -260350730, tmp))^(tmp = 1920522110.852598, tmp)))>>(-697620442)))); + assertEquals(0, x &= x); + assertEquals(-591399642.958673, x += (x-(tmp = 591399642.958673, tmp))); + assertEquals(27, x >>>= (tmp = -726721317.2109983, tmp)); + assertEquals(-2043736843, x -= (2043736870)); + assertEquals(-3991674, x >>= (tmp = 1098126089, tmp)); + assertEquals(-997919, x >>= ((x%(((x*(((-1497329257.1781685)%(2334511329.2690516))/(-3072526140.6635056)))+(-1843998852))-(tmp = 240300314.34070587, tmp)))+(714080860.6032693))); + assertEquals(-0, x %= x); + assertEquals(NaN, x /= x); + assertEquals(0, x >>= (tmp = 538348328.5363884, tmp)); + assertEquals(0, x *= (800317515)); + assertEquals(0, x -= x); + assertEquals(0, x >>= (984205514)); + assertEquals(857282491, x += (tmp = 857282491, tmp)); + assertEquals(587792897, x &= (tmp = 2951307845.164059, tmp)); + assertEquals(595301269, x |= (tmp = 24285588.90314555, tmp)); + assertEquals(1190602538, x += x); + assertEquals(0, x -= x); + assertEquals(-442423060, x |= ((x^((x-(tmp = 2342497475.637024, tmp))%(-1900074414.7678084)))|((tmp = 1932380130, tmp)%(x%(2291727569.817062))))); + assertEquals(-442423060, x %= (((tmp = 703479475.545413, tmp)>>(x-x))<<(2435723056.753845))); + assertEquals(1, x /= x); + assertEquals(0, x >>= x); + assertEquals(-1265317851, x |= (tmp = -1265317851, tmp)); + assertEquals(-2, x >>= (-2015895906.8256726)); + assertEquals(-0, x %= x); + assertEquals(-0, x %= (((1219237746)+(284683029))*(((tmp = 2288119628, tmp)|(-404658161.2563329))*(-265228691.74142504)))); + assertEquals(1039509109, x -= (-1039509109)); + assertEquals(2079018218, x += x); + assertEquals(-1979.9362673719077, x /= ((3219723500)>>x)); + assertEquals(-62, x >>= ((x/(326466691))*(tmp = -607654070, tmp))); + assertEquals(-45, x |= (tmp = -2954888429.549882, tmp)); + assertEquals(-1180929712, x &= (3114037588.570232)); + assertEquals(815550480, x &= (-2302684143.3378315)); + assertEquals(815550480, x %= (-2177479570)); + assertEquals(815550480, x %= (tmp = 2895822167, tmp)); + assertEquals(815550480, x %= (-1247621230.5438688)); + assertEquals(283929811, x -= ((tmp = 251831053.17096448, tmp)|((tmp = 1140463506.004994, tmp)+(tmp = -743224673.546309, tmp)))); + assertEquals(1825767424, x <<= (((tmp = 1732353599, tmp)^(tmp = 658726044, tmp))>>>((-2827889370.932477)%(tmp = 1950139204.3291233, tmp)))); + assertEquals(1828450414, x |= (tmp = 1618538606, tmp)); + assertEquals(0, x <<= (-2411670689.045702)); + assertEquals(0, x <<= (-27744888.428537607)); + assertEquals(-0, x /= (tmp = -1597552450, tmp)); + assertEquals(0, x >>>= (((2165722776.7220936)>>>(tmp = 1233069931, tmp))>>>(-1120420811))); + assertEquals(-0, x *= ((tmp = -1505252656, tmp)>>((((3035637099.6156535)&((467761577.7669761)>>(-361034537)))^(tmp = -2347994840.6541123, tmp))*(tmp = -2191739821, tmp)))); + assertEquals(0, x &= (795727404.0738752)); + assertEquals(-0, x *= (tmp = -3125944685.3991394, tmp)); + assertEquals(-0, x *= (x&x)); + assertEquals(0, x >>= ((tmp = -2045709233, tmp)^x)); + assertEquals(NaN, x /= (x>>(x/(3102894071)))); + assertEquals(NaN, x += ((tmp = 2149079756.8941655, tmp)-(tmp = 810121645.305179, tmp))); + assertEquals(0, x >>>= (-859842989)); + assertEquals(0, x >>>= (tmp = 2530531143.9369526, tmp)); + assertEquals(0, x >>= (((-932981419.6254237)|(tmp = 1591591715, tmp))>>>(x+((3149795006)>>>(tmp = 613352154, tmp))))); + assertEquals(-4294967295, x -= ((((-2289331668)%(-282648480.0078714))>>(-1373720705.5142756))>>>((tmp = 15511563.517014384, tmp)/(360279080)))); + assertEquals(1, x &= x); + assertEquals(0, x >>= (x^(-2791872557.5190563))); + assertEquals(0, x &= ((tmp = 336466956.7847167, tmp)>>((1235728252.053619)|(x<<((1828176636.13488)%x))))); + assertEquals(-0, x *= (-364042830.8894656)); + assertEquals(0, x >>>= x); + assertEquals(-1675298680, x |= ((2323049541.321387)+(296619075))); + assertEquals(-0, x %= x); + assertEquals(-1583048579.4420977, x += (-1583048579.4420977)); + assertEquals(0, x -= x); + assertEquals(-2, x ^= ((603171992.0545617)/(((-271888695.718297)%(tmp = -400159585, tmp))^((((tmp = 1536123971, tmp)-(tmp = -2310418666.6243773, tmp))|((tmp = 2242779597.1219435, tmp)<<(tmp = 1758127684.4745512, tmp)))/x)))); + assertEquals(-2, x &= (x&x)); + assertEquals(0, x &= ((tmp = -1098806007.4049063, tmp)/(((2862384059.3229523)/((((tmp = -92960842, tmp)-(x>>(tmp = 1244068344.2269042, tmp)))&x)*(tmp = -1919148313, tmp)))<<(-2486665929)))); + assertEquals(0, x &= x); + assertEquals(-1441272634.582818, x -= (1441272634.582818)); + assertEquals(-3, x >>= (tmp = 3186393693.7727594, tmp)); + assertEquals(-1206855850, x ^= (((tmp = 607979495.303539, tmp)-(tmp = -2480131951, tmp))^(x*((tmp = 1324153477, tmp)/((1248126288)+(x|(1917331780.0741704))))))); + assertEquals(-1206855853, x ^= (x>>>(653288765.1749961))); + assertEquals(-1206857725, x &= (3149461539.6019173)); + assertEquals(3088109571, x >>>= (x*(x<<(tmp = 1543540084, tmp)))); + assertEquals(536903680, x &= (tmp = 644851760, tmp)); + assertEquals(536903674.312194, x += (((-3183290076)-((tmp = 40738191.12097299, tmp)-x))/((x>>>(3151371851.9408646))^(tmp = 472698205.22445416, tmp)))); + assertEquals(2127424750.0506563, x -= (tmp = -1590521075.7384624, tmp)); + assertEquals(2127424750.0506563, x %= (tmp = 3027273433.361373, tmp)); + assertEquals(0, x >>= (x>>(1445204441.702043))); + assertEquals(NaN, x %= (x<<x)); + assertEquals(0, x ^= ((tmp = -2903841152.136344, tmp)-(x%(2938662860)))); + assertEquals(0, x <<= (x<<x)); + assertEquals(0, x >>>= (tmp = -979481631.33442, tmp)); + assertEquals(0, x >>= x); + assertEquals(0, x &= (((x%((((((tmp = 1657446354.6820035, tmp)>>(-1916527001.2992697))/x)>>(tmp = 1450467955, tmp))&(277676820))+(x/(-945587805))))/((tmp = -690095354, tmp)^x))+(tmp = -2651195021, tmp))); + assertEquals(0, x <<= (752343428.2934296)); + assertEquals(0, x /= (tmp = 3022310299, tmp)); + assertEquals(0, x >>= (x%((388245402)>>>x))); + assertEquals(NaN, x %= x); + assertEquals(NaN, x %= ((tmp = 1205123529.8649468, tmp)>>>(-2848300932))); + assertEquals(0, x >>= ((x>>>x)<<(tmp = 487841938, tmp))); + assertEquals(0, x *= (((273436000.9463471)|(tmp = 141134074.27978027, tmp))^(tmp = 1220326800.7885802, tmp))); + assertEquals(1525600768, x |= (((x^(-2674777396))-(tmp = 1966360716.3434916, tmp))<<(794782595.9340223))); + assertEquals(761927595, x %= (tmp = -763673173, tmp)); + assertEquals(1.1353588586934338, x /= ((x&((-1897159300.4789193)*(-348338328.0939896)))&(978680905.6470605))); + assertEquals(8.631173314966319e-10, x /= (1315416592)); + assertEquals(0, x >>= ((tmp = -2581239435, tmp)-((-628818404.1122074)<<x))); + assertEquals(0, x -= x); + assertEquals(0, x *= (2925158236)); + assertEquals(0, x /= (x+(tmp = 1405531594.0181243, tmp))); + assertEquals(0, x *= (2712022631.230831)); + assertEquals(0, x >>= (tmp = 80518779.81608999, tmp)); + assertEquals(1953477932.8046472, x += (tmp = 1953477932.8046472, tmp)); + assertEquals(1953477932, x >>= (tmp = 3025539936, tmp)); + assertEquals(1953477932, x -= ((-2675119685.8812313)>>(x/(-1808264410.9754841)))); + assertEquals(1292620430, x += ((-660857502)%((((tmp = -698782819, tmp)%(tmp = 2847304199, tmp))<<(-2423443217.1315413))+x))); + assertEquals(78895, x >>>= x); + assertEquals(2, x >>= x); + assertEquals(2, x <<= (tmp = 1313641888.8301702, tmp)); + assertEquals(1857416935.2532766, x += (tmp = 1857416933.2532766, tmp)); + assertEquals(-1677721600, x <<= (tmp = -2482476902, tmp)); + assertEquals(309226853.62854385, x -= (tmp = -1986948453.6285439, tmp)); + assertEquals(33965156, x &= (2409088742)); + assertEquals(Infinity, x /= (x-(x<<((x/(tmp = -3106546671.536726, tmp))/((tmp = 2695710176, tmp)-((((-2102442864)&(857636911.7079853))/x)%(-65640292))))))); + assertEquals(1270005091, x |= (tmp = 1270005091.0081215, tmp)); + assertEquals(1270005091, x %= (tmp = -1833876598.2761571, tmp)); + assertEquals(158750636, x >>>= x); + assertEquals(-1000809106.0879555, x -= (tmp = 1159559742.0879555, tmp)); + assertEquals(72400936, x &= ((2448271389.3097963)%(tmp = 1517733861, tmp))); + assertEquals(282816, x >>= x); + assertEquals(282816, x %= (tmp = 3192677386, tmp)); + assertEquals(0.00021521351827207216, x /= (1314118194.2040696)); + assertEquals(Infinity, x /= (((tmp = 2822091386.1977024, tmp)&x)%(tmp = -3155658210, tmp))); + assertEquals(NaN, x %= (-359319199)); + assertEquals(0, x >>>= (((tmp = -2651558483, tmp)-(x<<(tmp = 2537675226.941645, tmp)))<<(tmp = 667468049.0240343, tmp))); + assertEquals(-0, x *= (tmp = -2827980482.12998, tmp)); + assertEquals(-0, x %= (((tmp = -689972329.3533998, tmp)>>>x)|(tmp = -7488144, tmp))); + assertEquals(0, x >>>= x); + assertEquals(0, x |= x); + assertEquals(-2410373675.2262926, x -= (2410373675.2262926)); + assertEquals(1840423, x >>= ((-1081642113)^x)); + assertEquals(-4829451429403412, x *= (-2624098606.35485)); + assertEquals(-94552231, x %= (tmp = -97015883, tmp)); + assertEquals(-94433287, x ^= (((tmp = -2297735280, tmp)&(((tmp = 2261074987.7072973, tmp)%((((2565078998)^(-2573247878))|x)|(((tmp = -2120919004.7239416, tmp)>>(tmp = -579224101, tmp))>>>(1905808441))))*(x|(3149383322))))>>(542664972))); + assertEquals(0, x ^= (x<<(tmp = -3112569312, tmp))); + assertEquals(0, x <<= (-2141934818.7052917)); + assertEquals(0, x >>= (tmp = -2539525922, tmp)); + assertEquals(-434467613, x ^= (tmp = -434467613, tmp)); + assertEquals(-274792709, x |= (1233452601.462551)); + assertEquals(-274726917, x |= (-2130333750)); + assertEquals(-272629761, x |= (-1516071602.5622227)); + assertEquals(-272629761, x |= ((tmp = 3012131694, tmp)&((tmp = -2595342375.8674774, tmp)-((tmp = -2710765792, tmp)>>>((x-(tmp = 2397845540, tmp))+(2496667307)))))); + assertEquals(-4194305, x |= (1343705633.165825)); + assertEquals(4190207, x >>>= ((tmp = 276587830, tmp)*((tmp = -1517753936, tmp)>>x))); + assertEquals(0, x >>= (x|((2247486919)-((-1664642412.4710495)*((((tmp = -358185292.17083216, tmp)-(tmp = -1472193444, tmp))*(tmp = 2699733752, tmp))&((x|(x<<(1137610148.1318119)))>>(((375089690.8764564)*x)&(tmp = 859788933.9560187, tmp)))))))); + assertEquals(0, x %= (3080673960)); + assertEquals(0, x >>>= (1328846190.1963305)); + assertEquals(1249447579, x |= (-3045519717.580775)); + assertEquals(-0.8743931060971377, x /= (-1428931187)); + assertEquals(1, x |= ((tmp = -1756877535.7557893, tmp)/((-142900015.93200803)<<(1414557031.347334)))); + assertEquals(759627265, x ^= (759627264.0514802)); + assertEquals(741823, x >>= (1106391210)); + assertEquals(610451, x &= ((x>>>((919849416)+((tmp = -427708986, tmp)^((x%x)|(tmp = -2853100288.932063, tmp)))))*x)); + assertEquals(372650423401, x *= x); + assertEquals(410404493, x >>>= ((((-1425086765)>>>x)>>((2813118707.914771)>>(-424850240)))^x)); + assertEquals(120511585729013, x *= ((tmp = -1889454669, tmp)>>>x)); + assertEquals(120513295294304.22, x -= (tmp = -1709565291.2115698, tmp)); + assertEquals(6164, x >>>= ((2244715719.397763)^(tmp = -741235818.6903033, tmp))); + assertEquals(937572790.468221, x -= (tmp = -937566626.468221, tmp)); + assertEquals(937572790, x |= ((2129102867.156146)*(x%x))); + assertEquals(32, x &= ((2700124055.3712993)>>>((1977241506)>>>(-2915605511)))); + assertEquals(32, x %= (tmp = -2513825862, tmp)); + assertEquals(0, x <<= (-1379604802)); + assertEquals(0, x >>>= (tmp = -1033248759, tmp)); + assertEquals(-1151517050, x ^= (3143450246)); + assertEquals(-180577, x |= ((738373819.4081701)^(-357134176))); + assertEquals(-0, x %= x); + assertEquals(-2086887759, x |= (tmp = 2208079537, tmp)); + assertEquals(-2, x >>= (1460216478.7305799)); + assertEquals(-2, x %= ((-1979700249.0593133)^(-3156454032.4790583))); + assertEquals(-256, x <<= ((1810316926)>>>(tmp = 414362256, tmp))); + assertEquals(-1, x >>= (((((((-1616428585.595561)*((tmp = 2574896242.9045777, tmp)|(86659152.37838173)))>>(((tmp = 2476869361, tmp)&((x+((tmp = -2445847462.1974697, tmp)>>(tmp = -1960643509.5255682, tmp)))+(x|(((((2231574372.778028)|(tmp = 1824767560, tmp))>>>((1108035230.2692142)|(tmp = 2354035815, tmp)))/((tmp = -2602922032, tmp)>>(-925080304.7681987)))-x))))-(x>>x)))>>>((tmp = 751425805.8402164, tmp)|(tmp = 1165240270.3437088, tmp)))-x)*(2870745939))-(x>>>((tmp = 2986532631.405425, tmp)>>>(((tmp = 2547448699, tmp)+(((((x<<(((((-2756908638.4197435)>>>(3134770084))-(-1147872642.3756688))%(x*(tmp = -282198341.6600039, tmp)))+(-770969864.2055655)))+((-2725270341)^x))/(-3093925722))>>(x&x))>>((tmp = -2705768192, tmp)>>>(((tmp = 577253091.6042917, tmp)/(((x&(((((x+x)>>>(-1000588972))/(x&(717414336)))^(tmp = 428782104.21504414, tmp))>>>(1084724288.953223)))%(tmp = -2130932217.4562194, tmp))&x))-(-286367389)))))+((x>>(tmp = 2001277117, tmp))>>((tmp = 1028512592, tmp)^((tmp = 2055148650, tmp)+((tmp = 1490798399, tmp)/(tmp = -2077566434.2678986, tmp)))))))))); + assertEquals(-1, x |= (tmp = 1542129482, tmp)); + assertEquals(-671816743, x &= (tmp = -671816743.9111726, tmp)); + assertEquals(-1840333080, x -= (1168516337)); + assertEquals(-1755382023, x |= ((((tmp = 2625163636.0142937, tmp)>>>((tmp = 1534304735, tmp)^x))-(tmp = -1959666777.9995313, tmp))%x)); + assertEquals(-1750421896, x += (x>>>(tmp = -1364828055.1003118, tmp))); + assertEquals(-72864007, x %= (tmp = 239651127, tmp)); + assertEquals(-72863956, x -= (((tmp = -1103261657.626319, tmp)*((tmp = 2789506613, tmp)+((tmp = 2294239314, tmp)>>>(2588428607.5454817))))>>x)); + assertEquals(-170337477, x -= (tmp = 97473521, tmp)); + assertEquals(-170337477, x |= (((tmp = 246292300.58998203, tmp)/(((tmp = -2664407492, tmp)|((-2416228818)^(tmp = 909802077, tmp)))%(tmp = 532643021.68109465, tmp)))/(tmp = 1015597843.8295637, tmp))); + assertEquals(1, x >>>= (((tmp = -2247554641.7422867, tmp)/(1186555294))%(tmp = -785511772.3124621, tmp))); + assertEquals(1188939891.668705, x -= (tmp = -1188939890.668705, tmp)); + assertEquals(1188939891, x &= x); + assertEquals(1188413555, x &= (((tmp = -372965330.5709038, tmp)%(((tmp = 3108909487, tmp)|(x^(-1056955571.9951684)))^(-1549217484.009048)))/(x>>>(1403428437.9368362)))); + assertEquals(-0.7343692094664643, x /= (-1618278026.4758227)); + assertEquals(0, x -= x); + assertEquals(0, x &= (-2701762139.7500515)); + assertEquals(0, x >>>= (((-1692761485.2299166)^x)+(tmp = -1221349575.938864, tmp))); + assertEquals(0, x <<= ((2148160230)<<x)); + assertEquals(0, x <<= (((x<<(-740907931.38363))&(tmp = -930960051.6095045, tmp))>>(x/((tmp = -1921545150.1239789, tmp)/(-3015379806))))); + assertEquals(0, x <<= x); + assertEquals(NaN, x /= (x|x)); + assertEquals(0, x >>= (tmp = -2265988773, tmp)); + assertEquals(-0, x *= (((x<<(-928153614))<<(-989694208))^(2544757713.481016))); + assertEquals(0, x >>= ((tmp = 578009959.5299993, tmp)>>x)); + assertEquals(0, x /= ((((tmp = 412689800.0431709, tmp)&(1630886276))*(tmp = 2028783080.7296097, tmp))/x)); + assertEquals(0, x |= ((((x*(-2197198786))>>((2719887264.761987)<<(tmp = 2253246512, tmp)))-(tmp = -150703768.07045603, tmp))/(((-3160098146)%(((((1486098047.843547)>>(((tmp = -593773744.1144242, tmp)&(x<<(2651087978)))|((-680492758.930413)>>(tmp = 88363052.13662052, tmp))))<<x)<<(tmp = 2232672341, tmp))/((x<<x)&(((((348589117.64135563)<<(-1010050456.3097556))^(x/(tmp = -2282328795, tmp)))-(tmp = 1653716293, tmp))-((3157124731)/((tmp = 3007369535.341745, tmp)%(tmp = -2246556917, tmp)))))))+x))); + assertEquals(0, x >>= ((1935211663.5568764)>>(x-(tmp = 2116580032, tmp)))); + assertEquals(-1725272693, x ^= (tmp = -1725272693, tmp)); + assertEquals(313683, x >>>= (-1782632531.2877684)); + assertEquals(0.009772287443565642, x /= (tmp = 32099240, tmp)); + assertEquals(-647945916.9902277, x += (-647945917)); + assertEquals(3647021380, x >>>= ((((((((2470411371.688199)<<x)>>x)-(x>>>((tmp = 1750747780, tmp)/x)))-x)<<(tmp = -2666186351.695101, tmp))^(((tmp = 2749205312.6666174, tmp)%x)&(2069802830.360536)))<<(tmp = 6051917.9244532585, tmp))); + assertEquals(-647939220, x |= ((x>>>((tmp = -2980404582.794245, tmp)>>>(-996846982)))^x)); + assertEquals(-572178450, x |= ((-800571300.3277931)+(tmp = 2084365671, tmp))); + assertEquals(1172311208, x &= (x&((tmp = -1207487657.8953774, tmp)^x))); + assertEquals(12176516458994, x += ((((tmp = -1534997221, tmp)%(412142731))*((tmp = 2958726303, tmp)>>(1489169839)))+(((-574726407.2051775)>>>(((1772885017)<<(947804536.9958035))>>(-2406844737)))>>x))); + assertEquals(-1480065024, x <<= x); + assertEquals(-1736999042.227129, x += (tmp = -256934018.22712898, tmp)); + assertEquals(-1338699394, x ^= ((((((x%(((tmp = -2551168455.222048, tmp)|(3213507293.930222))/((-1559278033)>>((tmp = 3107774495.3698573, tmp)-(2456375180.8660913)))))*((x*(tmp = 1088820004.8562922, tmp))+((tmp = 1850986704.9836102, tmp)%(tmp = -1226590364, tmp))))*(1786192008))&(((2193303940.310299)%(tmp = 1041726867.0602217, tmp))|((2210722848)/((-1293401295.6714435)&((tmp = 3052430315, tmp)|x)))))>>>(tmp = -2028014470.1524236, tmp))+(((1695818039.0383925)<<((1669068145)*(-2746592133.899276)))<<(tmp = 519092169, tmp)))); + assertEquals(-334674849, x >>= (1170377794)); + assertEquals(-10214, x >>= ((tmp = 1074704264.3712895, tmp)>>>((tmp = -1200860192, tmp)^((tmp = 539325023.4101218, tmp)*((tmp = -588989295, tmp)|x))))); + assertEquals(1384169472, x &= (1384171140)); + assertEquals(1384169472, x >>>= ((tmp = -2161405973.830981, tmp)*(tmp = 2054628644, tmp))); + assertEquals(1610140972, x |= (527961388)); + assertEquals(1073273198, x += ((tmp = -259650225.71344328, tmp)&(tmp = -344359694, tmp))); + assertEquals(65507, x >>= ((x<<((tmp = 2925070713.5245204, tmp)%(x+((tmp = -1229447799, tmp)/(((x/(x|(((-2337139694)|((((((2996268529.7965417)&x)%(((tmp = -1088587413, tmp)>>(-1384104418.90339))>>((tmp = -1643984822.3946526, tmp)+x)))%(((1118125268.4540217)-((((-1975051668.6652594)-(-704573232))+((tmp = 1674952373, tmp)/(tmp = 1321895696.0062659, tmp)))*(tmp = 1820002533.2021284, tmp)))>>>(tmp = -583960746.9993203, tmp)))|((tmp = -2577675508.550925, tmp)&x))/(tmp = 1459790066, tmp)))/(((((1051712301.7804044)&(tmp = -2726396354, tmp))^(tmp = 263937254.18934345, tmp))+(((x^x)*(((tmp = -2289491571, tmp)+x)%(-2239181148)))&x))>>(tmp = -1743418186.3030887, tmp)))))/(tmp = 1475718622, tmp))<<x)))))|(x&((((tmp = -2934707420, tmp)<<x)/x)^(1022527598.7386684))))); + assertEquals(2047, x >>= (x-(tmp = 2300626270, tmp))); + assertEquals(8384512, x <<= (tmp = -1917680820, tmp)); + assertEquals(0, x <<= (2393691134)); + assertEquals(0, x >>= x); + assertEquals(649995936.5853252, x -= (tmp = -649995936.5853252, tmp)); + assertEquals(649995936, x &= x); + assertEquals(-0.33672017582945424, x /= (tmp = -1930374188, tmp)); + assertEquals(-0.33672017582945424, x += (x&((1208055031)^(-2761287670.968586)))); + assertEquals(0, x |= x); + assertEquals(0, x <<= ((-2038368978)/x)); + assertEquals(0, x >>= (x&((tmp = 2481378057.738218, tmp)&(x+(1172701643))))); + assertEquals(0, x <<= ((x*(((((((tmp = 70690601.3046323, tmp)&(((((((((((x+(x+(x^(3118107461))))<<(264682213.41888392))&(tmp = -709415381.8623683, tmp))%(((((-1840054964)>>>(tmp = -405893120.89603686, tmp))|((-625507229)^(3128979265)))>>(x>>((tmp = -2480442390, tmp)*((x>>(tmp = -421414980.88330936, tmp))>>>((tmp = 1850868592, tmp)&(-2948543832.879225))))))|((2986545185)&((tmp = -1947550706, tmp)%(((tmp = 2590238422.1414256, tmp)/(((tmp = -361038812, tmp)>>x)|(((tmp = 1798444068, tmp)|((x&((tmp = -3104542069, tmp)-x))*((tmp = -1158658918, tmp)+((tmp = 2777031040.5552707, tmp)<<(-2816019335.9008327)))))<<x)))/(((2287795988.231702)/x)/(((-2588712925)>>>(2521189250))*((tmp = -2533527920, tmp)+(tmp = 1762281307.2162101, tmp)))))))))/x)/(tmp = 1047121955.5357032, tmp))|(((-121292251)<<(x^(x-(tmp = 1420006180, tmp))))%((-2278606219)>>>(((tmp = -1412487726, tmp)&(((((tmp = 253596554.16016424, tmp)/(tmp = 2083376247.0079951, tmp))^(x^((1549116789.8449988)>>>((((-1844170084)^(tmp = 1886066422, tmp))&x)<<(34918329)))))^(tmp = -440805555.3369155, tmp))-x))%(-1936512969)))))+(2911511178.4035435))|(1012059391))|(x>>>(tmp = -2551794626.158037, tmp)))+((2926596072.210515)/(tmp = -280299595.0450909, tmp))))&((tmp = 1501086971, tmp)^(tmp = 2114076983, tmp)))-((-1679390574.1466925)-(941349044)))-((x>>x)>>((-2600539474.2033434)+(tmp = 2567056503.9079475, tmp))))*(tmp = 1285896052, tmp))%(((tmp = 1191465410.7595167, tmp)>>((tmp = -2857472754, tmp)%x))>>>(((tmp = 1960819627.6552541, tmp)&(-2651207221.127376))*((((-687312743)+((x>>x)<<x))|((((((1549588195)*((tmp = 2733091019, tmp)^((527322540)<<(x>>x))))%(tmp = -2063962943, tmp))*x)*(734060600))&(-3049417708)))+(((((1084267726)+((x|x)^((tmp = -1917070472.4858549, tmp)%((690016078.9375831)*x))))%((((((tmp = -2091172769, tmp)%(2532365378))>>>(-871354260))/(tmp = 254167019.07825458, tmp))&(1330216175.9871218))>>(tmp = 1931099207, tmp)))^(-1116448185.2618852))>>((961660080.8135855)/x)))))))>>>(-1486048007.7053368))); + assertEquals(0, x >>= x); + assertEquals(0, x %= (tmp = -1202200444.6506357, tmp)); + assertEquals(-0, x *= (-527500796.4145117)); + assertEquals(0, x >>= (tmp = -2082822707, tmp)); + assertEquals(0, x *= ((-1882398459.290778)>>>x)); + assertEquals(0, x &= (x/(tmp = -1569332286.392817, tmp))); + assertEquals(-390169607, x |= (-390169607.11600184)); + assertEquals(-780339214, x += x); + assertEquals(-780339214, x %= (2765959073)); + assertEquals(-5954, x >>= (tmp = -1900007055, tmp)); + assertEquals(743563420, x &= ((((-1520146483.5367205)|(-2075330284.3762321))-(tmp = -2263151872, tmp))%(-1264641939.957402))); + assertEquals(1487126840, x += (x>>>(((x+((tmp = -1263274491, tmp)>>>x))&(470419048.0490037))%(tmp = -2642587112, tmp)))); + assertEquals(Infinity, x /= (x^x)); + assertEquals(0, x ^= ((tmp = -1436368543, tmp)+(x/(tmp = -1125415374.3297129, tmp)))); + assertEquals(0, x += x); + assertEquals(0, x <<= x); + assertEquals(0, x &= (tmp = 3101147204.2905564, tmp)); + assertEquals(0, x &= (tmp = 2914487586.606511, tmp)); + assertEquals(0, x += x); + assertEquals(0, x -= (((-1738542908.6138556)&(((x+x)-(tmp = -2801153969, tmp))%(tmp = -1206684064.1477358, tmp)))>>((-2575546469.271897)|(tmp = -2573119106, tmp)))); + assertEquals(-1468808707, x ^= (tmp = -1468808707, tmp)); + assertEquals(1357349882, x <<= (tmp = -2808501087.7003627, tmp)); + assertEquals(-572025862, x |= ((((tmp = -2415486246.573399, tmp)/((tmp = -707895732.4593301, tmp)&x))%((-1960091005.0425267)*(972618070.9166157)))-(1649962343))); + assertEquals(327213586796843100, x *= (x%(1337884626))); + assertEquals(42991616, x &= (-2905576654.1280055)); + assertEquals(-26049289585042860, x *= (-605915571.6557121)); + assertEquals(597809748, x >>= ((362850791.077795)/(tmp = 1222777657.4401796, tmp))); + assertEquals(597809748, x |= x); + assertEquals(770065246, x -= ((-711227660)|(tmp = -508554506, tmp))); + assertEquals(593000483097040500, x *= x); + assertEquals(0, x %= x); + assertEquals(0, x <<= (317862995.456813)); + assertEquals(0, x >>= ((tmp = 2518385735, tmp)+((-2973864605.267604)/(-930953312.718833)))); + assertEquals(1227822411, x ^= (x^(1227822411.8553264))); + assertEquals(1090520320, x &= (x+((((-2100097959)>>(x/(tmp = -2002285068, tmp)))/(-364207954.9242482))-((tmp = 2771293106.7927113, tmp)-(tmp = -847237774, tmp))))); + assertEquals(1090520320, x >>= (((((2439492849)<<((-2932672756.2578926)*((743648426.7224461)+((2942284935)<<((x/(((tmp = 886289462.6565771, tmp)+(-459458622.7475352))>>(tmp = -785521448.4979162, tmp)))|(tmp = -11630282.877367258, tmp))))))-(tmp = -647511106.9602091, tmp))^x)&x)); + assertEquals(115944291.48829031, x %= (243644007.12792742)); + assertEquals(1, x /= x); + assertEquals(0, x >>>= ((tmp = -819782567, tmp)%(tmp = 2774793208.1994505, tmp))); + assertEquals(0, x >>= (tmp = 721096000.2409859, tmp)); + assertEquals(0, x &= ((x%x)%x)); + assertEquals(-0, x *= ((-1670466344)<<x)); + assertEquals(0, x >>= (-677240844.904707)); + assertEquals(NaN, x %= (((((-1575993236.6126876)/(-2846264078.9581823))^((((-2220459664)-(((-1809496020)>>>(tmp = -3015964803.4566207, tmp))&x))/(tmp = -3081895596.0486784, tmp))>>>(x&x)))%(x^(-1338943139)))^(x-((((2074140963.2841332)^(tmp = 1878485274, tmp))%(((x/(-2568856967.6491556))^x)<<((x+x)^((((2139002721)|(x<<(-1356174045.840464)))>>x)-(tmp = 2305062176, tmp)))))>>>(((((x<<(tmp = -1663280319.078543, tmp))-((1498355849.4158854)-((-1321681257)>>>(tmp = -1321415088.6152222, tmp))))^(-2266278142.1584673))+(858538943))&((((x-((x|(((tmp = -1576599651, tmp)+((tmp = 1595319586, tmp)&(-2736785205.9203863)))>>((x+((-1856237826)+x))<<(tmp = -1590561854.3540869, tmp))))^(((-41283672.55606127)&(tmp = 2971132248, tmp))+x)))/(-849371349.1667476))%(x*((-1705070934.6892798)>>>x)))<<((2418200640)*x))))))); + assertEquals(0, x >>>= (tmp = 664214199.5283061, tmp)); + assertEquals(0, x <<= ((-2827299151)<<(1815817649))); + assertEquals(1405772596, x |= (tmp = 1405772596, tmp)); + assertEquals(-1483422104, x <<= (-2791499935.6822596)); + assertEquals(-45271, x >>= (1740128943.4254808)); + assertEquals(-45271, x <<= ((2072269957)-((tmp = -2553664811.4472017, tmp)*(tmp = -2502730352, tmp)))); + assertEquals(1192951471.6745887, x -= (-1192996742.6745887)); + assertEquals(-353370112, x <<= (tmp = -1410280844, tmp)); + assertEquals(0, x ^= (x%((2754092728)*(-1017564599.1094015)))); + assertEquals(-2662096003.2397957, x -= (tmp = 2662096003.2397957, tmp)); + assertEquals(-2587094028.50764, x -= (tmp = -75001974.7321558, tmp)); + assertEquals(6693055512339889000, x *= x); + assertEquals(897526784, x %= (x-((tmp = 897526813, tmp)%(-1525574090)))); + assertEquals(7011928, x >>= ((-440899641.344357)%x)); + assertEquals(8382047686388683, x += (x*(1195398423.8538609))); + assertEquals(16764095372777366, x += x); + assertEquals(16764096859576696, x -= (tmp = -1486799329.7207344, tmp)); + assertEquals(16764099774187724, x += (2914611029)); + assertEquals(16764102926624664, x -= (-3152436939.724612)); + assertEquals(-538220648, x |= x); + assertEquals(269110324, x /= (((-2114698894.6014318)/(tmp = 767687453, tmp))>>(623601568.1558858))); + assertEquals(256, x >>= x); + assertEquals(-293446891, x += (x+(-293447403))); + assertEquals(119, x >>>= ((1759400753)>>(2481263470.4489403))); + assertEquals(14, x >>= (762849027.89693)); + assertEquals(16, x += (x&(x>>(1104537666.1510491)))); + assertEquals(-12499808227.980995, x *= (tmp = -781238014.2488122, tmp)); + assertEquals(1, x /= x); + assertEquals(1, x &= x); + assertEquals(0, x >>>= ((tmp = 1513381008, tmp)|(tmp = 1593208075.7259543, tmp))); + assertEquals(0, x &= (-788154636.2843091)); + assertEquals(-0, x /= (tmp = -2124830879, tmp)); + assertEquals(0, x &= (934237436)); + assertEquals(0, x |= x); + assertEquals(-79370942.97651315, x += (-79370942.97651315)); + assertEquals(-79370942.97651315, x %= ((tmp = -2683255523, tmp)<<(tmp = 2323123280.287587, tmp))); + assertEquals(-79370942, x |= x); + assertEquals(0.05861647801688159, x /= (-1354072177.061561)); + assertEquals(0, x <<= (((((((tmp = 1989257036, tmp)&(tmp = 1565496213.6578887, tmp))&x)&(tmp = -2798643735.905287, tmp))&(2354854813.43784))%(tmp = 1118124748, tmp))<<((tmp = 2453617740, tmp)*(((tmp = 1762604500.492329, tmp)<<(-2865619363))%(((2474193854.640994)|((tmp = 1425847419.6256948, tmp)|(((-1271669386)%((x|((tmp = -2059795445.3607287, tmp)+x))*(x*x)))>>>(tmp = -2997360849.0750895, tmp))))/(tmp = 2326894252, tmp)))))); + assertEquals(0, x >>>= ((-671325215)/((-727408755.8793397)>>(tmp = 315457854, tmp)))); + assertEquals(0, x >>= (x&x)); + assertEquals(0, x <<= ((x/x)>>>(((((x&x)-((x*(((tmp = -2689062497.0087833, tmp)^x)/((-1465906334.9701924)<<(tmp = -349000262, tmp))))*x))%(1630399442.5429945))*x)+((tmp = 605234630, tmp)%(tmp = 2325750892.5065155, tmp))))); + assertEquals(0, x |= (x%((x>>(((((tmp = 1622100459, tmp)<<x)&((((((tmp = 2411490075, tmp)<<x)|x)>>((x<<x)-(-2133780459)))/x)&(x+x)))%(x/((((tmp = 580125125.5035453, tmp)>>>(-470336002.1246581))|((tmp = 871348531, tmp)*x))>>(2866448831.23781))))-((2352334552)-(-562797641.6467373))))-(x^(tmp = -681731388, tmp))))); + assertEquals(0, x <<= (tmp = -1358347010.3729038, tmp)); + assertEquals(-260967814, x |= ((tmp = -260967814.45976686, tmp)%(tmp = 1126020255.1772437, tmp))); + assertEquals(NaN, x %= ((((tmp = 3176388281, tmp)<<(tmp = 611228283.2600244, tmp))>>>((tmp = 3068009824, tmp)+(tmp = 2482705111, tmp)))>>>((tmp = -750778285.2580311, tmp)>>>x))); + assertEquals(0, x <<= (x>>>x)); + assertEquals(0, x /= (1238919162)); + assertEquals(0, x >>= (x^x)); + assertEquals(0, x &= (-2137844801)); + assertEquals(0, x >>>= (x^(x*(-1774217252)))); + assertEquals(0, x >>= x); + assertEquals(0, x |= x); + assertEquals(0, x &= (x<<(tmp = 2791377560, tmp))); + assertEquals(-1330674638.8117397, x += (tmp = -1330674638.8117397, tmp)); + assertEquals(353, x >>>= (-212202857.4320326)); + assertEquals(353, x ^= ((((x+(tmp = 1448262278, tmp))-(-3141272537))>>(tmp = 1116596587.7832575, tmp))>>>((x-(((tmp = 303953098, tmp)>>>((tmp = 691514425, tmp)/((176223098)*(((2876180016)%(-1805235275.892374))|x))))<<(((tmp = 528736141.838547, tmp)^(2556817082))*(2898381286.2846575))))|((-1445518239)&(tmp = 389789481.9604758, tmp))))); + assertEquals(0, x >>>= (-227376461.14343977)); + assertEquals(0, x <<= (tmp = -2575967504, tmp)); + assertEquals(0, x <<= (x^((-2668391896)>>((x+(tmp = 598697235.9205595, tmp))+((((-2105306785)|((-1174912319.794015)>>>(x-((148979923)%((((tmp = -2459140558.4436393, tmp)|(1265905916.494016))^(tmp = 1213922357.2230597, tmp))|(1028030636))))))%x)+(((tmp = 1393280827.0135512, tmp)^((tmp = 1210906638, tmp)+(-1572777641.1396031)))<<x)))))); + assertEquals(0, x *= (tmp = 2134187165, tmp)); + assertEquals(-1084549964, x -= (tmp = 1084549964, tmp)); + assertEquals(-2045706240, x &= ((tmp = -1250758905.7889671, tmp)*(x+(((x<<(x/(tmp = -738983664.845448, tmp)))>>>x)&(tmp = 2197525295, tmp))))); + assertEquals(-2045706240, x ^= (((522049712.14743733)>>(tmp = -2695628092, tmp))>>>(tmp = -2603972068, tmp))); + assertEquals(2249261056, x >>>= x); + assertEquals(-33291, x |= ((((1891467762)<<(184547486.213719))-((458875403.50689447)^(((x&(x*x))|x)%(-3127945140))))|(-100765232))); + assertEquals(-33291, x %= (1460486884.1367688)); + assertEquals(-1, x >>= (tmp = -2667341441, tmp)); + assertEquals(-3.6289151568259606e-10, x /= (tmp = 2755644474.4072013, tmp)); + assertEquals(-3.6289151568259606e-10, x %= (tmp = 1186700893.0751028, tmp)); + assertEquals(0, x <<= (tmp = -1199872107.9612694, tmp)); + assertEquals(371216449, x ^= ((tmp = 371324611.1357789, tmp)&(x-(x|((tmp = -518410357, tmp)>>((tmp = 687379733, tmp)/x)))))); + assertEquals(0.3561383159088311, x /= (((((x%(((((-2293101242)%((((495316779)/x)-((-3198854939.8857965)>>>((tmp = -288916023, tmp)-(x^(tmp = -2504080119.431858, tmp)))))^(-1201674989)))-((2965433901)*(405932927)))/((1974547923)|(tmp = 534069372, tmp)))-(x-((x+(-1258297330))%x))))<<(((-2648166176.4947824)^(-3043930615))&(1550481610)))<<(tmp = -3118264986.743822, tmp))<<x)|x)); + assertEquals(-46272499.15029934, x -= (tmp = 46272499.50643766, tmp)); + assertEquals(-6, x >>= ((tmp = -731454087.0621192, tmp)>>>x)); + assertEquals(-2.7207928474520667e-9, x /= (((x<<(x|((tmp = -1650731700.9540024, tmp)/(tmp = -677823292, tmp))))^((((((1972576122.928667)>>x)%(2952412902.115453))<<((-2888879343)+(tmp = -425663504, tmp)))>>>(((((tmp = 1089969932, tmp)>>>(x|((-2088509661)/(1131470551))))>>>x)+x)|(tmp = 955695979.7982506, tmp)))|(((((tmp = 826954002.6188571, tmp)^(2016485728))|((x/(((x<<(tmp = 2493217141, tmp))/(-2259979800.997408))-(tmp = -427592173.41389966, tmp)))%(((-471172918)/x)>>>((383234436.16425097)&(tmp = 1664411146.5308032, tmp)))))*(tmp = 1863669754.7545495, tmp))*(x>>(2062197604)))))>>>((x-(2624545856))*(tmp = 1025803102, tmp)))); + assertEquals(0, x >>= ((tmp = 1068702028, tmp)*(296106770))); + assertEquals(0, x ^= (x/x)); + assertEquals(85359536, x ^= (((x|(((tmp = 740629227, tmp)<<(-1107397366))%((tmp = 2315368172, tmp)>>(((-2269513683)|(-2698795048))+(-396757976)))))*(929482738.803125))^(((-1415213955.4198723)-(tmp = -2885808324, tmp))>>>((tmp = -472842353.85736656, tmp)&(tmp = 1684231312.4497018, tmp))))); + assertEquals(2075131904, x <<= x); + assertEquals(123, x >>>= (x>>>(tmp = 754093009, tmp))); + assertEquals(0, x >>= ((-2690948145)/((1988638799)+x))); + assertEquals(0, x >>>= (tmp = -798849903.2467625, tmp)); + assertEquals(NaN, x %= x); + assertEquals(NaN, x *= (2431863540.4609756)); + assertEquals(484934656, x |= ((-2322193663)*(tmp = -2754666771, tmp))); + assertEquals(-82505091404694530, x *= (tmp = -170136513, tmp)); + assertEquals(-82505090515370620, x += ((-148762237)&(tmp = 889417717, tmp))); + assertEquals(-908221124, x %= (tmp = -2346393300, tmp)); + assertEquals(-1242515799, x ^= (2083328917)); + assertEquals(-1126056310271520600, x *= ((((tmp = -3065605442, tmp)<<(-3012703413))|x)^(-2081329316.4781387))); + assertEquals(-1126056309941068000, x += ((((tmp = 1886925157, tmp)&((tmp = -163003119.31722307, tmp)/((tmp = 2094816076, tmp)>>((tmp = -706947027, tmp)^x))))^((1819889650.5261197)<<(-1641091933)))>>x)); + assertEquals(-1864360191, x |= (((x/x)|x)|x)); + assertEquals(-1864360191, x &= x); + assertEquals(-3728720382, x += x); + assertEquals(1042663165, x ^= (535165183.4230335)); + assertEquals(2644530017.8833704, x += (1601866852.8833704)); + assertEquals(-574949401, x |= ((tmp = 943193254.5210983, tmp)^((x%(tmp = -2645213497, tmp))*(-1904818769)))); + assertEquals(1763223578, x ^= ((x^(tmp = -2244359016, tmp))^(tmp = 320955522, tmp))); + assertEquals(-1.9640961474334235, x /= (tmp = -897727731.0502782, tmp)); + assertEquals(1, x >>>= (x-(-3183031393.8967886))); + assertEquals(1, x &= (tmp = 1732572051.4196641, tmp)); + assertEquals(1, x >>= (-1642797568)); + assertEquals(-2339115203.3140306, x += (-2339115204.3140306)); + assertEquals(1955852093, x ^= (((((-1469402389)/(-2648643333.1454573))>>>x)<<(x/x))>>x)); + assertEquals(-965322519, x ^= (3001399252)); + assertEquals(-2139727840, x &= (tmp = 2298411812.964484, tmp)); + assertEquals(2103328, x &= (tmp = -2488723009, tmp)); + assertEquals(1799011007, x |= (tmp = -2498057537.226923, tmp)); + assertEquals(1799011007, x |= ((-308193085)>>>x)); + assertEquals(1799011007, x |= x); + assertEquals(818879107, x ^= (1542823996.423564)); + assertEquals(-2601416919234843600, x *= ((-2357923057.076759)-x)); + assertEquals(-2601416920481796600, x -= (x|(tmp = -3048039765, tmp))); + assertEquals(-33690112, x <<= x); + assertEquals(1039491072, x &= (tmp = 1039491474.3389125, tmp)); + assertEquals(126891, x >>= (-3079837011.6151257)); + assertEquals(-163191923097543, x *= (((tmp = -2847221258.4048786, tmp)*(x-(tmp = 1527622853.5925639, tmp)))^x)); + assertEquals(753616551, x ^= (-946895202)); + assertEquals(-347691264, x <<= (tmp = -433184408.33790135, tmp)); + assertEquals(0, x <<= (x|(tmp = -1911731462.6835637, tmp))); + assertEquals(-0, x *= (tmp = -2616154415.1662617, tmp)); + assertEquals(0, x >>= x); + assertEquals(0, x -= x); + assertEquals(0, x *= (2272504250.501526)); + assertEquals(0, x ^= x); + assertEquals(NaN, x %= x); + assertEquals(0, x >>>= (2475346113)); + assertEquals(NaN, x /= (((x+(-2646140897))&(((tmp = 1039073714.142481, tmp)-x)*x))|(x*(((-1277822905.773948)>>(tmp = 2035512354.2400663, tmp))*(77938193.80013895))))); + assertEquals(0, x ^= (x<<(tmp = 2491934268, tmp))); + assertEquals(0, x &= (tmp = 569878335.4607931, tmp)); + assertEquals(-88575883, x ^= ((453890820.8012209)-((1569189876)%((-1280613677.7083852)^(-1902514249.29567))))); + assertEquals(-88575883, x %= (tmp = 257947563.19206762, tmp)); + assertEquals(-88575881.7863678, x -= ((tmp = 1257547359.029678, tmp)/(x^(tmp = 948265672.821815, tmp)))); + assertEquals(-169, x >>= (tmp = -2530523309.6703596, tmp)); + assertEquals(-1, x >>= x); + assertEquals(-1, x |= x); + assertEquals(131071, x >>>= (-673590289)); +} +f(); diff --git a/deps/v8/test/mjsunit/numops-fuzz-part3.js b/deps/v8/test/mjsunit/numops-fuzz-part3.js new file mode 100644 index 0000000000..7813f91820 --- /dev/null +++ b/deps/v8/test/mjsunit/numops-fuzz-part3.js @@ -0,0 +1,1178 @@ +// 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. + +function f() { + var x = 131071; + var tmp = 0; + assertEquals(1117196836, x -= (-1117065765)); + assertEquals(3092236000.7125187, x -= (-1975039164.7125185)); + assertEquals(1, x /= x); + assertEquals(-1599945863, x ^= (tmp = 2695021432.453696, tmp)); + assertEquals(940543782, x ^= (tmp = 2561494111, tmp)); + assertEquals(891400321673221800, x *= (tmp = 947749949.2662871, tmp)); + assertEquals(-1509927296, x >>= ((tmp = 1113290009, tmp)-x)); + assertEquals(-23, x >>= (tmp = 3216989626.7370152, tmp)); + assertEquals(-0, x %= x); + assertEquals(0, x <<= (431687857.15246475)); + assertEquals(-0, x /= (tmp = -1924652745.081665, tmp)); + assertEquals(0, x <<= (1312950547.2179976)); + assertEquals(0, x %= ((tmp = 2110842937.8580878, tmp)|(x<<x))); + assertEquals(0, x >>>= ((((-386879000)-((tmp = -2334036143.9396124, tmp)/((tmp = 965101904.2841234, tmp)<<(((3029227182.8426695)<<((tmp = -464466927, tmp)>>((((((tmp = 849594477.4111787, tmp)^(x&((513950657.6663146)%(x>>>x))))-((2898589263)|x))+(tmp = 2842171258.621288, tmp))>>>(tmp = -3158746843, tmp))<<(tmp = -2891369879, tmp))))-(x-(x&(tmp = -1707413686.2706504, tmp)))))))-(-2860419051))*(-1708418923))); + assertEquals(-328055783, x += ((((2857010474.8010874)|((tmp = -1415997622.320347, tmp)-(-1706423374)))%(tmp = 824357977.1339042, tmp))^(x>>(x|x)))); + assertEquals(-168539902503779140, x *= ((tmp = -1057687018, tmp)<<((1408752963)-(2030056734)))); + assertEquals(-Infinity, x /= ((x-(2232683614.320658))*(((tmp = 195551174, tmp)*((((739595970)>>>(tmp = -2218890946.8788786, tmp))>>>(((tmp = -240716255.22407627, tmp)&(((((1598029916.3478878)|((tmp = -881749732, tmp)+(x>>x)))^(4443059))<<(((tmp = 2453020763, tmp)+((x>>>(tmp = -1904203813, tmp))&(-355424604.49235344)))<<(tmp = 2814696070, tmp)))%((tmp = -250266444, tmp)>>>(((((2710614972)&(((tmp = 910572052.6994087, tmp)^(tmp = -1028443184.3220406, tmp))/((-2718010521)^(tmp = 676361106, tmp))))|x)^(-1326539884))>>(-1573782639.7129154)))))/(tmp = 1923172768, tmp)))>>>(tmp = -2858780232.4886074, tmp)))/((((((-2060319376.353397)%x)>>(tmp = -3122570085.9065285, tmp))/(tmp = -1499018723.8064275, tmp))*((-655257391)<<x))>>x)))); + assertEquals(NaN, x += ((3059633304)%((((tmp = 2538190083, tmp)*((tmp = -2386800763.356364, tmp)/x))&(1341370996))%(-2929765076.078223)))); + assertEquals(NaN, x %= ((x&(347774821))>>>(462318570.2578629))); + assertEquals(NaN, x *= ((2829810152.071517)*(tmp = 768565684.6892327, tmp))); + assertEquals(NaN, x -= x); + assertEquals(0, x >>>= (x&(tmp = 1786182552, tmp))); + assertEquals(973967377, x ^= ((tmp = 2115869489.836838, tmp)&(994956497))); + assertEquals(985246427.4230617, x += (11279050.423061728)); + assertEquals(985246427, x &= x); + assertEquals(0, x >>= ((tmp = 1090502660.1867907, tmp)>>((-1599370623.5747645)-(tmp = -1321550958, tmp)))); + assertEquals(0, x %= (tmp = -2386531950.018572, tmp)); + assertEquals(0, x >>>= x); + assertEquals(NaN, x /= x); + assertEquals(0, x >>>= (tmp = -1535987507.682257, tmp)); + assertEquals(-0, x /= (-2570639987)); + assertEquals(-542895632, x |= (tmp = -542895632, tmp)); + assertEquals(-33930977, x >>= (tmp = -861198108.1147206, tmp)); + assertEquals(-0, x %= x); + assertEquals(0, x ^= (x*(-608154714.1872904))); + assertEquals(-140011520, x |= ((tmp = 377418995, tmp)<<((1989575902)>>(tmp = -2558458031.066773, tmp)))); + assertEquals(-140026048, x -= ((((tmp = 1465272774.7540011, tmp)<<((2164701398)<<(tmp = -818119264, tmp)))>>((tmp = -1490486001, tmp)>>(664410099.6412607)))>>(x>>>(((tmp = -2438272073.2205153, tmp)%(tmp = 2142162105.4572072, tmp))-(tmp = 2259040711.6543813, tmp))))); + assertEquals(39214588236996610, x *= (x<<(-401696127.06632423))); + assertEquals(1, x /= x); + assertEquals(0, x %= x); + assertEquals(0, x *= ((tmp = -1709874807.176726, tmp)&(-2786424611))); + assertEquals(-1320474063.3408537, x += (tmp = -1320474063.3408537, tmp)); + assertEquals(88, x >>>= (tmp = -3179247911.7094674, tmp)); + assertEquals(1606348131, x += ((tmp = 1555621121.5726175, tmp)|(-3026277110.9493155))); + assertEquals(200793516, x >>>= x); + assertEquals(-2952688672.1074514, x -= (tmp = 3153482188.1074514, tmp)); + assertEquals(1342278624, x >>>= ((x>>>((tmp = 1264475713, tmp)-(-913041544)))>>>((tmp = 2008379930, tmp)%(tmp = 3105129336, tmp)))); + assertEquals(0, x ^= x); + assertEquals(0, x /= (tmp = 788363717, tmp)); + assertEquals(430466213, x -= (tmp = -430466213, tmp)); + assertEquals(164757385222499550, x *= (tmp = 382741735, tmp)); + assertEquals(164757385222499550, x %= (((tmp = 1974063648, tmp)%((806015603)>>>x))*((tmp = 2836795324, tmp)<<(tmp = -1785878767, tmp)))); + assertEquals(-190957725.86956096, x /= (x^((-2939333300.066044)-(x|(-2085991826))))); + assertEquals(-190957725.86956096, x %= (tmp = -948386352, tmp)); + assertEquals(0.6457336106922105, x /= (-295722141)); + assertEquals(0, x |= ((415991250)&((x>>(tmp = -3188277823, tmp))<<(511898664.1008285)))); + assertEquals(0, x &= ((793238922)|x)); + assertEquals(-1576701979, x ^= (2718265317)); + assertEquals(-49271937, x >>= x); + assertEquals(-49271937, x |= x); + assertEquals(-49271937, x &= x); + assertEquals(775316382, x -= (-824588319)); + assertEquals(912498176, x <<= (tmp = -2223542776.836312, tmp)); + assertEquals(0, x -= (x&((tmp = 1999412385.1074471, tmp)/(-1628205254)))); + assertEquals(0, x -= x); + assertEquals(0, x >>= (-768730139.7749677)); + assertEquals(-1861304245, x |= (((5128483)^(((tmp = -1768372004, tmp)/(x^(tmp = 1310002444.757094, tmp)))*((tmp = 188242683.09898067, tmp)^(tmp = -2263757432, tmp))))^((tmp = 2223246327, tmp)*((tmp = -2360528979, tmp)-((tmp = 2442334308, tmp)>>(458302081)))))); + assertEquals(1, x /= x); + assertEquals(2, x += x); + assertEquals(1, x /= x); + assertEquals(0, x ^= x); + assertEquals(-0, x *= (-1852374359.3930533)); + assertEquals(0, x <<= (tmp = 1223645195.148961, tmp)); + assertEquals(1789655087, x |= ((-2505312209.770559)>>x)); + assertEquals(-65568768, x <<= x); + assertEquals(4229398528, x >>>= x); + assertEquals(-8408187, x |= (-3029781627)); + assertEquals(-8408187, x |= (((2322165037)-((tmp = -1424506897.362995, tmp)%x))&x)); + assertEquals(-7884926, x += (x>>>(x|(2738095820)))); + assertEquals(-7884926, x %= (576507013)); + assertEquals(751801768, x ^= (tmp = -750241238, tmp)); + assertEquals(-1986010067668600800, x *= (tmp = -2641667195, tmp)); + assertEquals(1921196240, x ^= (x%(-1954178308))); + assertEquals(847388880, x ^= ((tmp = 1632856124, tmp)&((tmp = -1536309755, tmp)<<(tmp = -3158362800, tmp)))); + assertEquals(-469662000.6651099, x += (tmp = -1317050880.6651099, tmp)); + assertEquals(-812358332, x ^= ((-2832480471)>>>(2016495937))); + assertEquals(21, x ^= (((tmp = 1815603134.2513008, tmp)/((tmp = 147415927, tmp)%(-1059701742)))+x)); + assertEquals(-2844409139.792712, x += (tmp = -2844409160.792712, tmp)); + assertEquals(177070, x >>>= x); + assertEquals(0, x %= x); + assertEquals(0, x >>= x); + assertEquals(1459126376, x ^= (tmp = -2835840920, tmp)); + assertEquals(1459126376, x %= (-1462864282)); + assertEquals(0, x >>>= (tmp = 2922724319, tmp)); + assertEquals(338995506, x ^= (338995506.6411549)); + assertEquals(336896258, x &= (2635904967)); + assertEquals(336634112, x -= (x&(tmp = 1659656287, tmp))); + assertEquals(NaN, x %= (x-x)); + assertEquals(NaN, x /= (tmp = -674606200, tmp)); + assertEquals(NaN, x %= ((x|(2788108542))/(x+(tmp = 600941473, tmp)))); + assertEquals(0, x >>>= ((-1858251597.3970242)>>>x)); + assertEquals(1951294747, x |= (tmp = 1951294747, tmp)); + assertEquals(1951294747, x &= x); + assertEquals(-153190625, x |= (-1500095737)); + assertEquals(23467367587890624, x *= x); + assertEquals(346531290.1813514, x /= (((((-513617734.11148167)|x)/((tmp = -2042982150.1170752, tmp)%((x%((x%x)>>>(((-1369980151)&(((922678983)%(x&(tmp = -855337708, tmp)))-((tmp = -2717183760, tmp)>>>((1939904985.4701347)%(((tmp = -2473316858, tmp)&((tmp = -599556221.9046664, tmp)>>((tmp = -6352213, tmp)/x)))&x)))))%x)))/((tmp = -1842773812.8648412, tmp)>>>(((x>>>(tmp = 499774063, tmp))<<(((tmp = -1353532660.5755146, tmp)*(-3070956509))>>(((-905883994.0188017)>>(tmp = -16637173, tmp))<<((tmp = 471668537, tmp)*((tmp = -232036004.26637793, tmp)/x)))))&(tmp = 85227224, tmp))))))>>>(x|(-2528471983)))-((tmp = 1531574803, tmp)+((x>>>x)-(2889291290.158888))))); + assertEquals(-94.42225749399837, x /= (((tmp = 2381634642.1432824, tmp)>>(tmp = -2637618935, tmp))|(2307200473))); + assertEquals(-47, x >>= (1524333345.141235)); + assertEquals(-2.8699253616435082e-8, x /= (1637673252)); + assertEquals(0, x |= x); + assertEquals(1083427040, x += ((-2012055268)<<(tmp = -2192382589.6911573, tmp))); + assertEquals(1083427040, x %= (x*x)); + assertEquals(2694039776, x += ((((-1740065704.9004602)<<(-736392934))%(2781638048.424092))>>>(x&x))); + assertEquals(-1600927520, x |= ((tmp = 2904430054.869525, tmp)*(((1054051883.4751332)*x)*((-939020743)-(tmp = 1636935481.1834455, tmp))))); + assertEquals(-1600927520, x -= (x%x)); + assertEquals(3037584978216498700, x *= (tmp = -1897390694, tmp)); + assertEquals(372598954.1823988, x %= (tmp = 1553763703.5082102, tmp)); + assertEquals(-1476395008, x <<= ((x>>((tmp = 282496335.49494267, tmp)^((-1948623419.6947453)|((((((tmp = -1203306995, tmp)-(-5554612.355098486))>>>(1867254951.4836824))>>x)|(-695777865))/((-59122652.19377303)<<(-609999229.7448442))))))>>(x/(tmp = -1207010654.9993455, tmp)))); + assertEquals(-2.2540185787941605, x /= (((tmp = 1364159859.9199843, tmp)*x)>>x)); + assertEquals(-2, x |= x); + assertEquals(2241824008, x *= ((3174055292.962967)>>(((-2379151623.602476)>>(tmp = -1423760236, tmp))>>(tmp = -522536019.2225733, tmp)))); + assertEquals(-2138158385, x ^= ((x>>((((1316131966.9180691)-((x*x)>>x))>>>x)>>((-2712430284)|(((((x<<(-616185937.6090865))-(((x-(tmp = 2957048661, tmp))<<(tmp = 617564839.888214, tmp))/(x%((tmp = -447175647.9393475, tmp)<<(2203298493.460617)))))-((x&((x<<(914944265))^(((-1294901094)*((tmp = 2512344795, tmp)+((((tmp = -1227572518, tmp)%(1831277766.4920158))*((x|x)^(tmp = 2515415182.6718826, tmp)))*x)))-(961485129))))>>>(tmp = 2079018304, tmp)))>>(tmp = 734028202, tmp))^(554858721.6149715)))))-((tmp = 1312985279.5114603, tmp)^(tmp = 2450817476.179955, tmp)))); + assertEquals(2.759030298237921, x /= (x|(tmp = -775901745.3688724, tmp))); + assertEquals(8, x <<= x); + assertEquals(NaN, x %= (((x&((1792031228.831834)>>(-1174912501)))%(((-2351757750)+(tmp = -2610099430, tmp))*(-2811655968)))*(x&(tmp = -1881632878, tmp)))); + assertEquals(0, x &= ((x*(616116645.7508612))^(2789436828.536846))); + assertEquals(0, x *= x); + assertEquals(35097452, x ^= ((tmp = 1023684579, tmp)%(((x|((tmp = -757953041, tmp)+(772988909)))+(tmp = -2934577578, tmp))>>>((tmp = -1973224283, tmp)>>>((x*(2244818063.270375))|(x-(-716709285))))))); + assertEquals(0.015207441433418992, x /= (2307913014.4056892)); + assertEquals(-5865042.942076175, x -= (5865042.957283616)); + assertEquals(-67719.94207617454, x %= (((1464126615.2493973)+(398302030.0108756))>>>x)); + assertEquals(4294899577, x >>>= (x<<x)); + assertEquals(-1, x >>= (tmp = 607447902, tmp)); + assertEquals(-1, x >>= (3081219749.9119744)); + assertEquals(6.53694303504065e-10, x /= (tmp = -1529767040.4034374, tmp)); + assertEquals(6.53694303504065e-10, x %= ((tmp = 899070650.7190754, tmp)&(tmp = -1101166301, tmp))); + assertEquals(6.53694303504065e-10, x %= (tmp = -2207346460, tmp)); + assertEquals(NaN, x %= (((x&x)>>x)%(((-10980184)+x)&(tmp = -1473044870.4729445, tmp)))); + assertEquals(NaN, x -= x); + assertEquals(-1755985426, x ^= (tmp = 2538981870, tmp)); + assertEquals(-13842, x %= ((((-2258237411.3816605)+(-1325704332.0531585))<<((tmp = -877665450.1877053, tmp)>>(((((2420989037)+(2084279990.6278818))*(-327869571.9348242))+x)^x)))>>>x)); + assertEquals(1, x /= x); + assertEquals(1, x >>= ((2241312290)^(2859250114))); + assertEquals(0, x >>= x); + assertEquals(-1615631756, x |= (-1615631756.1469975)); + assertEquals(-1615631756, x |= x); + assertEquals(-627245056, x <<= ((x*(tmp = -1308330685.5971081, tmp))|(tmp = 1479586158, tmp))); + assertEquals(-627245056, x |= x); + assertEquals(1786953888, x ^= (-1340096352.1839824)); + assertEquals(1668014353, x -= (tmp = 118939535, tmp)); + assertEquals(1, x /= x); + assertEquals(-645681, x ^= ((-1322356629)>>(tmp = 1829870283, tmp))); + assertEquals(-1322354688, x <<= (-794779253)); + assertEquals(-4310084378.672725, x += (-2987729690.6727247)); + assertEquals(-8620168757.34545, x += x); + assertEquals(-8720421, x |= (tmp = -748107877.6417065, tmp)); + assertEquals(-1508858270, x ^= (1500137913)); + assertEquals(-0.825735756765112, x /= (1827289490.1767085)); + assertEquals(1253449509.1742642, x += (((tmp = 1253449509.9576545, tmp)-(((tmp = 2860243975, tmp)+(367947569.85976696))>>(((((530960315)>>>((((x%(tmp = -2203199228, tmp))<<(x*(((tmp = -117302283, tmp)/(x-((2579576936)%(-1225024012))))&(tmp = -2857767500.1967726, tmp))))/((x/((tmp = -166066119, tmp)<<x))|x))>>>x))|(((2771852372)>>(((tmp = -3103692094.1463976, tmp)-(tmp = 2867208546.069278, tmp))>>>(702718610.1963737)))|(tmp = 2680447361, tmp)))>>x)>>(-2006613979.051014))))^((-1665626277.9339101)/(x<<(tmp = 342268763, tmp))))); + assertEquals(1693336701.1742642, x += (tmp = 439887192, tmp)); + assertEquals(0.8479581831275719, x /= ((1171383583)+(((x&x)>>>(51482548.618915915))-(tmp = -825572595.1031849, tmp)))); + assertEquals(28, x |= ((tmp = -2355932919.6737213, tmp)>>(tmp = -2395605638, tmp))); + assertEquals(0, x %= x); + assertEquals(0, x -= x); + assertEquals(0, x <<= (x^((tmp = 2793423893.484949, tmp)*(1585074754.3250475)))); + assertEquals(0, x >>= (x/(x-((957719861.9175875)&(1288527195))))); + assertEquals(0, x >>>= ((-1429196921.4432657)/x)); + assertEquals(-852424225.734199, x -= (tmp = 852424225.734199, tmp)); + assertEquals(-46674433, x |= ((tmp = -2335242963, tmp)*((2135206646.2614377)>>(tmp = 505649511.8292929, tmp)))); + assertEquals(2944662357, x += (tmp = 2991336790, tmp)); + assertEquals(1404, x >>>= (849155189.1503456)); + assertEquals(-846755170, x ^= (tmp = -846753822.4471285, tmp)); + assertEquals(52615, x >>>= ((-517068110)+x)); + assertEquals(1475021859.9916897, x += (tmp = 1474969244.9916897, tmp)); + assertEquals(0, x %= x); + assertEquals(0, x %= ((539583595.8244679)*(tmp = 1469751690.9193692, tmp))); + assertEquals(0, x &= (807524227.2057163)); + assertEquals(NaN, x %= x); + assertEquals(NaN, x -= (x^((tmp = -362481588, tmp)%(2611296227)))); + assertEquals(NaN, x *= x); + assertEquals(0, x >>= ((-2519875630.999908)<<x)); + assertEquals(NaN, x %= x); + assertEquals(NaN, x += (((tmp = 2485209575, tmp)>>(tmp = 2326979823, tmp))%(x-(((-1296334640.7476478)&x)<<x)))); + assertEquals(0, x >>= (((tmp = 1370704131, tmp)^((((tmp = 793217372.7587746, tmp)>>(((-1455696484.109328)|(((((-2186284424.5379324)<<(tmp = 3052914152.254852, tmp))-(x>>(tmp = 3121403408, tmp)))+((778194280)-(((((tmp = 2398957652, tmp)-(x+(((-2592019996.937958)>>((tmp = 1648537981, tmp)>>x))<<(-677436594))))<<(39366669.09012544))|((tmp = 3133808408.9582872, tmp)-(-2987527245.010673)))*x)))|((tmp = -2178662629, tmp)<<x)))^(((tmp = 909652440.3570575, tmp)%(-2572839902.6852217))%(-1879408081))))*(tmp = -2910988598, tmp))&(((x^x)>>(2822040993))|((x*x)^(((1072489842.6785052)|(x-(((464054192.7390214)^x)<<(tmp = -2754448095, tmp))))*((tmp = -1544182396, tmp)/(tmp = -3198554481, tmp)))))))^(tmp = 1946162396.9841106, tmp))); + assertEquals(371272192, x |= (((x^((x-(x/x))&(tmp = 2370429394, tmp)))-(tmp = -403692829, tmp))*(tmp = 2808636109, tmp))); + assertEquals(929786482, x |= ((729966239.8987448)^(x-((tmp = 120127779, tmp)^((tmp = -3088531385, tmp)>>>((x+((tmp = 2364833601, tmp)>>>(((599149090.6666714)>>(tmp = 2838821032, tmp))%(tmp = -662846011, tmp))))-(tmp = 1168491221.1813436, tmp))))))); + assertEquals(-681121542, x += ((-1610909505.998718)^((tmp = -957338882, tmp)>>>(tmp = 1935594133.6531684, tmp)))); + assertEquals(-2147483648, x <<= ((tmp = 15161708, tmp)|(2453975670))); + assertEquals(-2147483648, x >>= x); + assertEquals(0, x <<= (2080486058)); + assertEquals(0, x &= (((x&(tmp = -767821326, tmp))/((tmp = 1877040536, tmp)>>>(tmp = 2378603217.75597, tmp)))*(-1601799835))); + assertEquals(0, x %= (-1820240383)); + assertEquals(1621233920, x ^= ((tmp = 820230232, tmp)*(1727283900))); + assertEquals(1621233920, x |= (x>>>x)); + assertEquals(1621233931, x += ((tmp = 794966194.9011587, tmp)>>(tmp = -597737830.5450518, tmp))); + assertEquals(1621276543, x |= (((x^((2354444886)+(tmp = 685142845.4708651, tmp)))-(tmp = 790204976.9120214, tmp))>>>((((tmp = -2792921939, tmp)/(((((tmp = -80705524, tmp)<<x)-(((((((tmp = 1951577216.379527, tmp)>>>x)%((-529882150)>>>(tmp = -1682409624, tmp)))<<((-42043756.29025769)-(-1803729173.6855814)))/(2937202170.118023))*(tmp = -1998098798.5722106, tmp))*(tmp = -2996229463.904228, tmp)))&x)>>>(-301330643)))/(-2858859382.0050273))-(tmp = 1571854256.0740635, tmp)))); + assertEquals(810638271, x >>>= (x/(1553632833))); + assertEquals(810638271, x <<= (tmp = -1467397440, tmp)); + assertEquals(-2147483648, x <<= x); + assertEquals(871068871, x ^= (tmp = 3018552519, tmp)); + assertEquals(-1073743881, x |= ((tmp = 2294122324.020989, tmp)|(tmp = -1799706842.4493146, tmp))); + assertEquals(-77816868, x += (((-2225296403)&x)>>(tmp = -2667103424.445239, tmp))); + assertEquals(-1215889, x >>= (tmp = 1876107590.8391647, tmp)); + assertEquals(-2431778, x += x); + assertEquals(4292535518, x >>>= (((x>>(-1825580683))/x)%x)); + assertEquals(4292802560, x -= (x|(1492864090))); + assertEquals(0, x -= x); + assertEquals(0, x >>= x); + assertEquals(0, x %= (tmp = 2173121205, tmp)); + assertEquals(0, x *= (x>>x)); + assertEquals(1565261471, x |= ((1565261471.323931)>>>x)); + assertEquals(0, x -= x); + assertEquals(-86980804, x |= (-86980804)); + assertEquals(-698956484, x -= (((((2754713793.1746016)*(((((-1514587465.0698888)>>(tmp = -1307050817, tmp))/(tmp = 2368054667.438519, tmp))*(-1908125943.5714772))<<(x>>>(-357164827.4932244))))+(1257487617))<<(2954979945))&(612330472))); + assertEquals(-1073741824, x <<= x); + assertEquals(54497747, x ^= (-1019244077.098908)); + assertEquals(54501375, x |= (((tmp = 1944912427, tmp)>>>x)%x)); + assertEquals(0, x -= x); + assertEquals(0, x -= x); + assertEquals(-0, x *= (-1748215388)); + assertEquals(0, x >>= x); + assertEquals(0, x >>>= (((tmp = 988769112, tmp)%(tmp = -3133658477, tmp))<<x)); + assertEquals(0, x %= (1685221089.2950323)); + assertEquals(0, x >>>= (x+((793467168)-(tmp = 135877882, tmp)))); + assertEquals(0, x %= ((tmp = -2406801984, tmp)%(tmp = -987618172, tmp))); + assertEquals(0, x *= ((-2943444887.953456)|(tmp = -2327469738.4544783, tmp))); + assertEquals(0, x >>= x); + assertEquals(-145484729.70167828, x += (tmp = -145484729.70167828, tmp)); + assertEquals(1140855872, x &= (x^(tmp = 3151437967.965556, tmp))); + assertEquals(1486808408, x += (tmp = 345952536, tmp)); + assertEquals(107846582.36594129, x %= (-1378961825.6340587)); + assertEquals(-642031616, x <<= (x+x)); + assertEquals(151747770.95108718, x *= (x/(tmp = 2716379907, tmp))); + assertEquals(192723456, x <<= (tmp = -1731167384, tmp)); + assertEquals(2151208003, x -= ((-2151208003)+x)); + assertEquals(1, x /= x); + assertEquals(1, x |= x); + assertEquals(1996766603, x |= (1996766602)); + assertEquals(895606123, x ^= (tmp = 1113972960.966081, tmp)); + assertEquals(-1500036886, x ^= (tmp = 2482412929, tmp)); + assertEquals(-1542644247, x ^= (x>>>((tmp = 51449105, tmp)>>>(((-2057313176)*x)/(-1768119916))))); + assertEquals(-1496074063273093600, x *= ((tmp = 786152274, tmp)^(387292498))); + assertEquals(-794329073, x %= (((tmp = -2314637675.617696, tmp)*((((x*(411053423.29070306))-(2889448433.4240828))/((-970630131)/(tmp = -2886607600.7423067, tmp)))<<(tmp = 1263617112.9362245, tmp)))|(2816980223.8209996))); + assertEquals(2468008436047106600, x *= (tmp = -3107035257.725115, tmp)); + assertEquals(3040956928, x >>>= ((tmp = 1514372119.1787262, tmp)*(3169809008))); + assertEquals(-19, x >>= (tmp = -266966022.10604453, tmp)); + assertEquals(-1.6505580654964654e-8, x /= ((-3143841480)>>(x-x))); + assertEquals(-2.2420284729165577e-7, x *= (x*((((703414102.2523813)%(tmp = 2989948152, tmp))-((-1583401827.2949386)^((tmp = -1916731338, tmp)%((331500653.3566053)|(((tmp = 29865940, tmp)+((tmp = -2294889418.6764183, tmp)<<(tmp = -1558629267.255229, tmp)))>>>(x*(x+x)))))))|((988977957)&(-2986790281))))); + assertEquals(0, x ^= (x/(tmp = 781117823.345541, tmp))); + assertEquals(NaN, x *= (((x^((((tmp = -2969290335, tmp)+(((((tmp = -175387021, tmp)&(tmp = -1080807973, tmp))<<(tmp = -2395571076.6876855, tmp))|((tmp = -1775289899.4106793, tmp)^x))|(-2963463918)))*(tmp = -1761443911, tmp))^(tmp = 847135725, tmp)))<<((146689636)<<x))%x)); + assertEquals(0, x ^= x); + assertEquals(1720182184, x -= (((tmp = 3184020508, tmp)|((-489485703)+(tmp = -2644503573, tmp)))&(tmp = 2575055579.6375213, tmp))); + assertEquals(1720182184, x >>= (x<<(-45408034))); + assertEquals(5.759243187540471e+27, x *= (((x&(1456298805))+(x<<(106573181)))*((566861317.2877743)+(2262937360.3733215)))); + assertEquals(5.759243187540471e+27, x -= (tmp = -1365873935, tmp)); + assertEquals(0, x <<= x); + assertEquals(0, x >>= (1960073319.3465362)); + assertEquals(0, x <<= x); + assertEquals(560463904, x += ((tmp = 1844076589.9286406, tmp)&((((((-691675777.5800121)|(-745631201))|x)+(tmp = 1504458593.2843904, tmp))-x)<<x))); + assertEquals(-513210271, x -= (x|(1052702623.7761713))); + assertEquals(3781757025, x >>>= ((-1346666404.362477)*(tmp = 2798191459, tmp))); + assertEquals(1080100929, x &= (1122097879.882534)); + assertEquals(1276833905.8093092, x *= ((1276833905.8093092)/x)); + assertEquals(1276833905.8093092, x %= (1796226525.7152414)); + assertEquals(1276833905, x <<= (((tmp = -491205007.83412814, tmp)*(tmp = 1496201476.496839, tmp))>>(x+((tmp = -854043282.114594, tmp)-((x|(tmp = -807842056, tmp))*x))))); + assertEquals(1276833905, x %= (((-1870099318)>>>(((tmp = -2689717222, tmp)/(248095232))/(tmp = 1036728800.5566598, tmp)))&(((((857866837)>>(tmp = 3034825801.740485, tmp))|(-1676371984))>>>(x<<x))%((-3035366571.0221004)*(1578324367.8819473))))); + assertEquals(1, x /= x); + assertEquals(2819223656.189109, x += (2819223655.189109)); + assertEquals(-1475743640, x >>= (((tmp = 2586723314.38089, tmp)/(x&(tmp = -697978283.9961061, tmp)))<<(x%((-1167534676)>>(x^((tmp = -284763535, tmp)*((x%x)&((((tmp = 2916973220.726839, tmp)%x)/(tmp = -1338421209.0621986, tmp))|((tmp = -834710536.803335, tmp)%x))))))))); + assertEquals(-3267683406, x -= (tmp = 1791939766, tmp)); + assertEquals(-2090420900700614100, x *= (639725653)); + assertEquals(-1540353536, x %= ((-1800269105)<<((((x&(((tmp = 1135087416.3945065, tmp)^(613708290))>>x))>>(tmp = -1234604858.7683473, tmp))^(2404822882.7666225))>>>((tmp = -287205516, tmp)-((1648853730.1462333)^((x+(x%((tmp = 359176339, tmp)%((2856479172)<<(tmp = -1995209313, tmp)))))^(((tmp = 2857919171.839304, tmp)>>>(tmp = 2779498870, tmp))>>x))))))); + assertEquals(-2093767030, x ^= (654554250.498078)); + assertEquals(1, x >>>= ((tmp = -166296226.12181997, tmp)^(x/x))); + assertEquals(-1487427474, x -= ((x<<x)|(1487427475.4063978))); + assertEquals(-1487427470.562726, x += ((-1226399959.8267038)/((tmp = 2172365551, tmp)<<x))); + assertEquals(-3457859227618939400, x *= (tmp = 2324724597.3686075, tmp)); + assertEquals(396221312, x >>= (-1354035390)); + assertEquals(0, x %= x); + assertEquals(0, x &= (tmp = 2733387603, tmp)); + assertEquals(1485905453, x |= ((((tmp = -1321532329.304437, tmp)&((((tmp = 1817382709.4180388, tmp)%(((tmp = 2089156555.7749293, tmp)-(-1555460267))|(tmp = 717392475.9986715, tmp)))%(tmp = 1976713214, tmp))^x))>>>x)+(tmp = -2812404197.002721, tmp))); + assertEquals(1485905453, x |= x); + assertEquals(-997658264, x <<= (-1409757949.6038744)); + assertEquals(-997657290, x -= ((-2041106361)>>(tmp = -2014750507, tmp))); + assertEquals(-2138512124, x &= (tmp = 2565597060, tmp)); + assertEquals(8422400, x &= ((-2819342693.5172367)*(tmp = 1441722560, tmp))); + assertEquals(111816531.81703067, x -= (-103394131.81703067)); + assertEquals(59606682.673836395, x *= ((tmp = -1451690098, tmp)/(x-(2835050651.717734)))); + assertEquals(-119213365.34767279, x *= (x|((-2656365050)/((-66180492)+(tmp = 284225706.32323086, tmp))))); + assertEquals(-232839, x >>= (1694344809.435083)); + assertEquals(-1, x >>= x); + assertEquals(1, x *= x); + assertEquals(1, x |= x); + assertEquals(0, x >>= (tmp = 397239268, tmp)); + assertEquals(-1525784563, x -= (tmp = 1525784563, tmp)); + assertEquals(-153.62740888512675, x /= (((tmp = -2040622579.5354173, tmp)*(tmp = -1149025861.549324, tmp))%(((tmp = 2981701364.0073133, tmp)*(tmp = 2993366361, tmp))|(x|(tmp = 1800299979, tmp))))); + assertEquals(-1671795135, x &= (-1671795135.6173766)); + assertEquals(-4253, x |= ((((x*((1533721762.8796673)<<((tmp = 1026164775.0081646, tmp)<<x)))<<(((x-((((x>>((((((tmp = -481536070.7067797, tmp)&(tmp = 1663121016, tmp))>>>(-2974733313.5449667))+(tmp = -493019653, tmp))>>x)&(tmp = 879307404.8600142, tmp)))>>>x)%(x-(tmp = -1806412445.788453, tmp)))%x))<<(x<<(x+x)))+x))>>((tmp = -332473688.28477216, tmp)<<((tmp = 1701065928, tmp)+(((((tmp = -2407330783, tmp)+x)-((tmp = 584100783, tmp)%(tmp = -3077106506, tmp)))^x)>>x))))<<x)); + assertEquals(-0, x %= x); + assertEquals(0, x >>>= x); + assertEquals(0, x >>>= (1578470476.6074834)); + assertEquals(0, x >>>= (974609751)); + assertEquals(-120, x += (x-((tmp = -245718438.0842378, tmp)>>>(tmp = -1870354951, tmp)))); + assertEquals(-6.134465505515781e-8, x /= (1956160645)); + assertEquals(-0, x %= x); + assertEquals(0, x *= (tmp = -399718472.70049024, tmp)); + assertEquals(-1803198769.8413258, x += (-1803198769.8413258)); + assertEquals(988624943, x ^= ((((tmp = 320776739.5608537, tmp)*(((tmp = -983452570.3150327, tmp)^x)&(tmp = -3181597938, tmp)))-(tmp = -1367913740.9036021, tmp))/(((tmp = -535854933.2943456, tmp)-(717666905.8122432))>>>(((((x^(tmp = 380453258.60062766, tmp))^(tmp = -1242333929, tmp))/((tmp = 1072416261, tmp)+(((2090466933)*(x*(tmp = -386283072, tmp)))|((tmp = 789259942, tmp)<<(tmp = -1475723636.1901488, tmp)))))>>>x)%((x>>(tmp = -1243048658.3818703, tmp))|((((((tmp = -619553509, tmp)|x)/(878117279.285609))|((x<<(x>>>(tmp = -749568437.7390883, tmp)))*x))/(tmp = 1674804407, tmp))-(x*(tmp = 1528620873, tmp)))))))); + assertEquals(988625135, x |= (x>>>(tmp = 2402222006, tmp))); + assertEquals(988625135, x %= (-2691094165.990094)); + assertEquals(0, x %= x); + assertEquals(-0, x *= (tmp = -1409904262, tmp)); + assertEquals(-0, x /= ((1176483512.8626208)<<x)); + assertEquals(0, x &= ((((1677892713.6240005)^(tmp = 2575724881, tmp))^(tmp = -2935655281.208194, tmp))*(216675668))); + assertEquals(0, x >>= (tmp = -1296960457, tmp)); + assertEquals(0, x |= x); + assertEquals(NaN, x /= x); + assertEquals(0, x <<= (x>>(-3127984289.9112387))); + assertEquals(0, x %= ((tmp = 190018725.45957255, tmp)<<((x>>>x)/x))); + assertEquals(0, x /= (1185681972)); + assertEquals(0, x &= ((tmp = -1285574617, tmp)>>x)); + assertEquals(0, x >>>= ((tmp = 2498246277.2054763, tmp)+(((tmp = 924534435, tmp)&x)>>(tmp = 1379755429, tmp)))); + assertEquals(0, x -= x); + assertEquals(0, x /= (3093439341)); + assertEquals(0, x *= (x>>>x)); + assertEquals(0, x &= (tmp = 551328367, tmp)); + assertEquals(-0, x /= (-3153411714.834353)); + assertEquals(1217585288, x ^= (tmp = -3077382008.637764, tmp)); + assertEquals(-639702017, x |= ((tmp = -640922633, tmp)%(tmp = -879654762, tmp))); + assertEquals(-1645297680, x <<= (tmp = 1418982820.8182912, tmp)); + assertEquals(-1.4059558868398736, x /= (1170234212.4674253)); + assertEquals(-2650856935.66554, x *= (1885448157)); + assertEquals(1326259953.26931, x *= (((x>>(x|(-496195134.78045774)))+((2029515886)%(tmp = 1148955580, tmp)))/(tmp = -1760016519, tmp))); + assertEquals(0, x &= (((((-273334205)+(tmp = 797224093.682485, tmp))/x)>>>((((tmp = -887577414, tmp)/x)+x)%(tmp = 720417467, tmp)))^(((x-(tmp = -309071035, tmp))>>(-3123114729.33889))/x))); + assertEquals(0, x ^= x); + assertEquals(0, x %= ((tmp = -2243857462, tmp)/((((((2642220700.6673346)&x)*(tmp = 1454878837, tmp))|((-25825087.30002737)%(851535616.3479034)))<<(tmp = -697581582, tmp))%(tmp = 2248990486, tmp)))); + assertEquals(0, x >>= (((x|(((tmp = -220437911, tmp)&((((255690498)*(((2993252642)>>>(tmp = 300426048.0338713, tmp))>>x))&((-364232989)+(x<<(-1824069275))))%(x+(tmp = 2696406059.026349, tmp))))+((tmp = 2911683270, tmp)/(tmp = 2718991915, tmp))))*(x/(((tmp = -982851060.0744538, tmp)^((-2903383954)<<((-85365803.80553412)^x)))%(1489258330.5730634))))>>>x)); + assertEquals(0.7805921633088815, x += (((-1886920875)/(-2417294156.5304217))%(tmp = -1176793645.8923106, tmp))); + assertEquals(0, x <<= x); + assertEquals(-2215008905, x -= (2215008905)); + assertEquals(1931542900, x &= (-215923724.72133207)); + assertEquals(907191462, x ^= (-3133954606.357727)); + assertEquals(453595731, x >>>= (((tmp = 2726241550, tmp)/(tmp = -332682163, tmp))*((((tmp = 2500467531, tmp)>>>(((x<<(tmp = -1847200310.4863105, tmp))/x)^x))+x)<<(191688342.22953415)))); + assertEquals(-0.21671182880645923, x /= ((((-1169180683.1316955)%x)>>>(1650525418))^((2198033206.797462)&((-6913973.910871983)%(1758398541.8440342))))); + assertEquals(-375102237.1603561, x += (tmp = -375102236.9436443, tmp)); + assertEquals(1, x &= (((84374105.89811504)|((tmp = -2480295008.926951, tmp)>>((605043461)>>(tmp = -2495122811, tmp))))>>(-2129266088))); + assertEquals(1, x |= x); + assertEquals(0.0000024171579540208214, x /= (((-2600416098)>>(-2076954196))^x)); + assertEquals(0.0000024171579540208214, x %= (tmp = -2632420148.815531, tmp)); + assertEquals(1809220936.0126908, x -= (-1809220936.0126884)); + assertEquals(1682452118.2686126, x += (((2358977542)<<(x/(tmp = -2862107929, tmp)))+(x+(x%((-3101674407)/(((x*((x>>(tmp = 630458691.3736696, tmp))>>>(tmp = -852137742, tmp)))/x)-((-1875892391.1022017)&(tmp = -1027359748.9533749, tmp)))))))); + assertEquals(1682452118, x <<= (((tmp = -80832958.07816291, tmp)>>x)%(x-((x^(x<<(tmp = -156565345, tmp)))|((tmp = -1208807363.727137, tmp)/(tmp = 2614737513.304538, tmp)))))); + assertEquals(6572078, x >>= (-1573364824)); + assertEquals(13144156, x += x); + assertEquals(1731678184, x ^= ((tmp = 593370804.9985657, tmp)|(-3124896848.53273))); + assertEquals(845545, x >>>= (tmp = -605637621.2299933, tmp)); + assertEquals(-1383361088, x ^= (tmp = -1383632087, tmp)); + assertEquals(-82545896480031520, x += ((x+(1023183845.7316296))*((((tmp = 576673669, tmp)>>(((-584800080.1625061)/(2388147521.9174623))+((((x>>>(-905032341.5830328))^(tmp = -2170356357, tmp))-x)+((136459319)+(-1799824119.689473)))))|x)&(tmp = -2688743506.0257063, tmp)))); + assertEquals(-895206176, x |= x); + assertEquals(-0, x %= x); + assertEquals(1791306023, x ^= ((tmp = -3219480856, tmp)+(tmp = 715819582.0181161, tmp))); + assertEquals(1791306023, x &= x); + assertEquals(2725167636753240600, x *= (1521330025)); + assertEquals(-281190679, x |= (tmp = -1422045975.798171, tmp)); + assertEquals(-281190679, x += (x%x)); + assertEquals(-2342097426.906673, x -= (tmp = 2060906747.906673, tmp)); + assertEquals(-4651462701.906673, x -= (2309365275)); + assertEquals(1878, x >>>= (2544974549.345834)); + assertEquals(1964, x += (x&((1067649861)>>(182139255.7513579)))); + assertEquals(2209, x += (x>>(tmp = -1775039165, tmp))); + assertEquals(0, x -= x); + assertEquals(-0, x /= (tmp = -1634697185, tmp)); + assertEquals(NaN, x /= x); + assertEquals(0, x >>>= ((tmp = 3075747652, tmp)&(tmp = 819236484, tmp))); + assertEquals(0, x /= ((1276203810.476657)%(-2434960500.784484))); + assertEquals(0, x >>>= (tmp = -503633649, tmp)); + assertEquals(-982731931, x |= (-982731931)); + assertEquals(-1965463862, x += x); + assertEquals(-0.221469672913716, x %= ((tmp = -1742292120, tmp)/x)); + assertEquals(-0.221469672913716, x %= (-2021391941.1839576)); + assertEquals(0, x <<= (((((tmp = -2802447851, tmp)>>((2534456072.6518855)&x))%(tmp = 2841162496.610816, tmp))<<((89341820)/(2565367990.0552235)))>>(tmp = 2700250984.4830647, tmp))); + assertEquals(0, x >>= x); + assertEquals(0, x >>= ((tmp = -636189745, tmp)>>>(x/(((tmp = 2634252476, tmp)%(2026595795))>>(tmp = -2048078394.743723, tmp))))); + assertEquals(NaN, x %= ((x%((((x%((tmp = -2583207106, tmp)&x))|(190357769))<<(tmp = 595856931.2599536, tmp))%x))*((-2433186614.6715775)<<((2856869562.1088696)^(tmp = 1112328003, tmp))))); + assertEquals(1621713910, x |= (tmp = 1621713910.0282416, tmp)); + assertEquals(3243427820, x += x); + assertEquals(0, x *= (x&(x-x))); + assertEquals(0, x >>>= (((2871235439)<<((x+((tmp = -1319445828.9659343, tmp)+(tmp = 1595655077.959171, tmp)))>>(tmp = -86333903, tmp)))-(x/(2907174373.268768)))); + assertEquals(0, x >>= (-1091774077.2173789)); + assertEquals(NaN, x /= x); + assertEquals(NaN, x *= (tmp = 1976023677.7015994, tmp)); + assertEquals(NaN, x -= (-3013707698)); + assertEquals(NaN, x += ((x+(((tmp = -3119865782.9691515, tmp)<<(1327383504.0158405))^(((-143382411.7239611)>>>((-2157016781)+(((-335815848)/x)<<(tmp = 1953515427, tmp))))&(-2715729178))))/(413738158.2334299))); + assertEquals(NaN, x %= x); + assertEquals(NaN, x += (-845480493)); + assertEquals(-789816013, x |= (tmp = -789816013.129916, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x <<= (3032573320)); + assertEquals(47630, x ^= ((1086705488)%((x^(tmp = -1610832418, tmp))>>>(tmp = 1136352558, tmp)))); + assertEquals(47630, x >>= (tmp = 1035320352.4269229, tmp)); + assertEquals(47630, x >>= ((((x^x)<<(x*((((x&((-1657468419)*((tmp = -674435523, tmp)&((tmp = 2992300334, tmp)|x))))*((tmp = -489509378.31950426, tmp)*(tmp = 2276316053, tmp)))>>>x)<<x)))%(tmp = -1209988989, tmp))/(tmp = -2080515253.3541622, tmp))); + assertEquals(3192518951.8129544, x += (3192471321.8129544)); + assertEquals(648116457.8129544, x %= (-2544402494)); + assertEquals(0, x -= x); + assertEquals(NaN, x /= x); + assertEquals(NaN, x /= x); + assertEquals(0, x <<= x); + assertEquals(0, x >>= x); + assertEquals(0, x *= (tmp = 30051865, tmp)); + assertEquals(0, x ^= ((x&(((x&x)>>>(((((((x+(2319551861.0414495))>>>(tmp = -3099624461, tmp))^((((tmp = 1574312763, tmp)|x)>>>((-2723797246)&(tmp = -1993956152, tmp)))|(-1830179045)))|(((((((-2545698704.3662167)>>>x)-(((-79478653)|x)%(x+(x>>((tmp = 2386405508.2180576, tmp)/x)))))>>((((-1947911815.2808042)*((x+(368522081.2884482))-(tmp = 2452991210, tmp)))>>(343556643.1123545))>>((((tmp = 1869261547.537739, tmp)>>(3193214755))|x)&(x*(2027025120)))))<<((-1149196187)>>>(814378291.8374172)))+((((((((-160721403)/(2079201480.2186408))+((x|((((tmp = -299595483.16805863, tmp)>>>((x|((x+x)/(-2359032023.9366207)))<<(tmp = -3095108545, tmp)))>>((tmp = -1547963617.9087071, tmp)*(x>>x)))&((tmp = -1568186648.7499216, tmp)+(((2646528453)^(-2004832723.0506048))>>>(tmp = -3188715603.921877, tmp)))))+(tmp = 1578824724, tmp)))^x)^x)/(tmp = -985331362, tmp))|(tmp = 445135036, tmp))<<(tmp = -73386074.43413758, tmp)))+(((-1674995105.9837937)-(tmp = 1392915573, tmp))>>x)))%(tmp = 1215953864, tmp))&((tmp = -439264643.5238693, tmp)>>>x))+(((tmp = 2311895902, tmp)|(1604405793.6399229))&(tmp = -565192829, tmp))))-x))>>(-2455985321))); + assertEquals(0, x %= ((1177798817)>>(tmp = 2081394163.5420477, tmp))); + assertEquals(0, x >>>= ((x^(tmp = -41947528.33954811, tmp))>>(x>>>((tmp = 1367644771, tmp)+x)))); + assertEquals(0, x %= ((x+((tmp = 163275724, tmp)<<((tmp = -514460883.3040788, tmp)+x)))|(tmp = -287112073.2482593, tmp))); + assertEquals(0, x &= (3067975906)); + assertEquals(201342051, x |= (tmp = 201342051, tmp)); + assertEquals(0, x %= (((((-2580351108.8990865)<<(tmp = 2675329316, tmp))&((1338398946)%((-1548041558)+((x>>(-1568233868.7366815))|((x>>((tmp = -1064582207, tmp)/(-1062237014)))>>(tmp = 854123209, tmp))))))<<(((989032887)*(1842748656))%(tmp = -1566983130, tmp)))-x)); + assertEquals(-0, x /= (tmp = -828519512.617768, tmp)); + assertEquals(0, x &= ((((1449608518)+(-1829731972))*(1828894311))*(((tmp = -1121326205.614264, tmp)^(-2057547855))<<(tmp = -2758835896, tmp)))); + assertEquals(NaN, x %= ((tmp = -2138671333, tmp)%x)); + assertEquals(0, x &= x); + assertEquals(665568613.0328879, x += (665568613.0328879)); + assertEquals(317, x >>= (2627267349.735873)); + assertEquals(0, x -= x); + assertEquals(0, x &= (((tmp = 3030611035, tmp)*(((tmp = 476143340.933007, tmp)>>(x-(2238302130.2331467)))|(x|x)))%(tmp = 320526262, tmp))); + assertEquals(0, x <<= (tmp = 729401206, tmp)); + assertEquals(0, x >>>= (1721412276)); + assertEquals(217629949.3530736, x += ((tmp = 217629949.3530736, tmp)%((-931931100.601475)%(x^(tmp = -2149340123.548764, tmp))))); + assertEquals(217629949.3530736, x %= (tmp = 2275384959.4243402, tmp)); + assertEquals(0, x >>>= (1112677437.5524077)); + assertEquals(0, x *= (500256656.7476063)); + assertEquals(0, x >>>= x); + assertEquals(0, x -= x); + assertEquals(0, x -= x); + assertEquals(0, x &= (-1076968794)); + assertEquals(0, x /= (tmp = 1774420931.0082943, tmp)); + assertEquals(0, x |= x); + assertEquals(0, x >>= x); + assertEquals(0, x %= (-2978890122.943079)); + assertEquals(-0, x /= (tmp = -2954608787, tmp)); + assertEquals(-800048201, x ^= ((tmp = -800048201.7227018, tmp)>>>((-2016227566.1480863)/(tmp = -2263395521, tmp)))); + assertEquals(3333, x >>>= (-2038839052)); + assertEquals(487957736.625432, x += (487954403.625432)); + assertEquals(-1650983426, x |= (2643918270)); + assertEquals(-1861867448, x &= (tmp = -251254199.12813115, tmp)); + assertEquals(-7.934314690172143e-18, x %= ((((x^(-703896560.6519544))>>(tmp = -1853262409, tmp))/(tmp = -1168012152.177894, tmp))/(tmp = 837616075.1097361, tmp))); + assertEquals(0, x ^= x); + assertEquals(0, x &= (tmp = -2328150260.5399947, tmp)); + assertEquals(-1954860020, x |= (tmp = 2340107276, tmp)); + assertEquals(-1954860020, x >>= ((tmp = 159177341, tmp)*(x&(-705832619)))); + assertEquals(-1954895727, x -= (x>>>((-1443742544.7183702)^((((tmp = 869581714.0137681, tmp)+x)^((x%(tmp = -1036566362.5189383, tmp))^(x%x)))>>x)))); + assertEquals(1.0241361338078498, x /= (tmp = -1908824093.2692068, tmp)); + assertEquals(16777216, x <<= (x*(((-1925197281)^(tmp = -1392300089.4750946, tmp))|x))); + assertEquals(-225882765524992, x *= (tmp = -13463662, tmp)); + assertEquals(-1845493760, x |= x); + assertEquals(-1845493760, x %= (tmp = 3181618519.786825, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x <<= x); + assertEquals(0, x >>>= x); + assertEquals(NaN, x /= (x>>>x)); + assertEquals(NaN, x %= (((((tmp = -521176477, tmp)>>(((tmp = 370693623, tmp)/(((tmp = -1181033022.4136918, tmp)>>(x|(x*(2601660441))))+(tmp = -1696992780, tmp)))|(x|(-1197454193.198036))))>>>(((2512453418.3855605)+((((((tmp = 799501914, tmp)&(((1788580469.7069902)*(((((1476778529.5109258)<<(tmp = -1873387738.3541565, tmp))-((tmp = -521988584.7945764, tmp)*(-1598785351.3914914)))&(-1899161721.8061454))&((x/x)*(690506460))))>>>((tmp = 2255896398.840741, tmp)>>((tmp = -1331486014.6180065, tmp)+(-1159698058.534132)))))*((1112115365.2633948)&((x>>((x>>(-784426389.4693215))&(-492064338.97227573)))>>x)))^((x-((tmp = 2986028023, tmp)>>(tmp = 2347380320.00517, tmp)))*(tmp = -1463851121, tmp)))*(tmp = -1059437133, tmp))%(x-(tmp = 1238739493.7636225, tmp))))^(2029235174)))*(-1923899530))>>>x)); + assertEquals(0, x >>>= (2848792983.510682)); + assertEquals(0, x >>= (((tmp = 3042817032.705198, tmp)>>>x)&((((tmp = -829389221, tmp)-((2669682285.8576303)+(tmp = 1812236814.3082042, tmp)))^x)%((tmp = -2401726554, tmp)^((tmp = 2464685683, tmp)|(-2685039620.224061)))))); + assertEquals(2069649722, x |= (2069649722.311271)); + assertEquals(NaN, x %= (((((-68757739.39282179)&(-1382816369))/(3122326124))<<(x-(-507995800.3369653)))<<(((-1962768567.343907)+((tmp = 1357057125, tmp)/x))^(tmp = 1997617124, tmp)))); + assertEquals(NaN, x += x); + assertEquals(0, x >>= (26895919)); + assertEquals(0, x >>>= x); + assertEquals(0, x %= (tmp = 1092448030, tmp)); + assertEquals(0, x <<= (tmp = -477672441.46258235, tmp)); + assertEquals(0, x /= (2113701907)); + assertEquals(0, x >>>= x); + assertEquals(NaN, x /= x); + assertEquals(1341078673, x |= (-2953888623)); + assertEquals(1341078673, x &= x); + assertEquals(0, x %= x); + assertEquals(414817852.151006, x -= (-414817852.151006)); + assertEquals(1006632960, x <<= ((((((126465614.8316778)+(x-(2511803375)))+(tmp = 1620717148.352402, tmp))*x)/(tmp = -3013745105.5275207, tmp))-((tmp = -418034061.6865432, tmp)/(-300492911)))); + assertEquals(1055624813, x |= (tmp = 921407085, tmp)); + assertEquals(-3, x |= ((((tmp = 1382397819.7507677, tmp)+(tmp = -111851147.7289567, tmp))+x)/((tmp = 247980405.7238742, tmp)^(tmp = -592156399.8577058, tmp)))); + assertEquals(35161, x &= (((((((-2973570544.725141)*(tmp = -1244715638, tmp))+x)<<(x/((x>>>(-2143371615.073137))/(226072236))))%((x-(tmp = 1971392936, tmp))^(tmp = 2653103658, tmp)))%((tmp = 2828319571.7066674, tmp)>>((1528970502)^((tmp = -55869558, tmp)%x))))>>(889380585.6738582))); + assertEquals(0, x ^= x); + assertEquals(0, x *= (2749718750)); + assertEquals(0, x >>>= ((((-1633495402.6252813)*(tmp = 2943656739.1108646, tmp))+(tmp = 977432165, tmp))&((tmp = -2338132019, tmp)*(408176349.8061733)))); + assertEquals(-1778794752, x -= (((tmp = -1391412154.5199084, tmp)-((-3172342474)|x))&(1854366052))); + assertEquals(-1778794752, x %= (tmp = 2024807296.6901965, tmp)); + assertEquals(-1114410.466337204, x %= ((tmp = -240344444.24487805, tmp)%(-47661164))); + assertEquals(-0, x %= x); + assertEquals(0, x >>= (x>>x)); + assertEquals(0, x *= x); + assertEquals(0, x /= ((-3134902611)|(tmp = -3131158951, tmp))); + assertEquals(-0, x /= (((tmp = 1430247610.634234, tmp)&x)+((tmp = -2047191110.8623483, tmp)-((((x%((((x/(tmp = -2599234213, tmp))|(tmp = 2650380060, tmp))|x)+x))>>>x)&(-1961373866))<<x)))); + assertEquals(-718394682, x -= ((x|(tmp = 1764417670.8577194, tmp))%(1046022988))); + assertEquals(3576572614, x >>>= (((tmp = 2480472883.078992, tmp)<<x)>>((2035208402.8039393)&(tmp = 492980449, tmp)))); + assertEquals(434034142, x %= (x&((x>>>(311110449.48751545))|(-243530647)))); + assertEquals(524703439.3065736, x += (((tmp = 1392771723.3065736, tmp)%(x&x))%(tmp = -2199704930, tmp))); + assertEquals(373686272, x &= (x<<((tmp = 2103372351.9456532, tmp)%(tmp = -1367109519, tmp)))); + assertEquals(373686272, x >>= x); + assertEquals(-0.12245430020241108, x /= (tmp = -3051638622.5907507, tmp)); + assertEquals(1, x /= x); + assertEquals(1, x %= (3095983855)); + assertEquals(-1454736871, x ^= (x*(tmp = -1454736872, tmp))); + assertEquals(-1454736866, x ^= (((724989405.7338341)|(tmp = -2834298786.384371, tmp))>>>(tmp = -2029602148.1758833, tmp))); + assertEquals(-1454736866, x &= x); + assertEquals(-197394432, x <<= (tmp = -1562128975, tmp)); + assertEquals(251658240, x <<= (tmp = 2126510950, tmp)); + assertEquals(3295700610.703306, x -= (tmp = -3044042370.703306, tmp)); + assertEquals(-51152917, x |= ((949179883.1784958)|(((tmp = -2046168220, tmp)>>(x/x))/(((835064313)*(tmp = 2197600689, tmp))^(((tmp = 2717104216, tmp)&x)<<(-1402661995.3845913)))))); + assertEquals(-1549204421, x ^= ((((tmp = -481013711, tmp)>>>((tmp = 119589341.80209589, tmp)%(-995489985.2905662)))-(635717011))^(x+(x*x)))); + assertEquals(-1078356672.3999934, x += (470847748.6000067)); + assertEquals(1484987268.4638166, x += (tmp = 2563343940.86381, tmp)); + assertEquals(277020804, x &= (tmp = 2532819117, tmp)); + assertEquals(-2097118208, x <<= (x>>>x)); + assertEquals(-2147483648, x <<= (tmp = 761285045, tmp)); + assertEquals(2147483648, x >>>= x); + assertEquals(-935909870282997800, x *= ((-2583300643)|x)); + assertEquals(-370753566.54721737, x %= (-1084543510.4524941)); + assertEquals(-177, x >>= (-946264747.6588805)); + assertEquals(-416077682, x ^= (tmp = 416077761, tmp)); + assertEquals(NaN, x %= ((((tmp = 779607408, tmp)*(((tmp = -3007128117, tmp)*(851442866.6153773))+x))&(1283388806))/(-876363553))); + assertEquals(NaN, x %= (x/(tmp = -1668413939.652408, tmp))); + assertEquals(-1726405921, x ^= (tmp = -1726405921, tmp)); + assertEquals(-1, x >>= ((3031008213.807012)>>x)); + assertEquals(4294967295, x >>>= ((x>>>x)&(tmp = 2788082290, tmp))); + assertEquals(8544111670008449000, x *= (tmp = 1989331020.0417833, tmp)); + assertEquals(268435456, x <<= (tmp = 3121736017.2098465, tmp)); + assertEquals(-2.1011176170964474e+26, x -= (((tmp = 1392503299, tmp)*(tmp = 1446108825.1572113, tmp))*(x^(tmp = 372776014.213725, tmp)))); + assertEquals(0, x |= x); + assertEquals(0, x >>= ((-112413907.70074797)*(-702798603))); + assertEquals(1829518838, x |= (tmp = -2465448458, tmp)); + assertEquals(57172463, x >>= ((tmp = 2979642955.241792, tmp)%(tmp = -2464398693.291434, tmp))); + assertEquals(114344926, x += x); + assertEquals(113279134, x &= (2397742238.6877637)); + assertEquals(54, x >>= (1908522709.6377516)); + assertEquals(-2.966982919573829e-7, x /= (tmp = -182003070, tmp)); + assertEquals(0, x <<= (-1078417156)); + assertEquals(-147831390, x ^= (((-147831390)>>>x)+x)); + assertEquals(0, x -= x); + assertEquals(-242221450.44696307, x -= (tmp = 242221450.44696307, tmp)); + assertEquals(-484442900, x <<= (((tmp = -2033947265.088614, tmp)&x)/(x^(tmp = -2893953848, tmp)))); + assertEquals(-3227648, x <<= (x<<((tmp = -193993010, tmp)*((983187830)|(3146465242.2783365))))); + assertEquals(-6455296, x += x); + assertEquals(-1771542585, x -= (x^(tmp = -1767335879, tmp))); + assertEquals(-0, x %= x); + assertEquals(0, x >>>= ((((tmp = -1612864670.4532743, tmp)*(tmp = 786265765.210487, tmp))*((((tmp = -893735877.3250401, tmp)*((x^(tmp = -2804782464.233885, tmp))<<x))&(x-x))^x))<<x)); + assertEquals(0, x -= (x>>>(-1648118674.380736))); + assertEquals(0, x >>= ((tmp = -2706058813.0028524, tmp)>>(2745047169))); + assertEquals(0, x += x); + assertEquals(0, x %= (-898267735.137356)); + assertEquals(0, x >>>= x); + assertEquals(0, x >>= ((265527509)/((tmp = 2190845136.7048635, tmp)+((x>>x)>>>((x%(x-x))&((((-2080184609.8989801)&((-327231633)>>>((tmp = 864849136, tmp)%(((-524363239)*(((((tmp = 2245852565.3713694, tmp)&(1918365.8978698254))>>>(tmp = -2463081769, tmp))-(((2438244059.471446)|((((-135303645.38470244)*(-861663832.2253196))%(tmp = 1273185196.0261836, tmp))|((2261539338.832875)%((320267076.2363237)+x))))>>(tmp = -2731398821, tmp)))/(tmp = -1947938611, tmp)))^x))))>>(tmp = 833666235, tmp))|x)))))); + assertEquals(-1116704570, x ^= (-1116704570)); + assertEquals(1379561710, x ^= (tmp = -280362968.19654894, tmp)); + assertEquals(-1673822208, x <<= x); + assertEquals(-1673822208, x |= (x<<(tmp = 1389479193.9038138, tmp))); + assertEquals(2559712, x >>>= (-2703763734.0354066)); + assertEquals(2593499, x ^= (x>>>((tmp = 148668150.03291285, tmp)^(tmp = -1580360304, tmp)))); + assertEquals(2070393855, x |= (tmp = -2227002907, tmp)); + assertEquals(304197770, x &= (tmp = 2453257354, tmp)); + assertEquals(304197770, x <<= ((-669331453.8814087)-(x^(x^(tmp = 33804899.98928583, tmp))))); + assertEquals(297068, x >>= x); + assertEquals(Infinity, x /= (x-x)); + assertEquals(NaN, x %= x); + assertEquals(0, x ^= x); + assertEquals(0, x %= ((tmp = 1723087085, tmp)%(2859382131.304421))); + assertEquals(0, x %= (((tmp = 2935439763, tmp)<<(-3163992768.637094))%(tmp = 67176733, tmp))); + assertEquals(0, x &= (tmp = 2480771277, tmp)); + assertEquals(0, x >>>= (x+(tmp = -3168690063, tmp))); + assertEquals(0, x *= ((tmp = -1915275449.1806245, tmp)>>>((tmp = -1644482094.1822858, tmp)/(tmp = -432927173, tmp)))); + assertEquals(0, x += (((2766509428.071809)/(x/((942453848.5423365)/(((tmp = -1284574492, tmp)&((tmp = 760186450.7301528, tmp)-(2464974117.358138)))/((x/(x|(672536969)))*(x>>(-1272232579)))))))>>(x*(-3175565978)))); + assertEquals(-1277710521, x -= (1277710521)); + assertEquals(-1277710521, x >>= (((tmp = -2349135858, tmp)-x)-x)); + assertEquals(-1277710521, x >>= ((tmp = 2135645051, tmp)*(tmp = -2468555366, tmp))); + assertEquals(-155971, x >>= (-1294859507)); + assertEquals(-0, x %= x); + assertEquals(0, x >>>= (((861078292.6597499)|(-268063679))-(((((-221864206.9494424)-(-3186868203.2201176))&(tmp = 1287132927, tmp))<<(((tmp = 1964887915, tmp)<<((25908382)^(tmp = -688293519.875164, tmp)))*(2075946055)))&(x-((x>>x)&(1395338223.7954774)))))); + assertEquals(788002218, x -= (-788002218)); + assertEquals(716399906, x &= (-1145868506)); + assertEquals(145776674, x &= (-1661931477.360386)); + assertEquals(145776674, x |= x); + assertEquals(-0.05255700469257692, x /= (tmp = -2773686873, tmp)); + assertEquals(-660918434, x |= (-660918434.2915542)); + assertEquals(1223537346, x ^= (tmp = -1871274596, tmp)); + assertEquals(305884336, x >>= (x&x)); + assertEquals(-1.1123775647978218e-8, x *= ((tmp = -793393031.4229445, tmp)/((tmp = -503919284, tmp)*(((((tmp = 429810625, tmp)>>>x)-((2091544148.870375)<<(((((x^x)%x)|x)/(-260773261))<<((tmp = -1323834653, tmp)&x))))*((-1231800099.3724015)+x))*((x+((-559726167)^x))>>>((-549148877)<<((((tmp = 1196115201, tmp)/((tmp = -2654658968.390111, tmp)%(tmp = -1044419580, tmp)))*(((((x>>>(733571228))+(2919762692.511447))/(-2718451983.570547))^x)+((2891533060.1804514)^((tmp = -2514488663, tmp)&x))))<<(tmp = -2526139641.6733007, tmp)))))))); + assertEquals(0, x >>>= x); + assertEquals(0, x *= x); + assertEquals(0, x |= x); + assertEquals(3076984066.336236, x -= ((tmp = -3076984066.336236, tmp)+((tmp = -446575828.5155368, tmp)&x))); + assertEquals(1, x /= x); + assertEquals(1513281647.839972, x *= (1513281647.839972)); + assertEquals(1251138155, x ^= ((tmp = 2124481052, tmp)&(2431937351.4392214))); + assertEquals(1, x /= x); + assertEquals(0, x &= (tmp = 627050040, tmp)); + assertEquals(497153016, x ^= (497153016)); + assertEquals(-1112801283, x |= (tmp = 2752196557, tmp)); + assertEquals(0.5735447276296568, x /= ((((tmp = -500878794, tmp)%(tmp = -2559962372.2930336, tmp))%(2661010102))+(tmp = -1439338297, tmp))); + assertEquals(1.0244795995097235e-9, x /= (559840067)); + assertEquals(0.43468811912309857, x *= (424301391)); + assertEquals(-1972757928, x ^= (tmp = -1972757928.9227014, tmp)); + assertEquals(-606757265, x ^= (tmp = -2923461577.264596, tmp)); + assertEquals(-37, x >>= (((-2736561559.7474318)%(tmp = -27668972.662741184, tmp))*(2774711606))); + assertEquals(-1923785671, x += ((-1923785597)+x)); + assertEquals(-3877639176, x += (tmp = -1953853505, tmp)); + assertEquals(-4688259242, x -= ((810620066.4394455)>>(((-1474285107.459875)>>x)/(((((-570672326.4007359)>>(tmp = -3086802075, tmp))%x)>>>(((tmp = 286938819.28193486, tmp)>>>((1712478502)>>(tmp = 3045149117.796816, tmp)))<<(tmp = 750463263.292952, tmp)))&(tmp = 2055350255.5669963, tmp))))); + assertEquals(-0, x %= x); + assertEquals(0, x <<= (1037856162.5105649)); + assertEquals(0, x *= x); + assertEquals(0, x &= (997845077.4917375)); + assertEquals(0, x *= x); + assertEquals(0, x *= x); + assertEquals(0, x <<= (((x<<x)&(57691805))>>(786927663))); + assertEquals(0, x ^= x); + assertEquals(0, x += x); + assertEquals(0, x &= (-2131910624.1429484)); + assertEquals(0, x >>>= (-43787814)); + assertEquals(-2415062021, x += (tmp = -2415062021, tmp)); + assertEquals(-4830124042, x += x); + assertEquals(-186683401, x |= (tmp = 1960135383, tmp)); + assertEquals(NaN, x *= ((tmp = -1674740173.9864025, tmp)%(((((((-432895485.7261934)-x)^x)>>>(((-1627743078.3383338)>>(179992151))<<((tmp = 911484278.0555259, tmp)|(((tmp = -3042492703, tmp)>>(((-663866035.302746)>>(((x-((440661929.50030375)>>>(tmp = 263692082, tmp)))*x)+x))/((1546004407)^(((tmp = 2023662889.1594632, tmp)*(tmp = -2456602312, tmp))+(tmp = 755602286.1810379, tmp)))))%((tmp = -336449961, tmp)|(tmp = 206780145, tmp))))))/(1068005219.1508512))<<(tmp = -474008862.6864624, tmp))/(((((((1518711056.5437899)>>>(tmp = 287418286.63085747, tmp))<<(tmp = 2823048707, tmp))^(((x<<(x^(-1600970311)))&(x>>(((tmp = 157300110.7636031, tmp)*(tmp = -3047000529, tmp))&(1743024951.3535223))))>>x))-(tmp = -2895435807, tmp))*((tmp = -314120704, tmp)&(tmp = 1759205369, tmp)))>>(tmp = 1833555960.046526, tmp))))); + assertEquals(NaN, x -= (tmp = 694955369, tmp)); + assertEquals(NaN, x *= (x%x)); + assertEquals(0, x |= x); + assertEquals(0, x ^= x); + assertEquals(0, x &= x); + assertEquals(NaN, x /= (x+x)); + assertEquals(NaN, x %= ((tmp = -1595988845, tmp)*((1754043345)>>>(-601631332)))); + assertEquals(0, x >>>= (tmp = 862768754.5445609, tmp)); + assertEquals(NaN, x /= x); + assertEquals(NaN, x %= x); + assertEquals(NaN, x *= (tmp = -1774545519, tmp)); + assertEquals(0, x >>>= (tmp = -2492937784, tmp)); + assertEquals(0, x %= ((((x<<(-1657262788.2028513))&((x^(tmp = -671811451, tmp))<<(-2984124996)))^(1455422699.7504625))-((-340550620)>>x))); + assertEquals(918278025, x ^= ((tmp = -918278027, tmp)^((tmp = 2889422870, tmp)/(tmp = -657306935.7725658, tmp)))); + assertEquals(918278025, x %= (2603186571.0582614)); + assertEquals(107034679.32509923, x %= (tmp = -811243345.6749008, tmp)); + assertEquals(53517339, x >>= (x%((((x*((tmp = -983766424, tmp)^(-1881545357.8686862)))|(tmp = -1429937087, tmp))>>((x<<x)>>((((tmp = -2347470476, tmp)&x)+((x&x)<<(396061331.6476157)))*(tmp = -3136296453.209073, tmp))))>>>(((tmp = 908427836, tmp)|(tmp = 207737064, tmp))|(((1253036041)-(tmp = 2705074182, tmp))+(-431215157.82083917)))))); + assertEquals(53477378, x &= ((((-1128036654.165636)*x)+x)>>(x>>(3080099059)))); + assertEquals(0, x >>= (-590692293)); + assertEquals(0, x %= (-2395850570.9700127)); + assertEquals(0, x *= ((tmp = 1377485272, tmp)&(1129370608))); + assertEquals(0, x += (x>>>(x%(((((tmp = -1746827236, tmp)+((tmp = -326913490, tmp)&((-58256967)&x)))*(tmp = -1176487022.001651, tmp))>>>(-2089147643))-x)))); + assertEquals(0, x <<= (tmp = 1073298160.2914447, tmp)); + assertEquals(-837811832, x ^= (-837811832)); + assertEquals(102760448, x <<= (tmp = 2833582450.4544373, tmp)); + assertEquals(0, x &= (((((((tmp = 2595641175, tmp)*x)+(tmp = -2049260172.1025927, tmp))%((2986747823)>>(tmp = -2120598518, tmp)))&((tmp = -2742408622, tmp)&x))>>x)*((1043474247.9601482)&(tmp = 1686365779.9885998, tmp)))); + assertEquals(0, x >>= ((tmp = 1717862848, tmp)-(tmp = 1077024446.4160957, tmp))); + assertEquals(NaN, x /= x); + assertEquals(NaN, x /= (-1669429787.975099)); + assertEquals(NaN, x -= (-2299895633.4807186)); + assertEquals(138173970, x ^= (138173970.56627905)); + assertEquals(-2084183776, x <<= (3073345316)); + assertEquals(-0, x %= x); + assertEquals(0, x >>= (-3080556066.068573)); + assertEquals(0, x &= ((tmp = -2587514820, tmp)*(x-((x^(1995672257))*(1125326747.2339358))))); + assertEquals(NaN, x %= x); + assertEquals(0, x >>= (tmp = 2139186585, tmp)); + assertEquals(-1904096640, x |= ((-602301360.1919911)*(-1270444810))); + assertEquals(1073741824, x <<= (tmp = -1069467849, tmp)); + assertEquals(1073741824, x ^= (x-x)); + assertEquals(536870912, x >>>= (-1579466367.160293)); + assertEquals(512, x >>= (972402804.3890183)); + assertEquals(512, x &= (tmp = 2664796831, tmp)); + assertEquals(16777216, x <<= (-2738292561)); + assertEquals(0, x >>>= ((((1397663615.3889246)|(1117420260.6730964))-(-1173734560))<<((tmp = 1007006104.0172879, tmp)<<((tmp = -623002097, tmp)%(tmp = -35829654.379403114, tmp))))); + assertEquals(1200191544, x ^= (tmp = -3094775752, tmp)); + assertEquals(71, x >>>= x); + assertEquals(71, x |= x); + assertEquals(1394763772, x += (1394763701)); + assertEquals(-1.492717171027427, x /= ((x&(tmp = 1243787435, tmp))-(2043911970.26752))); + assertEquals(-1.1002448961224718e-8, x /= ((((835185744)*(((tmp = 2165818437, tmp)^(tmp = 2567417009.1166553, tmp))/x))/x)/(((63485842.39971793)^(2668248282.597389))/x))); + assertEquals(0, x <<= (tmp = 1598238578.637568, tmp)); + assertEquals(0, x |= (x&((tmp = -1812945547.5373957, tmp)>>>x))); + assertEquals(0, x >>>= (x+(-1969679729.7299538))); + assertEquals(1582033662, x += (tmp = 1582033662, tmp)); + assertEquals(1, x >>>= x); + assertEquals(-550748739, x += ((tmp = -550748740, tmp)/(x&((2537822642.235506)^((-2167656297)%(tmp = 1161201210, tmp)))))); + assertEquals(-268921, x >>= (tmp = 1916069547.7381654, tmp)); + assertEquals(-0.00021776939364231114, x /= (tmp = 1234888868, tmp)); + assertEquals(0, x <<= (-1036375023)); + assertEquals(0, x &= ((((x/(2398886792.27443))&(x|((-1813057854.1797302)-x)))&(x/(((tmp = 3091133731.4967556, tmp)|(3013139691.823039))<<x)))>>>(2542784636.963599))); + assertEquals(0, x += ((x*x)/(tmp = 347079383, tmp))); + assertEquals(788347904, x |= ((1462257124.6374629)*((3180592147.4065146)-(x&(1922244678))))); + assertEquals(2130672735, x |= (tmp = -2846986145, tmp)); + assertEquals(-1331327970, x ^= ((656251304)-(tmp = 1489152359, tmp))); + assertEquals(-0.14377179742889856, x %= (((2889747597.813753)-(1730428996))/(((tmp = -1378710998, tmp)&x)|x))); + assertEquals(-1754612583.143772, x += ((-1754725729)^((-2285838408)>>>(1434074349)))); + assertEquals(-0, x %= x); + assertEquals(0, x &= (tmp = -1031961332, tmp)); + assertEquals(NaN, x /= x); + assertEquals(NaN, x /= (3059476325)); + assertEquals(NaN, x *= ((x*((((tmp = 13529540.462185979, tmp)&x)^((x<<(-1312696238.1628869))&(-2029766712.3852897)))>>x))/x)); + assertEquals(1657339940, x ^= ((tmp = -488956817.1491232, tmp)&(tmp = -2352413900.1983714, tmp))); + assertEquals(-530683621952432200, x *= (tmp = -320202035.2882054, tmp)); + assertEquals(229226258, x ^= ((tmp = -1263410990.026416, tmp)+(((-808046349)&(tmp = -1294442506, tmp))&((tmp = 1147437219, tmp)<<((tmp = -820299900, tmp)-(tmp = -1947748943.3443851, tmp)))))); + assertEquals(7163320, x >>= (-2631307131)); + assertEquals(-68, x |= (((-1271721343)>>x)%x)); + assertEquals(-39956523818.38862, x *= (587595938.505715)); + assertEquals(0, x -= x); + assertEquals(0, x >>>= ((x^(x+x))<<(tmp = 265212367, tmp))); + assertEquals(0, x |= (((x>>((tmp = 2294761023, tmp)/(x>>(2125624288))))&((-2125650113)|(tmp = 1014409884, tmp)))%(tmp = -527324757, tmp))); + assertEquals(0, x >>= ((tmp = 2267075595, tmp)*(-1681569641.8304193))); + assertEquals(0, x >>>= x); + assertEquals(0.5738410949707031, x -= ((tmp = -1846572645.573841, tmp)%((((((x^(((-156613905.64173532)/x)<<x))+((x|((2405109060)>>>x))^x))/(570585894.8542807))+(x&(-2544708558)))^((((tmp = -2539082152.490635, tmp)+((((-657138283)/(2204743293))-((tmp = -1422552246.565012, tmp)+x))<<(x-x)))>>(x/(x>>>(tmp = -3027022305.484394, tmp))))<<x))&((-2066650303.3258202)/(tmp = -1666842593.0050385, tmp))))); + assertEquals(0, x >>>= ((((tmp = 2473451837.613817, tmp)>>((2526373359.1434193)>>(x<<x)))+((tmp = -579162065, tmp)+((tmp = -3115798169.551487, tmp)-(tmp = 933004398.9618305, tmp))))&(tmp = 131167062, tmp))); + assertEquals(-2067675316, x ^= (-2067675316.6300585)); + assertEquals(543772, x >>>= x); + assertEquals(-1073741824, x <<= x); + assertEquals(3221225472, x >>>= ((x*(1478586441.081221))&(tmp = -3050416829.2279186, tmp))); + assertEquals(0, x ^= x); + assertEquals(0, x *= x); + assertEquals(-1017771903.0298333, x -= (1017771903.0298333)); + assertEquals(0.6404112721149928, x /= ((tmp = -144667370, tmp)^(-2849599562))); + assertEquals(-2410517638773644000, x -= (((tmp = 1759631550, tmp)*x)*((((tmp = -2949481475, tmp)>>>x)*x)|(tmp = -2977983804, tmp)))); + assertEquals(-0, x %= (x+((((tmp = -1307866327.7569134, tmp)<<((x&((tmp = -2380043169.8405933, tmp)|x))>>(472992789.7639668)))|(((((x<<(tmp = -1416427232.7298179, tmp))%(-1404989679.409946))*((x/(tmp = -992416608, tmp))/(tmp = 524646495, tmp)))-(tmp = 734405570, tmp))>>x))/(1079256317.7325506)))); + assertEquals(0, x <<= (tmp = 2459834668, tmp)); + assertEquals(-0, x /= (tmp = -1892164840.5719755, tmp)); + assertEquals(0, x >>= (x|(((1299844244)>>>(((tmp = -2422924469.9824634, tmp)|x)-((((1914590293.2194016)+(-3033885853.8243046))-((tmp = -1720088308, tmp)%x))<<(tmp = 2210817619, tmp))))<<x))); + assertEquals(0, x <<= (((tmp = 3192483902.841396, tmp)>>>(((x^(2944537154))|(tmp = -1334426566, tmp))*(((((((-2705218389)&x)+(1987320749))+(tmp = -111851605, tmp))|(2894234323))-(265580345))&x)))%(((tmp = 1431928204.6987057, tmp)&(tmp = 914901046, tmp))&(x>>>x)))); + assertEquals(0, x >>>= (tmp = 1941940941, tmp)); + assertEquals(0, x %= (3089014384)); + assertEquals(0, x += ((tmp = 2948646615, tmp)*x)); + assertEquals(-0, x /= (tmp = -1480146895, tmp)); + assertEquals(NaN, x /= x); + assertEquals(NaN, x %= (-2995257724.158043)); + assertEquals(NaN, x %= (tmp = 2714835455, tmp)); + assertEquals(NaN, x /= (tmp = -311440765.98078775, tmp)); + assertEquals(NaN, x -= (-1600234513.697098)); + assertEquals(0, x <<= x); + assertEquals(0, x <<= (-1499045929)); + assertEquals(-0, x *= (-2491783113)); + assertEquals(0, x ^= (x%((x>>(((1234398704.3681123)>>>x)%(x+x)))>>(402257223.4673699)))); + assertEquals(-643225204, x ^= (((-55960194.698637486)+((((721411198)-(((tmp = 1308676208.7953796, tmp)%(2242904895))-x))>>((((tmp = 332791012, tmp)&((tmp = -2094787948, tmp)/((x/(2427791092))^(2444944499.6414557))))%(((x+(1253986263.5049214))+(((((3135584075.248715)+((tmp = -2569819028.5414333, tmp)%(440908176.1619092)))>>>(x<<((3061615025)-x)))%x)%(x+((2369612016)*((((tmp = 1173615806, tmp)*(-1910894327))&(2428053015.077821))*(-55668334.70082307))))))<<(tmp = -2129259989.0307562, tmp)))+(1579400360)))%((-3053590451.8996153)>>x)))+(x>>(x%(x^((-1772493876)^x)))))); + assertEquals(413738663060841600, x *= x); + assertEquals(1581062538.4501781, x %= ((tmp = -1298397672.0300272, tmp)-((2237197923)+(tmp = -1385478459, tmp)))); + assertEquals(755644566.8709538, x %= (tmp = -825417971.5792243, tmp)); + assertEquals(1, x /= x); + assertEquals(0, x >>>= ((89330582)%(-1012731642.4855506))); + assertEquals(0, x >>>= x); + assertEquals(NaN, x %= ((x>>>((x/(tmp = -1848848941.2352903, tmp))>>>(tmp = -71862893, tmp)))&(-2385996598.2015553))); + assertEquals(NaN, x += (-2292484503.318904)); + assertEquals(NaN, x *= (2961064461)); + assertEquals(NaN, x += (x<<((2076798243.6442)/((tmp = -81541044.75366282, tmp)^((3041366498.551101)+((2126874365)/(tmp = -177610359, tmp))))))); + assertEquals(NaN, x %= ((x/((x/x)+x))>>>x)); + assertEquals(NaN, x /= x); + assertEquals(NaN, x += (1171761980.678)); + assertEquals(NaN, x += ((2355675823)<<(-390497521))); + assertEquals(NaN, x %= x); + assertEquals(0, x &= (tmp = -658428225.56619, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x <<= (1643310725.5713737)); + assertEquals(0, x <<= x); + assertEquals(0, x <<= (-397005335.3712895)); + assertEquals(0, x >>>= (tmp = -2804713458.166788, tmp)); + assertEquals(0, x <<= (((((((tmp = 1879988501, tmp)%(1528081313.9360204))+(1376936736))*((((x>>>((1736268617.339198)>>>(-2598735297.4277673)))<<((((((((-2742982036)/(231867353.4549594))-(875335564))<<x)|((2241386341.742653)<<((-22024910.828409433)&(x<<x))))*(-756987803.5693252))+x)^(tmp = 1084498737, tmp)))<<(1920373881.8464394))&(2370827451.82652)))&(x^(tmp = -891503574, tmp)))<<x)>>>((-1519588625.2332087)^(483024636.2600144)))); + assertEquals(52193878.40997505, x -= ((tmp = -341753803.40997505, tmp)%(tmp = -96519975, tmp))); + assertEquals(-1665844168.938803, x -= (1718038047.348778)); + assertEquals(3.6962232549405003e-19, x /= (((((-809583468.5507183)>>>((tmp = 286797763, tmp)%((1579183142.7321532)/(1853824036.001172))))<<x)>>(((x|x)^((tmp = -2641304815, tmp)<<(x<<x)))>>(((((268338128.8300134)&(-1778318362.8509881))*(751081373.346478))<<(((525066612)>>(-1139761212))*(2949167563.299916)))<<x)))+((tmp = 664905121, tmp)*((-2208280205)*(3069462420))))); + assertEquals(4710721795.110161, x += (((217604832)+((1307891481.781326)-x))+(tmp = 3185225481.328835, tmp))); + assertEquals(0, x %= x); + assertEquals(0, x -= (((x>>>(x/(tmp = 46977522.46204984, tmp)))>>(-2466993199.615269))&(tmp = 14524430.287991166, tmp))); + assertEquals(0, x >>= x); + assertEquals(0, x /= (tmp = 578120637, tmp)); + assertEquals(-17267104, x -= (((tmp = 1515285919.495792, tmp)+(((tmp = -1364790286.7057304, tmp)+((954599071)>>((897770243.1509961)*x)))^x))>>>(566027942.1732262))); + assertEquals(-17267104, x &= x); + assertEquals(189138241, x ^= ((tmp = 1565742675.9503145, tmp)-((tmp = 1737806643, tmp)|((x*(tmp = -1382435297.5955122, tmp))*(-2820516692.153056))))); + assertEquals(189138241, x %= (x*(tmp = -1670678493, tmp))); + assertEquals(1693, x %= ((-2328713314)>>>(1623637325))); + assertEquals(1693, x %= ((-1019394014)*(x|x))); + assertEquals(3386, x += x); + assertEquals(9268970871604, x *= (2737439714)); + assertEquals(-4720.120483643183, x /= (tmp = -1963714889, tmp)); + assertEquals(-1, x >>= ((x^(((-2404688047.455056)|((1439590234.6203847)<<(tmp = -2496557617, tmp)))/((x<<((tmp = 1865549512.282249, tmp)/(((360384191.55661833)>>(tmp = -1225297117.344188, tmp))>>>(2703264010.4122753))))*(1521960888.0071676))))%(tmp = 2834001448.0508294, tmp))); + assertEquals(63, x >>>= (x&(-3079339174.6490154))); + assertEquals(0, x >>>= (1039770956.6196513)); + assertEquals(0, x >>>= (-1074820214)); + assertEquals(0, x >>>= (x/x)); + assertEquals(0, x >>= ((tmp = -449117604.2811785, tmp)&x)); + assertEquals(-0, x /= (tmp = -118266935.1241343, tmp)); + assertEquals(2226140134, x += (tmp = 2226140134, tmp)); + assertEquals(2068827161, x ^= ((tmp = -1950744808.846384, tmp)>>((2258661151)^((tmp = -1118176421.8650177, tmp)<<(2828634014))))); + assertEquals(123, x >>>= (-1779624840.0515127)); + assertEquals(0, x >>>= (x|((tmp = -239082904, tmp)<<(tmp = 1404827607, tmp)))); + assertEquals(0, x >>>= x); + assertEquals(1793109749, x ^= (tmp = -2501857547.710491, tmp)); + assertEquals(855, x >>>= x); + assertEquals(0, x >>>= (-847289833)); + assertEquals(0, x %= (-2271241045)); + assertEquals(169648072, x ^= (((tmp = 169648072.66759944, tmp)^x)|x)); + assertEquals(176025927479164930, x *= ((tmp = 1111997198.8803885, tmp)<<(tmp = 2913623691, tmp))); + assertEquals(176025926613281700, x += ((tmp = -865883245, tmp)<<(x+(-2624661650)))); + assertEquals(3406506912, x >>>= ((x|(tmp = 2436016535, tmp))*(((tmp = -1222337225, tmp)<<((1765930268)&x))*(tmp = 1600702938, tmp)))); + assertEquals(1.694694170868292, x %= (x/(-1597121830.794548))); + assertEquals(0, x >>= (tmp = -2443203089, tmp)); + assertEquals(0, x >>>= (1323174858.2229874)); + assertEquals(0, x &= ((tmp = 846556929.2764134, tmp)|(((1483000635.0020065)|(-3151225553))|(tmp = -229028309, tmp)))); + assertEquals(0, x >>= x); + assertEquals(0, x >>= ((((((-2677334787)>>>x)>>((tmp = 496077992, tmp)&((((x<<(x*(tmp = 1095163344.2352686, tmp)))+(-952017952))%((x<<((x*x)/(tmp = 2983152477, tmp)))^((tmp = -939521852.1514642, tmp)^(tmp = 143967625.83755958, tmp))))*((tmp = 551827709.8366535, tmp)>>>x))))^((-1552681253.69869)-(-1874069995)))>>>(x>>(x%(tmp = -2554673215, tmp))))|(tmp = -190693051.77664518, tmp))); + assertEquals(0, x /= (tmp = 427402761.37668264, tmp)); + assertEquals(0, x <<= x); + assertEquals(0, x |= (x>>>(((((-543326164.0673618)>>>(-2344090136.707964))>>>((((-563350246.6026886)/x)/(1525481037.3332934))&(tmp = -2917983401.88958, tmp)))^(-1094667845.1208413))^x))); + assertEquals(0, x &= (1080322749.897747)); + assertEquals(0, x %= (tmp = -1572157280, tmp)); + assertEquals(0, x >>>= x); + assertEquals(0, x %= ((377280936)|x)); + assertEquals(708335912, x -= (tmp = -708335912, tmp)); + assertEquals(2766937, x >>>= x); + assertEquals(547342779, x += (tmp = 544575842, tmp)); + assertEquals(546273751, x -= ((x>>>(472833385.9560914))|((tmp = -1164832103.9970903, tmp)/(3147856452.1699758)))); + assertEquals(546273751, x &= x); + assertEquals(0, x ^= x); + assertEquals(0, x >>>= (tmp = -3181805175, tmp)); + assertEquals(-375546685, x |= (-375546685.08261824)); + assertEquals(1089992785780217200, x *= (tmp = -2902416209, tmp)); + assertEquals(0, x %= x); + assertEquals(-1854981526, x -= ((x-x)-(-1854981526))); + assertEquals(-3709963052, x += x); + assertEquals(-316772482, x %= (tmp = -1696595285, tmp)); + assertEquals(-316772482, x |= x); + assertEquals(1, x /= x); + assertEquals(0, x -= x); + assertEquals(-1418375842, x ^= (-1418375842)); + assertEquals(-2, x >>= x); + assertEquals(-4, x += x); + assertEquals(-8388608, x &= (x<<(-350555339.30086184))); + assertEquals(-16777216, x += x); + assertEquals(-0, x %= x); + assertEquals(1083355129, x += (tmp = 1083355129, tmp)); + assertEquals(0, x &= (((tmp = 389729053, tmp)-(tmp = 2944192190.0939536, tmp))/(x-(2081712461.2657034)))); + assertEquals(0, x += x); + assertEquals(-3, x += ((3147270119.5831738)>>((2455837253.1801558)%((-2100649096)>>(((290236808.01408327)|(x&((2661741230.3235292)|((tmp = 1686874589.4690177, tmp)<<x))))*(x+(tmp = 2327674670, tmp))))))); + assertEquals(-3, x %= ((x>>(((-2962686431)%x)>>((((2438370783)-(tmp = 2667305770.4839745, tmp))>>>x)>>>x)))<<((x&(tmp = 1428498616, tmp))|((tmp = 2621728539.102742, tmp)/(-204559901))))); + assertEquals(2, x ^= (x|((((tmp = 1751230118.6865973, tmp)/(-867465831.207304))>>((-808143600.0912395)+(-2882191493.0506454)))^x))); + assertEquals(2, x %= (-2015954220.2250996)); + assertEquals(0, x >>>= (tmp = 401373999, tmp)); + assertEquals(0, x >>= (2371830723)); + assertEquals(0, x >>>= ((((tmp = 2765919396, tmp)-x)-(530310269.7131671))|(tmp = -615761207.9006102, tmp))); + assertEquals(-145389011, x ^= (tmp = -145389011, tmp)); + assertEquals(-145389011, x |= x); + assertEquals(1632929832, x &= (-2518898392)); + assertEquals(4190540017.751949, x += (tmp = 2557610185.751949, tmp)); + assertEquals(4980024282.153588, x += ((1841304364.1177452)%(tmp = 1051820099.7161053, tmp))); + assertEquals(0, x >>>= (((((1379314342.4233718)>>((-2782805860)^((x%(tmp = 1328845288, tmp))>>>(tmp = 901403219.858733, tmp))))+(x/((tmp = -3078904299, tmp)/x)))/x)|(x|(1399702815)))); + assertEquals(-1820494882, x ^= (tmp = -1820494882.407127, tmp)); + assertEquals(-305870376, x %= (tmp = -757312253, tmp)); + assertEquals(-577530443, x += (x|(tmp = -1958083619.6653333, tmp))); + assertEquals(333541412591776260, x *= x); + assertEquals(-949341696, x >>= ((((1550069663)<<((x>>>(tmp = 2406565178.902887, tmp))>>>((1844746612.632984)/((tmp = 2233757197, tmp)*((-1524891464.1028347)>>(tmp = 2498623474.5616803, tmp))))))&x)<<(x&(tmp = -370379833.3884752, tmp)))); + assertEquals(-277202090, x |= ((-762200848.8405354)-(tmp = 1749136282, tmp))); + assertEquals(0.13704539927239265, x /= (tmp = -2022702633.373563, tmp)); + assertEquals(0, x -= x); + assertEquals(0, x %= ((132951580.19304836)-((427623236.27544415)-(1212242858)))); + assertEquals(0, x &= ((449148576)&(-1609588210.249217))); + assertEquals(0, x >>= x); + assertEquals(0, x -= x); + assertEquals(-0, x /= (tmp = -1640777090.9694843, tmp)); + assertEquals(0, x &= (((tmp = -1923412153, tmp)>>>((x>>(tmp = 3027958119.0651507, tmp))+(60243350)))>>(tmp = -2610106062, tmp))); + assertEquals(0, x ^= (((-186998676)/(tmp = 2697937056, tmp))-x)); + assertEquals(-1147950080, x |= ((2425449461)*(tmp = -2525854833, tmp))); + assertEquals(457688198, x ^= (2698274950.660941)); + assertEquals(8724, x %= ((1174351031)>>>((371599047.36048746)+(3025292010)))); + assertEquals(0, x <<= (tmp = -710011617, tmp)); + assertEquals(0, x >>>= (1693410026)); + assertEquals(1443005362, x ^= ((tmp = -2851961934, tmp)+((((x%x)-(tmp = 547622400, tmp))<<(((tmp = 722396486.5553623, tmp)|x)>>>((((tmp = -542268973.5080287, tmp)<<(tmp = 1347854903.771954, tmp))>>>(tmp = -889664427.7115686, tmp))&((tmp = 1549560114, tmp)*(tmp = 964918035, tmp)))))&(-2422502602.920377)))); + assertEquals(3986573462, x -= (-2543568100)); + assertEquals(7973146924, x += x); + assertEquals(-1, x >>= (-75987297)); + assertEquals(-12, x += ((2940824338.64834)>>(tmp = 3061467355, tmp))); + assertEquals(-3.8229398525977614e-8, x /= (313894554)); + assertEquals(-2.890709270374084e-17, x /= (tmp = 1322491989, tmp)); + assertEquals(0, x |= (x-x)); + assertEquals(0, x >>>= (tmp = -1205300664, tmp)); + assertEquals(-0, x /= (((2869505187.6914144)>>(tmp = 1541407065, tmp))/(((-571132581)>>>(x>>x))/((x^(170373762.8793683))>>>((((tmp = -363073421.05897164, tmp)|(((tmp = -1591421637, tmp)>>(1095719702.8838692))&(636687681.9145031)))^x)^(x|x)))))); + assertEquals(-1487828433, x ^= (-1487828433.3462324)); + assertEquals(-0, x %= x); + assertEquals(1716342498, x -= ((tmp = 2578624798, tmp)^x)); + assertEquals(1636, x >>= ((264194540)>>>(-801900756))); + assertEquals(0, x >>>= ((tmp = 2502688876, tmp)+((x<<(x|((-628272226.0338528)|((x<<(-2083074091))>>>(tmp = 1692123246.8418589, tmp)))))>>(1594759826.990993)))); + assertEquals(0, x <<= (tmp = -904399643, tmp)); + assertEquals(NaN, x /= ((x^(x-x))%((tmp = 1744962024.4882128, tmp)%x))); + assertEquals(NaN, x /= (-1013142883.1845908)); + assertEquals(NaN, x /= ((tmp = 793633198, tmp)^(-2993598490.8659954))); + assertEquals(0, x &= (x>>((tmp = 1200937851, tmp)<<(((tmp = -2807378465, tmp)&(tmp = -143778237, tmp))|(tmp = -1200772223, tmp))))); + assertEquals(0, x <<= x); + assertEquals(88144, x |= (((((tmp = 3002723937.8560686, tmp)*(tmp = -3171720774.2612267, tmp))%(((tmp = -2586705978.7271833, tmp)%((x+(-1553704278))&(2405085526.501994)))>>((-240842053)>>>(((((tmp = -1886367228.4794896, tmp)>>>x)^(tmp = 2604098316, tmp))^(tmp = 1362808529, tmp))<<((tmp = -1062263918, tmp)|((-172718753)%(tmp = -1910172365.4882073, tmp)))))))^((1444153362)>>((x&((-1205465523.2604182)^(tmp = -2062463383, tmp)))>>(tmp = 956712476, tmp))))>>((((-1004215312)^((((-1707378612.5424936)^(tmp = 2372161553, tmp))/((tmp = 1802586581, tmp)*((2082257.1896460056)&((tmp = -1270773477, tmp)^(tmp = 942517360.3447798, tmp)))))+x))%((((666494127)^(x^x))>>>(tmp = -2592829775, tmp))+((-1601528223)+((x+(tmp = -2417034771.7409983, tmp))>>>((tmp = -730673817, tmp)*x)))))>>x))); + assertEquals(-2603179111.7557006, x -= ((2603267255.755627)+(x/(1200979191.2823262)))); + assertEquals(1691788185, x >>= (tmp = 3088840032, tmp)); + assertEquals(-168382533, x |= (tmp = -780750941.4590135, tmp)); + assertEquals(-168382533, x >>= (60741120.48285198)); + assertEquals(-134287365, x |= (x*(tmp = 834637940.7151251, tmp))); + assertEquals(-1481917089, x -= (tmp = 1347629724, tmp)); + assertEquals(1, x >>>= x); + assertEquals(262144, x <<= (2680216914)); + assertEquals(1075132032, x ^= (x-((tmp = 3220359552.3398685, tmp)^(((-434474746.6039338)|((((((((tmp = 1945689314.9683735, tmp)>>(1300022273))>>>(333705550))&x)%(588357521))-(x+(x^(((tmp = -134560382, tmp)+x)-((((994246147.7195556)-(-1506599689.7383268))%(x<<x))>>((1256426985.5269494)+(tmp = 1860295952.8232574, tmp)))))))^(((tmp = 917333220.2226384, tmp)>>x)>>>(tmp = 865898066, tmp)))%((x|(x%((tmp = -2660580370, tmp)&(tmp = 2966426022, tmp))))*x)))/(((tmp = 682585452, tmp)&(-3219368609))+((tmp = -1330253964, tmp)+((x&(2857161427))/x))))))); + assertEquals(274944, x &= ((2606953028.1319966)-(-1707165702))); + assertEquals(266752, x &= ((x<<((x+(x+(x^(-1570175484))))^x))^(x+(x<<(tmp = 90330700.84649956, tmp))))); + assertEquals(266752, x &= ((((x*(tmp = 2033225408, tmp))-(x-((tmp = 1507658653, tmp)/(-3016036094))))>>>((1497480588)>>(2784070758)))|(tmp = -3025904401.93921, tmp))); + assertEquals(-1680442631, x |= ((x/(445284843))|((tmp = 2614520057.2723284, tmp)<<x))); + assertEquals(40851947, x >>>= (tmp = -1577031386.938616, tmp)); + assertEquals(2493, x >>= ((3044630989.3662357)-(-2670572992.8580284))); + assertEquals(-0.0000017317105653562252, x /= (-1439617017.9207587)); + assertEquals(0, x &= (2359806567)); + assertEquals(623768541, x ^= (623768541)); + assertEquals(1028567149.0716183, x += (((tmp = 1307794561, tmp)%(x>>x))-(-404798608.0716183))); + assertEquals(-1.2971762489811298, x /= (tmp = -792927830.6471529, tmp)); + assertEquals(-1.2971762489811298, x %= ((-2426421701.2490773)/(-689566815.3393874))); + assertEquals(-2147483648, x <<= x); + assertEquals(-2147483648, x &= (tmp = -869991477, tmp)); + assertEquals(-268435456, x >>= (1383186659)); + assertEquals(0, x -= x); + assertEquals(-2009742037, x |= (-2009742037.5389993)); + assertEquals(-1386630820, x ^= (627864695)); + assertEquals(-1033479103975173600, x *= (tmp = 745316697.9046186, tmp)); + assertEquals(-1628048487, x |= (2662654361)); + assertEquals(325551, x >>>= (340874477)); + assertEquals(-1235730537, x ^= (tmp = 3059533880.0725217, tmp)); + assertEquals(-1235730537, x %= (2247137328)); + assertEquals(-220200960, x <<= ((x>>x)-x)); + assertEquals(0, x <<= ((tmp = 337220439.90653336, tmp)|(tmp = 2901619168.375105, tmp))); + assertEquals(0, x >>>= ((-2114406183)/x)); + assertEquals(0, x %= ((1425828626.3896675)/x)); + assertEquals(0, x >>>= ((3213757494)>>>(2595550834.3436537))); + assertEquals(0, x <<= x); + assertEquals(-0, x /= ((1544519069.5634403)/((tmp = -1332146306, tmp)&(-762835430.0022461)))); + assertEquals(0, x ^= x); + assertEquals(0, x >>= (x|((((x*((-786272700)+x))<<x)+((tmp = -1868484904, tmp)-(tmp = -1692200376, tmp)))+(-1010450257.6674457)))); + assertEquals(0, x -= x); + assertEquals(0, x ^= (x>>>(706010741))); + assertEquals(-964928697, x |= (-964928697)); + assertEquals(1, x /= x); + assertEquals(0, x >>= ((((tmp = 1778003555.3780043, tmp)>>(x%((tmp = -766158535, tmp)^((-2681449292.8257303)%((x-(x|(tmp = 1966478387.2443752, tmp)))^(((tmp = -1848398085, tmp)&x)>>>(tmp = -2860470842, tmp)))))))%(tmp = 2315077030, tmp))^x)); + assertEquals(0, x ^= x); + assertEquals(-288007757, x ^= ((tmp = 183607156.1803962, tmp)-(tmp = 471614914, tmp))); + assertEquals(-270573581, x |= (tmp = -849475741.9424644, tmp)); + assertEquals(-2129929, x |= (((((1942852445)&(tmp = 1280372312, tmp))*(x*(tmp = -1601900291, tmp)))^((509080002.81080174)-(tmp = 2699498226.9164257, tmp)))>>(((-335361221)>>(tmp = 843134832, tmp))%(-35532542)))); + assertEquals(-232622355, x ^= ((-3060885134.5375547)-(((tmp = 1965966723, tmp)-((tmp = 1248630129.6970558, tmp)<<(tmp = 1859637857.5027392, tmp)))*x))); + assertEquals(-52149658093200070, x *= (224181627.31264615)); + assertEquals(-697122968, x ^= (x-(x+(tmp = 2747211186.407712, tmp)))); + assertEquals(-2146269688, x &= ((tmp = -1466710519, tmp)^(x/(1419998975)))); + assertEquals(-536567422, x >>= (((((tmp = -1760701688.999274, tmp)>>(-1821976334))/(((tmp = -1660849531, tmp)>>>x)-((x+((tmp = -2489545009.4327965, tmp)>>>((tmp = -267360771.39148235, tmp)^x)))*(((-1453528661)%x)>>>(((243967010.3118453)/((((((2977476024)>>>((-1630798246)<<x))&(591563895.2506002))*(((2668543723.9720144)>>>x)|(1600638279)))^x)>>(x<<(tmp = -152589389, tmp))))>>>(x|(2821305924.9225664)))))))+(618968002.8307843))%(tmp = -1005408074.368274, tmp))); + assertEquals(40962, x &= (114403906)); + assertEquals(19741977727890, x *= ((-2367133915.963945)>>>(-3119344126))); + assertEquals(1313341440, x <<= x); + assertEquals(626, x >>>= ((((-333992843)%(tmp = -2742280618.6046286, tmp))>>>x)|x)); + assertEquals(0, x <<= (2598188575)); + assertEquals(NaN, x %= x); + assertEquals(NaN, x %= x); + assertEquals(0, x ^= (x%((2507288229.3233204)&(tmp = -1714553169.9276752, tmp)))); + assertEquals(0, x /= ((633436914.3859445)>>>(tmp = 1579804050.6442273, tmp))); + assertEquals(0, x *= ((tmp = 1172218326, tmp)<<((tmp = -2491306095.8456626, tmp)*(((tmp = 1305371897.9753594, tmp)>>((x^(((3077992060)*x)<<(492815553.904796)))>>((652151523)|x)))%x)))); + assertEquals(0, x <<= x); + assertEquals(0, x %= (1118131711)); + assertEquals(0, x &= ((tmp = 2734673884, tmp)|(x-((tmp = 2694578672.8975897, tmp)*(((x>>(2350811280.974167))*(1052548515))&(x^(x*(tmp = -1336287059.0982835, tmp)))))))); + assertEquals(-2632782867.1256156, x += ((tmp = -2743992725.1256156, tmp)+(tmp = 111209858, tmp))); + assertEquals(-0, x %= x); + assertEquals(0, x >>>= (((tmp = -2050519887, tmp)^(106865302.74529803))>>(1642851915.2909596))); + assertEquals(-171964826, x |= (tmp = -171964826.6087358, tmp)); + assertEquals(-2.113405951193522, x /= (tmp = 81368572.80206144, tmp)); + assertEquals(3, x >>>= x); + assertEquals(0, x %= x); + assertEquals(-1717345907.837667, x += (-1717345907.837667)); + assertEquals(-100964883, x |= (tmp = -109574931.80629134, tmp)); + assertEquals(-33849857, x |= (-974111718.2433801)); + assertEquals(1, x >>>= (tmp = -2556222849.005595, tmp)); + assertEquals(1, x /= x); + assertEquals(0, x >>>= (-1796630999.4739401)); + assertEquals(0, x >>>= x); + assertEquals(2031695758, x += (((x/(((tmp = -2364918403, tmp)%(x^((tmp = 277767803.6375599, tmp)>>((((tmp = 540036080, tmp)/(x|(2665298931)))/(x|((x>>(-2035456216.6165116))<<(2143184420.5651584))))^x))))&(tmp = 927798419.8784283, tmp)))-(-2031695758))>>>x)); + assertEquals(2031695758, x |= x); + assertEquals(2031695758, x <<= (((x>>(x%x))|(tmp = -1164531232.7384055, tmp))*x)); + assertEquals(124004, x >>>= x); + assertEquals(529846352, x += ((529722348)%((2417645298.865121)|(x>>(x>>>(x+x)))))); + assertEquals(60067920, x &= (((tmp = -3166008541.8486233, tmp)-x)|(x%x))); + assertEquals(1415594240755200, x *= ((-2786707452.873729)>>(((tmp = -2369315809, tmp)*((1559868465)|(1011218835.1735028)))>>>x))); + assertEquals(1415595182259140, x += (941503939.9023957)); + assertEquals(0, x <<= ((tmp = 2887184784.265529, tmp)/(-2575891671.0881453))); + assertEquals(0, x &= ((tmp = -1546339583, tmp)>>>(tmp = -587433830, tmp))); + assertEquals(0, x *= (((tmp = 1356991166.5990682, tmp)%(tmp = -284401292, tmp))*(1869973719.9757812))); + assertEquals(NaN, x %= x); + assertEquals(0, x ^= (((tmp = 92575404.43720293, tmp)>>>(263475358.17717505))%x)); + assertEquals(0, x <<= (((561514358)*(tmp = -439584969, tmp))%((((-3005411368.7172136)+x)|(-2230472917))&x))); + assertEquals(0, x >>= ((x>>>x)-((x-(1630649280.510933))+x))); + assertEquals(0, x >>= (tmp = -1772403084.7012017, tmp)); + assertEquals(0, x *= x); + assertEquals(0, x += x); + assertEquals(0, x &= x); + assertEquals(0, x >>= (tmp = 1622680387, tmp)); + assertEquals(1033887633558225200, x -= ((-510616337)*(tmp = 2024783695, tmp))); + assertEquals(-2.8073538539158063e+27, x *= (tmp = -2715337492, tmp)); + assertEquals(-2.8073538539158063e+27, x -= ((tmp = -1664804757, tmp)&((tmp = -226616419, tmp)>>>(1006711498)))); + assertEquals(1894539615, x |= (tmp = -2400427681.1831083, tmp)); + assertEquals(7400545, x >>= (774629608.4463601)); + assertEquals(456756268, x += (449355723)); + assertEquals(285771784, x &= (-1316427366)); + assertEquals(17, x >>= ((tmp = -220509931.20787525, tmp)*(((tmp = 2518859292, tmp)+(-1477543005.1586645))>>(tmp = 3172820250.687789, tmp)))); + assertEquals(85924262443, x *= (x*((tmp = -2856669745.965829, tmp)&(((tmp = 401420695, tmp)^(tmp = 2355371132, tmp))|(tmp = 590645330.021911, tmp))))); + assertEquals(1703875715, x ^= ((-2576394029.7843904)-x)); + assertEquals(1703875715, x %= (tmp = 2234144310, tmp)); + assertEquals(271405807, x ^= (1973569132)); + assertEquals(1060178, x >>>= (tmp = -84823096, tmp)); + assertEquals(8, x >>>= (tmp = 2246120561.905554, tmp)); + assertEquals(-2846791089, x += (-2846791097)); + assertEquals(104933962, x &= (x-(-2969030955.99584))); + assertEquals(489215611.96215343, x -= (-384281649.96215343)); + assertEquals(489215611, x |= x); + assertEquals(1186191360, x <<= ((tmp = 774407142.993727, tmp)%x)); + assertEquals(1186191360, x %= (1555004022)); + assertEquals(-1697134080, x ^= (tmp = -597421568, tmp)); + assertEquals(-1102053376, x <<= ((-927370769.4059179)^((tmp = 1093490918, tmp)>>(((-2522227493.3821955)%x)+(-2657319903))))); + assertEquals(1086450058, x ^= (-23991926.187098265)); + assertEquals(1086450058, x |= x); + assertEquals(-1.6554590588410778, x /= (x|(x<<(x+x)))); + assertEquals(67108863, x >>>= ((-926530233)+x)); + assertEquals(494553310, x ^= (tmp = 512079649, tmp)); + assertEquals(207751168, x &= (2892146720.6261826)); + assertEquals(207751168, x &= x); + assertEquals(207751168, x |= x); + assertEquals(6340, x >>>= (((((x<<(x-((-2819638321)*((x<<x)+x))))>>x)+(tmp = 2016170261, tmp))+(tmp = 2755496043.772017, tmp))+(-841368625.1402085))); + assertEquals(6340, x ^= ((x/(tmp = -192734784, tmp))>>>(((-140306239)&x)-x))); + assertEquals(1, x /= x); + assertEquals(0, x >>= x); + assertEquals(26786600, x ^= (tmp = 26786600, tmp)); + assertEquals(-0.014657576899542954, x /= ((-1454855938.0338)+(-372635753.3681567))); + assertEquals(0, x &= ((tmp = 2480635933, tmp)&(-2986584704.9165974))); + assertEquals(-2108639122, x += ((tmp = 2108639123.8683565, tmp)^((-881296055)/(((x<<(2026200582))|(tmp = -862495245.138771, tmp))-(-1111596494.892467))))); + assertEquals(1893466112, x <<= (tmp = 607974481, tmp)); + assertEquals(1893466112, x |= x); + assertEquals(1133122783.997418, x += ((tmp = -760343332, tmp)-((x-(tmp = -878561823.4218843, tmp))/(tmp = -693454632.596637, tmp)))); + assertEquals(8, x >>>= (tmp = 700339003.3919828, tmp)); + assertEquals(4.605305035175536e-9, x /= (1737127060.8343256)); + assertEquals(4.605305035175536e-9, x -= ((x%(897221779))>>>x)); + assertEquals(-1864423625.5704088, x += (tmp = -1864423625.5704088, tmp)); + assertEquals(1132240092, x <<= (1304417186.1193643)); + assertEquals(-2088985380, x ^= (x<<x)); + assertEquals(-4, x >>= ((tmp = 1959823884.0935726, tmp)%(-1679792398.569136))); + assertEquals(-268435456, x <<= ((tmp = 2586838136, tmp)|((tmp = -481716750.718518, tmp)>>>((1485826674.882607)/(tmp = -2826294011, tmp))))); + assertEquals(-32768, x >>= (2060648973)); + assertEquals(1, x /= x); + assertEquals(-2838976297, x -= (tmp = 2838976298, tmp)); + assertEquals(-1382985298, x <<= ((tmp = -2104305023, tmp)&x)); + assertEquals(10, x >>>= (x+x)); + assertEquals(10, x -= (x>>>(361588901.70779836))); + assertEquals(854603510, x -= (-854603500)); + assertEquals(-557842432, x <<= (tmp = 1212985813.6094751, tmp)); + assertEquals(-459390188241943040, x *= (tmp = 823512450.6304014, tmp)); + assertEquals(-232800033621957060, x /= ((((((686635689)/(tmp = 2013252543, tmp))*(tmp = -1591617746.8678951, tmp))|(((tmp = -1777454093.5611362, tmp)>>>((tmp = 2680809394, tmp)^(((x>>((((((tmp = -265022244, tmp)%((tmp = -3075004537, tmp)>>(((((1427784269.5686688)^((tmp = -1095171528.911587, tmp)^(-942424985.7979553)))>>(-1279441481.1987405))*((2493620394)>>(-2769016043)))/(x&((tmp = 2059033657, tmp)%(((tmp = 1948606940.1488457, tmp)-(tmp = -2645984114.13219, tmp))^x))))))^x)^x)%(x%((((tmp = 3209433446.4551353, tmp)%(tmp = 1364430104.0424738, tmp))/(tmp = -2103044578.349498, tmp))+(tmp = -2613222750, tmp))))*(2099218034)))&(((tmp = -378500985.49700975, tmp)>>(((x+x)|(x%(((-1841907486)<<(-1220613546.194021))<<(tmp = -1260884176, tmp))))^(tmp = 1858784116, tmp)))>>>((x%x)%((x>>>(tmp = -2540799113.7667685, tmp))|x))))/((((tmp = 642072894.6455215, tmp)-(-324951103.6679399))*(tmp = 1424524615, tmp))+((x<<(tmp = -904578863.5945344, tmp))*(tmp = 49233475.435349464, tmp))))))<<(tmp = 1680210257, tmp)))+((tmp = -1516431503, tmp)>>>(-1105406695.3068116)))/(-275019361.6764543))); + assertEquals(192359387.42913792, x /= (-1210234846)); + assertEquals(192359387.42913792, x %= (-2920206625.0154076)); + assertEquals(192359387.42913803, x -= (((((((tmp = -1263203016.3258834, tmp)-(2432034005.6011124))&x)<<(1479434294))>>((tmp = -1695856315.523002, tmp)>>>(tmp = 557391345, tmp)))/(tmp = -1280240246.2501266, tmp))%((tmp = -2196489823.034029, tmp)>>(((x&((912221637.1101809)+((tmp = -3003677979.652423, tmp)>>(tmp = -716129460.1668484, tmp))))-((x+(x-(-2780610859)))>>>(-2445608016)))<<((x*(x+(x+(((-2124412727.9007604)%(tmp = -593539041.5539455, tmp))&(tmp = 2404054468.768749, tmp)))))%(x>>(tmp = -2913066344.404591, tmp))))))); + assertEquals(11740, x >>= (688848398.7228824)); + assertEquals(11740, x >>= ((1545765912)*(307650529.9764147))); + assertEquals(23480, x += x); + assertEquals(0, x >>>= ((tmp = 1313078391, tmp)|x)); + assertEquals(1726251264, x -= ((1939413887)<<(1004888744.2840619))); + assertEquals(765324793.5278986, x %= (960926470.4721014)); + assertEquals(747387, x >>= ((2483010044)-(tmp = -413698190, tmp))); + assertEquals(1, x /= x); + assertEquals(3016811624, x *= (3016811624)); + assertEquals(17408, x &= (((tmp = -991624868, tmp)<<(((63107932)/(tmp = 2659939199, tmp))|(tmp = -1968768911.3575773, tmp)))>>(((-2876822038.9910746)|(tmp = 2550230179.243425, tmp))<<((x*(x<<((x<<((tmp = -1627718523.616604, tmp)|((2154120561.254636)-(x%(x<<(1484563622.1791654))))))<<((((x^(tmp = 3016524169, tmp))<<(((x+(tmp = 1887816698.2455955, tmp))+x)-x))-(-3023329069))-x))))+x)))); + assertEquals(0, x <<= (((1247441062.177967)/(-1717276234))+x)); + assertEquals(0, x |= ((x%((-1648299429.4520087)>>(-137511052)))>>(tmp = 221301016.4926411, tmp))); + assertEquals(0, x /= ((-2598501544.913707)>>>(-2177037696))); + assertEquals(NaN, x %= (x>>x)); + assertEquals(0, x &= (tmp = 1852419158, tmp)); + assertEquals(-829029120, x |= (((2122339180)*((((((tmp = 768748914, tmp)<<((1008490427)&((1937367899.957056)-(((635094486)>>(((tmp = -795046025, tmp)*(2665104134.4455256))^(tmp = 706594584.2462804, tmp)))/(504397522)))))/(-556057788))>>((x/(tmp = -2732280594, tmp))-x))+(-1989667473))+(tmp = 2766802447.789895, tmp)))<<(((tmp = -2969169096, tmp)-x)+(tmp = 2093593159.0942125, tmp)))); + assertEquals(0.6451933462602606, x /= ((-1284931292)<<(x<<(tmp = 1294716764, tmp)))); + assertEquals(1515416866.520901, x *= (2348779440)); + assertEquals(-1620606242886682600, x *= ((-993898625.5357854)&(((tmp = -571100481, tmp)/x)*((2428590177.311031)%(tmp = -2671379453, tmp))))); + assertEquals(-1137472828, x %= (tmp = -1195183004, tmp)); + assertEquals(-3096634005473250000, x *= (tmp = 2722380640, tmp)); + assertEquals(-3096634003996758500, x -= (-1476491033.833419)); + assertEquals(-3096634000805538000, x += (3191220521.978341)); + assertEquals(-3096634000805468000, x += ((((tmp = -3024976741, tmp)&(952616360))|((x*(-1547952311))+(x*x)))>>>(tmp = 981373323, tmp))); + assertEquals(-3096633998655594000, x += (2149873927)); + assertEquals(-118812224101.54297, x %= (((2641881276.9898443)*(((502159480)^x)<<x))%((tmp = -2840045365.547772, tmp)*(((((-2297661528)>>>(x>>(-229103883.94961858)))&(((-1285047374.6746495)<<((-360045084)>>>((x-(tmp = -956123411.1260898, tmp))%x)))>>((tmp = -2375660287.5213504, tmp)+((((tmp = -2753478891, tmp)>>>(((tmp = 101438098, tmp)>>(((tmp = -2736502951, tmp)<<((tmp = -3084561882.368902, tmp)&(tmp = 1491700884, tmp)))|x))&(tmp = 1627412882.6404104, tmp)))>>>(tmp = 1039002116.6784904, tmp))<<((tmp = -2840130800, tmp)-(tmp = -740035567, tmp))))))&(tmp = -416316142, tmp))>>x)))); + assertEquals(86, x >>>= (tmp = -293489896.5572462, tmp)); + assertEquals(172, x += (x%((((-2635082487.364155)|((-2361650420.634912)&(-2147095650.7451198)))<<((tmp = 2258905145.9231243, tmp)%((((tmp = -1365987098.5130103, tmp)*(((((((932437391)/x)/(289270413.0780891))%(x-x))+((((2194986374.917528)>>(((((tmp = -1553805025, tmp)|x)^(((x>>(-564400586.0780811))^(tmp = 1738428582.0238137, tmp))>>(tmp = 1717774140, tmp)))&(tmp = -2789427438, tmp))%(((tmp = -1386118057, tmp)*(-2333221237.7915535))*(x>>>(((((41346648.46438944)&x)%(-478973697.6792319))|(tmp = 2108106738, tmp))/x)))))-(tmp = -133437701.64136505, tmp))>>>x))+(tmp = -1567210003, tmp))*(x+((x&x)-(2942851671)))))>>>(tmp = -446377136, tmp))*((((((tmp = 1597203255, tmp)>>>(619157171))|(-2766246629.005985))>>((tmp = 3130227370, tmp)%x))*(tmp = 2072227901.6101904, tmp))|((tmp = 1369019520, tmp)^(759659487))))))>>>x))); + assertEquals(1996475731, x ^= ((1456327892.2281098)|(1728022827))); + assertEquals(0, x %= x); + assertEquals(0, x &= (1323847974)); + assertEquals(3076829073.8848357, x += (3076829073.8848357)); + assertEquals(9569842648396755000, x *= (3110293883.2782717)); + assertEquals(9569842646260304000, x -= (2136450372.9038036)); + assertEquals(9.158188827418242e+37, x *= x); + assertEquals(0, x <<= ((x&(tmp = -2241179286, tmp))+((tmp = 2553144081, tmp)&((tmp = -1914709694, tmp)^(tmp = -1469651409.0651562, tmp))))); + assertEquals(0, x <<= x); + assertEquals(0, x /= (2177840666.276347)); + assertEquals(0, x %= (-690827104)); + assertEquals(0, x >>>= x); + assertEquals(0, x ^= x); + assertEquals(-0, x /= (tmp = -803415280, tmp)); + assertEquals(-2355576914.316743, x += (-2355576914.316743)); + assertEquals(-833671722514674000, x *= ((3053388806.692315)-(tmp = 2699474775.081724, tmp))); + assertEquals(1, x /= x); + assertEquals(1898147684, x += ((tmp = 1898147683, tmp)|(x<<x))); + assertEquals(2.192324660388075, x %= ((tmp = 2630187518, tmp)/((2868794982.790862)|(490860748)))); + assertEquals(0, x >>>= ((2751021779)/(-952522559))); + assertEquals(321040461, x ^= ((321040461.153594)-x)); + assertEquals(-2.3814602031636922, x /= ((tmp = -170472190, tmp)|x)); + assertEquals(-1, x >>= (2200125174.177402)); + assertEquals(-2964432647.9379396, x += (-2964432646.9379396)); + assertEquals(-370116502.93793964, x %= (tmp = -518863229, tmp)); + assertEquals(777927355.2283959, x -= (-1148043858.1663356)); + assertEquals(0, x *= ((tmp = 1134913539, tmp)&(((x>>>((tmp = -989822787, tmp)>>>x))%x)&(tmp = 1078636160.7313156, tmp)))); + assertEquals(-1089245637, x ^= (3205721659.3548856)); + assertEquals(-1192493056, x <<= (-1173291054)); + assertEquals(78013832, x += ((tmp = 2462999944, tmp)+x)); + assertEquals(0, x %= x); + assertEquals(0, x >>>= (1794908927.7409873)); + assertEquals(1708338504, x += ((-2586628792.3484306)<<x)); + assertEquals(12, x >>= (-545794789.3827574)); + assertEquals(0, x &= ((2753207225)<<(((-1776581207.557251)+((tmp = -2414140402, tmp)*x))+(x<<(x|(tmp = 772358560.3022032, tmp)))))); + assertEquals(0, x <<= ((tmp = -2755724712.152605, tmp)/((x>>(-732875466))&x))); + assertEquals(NaN, x *= (((tmp = 2617815318.1134562, tmp)/x)%(x|((((((-851659337.194871)<<(tmp = 2072294700, tmp))%((x+(2193880878.5566335))^((tmp = 3005338026, tmp)-(2947963290))))/x)/(x+(2091745239.4210382)))-(x>>x))))); + assertEquals(NaN, x /= (tmp = -427684595.0278094, tmp)); + assertEquals(NaN, x /= (tmp = -263945678, tmp)); + assertEquals(0, x <<= x); + assertEquals(0, x <<= x); + assertEquals(0, x -= (((x>>((x&x)-(tmp = -673697315, tmp)))>>(((1575095242.2330558)/(x-(-1816886266)))%(-1580195729)))>>>x)); + assertEquals(0, x >>>= x); + assertEquals(0, x >>= (-2815518206)); + assertEquals(0, x -= (x/(1795634670.692437))); + assertEquals(-2753579891, x += (tmp = -2753579891, tmp)); + assertEquals(2.7773776150171776, x /= (tmp = -991431585, tmp)); + assertEquals(5.554755230034355, x += x); + assertEquals(3.362161997528237e-9, x /= (1652137890.4758453)); + assertEquals(3.362161997528237e-9, x %= (tmp = -10848734.527020693, tmp)); + assertEquals(1, x /= x); + assertEquals(-2978012493, x -= (x+(2978012493))); + assertEquals(-5.158905851797543, x /= (((x+((tmp = -2548840164, tmp)>>x))<<(x^((tmp = -533281232.7294345, tmp)&x)))&(tmp = -1502692171, tmp))); + assertEquals(-5.158905851797543, x %= (-3009435255.5612025)); + assertEquals(-20971520, x <<= ((tmp = -2728812464, tmp)%(2619809573.672677))); + assertEquals(-1900019712, x &= (2398099552)); + assertEquals(-1991377, x %= ((tmp = 1562364373.7334614, tmp)>>>(((x-(-946283217))<<(-2044590694))^(((tmp = 1681238509, tmp)>>(-2801649769))-x)))); + assertEquals(1, x /= x); + assertEquals(1, x %= (x/(x-x))); + assertEquals(1.3525631913093335e-9, x /= (739336991)); + assertEquals(0, x &= ((x&(x|(-1530424204)))<<((((tmp = -295143065.9115021, tmp)>>x)+x)<<x))); + assertEquals(0, x <<= (-1311017801)); + assertEquals(-0, x /= (-667133339.1918633)); + assertEquals(1038307283, x += (1038307283)); + assertEquals(506985, x >>>= ((tmp = 1550624472.9157984, tmp)^x)); + assertEquals(506985, x >>>= ((254646626)<<(tmp = 1572845412.744642, tmp))); + assertEquals(32447040, x <<= (tmp = -2427326042, tmp)); + assertEquals(0, x -= (x<<((x|x)>>>x))); + assertEquals(0, x &= x); + assertEquals(0, x &= ((-484420357)|((tmp = 807540590.6132902, tmp)/(x/x)))); +} +f(); diff --git a/deps/v8/test/mjsunit/numops-fuzz-part4.js b/deps/v8/test/mjsunit/numops-fuzz-part4.js new file mode 100644 index 0000000000..c4ea614b32 --- /dev/null +++ b/deps/v8/test/mjsunit/numops-fuzz-part4.js @@ -0,0 +1,1177 @@ +// 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. + +function f() { + var x = 0; + var tmp = 0; + assertEquals(-890607324, x ^= ((tmp = -890607324, tmp)>>((((-2876826295)>>x)<<((tmp = 2351495148.117994, tmp)>>(tmp = 1368611893.274765, tmp)))*(tmp = 1531795251, tmp)))); + assertEquals(-729075363, x += (x+(tmp = 1052139285, tmp))); + assertEquals(531550884933581760, x *= x); + assertEquals(1980836332, x ^= ((-746269795.2320724)-((2400458512)>>((1290672548)>>>((((1536843439.5629003)&(3185059975.158061))*(tmp = -1339249276.2667086, tmp))&x))))); + assertEquals(941373096, x %= ((x+(-451098412))^(tmp = 1725497732, tmp))); + assertEquals(-1766019323, x += (tmp = -2707392419, tmp)); + assertEquals(2528947973, x >>>= (x^(-896237435.3809054))); + assertEquals(-263192576, x <<= (-866361580)); + assertEquals(-2008, x >>= (-2608071791)); + assertEquals(-88, x %= (((-1076807218.4792447)&((tmp = 601044863, tmp)>>((tmp = 1228976729, tmp)+((((-2711426325)*x)|x)|(x%(-2700007330.3266068))))))&(tmp = 3147972836.778858, tmp))); + assertEquals(1762886843, x ^= (tmp = 2532080403, tmp)); + assertEquals(1762886843, x %= ((((((tmp = -2059247788, tmp)>>x)/x)+(x<<x))^x)>>>(-1969283040.3683646))); + assertEquals(4812334726.587896, x += (tmp = 3049447883.587897, tmp)); + assertEquals(1, x /= x); + assertEquals(1, x *= x); + assertEquals(-2150507334, x -= ((tmp = 1578221999, tmp)+(tmp = 572285336, tmp))); + assertEquals(-4546475858941548500, x *= ((tmp = -931533139.5546813, tmp)^(tmp = 3061503275, tmp))); + assertEquals(-269064192, x |= ((207217276.91936445)<<(tmp = -957353678.4997551, tmp))); + assertEquals(1, x /= x); + assertEquals(1, x <<= (((1463856021.8616743)%(x*(tmp = -2286419102, tmp)))/(-2852887593))); + assertEquals(2223868564.8383617, x *= (tmp = 2223868564.8383617, tmp)); + assertEquals(918797189.9033995, x -= ((1305071374.9349623)%(x+(2211992629)))); + assertEquals(-2212004787.4668465, x -= (tmp = 3130801977.370246, tmp)); + assertEquals(31783, x >>= (2951958960)); + assertEquals(31783, x ^= ((((tmp = -2441511566, tmp)&((tmp = 91427553.90168321, tmp)+((tmp = 3001737720.327718, tmp)%x)))>>>(-2263859841))>>>((2109161329)>>(tmp = -2816295136.7443414, tmp)))); + assertEquals(4068224, x <<= (x%((tmp = -682576250.4464607, tmp)*(x/(((x-x)>>>(x&((((x<<(x<<x))>>>((((2243036981.528562)/(((-1839328916.9411087)>>(-1907748022.162144))<<(x+x)))+((tmp = 2362574171, tmp)<<(tmp = 1987834539, tmp)))|(-444329240)))|(399451601.1717081))>>x)))&(968363335.6089249)))))); + assertEquals(0.0030991932898194294, x /= ((tmp = 1067316540.5529796, tmp)^(-2388640366))); + assertEquals(0, x >>= x); + assertEquals(0, x >>>= (tmp = -393433349.1636851, tmp)); + assertEquals(0, x *= (((x^(((1806955787.471396)<<x)^((517668047.55566347)>>>(x%(x<<(tmp = -276586733.4844558, tmp))))))%(1661242196.1472542))|x)); + assertEquals(0, x |= (x>>x)); + assertEquals(-155236210, x |= (tmp = -155236210.19366312, tmp)); + assertEquals(-606392, x >>= ((tmp = -1533446042.97781, tmp)^x)); + assertEquals(-1, x >>= (936126810)); + assertEquals(2325115611, x -= (-2325115612)); + assertEquals(0, x -= x); + assertEquals(0, x >>= (tmp = -354826623, tmp)); + assertEquals(-0, x *= (-1232528947.7321298)); + assertEquals(0, x |= x); + assertEquals(0, x <<= (((tmp = 187758893.4254812, tmp)&(x-(tmp = 648201576, tmp)))&(385106597))); + assertEquals(0, x >>= (tmp = 2554891961, tmp)); + assertEquals(-1311492611.2970417, x += (-1311492611.2970417)); + assertEquals(-688179220.3221785, x += (623313390.9748632)); + assertEquals(1416835528, x &= (tmp = 1953739224, tmp)); + assertEquals(-11.04719252755072, x /= (-128252995)); + assertEquals(-6.287413042114223e-9, x /= (tmp = 1757033052.1558928, tmp)); + assertEquals(-4231171, x |= (((((2022730885.7773404)*((-2495777565.221855)|(tmp = 274627292, tmp)))<<(-3072596920.4902725))>>>((-2215057529)+(-1134713759.4247034)))^((tmp = -1888181788, tmp)/(572025985.2748461)))); + assertEquals(-4194305, x |= ((tmp = 167328318.038759, tmp)>>>(153800904.34551537))); + assertEquals(-1316525687, x -= (1312331382)); + assertEquals(1448723245.7863903, x += (2765248932.7863903)); + assertEquals(1.7219707102205526, x /= (tmp = 841317008, tmp)); + assertEquals(1872027792.5217001, x *= (x|(tmp = 1087142645.6665378, tmp))); + assertEquals(3504488055973669400, x *= x); + assertEquals(-1075254784, x |= x); + assertEquals(-5, x >>= (((844461331.8957539)-((x&x)<<((tmp = 1443904777, tmp)+(tmp = 736164505.3670597, tmp))))-(((tmp = 1348422110, tmp)>>((tmp = -2878252514, tmp)/(-1175443113)))|((-2138724317)%(2057081133))))); + assertEquals(-3.038875804165675e-9, x /= (1645345292.8698258)); + assertEquals(1.25204541454491e-18, x /= (-2427129055.274914)); + assertEquals(-1.7151576137235622e-9, x *= (-1369884505.6247284)); + assertEquals(1590804618, x ^= (1590804618.4910607)); + assertEquals(5061318665300252000, x *= (x+x)); + assertEquals(5061318665300252000, x %= ((tmp = 1102144242, tmp)*x)); + assertEquals(-7, x >>= (2772167516.624264)); + assertEquals(16383, x >>>= (-2979259214.5855684)); + assertEquals(47108415435, x *= ((2944456517.839616)>>>(1041288554.5330646))); + assertEquals(61, x >>>= (x^(((-1305163705)<<((948566605)-x))-x))); + assertEquals(0, x %= x); + assertEquals(0, x ^= (((tmp = 1918861879.3521824, tmp)/((x%(tmp = 945292773.7188392, tmp))%(x|x)))>>x)); + assertEquals(-0, x *= ((((x|((2810775287)|(tmp = 1265530406, tmp)))^((tmp = 3198912504.175658, tmp)-(((tmp = 1422607729.281712, tmp)<<(tmp = 2969836271.8682737, tmp))&x)))<<((tmp = 844656612, tmp)*(((((tmp = -828311659, tmp)%(((-2083870654)>>>(x^(((((933133782)-(tmp = 1033670745, tmp))-(629026895.4391923))%((-605095673.8097742)*((((-227510375.38460112)*x)+x)&(((((tmp = 472873752.68609154, tmp)^(tmp = 2815407038.712165, tmp))+((x>>>((tmp = -1331030665.3510115, tmp)>>>(2281234581)))-(x>>>x)))&(tmp = -2160840573.325921, tmp))&x))))<<(tmp = 1411888595, tmp))))|(((tmp = -915703839.0444739, tmp)/((x+(418836101.8158506))%(-1112605325.4404268)))&((-3098311830.6721926)-x))))-((49446671.477988124)*(-2522433127)))+((tmp = 443068797, tmp)>>(tmp = 418030554.97275746, tmp)))*((tmp = 38931296.738208175, tmp)+(1842742215.3282685)))))-((tmp = 1325672181.205841, tmp)^(tmp = 669284428, tmp)))); + assertEquals(-0, x *= (tmp = 93843030, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x ^= x); + assertEquals(0, x <<= x); + assertEquals(0, x >>>= (x%((((((tmp = -107458601, tmp)>>(x*((x|((tmp = 2117286494, tmp)>>((x^(tmp = 114214295.42048478, tmp))>>>(tmp = 1032826615, tmp))))&((x*x)&(-225386977.67686415)))))^((-780566702.5911419)+(-1113319771)))|(((x^x)<<(1288064444))>>(-2292704291.619477)))>>(365125945))-((tmp = -1986270727.235776, tmp)/x)))); + assertEquals(-0, x *= (((-18925517.67125845)|((((-1975220517)+(tmp = -1250070128.296064, tmp))+(1085931410.5895243))<<(((x|(((x*(tmp = 160207581.50536323, tmp))|(tmp = 1798744469.7958293, tmp))-x))>>>(((x+((x%x)&((((x^x)<<((tmp = 2538012074.623554, tmp)^x))*x)&x)))/(x+(tmp = -2563837407, tmp)))/(tmp = 2189564730, tmp)))/(((-1703793330.5770798)<<((176432492)|x))<<(1347017755.345185)))))<<(((tmp = -577100582.7258489, tmp)&x)/(-31246973)))); + assertEquals(0, x >>>= x); + assertEquals(NaN, x %= ((x*(tmp = 1167625971, tmp))&(((tmp = -770445060, tmp)>>((339248786)^((2058689781.2387645)-((-2381162024)*(660448066)))))&x))); + assertEquals(NaN, x += ((3088519732.515986)-(-267270786.06493092))); + assertEquals(0, x &= (tmp = 2748768426.3393354, tmp)); + assertEquals(-1109969306, x ^= ((-1109969306)>>>x)); + assertEquals(-1109969306, x %= (tmp = 1150376563.581773, tmp)); + assertEquals(-2058145178, x &= (-2057586057)); + assertEquals(-850185626, x |= ((x^(tmp = 1223093422, tmp))&((-589909669)<<(2299786170)))); + assertEquals(1489215443, x += (2339401069)); + assertEquals(-23592960, x <<= x); + assertEquals(2063937322, x ^= (-2053296342.2317986)); + assertEquals(12922122, x %= (x^((-2259987830)>>(x*(((tmp = -799867804.7716949, tmp)&(tmp = -1068744142, tmp))*(((((1091932754.8596292)-((tmp = -1778727010, tmp)>>(((tmp = 1207737073.2689717, tmp)-(x-(tmp = -1191958946, tmp)))+(-631801383.7488799))))-(-618332177))>>>(-156558558))>>>(3032101547.6262517))))))); + assertEquals(12922122, x &= x); + assertEquals(Infinity, x /= (x%x)); + assertEquals(0, x &= (x*(-227800722.62070823))); + assertEquals(-865648691, x ^= (-865648691)); + assertEquals(1, x /= (x%(tmp = 1524739353.8907173, tmp))); + assertEquals(16, x <<= (x<<(2335214658.789205))); + assertEquals(0, x &= ((tmp = 570332368.1239192, tmp)^(-2278439501))); + assertEquals(1881145344, x -= (((-569715735.8853142)+(2093355159))<<(tmp = 2788920949, tmp))); + assertEquals(0, x ^= x); + assertEquals(NaN, x -= ((tmp = -1427789954, tmp)%((((((411038329.49866784)-x)-(x<<((-1330832247)+x)))/x)^((x*(845763550.2134092))>>(tmp = 1427987604.5938706, tmp)))>>>(1857667535)))); + assertEquals(NaN, x /= (-313793473)); + assertEquals(0, x >>>= (x/x)); + assertEquals(1869358566, x -= (-1869358566)); + assertEquals(-1901664519209545200, x += ((tmp = 944729941.3936644, tmp)*(-2012918653))); + assertEquals(-1901664519209545200, x += ((tmp = 1348246793, tmp)/(x&x))); + assertEquals(-1576791552, x &= (tmp = 2719250966.739456, tmp)); + assertEquals(-305087899, x ^= (-2955630491.030272)); + assertEquals(0, x ^= (x%(1575252839.559443))); + assertEquals(4184604407, x += ((((tmp = -244720076.17657042, tmp)|(2819320515))^((((tmp = 1222623743.9184055, tmp)*(-95662379.577173))/(x/(x+(((x-(tmp = -3024718107.6310973, tmp))^(-1494390781))&(tmp = 2284054218.8323536, tmp)))))>>>(tmp = 2090069761, tmp)))>>>(x%x))); + assertEquals(3148907440, x -= (((tmp = -332379100.7695112, tmp)-(-1145399547))^(((((((tmp = 3133792677.785844, tmp)+x)<<(2306999139.5799255))>>((tmp = -2051266106, tmp)*(((((x+(((-728654312.8954825)>>(x>>>(((x%x)&(-1587152364))|(((((-2114138294)&x)&(1547554688))^x)-(-1856094268)))))*(((-1135018784)&((x+(tmp = -1444020289, tmp))|x))+x)))>>x)&x)/(2449005489))<<((131073798.64314616)%(x>>>((-2592101383.2205048)^(tmp = -757096673.0381112, tmp)))))))^(2766467316.8307915))-(-2465892914.515834))-((((tmp = 234064056, tmp)^((x>>>(1622627548.7944543))+(-1750474146)))|(-1959662039.4687617))^((-1222880974)&(-2794536175.906498)))))); + assertEquals(-1157627488, x &= (-1156639323)); + assertEquals(-1342170624, x <<= ((x/((((1829945345.0613894)/(x*((tmp = 1278865203.0854595, tmp)/(((tmp = -2298274086.519347, tmp)+(tmp = -545203761, tmp))-(tmp = 2712195820, tmp)))))>>>((tmp = 240870798.9384452, tmp)-(tmp = -3188865300.4768195, tmp)))>>>(x%((648799266)>>>(tmp = 24460403.864815235, tmp)))))|((tmp = 232533924, tmp)|x))); + assertEquals(-2684341248, x += x); + assertEquals(1073755136, x &= (((-662718514.9245079)>>(tmp = -1915462105, tmp))+(tmp = 1478850441.8689613, tmp))); + assertEquals(-1073755136, x /= (x|((tmp = -1767915185, tmp)|((325827419.1430224)|(((-1343423676)|(tmp = -1929549501, tmp))|(-866933068.9585254)))))); + assertEquals(-1073755136, x %= ((tmp = 547342356, tmp)-((tmp = 2213249646.7047653, tmp)-((((((-2463314705)^(tmp = -993331620, tmp))^(((x%x)>>(tmp = 1798026491.3658786, tmp))-(((1024072781)/(tmp = -2407354455, tmp))%(1973295010))))<<(-1966787233))^x)|(-1787730004))))); + assertEquals(-1073754452, x |= (tmp = 3099823788.077907, tmp)); + assertEquals(-1540683096, x &= (-1540674632.7013893)); + assertEquals(-1540683052, x ^= ((tmp = -126183090, tmp)>>>((-622437575.5788481)|((((tmp = -2947914022, tmp)%(((tmp = 2512586745, tmp)>>x)>>>((27238232.23677671)/(tmp = 3203958551, tmp))))/(tmp = 2906005721.402535, tmp))^((((tmp = 1763897860.737334, tmp)^(1445562340.2485332))/x)+(-2393501217.716533)))))); + assertEquals(-1258599433, x |= (tmp = 351291767.59661686, tmp)); + assertEquals(-1241560065, x |= (626346046.5083935)); + assertEquals(-1241560065, x ^= ((2263372092)/((tmp = -2868907862, tmp)>>>x))); + assertEquals(-893685228, x -= (tmp = -347874837, tmp)); + assertEquals(3401282068, x >>>= (x*x)); + assertEquals(0, x %= x); + assertEquals(0, x >>>= x); + assertEquals(-2079237393, x ^= (tmp = 2215729903, tmp)); + assertEquals(NaN, x %= ((((tmp = 3203450436, tmp)/(2867575150.6528325))&(1864945829))&((x&((((tmp = -1927086741.3438427, tmp)|x)|(-1783290909.3240588))*((-1074778499.0697656)*(x-((tmp = -848983542.8456669, tmp)^(tmp = -1324673961, tmp))))))>>(tmp = -2144580304.245896, tmp)))); + assertEquals(-43334009, x |= (x^(-43334009.72683525))); + assertEquals(-43334009, x &= x); + assertEquals(-43334009, x %= (tmp = 1252450645.060542, tmp)); + assertEquals(-43334009, x |= (((((((tmp = 968062202, tmp)/(x|(tmp = 2766801984, tmp)))*((2173353793.938968)>>(((tmp = -2459317247, tmp)<<(tmp = -2333601397, tmp))>>>((tmp = -578254251.8969193, tmp)*(tmp = 839964110.7893236, tmp)))))&(((1675305119)&(tmp = -929153707, tmp))*((x*x)*x)))/x)|(x/(tmp = 384740559.43867135, tmp)))%(1657362591))); + assertEquals(0, x -= x); + assertEquals(0, x %= (-1334758781.1087842)); + assertEquals(0, x -= x); + assertEquals(-54, x += ((tmp = -1787151355.470972, tmp)>>((tmp = 237028977, tmp)>>(((2829473542)<<(x>>>(((((((x-(-1950724753))*(((x>>>(2807353513.6283565))<<((-583810779.1155353)>>(x*x)))>>(-1068513265)))^(x^(-696263908.5131407)))%(((tmp = -1325619399, tmp)<<((tmp = -1030194450, tmp)-x))^x))+((-2852768585.3718724)>>(tmp = -3160022361, tmp)))%(x&x))>>(tmp = 2667222702.5454206, tmp))))+((804998368.8915854)<<x))))); + assertEquals(-54, x %= (-1601267268.4306633)); + assertEquals(1, x >>>= (tmp = -543199585.579128, tmp)); + assertEquals(4.732914708226396e-10, x /= (tmp = 2112862922, tmp)); + assertEquals(-4266932650, x -= ((((x^((((tmp = 2784618443, tmp)^(tmp = -2271260297.9010153, tmp))|((((tmp = -599752639.7516592, tmp)*(2751967680.3680997))^(tmp = -1478450055.578217, tmp))*x))-x))&((tmp = -520061982, tmp)-((tmp = 1400176711.9637299, tmp)^(((2100417541)|(x+(tmp = -674592897.0420957, tmp)))>>x))))^(tmp = -365650686.7947228, tmp))>>>((-2943521813)&(((tmp = -1888789582, tmp)>>(tmp = 700459655.488978, tmp))+(tmp = -1725725703.655931, tmp))))); + assertEquals(224277168, x <<= (tmp = 2885115011.8229475, tmp)); + assertEquals(224277168, x %= (tmp = -2655345206.442777, tmp)); + assertEquals(850395136, x <<= (x-(((((-769868538.1729524)/((tmp = -298603579, tmp)%(x^x)))+((2691475692)|(((x>>>(628995710.4745524))^(x<<(((tmp = -1046054749, tmp)|(919868171))-x)))^((-1377678789.8170452)&((3065147797)%(tmp = 2638804433, tmp))))))^(tmp = -2036295169, tmp))&(((tmp = -157844758.08476114, tmp)*(tmp = -2819601496, tmp))&((((tmp = 78921441, tmp)<<(653551762.5197772))/(1801316098))*(-1479268961.8276927)))))); + assertEquals(1645565728, x ^= (tmp = 1353013024, tmp)); + assertEquals(1645565728, x >>>= x); + assertEquals(3020513544, x += (1374947816)); + assertEquals(0, x %= x); + assertEquals(0, x %= ((((((tmp = -304228072.4115715, tmp)>>>((-90523260.45975709)-(tmp = -3013349171.084838, tmp)))%((-1640997281)*((tmp = -1600634553, tmp)%((tmp = 557387864, tmp)<<((888796080.766409)|(x^((((x%(((((tmp = 1164377954.1041703, tmp)*x)|(2742407432.192806))&((tmp = 1707928950, tmp)<<(1279554132.4481683)))+(tmp = -2108725405.7752397, tmp)))%(tmp = -465060827, tmp))^((tmp = 2422773793, tmp)+x))^((((((((tmp = -1755376249, tmp)^((-267446806)^x))/(((tmp = -1808578662.4939392, tmp)+((tmp = -1997100217, tmp)+x))+(((tmp = -2469853122.411479, tmp)/x)>>(tmp = 660624616.7956645, tmp))))%((x<<((((((tmp = -1701946558, tmp)-(tmp = 133302235, tmp))>>>x)/(738231394))<<(-1060468151.4959564))&(((((-1877380837.4678264)|(tmp = 2366186363, tmp))%x)>>>(-2382914822.1745577))>>((-1874291848.9775913)<<(tmp = 2522973186, tmp)))))<<(-2672141993)))|(tmp = 732379966, tmp))%x)^x)^x))))))))%(tmp = 2385998902.7287374, tmp))*x)+(tmp = -2195749866.017106, tmp))); + assertEquals(401488, x ^= (((-320896627)>>>(tmp = 2812780333.9572906, tmp))&(tmp = -2088849328, tmp))); + assertEquals(-1661116571.0046256, x += (tmp = -1661518059.0046256, tmp)); + assertEquals(-1616122720, x <<= x); + assertEquals(-1616122720, x >>= x); + assertEquals(-390439413, x %= (tmp = -1225683307, tmp)); + assertEquals(-84189205, x |= ((x|(2054757858))^(((x<<(((x|x)|(((x>>>((-2938303938.1397676)<<((2993545056)^((tmp = -643895708.5427527, tmp)/((1371449825.5345795)-(1896270238.695752))))))-(tmp = 1061837650, tmp))+(x+(tmp = 3072396681, tmp))))>>(x-((((tmp = -1877865355.1550744, tmp)&x)%(-2766344937))>>>(2055121782)))))-((x<<x)|(tmp = -2742351880.1974454, tmp)))<<((-2600270279.219802)>>(-1625612979))))); + assertEquals(-168378410, x += x); + assertEquals(-168378410, x &= x); + assertEquals(-1534983792, x &= (-1501412943)); + assertEquals(-1821543761, x ^= (938439487)); + assertEquals(-1821543761, x &= (x^(((tmp = -4237854, tmp)>>x)/x))); + assertEquals(2358, x >>>= (2954252724.620632)); + assertEquals(4716, x <<= ((-75522382.8757689)/((tmp = 1074334479, tmp)|((tmp = -720387522, tmp)>>(x>>>(-3085295162.6877327)))))); + assertEquals(-1313079316, x |= (2981887904.020387)); + assertEquals(-1957790646, x -= (644711330)); + assertEquals(17831, x >>>= ((tmp = -2550108342, tmp)-(((tmp = 454671414.0146706, tmp)+(-661129693.9333956))>>(x>>>(((tmp = 1752959432.3473055, tmp)*(-2619510342.1812334))%(tmp = -456773274.2411971, tmp)))))); + assertEquals(689287937.6879716, x -= ((tmp = -397126863.6879716, tmp)-(((x>>x)^(x/(-1387467129.6278908)))|((x>>((tmp = -2361114214.8413954, tmp)<<(tmp = -805670024.4717407, tmp)))<<(-2724018098))))); + assertEquals(1378575875.3759432, x += x); + assertEquals(84112428460187.8, x *= (((((2681425112.3513584)%(tmp = -1757945333, tmp))|x)>>(-1793353713.0003397))%x)); + assertEquals(-3221, x >>= (-1976874128)); + assertEquals(-3221, x %= (((tmp = 2318583056.834932, tmp)|((tmp = -1016115125, tmp)+((-472566636.32567954)+x)))|(tmp = 3135899138.065598, tmp))); + assertEquals(-6596608, x <<= x); + assertEquals(-1249902592, x <<= (((tmp = -2025951709.5051148, tmp)/((-465639441)<<(-2273423897.9682302)))*((tmp = -2408892408.0294642, tmp)-(tmp = 1017739741, tmp)))); + assertEquals(73802092170444800, x *= (tmp = -59046275, tmp)); + assertEquals(-1619001344, x <<= x); + assertEquals(0, x <<= (tmp = 1610670303, tmp)); + assertEquals(-0, x *= ((((x+(tmp = 2039867675, tmp))|(tmp = 399355061, tmp))<<(1552355369.313559))^x)); + assertEquals(0, x *= x); + assertEquals(0, x >>>= (((2875576018.0610805)>>x)%(tmp = -2600467554, tmp))); + assertEquals(2290405226.139538, x -= (-2290405226.139538)); + assertEquals(0, x %= x); + assertEquals(0, x ^= (((tmp = 2542309844.485515, tmp)-x)%((-2950029429.0027323)/(tmp = 2943628481, tmp)))); + assertEquals(0, x += x); + assertEquals(0, x -= x); + assertEquals(0, x >>>= (tmp = 2337330038, tmp)); + assertEquals(0, x += (x/(((292272669.0808271)&(tmp = 2923699026.224247, tmp))^(tmp = 367745855, tmp)))); + assertEquals(0, x &= x); + assertEquals(0, x %= ((tmp = 1565155613.3644123, tmp)<<(-308403859.5844681))); + assertEquals(-1845345399.3731332, x += (tmp = -1845345399.3731332, tmp)); + assertEquals(5158590659731951000, x *= (-2795460763.8680177)); + assertEquals(-364664, x >>= (1837745292.5701954)); + assertEquals(1, x /= x); + assertEquals(-860616114.8182092, x += ((tmp = 2076961323.1817908, tmp)+(-2937577439))); + assertEquals(-860616115, x ^= ((x*(tmp = 2841422442.583121, tmp))>>>((tmp = 1929082917.9039137, tmp)>>(-2602087246.7521305)))); + assertEquals(-38387843, x |= (3114677624)); + assertEquals(2927507837, x += (tmp = 2965895680, tmp)); + assertEquals(1, x /= x); + assertEquals(-1792887531, x *= (-1792887531)); + assertEquals(-0, x %= ((x^x)+x)); + assertEquals(-0, x %= (tmp = 2800752702.562547, tmp)); + assertEquals(1384510548, x ^= (tmp = 1384510548, tmp)); + assertEquals(42251, x >>= (1645421551.363844)); + assertEquals(0, x >>>= (17537561)); + assertEquals(-2076742862, x ^= (tmp = 2218224434, tmp)); + assertEquals(-2.790313825067623, x /= (744268563.3934636)); + assertEquals(5313538, x &= (((((tmp = -2406579239.0691676, tmp)+((-1470174628)+(((tmp = -783981599, tmp)<<(tmp = -1789801141.272646, tmp))^(((((((tmp = -844643189.5616491, tmp)&(tmp = -252337862, tmp))&(x|x))%((-3159642145.7728815)+(tmp = 2149920003.9525595, tmp)))&(x>>(1737589807.9431858)))-((((((((1610161800)<<(497024994))>>x)<<x)/x)>>>x)&x)-(757420763.2141517)))-(tmp = -3061016994.9596977, tmp)))))/(tmp = 1810041920.4089384, tmp))&(tmp = 5887654.786785364, tmp))&((tmp = 1626414403.2432103, tmp)+(x%x)))); + assertEquals(-2147483648, x <<= (tmp = 1304102366.8011155, tmp)); + assertEquals(-208418816, x %= (((((-2850404799)*(x+(3158771063.226051)))*(-2017465205))/(x>>x))>>(x%(tmp = 2760203322, tmp)))); + assertEquals(-2189223477, x -= (1980804661)); + assertEquals(-859239912, x ^= (tmp = 2974421971.3544703, tmp)); + assertEquals(-1599850415, x ^= (tmp = -2475871671.140151, tmp)); + assertEquals(-1600636847, x += ((((tmp = -1311002944, tmp)<<((tmp = -1137871342, tmp)<<(tmp = 115719116, tmp)))/(413107255.6242596))<<(x>>((((-1908022173)&(((-1519897333)^((x>>(x*(tmp = -2886087774.426503, tmp)))*(tmp = 530910975, tmp)))+(-2579617265.889692)))+((2518127437.127563)>>>((tmp = 481642471.56441486, tmp)>>>(792447239))))^(x<<(248857393.6819017)))))); + assertEquals(-191, x >>= (-1591265193)); + assertEquals(-192.27421813247196, x += ((tmp = 2627329028.207775, tmp)/(tmp = -2061914644.9523563, tmp))); + assertEquals(1230613220, x ^= (tmp = 3064354212.307105, tmp)); + assertEquals(1230613220, x &= x); + assertEquals(1230613220, x %= (1833479205.1064768)); + assertEquals(1230613220, x >>>= ((((1559450742.1425748)|((2151905260.956583)*(1213275165)))%(514723483.12764716))>>>x)); + assertEquals(1230613493, x |= ((((3004939197.578903)*(tmp = -576274956, tmp))+((tmp = 1037832416.2243971, tmp)^x))>>>(tmp = 2273969109.7735467, tmp))); + assertEquals(2461226986, x += x); + assertEquals(-27981, x >>= ((692831755.8048055)^((tmp = -1593598757, tmp)%(x-((((-1470536513.882593)|((tmp = -2716394020.466401, tmp)|(tmp = 2399097686, tmp)))&x)%x))))); + assertEquals(-1.4660454948034359e+23, x *= (((x>>>((((((tmp = -3056016696, tmp)<<(-2882888332))*(2041143608.321916))&(((tmp = -634710040, tmp)|(tmp = -2559412457, tmp))>>(1916553549.7552106)))%((-2150969350.3643866)*x))<<((x*(tmp = 2657960438.247278, tmp))|x)))%((tmp = 526041379, tmp)*(tmp = 2514771352.4509397, tmp)))*(1219908294.8107886))); + assertEquals(-1.4660454948034359e+23, x -= ((1709004428)>>(((x|(-422745730.626189))%x)>>x))); + assertEquals(-2247766068, x %= (-3105435508)); + assertEquals(-386845856.0649812, x -= (-1860920211.9350188)); + assertEquals(-386846803.0649812, x -= ((((-3214465921)|((tmp = -1326329034, tmp)+(((tmp = -1203188938.9833462, tmp)%((((((-1318276502)+(x+x))^((x<<x)%(x>>>x)))+(tmp = -439689881, tmp))+((-1455448168.695214)^(x-((-388589993)>>((((940252202)^(-2218777278))|x)/(tmp = -1007511556, tmp))))))&(-140407706.28176737)))-(x/((888903270.7746506)-((tmp = -2885938478.632409, tmp)<<(((((tmp = -1750518830.270917, tmp)>>(((((((tmp = 868557365.7908674, tmp)/(tmp = -2805687195.5172157, tmp))*x)|((((((-1342484550)-((tmp = 1089284576, tmp)^(tmp = 120651272, tmp)))<<(tmp = 2230578669.4642825, tmp))-(x*x))%(x^(((tmp = -3177941534, tmp)+(x>>(-1595660968)))/(-1738933247))))>>>(tmp = 2860175623, tmp)))-(((2392690115.8475947)>>>(tmp = -1754609670.2068992, tmp))>>>(tmp = 2615573062, tmp)))-(tmp = 2590387730, tmp))^((x+((((x-(tmp = -2823664112.4548965, tmp))*(200070977))>>>(((x|((((tmp = 1361398, tmp)>>((tmp = 1649209268, tmp)%x))+x)+(x>>>(tmp = -2379989262.1245675, tmp))))|(x^((tmp = -647953298.7526417, tmp)-x)))&(tmp = -1881232501.1945808, tmp)))>>>x))%(x^(tmp = -1737853471.005935, tmp)))))>>>(427363558))>>>((tmp = -3076726422.0846386, tmp)^(-1518782569.1853383)))/x)))))))|x)>>>(1854299126))); + assertEquals(-386846803.0649812, x -= (x%x)); + assertEquals(238532, x >>>= (-448890706.10774803)); + assertEquals(232, x >>>= (-791593878)); + assertEquals(232, x <<= (((x^((x-x)&(tmp = 1219114201, tmp)))/(tmp = -427332955, tmp))%(tmp = 1076283154, tmp))); + assertEquals(210, x ^= (x>>>((2975097430)>>>x))); + assertEquals(1, x /= x); + assertEquals(2317899531, x *= (2317899531)); + assertEquals(1131786, x >>>= x); + assertEquals(2301667519.6379366, x += ((tmp = 193109669.63793683, tmp)+(tmp = 2107426064, tmp))); + assertEquals(3842614963.6379366, x += (((-1676516834)>>>(tmp = -1817478916.5658965, tmp))^(((tmp = 1122659711, tmp)>>>(tmp = -2190796437, tmp))|(tmp = -2754023244, tmp)))); + assertEquals(-452352333, x &= x); + assertEquals(-863, x >>= x); + assertEquals(-3.777863669459606e-7, x /= (2284359827.424491)); + assertEquals(-3.777863669459606e-7, x %= ((tmp = -2509759238, tmp)>>>x)); + assertEquals(0, x <<= (-814314066.6614306)); + assertEquals(0, x %= (tmp = 190720260, tmp)); + assertEquals(2301702913, x += (2301702913)); + assertEquals(-249158048, x >>= (tmp = -2392013853.302008, tmp)); + assertEquals(-249158048, x >>= x); + assertEquals(-498316096, x += x); + assertEquals(-498316096, x %= (tmp = 2981330372.914731, tmp)); + assertEquals(106616.2199211318, x *= (((((tmp = 1020104482.2766557, tmp)^((tmp = -416114189.96786, tmp)>>>(1844055704)))|(tmp = 1665418123, tmp))>>(1826111980.6564898))/(-2446724367))); + assertEquals(106616, x |= x); + assertEquals(1094927345, x -= (((-1229759420)|(741260479.7854375))-x)); + assertEquals(8353, x >>= x); + assertEquals(0, x >>>= (tmp = -327942828, tmp)); + assertEquals(-953397616.8888416, x += (tmp = -953397616.8888416, tmp)); + assertEquals(-1906641240.7776833, x += (x+((-3033450184.9106326)>>>(tmp = 2090901325.5617187, tmp)))); + assertEquals(-1906641240.7776833, x %= (tmp = 2584965124.3953505, tmp)); + assertEquals(-1098907671, x |= (tmp = -1272590495, tmp)); + assertEquals(-1.8305258600334393, x /= (600323489)); + assertEquals(-1, x &= x); + assertEquals(-1, x |= ((x+x)-x)); + assertEquals(1, x *= x); + assertEquals(867473898, x ^= (tmp = 867473899.0274491, tmp)); + assertEquals(6, x >>>= (tmp = 1174763611.341228, tmp)); + assertEquals(0, x >>= ((689882795)^(2250084531))); + assertEquals(0, x /= (tmp = 2545625607, tmp)); + assertEquals(0, x >>= x); + assertEquals(0, x += x); + assertEquals(0, x -= (x*(-1098372339.5157008))); + assertEquals(NaN, x %= x); + assertEquals(NaN, x -= (tmp = -1797344676.375759, tmp)); + assertEquals(1121476698, x |= (tmp = 1121476698, tmp)); + assertEquals(1, x /= x); + assertEquals(1, x &= (-191233693)); + assertEquals(330137888.92595553, x += (330137887.92595553)); + assertEquals(-1792236714, x ^= (tmp = 2256609910, tmp)); + assertEquals(269000724, x &= (316405813.62093115)); + assertEquals(256, x >>= x); + assertEquals(256, x %= ((2556320341.54669)|(1066176021.2344948))); + assertEquals(256, x |= x); + assertEquals(131072, x <<= ((-1650561175.8467631)|x)); + assertEquals(-286761951, x -= ((tmp = 287024095, tmp)-((-2293511421)&(x|x)))); + assertEquals(-1561852927, x &= (3002663949.0989227)); + assertEquals(-460778761, x %= (tmp = -550537083, tmp)); + assertEquals(-3023749308.0492287, x += (tmp = -2562970547.0492287, tmp)); + assertEquals(-481313332.04922867, x %= ((x|((tmp = -855929299, tmp)%((2181641323)%(x|(220607471.33018696)))))&x)); + assertEquals(17510668, x &= (tmp = 363557663, tmp)); + assertEquals(12552, x &= (3020225307)); + assertEquals(1814655896, x |= ((x<<(((-1475967464)*(-3122830185))*x))+(x^(-2480340864.2661023)))); + assertEquals(-3209124403525266400, x -= ((1146847590)*(tmp = 2798213497, tmp))); + assertEquals(-6418248807050533000, x += x); + assertEquals(1.1856589432073933e+28, x *= (-1847324681.313275)); + assertEquals(-1238853292, x ^= (-1238853292)); + assertEquals(-77428331, x >>= (x&((((2043976651.8514216)>>>x)^(x>>>(((tmp = -1785122464.9720652, tmp)%x)<<(1570073474.271266))))*x))); + assertEquals(2011, x >>>= x); + assertEquals(2011, x &= x); + assertEquals(0, x >>= (-2682377538)); + assertEquals(-1.1367252770299785, x -= (((tmp = 2704334195.566802, tmp)/(2379056972))%((((-1764065164)*((((468315142.8822602)>>((x%(((tmp = 2537190513.506641, tmp)+((x&(x|((tmp = -947458639, tmp)^(2653736677.417406))))*((x<<((1243371170.1759553)>>>(((tmp = 1572208816, tmp)<<((tmp = 963855806.1090456, tmp)>>>x))%((-3078281718.7743487)*x))))^(-1154518374))))^(-2839738226.6314087)))^((-2865141241.190915)*(-2400659423.8207664))))>>((tmp = 32940590, tmp)/(tmp = 2917024064.570817, tmp)))+(((27601850)/(tmp = 3168834986, tmp))>>x)))+(tmp = 2528181032.600125, tmp))/(3162473952)))); + assertEquals(-1697395408.7948515, x -= (1697395407.6581264)); + assertEquals(1536992607912062500, x *= (tmp = -905500627.5781817, tmp)); + assertEquals(102759872, x >>= (tmp = -707887133.4484048, tmp)); + assertEquals(102759872, x %= (tmp = -1764067619.7913327, tmp)); + assertEquals(12543, x >>>= (-144142995.1469829)); + assertEquals(-2059555229.2592103, x += ((-2059555229.2592103)-x)); + assertEquals(-537022593, x |= (tmp = -2770761410.407701, tmp)); + assertEquals(23777505, x ^= (-560496738.6854918)); + assertEquals(-64329014115772310, x *= ((tmp = -2729234369.198843, tmp)+x)); + assertEquals(189083830, x ^= (tmp = 933619934, tmp)); + assertEquals(189083830, x %= ((tmp = -2918083254, tmp)-(x|(x^(-2481479224.0329475))))); + assertEquals(378167660, x += x); + assertEquals(-0.45833387791900504, x /= ((tmp = 2727991875.241294, tmp)<<(tmp = 2570034571.9084663, tmp))); + assertEquals(0, x <<= x); + assertEquals(-0, x /= (tmp = -67528553.30662966, tmp)); + assertEquals(0, x <<= (938440044.3983492)); + assertEquals(-945479171, x ^= (tmp = -945479171, tmp)); + assertEquals(-225632619284361200, x *= (238643670.00884593)); + assertEquals(-0, x %= x); + assertEquals(-585826304, x ^= ((-1256265560)<<(tmp = 1144713549, tmp))); + assertEquals(-671583855, x ^= (183333265.1468178)); + assertEquals(-484311040, x <<= x); + assertEquals(-3969762.62295082, x /= ((((tmp = -1164308668.931008, tmp)-x)%x)>>>(((397816647)>>(-1605343671.4070785))<<x))); + assertEquals(758097879, x ^= ((tmp = -2871307491, tmp)^(-2043176492.646442))); + assertEquals(0, x *= ((x>>(tmp = 1983292927, tmp))&(tmp = -860505131.4484091, tmp))); + assertEquals(0, x <<= x); + assertEquals(0, x &= x); + assertEquals(0, x %= ((3132981707)-(-2832016477))); + assertEquals(0, x >>= (x<<((1830195133.0342631)>>>(tmp = -1003969250, tmp)))); + assertEquals(NaN, x %= x); + assertEquals(NaN, x += (tmp = 273271019.87603223, tmp)); + assertEquals(NaN, x += (625749326.1155348)); + assertEquals(0, x >>= (tmp = -531039433.3702333, tmp)); + assertEquals(0, x -= (((tmp = 2029464099, tmp)-(x-(tmp = -329058111.411458, tmp)))*(x<<x))); + assertEquals(-0, x *= ((-1112957170.5613296)|((tmp = 847344494, tmp)>>>(tmp = 2735119927, tmp)))); + assertEquals(-0, x /= (tmp = 544636506, tmp)); + assertEquals(0, x >>>= (x^(545093699))); + assertEquals(0, x %= (((tmp = -2208409647.5052004, tmp)+(3083455385.374988))+(((-482178732.7077277)*x)>>>((2661060565)*(-2125201239))))); + assertEquals(0, x >>>= (-212334007.34016395)); + assertEquals(0.7004300865203454, x -= ((2032883941)/(-2902336693.0154715))); + assertEquals(0, x <<= (x<<((265868133.50175047)>>>(1162631094)))); + assertEquals(604920272.4394834, x -= (-604920272.4394834)); + assertEquals(604920272, x &= x); + assertEquals(0, x <<= (((-1961880051.1127694)%(tmp = 1715021796, tmp))|((tmp = 2474759639.4587016, tmp)|(243416152.55635)))); + assertEquals(-46419074, x |= (((tmp = -518945938.5238774, tmp)%((x+(tmp = 242636408, tmp))+(-1974062910)))|(1546269242.0259726))); + assertEquals(-46419074, x += ((-629802130)*((tmp = -658144149, tmp)%((-905005358.5370393)>>>x)))); + assertEquals(-46419074, x |= (x%(-1103652494))); + assertEquals(7892881050983985, x *= (-170035297.36469936)); + assertEquals(1105701997.4273424, x %= ((((-490612260.0023911)>>>(tmp = 1803426906, tmp))^(x%(2725270344.2568116)))-(1010563167.8934317))); + assertEquals(1088619532, x &= (-2232199650)); + assertEquals(1073807364, x &= (-888024506.5008001)); + assertEquals(1153062254980628500, x *= x); + assertEquals(1153062255703627000, x -= (tmp = -722998613.897227, tmp)); + assertEquals(-1141418584, x |= (3017232552.4814596)); + assertEquals(-373464140, x ^= (-2914372068)); + assertEquals(994050048, x <<= x); + assertEquals(0, x ^= x); + assertEquals(0, x &= (tmp = -3166402389, tmp)); + assertEquals(0, x &= ((-1760842506.337213)|(tmp = 2538748127.795164, tmp))); + assertEquals(-0, x /= (-2635127769.808626)); + assertEquals(0, x &= ((((tmp = 1414701581, tmp)^(((2425608769)/((x<<x)^(x-x)))^((tmp = -2641946468.737288, tmp)|(tmp = -313564549.1754241, tmp))))*(tmp = -2126027460, tmp))|(-2255015479))); + assertEquals(225482894, x ^= (225482894.8767246)); + assertEquals(0, x ^= x); + assertEquals(306216231, x += (tmp = 306216231, tmp)); + assertEquals(306216231, x -= ((-465875275.19848967)&((-806775661.4260025)/((((-184966089.49763203)>>>((x>>x)+((tmp = -1951107532, tmp)|x)))%x)*((2704859526.4047284)%((x*x)>>x)))))); + assertEquals(30754, x &= (1706162402.033193)); + assertEquals(30454.010307602264, x -= (((590456519)>>>(tmp = 2713582726.8181214, tmp))/x)); + assertEquals(8419062, x |= ((2848886788)<<(tmp = 2993383029.402275, tmp))); + assertEquals(16, x >>= (tmp = -1651287021, tmp)); + assertEquals(1, x /= x); + assertEquals(-1407643485, x ^= (-1407643486)); + assertEquals(2, x >>>= (-1126004674)); + assertEquals(470812081, x ^= ((-2411718964)>>>x)); + assertEquals(550443688.6407901, x += (tmp = 79631607.6407901, tmp)); + assertEquals(3669092443.64079, x -= (-3118648755)); + assertEquals(-625874853, x <<= (((tmp = -1640437346, tmp)/(((x*x)>>>x)<<x))/x)); + assertEquals(-1431439050363516700, x *= (2287101077)); + assertEquals(-1921660672, x |= ((((((((-1912249689.9978154)&(-1676922742.5343294))*(2625527768))<<((820676465)^(((x+(tmp = -852743692, tmp))&((x-((((1361714551)/(311531668))>>>(tmp = -1330495518.8175917, tmp))<<(((tmp = 1369938417.8760853, tmp)*(-1217947853.8942266))<<(-2048029668))))-(-513455284)))>>>(tmp = 1980267333.6201067, tmp))))<<(((1503464217.2901971)>>(tmp = 2258265389, tmp))>>>(1868451148)))&(x-(x^(tmp = -1565209787, tmp))))*x)<<(tmp = -2426550685, tmp))); + assertEquals(-1921660672, x %= (((tmp = 523950472.3315773, tmp)+(((2971865706)^x)-x))&(-1773969177))); + assertEquals(420176973.1169958, x += (2341837645.116996)); + assertEquals(420176973, x >>>= (((tmp = -2485489141, tmp)<<((tmp = -2520928568.360244, tmp)+x))&(543950045.0932506))); + assertEquals(50, x ^= (x|((tmp = 2001660699.5898843, tmp)>>>(tmp = 1209151128, tmp)))); + assertEquals(138212770720.96973, x *= (2764255414.4193945)); + assertEquals(-28683, x |= (((-535647551)|x)>>((((2065261509)>>(-354214733))*x)+(-3218217378.2592907)))); + assertEquals(1627048838, x ^= (tmp = -1627044749, tmp)); + assertEquals(-839408795, x ^= (2903337187.480303)); + assertEquals(-1000652427, x += (tmp = -161243632, tmp)); + assertEquals(740237908.4196916, x += ((tmp = 1587000348, tmp)+(tmp = 153889987.41969144, tmp))); + assertEquals(Infinity, x /= (((((-615607376.1012697)&(57343184.023578644))+((-1967741575)|(-3082318496)))<<(((tmp = -958212971.99792, tmp)>>(tmp = 2962656321.3519197, tmp))-(x|(x*(969365195)))))<<(tmp = -1739470562.344624, tmp))); + assertEquals(-Infinity, x /= ((tmp = -1736849852, tmp)%x)); + assertEquals(0, x <<= x); + assertEquals(0, x %= (tmp = -226505646, tmp)); + assertEquals(1982856549, x -= (((x+(-1982856549))%(-2274946222))>>(x%(((tmp = -1289577208.9097936, tmp)>>x)^(778147661))))); + assertEquals(1648018703, x ^= ((3085618856)+((tmp = 1546283467, tmp)&(((x|((-2376306530)*(((((((tmp = -2807616416, tmp)%(((((tmp = 347097983.1491085, tmp)<<x)|(((((1135380667)/(x>>>(tmp = 1679395106, tmp)))^((1277761947)<<((tmp = -1614841203.5244312, tmp)>>x)))%((tmp = 1552249234.2065845, tmp)>>>x))>>>(tmp = -1677859287, tmp)))>>>(2605907565))/(tmp = 2291657422.221277, tmp)))%(((tmp = 425501732.6666014, tmp)>>>(1327403879.455553))+x))>>((tmp = -3075752653.2474413, tmp)&(x-(tmp = -71834630, tmp))))|((((2532199449.6500597)*(-842197612.4577162))%x)>>x))*(((1220047194.5100307)<<((tmp = 1642962251, tmp)<<((-662340)>>>((tmp = -1672316631.3251066, tmp)<<((tmp = 1762690952.542441, tmp)-(x/(1904755683.3277364)))))))>>x))|(((((tmp = 1625817700.7052522, tmp)%(tmp = -2990984460, tmp))|(2395645662))-((2619930607.550086)>>x))^(tmp = 130618712, tmp)))))&((-3142462204.4628367)/(1078126534.8819227)))%(((tmp = -256343715.2267704, tmp)+x)^(tmp = 2009243755, tmp)))))); + assertEquals(1937698223, x |= (((tmp = 866354374.7435778, tmp)+(tmp = 2751925259.3264275, tmp))%(-2252220455))); + assertEquals(0, x -= x); + assertEquals(-823946290.6515498, x -= (tmp = 823946290.6515498, tmp)); + assertEquals(706970324, x ^= (-457174758)); + assertEquals(32916, x &= (25740724)); + assertEquals(0, x >>>= ((-1658933418.6445677)|(tmp = -846929510.4794133, tmp))); + assertEquals(0, x ^= ((-834208600)/((-1256752740)&(tmp = 1973248337.8973258, tmp)))); + assertEquals(-1639195806, x += (-1639195806)); + assertEquals(-1559416478, x ^= ((tmp = 1349893449.0193534, tmp)*(tmp = 2044785568.1713037, tmp))); + assertEquals(0, x &= ((x>>(tmp = 1720833612, tmp))/((x+(-1305879952.5854573))^x))); + assertEquals(-0, x *= (tmp = -1713182743, tmp)); + assertEquals(0, x >>= x); + assertEquals(NaN, x /= (((x%((x>>>(((-1515761763.5499895)^(-3076528507.626539))<<(tmp = 1293944457.8983147, tmp)))<<(tmp = 276867491.8483894, tmp)))>>(tmp = -2831726496.6887417, tmp))%((((tmp = 1780632637.3666987, tmp)^x)%((208921173.18897665)>>(tmp = 633138136, tmp)))+x))); + assertEquals(0, x >>= (tmp = -2755513767.0561147, tmp)); + assertEquals(0, x |= x); + assertEquals(840992300.0324914, x -= ((-840992300.0324914)+x)); + assertEquals(840992300, x &= x); + assertEquals(-1094140277, x ^= (2364029095)); + assertEquals(-Infinity, x /= ((((((1257084956)<<(2009241695))>>(x+x))*x)>>>x)>>>(205318919.85870552))); + assertEquals(-Infinity, x -= (((x>>>(tmp = 3037168809.20163, tmp))&x)*(x&(((806151109)*x)-(tmp = -1741679480.58333, tmp))))); + assertEquals(400659949, x ^= (tmp = 400659949, tmp)); + assertEquals(5, x >>= (tmp = 1175519290, tmp)); + assertEquals(5, x |= x); + assertEquals(0, x >>= x); + assertEquals(0, x >>= ((1317772443)&(x<<x))); + assertEquals(-1123981819, x ^= (tmp = 3170985477, tmp)); + assertEquals(1123864651, x ^= ((x%(((x&x)&(-2606227299.7590737))<<((tmp = -2018123078.1859496, tmp)*x)))|(x+(((((1935939774.8139446)/((-1303958190)/(2802816697.32639)))<<((2880056582)*x))+x)+x)))); + assertEquals(1543368927, x |= (-2795691884)); + assertEquals(NaN, x /= (x%((tmp = -1129915114, tmp)<<x))); + assertEquals(NaN, x += (tmp = -3045743135, tmp)); + assertEquals(NaN, x -= (tmp = -2849555731.8207827, tmp)); + assertEquals(NaN, x /= (((((2127485827)>>>((((tmp = 363239924, tmp)>>x)|((((tmp = -1419142286.0523334, tmp)-(x<<x))^(tmp = -1990365089.8283136, tmp))*((tmp = 2780242444.0739098, tmp)>>>(((-2336511023.342298)&x)/(tmp = 2296926221.402897, tmp)))))>>((tmp = 1378982475.6839466, tmp)>>(tmp = -816522530, tmp))))&(x^(tmp = -1668642255.0586753, tmp)))%(((tmp = 921249300.1500335, tmp)^x)*(tmp = -2228816905, tmp)))>>x)); + assertEquals(-1460685191, x |= (tmp = 2834282105, tmp)); + assertEquals(-1463439264, x &= (tmp = 2881860064.146755, tmp)); + assertEquals(20.98100714963762, x /= (((3017150580.7875347)^((250499372.5339837)<<(tmp = -42767556.30788112, tmp)))|(x%(-2829281526)))); + assertEquals(1, x /= x); + assertEquals(2, x += x); + assertEquals(8, x <<= x); + assertEquals(0, x >>>= ((730174750)>>>x)); + assertEquals(0, x ^= x); + assertEquals(-1459637373, x ^= (2835329923.456409)); + assertEquals(-1233115861, x ^= (511678120)); + assertEquals(95682857, x >>>= ((tmp = 1534570885, tmp)|(tmp = -414425499.3786578, tmp))); + assertEquals(70254633, x &= (-1502067585)); + assertEquals(51384749748909710, x *= (tmp = 731407276, tmp)); + assertEquals(9390482.873469353, x %= (tmp = -592576964.7982686, tmp)); + assertEquals(4695241, x >>>= (tmp = -1879898431.5395758, tmp)); + assertEquals(-3129811912538149000, x += (((-727481809)^((3106908604)%x))*((((tmp = -1218123690, tmp)^(x>>((-942923806)^x)))/(x+x))>>>(-1508881888.969373)))); + assertEquals(1596870236, x ^= (-1135673764.9721224)); + assertEquals(0, x ^= x); + assertEquals(2133782410, x |= (((-2202469371)>>((tmp = 1327588406.183342, tmp)/(tmp = 253581265.7246865, tmp)))-((tmp = 2226575446.838795, tmp)^x))); + assertEquals(-81895217.83608055, x -= (tmp = 2215677627.8360806, tmp)); + assertEquals(812089344, x <<= ((tmp = 882824005, tmp)/(((x>>((((((((tmp = 1211145185, tmp)/((-137817273)-(((tmp = 2165480503.1144185, tmp)-(-1840859887.1288517))*((155886014.8393339)>>((-1984526598)<<(tmp = 1331249058.3246582, tmp))))))>>(x*x))%(2830324652))%(933701061))|(1346496215))^(tmp = -988800810, tmp))+x))>>>x)<<(-2372088384)))); + assertEquals(812089344, x <<= x); + assertEquals(8472, x %= ((((x|(((x%(tmp = 2772099481.664402, tmp))+(2894690616))-x))&(x&(((-715790638.6454093)>>(tmp = -1447931029, tmp))-(tmp = 1761027889, tmp))))^x)%(((tmp = 830969811, tmp)|x)|((-1102267929)-(3193018687))))); + assertEquals(-0.0000028559857417864914, x /= (-2966401364)); + assertEquals(0, x >>= x); + assertEquals(-701800392, x += (tmp = -701800392, tmp)); + assertEquals(2034756873, x -= (tmp = -2736557265, tmp)); + assertEquals(-0.9475075048394501, x /= (((((82879340.27231383)+((tmp = -2876678920.653639, tmp)*(-2801097850)))<<x)>>>((x<<(((((x|x)&(tmp = -1572694766, tmp))>>(x+(x/((x-(((tmp = 1435301275, tmp)|(tmp = 983577854.212041, tmp))>>(tmp = 632633852.1644179, tmp)))+x))))>>>x)|(-850932021)))>>x))<<(-821983991))); + assertEquals(0, x >>= (x>>(2424003553.0883207))); + assertEquals(2599386349, x -= (-2599386349)); + assertEquals(-68157441, x |= (((tmp = -1170343454.9327996, tmp)+((((tmp = 448468098, tmp)|(x>>(x>>(((x>>(((x/(x&(x<<x)))<<(2436876051.2588806))^(3010167261)))%((tmp = 2577616315.7538686, tmp)>>>(-2953152591.015912)))%((tmp = -1304628613, tmp)/(x&((x|((-2000952119)%((691146914)/((tmp = 1480966978.7766845, tmp)<<((tmp = 2644449477.392441, tmp)|(-2143869305.871568))))))+(tmp = -315254308, tmp))))))))&(-2060205555))|((-604140518.8186448)^(x*x))))%(x*((tmp = 1383244000.2807684, tmp)/(3195793656))))); + assertEquals(-68157441, x |= x); + assertEquals(-1, x >>= x); + assertEquals(-2147483648, x <<= x); + assertEquals(-1.5257198286933313, x /= (tmp = 1407521622, tmp)); + assertEquals(1149084989.47428, x += (((tmp = 1149084991.9004865, tmp)&x)^((((((2797053000)/(x^x))*(-2829253694))>>>((tmp = -610924351, tmp)>>x))>>>(tmp = -675681012, tmp))<<(2812852729)))); + assertEquals(0, x %= x); + assertEquals(0, x <<= ((tmp = -584069073, tmp)*(-2953140326))); + assertEquals(0, x <<= (tmp = -481515023.6404002, tmp)); + assertEquals(-1441535370, x ^= (2853431926)); + assertEquals(2853431926, x >>>= (((((((tmp = 2215663525.9620194, tmp)%((-1102832735.9274108)/x))>>x)&(3220898702.76322))&(((2077584946)*((x>>x)<<((tmp = 1845701049, tmp)-x)))/(tmp = 1947184202.5737212, tmp)))|(((tmp = 2976351488, tmp)^(-42517339))%((2648230244.410125)^(1520051731.31089))))/(1761635964))); + assertEquals(43539, x >>>= (tmp = 1361671184.7432632, tmp)); + assertEquals(21769, x >>= ((tmp = -804932298.9572575, tmp)>>((((tmp = 1749006993.253409, tmp)+(276536978))^x)|(2698166994)))); + assertEquals(1103025563, x |= (tmp = 1103007891, tmp)); + assertEquals(1327594607, x += (tmp = 224569044, tmp)); + assertEquals(1327594607, x |= x); + assertEquals(-478674944, x <<= (((672378508)&x)^(((-2070209708.6470091)|x)|(x>>>x)))); + assertEquals(-478674943, x ^= ((-1832457698.6345716)>>>((tmp = -3077714019, tmp)/(1809383028)))); + assertEquals(229129701056053250, x *= x); + assertEquals(1, x /= x); + assertEquals(2, x <<= (-1522529727)); + assertEquals(2, x &= x); + assertEquals(-2016989182, x |= ((((tmp = -1267845511, tmp)*(1225350332))+((tmp = -1397690831.5717893, tmp)>>>(tmp = -2575382994, tmp)))+x)); + assertEquals(-241, x >>= (tmp = 931869591, tmp)); + assertEquals(-1048087547, x &= (tmp = -1048087403.1163051, tmp)); + assertEquals(-4004486369.844599, x += (tmp = -2956398822.844599, tmp)); + assertEquals(-4004486368.844599, x -= (((2701878498)>>x)|(x|(-1079354967)))); + assertEquals(1, x >>= (tmp = -1583689092, tmp)); + assertEquals(1, x *= (x>>(x%x))); + assertEquals(0, x %= x); + assertEquals(-0, x *= (-120818969)); + assertEquals(0, x >>= ((tmp = 1794099660, tmp)/(((x&(((-321906091)^(tmp = -3009885933.8449526, tmp))&((tmp = -140917780, tmp)|(2037803173.4075825))))&x)&(tmp = -745357154, tmp)))); + assertEquals(0, x <<= (563984257.3493614)); + assertEquals(NaN, x %= ((((x>>(tmp = -2190891392.320677, tmp))-x)<<(462714956))<<((tmp = -84413570, tmp)|((x|(-2787022855))-((tmp = 2028532622, tmp)|(tmp = 1103757073.9178817, tmp)))))); + assertEquals(NaN, x *= ((2137674085.3142445)|((tmp = -1054749859.2353804, tmp)%x))); + assertEquals(NaN, x /= (x>>>(((((tmp = 597103360.9069608, tmp)>>>(-2850217714.1866236))-((tmp = 1125150527, tmp)*x))%(tmp = -982662312, tmp))|((x/(((968656808.6069037)*(((128484784.15362918)>>x)^x))&((((x/((((tmp = 748775979, tmp)*((x-(((tmp = 709571811.9883962, tmp)%(-2083567026))%(x/(tmp = -680467505, tmp))))/((tmp = -167543858, tmp)/(tmp = -3113588783, tmp))))/x)<<(-2605415230)))>>>(tmp = 3133054172, tmp))%(tmp = -1904650393, tmp))*((x|(-1193709562))*(tmp = -1731312795.718104, tmp)))))/((tmp = -672386301, tmp)/(tmp = 808898833.4163612, tmp)))))); + assertEquals(-9, x |= (((((tmp = 150377964.57195818, tmp)/(tmp = 2161910879.0514045, tmp))-(-2381625849))>>(-2715928517))/(((452113643)^(-2502232011))/((-3076471740)^(((tmp = 1664851172, tmp)*(((-1460011714)>>>x)<<((-2870606437)%x)))*((tmp = -2836565755.609597, tmp)-((x/(tmp = -871461415, tmp))-(2278867564)))))))); + assertEquals(-1, x >>= x); + assertEquals(-1, x |= ((-1319927272)>>>(-2866709980))); + assertEquals(-1, x >>= ((2345179803.155703)&(-978025218.2243443))); + assertEquals(1, x /= x); + assertEquals(-260730973, x |= (tmp = -260730973, tmp)); + assertEquals(1174405120, x <<= (2681054073)); + assertEquals(1174405120, x &= x); + assertEquals(1073741824, x &= (tmp = 2017166572.7622075, tmp)); + assertEquals(1073741824, x |= x); + assertEquals(168806102, x %= ((((tmp = -2939969193.950067, tmp)|((-2325174027.614815)/(-2329212715)))*(x/(((((-2927776738)/(x|x))+(x%(tmp = -3007347037.698492, tmp)))<<(-1898633380))>>(tmp = 204338085.45241892, tmp))))^x)); + assertEquals(168806102, x %= ((-832849739.5197744)&(tmp = -141908598, tmp))); + assertEquals(-401033205.05225074, x -= (tmp = 569839307.0522507, tmp)); + assertEquals(-401033205, x &= x); + assertEquals(-401130402, x ^= ((x*(tmp = 311418759.22436893, tmp))>>x)); + assertEquals(793533469, x ^= (-950312893.5201888)); + assertEquals(756, x >>>= (-1096189516)); + assertEquals(711, x += ((tmp = -753105189, tmp)>>(599823192.5381484))); + assertEquals(0, x >>>= ((tmp = -2859668634.4641137, tmp)+(-1160392986.1521513))); + assertEquals(2427599726.176195, x -= (-2427599726.176195)); + assertEquals(1942312465.2523103, x -= (485287260.92388475)); + assertEquals(0, x >>>= ((tmp = -1740656456, tmp)/(tmp = 1339746799.9335847, tmp))); + assertEquals(0, x <<= ((-7017077.38786912)*((-699490904.4551768)^x))); + assertEquals(0, x <<= (tmp = 715662384, tmp)); + assertEquals(0, x *= (x>>>(2149735450.0758677))); + assertEquals(NaN, x /= x); + assertEquals(0, x >>= ((397078885)*((851639692.8982519)-x))); + assertEquals(0, x &= (-2526654445)); + assertEquals(0, x %= (-1204924598)); + assertEquals(251639720, x ^= (x|(tmp = 251639720, tmp))); + assertEquals(695433573, x ^= (663539405)); + assertEquals(-1038050104, x -= (1733483677)); + assertEquals(0, x ^= x); + assertEquals(NaN, x %= x); + assertEquals(0, x &= (392107269)); + assertEquals(0, x %= (-3084908458.241551)); + assertEquals(0, x ^= x); + assertEquals(-2121660509, x ^= (tmp = -2121660509.7861986, tmp)); + assertEquals(2285041855588855800, x *= (x|(3209046634))); + assertEquals(54915072, x >>>= (x%(((((x%((((tmp = -1429433339.5078833, tmp)|(tmp = 2906845137, tmp))^(3207260333))&(-848438650)))-(-2721099735))&(141851917.19978714))+x)/x))); + assertEquals(54915072, x &= x); + assertEquals(54915072, x %= (x+(1855489160))); + assertEquals(70078753, x ^= ((((((-1648661736)+(x%((-1421237596)+(tmp = 2053180992.3857927, tmp))))+(tmp = 38606889, tmp))<<((-241334284)%((x>>(215316122))*(tmp = 396488307, tmp))))+((tmp = -2900704565, tmp)^x))^(((1103481003.1111188)^x)-(tmp = 1304113534, tmp)))); + assertEquals(1149501440, x <<= ((x>>(tmp = 3203172843, tmp))*(tmp = -192535531, tmp))); + assertEquals(0, x ^= x); + assertEquals(0, x >>= ((tmp = 2751499787, tmp)&((tmp = 2217654798, tmp)*(tmp = -2798728014, tmp)))); + assertEquals(NaN, x /= ((((-2019592425)>>>((((-1571930240.741224)>>>((-183952981)/((((1990518443.672842)>>(((((2051371284)%(685322833.6793983))>>>(2662885938))<<(-1212029669.6675105))|((-2790877875)<<(1546643473))))<<x)-(tmp = 804296674.4579233, tmp))))-(tmp = -417759051.68770766, tmp))/((-621859758)>>>x)))&x)<<(tmp = -48558935.55320549, tmp))); + assertEquals(0, x <<= (x&x)); + assertEquals(0, x *= (x%(tmp = 301196068, tmp))); + assertEquals(398290944, x |= (((tmp = 1904146839, tmp)+(1521017178))*(-3174245888.562067))); + assertEquals(1256401076, x ^= (1566464180)); + assertEquals(149620758, x %= ((tmp = 532626355, tmp)^(tmp = -382971203, tmp))); + assertEquals(149620791, x |= (x>>x)); + assertEquals(-0.07034576194938641, x /= ((tmp = -1977313182.7573922, tmp)-x)); + assertEquals(0, x <<= x); + assertEquals(0, x &= x); + assertEquals(0, x /= ((2182424851.139966)%(((-2768516150)+x)>>>x))); + assertEquals(0, x %= (-504299638.53962016)); + assertEquals(-0, x *= (-2915134629.6909094)); + assertEquals(0, x <<= ((tmp = 952692723.402582, tmp)%(2146335996.785011))); + assertEquals(230457472, x |= ((tmp = -574776101.8681948, tmp)*(683185125))); + assertEquals(933795934, x ^= (tmp = 974395614, tmp)); + assertEquals(933801974, x ^= (x>>>((-148683729)*(((tmp = 2912596991.415531, tmp)^(-2883672328))/x)))); + assertEquals(222, x >>= (-3060224682)); + assertEquals(27, x >>>= (1429156099.1338701)); + assertEquals(754519106, x ^= (tmp = 754519129.7281355, tmp)); + assertEquals(188629776, x >>>= ((x>>>((1247267193)<<(tmp = -936228622, tmp)))%((tmp = 978604324.8236886, tmp)*((tmp = -3018953108, tmp)^(((tmp = 259650195, tmp)>>>(tmp = 2762928902.7901163, tmp))*(x>>((tmp = 787444263.5542864, tmp)/(x>>>(((-2039193776)<<(tmp = -1408159169, tmp))-(1238893783)))))))))); + assertEquals(188629775.33987066, x += ((tmp = 1040520414, tmp)/((-1576237184)|((tmp = -970083705, tmp)&(((tmp = -312062761.12228274, tmp)|(1171754278.2968853))<<(-2069846597.7723892)))))); + assertEquals(1473670, x >>>= ((tmp = 202409672, tmp)^x)); + assertEquals(2171703268900, x *= (x>>(((tmp = 840468550, tmp)&(-3208057101.2136793))/x))); + assertEquals(0, x ^= x); + assertEquals(0, x ^= (x&((tmp = 2569871408.2405066, tmp)|((tmp = -3149374622, tmp)<<(x-(x|((tmp = -821239139.1626894, tmp)>>>x))))))); + assertEquals(NaN, x /= x); + assertEquals(NaN, x %= (tmp = 1926106354, tmp)); + assertEquals(0, x >>= ((x/(-2848416))/(tmp = 2484293767, tmp))); + assertEquals(0, x <<= ((tmp = -2484137114, tmp)>>>(tmp = -887083772.8318355, tmp))); + assertEquals(0, x >>= (tmp = -2651389432, tmp)); + assertEquals(0, x ^= x); + assertEquals(1041871201, x += ((tmp = 1041871201.9272791, tmp)|(x<<(-1136959830)))); + assertEquals(651390879501530900, x *= ((tmp = 1250424964.0346212, tmp)>>x)); + assertEquals(1965815296.245636, x %= ((2650603245.655831)+((-1610821947.8640454)>>>(((878987151.6917406)*((((784630543)%(((1448720244)>>(((tmp = 3036767847, tmp)+((tmp = 1012548422, tmp)<<(1957000200)))-x))/(x>>x)))<<((tmp = 914710268, tmp)*(((x^(1559603121))<<(tmp = 3181816736, tmp))|((-1964115655)+x))))-(-1055603890)))&(946797797.0616649))))); + assertEquals(1965815296.245636, x %= (tmp = -2601038357.593118, tmp)); + assertEquals(-769384440.872302, x += (-2735199737.117938)); + assertEquals(-769384440.872302, x %= (2193123162)); + assertEquals(1, x /= x); + assertEquals(1, x -= (((x>>>(-1968465925))*((tmp = 563037904, tmp)>>((tmp = 3009534415.769578, tmp)>>((-2567240601.7038674)<<(tmp = -1258402723.4150183, tmp)))))%(3112239470.276867))); + assertEquals(1, x |= x); + assertEquals(1505461527, x ^= (tmp = 1505461526.5858076, tmp)); + assertEquals(406553877, x &= (tmp = 2558242293, tmp)); + assertEquals(406553877, x |= x); + assertEquals(-574902339, x |= ((-709809495)%(tmp = -2880884811.410611, tmp))); + assertEquals(-20281777.349363208, x %= (22184822.46602547)); + assertEquals(1, x /= x); + assertEquals(-4360732, x ^= ((x|(tmp = 3178620274, tmp))>>(((2686286888)&(((-1107223053.8716578)/(((-2955575332.3675404)+(-2770518721))|(-2705016953.640522)))-x))^((1473641110.4633303)*((((-1466496401)<<x)+x)%(1805868749.082736)))))); + assertEquals(-1158545408, x <<= ((((x/((-2710098221.691819)-(-2421462965.788145)))/(((((x>>>(tmp = 1994541591.1032422, tmp))+(tmp = -1276676679.9747126, tmp))&((tmp = 1764029634.2493339, tmp)+((x|(tmp = -3050446156, tmp))-((tmp = -9441859, tmp)/(((-2072420232)&x)*(-1003199889))))))+(tmp = -2443230628, tmp))*x))*((x&((((x|(747566933))*(((2039741506)>>>((tmp = -2456000554, tmp)>>>(-1566360933.7788877)))^((tmp = 960600745, tmp)/x)))&(x^(((-2649310348.777452)^((2224282875)-(tmp = -2129141087.3182096, tmp)))<<((x<<x)+((-1307892509.3874407)-(x|(tmp = -2831643528.9720087, tmp)))))))/(((tmp = -35502946, tmp)<<((tmp = 1091279222, tmp)>>(((-2686069468.8930416)-x)+(tmp = 367442353.2904701, tmp))))%(1218262628))))/x))^(-919079153.7857773))); + assertEquals(747, x >>>= (1229157974)); + assertEquals(747, x |= x); + assertEquals(NaN, x %= (((3086718766.4715977)*((7912648.497568846)*((-2713828337.1659327)*(-176492425.4011252))))<<(tmp = -1074475173, tmp))); + assertEquals(0, x >>>= ((((444923201)<<x)>>>(-883391420.2142565))*((((617245412)<<x)>>>x)*(-913086143.2793813)))); + assertEquals(1941802406, x ^= (tmp = -2353164890, tmp)); + assertEquals(14, x >>>= (-1600311077.4571416)); + assertEquals(-18229482703.7246, x += (((x+(-993157139.7880647))%x)*(1862419512.1781366))); + assertEquals(-14.531388114858734, x /= ((tmp = -1649072797.951641, tmp)<<x)); + assertEquals(0, x ^= x); + assertEquals(0, x >>= ((x/x)^x)); + assertEquals(2, x ^= ((-1597416259)/(-738770020))); + assertEquals(0, x >>= (tmp = -387850072.74833393, tmp)); + assertEquals(0, x >>>= ((2491085477.186817)>>(x*(((tmp = -1592498533, tmp)+(tmp = 2086841852, tmp))&(-3174019330.8288536))))); + assertEquals(0, x >>= x); + assertEquals(0, x >>>= (tmp = -3045348659.45243, tmp)); + assertEquals(-1208573479, x |= ((3086393817)-x)); + assertEquals(1460649854142163500, x *= x); + assertEquals(1588199424, x <<= (-1902076952)); + assertEquals(1586102272, x &= (tmp = 2139876091.9142454, tmp)); + assertEquals(-460908552.5528109, x -= (tmp = 2047010824.552811, tmp)); + assertEquals(-460908552.5528109, x %= (tmp = 507904117.09368753, tmp)); + assertEquals(-460908552.5528109, x %= (2749577642.527038)); + assertEquals(234012, x >>>= (-340465746.91275)); + assertEquals(0, x >>>= x); + assertEquals(0, x %= (tmp = -2601875531, tmp)); + assertEquals(0, x %= (x|(tmp = 650979981.1158671, tmp))); + assertEquals(0, x %= (tmp = -2286020987, tmp)); + assertEquals(0, x |= x); + assertEquals(0, x &= (x|((tmp = 2568101411, tmp)-(-1438002403)))); + assertEquals(0, x >>>= (1399248574)); + assertEquals(0, x %= (-1906670287.2043698)); + assertEquals(0, x >>= (1019286379.6962404)); + assertEquals(0, x |= (x/(tmp = -82583591.62643051, tmp))); + assertEquals(NaN, x %= x); + assertEquals(NaN, x *= (x^(1874776436))); + assertEquals(NaN, x -= ((-1238826797)-(-2971588236.7228813))); + assertEquals(0, x <<= (2064632559)); + assertEquals(-0.5967273958864694, x += (((tmp = 1502995019, tmp)>>x)/(-2518729707))); + assertEquals(0, x >>>= x); + assertEquals(-0, x /= (-1923030890)); + assertEquals(NaN, x %= x); + assertEquals(0, x >>= (tmp = 1081732779.9449487, tmp)); + assertEquals(-820183066, x |= ((tmp = -3169007292.4721155, tmp)|(-1912588318))); + assertEquals(0, x -= x); + assertEquals(NaN, x %= x); + assertEquals(NaN, x /= (tmp = 287181840, tmp)); + assertEquals(0, x &= (x/((tmp = -1139766051, tmp)<<(x&(tmp = 2779004578, tmp))))); + assertEquals(0, x >>= (((tmp = -1816938028, tmp)+(-224851993.3139863))*(-2933829524))); + assertEquals(0, x |= ((((tmp = 305077929.1808746, tmp)&((x-(((((tmp = 2122810346.7475111, tmp)<<(717271979))*(tmp = 256854043.72633624, tmp))%((x+(tmp = -318657223.9992106, tmp))*((1993144830)<<(2594890698.603228))))^((((tmp = 257370667, tmp)>>>((((x^(3160746820))>>>(2049640466.8116226))>>>(2543930504.7117066))^(x-x)))^(x%(964838975)))^x)))%(x*x)))>>>x)*(tmp = -46861540, tmp))); + assertEquals(747575633, x ^= ((-2406502427)-(-3154078060.3794584))); + assertEquals(0, x *= (x%x)); + assertEquals(0, x <<= (1313773705.3087234)); + assertEquals(0, x >>>= ((x+x)>>>(3068164056))); + assertEquals(-0, x *= (tmp = -1771797797, tmp)); + assertEquals(1784146970, x ^= (tmp = 1784146970, tmp)); + assertEquals(1784146970, x >>>= (tmp = -2219972320.7195597, tmp)); + assertEquals(1744830464, x <<= ((((-2769476584)-(((1798431604)>>(tmp = 1337687914.799577, tmp))>>>((-2802941943.15014)>>x)))>>>(tmp = 646033678, tmp))-x)); + assertEquals(3044433348102455300, x *= x); + assertEquals(0, x >>= ((tmp = 1592076570.1900845, tmp)-((645774223.6317859)>>x))); + assertEquals(0, x >>= (x>>>(-3045822290.1536255))); + assertEquals(-0, x *= (tmp = -2450298800.986624, tmp)); + assertEquals(0, x >>= (tmp = 1379605393, tmp)); + assertEquals(0, x &= (((x-((((tmp = 837939461.6683749, tmp)+((((-813261853.3247359)|(x&(((-2565113940)*(tmp = -2725085381.240134, tmp))|x)))%(-1457259320))-(x+((tmp = -273947066, tmp)%((1164825698.879649)>>(1653138880.3434052))))))>>>(2823967606.411492))>>>((((((((1189235604.9646997)/(tmp = -2875620103.4002438, tmp))-(tmp = -801261493, tmp))<<(((1832556579.5095325)<<x)|((tmp = -2740330665, tmp)>>(tmp = -2352814025, tmp))))-(tmp = -1445043552.99499, tmp))&(x<<(((((445325471)*(1293047043.1808558))>>>(((1901837408.5910044)-(tmp = -2349093446.5313253, tmp))>>>(tmp = 1000847053.1861948, tmp)))*(x>>>(1771853406.6567078)))>>x)))>>>x)>>>(x^((tmp = 2813422715, tmp)-(x+(-342599947)))))))&(x>>>x))*x)); + assertEquals(NaN, x %= ((tmp = -3027713526, tmp)-((((x%(((((x/((2711155710)^(((((x>>>x)%((1098599291.155015)^(((((tmp = 1855724377.8987885, tmp)/(x|x))*((-1963179786)*((x-((-1634717702)%x))<<x)))>>(2008859507))>>((tmp = 2635024299.7983694, tmp)^(tmp = -602049246, tmp)))))*(x>>x))&(tmp = -1925103609, tmp))*((tmp = 2106913531.2828505, tmp)%((tmp = -200970069, tmp)*(-2809001910.951446))))))%x)*((1990098169)>>((x<<(2303347904.2601404))%x)))|(2767962065.9846206))+(201589933.301661)))>>(((tmp = 1921071149.5140274, tmp)>>(1054558799.1731887))|x))*(x/((((-2833879637.345674)>>>(tmp = 2849099601, tmp))%x)+(x%(x%(((tmp = 1983018049, tmp)^(tmp = -2659637454, tmp))>>((-1335497229.6945198)-(x+(((((tmp = 1136612609.848967, tmp)%(2471741030.01762))<<(x|(((tmp = 1644081190.1972675, tmp)&(-1422527338))^(2379264356.265957))))/(tmp = 2979299484.1884174, tmp))/x)))))))))*((tmp = 1858298882, tmp)^((tmp = -547417134.9651439, tmp)*x))))); + assertEquals(-7664, x |= ((2286000258.825538)>>(1716389170))); + assertEquals(-1, x >>= x); + assertEquals(-1231640486.3023372, x += ((tmp = 1231640485.3023372, tmp)*x)); + assertEquals(-2463280972.6046743, x += x); + assertEquals(1746, x >>>= x); + assertEquals(1746, x >>>= (((tmp = -562546488.0669937, tmp)*((-2475357745.8508205)&((x%(821425388.8633704))%((((-2315481592.687686)&(((tmp = 3130530521.7453523, tmp)+x)-x))^(-973033390.1773088))/x))))<<x)); + assertEquals(1746, x %= (-1544973951.076033)); + assertEquals(27936, x <<= (-525441532.33816123)); + assertEquals(27936, x %= (x*((tmp = 344991423.5336287, tmp)+(-2267207281)))); + assertEquals(27, x >>>= (tmp = 1249792906, tmp)); + assertEquals(0, x >>>= (tmp = -1068989615, tmp)); + assertEquals(0, x >>>= (tmp = 347969658.92579734, tmp)); + assertEquals(-2656611892, x -= (2656611892)); + assertEquals(1944539596, x |= (((tmp = 3000889963, tmp)-x)<<((tmp = 2917390580.5323124, tmp)^(-996041439)))); + assertEquals(1944539596, x |= x); + assertEquals(-739740167.0752468, x -= ((1712009965.0752468)+(x>>((tmp = -740611560.99014, tmp)>>>((tmp = -1033267419.6253037, tmp)&(862184116.3583733)))))); + assertEquals(-1479480334.1504936, x += x); + assertEquals(-4294967296.150494, x -= (x>>>((1219235492.3661718)&(3138970355.0665245)))); + assertEquals(0, x >>= (x*x)); + assertEquals(-0, x *= ((-2202530054.6558375)-(-676578695))); + assertEquals(-0, x %= (1336025846)); + assertEquals(0, x &= x); + assertEquals(0, x /= (1759366510)); + assertEquals(630007622, x |= (630007622)); + assertEquals(-0.22460286863455903, x /= (tmp = -2804984753, tmp)); + assertEquals(1102410276.775397, x -= (-1102410277)); + assertEquals(1102410276.775397, x %= ((((-2569525203)&x)*(x|(-1932675298)))/((-2376634450)>>>(x>>>(tmp = 936937604.9491489, tmp))))); + assertEquals(33642, x >>= (3028252527)); + assertEquals(2181106522.688034, x -= (-2181072880.688034)); + assertEquals(-2113861630, x &= (2523921542)); + assertEquals(-2147483646, x &= (-1996601566.9370148)); + assertEquals(-2147483648, x &= (tmp = -665669175.1968856, tmp)); + assertEquals(-2858673260.1367273, x -= (tmp = 711189612.1367272, tmp)); + assertEquals(350657, x >>= (tmp = -170243892.25474262, tmp)); + assertEquals(-0.0001405571562140975, x /= (-2494764474.7868776)); + assertEquals(0, x ^= x); + assertEquals(NaN, x /= ((x&(-2041236879))*((tmp = -2182530229, tmp)^((1274197078)*x)))); + assertEquals(0, x |= (x&(x-(1794950303)))); + assertEquals(1222105379, x |= (tmp = 1222105379, tmp)); + assertEquals(729884484, x ^= (tmp = 1666645607.6907792, tmp)); + assertEquals(729884484, x %= (tmp = -2896922082, tmp)); + assertEquals(8768, x &= ((tmp = 358940932, tmp)>>>(3159687631.3308897))); + assertEquals(1892384495, x |= (-2402591569)); + assertEquals(1892470533, x += ((((x^(-2266612043))>>>(tmp = -531009952, tmp))<<(x>>>((-1365315963.5698428)>>>((x+((-3168207800.184341)-(tmp = 1776222157.609917, tmp)))+(-1588857469.3596382)))))>>>x)); + assertEquals(143587205, x += (tmp = -1748883328, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x >>= (tmp = 2334880462.3195543, tmp)); + assertEquals(0, x &= ((tmp = 1819359625.4396145, tmp)|(tmp = -1323513565, tmp))); + assertEquals(-1102259874, x ^= (3192707422)); + assertEquals(2567457772588852700, x *= (-2329267202)); + assertEquals(-16783687, x |= ((-2212476227.060922)^(378973700.78452563))); + assertEquals(4278183609, x >>>= ((((((((tmp = 1766363150.197206, tmp)*(-2774552871))%x)>>>((3071429820)&((((((tmp = 351068445.27642524, tmp)<<(tmp = 2646575765, tmp))^(806452682))<<((x>>>(-2217968415.505327))<<(1564726716)))|x)-(tmp = -3110814468.9023848, tmp))))+x)^x)>>>(tmp = -617705282.0788529, tmp))>>>x)); + assertEquals(4314933530, x -= ((1032195469.789219)|(tmp = -448053861.9531791, tmp))); + assertEquals(9709850, x %= (((tmp = -3056286252.5853324, tmp)*x)&x)); + assertEquals(9709850, x %= (tmp = -2596800940, tmp)); + assertEquals(2655489828.9461126, x -= (tmp = -2645779978.9461126, tmp)); + assertEquals(369266212, x &= (((335712316.24874604)|(tmp = 33648215, tmp))-((x/(2639848695))<<((-499681175)<<(-2490554556))))); + assertEquals(-2147483648, x <<= (-834465507)); + assertEquals(1073741824, x >>>= (((tmp = 3018385473.1824775, tmp)>>(x*(-2574502558.216812)))|(((tmp = -1742844828, tmp)*(1698724455))&x))); + assertEquals(-270818218, x += (-1344560042)); + assertEquals(360710144, x <<= x); + assertEquals(0, x <<= (tmp = 612718075, tmp)); + assertEquals(0, x <<= x); + assertEquals(-0, x /= (tmp = -1922423684, tmp)); + assertEquals(-0, x *= ((((tmp = 741806213.3264687, tmp)%(-711184803.2022421))+((tmp = -3209040938, tmp)&(525355849.044886)))&(x<<(tmp = -698610297, tmp)))); + assertEquals(0, x <<= (-482471790)); + assertEquals(0, x &= ((-921538707)/(tmp = -482498765.988616, tmp))); + assertEquals(0, x ^= (x^x)); + assertEquals(-351721702, x ^= (-351721702.8850286)); + assertEquals(726242219625599900, x -= ((2064820612)*x)); + assertEquals(1452484439251199700, x += x); + assertEquals(2.52318299412847e-15, x %= ((((x<<((2508143285)+x))>>(-2493225905.011774))%(1867009511.0792103))/((((x<<(2542171236))>>((x|x)&(tmp = -384528563, tmp)))+((-1168755343)*(1731980691.6745195)))+(tmp = -1608066022.71164, tmp)))); + assertEquals(79905008, x += ((((-2702081714.590131)&(x+(tmp = -1254725471.2121565, tmp)))*(3088309981))%(((tmp = 1476844981.1453142, tmp)|((((tmp = -1243556934.7291331, tmp)%x)^(-1302096154))+((660489180)/(tmp = -681535480.8642154, tmp))))^(tmp = -8410710, tmp)))); + assertEquals(1215822204, x ^= ((-3008054900)>>>(tmp = -1990206464.460693, tmp))); + assertEquals(-394790532, x |= ((((-1334779133.2038574)+(tmp = -1407958866.832946, tmp))<<(1699208315))-(((x^(x%x))<<(3216443))>>(x+((((2576716374.3081336)|((tmp = 2316167191.348064, tmp)&((51086351.20208645)&((x|(tmp = -357261999, tmp))^(x/x)))))*(-45901631.10155654))*(((-439588079)>>>((-2358959768.7634916)|(1613636894.9373643)))+(((-908627176)<<x)%(x%((-1669567978)>>>((x>>(1289400876))+(tmp = 2726174270, tmp))))))))))); + assertEquals(-0.17717467607696327, x /= (2228255982.974148)); + assertEquals(-1905616474, x ^= (tmp = 2389350822.851587, tmp)); + assertEquals(-0, x %= x); + assertEquals(2818124981.508915, x -= (-2818124981.508915)); + assertEquals(-1476842315, x |= x); + assertEquals(73408564, x &= (-3147390604.3453345)); + assertEquals(70, x >>>= x); + assertEquals(1, x >>= x); + assertEquals(3086527319.899181, x *= (3086527319.899181)); + assertEquals(-145, x >>= x); + assertEquals(-145, x %= (tmp = -2500421077.3982406, tmp)); + assertEquals(-1, x >>= (tmp = -2970678326.712191, tmp)); + assertEquals(-1, x %= ((tmp = -535932632.4668834, tmp)+(((-1226598339.347982)<<((tmp = 616949449, tmp)/(tmp = 2779464046, tmp)))/(214578501.67984307)))); + assertEquals(1, x *= x); + assertEquals(1, x >>= ((tmp = 11080208, tmp)<<(460763913))); + assertEquals(-1.8406600706723492e-19, x /= ((tmp = -2334126306.1720915, tmp)*(tmp = 2327566272.5901165, tmp))); + assertEquals(856681434186007200, x -= ((tmp = -2286974992.8133907, tmp)*(374591518))); + assertEquals(3126084224, x >>>= x); + assertEquals(-1160460669, x |= (tmp = 181716099, tmp)); + assertEquals(873988096, x <<= (tmp = 406702419, tmp)); + assertEquals(0, x <<= ((tmp = 802107965.4672925, tmp)-((tmp = 1644174603, tmp)>>((tmp = 604679952, tmp)+(tmp = -515450096.51425123, tmp))))); + assertEquals(NaN, x %= ((x>>(tmp = 2245570378, tmp))*(tmp = 1547616585, tmp))); + assertEquals(NaN, x /= ((tmp = -776657947.0382309, tmp)&(tmp = 163929332.28270507, tmp))); + assertEquals(NaN, x *= (tmp = 243725679.78916526, tmp)); + assertEquals(NaN, x /= (x>>x)); + assertEquals(0, x <<= ((tmp = -1293291295.5735884, tmp)%(((((63309078)>>>x)&(x&(-2835108260.025297)))+x)>>>(-1317213424)))); + assertEquals(0, x *= ((((tmp = -1140319441.0068483, tmp)*(tmp = 2102496185, tmp))&(-2326380427))<<(tmp = -2765904696, tmp))); + assertEquals(0, x /= (tmp = 2709618593, tmp)); + assertEquals(0, x >>= (-1753085095.7670164)); + assertEquals(1766381484, x |= (-2528585812)); + assertEquals(1766381484, x %= (2735943476.6363373)); + assertEquals(1766381484, x %= (x*(tmp = 2701354268, tmp))); + assertEquals(-2147483648, x <<= (-323840707.4949653)); + assertEquals(4611686018427388000, x *= (x<<x)); + assertEquals(0, x <<= (3066735113)); + assertEquals(0, x ^= ((((x*x)^(tmp = -2182795086.39927, tmp))<<(x^(tmp = 1661144992.4371827, tmp)))<<((((-2885512572.176741)*(tmp = 609919485, tmp))|(tmp = 929399391.0790694, tmp))>>>((((((((((399048996)>>((-107976581.61751771)>>>x))|(((-1502100015)<<(tmp = -1108852531.9494338, tmp))&(x/(tmp = -3198795871.7239237, tmp))))+((-2627653357)>>x))>>>x)*(1066736757.2718519))%(tmp = 1326732482.201604, tmp))/(tmp = 2513496019.814191, tmp))>>>((1694891519)>>>(-2860217254.378931)))<<(tmp = 31345503, tmp))))); + assertEquals(0, x ^= (x/((-2556481161)>>>(x/(x%(x&(1302923615.7148068))))))); + assertEquals(NaN, x /= x); + assertEquals(NaN, x += (tmp = 846522031, tmp)); + assertEquals(0, x >>= (x+(-1420249556.419045))); + assertEquals(0, x ^= (((x%(-1807673170))&x)-x)); + assertEquals(-3484.311990686845, x -= ((((((-510347602.0068991)>>>x)<<((tmp = 1647999950, tmp)&(((305407727)>>((1781066601.791009)&x))<<((tmp = -998795238, tmp)%(((x/x)+x)<<(((2586995491.434947)<<x)-((((tmp = 545715607.9395425, tmp)*x)>>>x)>>>(((((2332534960.4595165)^(-3159493972.3695474))<<(tmp = 867030294, tmp))|(2950723135.753855))^(((3150916666)<<x)>>((tmp = 414988690, tmp)|((tmp = -1879594606, tmp)/(tmp = 1485647336.933429, tmp))))))))))))>>(tmp = -2676293177, tmp))%(617312699.1995015))/((((tmp = -1742121185, tmp)^((((x&x)<<(tmp = 698266916, tmp))/(-1860886248))+((-213304430)%((((((-2508973021.1333447)+(tmp = 2678876318.4903, tmp))&(tmp = -43584540, tmp))-x)^(-2251323850.4611115))-x))))>>>(tmp = 2555971284, tmp))%((((tmp = 16925106, tmp)^x)&x)|((x/((x|(tmp = -2787677257.125139, tmp))<<(-853699567)))+(tmp = -1721553520, tmp)))))); + assertEquals(-447873933.26863855, x += (-447870448.9566479)); + assertEquals(200591060101520900, x *= x); + assertEquals(200591062202483420, x -= (-2100962536)); + assertEquals(-5.261023346568228e+24, x *= ((tmp = -419641692.6377077, tmp)>>(tmp = -224703100, tmp))); + assertEquals(1269498660, x |= (195756836)); + assertEquals(1269498660, x |= x); + assertEquals(1269498660, x |= x); + assertEquals(-37.75978948486164, x /= (((tmp = -595793780, tmp)+((tmp = 2384365752, tmp)>>>(1597707155)))|((968887032)^(tmp = 2417905313.4337964, tmp)))); + assertEquals(-37.75978948486164, x %= (tmp = -1846958365.291661, tmp)); + assertEquals(1102319266.6421175, x += (1102319304.401907)); + assertEquals(-1664202255175155200, x -= ((x^(tmp = 407408729, tmp))*x)); + assertEquals(-752874653, x ^= (tmp = 314673507, tmp)); + assertEquals(-72474761, x |= (tmp = -2538726025.8884344, tmp)); + assertEquals(-72474761, x |= x); + assertEquals(-122849418, x += ((tmp = -2332080457, tmp)|(((((30496388.145492196)*(((-1654329438.451212)|(-2205923896))&(x>>(tmp = -1179784444.957002, tmp))))&(tmp = 319312118, tmp))*(651650825))|(((-2305190283)|x)>>>(-428229803))))); + assertEquals(994, x >>>= x); + assertEquals(614292, x *= (((((2565736877)/((tmp = 649009094, tmp)>>>(((x>>>(2208471260))>>(x>>>x))%x)))&(tmp = 357846438, tmp))<<(tmp = -2175355851, tmp))%x)); + assertEquals(1792008118, x |= (tmp = 1791924774.5121183, tmp)); + assertEquals(1246238208, x &= (tmp = 1264064009.9569638, tmp)); + assertEquals(-88877082, x ^= (2969289190.285704)); + assertEquals(0.044923746573582474, x /= ((tmp = -3057438043, tmp)^(-1009304907))); + assertEquals(0, x <<= ((-828383918)-((((x>>(734512101))*(tmp = -3108890379, tmp))-(x|((tmp = 3081370585.3127823, tmp)^((-271087194)-(x/(tmp = -2777995324.4073873, tmp))))))%x))); + assertEquals(1604111507.3365753, x -= (-1604111507.3365753)); + assertEquals(-1721314970, x ^= (tmp = -956686859, tmp)); + assertEquals(-102247425, x |= (tmp = -2535095555, tmp)); + assertEquals(-102247425, x %= (-955423877)); + assertEquals(1053144489850425, x *= (((tmp = 1583243590.9550207, tmp)&(1356978114.8592746))|(tmp = -10299961.622774363, tmp))); + assertEquals(-0.0043728190668037336, x /= ((-1196259252.435701)*(((-689529982)|(tmp = -1698518652.4373918, tmp))<<x))); + assertEquals(-2, x ^= (((x+(tmp = 2961627388, tmp))>>(tmp = 231666110.84104693, tmp))|x)); + assertEquals(-1, x >>= (tmp = -83214419.92958307, tmp)); + assertEquals(-1, x %= (-1303878209.6288595)); + assertEquals(2944850457.5213213, x -= (tmp = -2944850458.5213213, tmp)); + assertEquals(-1.6607884436053055, x /= (-1773164107)); + assertEquals(-0.6607884436053055, x %= ((x>>(1240245489.8629928))%(tmp = -3044136221, tmp))); + assertEquals(-0, x *= ((x*x)>>>((1069542313.7656753)+x))); + assertEquals(0, x >>>= (tmp = -202931587.00212693, tmp)); + assertEquals(-0, x *= (-375274420)); + assertEquals(0, x |= ((x/(((tmp = -876417141, tmp)*(x>>>x))&(-2406962078)))<<x)); + assertEquals(0, x &= ((tmp = -650283599.0780096, tmp)*(tmp = 513255913.34108484, tmp))); + assertEquals(3027255453.458466, x += (3027255453.458466)); + assertEquals(-12568623413253943000, x *= (((x-(198689694.92141533))|x)-x)); + assertEquals(-12568623410285185000, x -= (tmp = -2968758030.3694654, tmp)); + assertEquals(-2008903680, x &= (3111621747.7679076)); + assertEquals(-110045263.26583672, x += (tmp = 1898858416.7341633, tmp)); + assertEquals(15964, x >>>= (1141042034)); + assertEquals(31928, x += x); + assertEquals(0, x ^= x); + assertEquals(-1159866377, x |= (-1159866377)); + assertEquals(0, x ^= x); + assertEquals(3072699529.4306993, x -= (tmp = -3072699529.4306993, tmp)); + assertEquals(1, x /= x); + assertEquals(-1471195029, x |= (2823772267.429641)); + assertEquals(-4152937108, x += (-2681742079)); + assertEquals(142030188, x |= x); + assertEquals(270, x >>= (tmp = 1013826483, tmp)); + assertEquals(0, x >>>= (529670686)); + assertEquals(-2912300367, x -= (2912300367)); + assertEquals(2213791134963007500, x *= (x<<((((-3214746140)>>(tmp = -588929463, tmp))+((tmp = -3084290306, tmp)>>x))>>x))); + assertEquals(2213791133466809900, x -= (tmp = 1496197641, tmp)); + assertEquals(69834416, x >>>= (x|(((2755815509.6323137)^(x%(((x*((((tmp = 375453453, tmp)<<(x*x))>>(tmp = -973199642, tmp))*x))>>((tmp = -356288629, tmp)>>(tmp = 2879464644, tmp)))<<((((1353647167.9291127)>>>(x/x))<<((2919449101)/(2954998123.5529594)))^x))))&((-2317273650)>>>(tmp = 34560010.71060455, tmp))))); + assertEquals(69834416, x >>>= (x^(-2117657680.8646245))); + assertEquals(2217318064, x -= ((tmp = 2035883891, tmp)<<(tmp = -1884739265, tmp))); + assertEquals(-1272875686, x ^= (tmp = 805889002.7165648, tmp)); + assertEquals(-1272875686, x >>= (x&(((1750455903)*x)>>((722098015)%((tmp = 1605335626, tmp)>>(tmp = -565369634, tmp)))))); + assertEquals(-1274351316, x -= (x>>>((tmp = 2382002632, tmp)-((tmp = -2355012843, tmp)+(1465018311.6735773))))); + assertEquals(-2982908522.4418216, x -= ((tmp = 1635549038.4418216, tmp)+(((1952167017.720186)&((tmp = -2284822073.1002254, tmp)>>(-1403893917)))%(tmp = 655347757, tmp)))); + assertEquals(312, x >>>= x); + assertEquals(1248, x <<= (2376583906)); + assertEquals(0, x ^= x); + assertEquals(0, x *= ((((tmp = 1914053541.881434, tmp)>>>(tmp = 1583032186, tmp))>>>(-2511688231))%(tmp = -2647173031, tmp))); + assertEquals(0, x >>>= (tmp = -2320612994.2421227, tmp)); + assertEquals(0, x %= (((x+(tmp = -720216298.5403998, tmp))<<(414712685))>>(tmp = 480416588, tmp))); + assertEquals(0, x >>= ((((3039442014.271272)<<x)%(-2402430612.9724464))&((-2141451461.3664773)%((x>>(1361764256))/((tmp = -1723952801.9320493, tmp)%(477351810.2485285)))))); + assertEquals(-0, x /= (tmp = -1627035877, tmp)); + assertEquals(0, x >>>= (tmp = 1745193212, tmp)); + assertEquals(0, x >>>= (2309131575)); + assertEquals(NaN, x %= (((x*(tmp = -1730907131.6124666, tmp))%((((1481750041)|(x>>((((x>>>(tmp = 3128156522.5936565, tmp))/(tmp = -1277222645.9880452, tmp))^(tmp = -2327254789, tmp))+x)))>>>(-1161176960))>>>(tmp = 3135906272.5466847, tmp)))*(((((-2230902834.464362)^(1822893689.8183987))+(((tmp = 1597326356, tmp)/(x&((tmp = -3044163063.587389, tmp)>>(tmp = 2844997555, tmp))))%(x^x)))>>((x|x)/x))^(2634614167.2529745)))); + assertEquals(0, x &= (3081901595)); + assertEquals(0, x &= (-2453019214.8914948)); + assertEquals(0, x &= x); + assertEquals(0, x >>>= (-596810618.3666217)); + assertEquals(0, x >>= (((908276623)|x)/x)); + assertEquals(0, x ^= x); + assertEquals(958890056, x |= (tmp = 958890056.474458, tmp)); + assertEquals(1325436928, x <<= (tmp = -2474326583, tmp)); + assertEquals(711588532333838300, x *= ((-148161646.68183947)<<(tmp = -1149179108.8049204, tmp))); + assertEquals(0, x ^= (((2862565506)%x)/(tmp = -2865813112, tmp))); + assertEquals(-2064806628, x += (((tmp = -2677361175.7317276, tmp)/((817159440)>>>(tmp = 1895467706, tmp)))^(x|(tmp = -2309094859, tmp)))); + assertEquals(-69806982479424, x *= ((x&(tmp = 2857559765.1909904, tmp))&(-3166908966.754988))); + assertEquals(-430255744, x %= ((((((-2968574724.119535)<<x)<<((tmp = 1603913671, tmp)%((-1495838556.661653)^(tmp = 1778219751, tmp))))*(-400364265))<<((((1607866371.235576)-(1961740136))|(1259754297))&(tmp = -1018024797.1352971, tmp)))^x)); + assertEquals(6.828637393208647e-7, x /= (x*(tmp = 1464421, tmp))); + assertEquals(0, x &= x); + assertEquals(-0, x *= (((tmp = -2510016276, tmp)-(2088209546))<<((tmp = -1609442851.3789036, tmp)+(tmp = 1919930212, tmp)))); + assertEquals(-0, x %= (tmp = 1965117998, tmp)); + assertEquals(-290294792.53186846, x += ((tmp = -2361555894.5318685, tmp)%(2071261102))); + assertEquals(-70873, x >>= (tmp = 2206814124, tmp)); + assertEquals(-141746, x += x); + assertEquals(-141733.9831459089, x -= (((tmp = -806523527, tmp)>>>(tmp = 1897214891, tmp))/x)); + assertEquals(-141733.9831459089, x %= ((tmp = 1996295696, tmp)<<(tmp = 3124244672, tmp))); + assertEquals(141733.9831459089, x /= (x>>(2688555704.561076))); + assertEquals(3196954517.3075542, x -= (tmp = -3196812783.3244085, tmp)); + assertEquals(-19929155, x |= (((x|x)+x)^((tmp = 391754876, tmp)-(((((((tmp = -3051902902.5100636, tmp)*(x/(1546924993)))|(tmp = 1494375949, tmp))/((((-795378522)/(tmp = 509984856, tmp))>>>(tmp = -106173186, tmp))+x))|x)|(1916921307))>>>x)))); + assertEquals(1279271449, x &= ((tmp = 1289446971, tmp)&(tmp = 1836102619, tmp))); + assertEquals(17876992, x <<= (-207633461)); + assertEquals(0, x >>= (tmp = -903885218.9406946, tmp)); + assertEquals(0, x >>>= x); + assertEquals(-2999, x -= (((754533336.2183633)%(tmp = 557970276.0537136, tmp))>>(tmp = -1171045520, tmp))); + assertEquals(-0.000003020470363504361, x /= (tmp = 992891715.2229724, tmp)); + assertEquals(1, x /= x); + assertEquals(0.45768595820301217, x %= ((tmp = 673779031, tmp)/(tmp = -1242414872.3263657, tmp))); + assertEquals(-980843052.1872087, x += (tmp = -980843052.6448946, tmp)); + assertEquals(-Infinity, x /= ((((tmp = 317747175.8024508, tmp)&(x&(((tmp = 1632953053, tmp)>>x)/x)))%x)/(3145184986))); + assertEquals(0, x &= (x<<x)); + assertEquals(0, x ^= (x-((2969023660.5619783)/x))); + assertEquals(0, x *= x); + assertEquals(NaN, x %= (x/(((x-x)/((tmp = -1622970458.3812745, tmp)-(1626134522)))&((((((tmp = 1384729039.4149384, tmp)^(x%(tmp = -2736365959, tmp)))+((-1465172172)%x))>>(tmp = -1839184810.2603343, tmp))^(((tmp = 1756918419, tmp)>>>(x+(x%(tmp = -2011122996.9794662, tmp))))<<(-3026600748.902623)))*((tmp = -2040286580, tmp)>>(-2899217430.655154)))))); + assertEquals(0, x >>>= (tmp = 2100066003.3046467, tmp)); + assertEquals(1362012169, x ^= (tmp = 1362012169, tmp)); + assertEquals(1476312683, x |= ((457898409)>>>(-3079768830.723079))); + assertEquals(1441711, x >>>= (905040778.7770994)); + assertEquals(2078530607521, x *= x); + assertEquals(-208193103, x |= ((tmp = -241750000, tmp)^x)); + assertEquals(745036378, x ^= (((tmp = -1737151062.4726632, tmp)<<x)|(tmp = -1900321813, tmp))); + assertEquals(1744830464, x <<= x); + assertEquals(212992, x >>>= ((1210741037)-(x-(x>>>((x^(-1273817997.0036907))+((2401915056.5471)%(x<<(tmp = 1696738364.277438, tmp)))))))); + assertEquals(0.0001604311565639742, x /= (1327622418)); + assertEquals(0, x <<= (tmp = 166631979.34529006, tmp)); + assertEquals(0, x *= ((((tmp = 657814984, tmp)/(((-831055031)>>>(1531978379.1768064))|((tmp = 2470027754.302619, tmp)^(-223467597))))/(tmp = 1678697269.468965, tmp))&(tmp = -1756260071.4360774, tmp))); + assertEquals(-2049375053, x ^= (tmp = -2049375053, tmp)); + assertEquals(-1879109889, x |= (tmp = -1963586818.0436726, tmp)); + assertEquals(718239919, x ^= (tmp = -1523550640.1925273, tmp)); + assertEquals(-1361085185, x |= (-1939964707)); + assertEquals(2, x >>>= (1864136030.7395325)); + assertEquals(0.794648722849246, x %= ((-668830999)*(((-2227700170.7193384)%(x^(x>>>x)))/(tmp = 399149892, tmp)))); + assertEquals(0, x >>= x); + assertEquals(0, x *= x); + assertEquals(0, x &= ((tmp = -2389008496.5948563, tmp)|((((tmp = -2635919193.905919, tmp)*((-64464127)<<(2136112830.1317358)))>>((184057979)*(-1204959085.8362718)))>>>(-442946870.3341484)))); + assertEquals(-243793920, x -= ((tmp = 3002998032, tmp)<<((537875759)<<x))); + assertEquals(0, x -= x); + assertEquals(0, x *= ((((66852616.82442963)/((((x^x)&(2975318321.223734))+(((tmp = -1388210811.1249495, tmp)^((((-680567297.7620237)%(x-(tmp = -672906716.4672911, tmp)))-x)*(tmp = -1452125821.0132627, tmp)))*(((2770387154.5427895)%x)%x)))-x))<<((-1481832432.924325)>>(tmp = 3109693867, tmp)))>>>(x/(((((((tmp = 928294418, tmp)^(((-1018314535)/(tmp = -3167523001, tmp))%((((((tmp = -1639338126, tmp)-(tmp = -2613558829, tmp))&x)/x)%(tmp = 513624872, tmp))/((-520660667)&x))))*(2620452414))^((tmp = 2337189239.5949326, tmp)*(3200887846.7954993)))>>>((tmp = 1173330667, tmp)^x))<<x)>>(((tmp = -2475534594.982338, tmp)*x)|x))))); + assertEquals(0, x /= (2520915286)); + assertEquals(0, x &= x); + assertEquals(0, x >>= (-1908119327)); + assertEquals(0, x >>>= (tmp = 549007635, tmp)); + assertEquals(0, x >>= (-994747873.8117285)); + assertEquals(0, x <<= ((((x>>>((-3084793026.846681)%((1107295502)&(tmp = -296613957.8133817, tmp))))&((19637717.166736007)/(x+x)))+x)/(-2479724242))); + assertEquals(-695401420, x += (-695401420)); + assertEquals(-695401394, x += (x>>>(tmp = 2340097307.6556053, tmp))); + assertEquals(-555745552, x -= (x|(-483851950.68644))); + assertEquals(-17825792, x <<= x); + assertEquals(-17825792, x >>= x); + assertEquals(-17, x %= ((tmp = 1799361095, tmp)|((x>>(((-1201252592)<<((((543273288)+(-2859945716.606924))*x)<<((-3030193601)<<(3081129914.9217644))))|((1471431587.981769)>>(-246180750))))|(((tmp = -2689251055.1605787, tmp)>>x)&(((2131333169)^x)-((tmp = -951555489, tmp)/x)))))); + assertEquals(-8912896, x <<= (1146444211)); + assertEquals(2854567584, x += (tmp = 2863480480, tmp)); + assertEquals(426232502.24151134, x %= (1214167540.8792443)); + assertEquals(1806802048, x ^= (-2368317898)); + assertEquals(432537600, x <<= (tmp = 2831272652.589364, tmp)); + assertEquals(432537600, x %= (((1713810619.3880467)-x)&((-2853023009.553296)&(tmp = -3158798098.3355417, tmp)))); + assertEquals(-509804066, x += (tmp = -942341666, tmp)); + assertEquals(-509804066, x %= (-732349220)); + assertEquals(259900185710132350, x *= x); + assertEquals(711598501.7021885, x %= ((tmp = 2020395586.2280731, tmp)-(tmp = 3031459563.1386633, tmp))); + assertEquals(711598503.0618857, x += ((tmp = 967558548.4141241, tmp)/x)); + assertEquals(711598503, x &= x); + assertEquals(711598503, x ^= (((((1609355669.1963444)+((((tmp = -2660082403.258437, tmp)+(tmp = -235367868, tmp))&(x/x))*((-2595932186.69466)|((tmp = -3039202860, tmp)<<x))))>>>(-951354869))-((tmp = -691482949.6335375, tmp)/(tmp = -1735502400, tmp)))/(tmp = 798440377, tmp))); + assertEquals(558262613882868500, x *= (784519095.4299527)); + assertEquals(558262611968479000, x -= ((((tmp = 1039039153.4026555, tmp)/(-3138845051.6240187))*(tmp = 633557994, tmp))&(1981507217))); + assertEquals(1170427648, x |= ((x>>((((-1086327124)%((tmp = -1818798806.368613, tmp)^(tmp = 2183576654.9959817, tmp)))>>x)&((((((tmp = 1315985464.0330539, tmp)&(2774283689.333836))%x)*((2722693772.8994813)&(tmp = -2720671984.945404, tmp)))^(tmp = -76808019, tmp))<<((tmp = 685037799.2336662, tmp)^((tmp = 1057250849, tmp)&(tmp = 1469205111.2989025, tmp))))))+(x*(((tmp = 448288818.47173154, tmp)-(-2527606231))-((8387088.402292728)>>x))))); + assertEquals(558, x >>>= (tmp = 2732701109, tmp)); + assertEquals(558, x &= x); + assertEquals(-0.00015855057024653912, x /= ((x+(((tmp = -1963815633, tmp)-(x>>x))-((x|x)>>x)))/x)); + assertEquals(1.3458861596445712e-13, x /= (-1178038492.4116466)); + assertEquals(0, x <<= (-104550232)); + assertEquals(0, x >>>= (x>>(tmp = -255275244.12613606, tmp))); + assertEquals(0, x >>= x); + assertEquals(375, x |= ((1576819294.6991196)>>>(-2570246122))); + assertEquals(96000, x <<= ((2252913843.0150948)>>>(-49239716))); + assertEquals(6144000, x <<= ((((tmp = -2478967279, tmp)&((x%((tmp = -1705332610.8018858, tmp)+(x+(tmp = 590766349, tmp))))<<(tmp = 1759375933, tmp)))+(-2024465658.849834))&(1564539207.3650014))); + assertEquals(-1149239296, x <<= (1862803657.7241006)); + assertEquals(-9, x >>= (((tmp = 463306384.05696774, tmp)^x)|((x>>((((-2098070856.799663)<<((-2054870274.9012866)<<(((-2582579691)/(829257170.0266814))<<(((((tmp = -1753535573.7074275, tmp)<<((x>>(-197886116))%((2487188445)%(tmp = 2465391564.873364, tmp))))&(((tmp = -500069832, tmp)&(tmp = 3016637032, tmp))&((tmp = 2525942628, tmp)|((((-920996215)|x)^((((tmp = -687548533.419106, tmp)&(1423222636.058937))<<((tmp = -1096532228, tmp)>>((((tmp = -3124481449.2740726, tmp)^(tmp = 2724328271.808975, tmp))>>x)*x)))+(-1661789589.5808442)))+(((x*(tmp = -1224371664.9549093, tmp))^((tmp = 3202970043, tmp)^x))/(tmp = 131494054.58501709, tmp))))))|(((tmp = -1654136720, tmp)<<x)>>((1652979932.362416)-(tmp = -863732721, tmp))))^(-113307998)))))^(-90820449.91417909))*((tmp = 641519890, tmp)-((((x<<(tmp = 2349936514.071881, tmp))*(2324420443.587892))^x)%(x<<((tmp = -1838473742, tmp)/(((-3154172718.4274178)-x)+x)))))))|(x>>>((tmp = 2096024376.4308293, tmp)<<x))))); + assertEquals(81, x *= x); + assertEquals(81, x &= x); + assertEquals(81, x %= (tmp = 2223962994, tmp)); + assertEquals(81, x ^= ((x/(((-1606183420.099584)|(-1242175583))&(((x|((tmp = 828718431.3311573, tmp)/(x>>x)))+(((-2207542725.4531174)^(x*x))*(tmp = 551575809.955105, tmp)))/x)))&((x>>x)&x))); + assertEquals(81, x %= (tmp = 279598358.6976975, tmp)); + assertEquals(101.72338484518858, x -= (((tmp = 2452584495.44003, tmp)%((-1181192721)+(((x>>(((x&x)^x)+((x>>>((x+(-2472793823.57181))/(((2854104951)>>(-1208718359.6554642))>>>(1089411895.694705))))/(x|(-2821482890.1780205)))))^(-1786654551))/(-29404242.70557475))))/(((-4352531)<<((-1227287545)<<x))%(-2558589438)))); + assertEquals(101.72338484518858, x %= (-943645643)); + assertEquals(0, x -= x); + assertEquals(0, x >>>= (-2440404084)); + assertEquals(0, x >>= (tmp = 1029680958.405923, tmp)); + assertEquals(0, x >>>= (1213820208.7204895)); + assertEquals(-0, x /= (tmp = -103093683, tmp)); + assertEquals(0, x >>>= (-2098144813)); + assertEquals(-0, x /= (((-3087283334)+(((tmp = -3129028112.6859293, tmp)%(tmp = 2413829931.1605015, tmp))-(2578195237.8071446)))|x)); + assertEquals(-15, x |= ((((-178926550.92823577)>>>(-965071271))^((tmp = -484633724.7237625, tmp)-(tmp = 473098919.1486404, tmp)))>>((-2264998310.203265)%(tmp = -499034672, tmp)))); + assertEquals(0, x ^= x); + assertEquals(0, x >>= (((-3207915976.698118)<<(tmp = 2347058630, tmp))|(tmp = -2396250098.559627, tmp))); + assertEquals(NaN, x %= x); + assertEquals(NaN, x *= (621843222)); + assertEquals(0, x >>= (((-2409032228.7238913)*x)-(tmp = -887793239, tmp))); + assertEquals(NaN, x /= x); + assertEquals(1193017666, x ^= (tmp = 1193017666, tmp)); + assertEquals(3.5844761899682753, x /= (tmp = 332829011.206393, tmp)); + assertEquals(-888572929, x |= (((tmp = 1032409228, tmp)+(tmp = -1920982163.7853453, tmp))+x)); + assertEquals(-1817051951333455600, x *= (((-1506265102)^(tmp = -775881816, tmp))-(tmp = -32116372.59181881, tmp))); + assertEquals(-1638479616, x |= x); + assertEquals(-114489, x %= (((tmp = -247137297.37866855, tmp)>>>((((((-322805409)-x)^x)>>((((((((x>>>(tmp = -900610424.7148039, tmp))/(-1155208489.6240904))|((-2874045803)|(tmp = 3050499811, tmp)))+(x/((tmp = -613902712, tmp)^((-982142626.2892077)*((((tmp = -3201753245.6026397, tmp)|((1739238762.0423079)^x))/(243217629.47237313))^((tmp = -11944405.987132788, tmp)/(tmp = 2054031985.633406, tmp)))))))*(tmp = 2696108952.450961, tmp))*x)>>>(tmp = 3058430643.0660386, tmp))>>(x<<x)))>>(-984468302.7450335))%((tmp = 1302320585.246251, tmp)>>>x)))%(tmp = -2436842285.8208156, tmp))); + assertEquals(2047, x >>>= (2380161237)); + assertEquals(0, x >>= x); + assertEquals(0, x &= (tmp = 980821012.975836, tmp)); + assertEquals(-1090535537, x -= ((-3064511503.1214876)&((tmp = -2598316939.163751, tmp)<<((tmp = -969452391.8925576, tmp)*x)))); + assertEquals(-2181071074, x += x); + assertEquals(1, x >>>= ((2902525386.449062)>>x)); + assertEquals(1, x += (x&(tmp = -2643758684.6636515, tmp))); + assertEquals(1, x %= ((tmp = -2646526891.7004848, tmp)/x)); + assertEquals(448735695.7888887, x -= (tmp = -448735694.7888887, tmp)); + assertEquals(1, x /= x); + assertEquals(1, x >>= ((-480385726)<<(2641021142))); + assertEquals(1, x %= (375099107.9200462)); + assertEquals(1, x >>= (((x&((tmp = -2402469116.9903326, tmp)%(tmp = -2862459555.860298, tmp)))*(tmp = -2834162871.0586414, tmp))%(((x>>>(tmp = 721589907.5073895, tmp))*(x^x))%(((tmp = 2844611489.231776, tmp)^((983556913)&(906035409.6693488)))^(x>>>(1239322375)))))); + assertEquals(268435456, x <<= (tmp = 178807644.80966163, tmp)); + assertEquals(44, x %= ((tmp = 2527026779.081539, tmp)>>>(2736129559))); + assertEquals(88, x += x); + assertEquals(0, x >>>= x); + assertEquals(0, x -= x); + assertEquals(-1523121602, x |= (2771845694)); + assertEquals(-2, x >>= x); + assertEquals(-4, x += x); + assertEquals(-256, x <<= (((2522793132.8616533)>>(tmp = 77232772.94058788, tmp))+(3118669244.49152))); + assertEquals(4294967040, x >>>= x); + assertEquals(-256, x &= x); + assertEquals(1278370155.835435, x -= (-1278370411.835435)); + assertEquals(-3.488228054921667, x /= (tmp = -366481243.6881058, tmp)); + assertEquals(1.162742684973889, x /= ((x|(((((2404819175.562809)*(tmp = -2524589506, tmp))&(tmp = -675727145, tmp))>>>(x*x))&((-413250006)<<(tmp = 2408322715, tmp))))|((2940367603)>>>x))); + assertEquals(0, x >>>= ((2513665793)-(tmp = 1249857454.3367786, tmp))); + assertEquals(0, x ^= x); + assertEquals(0, x ^= x); + assertEquals(1989998348.6336238, x -= (-1989998348.6336238)); + assertEquals(903237918.986834, x %= (1086760429.6467898)); + assertEquals(-4.4185765232981975, x /= (-204418304)); + assertEquals(1471621914, x ^= (tmp = -1471621914.1771696, tmp)); + assertEquals(1471621914, x |= ((((((x<<(tmp = -2676407394.536844, tmp))%(((343324258)+(x/(x>>(((-221193011)>>>x)|x))))>>(((-2737713893)^((tmp = -49214797.00735545, tmp)+((-2818106123.172874)/(tmp = -2361786565.3028684, tmp))))<<(1859353297.6355076))))*(tmp = -751970685, tmp))|((tmp = 2502717391.425871, tmp)/(tmp = -2647169430, tmp)))*((tmp = -1647567294, tmp)&(((tmp = 1819557651, tmp)/x)>>((((-3073469753)/x)-(((tmp = -1973810496.6407511, tmp)&((x-(x+(tmp = -2986851659, tmp)))>>>(tmp = -2226975699, tmp)))|(418770782.142766)))<<x))))*(((((tmp = 125466732, tmp)/((((1453655756.398259)|(((874792086.7064595)-(194880772.91499102))>>>x))%(x<<(tmp = -1445557137, tmp)))<<x))>>>(tmp = -1953751906, tmp))/((tmp = -2140573172.2979035, tmp)*((-108581964)^x)))|(-481484013.0393069)))); + assertEquals(1454179065, x += ((tmp = 947147038.2829313, tmp)|(tmp = -154822975.3629098, tmp))); + assertEquals(1, x /= x); + assertEquals(1, x %= ((((((tmp = -2262250297.991866, tmp)-(tmp = 481953960, tmp))/(1629215187.6020458))|(2515244216))>>>((tmp = -3040594752.2184515, tmp)-(tmp = -1116041279, tmp)))^(((-182133502)-(1065160192.6609197))+(((((-1850040207)^(tmp = -1570328610, tmp))^(tmp = 20542725.09256518, tmp))*x)|(2386866629))))); + assertEquals(1, x &= (2889186303)); + assertEquals(0, x >>= (((-1323093107.050538)>>(x%x))-(((((((-1736522840)+(tmp = -2623890690.8318863, tmp))*(959395040.5565329))*(233734920))<<((x+(x%((tmp = -2370717284.4370327, tmp)%(tmp = 2109311949, tmp))))-(tmp = -1005532894, tmp)))|(861703605))>>>((2399820772)/x)))); + assertEquals(0, x >>= x); + assertEquals(57233408, x |= ((tmp = 2655923764.4179816, tmp)*(-1353634624.3025436))); + assertEquals(997939728, x |= (980552208.9005274)); + assertEquals(1859642592476610800, x *= (1863481872)); + assertEquals(-977190656, x <<= x); + assertEquals(4.378357529141239e+26, x *= ((((x/(((tmp = 2429520991, tmp)/(x/(tmp = 784592802, tmp)))-(tmp = -2704781982, tmp)))*(tmp = -2161015768.2322354, tmp))&((((-3164868762)>>(tmp = 2390893153.32907, tmp))^x)>>(-2422626718.322538)))*(tmp = 278291869, tmp))); + assertEquals(4.378357529141239e+26, x -= (1710777896.992369)); + assertEquals(0, x &= (((((tmp = -2532956158.400033, tmp)|((2195255831.279001)|(1051047432)))|(-1628591858))|(tmp = -2042607521.947963, tmp))>>((-1471225208)/(((-133621318)>>(1980416325.7358408))*((1741069593.1036062)-(x|(2133911581.991011))))))); + assertEquals(-0, x /= (-656083507)); + assertEquals(NaN, x += ((tmp = -1071410982.2789869, tmp)%x)); + assertEquals(NaN, x *= (tmp = -1513535145.3146675, tmp)); + assertEquals(0, x >>= ((2831245247.5267224)>>(x<<((x+(((3068824580.7922907)|(1708295544.275714))*((tmp = -1662930228.1170444, tmp)-(((tmp = 1979994889, tmp)<<(tmp = -1826911988, tmp))&((x/(x<<(1909384611.043981)))+(1958052414.7139997))))))<<(tmp = 2481909816.56558, tmp))))); + assertEquals(0, x *= (((tmp = -2979739958.1614842, tmp)&x)+x)); + assertEquals(-0, x *= ((-332769864.50313234)^x)); + assertEquals(0, x >>= ((((689018886.1436445)+(tmp = -2819546038.620694, tmp))|(((tmp = -1459669934.9066005, tmp)|x)/x))<<(((tmp = 2640360389, tmp)/((x%((-1947492547.9056122)%((1487212416.2083092)-(-1751984129))))^x))%(tmp = 2666842881, tmp)))); + assertEquals(-1801321460, x |= (tmp = 2493645836, tmp)); + assertEquals(-1801321460, x %= (2400405136)); + assertEquals(-2905399858195810300, x *= (tmp = 1612926911, tmp)); + assertEquals(-2905399858195810300, x -= (x>>(tmp = 1603910263.9593458, tmp))); + assertEquals(-238798848, x &= ((tmp = -2638646212.767516, tmp)/(((tmp = 1755616291.436998, tmp)>>>(tmp = 1083349775, tmp))-(x%(((tmp = 1728859105.53634, tmp)^(1931522619.0403612))/(tmp = 712460587.0025489, tmp)))))); + assertEquals(-2363873607.2302856, x += (-2125074759.230286)); + assertEquals(1712665, x &= (((117229515)>>>(((1707090894.1915488)>>>((-1696008695)>>(((-1045367326.7522249)<<(tmp = -209334716, tmp))-x)))|(-1707909786.080653)))%(1260761349.172689))); + assertEquals(1073741824, x <<= (tmp = -289437762.34742975, tmp)); + assertEquals(1073741824, x &= (tmp = 2079141140, tmp)); + assertEquals(0, x <<= ((x^(-3139646716.1615124))-(((-362323071.74237394)|(tmp = 2989896849, tmp))*(tmp = -218217991, tmp)))); + assertEquals(0, x &= (tmp = -1476835288.425903, tmp)); + assertEquals(0, x >>>= (tmp = 61945262.70868635, tmp)); + assertEquals(0, x ^= x); + assertEquals(-2735263498.7189775, x -= (2735263498.7189775)); + assertEquals(-1182289920, x <<= (x+x)); + assertEquals(-1182289580, x ^= ((2858446263.2258)>>>(2387398039.6273785))); + assertEquals(696693056, x &= ((2178665823)*(-51848583))); + assertEquals(1652555776, x <<= (((tmp = 2943916975, tmp)-((-1544273901)>>(-1671503106.2896929)))|x)); + assertEquals(6455296, x >>>= (tmp = 1492638248.675439, tmp)); + assertEquals(2097152, x &= (((x|x)*(2873891571.7000637))^((2165264807)+(tmp = 451721563, tmp)))); + assertEquals(2097152, x %= (tmp = 1089484582.1455994, tmp)); + assertEquals(2097152, x <<= x); + assertEquals(2097152, x &= ((tmp = 119096343.4032247, tmp)^((-1947874541)*x))); + assertEquals(0, x &= (tmp = 2363070677, tmp)); + assertEquals(0, x &= ((tmp = -1897325383, tmp)>>>((2368480527)>>>((tmp = 1837528979, tmp)*(-1838904077))))); + assertEquals(-1898659416, x ^= (-1898659416.1125412)); + assertEquals(-725506048, x <<= x); + assertEquals(1392943104, x <<= (295287938.9104482)); + assertEquals(-63620329, x ^= ((tmp = -3175925826.5573816, tmp)-(tmp = 2474613927, tmp))); + assertEquals(-1135111726, x -= ((tmp = -1133259081, tmp)^(((tmp = -742228219, tmp)>>((-7801909.587711811)%((tmp = -642758873, tmp)+(tmp = 2893927824.6036444, tmp))))^((tmp = -2145465178.9142997, tmp)+x)))); + assertEquals(0, x ^= x); + assertEquals(660714589, x |= (660714589)); + assertEquals(660714676, x ^= ((-376720042.8047826)>>>(2196220344))); + assertEquals(660714676, x |= ((((((((x<<(-1140465568))-(tmp = -1648489774.1573918, tmp))%(((tmp = -2955505390.573639, tmp)*x)<<((((tmp = -1769375963, tmp)*(tmp = -440619797, tmp))&((tmp = 1904284066, tmp)%(-2420852665.0629807)))+(-324601009.2063596))))>>(tmp = 2317210783.9757776, tmp))^((tmp = 750057067.4541628, tmp)^(tmp = -1391814244.7286487, tmp)))>>((344544658.6054913)%((tmp = -1508630423.218488, tmp)&(tmp = 1918909238.2974637, tmp))))>>((-647746783.685822)&(tmp = 2444858958.3595476, tmp)))&x)); + assertEquals(-962337195, x ^= (tmp = -507358495.30825853, tmp)); + assertEquals(-182008925.58535767, x %= (tmp = -195082067.35366058, tmp)); + assertEquals(502070, x >>>= (tmp = 1459732237.1447744, tmp)); + assertEquals(-2391009930.7235765, x -= (tmp = 2391512000.7235765, tmp)); + assertEquals(1568669696, x <<= x); + assertEquals(0, x <<= (tmp = -571056688.2717848, tmp)); + assertEquals(1770376226, x ^= (tmp = 1770376226.0584736, tmp)); + assertEquals(0, x ^= x); + assertEquals(0, x &= ((((x<<x)>>>x)|x)|(((tmp = -2141573723, tmp)^x)|(64299956)))); + assertEquals(0, x ^= x); + assertEquals(0, x &= x); + assertEquals(0, x <<= (1106060336.7362857)); + assertEquals(-0, x /= (x|(tmp = 2760823963, tmp))); + assertEquals(0, x <<= ((-2436225757)|(-1800598694.4062433))); + assertEquals(0, x >>>= ((-728332508.9870625)<<x)); + assertEquals(-173377680, x ^= ((tmp = -173377680, tmp)%(tmp = -2843994892, tmp))); + assertEquals(-173377680, x |= ((((-819217898)&(tmp = -1321650255, tmp))&(x+((x^x)<<((1700753064)>>((((((-1038799327)>>((782275464)^x))-(tmp = -2113814317.8539028, tmp))>>(2143804838))&x)-((2970418921)/(-3073015285.6587048)))))))&((-1759593079.4077306)%((1699128805)-((tmp = -467193967, tmp)&(((2225788267.3466334)*(((2687946762.5504274)+x)>>>x))<<(-1853556066.880512))))))); + assertEquals(-0.5520657226957338, x /= ((tmp = -755493878, tmp)&(tmp = 918108389, tmp))); + assertEquals(0.30477656217556287, x *= x); + assertEquals(0, x &= ((tmp = -2746007517, tmp)<<(2749629340))); + assertEquals(0, x ^= ((x%(tmp = 1683077876, tmp))%(-162706778))); + assertEquals(0, x *= (tmp = 10203423, tmp)); + assertEquals(119043212.1461842, x += (tmp = 119043212.1461842, tmp)); + assertEquals(587202560, x <<= (tmp = 658697910.7051642, tmp)); + assertEquals(-138689730, x |= (x-(tmp = 1296317634.5661907, tmp))); + assertEquals(-138663011, x -= ((-1751010109.5506423)>>(152829872))); + assertEquals(-138663011, x %= (-1266200468)); + assertEquals(-138663011, x &= (x|((tmp = -571277275.622529, tmp)<<x))); + assertEquals(-138663011, x >>= ((971259905.1265712)*(tmp = 2203764981, tmp))); + assertEquals(-138663011, x %= (-904715829)); + assertEquals(-138663011, x |= ((tmp = -2823047885.283391, tmp)>>>(((tmp = 533217000, tmp)|(650754598.7836078))|(-1475565890)))); + assertEquals(-1610612736, x <<= x); + assertEquals(-1610612736, x &= x); + assertEquals(163840, x >>>= (-188885010)); + assertEquals(-1224224814, x |= (tmp = 3070742482, tmp)); + assertEquals(1498726395213334500, x *= x); + assertEquals(1723591210, x |= ((tmp = 615164458, tmp)|x)); + assertEquals(1721910480, x ^= (x>>>x)); + assertEquals(4505284605.764313, x -= (tmp = -2783374125.7643127, tmp)); + assertEquals(-9504912393868483000, x *= (((tmp = 2896651872, tmp)<<(-2896385692.9017262))&(((((tmp = -2081179810.20238, tmp)|(tmp = -2484863999, tmp))>>((tmp = 1560885110.2665749, tmp)/(((tmp = 934324123.4289343, tmp)<<((tmp = -1591614157.0496385, tmp)+x))/(((x%(((tmp = 1672629986.8055913, tmp)%x)>>(tmp = 2116315086.2559657, tmp)))/(((-2687682697.5806303)>>x)/(-2034391222.5029132)))%(x-((((((tmp = 2598594967, tmp)/(((((((2950032233)%x)/x)^(tmp = -2126753451.3732262, tmp))<<(tmp = -3019113473, tmp))+(tmp = -2021220129.2320697, tmp))%((((-587645875.4666483)>>(((((x+x)+x)&(tmp = 533801785, tmp))|x)-((tmp = -2224808495.678903, tmp)/(1501942300))))>>>(-2558947646))>>((2798508249.020792)>>>x))))>>>((1060584557)/((((((((x&x)|(1426725365))>>>(tmp = 1500508838, tmp))>>(-1328705938))*((tmp = -2288009425.598777, tmp)>>>(((2586897285.9759064)%((-1605651559.2122297)>>>(tmp = 1936736684.4887302, tmp)))+((tmp = 2316261040, tmp)^(570340750.353874)))))&(x^((tmp = -2266524143, tmp)-(tmp = 2358520476, tmp))))+(tmp = 1449254900.9222453, tmp))%((-100598196)%((tmp = -2985318242.153491, tmp)>>((620722274.4565848)>>(871118975)))))))<<x)*(tmp = -1287065606.4143271, tmp))>>>(1038059916.2438471)))))))+((x/(-276990308.1264961))&(tmp = 2471016351.2195315, tmp)))|(((((tmp = -1288792769.3210807, tmp)+((tmp = -641817194, tmp)*(x<<(((-1933817364)>>(((tmp = 2084673536, tmp)|x)&x))&(tmp = -2752464480, tmp)))))%((796026752)*x))+(((tmp = -3083359669, tmp)|x)-((715303522)|(tmp = 181297266, tmp))))*(-1691520182.3207517))))); + assertEquals(0, x <<= (-2322389800)); + assertEquals(0, x *= (tmp = 3188682235, tmp)); + assertEquals(0, x |= (x>>>((tmp = -2729325231.8288336, tmp)^((-393497076.96012783)*(x/(tmp = -2198942459.9466457, tmp)))))); + assertEquals(0, x ^= x); + assertEquals(0, x %= (2835024997.4447937)); + assertEquals(0, x <<= x); + assertEquals(0, x >>= (tmp = 1109824126, tmp)); + assertEquals(0, x <<= (3013043386)); + assertEquals(206825782.74659085, x -= (-206825782.74659085)); + assertEquals(-645346761227699500, x *= (-3120243292)); + assertEquals(6825462, x >>= ((tmp = 1457908135, tmp)<<x)); + assertEquals(-612366097.9189918, x -= (619191559.9189918)); + assertEquals(-612306090.9189918, x -= ((2328676543.893506)>>x)); + assertEquals(0, x ^= (x>>(((x>>>(1856200611.2269292))&(tmp = 2003217473, tmp))%((((((-107135673)+(((3062079356.170611)<<(tmp = -676928983, tmp))>>((tmp = -1487074941.2638814, tmp)|((-1601614031)/(1317006144.5025365)))))+x)*(((1163301641)>>>(448796567))/((x%((tmp = 72293197.34410787, tmp)+(-2304112723)))/((455610361)%(-2799431520)))))>>>(-217305041.09432888))<<(x-(tmp = -2168353649, tmp)))))); + assertEquals(0, x >>= x); + assertEquals(-Infinity, x -= (((-1651597599.8950624)+(1780404320))/x)); + assertEquals(0, x <<= (tmp = 2246420272.4321294, tmp)); + assertEquals(0, x *= ((2793605382)-(tmp = -272299011, tmp))); + assertEquals(0, x *= x); + assertEquals(0, x <<= x); + assertEquals(0, x >>= (tmp = 2556413090, tmp)); + assertEquals(0, x >>= ((tmp = -1784710085, tmp)%x)); + assertEquals(0, x %= (tmp = -1929880813, tmp)); + assertEquals(0, x *= (2586983368)); + assertEquals(0, x &= x); + assertEquals(0, x <<= (-2144588807)); + assertEquals(0, x ^= ((x<<(((((((-596537598)+((x-(((((((tmp = -3179604796, tmp)/((tmp = 1156725365.3543215, tmp)>>>(tmp = -2762144319, tmp)))%(x<<x))&((tmp = 1750241928.1271567, tmp)&(x/((tmp = 1781306819, tmp)|x))))+((((2893068644)/((tmp = -576164593.9720252, tmp)<<((2724671.48995471)&(tmp = -573132475, tmp))))%(tmp = -1355625108, tmp))&(tmp = -302869512.5880568, tmp)))+x)<<x))>>((tmp = -2569172808, tmp)/x)))^x)-(tmp = -1174006275.2213159, tmp))&x)&(((((((-2303274799)>>(tmp = -814839320, tmp))/(tmp = 183887306.09810615, tmp))>>(((tmp = 1054106394.3704875, tmp)|x)>>>x))-(x-(tmp = 1313696830, tmp)))-((tmp = 2373274399.0742035, tmp)|((((tmp = -3163779539.4902935, tmp)*(tmp = -3056125181.726942, tmp))&(((x^(x^(x/((tmp = -576441696.6015451, tmp)<<(tmp = -26223719.920306206, tmp)))))>>(tmp = -2332835940, tmp))|((-146303509.41093707)&(tmp = -2676964025, tmp))))/((((x*(tmp = 1059918020, tmp))|((((2341797349)|(tmp = -744763805.1381104, tmp))<<x)+((2991320875.552578)^(2920702604.701831))))^(-1721756138))^(((tmp = -2794367554, tmp)>>((-2671235923.2097874)<<(x&((((tmp = -621472314.0859051, tmp)-(((x*x)+x)>>>((tmp = 1834038956, tmp)+x)))*x)^(tmp = -2090567586.321468, tmp)))))<<(321395210))))))>>>(tmp = -1207661719, tmp)))+(-2877264053.3805156)))/(x%(tmp = -2226991657.709366, tmp)))); + assertEquals(0, x *= (tmp = 986904991.061398, tmp)); + assertEquals(0, x -= (x%(650819306.6671969))); + assertEquals(0, x >>>= (905893666.2871252)); + assertEquals(0, x += (((tmp = 2501942710.4804144, tmp)&x)/((tmp = -851080399.1751502, tmp)-(-1168623992)))); + assertEquals(-0, x *= (tmp = -2014577821.4554045, tmp)); + assertEquals(0, x &= (tmp = 1995246018, tmp)); + assertEquals(0, x %= (1724355237.7031958)); + assertEquals(-954696411, x += (((-2825222201)+(((1662353496.1795506)>>>(x-x))|(tmp = 225015046, tmp)))^(x&x))); + assertEquals(-2158427339993389800, x *= (2260852052.1539803)); + assertEquals(19559, x >>>= (-862409169.4978967)); + assertEquals(-0.000012241163878671237, x /= (x^(tmp = 2697144215.160239, tmp))); + assertEquals(0, x -= x); + assertEquals(1448177644, x |= (tmp = 1448177644.624848, tmp)); + assertEquals(1448177644, x %= (((-1497553637.4976408)+(402228446))<<x)); + assertEquals(2304640553, x -= (-856462909)); + assertEquals(152436736, x &= ((766686903)*(((tmp = 660964683.1744609, tmp)|((((tmp = 297369746, tmp)-(x+((tmp = -2677127146, tmp)/x)))>>(((((((x%(x<<x))-(((((529254728)|((x|(-1407086127.6088922))&(tmp = -1968465008.5000398, tmp)))/(x%x))&((((-2761805265.92574)-x)*(x^(tmp = 110730179, tmp)))%((177220657.06030762)*(((2532585190.671373)/x)+(-1465143151)))))<<((tmp = -3008848338, tmp)<<(-2475597073))))|((-192996756.38619018)|((((1445996780)|(x>>>((((tmp = -2482370545.791443, tmp)*(tmp = -270543594, tmp))^x)*((1346780586)/(tmp = -625613363.885356, tmp)))))-(x<<(x/(-562307527))))&(-125701272))))*((x&x)%(tmp = 752963070, tmp)))>>>(tmp = 17419750.79086232, tmp))*x)^(x^((-157821212.04674292)-(tmp = 503849221.598824, tmp)))))-(tmp = 1479418449, tmp)))>>>((((((-78138548.2193842)<<(((2319032860.806689)-(tmp = -1564963892.5137577, tmp))>>>(-73673322.28957987)))<<((1797573493.3467085)*x))>>(tmp = 759994997, tmp))>>>(-1066441220))&(((((((tmp = 1972048857, tmp)*(((x&((-1347017320.0747669)>>>x))*(-2332716925.705054))%(-376976019.24362826)))>>>((tmp = -466479974, tmp)+x))&(-2282789473.3675604))|(((((((((269205423.7510414)-(tmp = 21919626.105656862, tmp))*((x-(tmp = -378670528, tmp))>>(tmp = -1045706598, tmp)))>>(tmp = -3062647341.234485, tmp))>>>x)|(tmp = -285399599.9386575, tmp))%(tmp = 2731214562, tmp))|((((tmp = 837093165.3438574, tmp)|(tmp = -2956931321, tmp))+((1871874558.3292787)<<((x|((tmp = -3169147427, tmp)%(((x^x)%(1479885041))%((1769991217)%(tmp = -1899472458, tmp)))))*(tmp = -837098563.71806, tmp))))>>(tmp = -1866722748, tmp)))-(2037734340.8345597)))>>((tmp = -1262019180.5332131, tmp)+(x*(1274173993.9800131))))*(tmp = 2336989321.855402, tmp)))))); + assertEquals(4, x >>= (tmp = -2577728327, tmp)); + assertEquals(16, x *= (x<<((2622323372.580596)*(tmp = -1947643367, tmp)))); + assertEquals(33554432, x <<= (tmp = -2938370507, tmp)); + assertEquals(-2399497018.987414, x -= (tmp = 2433051450.987414, tmp)); + assertEquals(1, x /= x); + assertEquals(2, x <<= x); + assertEquals(0, x >>= (x&x)); + assertEquals(0, x <<= x); +} +f(); diff --git a/deps/v8/test/mjsunit/numops-fuzz.js b/deps/v8/test/mjsunit/numops-fuzz.js deleted file mode 100644 index bd7e4fa23a..0000000000 --- a/deps/v8/test/mjsunit/numops-fuzz.js +++ /dev/null @@ -1,4609 +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. - -function f() { - var x = 0; - var tmp = 0; - assertEquals(0, x /= (tmp = 798469700.4090232, tmp)); - assertEquals(0, x *= (2714102322.365509)); - assertEquals(0, x *= x); - assertEquals(139516372, x -= (tmp = -139516372, tmp)); - assertEquals(1, x /= (x%(2620399703.344006))); - assertEquals(0, x >>>= x); - assertEquals(-2772151192.8633175, x -= (tmp = 2772151192.8633175, tmp)); - assertEquals(-2786298206.8633175, x -= (14147014)); - assertEquals(1509750523, x |= ((1073767916)-(tmp = 919311632.2789925, tmp))); - assertEquals(2262404051.926751, x += ((752653528.9267509)%x)); - assertEquals(-270926893, x |= (tmp = 1837232194, tmp)); - assertEquals(0.17730273401688765, x /= ((tmp = -2657202795, tmp)-(((((x|(tmp = -1187733892.282897, tmp))-x)<<(556523578))-x)+(-57905508.42881298)))); - assertEquals(122483.56550261026, x *= ((((tmp = 2570017060.15193, tmp)%((-1862621126.9968336)>>x))>>(x>>(tmp = 2388674677, tmp)))>>>(-2919657526.470434))); - assertEquals(0, x ^= x); - assertEquals(0, x <<= (tmp = 2705124845.0455265, tmp)); - assertEquals(0, x &= (-135286835.07069612)); - assertEquals(-0, x *= ((tmp = -165810479.10020828, tmp)|x)); - assertEquals(248741888, x += ((735976871.1308595)<<(-2608055185.0700903))); - assertEquals(139526144, x &= (tmp = -1454301068, tmp)); - assertEquals(-0.047221345672746884, x /= (tmp = -2954726130.994727, tmp)); - assertEquals(0, x <<= (x>>x)); - assertEquals(0, x >>>= ((x+(912111201.488966))-(tmp = 1405800042.6070075, tmp))); - assertEquals(-1663642733, x |= (((-1663642733.5700119)<<(x^x))<<x)); - assertEquals(-914358272, x <<= ((((-308411676)-(-618261840.9113789))%(-68488626.58621716))-x)); - assertEquals(-1996488704, x &= (-1358622641.5848842)); - assertEquals(-345978263, x += (1650510441)); - assertEquals(3, x >>>= (-1106714178.701668)); - assertEquals(1, x %= (((x>>(x>>(tmp = -3052773846.817114, tmp)))*(tmp = 1659218887.379526, tmp))&x)); - assertEquals(-943225672, x += (-943225673)); - assertEquals(-0.41714300120060854, x /= (tmp = 2261156652, tmp)); - assertEquals(0, x >>>= ((3107060934.8863482)<<(tmp = 1902730887, tmp))); - assertEquals(0, x &= x); - assertEquals(1476628, x |= ((tmp = -2782899841.390033, tmp)>>>(2097653770))); - assertEquals(0.0008887648921591833, x /= ((tmp = 1661438264.5253348, tmp)%((tmp = 2555939813, tmp)*(-877024323.6515315)))); - assertEquals(0, x <<= (tmp = -2366551345, tmp)); - assertEquals(0, x &= (tmp = 1742843591, tmp)); - assertEquals(0, x -= x); - assertEquals(4239, x += ((-3183564176.232031)>>>(349622674.1255014))); - assertEquals(-67560, x -= ((2352742295)>>>x)); - assertEquals(-67560, x &= x); - assertEquals(-0.00003219917807302283, x /= (2098190203.699741)); - assertEquals(0, x -= x); - assertEquals(0, x >>= ((((tmp = -869086522.8358297, tmp)/(187820779))-(tmp = -2000970995.1931965, tmp))|(1853528755.6064696))); - assertEquals(0, x >>= (-3040509919)); - assertEquals(0, x %= (((tmp = -2386688049.194946, tmp)<<(tmp = -669711391, tmp))|x)); - assertEquals(0, x %= (tmp = -298431511.4839926, tmp)); - assertEquals(0, x /= (2830845091.2793818)); - assertEquals(0, x /= ((((-2529926178)|x)^((tmp = 2139313707.0894063, tmp)%((-1825768525.0541775)-(-952600362.7758243))))+x)); - assertEquals(NaN, x /= x); - assertEquals(NaN, x -= x); - assertEquals(NaN, x /= (tmp = -432944480, tmp)); - assertEquals(0, x <<= (((((x^((-1777523727)+(2194962794)))>>>(((((-590335134.8224905)%(x*(2198198974)))|(tmp = -2068556796, tmp))/(1060765637))*(-147051676)))/((tmp = -477350113.92686677, tmp)<<((x/(2018712621.0397925))^((tmp = 491163813.3921983, tmp)+(((x|((((x%(1990073256.812654))%((-2024388518.9599915)>>((tmp = 223182187, tmp)*(-722241065))))>>>(tmp = 2517147885.305745, tmp))%(1189996239.11222)))&x)%(-306932860))))))&((tmp = 1117802724.485684, tmp)+((-1391614045)-x)))%((((x>>((2958453447)*x))^(((410825859)|(((tmp = -1119269292.5495896, tmp)>>>(((((((x%(tmp = 648541746.6059314, tmp))*((-2304508480)<<((((x^(1408199888.1454597))|((251623937)|x))/((-382389946.9984102)|(tmp = -2082681143.5893767, tmp)))-(((tmp = 631243472, tmp)>>>(1407556544))/(((x>>>x)>>>(tmp = -6329025.47865057, tmp))>>>(tmp = 948664752.543093, tmp))))))/((((-183248880)>>x)&x)&x))>>x)&(((-978737284.8492057)%(tmp = 2983300011.737006, tmp))&(tmp = 2641937234.2954116, tmp)))<<x)>>(2795416632.9722223)))%((((tmp = -50926632, tmp)/x)&(((tmp = -2510786916, tmp)/x)/(-699755674)))|((((tmp = 1411792593, tmp)>>(924286570.2637128))>>((1609997725)>>(2735658951.0762663)))*(tmp = 726205435, tmp)))))<<(tmp = -2135055357.3156831, tmp)))/(tmp = 1408695065, tmp))^(tmp = -1343267739.8562133, tmp)))); - assertEquals(0, x %= (-437232116)); - assertEquals(-2463314518.2747326, x -= (2463314518.2747326)); - assertEquals(109, x >>= (2401429560)); - assertEquals(-2687641732.0253763, x += (-2687641841.0253763)); - assertEquals(-2336375490019484000, x *= (tmp = 869303174.6678596, tmp)); - assertEquals(5.458650430363785e+36, x *= x); - assertEquals(0, x |= ((((-1676972008.797291)*x)*((tmp = 2606991807, tmp)-x))<<x)); - assertEquals(0, x &= ((-3053393759.3496876)+(-1431008367))); - assertEquals(-856728369, x |= (x-(((((764337872)/x)<<((x|(((tmp = 1409368192.1268077, tmp)+(tmp = -848083676, tmp))|(-2797102463.7915916)))^x))/x)^(tmp = 856728369.0589117, tmp)))); - assertEquals(-0, x %= x); - assertEquals(1116550103, x ^= (-3178417193)); - assertEquals(1116550103, x %= (tmp = -1482481942, tmp)); - assertEquals(133, x >>>= x); - assertEquals(-1.381429241671034e-7, x /= ((tmp = -962771116.8101778, tmp)^x)); - assertEquals(-1092268961, x |= ((tmp = 3202672531, tmp)-((x-(tmp = 845529357, tmp))>>(tmp = -868680593, tmp)))); - assertEquals(-1092268961, x %= (tmp = 2670840415.304719, tmp)); - assertEquals(-122794480, x %= (tmp = 969474481, tmp)); - assertEquals(-297606521542193600, x *= (2423614820)); - assertEquals(72460064, x >>>= (tmp = -1230798655, tmp)); - assertEquals(-203714325373689600, x *= (-2811401400)); - assertEquals(2154914048, x >>>= (((2241377026.001436)/x)+x)); - assertEquals(1177864081, x ^= (tmp = -968513903, tmp)); - assertEquals(35947664, x &= (-2086226758.2704995)); - assertEquals(20795732539020670, x += (x*(578500247))); - assertEquals(-892004992, x >>= x); - assertEquals(-7023661.354330708, x /= ((((((1740714214)%((tmp = -459699286, tmp)+(tmp = -1700187400, tmp)))>>(tmp = -3170295237, tmp))+(tmp = -497509780, tmp))+((1971976144.6197853)+(661992813.6077721)))>>>(-1683802728))); - assertEquals(-1634205696, x <<= x); - assertEquals(-7, x >>= (-3187653764.930914)); - assertEquals(-5.095345981491203, x -= ((tmp = 748315289, tmp)/(tmp = -392887780, tmp))); - assertEquals(1486531570, x &= (1486531570.9300508)); - assertEquals(5670, x >>= (((tmp = -2486758205.26425, tmp)*(732510414))|x)); - assertEquals(5670, x >>= (((-1811879946.2553763)%(1797475764))/(((tmp = -2159923884, tmp)|x)+(tmp = -1774410807, tmp)))); - assertEquals(38, x %= (x>>>x)); - assertEquals(-151134215, x ^= (((tmp = -2593085609.5622163, tmp)+((tmp = -814992345.7516887, tmp)-(534809571)))|(tmp = -232678571, tmp))); - assertEquals(-234881024, x <<= x); - assertEquals(-234881024, x <<= (x>>>x)); - assertEquals(55169095435288580, x *= x); - assertEquals(0, x >>= (tmp = 1176612256, tmp)); - assertEquals(0, x <<= (1321866341.2486475)); - assertEquals(0, x %= (x-(-602577995))); - assertEquals(0, x >>>= (((((tmp = -125628635.79970193, tmp)^(tmp = 1294209955.229382, tmp))&(((tmp = -2353256654.0725203, tmp)|((-1136743028.9425385)|((((950703429.1110399)-(x>>>x))/((((x%(-252705869.21126103))/((tmp = 886957620, tmp)<<(x%((tmp = -1952249741, tmp)*(tmp = -1998149844, tmp)))))|(tmp = 1933366713, tmp))|((tmp = -2957141565, tmp)>>>(tmp = 1408598804, tmp))))+(((((((-2455002047.4910946)%(tmp = -528017836, tmp))&((-2693432769)/(tmp = 2484427670.9045153, tmp)))%(-356969659))-((((((tmp = 3104828644.0753174, tmp)%(x>>>(tmp = 820832137.8175925, tmp)))*((tmp = 763080553.9260503, tmp)+(3173597855)))<<(((-510785437)^x)<<(x|(((x*(x%((tmp = -1391951515, tmp)/x)))-x)|(x-((-522681793.93221474)/((2514619703.2162743)*(2936688324))))))))|x)>>>(-2093210042)))&(763129279.3651779))&x))))-x))%(((-1331164821)&(tmp = 1342684586, tmp))<<(x<<(tmp = 2675008614.588005, tmp))))>>((2625292569.8984914)+(-3185992401)))); - assertEquals(0, x *= (tmp = 671817215.1147974, tmp)); - assertEquals(-1608821121, x ^= ((tmp = 2686146175.04077, tmp)>>>x)); - assertEquals(-0, x %= x); - assertEquals(-0, x /= ((tmp = 286794551.0720866, tmp)|(x%x))); - assertEquals(0, x <<= (x|(tmp = 1095503996.2285218, tmp))); - assertEquals(443296752, x ^= (443296752)); - assertEquals(110824188, x >>= ((184708570)>>(x&x))); - assertEquals(0.7908194935161674, x /= ((((167151154.63381648)&((tmp = -1434120690, tmp)-(tmp = 2346173080, tmp)))/(56656051.87305987))^(140138414))); - assertEquals(-0.9027245492678485, x *= ((tmp = 1724366578, tmp)/(((2979477411)<<(((897038568)>>(tmp = 348960298, tmp))%(281056223.2037884)))^((((-1383133388)-(((-1379748375)-((x>>(x&(tmp = 2456582046, tmp)))>>>(-2923911755.565961)))&x))<<(-2825791731))^(tmp = -1979992970, tmp))))); - assertEquals(0, x &= (2482304279)); - assertEquals(-0, x *= (-2284213673)); - assertEquals(0, x <<= ((2874381218.015819)|x)); - assertEquals(0, x *= (x>>>(tmp = 2172786480, tmp))); - assertEquals(0, x &= (-1638727867.2978938)); - assertEquals(0, x %= ((tmp = -2213947368.285817, tmp)>>x)); - assertEquals(0, x >>>= (tmp = -531324706, tmp)); - assertEquals(0, x %= (tmp = -2338792486, tmp)); - assertEquals(0, x <<= (((tmp = 351012164, tmp)<<(x|((tmp = -3023836638.5337825, tmp)^(-2678806692))))|x)); - assertEquals(0, x %= (x-(tmp = -3220231305.45039, tmp))); - assertEquals(0, x <<= (-2132833261)); - assertEquals(0, x >>>= x); - assertEquals(0, x %= ((2544970469)+(((-2633093458.5911965)&(644108176))-(x>>>(tmp = -949043718, tmp))))); - assertEquals(-2750531265, x += (-2750531265)); - assertEquals(0, x >>= x); - assertEquals(0, x *= ((tmp = 1299005700, tmp)-x)); - assertEquals(0, x >>= x); - assertEquals(-1785515304, x -= (((((-806054462.5563161)/x)>>>x)+(1785515304))|((tmp = 2937069788.9396844, tmp)/x))); - assertEquals(-3810117159.173689, x -= (2024601855.1736891)); - assertEquals(-6.276064139320051, x /= (607087033.3053156)); - assertEquals(134217727, x >>>= (((x%(tmp = 924293127, tmp))^x)|((x>>>(x&((((tmp = -413386639, tmp)/(x>>(tmp = 599075308.8479941, tmp)))^(tmp = -1076703198, tmp))*((tmp = -2239117284, tmp)>>(655036983)))))-x))); - assertEquals(134217727, x %= (tmp = 2452642261.038778, tmp)); - assertEquals(-569504740360507, x *= ((tmp = -1086243941, tmp)>>(tmp = 1850668904.4885683, tmp))); - assertEquals(113378806, x >>>= (tmp = -2558233435, tmp)); - assertEquals(979264375, x -= (((x>>(1950008052))%((2917183569.0209)*(tmp = 1184250640.446752, tmp)))|((((tmp = -691875212, tmp)-(-2872881803))>>(tmp = 44162204.97461021, tmp))^(tmp = 865885647, tmp)))); - assertEquals(-1127813632, x <<= ((((tmp = -2210499281, tmp)>>>x)-(tmp = 2359697240, tmp))-x)); - assertEquals(-1707799657, x ^= (653518231.3995534)); - assertEquals(2916579668449318000, x *= x); - assertEquals(2916579669254640600, x += (x&(tmp = 2986558026.399422, tmp))); - assertEquals(870995175, x ^= (2598813927.8991632)); - assertEquals(870995175, x %= (-2857038782)); - assertEquals(1869503575895591000, x *= (x|(x|(((tmp = 2478650307.4118147, tmp)*((tmp = 2576240847.476932, tmp)>>>x))<<x)))); - assertEquals(-134947790, x |= ((tmp = 1150911808, tmp)*((2847735464)/(-2603172652.929262)))); - assertEquals(-137053182, x -= ((tmp = 2155921819.0929346, tmp)>>>(x-(((-1960937402)-(-1907735074.2875962))%((1827808310)^(tmp = -2788307127, tmp)))))); - assertEquals(-134824702, x |= (((2912578752.2395406)^(x%(((-2585660111.0638976)<<(((((tmp = 747742706, tmp)%(-1630261205))&((((x|(x|(-2619903144.278758)))|((2785710568.8651934)>>((-968301967.5982246)<<(x&x))))>>((x>>>((x>>>(tmp = -1402085797.0310762, tmp))*((tmp = -323729645.2250068, tmp)<<(tmp = 2234667799, tmp))))>>>(-167003745)))>>((924665972.4681011)<<x)))>>>x)<<((((x+x)+x)-(((tmp = 2399203431.0526247, tmp)-(-2872533271))-(((tmp = 914778794.2087344, tmp)-(tmp = 806353942.9502392, tmp))|(((tmp = 262924334.99231672, tmp)&x)|(tmp = -460248836.5602243, tmp)))))/x)))%((-1681000689)/(tmp = -2805054623.654228, tmp)))))*(tmp = 957346233.9619625, tmp))); - assertEquals(-3274838, x %= ((((tmp = 3155450543.3524327, tmp)>>>x)<<(tmp = 2103079652.3410985, tmp))>>x)); - assertEquals(-3274838, x |= ((((tmp = 2148004645.639173, tmp)>>>(tmp = -1285119223, tmp))<<(((((-711596054)>>>(tmp = -2779776371.3473206, tmp))^(((((tmp = -1338880329.383915, tmp)<<((-1245247254.477341)>>x))*(tmp = -2649052844.20065, tmp))>>((1734345880.4600453)%(x/(2723093117.118899))))*(1252918475.3285656)))<<(2911356885))^x))<<(-1019761103))); - assertEquals(1703281954, x &= (((tmp = 1036570471.7412028, tmp)+((tmp = 3043119517, tmp)%(2374310816.8346715)))%(tmp = -2979155076, tmp))); - assertEquals(1741588391, x |= ((tmp = 1230009575.6003838, tmp)>>>(-1247515003.8152597))); - assertEquals(72869474.64782429, x %= (tmp = 1668718916.3521757, tmp)); - assertEquals(770936242.104203, x += (698066767.4563787)); - assertEquals(-0.2820604726420833, x /= (tmp = -2733230342, tmp)); - assertEquals(403480578, x |= ((969730374)&(tmp = 1577889835, tmp))); - assertEquals(-1669557233, x ^= ((-1616812135)+(tmp = -456209292, tmp))); - assertEquals(-1630427, x >>= ((2327783031.1175823)/(226947662.4579488))); - assertEquals(131022, x >>>= ((tmp = -1325018897.2482083, tmp)>>(x&((((((-1588579772.9240348)<<(tmp = -1775580288.356329, tmp))<<(tmp = -1021528325.2075481, tmp))>>((tmp = 2373033451.079956, tmp)*(tmp = 810304612, tmp)))-((tmp = -639152097, tmp)<<(tmp = 513879484, tmp)))&(2593958513))))); - assertEquals(1, x >>= ((3033200222)-x)); - assertEquals(-561146816.4851823, x += (tmp = -561146817.4851823, tmp)); - assertEquals(-4.347990105831158, x /= ((((-1270435902)*x)%((tmp = 637328492.7386824, tmp)-(x>>(-749100689))))%(x+x))); - assertEquals(-1, x >>= x); - assertEquals(1, x *= x); - assertEquals(111316849706694460, x += ((966274056)*(x|(115202150)))); - assertEquals(-1001883840, x >>= x); - assertEquals(-1001883840, x &= x); - assertEquals(-3006880758, x += ((((-2275110637.4054556)/((x+(tmp = -1390035090.4324536, tmp))>>(-5910593)))&(tmp = 378982420, tmp))|(tmp = 2289970378.568629, tmp))); - assertEquals(314474, x >>>= (x>>((tmp = -228007336.31281257, tmp)%(tmp = 1127648013, tmp)))); - assertEquals(-17694827, x ^= ((tmp = 2095133598.1849852, tmp)|(-1978322311))); - assertEquals(1, x /= x); - assertEquals(1, x %= (-2323617209.7531185)); - assertEquals(0, x >>>= (x*(tmp = -1574455400.489434, tmp))); - assertEquals(0, x >>= (3131854684)); - assertEquals(2853609824, x += ((-231012098)-(tmp = -3084621922, tmp))); - assertEquals(8143089027629311000, x *= x); - assertEquals(313052685, x ^= (tmp = 2962303501, tmp)); - assertEquals(4776, x >>= (tmp = 2271457232, tmp)); - assertEquals(0.000002812258572702285, x /= (tmp = 1698279115, tmp)); - assertEquals(0, x >>>= (tmp = 1698465782.0927145, tmp)); - assertEquals(0, x <<= x); - assertEquals(0, x |= ((x<<((-1824760240.3040407)<<(2798263764.39145)))&(tmp = 1795988253.0493627, tmp))); - assertEquals(1782206945, x ^= (-2512760351.7881565)); - assertEquals(7610569113843172000, x *= (((tmp = -44415823.92972565, tmp)&(tmp = 1402483498.9421625, tmp))+(tmp = 2909778666, tmp))); - assertEquals(15221138227873292000, x += (x-(tmp = -186948658.394145, tmp))); - assertEquals(0, x -= x); - assertEquals(-2238823252, x -= ((tmp = 2238823252, tmp)+x)); - assertEquals(0, x -= x); - assertEquals(0, x >>= (2976069570)); - assertEquals(0, x >>= ((tmp = -2358157433, tmp)/x)); - assertEquals(-949967713, x ^= (tmp = -949967713, tmp)); - assertEquals(-1, x >>= x); - assertEquals(-1522291702.1977966, x *= (1522291702.1977966)); - assertEquals(-1522291702, x >>= ((((2290279800)|x)|(1793154434.6798015))&((-1161390929.0766077)>>>x))); - assertEquals(83894274, x &= (tmp = 1571058486, tmp)); - assertEquals(43186847.90522933, x += ((tmp = -1131332988.0947707, tmp)%x)); - assertEquals(0, x >>= (tmp = -1968312707.269359, tmp)); - assertEquals(0, x &= (2507747643.26175)); - assertEquals(0, x %= (tmp = 3190525303.366887, tmp)); - assertEquals(-1968984602, x ^= (((x/(x|(-1607062026.5338054)))<<(tmp = 2207669861.8770065, tmp))+(tmp = 2325982694.956348, tmp))); - assertEquals(554, x >>>= (((tmp = -2302283871.993821, tmp)>>>(-3151835112))|(((((x%(-1534374264))/((731246012)<<(((883830997.1194847)<<(((-1337895080.1937215)/(tmp = 3166402571.8157315, tmp))^(tmp = -1563897595.5799441, tmp)))>>(tmp = -556816951.0537591, tmp))))>>(-2682203577))<<(x/((1654294674.865079)+x)))/((x^(-2189474695.4259806))/(-475915245.7363057))))); - assertEquals(1372586111, x ^= (1372586581)); - assertEquals(1166831229, x -= ((-834168138)&(762573579))); - assertEquals(2333662456, x -= ((x>>x)-x)); - assertEquals(-1961304840, x &= x); - assertEquals(-2130143128, x &= (2982852718.0711775)); - assertEquals(1073741824, x <<= (-1446978661.6426942)); - assertEquals(2097152, x >>>= ((-1424728215)-(((127872198)%(tmp = -2596923298, tmp))&x))); - assertEquals(2097152, x >>>= x); - assertEquals(0, x &= (x/(tmp = -518419194.42994523, tmp))); - assertEquals(0, x >>= ((x/(-1865078245))%(tmp = 2959239210, tmp))); - assertEquals(-0, x *= ((x|(-1721307400))|(-3206147171.9491577))); - assertEquals(0, x >>>= ((-694741143)&(tmp = -2196513947.699142, tmp))); - assertEquals(0, x <<= x); - assertEquals(0, x &= ((tmp = 2037824385.8836646, tmp)+((tmp = 1203034986.4647732, tmp)/(x>>>(((-1374881234)/(899771270.3237157))+((-2296524362.8020077)|(-1529870870))))))); - assertEquals(0, x >>= (tmp = 2770637816, tmp)); - assertEquals(0, x ^= x); - assertEquals(-1861843456, x |= ((632402668)*((x|(tmp = -1032952662.8269436, tmp))|(tmp = 2671272511, tmp)))); - assertEquals(-1861843456, x >>= (((x>>>x)+x)<<(-1600908842))); - assertEquals(-58182608, x >>= (x-(tmp = -2496617861, tmp))); - assertEquals(-3636413, x >>= (tmp = -400700028, tmp)); - assertEquals(-7272826, x += x); - assertEquals(-1, x >>= ((tmp = -3184897005.3614545, tmp)-((-1799843014)|(tmp = 2832132915, tmp)))); - assertEquals(-121800925.94209385, x *= (121800925.94209385)); - assertEquals(-30450232, x >>= (-979274206.6261561)); - assertEquals(-30450232, x >>= (tmp = -1028204832.5078967, tmp)); - assertEquals(-30450232, x |= x); - assertEquals(965888871, x ^= (((((-2157753481.3375635)*((tmp = -1810667184.8165767, tmp)&((tmp = 2503908344.422232, tmp)|x)))>>(x>>(1601560785)))<<x)^(tmp = 943867311.6380403, tmp))); - assertEquals(7546006, x >>>= x); - assertEquals(7546006, x <<= ((tmp = 1388931761.780241, tmp)*(x-(tmp = -1245147647.0070577, tmp)))); - assertEquals(12985628, x += (x&(-1520746354))); - assertEquals(12985628, x &= x); - assertEquals(12985628, x %= (tmp = 308641965, tmp)); - assertEquals(685733278, x |= ((tmp = -1275653544, tmp)-((tmp = -1956798010.3773859, tmp)%(tmp = 2086889575.643448, tmp)))); - assertEquals(679679376, x &= (2860752368)); - assertEquals(1770773904, x |= (x<<(3200659207))); - assertEquals(1224886544, x &= (-585733767.6876519)); - assertEquals(1224886544, x %= ((tmp = -114218494, tmp)-x)); - assertEquals(1208109328, x &= (tmp = 1854361593, tmp)); - assertEquals(18434, x >>>= x); - assertEquals(-349394636955256100, x *= (x*(-1028198742))); - assertEquals(-519536600.7713163, x %= (-1054085356.9120367)); - assertEquals(-1610612736, x ^= ((tmp = -3126078854, tmp)&x)); - assertEquals(-2637321565906333700, x *= (1637464740.5658746)); - assertEquals(-2637321568051070500, x -= ((tmp = -1006718806, tmp)<<(3005848133.106345))); - assertEquals(368168695, x ^= (x^(tmp = 368168695.6881037, tmp))); - assertEquals(43, x >>>= x); - assertEquals(-2081297089, x |= ((167169305.77248895)+(-2248466405.3199244))); - assertEquals(-2474622167, x -= (tmp = 393325078, tmp)); - assertEquals(-135109701, x %= (-1169756233)); - assertEquals(0, x ^= x); - assertEquals(0, x >>= (((((tmp = -164768854, tmp)/(tmp = -1774989993.1909926, tmp))+x)-((-921438912)>>(tmp = -191772028.69249105, tmp)))-(tmp = 558728578.22033, tmp))); - assertEquals(0, x %= (tmp = 2188003745, tmp)); - assertEquals(0, x <<= (((tmp = -999335540, tmp)>>((((325101977)/(tmp = -3036991542, tmp))<<(tmp = -213302488, tmp))+x))|(tmp = -1054204587, tmp))); - assertEquals(0, x &= ((2844053429.4720345)>>>x)); - assertEquals(NaN, x %= x); - assertEquals(NaN, x -= (-1481729275.9118822)); - assertEquals(NaN, x *= (tmp = 1098314618.2397528, tmp)); - assertEquals(-1073741824, x ^= ((tmp = 1718545772, tmp)<<(((tmp = -81058910, tmp)-(2831123087.424368))+(tmp = 576710057.2361784, tmp)))); - assertEquals(-2921155898.4793186, x -= (1847414074.4793184)); - assertEquals(-1295646720, x <<= (2178621744)); - assertEquals(-0.8906779709597907, x /= ((tmp = -2840292585.6837263, tmp)<<(x&((tmp = 892527695.6172305, tmp)>>>x)))); - assertEquals(0, x <<= (((tmp = 3149667213.298993, tmp)>>(tmp = 1679370761.7226725, tmp))^(115417747.21537328))); - assertEquals(0, x |= x); - assertEquals(0, x %= ((-1112849427)>>(-1245508870.7514496))); - assertEquals(0, x &= x); - assertEquals(0, x |= x); - assertEquals(0, x >>>= ((3144100694.930459)>>>(tmp = 2408610503, tmp))); - assertEquals(0, x <<= ((tmp = 2671709754.0318713, tmp)%x)); - assertEquals(0, x >>>= (x|((tmp = -3048578701, tmp)-(674147224)))); - assertEquals(NaN, x %= x); - assertEquals(0, x &= ((tmp = -2084883715, tmp)|(((((-3008427069)+(875536047.4283574))>>>x)%(tmp = -450003426.1091652, tmp))%(((-2956878433.269356)|(x/((((x%((((((x<<(((tmp = -1581063482.510351, tmp)^x)-(tmp = 1364458217, tmp)))^((tmp = 1661446342, tmp)+(1307091014)))/(342270750.9901335))>>>(x&((1760980812.898993)&((tmp = 2878165745.6401143, tmp)/(((tmp = -981178013, tmp)/(-2338761668.29912))>>(-958462630))))))*((1807522840)^((tmp = 1885835034, tmp)^(-2538647938))))*(1673607540.0854697)))%x)>>x)<<x)))<<(853348877.2407281))))); - assertEquals(0, x >>>= x); - assertEquals(-1162790279, x -= (1162790279)); - assertEquals(-1162790279, x >>= (((-490178658)*x)/((((((tmp = -1883861998.6699312, tmp)/(tmp = -2369967345.240594, tmp))+(3142759868.266447))&(508784917.8158537))&x)>>(-2129532322)))); - assertEquals(-1360849740.9829152, x -= (x+(1360849740.9829152))); - assertEquals(1928392181, x ^= (-602670783)); - assertEquals(19478708.898989897, x /= (((-2617861994)>>(tmp = 797256920, tmp))%(-1784987906))); - assertEquals(-8648903.575540157, x *= (((tmp = 673979276, tmp)/(-1517908716))%(x/x))); - assertEquals(-8648903.575540157, x %= ((((643195610.4221292)>>>(tmp = 2342669302, tmp))>>>(tmp = -1682965878, tmp))^((tmp = -208158937.63443017, tmp)>>((907286989)&(x<<(448634893)))))); - assertEquals(1399288769, x ^= (tmp = -1407486728, tmp)); - assertEquals(0, x &= (((1999255838.815517)/(tmp = 564646001, tmp))/(-3075888101.3274765))); - assertEquals(0, x ^= ((-78451711.59404826)%x)); - assertEquals(-1351557131, x |= (2943410165)); - assertEquals(1715626371, x -= (-3067183502)); - assertEquals(71434240, x &= ((-1800066426)<<(((((x<<(-324796375))+x)<<(tmp = 2696824955.735132, tmp))^x)%(tmp = 444916469, tmp)))); - assertEquals(71434240, x >>>= (((x&((x%x)|x))+(tmp = 2226992348.3050146, tmp))<<(-305526260))); - assertEquals(0, x -= (x%(tmp = 582790928.5832802, tmp))); - assertEquals(0, x *= ((x%(1865155340))>>>((x<<(2600488191))^(-308995123)))); - assertEquals(0, x >>= (x&(-3120043868.8531103))); - assertEquals(0, x |= x); - assertEquals(-0, x *= (tmp = -172569944, tmp)); - assertEquals(0, x <<= (-1664372874)); - assertEquals(1377713344.6784928, x += (tmp = 1377713344.6784928, tmp)); - assertEquals(1377713344, x |= x); - assertEquals(-232833282, x |= (tmp = 2685870654, tmp)); - assertEquals(84639, x -= (((((2778531079.998492)%(2029165314))>>>(tmp = -468881172.3729558, tmp))^x)|((x>>>((((x%(3044318992.943596))&(1996754328.2214756))^(1985227172.7485228))%(tmp = -1984848676.1347625, tmp)))|((tmp = 2637662639, tmp)<<x)))); - assertEquals(0, x ^= x); - assertEquals(1237720303, x -= (-1237720303)); - assertEquals(2, x >>= (-2148785379.428976)); - assertEquals(2, x &= (tmp = -3087007874, tmp)); - assertEquals(0, x %= x); - assertEquals(0, x >>>= x); - assertEquals(0, x >>>= x); - assertEquals(0, x += x); - assertEquals(0, x &= (2055693082)); - assertEquals(-1349456492, x += (x^(-1349456492.315998))); - assertEquals(671088640, x <<= (x>>(-2030805724.5472062))); - assertEquals(-417654580004782100, x *= (tmp = -622353822, tmp)); - assertEquals(1538160360, x |= (195983080.56698656)); - assertEquals(733, x >>>= (tmp = 661085269, tmp)); - assertEquals(657, x &= (-1611460943.993404)); - assertEquals(431649, x *= x); - assertEquals(863298, x += x); - assertEquals(0, x &= ((1899423003)/((472439729)>>((tmp = 2903738952, tmp)+(tmp = 2164601630.3456993, tmp))))); - assertEquals(0, x &= (x>>>(tmp = 1939167951.2828958, tmp))); - assertEquals(1557813284, x |= (x-(-1557813284))); - assertEquals(72876068, x &= (662438974.2372154)); - assertEquals(0.6695448637501589, x /= (tmp = 108844189.45702457, tmp)); - assertEquals(0, x -= x); - assertEquals(2944889412, x += (2944889412)); - assertEquals(3787980288, x -= ((((tmp = -2003814373.2301111, tmp)<<x)>>>(tmp = -3088357284.4405823, tmp))-(843090884))); - assertEquals(1, x >>>= (729274079)); - assertEquals(1, x %= (-148002187.33869123)); - assertEquals(3073988415.673201, x *= (tmp = 3073988415.673201, tmp)); - assertEquals(4839166225.673201, x += (tmp = 1765177810, tmp)); - assertEquals(4529373898.673201, x += (-309792327)); - assertEquals(3097903.090496063, x %= (-150875866.51942348)); - assertEquals(1270874112, x <<= ((((((tmp = -960966763.1418135, tmp)>>((((-3208596981.613482)>>>(tmp = 746403937.6913509, tmp))>>>(-2190042854.066803))/(2449323432)))*(-1272232665.791577))<<(-99306767.7209444))^((-1942103828)/((1570981655)/(tmp = 2381666337, tmp))))+(tmp = -1946759395.1558368, tmp))); - assertEquals(1273845956, x |= (tmp = -3197282108.6120167, tmp)); - assertEquals(159230744, x >>= (((tmp = -1036031403.8108604, tmp)>>>(((3084964493)>>((x*x)^x))+(((2980108409.352001)^x)-(tmp = -2501685423.513927, tmp))))&(326263839))); - assertEquals(-370091747145550100, x *= (tmp = -2324248055.674161, tmp)); - assertEquals(143384219.54999557, x /= (tmp = -2581119096, tmp)); - assertEquals(1843396287, x |= (tmp = 1842718767, tmp)); - assertEquals(2.4895593465813803, x /= (740450831)); - assertEquals(2.4895593465813803, x %= ((((((((-3175333618)>>>((tmp = -1403880166, tmp)<<(tmp = -134875360, tmp)))>>>(2721317334.998084))<<(x&(tmp = 2924634208.1484184, tmp)))*((((x>>(tmp = -200319931.15328693, tmp))-(tmp = -495128933, tmp))+((-788052518.6610589)*((((tmp = 107902557, tmp)&(1221562660))%(x<<(((3155498059)*(((tmp = -1354381139.4897022, tmp)^(tmp = 3084557138.332852, tmp))*((((tmp = 1855251464.8464525, tmp)/((-1857403525.2008865)>>x))|x)-(-2061968455.0023944))))*(1917481864.84619))))^(x-(-508176709.52712965)))))+((((x%(-1942063404))+(x%(tmp = 855152281.180481, tmp)))|(-522863804))>>x)))>>>((tmp = -2515550553, tmp)&(((((-801095375)-(tmp = -2298729336.9792976, tmp))^x)/(tmp = 2370468053, tmp))>>(x|(tmp = -900008879, tmp)))))>>>(((tmp = -810295719.9509168, tmp)*((tmp = -1306212963.6226444, tmp)/(((tmp = 3175881540.9514832, tmp)|(-1439142297.819246))+((tmp = -134415617, tmp)|((-245801870)+x)))))>>(tmp = 1889815478, tmp)))-(((tmp = 597031177, tmp)%(858071823.7655672))+((tmp = 2320838665.8243756, tmp)|((938555608)<<(2351739219.6461897)))))); - assertEquals(6.197905740150709, x *= x); - assertEquals(1, x /= x); - assertEquals(0, x >>= (-1639664165.9076233)); - assertEquals(0, x >>= (-3135317748.801177)); - assertEquals(0, x &= (3185479232.5325994)); - assertEquals(-0, x *= ((-119759439.19668174)/(tmp = 2123964608, tmp))); - assertEquals(0, x /= (-1183061929.2827876)); - assertEquals(0, x <<= (-1981831198)); - assertEquals(0, x >>= ((((x<<(((((((-2133752838)&((tmp = -3045157736.9331336, tmp)>>>(x%x)))>>x)%(tmp = 3082217039, tmp))&(tmp = 270770770.97558427, tmp))|((-2212037556)^((((((2089224421)|(tmp = 360979560, tmp))<<x)%((tmp = -1679487690.6940534, tmp)+((173021423)|((tmp = 560900612, tmp)+((244376267.58977115)^x)))))<<(tmp = 2534513699, tmp))^x)))>>>(2915907189.4873834)))+(x*x))%(1637581117))%(tmp = 2363861105.3786244, tmp))); - assertEquals(0, x &= ((-2765495757.873004)&(1727406493))); - assertEquals(NaN, x -= (((((-1419667515.2616255)|x)-(150530256.48022234))%((((x|x)<<x)>>>(x^x))+x))-((-1216384577.3749187)*(495244398)))); - assertEquals(NaN, x += (x^((tmp = 2472035493, tmp)+x))); - assertEquals(NaN, x %= ((tmp = -1753037412.885754, tmp)|((tmp = 2507058310, tmp)<<(1475945705)))); - assertEquals(-1008981005, x |= ((tmp = -1140889842.6099494, tmp)-(tmp = -131908837, tmp))); - assertEquals(999230327.5872104, x -= (tmp = -2008211332.5872104, tmp)); - assertEquals(975810, x >>= (((-1211913874)*x)>>>((-2842129009)>>(x&(tmp = -1410865834, tmp))))); - assertEquals(7623, x >>= ((tmp = -1051327071, tmp)-(((tmp = -237716102.8005445, tmp)|((2938903833.416546)&x))|(((-1831064579)^x)/((tmp = 2999232092, tmp)-(981996301.2875179)))))); - assertEquals(0, x -= x); - assertEquals(0, x %= (x|(tmp = -666201160.5810485, tmp))); - assertEquals(-1347124100, x |= (-1347124100)); - assertEquals(-0, x %= (x&x)); - assertEquals(-661607963, x ^= (tmp = -661607963.3794863, tmp)); - assertEquals(3465, x >>>= (-828119020.8056595)); - assertEquals(-268431991, x -= (((tmp = -1386256352, tmp)^((tmp = 743629575, tmp)%((x*((tmp = -1719517658, tmp)>>(2019516558)))<<((2637317661)|x))))<<(tmp = -51637065, tmp))); - assertEquals(1578876380, x += ((tmp = 1847308371, tmp)&(((((((tmp = 1487934776.1893163, tmp)%(tmp = 1423264469.3137975, tmp))|(((2653260792.5668964)/(-2417905016.043802))>>>(2097411118.4501896)))^x)^(((tmp = -71334226, tmp)|x)>>>(tmp = -2771758874.7696714, tmp)))^((tmp = -1464849031.3240793, tmp)%(tmp = 2349739690.6430283, tmp)))/x))); - assertEquals(3269293934, x += (1690417554)); - assertEquals(4025392608.031957, x -= (((tmp = 268501120.7225704, tmp)<<(tmp = 2841620654.8903794, tmp))+((tmp = 1606704462.8455591, tmp)/((-2601879963)/(tmp = 2966620168.989736, tmp))))); - assertEquals(7, x >>>= (x^(-1913800035))); - assertEquals(1.4326776816275493e-8, x /= ((((tmp = -2703417892, tmp)/x)^((-2693772270.396241)>>>((x-(tmp = 615999818.5666655, tmp))>>((((2308121439.3702726)<<((-1794701502)>>(x+(tmp = -2253406035.972883, tmp))))<<((tmp = -197103799.0624652, tmp)|(629975898)))>>>x))))>>>((tmp = 2833656803, tmp)^(x^(tmp = -1580436025, tmp))))); - assertEquals(0, x >>>= (tmp = 1525372830.2126007, tmp)); - assertEquals(0, x %= ((2354010949.24469)>>>(x<<x))); - assertEquals(0, x ^= (((1112335059.6922574)*(tmp = -1874363935, tmp))&(((((2154894295.8360596)<<x)&(tmp = -270736315.13505507, tmp))&x)>>>(-2205692260.552064)))); - assertEquals(0, x >>>= (x<<((1488533932)*(tmp = 1707754286, tmp)))); - assertEquals(0, x >>= (((tmp = 1232547376.463387, tmp)%((x>>(711691823.1608362))>>>x))>>(((895039781.7478573)*(((((-334946524)&x)*(tmp = -1214529640, tmp))^(tmp = -1586820245, tmp))*(1062595445)))+x))); - assertEquals(0, x *= (1863299863.2631998)); - assertEquals(0, x /= (tmp = 1858428705.1330547, tmp)); - assertEquals(0, x &= x); - assertEquals(611788028, x += (x^(611788028.1510412))); - assertEquals(1, x /= x); - assertEquals(0, x >>= ((tmp = -1617320707.1784317, tmp)-((-2139400380)-(-1402777976)))); - assertEquals(0, x >>= (415866827.34665)); - assertEquals(-1990811897, x -= (tmp = 1990811897, tmp)); - assertEquals(-1990811895, x += ((x>>>(tmp = -2175453282.769696, tmp))&(tmp = -1459450498.7327478, tmp))); - assertEquals(-2377017935.149517, x += (-386206040.1495173)); - assertEquals(1946129845, x |= (tmp = -2890956796.936539, tmp)); - assertEquals(0, x %= x); - assertEquals(0, x <<= (1616188263)); - assertEquals(-1081213596, x ^= (tmp = 3213753700, tmp)); - assertEquals(3213753700, x >>>= (tmp = -3211181312, tmp)); - assertEquals(-1081213596, x &= x); - assertEquals(-1081213583, x ^= (((tmp = 1599988273.4926577, tmp)>>((((-1061394954.6331315)^x)+((-1835761078)*x))+(x%(tmp = -696221869, tmp))))/((tmp = -1156966790.3436491, tmp)^x))); - assertEquals(0, x ^= x); - assertEquals(NaN, x /= x); - assertEquals(NaN, x += (-1257400530.9263027)); - assertEquals(NaN, x /= (753062089)); - assertEquals(NaN, x *= ((tmp = 305418865.57012296, tmp)^(((-2797769706)+((((tmp = -33288276.988654375, tmp)%(tmp = 1242979846, tmp))|(-316574800))-((tmp = -1766083579.4203427, tmp)*(((x*(tmp = -2400342309.2349987, tmp))>>(tmp = 2632061795, tmp))^(tmp = -1001440809, tmp)))))^((((x-(tmp = -1469542637.6925495, tmp))-x)-(3184196890))%(((((((633226688)*((tmp = -2692547856, tmp)>>(((tmp = -1244311756, tmp)>>>x)+((1746013631.405202)>>>(941829464.1962085)))))%(x-x))+(995681795))-(tmp = -3047070551.3642616, tmp))/(1968259705))-((-2853237880)^(tmp = -2746628223.4540343, tmp))))))); - assertEquals(0, x >>= x); - assertEquals(0.5713172378854926, x += (((x+(((x+x)/(tmp = 2642822318, tmp))*(-2590095885.4280834)))|(tmp = -1769210836, tmp))/(tmp = -3096722308.8665104, tmp))); - assertEquals(-0.000002311097780334994, x /= ((2269858877.9010344)>>(-2992512915.984787))); - assertEquals(-0.000002311097780334994, x %= (-1139222821)); - assertEquals(-0.000004622195560669988, x += x); - assertEquals(1, x /= x); - assertEquals(1, x >>>= (((3002169429.6061807)/(-3068577366))>>>((tmp = -1844537620, tmp)%((((tmp = 2087505119, tmp)>>>x)+x)&(2179989542))))); - assertEquals(-534213071, x *= (-534213071)); - assertEquals(-534213077.3716287, x -= (((tmp = -2390432951.154034, tmp)^x)/(-290501980))); - assertEquals(1836305, x >>>= (x&x)); - assertEquals(1836305, x %= ((x|((3070123855)^(49986396)))+((-1863644960.4202995)>>>((tmp = 1886126804.6019692, tmp)^x)))); - assertEquals(28692, x >>>= ((2561362139.491764)>>(((((tmp = -1347469854.7413375, tmp)/(((x|(x+x))^((x^(tmp = -2737413775.4595394, tmp))^x))<<(((tmp = 225344844.07128417, tmp)&x)&(tmp = 145794498, tmp))))*x)<<(1424529187))/((-2924344715)/(tmp = -2125770148, tmp))))); - assertEquals(-2089419535.2717648, x += (-2089448227.2717648)); - assertEquals(18957929, x ^= (tmp = 2186590872, tmp)); - assertEquals(-708972800, x -= (727930729)); - assertEquals(-4198593, x |= (799483455.1885371)); - assertEquals(-1, x >>= (-2330654693.6413193)); - assertEquals(-1, x |= (((tmp = -116877155, tmp)>>>((((tmp = -1677422314.1333556, tmp)/(tmp = -3108738499.0798397, tmp))%((x&(x/x))%((tmp = -695607185.1561592, tmp)-(tmp = 2302449181.622259, tmp))))^(((-1482743646.5604773)^((897705064)>>>x))-(tmp = -2933836669, tmp))))%(((tmp = -2991584625, tmp)|(((x>>x)+(-1101066835))-x))>>(-33192973.819939613)))); - assertEquals(-1, x &= x); - assertEquals(-524288, x <<= (-1177513101.3087924)); - assertEquals(1978770334.9189441, x += (tmp = 1979294622.9189441, tmp)); - assertEquals(901783582, x &= ((-368584615)^(((((-478030699.2647903)<<x)<<x)+(tmp = 708725752, tmp))^((tmp = -3081556856, tmp)/(tmp = 1149958711.0676727, tmp))))); - assertEquals(-1480333211.8654308, x += (tmp = -2382116793.865431, tmp)); - assertEquals(956930239.6783283, x *= ((tmp = 956930239.6783283, tmp)/x)); - assertEquals(1277610.4668602513, x /= ((tmp = 1571029828, tmp)>>(tmp = 2417481141, tmp))); - assertEquals(-1077333228, x ^= (tmp = 3218755006, tmp)); - assertEquals(-50218, x |= (tmp = -1044436526.6435988, tmp)); - assertEquals(-1, x >>= (-154655245.18921852)); - assertEquals(0.00006276207290978003, x *= (((tmp = 2234286992.9800305, tmp)>>(tmp = 2132564046.0696363, tmp))/((((tmp = -2565534644.3428087, tmp)>>>(tmp = 2622809851.043325, tmp))>>>((tmp = 311277386, tmp)&x))-(tmp = -2003980974, tmp)))); - assertEquals(0, x %= x); - assertEquals(1282114076, x += ((((422838227)>>>((tmp = 1024613366.1899053, tmp)-((368275340)<<(((tmp = -3066121318, tmp)+(-2319101378))&x))))^(x>>(tmp = 1920136319.803412, tmp)))^(1282264803.3968434))); - assertEquals(-277097604, x |= (-283585688.9123297)); - assertEquals(553816692, x &= (x&(tmp = 554082036.676608, tmp))); - assertEquals(658505728, x <<= x); - assertEquals(658505728, x &= (x%(2846071230))); - assertEquals(39, x >>= (334728536.5172192)); - assertEquals(0, x -= x); - assertEquals(0, x += x); - assertEquals(0, x &= (tmp = -335285336, tmp)); - assertEquals(0, x <<= (tmp = 1255594828.3430014, tmp)); - assertEquals(0, x %= (-630772751.1248167)); - assertEquals(NaN, x /= ((((x&(tmp = -1576090612, tmp))%x)>>>x)*((-1038073094.2787619)>>>x))); - assertEquals(NaN, x += x); - assertEquals(NaN, x -= (((tmp = -2663887803, tmp)&((x+(-1402421046))/x))/(-2675654483))); - assertEquals(NaN, x %= (x&(tmp = 672002093, tmp))); - assertEquals(0, x |= x); - assertEquals(-2698925754, x += (tmp = -2698925754, tmp)); - assertEquals(-2057748993, x += ((tmp = -2263466497, tmp)^x)); - assertEquals(1, x /= x); - assertEquals(-2769559719.4045835, x -= (2769559720.4045835)); - assertEquals(-1.3964174646069973, x /= (tmp = 1983332198, tmp)); - assertEquals(-2140716624.3964174, x += (tmp = -2140716623, tmp)); - assertEquals(0, x <<= ((2589073007)-(-816764911.8571186))); - assertEquals(-2837097288.161354, x -= (tmp = 2837097288.161354, tmp)); - assertEquals(-1445059927.161354, x += (tmp = 1392037361, tmp)); - assertEquals(155197984, x &= (tmp = -2694712730.924674, tmp)); - assertEquals(155197984, x |= (x>>>(tmp = 69118015.20305443, tmp))); - assertEquals(155197984, x >>>= (((x^(-1353660241))*x)<<(((((x%(tmp = -1905584634, tmp))>>>(tmp = -860171244.5963638, tmp))&(-1084415001.7039547))+(x-(((tmp = 298064661, tmp)>>x)>>((tmp = 378629912.383446, tmp)-(x%x)))))+(((3212580683)/(((((x^x)>>(tmp = -1502887218, tmp))<<x)%(-142779025))|(((tmp = 1361745708, tmp)*(((((tmp = 1797072528.0673332, tmp)+x)%(tmp = 167297609, tmp))%(-287345856.1791787))^(((((((x*(tmp = -640510459.1514752, tmp))<<(x^(tmp = 1387982082.5646644, tmp)))>>(tmp = 2473373497.467914, tmp))^((234025940)*x))+(tmp = 520098202.9546956, tmp))*(x*(tmp = -362929250.1775775, tmp)))^(-2379972900))))*(tmp = -1385817972, tmp))))+(-1788631834))))); - assertEquals(0, x >>= ((tmp = -18671049, tmp)/((tmp = 651261550.6716013, tmp)>>(-58105114.70740628)))); - assertEquals(0, x *= ((((x>>(tmp = 2256492150.737681, tmp))<<(x<<(((-2738910707)&x)<<(1892428322))))*(tmp = 1547934638, tmp))>>((((319464033.7888391)|(((((tmp = 2705641070, tmp)<<((tmp = 1566904759.36666, tmp)*((-682175559.7540412)&(-691692016.3021002))))%(tmp = 1118101737, tmp))|(902774462))<<x))^((tmp = -388997180, tmp)<<(x<<((((((-88462733)+(x>>>x))%x)*(tmp = -20297481.556210756, tmp))>>>(1927423855.1719701))-((2047811185.6278129)-(tmp = 2952219346.72126, tmp))))))|(-1685518403.7513878)))); - assertEquals(0, x /= (tmp = 1858074757.563318, tmp)); - assertEquals(-1351623058, x ^= (-1351623058.4756806)); - assertEquals(1, x /= x); - assertEquals(0, x ^= x); - assertEquals(0, x -= (x&(997878144.9798675))); - assertEquals(-0, x /= (-2769731277)); - assertEquals(0, x >>>= ((-2598508325)>>(-1355571351))); - assertEquals(0, x >>>= x); - assertEquals(0, x -= (x&(tmp = 1672810223, tmp))); - assertEquals(-924449908.1999881, x -= (924449908.1999881)); - assertEquals(-0, x %= x); - assertEquals(-0, x /= (tmp = 2007131382.059545, tmp)); - assertEquals(-0, x += x); - assertEquals(225132064, x += ((((tmp = -2422670578.1260514, tmp)|x)+x)^(1660142894.7066057))); - assertEquals(Infinity, x /= (x-x)); - assertEquals(0, x ^= x); - assertEquals(0, x <<= x); - assertEquals(-2455424946.732606, x -= (2455424946.732606)); - assertEquals(1208029258, x &= ((tmp = 1823728509, tmp)+x)); - assertEquals(1.3682499724725645, x /= ((((tmp = 1267938464.3854322, tmp)%((tmp = 2510853574, tmp)+(((2979355693.866435)-(tmp = 1989726095.7746763, tmp))<<x)))%((-1382092141.1627176)+(((-901799353)+((-2936414080.8254457)>>>(2515004943.0865674)))-(2532799222.353197))))<<(tmp = -2168058960.2694826, tmp))); - assertEquals(0.13799826710735907, x %= ((-1090423235)/(tmp = 2659024727, tmp))); - assertEquals(0, x >>= (1688542889.082693)); - assertEquals(0, x <<= x); - assertEquals(NaN, x %= ((((tmp = 1461037539, tmp)<<((x<<(tmp = 2101282906.5302017, tmp))>>(-2792197742)))%(((x%x)^(((tmp = 1399565526, tmp)^(tmp = 643902, tmp))-((tmp = -1449543738, tmp)|x)))/x))*(x<<(471967867)))); - assertEquals(0, x &= ((tmp = -2121748100.6824129, tmp)>>(tmp = -2817271480.6497793, tmp))); - assertEquals(0, x &= (3169130964.6291866)); - assertEquals(-0, x /= (-2303316806)); - assertEquals(0, x <<= (tmp = 120185946.51617038, tmp)); - assertEquals(449448375, x ^= ((((tmp = -836410266.014014, tmp)/x)&((x>>>(tmp = -2602671283, tmp))+x))+(tmp = 449448375, tmp))); - assertEquals(202003841790140640, x *= x); - assertEquals(202003840800829020, x += (((tmp = -1339865843, tmp)+(tmp = 350554234.15375435, tmp))<<((((((tmp = -1798499687.8208885, tmp)>>(((x-(x^x))|((tmp = 463627396.23932934, tmp)/(2714928060)))&(tmp = 3048222568.1103754, tmp)))&(-3127578553))<<(tmp = -2569797028.8299003, tmp))&x)<<((tmp = 2104393646, tmp)/((tmp = 2314471015.742891, tmp)<<((2704090554.1746845)>>(((tmp = 1935999696, tmp)*(((1348554815)>>>x)>>>(146665093.82445252)))%x))))))); - assertEquals(202003841764125400, x -= (tmp = -963296372.2846234, tmp)); - assertEquals(-413485056, x <<= (tmp = -2474480506.6054573, tmp)); - assertEquals(-3171894580.186845, x += ((tmp = -1261111102, tmp)+(tmp = -1497298422.1868448, tmp))); - assertEquals(17136, x >>= (tmp = 3055058160, tmp)); - assertEquals(17136, x %= (tmp = 1706784063.3577294, tmp)); - assertEquals(17136, x >>= ((tmp = 2161213808, tmp)*x)); - assertEquals(-17136, x /= ((((tmp = -1492618154, tmp)>>x)|(1381949066))>>(tmp = 2014457960, tmp))); - assertEquals(-34272, x += x); - assertEquals(-1498690902, x += (-1498656630)); - assertEquals(-1168674482, x ^= (486325220)); - assertEquals(-1168674482, x <<= ((x^x)*x)); - assertEquals(794521557347068000, x *= (-679848469)); - assertEquals(1.3330392590424505e+26, x *= (tmp = 167778866, tmp)); - assertEquals(0, x <<= (tmp = -2501540637.3664584, tmp)); - assertEquals(0, x >>>= (x-(x*(-890638026.1825848)))); - assertEquals(0, x %= ((-285010538.2813468)&(1314684460.7634423))); - assertEquals(0, x -= x); - assertEquals(0, x *= x); - assertEquals(NaN, x %= (x*(x<<x))); - assertEquals(NaN, x %= (x<<(((tmp = -1763171810.601149, tmp)&(-138151449.18303752))^(x|x)))); - assertEquals(0, x |= (x>>x)); - assertEquals(0, x &= (tmp = 1107152048, tmp)); - assertEquals(0, x >>= (1489117056.8200984)); - assertEquals(518749976, x ^= (518749976.20107937)); - assertEquals(356718654, x += (tmp = -162031322, tmp)); - assertEquals(356718654, x %= (((x>>>((tmp = -373747439.09634733, tmp)*(tmp = 563665566, tmp)))*(tmp = 2853322586.588251, tmp))*((1303537213)%(-2995314284)))); - assertEquals(5573728, x >>= (tmp = -2095997978, tmp)); - assertEquals(5573728, x <<= x); - assertEquals(5573728, x >>= (((((tmp = 1745399178.334154, tmp)<<(tmp = 2647999783.8219824, tmp))^(tmp = 1571286759, tmp))%x)/(2166250345.181711))); - assertEquals(10886, x >>>= ((682837289)+(x*x))); - assertEquals(170, x >>>= x); - assertEquals(169.95167497151652, x -= (((tmp = 527356024.19706845, tmp)+((tmp = 1263164619.2954736, tmp)|(tmp = 2942471886, tmp)))/((3017909419.131321)+(tmp = 2137746252.8006272, tmp)))); - assertEquals(-1915170061, x ^= (tmp = -1915170214, tmp)); - assertEquals(206045792, x &= (((tmp = 887031922, tmp)>>>x)-((-1861922770)|(9633541)))); - assertEquals(-1940321674, x |= (tmp = -2012149162.1817405, tmp)); - assertEquals(-1940321674, x &= x); - assertEquals(1128412272.160699, x += (tmp = 3068733946.160699, tmp)); - assertEquals(0.47486363523180236, x /= (tmp = 2376286976.807289, tmp)); - assertEquals(-1.4931079540252477e-10, x /= (tmp = -3180370407.5892467, tmp)); - assertEquals(0, x |= (((1220765170.5933602)*(884017786))*((x%(tmp = -2538196897.226384, tmp))<<(x^x)))); - assertEquals(-525529894, x += (tmp = -525529894, tmp)); - assertEquals(1621426184, x &= ((3046517714)*(((((-162481040.8033898)+(x/((x&(1489724492))/((x|(tmp = 943542303, tmp))>>>((-1840491388.1365871)<<(2338177232))))))+(((-2268887573.2430763)>>>(((tmp = 2919141667, tmp)+((tmp = 1326295559.692003, tmp)<<(-2256653815)))>>>(((((tmp = 1602731976.7514615, tmp)*(856036244.3730336))^x)>>>((((2846316421.252943)&(915324162))%(tmp = 1144577211.0221815, tmp))%x))*(x*x))))%(tmp = -2641416560, tmp)))*(x+(x>>>x)))>>x))); - assertEquals(1621426184, x %= (tmp = 1898223948, tmp)); - assertEquals(-3.383396676504762, x /= ((tmp = 2211088034.5234556, tmp)^x)); - assertEquals(7120923705.122882, x *= (((((tmp = 2632382342.914504, tmp)/(-615440284.1762738))&(2162453853.6658797))<<(-849038082.5298986))|(tmp = -2104667110.5603983, tmp))); - assertEquals(-1469010887, x &= x); - assertEquals(850767635866964700, x *= (tmp = -579143179.5338116, tmp)); - assertEquals(0, x %= x); - assertEquals(-571457, x |= ((2849326490.8464212)|(tmp = 1450592063, tmp))); - assertEquals(-571457, x &= x); - assertEquals(-0.00018638416434019244, x /= (3066016912.021368)); - assertEquals(0, x <<= (2058262829)); - assertEquals(NaN, x %= ((x|((x%x)>>>x))%((tmp = -2970314895.6974382, tmp)+x))); - assertEquals(NaN, x *= (-698693934.9483855)); - assertEquals(NaN, x += (-100150720.64391875)); - assertEquals(NaN, x %= x); - assertEquals(NaN, x -= (-530301478)); - assertEquals(NaN, x /= (1507673244)); - assertEquals(0, x <<= (x%(tmp = 2977838420.857235, tmp))); - assertEquals(0, x <<= (tmp = 3200877763, tmp)); - assertEquals(0, x <<= (tmp = -2592127060, tmp)); - assertEquals(NaN, x -= (((((((1930632619)*(3018666359))<<((tmp = 2676511886, tmp)&(-2786714482.25468)))%x)-(-633193192))<<((tmp = 403293598, tmp)*(-2765170226)))%x)); - assertEquals(530062092, x |= (tmp = 530062092, tmp)); - assertEquals(129409, x >>>= x); - assertEquals(-152430382316341.78, x *= (-1177896300.229055)); - assertEquals(-304860764632683.56, x += x); - assertEquals(0, x ^= x); - assertEquals(0, x %= (tmp = -63071565.367660046, tmp)); - assertEquals(0, x &= ((((tmp = -1007464338, tmp)<<(x<<((x^(tmp = -726826835, tmp))|x)))>>>x)*(((tmp = 469293335.9161849, tmp)<<(((((tmp = 1035077379, tmp)*(tmp = -555174353.7567515, tmp))&(3109222796.8286266))-(((((x-(tmp = 1128900353.6650414, tmp))|(tmp = 3119921303, tmp))&((-1353827690)&(x%((-924615958)&x))))>>>x)+(tmp = 1167787910, tmp)))+x))%((605363594)>>(1784370958.269381))))); - assertEquals(0, x %= (2953812835.9781704)); - assertEquals(0, x -= x); - assertEquals(0, x <<= x); - assertEquals(-901209266, x += (-901209266)); - assertEquals(-901209266, x &= x); - assertEquals(404, x >>>= (-3195686249)); - assertEquals(824237108, x ^= (824237472)); - assertEquals(497790936.1853996, x /= ((tmp = 1253776028, tmp)/(757207285))); - assertEquals(497790936, x >>>= ((tmp = -2212598336, tmp)<<(x^(1335355792.9363852)))); - assertEquals(0, x %= x); - assertEquals(-2659887352.6415873, x += (tmp = -2659887352.6415873, tmp)); - assertEquals(1635079945, x |= ((x&(1234659380))>>((((tmp = 2694276886.979136, tmp)|x)^((tmp = 132795582, tmp)<<((-1089828902)>>>x)))<<((((tmp = -2098728613.0310376, tmp)<<(x/(tmp = -2253865599, tmp)))*((x+(x>>>((48633053.82579231)-(385301592))))*(tmp = -1847454853.333535, tmp)))/((-540428068.8583717)+x))))); - assertEquals(1, x /= x); - assertEquals(33554432, x <<= ((((2803140769)<<x)|(tmp = -1965793804, tmp))>>>(tmp = -2273336965.575082, tmp))); - assertEquals(67108864, x += x); - assertEquals(9007199254740992, x *= (x+((x>>x)%(2674760854)))); - assertEquals(55369784, x %= (x|(-170725544.20038843))); - assertEquals(55369784, x %= (-1186186787)); - assertEquals(0, x ^= x); - assertEquals(0, x <<= x); - assertEquals(NaN, x /= ((-2968110098)-((x/(x|(((((x|((x&((-130329882)>>>(((-135670650)|(x<<(tmp = 1280371822, tmp)))^x)))-(-1183024707.2230911)))&(-1072829280))>>>(-340696948.41492534))>>>(tmp = 436308526.4938295, tmp))<<(((tmp = 3113787500, tmp)*((2038309320)>>>(-1818917055)))&((2808000707)/(774731251))))))%x))); - assertEquals(0, x |= (x*(tmp = -843074864, tmp))); - assertEquals(0, x &= (tmp = -752261173.8090212, tmp)); - assertEquals(0, x >>>= (tmp = 1532349931.7517128, tmp)); - assertEquals(0, x <<= ((tmp = -8628768, tmp)-((((tmp = 225928543, tmp)%(x>>>(x+x)))^((tmp = -2051536806.5249376, tmp)-x))-((tmp = -2274310376.9964137, tmp)%(tmp = 2251342739, tmp))))); - assertEquals(0, x >>= (1011388449)); - assertEquals(0, x += x); - assertEquals(0, x >>>= x); - assertEquals(-0, x *= ((-1781234179.8663826)>>(((1514201119.9761915)>>(((((1174857164.90042)^(tmp = 1124973934, tmp))^x)+((-1059246013.8834443)<<(2997611138.4876065)))%(((798188010)*(-1428293122))>>>(tmp = -3087267036.8035297, tmp))))<<x))); - assertEquals(1752554372, x ^= (tmp = -2542412924, tmp)); - assertEquals(1752554372, x %= (tmp = 3037553410.2298307, tmp)); - assertEquals(1859383977, x -= (x^(2446603103))); - assertEquals(1183048193, x &= ((tmp = -962336957, tmp)/(x/x))); - assertEquals(67738157, x %= ((((tmp = -1813911745.5223546, tmp)+x)<<(x-(((-1980179168)^x)|x)))|(1913769561.1308007))); - assertEquals(67698724, x &= ((1801574998.3142045)*((tmp = -2057492249, tmp)/((1713854494.72282)>>x)))); - assertEquals(0, x -= x); - assertEquals(-25232836, x -= ((tmp = 25232836, tmp)|x)); - assertEquals(-49, x >>= (x+((tmp = 2201204630.2897243, tmp)|(-1929326509)))); - assertEquals(-1605632, x <<= x); - assertEquals(-165965313, x += (tmp = -164359681, tmp)); - assertEquals(9.220413724941365e-10, x /= (((((tmp = 2579760013.0808706, tmp)*(tmp = -2535370639.9805303, tmp))>>((tmp = 2138199747.0301933, tmp)-(tmp = -2698019325.0972376, tmp)))*(tmp = -425284716, tmp))/((-1951538149.6611228)/(x^(2632919130))))); - assertEquals(0, x &= x); - assertEquals(0, x &= ((-645189137)/(tmp = 800952748, tmp))); - assertEquals(0, x &= (tmp = -1773606925, tmp)); - assertEquals(0, x += x); - assertEquals(0, x >>>= (tmp = 211399355.0741787, tmp)); - assertEquals(0, x <<= ((-1317040231.5737965)/((((((tmp = 838897586.0147077, tmp)|((-1902447594)|(tmp = 404942728.83034873, tmp)))^(2462760692.2907705))%((((((x%(tmp = -2888980287, tmp))<<(-368505224.49609876))-((x>>>(532513369))&(((((((tmp = -1298067543, tmp)^(tmp = -3130435881.100909, tmp))>>x)/(tmp = -3041161992, tmp))>>(x|(-431685991.95776653)))^((tmp = 1031777777, tmp)^((-105610810)>>>((-631433779)>>(tmp = -2577780871.167671, tmp)))))%(tmp = -3170517650.088039, tmp))))-(((tmp = 2175146237.968785, tmp)-((384631158.50508535)>>((893912279.4646157)|(tmp = -1478803924.5338967, tmp))))%(x/(-1089156420))))<<(tmp = -2024709456, tmp))>>x))*(tmp = -1423824994.6993582, tmp))%(tmp = 1739143409, tmp)))); - assertEquals(-1799353648, x |= ((-1799353648.3589036)>>>((((x&(-923571640.1012449))%x)+((tmp = 971885508, tmp)>>((tmp = -2207464428.2123804, tmp)+(-3108177894.0459776))))-(-2048954486.7014258)))); - assertEquals(-3666808032.2958965, x -= (tmp = 1867454384.2958965, tmp)); - assertEquals(-260069478915415100, x *= (tmp = 70925305.23136711, tmp)); - assertEquals(1142096768, x &= (tmp = 1866401706.9144325, tmp)); - assertEquals(1, x >>>= (tmp = 2701377150.5717473, tmp)); - assertEquals(1865946805, x |= (tmp = -2429020492, tmp)); - assertEquals(1424222287, x ^= ((((tmp = 433781338, tmp)>>(x>>>((-2914418422.4829016)/(tmp = 1600920669, tmp))))|(tmp = 588320482.9566053, tmp))>>>((((((x+(tmp = -2556387365.5071325, tmp))+(tmp = -2381889946.1830974, tmp))/(3154278191))>>>(-1069701268.8022757))>>(((tmp = 182049089.28866422, tmp)>>x)>>>(tmp = -447146173, tmp)))/(x-(2103883357.0929923))))); - assertEquals(0, x ^= x); - assertEquals(0, x -= (x%(3036884806))); - assertEquals(0, x >>>= (tmp = -652793480.3870945, tmp)); - assertEquals(0, x += x); - assertEquals(304031003, x ^= ((tmp = -900156495, tmp)^(-666397014.0711515))); - assertEquals(1, x /= x); - assertEquals(-1974501681, x |= (x^(-1974501681.4628205))); - assertEquals(-1.3089278317616264, x /= (((-1723703186.962839)>>>x)|((2061022161.6239533)<<x))); - assertEquals(-1, x |= (tmp = -1987006457, tmp)); - assertEquals(-0.14285714285714285, x /= ((((((x|(-1767793799.7595732))-(-1391656680))<<x)|(x>>(tmp = -2301588485.2811003, tmp)))>>>(((tmp = 1812723993, tmp)>>>((x^(((tmp = -3154100157.951021, tmp)%((tmp = -1254955564.4553523, tmp)-(((x>>>(((-1762886343)*x)*x))*(x^(x*(-750918563.4387553))))*x)))|((x>>x)>>(x<<((((-1766797454.5634143)^(tmp = -2251474340, tmp))-(-787637516.5276759))<<((1390653368)^(-1937605249.245374)))))))|(((tmp = 1156611894, tmp)<<x)<<(x>>((((x+(tmp = 2170166060.881797, tmp))&(x>>>(tmp = -1749295923.1498983, tmp)))>>(((-1014973878)|x)&(1302866805.684057)))*(tmp = 560439074.4002491, tmp))))))|(-2758270803.4510045)))&x)); - assertEquals(0, x |= x); - assertEquals(0, x += ((x>>((x+(tmp = -2776680860.870219, tmp))-(((688502468)<<(((tmp = 475364260.57888806, tmp)<<x)+(329071671)))/(-1097134948))))*(tmp = -1281834214.3416953, tmp))); - assertEquals(0, x *= ((((1159762330)<<(tmp = -1892429200, tmp))%x)<<x)); - assertEquals(0, x >>>= (-770595225)); - assertEquals(NaN, x += (((x>>x)/(tmp = 281621135, tmp))/x)); - assertEquals(0, x >>= (1363890241)); - assertEquals(1639023942.9945002, x += (1639023942.9945002)); - assertEquals(-2568590958567747000, x *= (-1567146697)); - assertEquals(1793554700, x ^= (tmp = 3215813388.405799, tmp)); - assertEquals(437879, x >>= x); - assertEquals(1339485943, x |= (1339220210)); - assertEquals(1, x /= x); - assertEquals(512, x <<= (2509226729.1477118)); - assertEquals(512, x <<= ((x>>(1326274040.7181284))<<(tmp = -760670199, tmp))); - assertEquals(1, x /= (x<<(x^x))); - assertEquals(0, x >>>= (((((1382512625.8298302)&(x>>>x))*(tmp = -815316595, tmp))>>>x)-(-95538051))); - assertEquals(-544344229.3548596, x -= (tmp = 544344229.3548596, tmp)); - assertEquals(-1088688458.7097192, x += x); - assertEquals(-1022850479579041900, x *= (939525418.3104812)); - assertEquals(2069622661, x |= (-2632744187.7721186)); - assertEquals(-1353480538017756400, x -= ((tmp = 1308085980, tmp)*((x>>>(-629663391.5165792))&(tmp = 3182319856.674114, tmp)))); - assertEquals(1.3702811563654176e+27, x *= ((((3061414617.6321163)/(tmp = 2628865442, tmp))+(-1549548261))+(x&((tmp = 809684398, tmp)|(x^(tmp = 801765002, tmp)))))); - assertEquals(0, x >>>= ((-2988504159)&((tmp = -260444190.02252054, tmp)^(2178729442.260293)))); - assertEquals(-1518607002, x -= (tmp = 1518607002, tmp)); - assertEquals(724566016, x <<= (tmp = 1042915731.7055794, tmp)); - assertEquals(707584, x >>>= (-208959862.93305588)); - assertEquals(0, x >>>= (((tmp = 877181764, tmp)>>(-970697753.3318911))%x)); - assertEquals(0, x ^= x); - assertEquals(0, x += x); - assertEquals(0, x <<= x); - assertEquals(0, x /= (x^((x/(-2903618412.4936123))+(tmp = 1169288899, tmp)))); - assertEquals(0, x >>>= x); - assertEquals(-1302645245, x ^= ((1855892732.3544865)+(tmp = 1136429319.5633948, tmp))); - assertEquals(0, x ^= x); - assertEquals(0, x &= (-1384534597.409375)); - assertEquals(-0, x /= (tmp = -680466419.8289509, tmp)); - assertEquals(-0, x *= (318728599.95017374)); - assertEquals(NaN, x %= (x>>(2019695267))); - assertEquals(0, x >>= (tmp = 1280789995, tmp)); - assertEquals(0, x *= (tmp = 2336951458, tmp)); - assertEquals(0, x >>= ((2981466013.758637)%(731947033))); - assertEquals(0, x -= x); - assertEquals(0, x ^= x); - assertEquals(0, x /= ((((3068070149.1452317)>>x)%(((1448965452)*((tmp = -2961594129, tmp)+(1829082104.0681171)))>>(-2331499703)))>>>(tmp = -3206314941.2626476, tmp))); - assertEquals(0, x >>= (x%(1869217101.9823673))); - assertEquals(0, x <<= (x+x)); - assertEquals(0, x >>>= ((1202130282)>>>x)); - assertEquals(0, x += x); - assertEquals(2603245248.6273212, x += (tmp = 2603245248.6273212, tmp)); - assertEquals(-1691864471, x ^= (x>>>(2504513614.117516))); - assertEquals(136835305, x -= ((-1618979896)&(-746953306))); - assertEquals(-2568499564.1261334, x += (tmp = -2705334869.1261334, tmp)); - assertEquals(1038075700, x ^= (1530399136)); - assertEquals(2076151400, x += x); - assertEquals(-524018410.1751909, x -= ((2398973627.175191)-(-201196183))); - assertEquals(0.327110599608614, x /= ((3181340288.602796)&x)); - assertEquals(0.327110599608614, x %= (tmp = -2284484060, tmp)); - assertEquals(0, x |= x); - assertEquals(403217947.5779772, x += (tmp = 403217947.5779772, tmp)); - assertEquals(403217947, x |= x); - assertEquals(-Infinity, x *= ((58693583.845808744)+(((tmp = -1527787016, tmp)*x)/((((2532689893.3191843)/(tmp = 2781746479.850424, tmp))|(((((460850355.9211761)/((((tmp = 626683450, tmp)<<((tmp = 1349974710, tmp)-((tmp = -1349602292, tmp)/(-2199808871.1229663))))>>((x/(-3092436372.3078623))&(tmp = -1190631012.0323825, tmp)))^((-2907082828.4552956)-(tmp = 1858683340.1157017, tmp))))^(-1513755598.5398848))%x)/x))&(1147739260.136806))))); - assertEquals(0, x &= (tmp = -3047356844.109563, tmp)); - assertEquals(637934616, x -= (tmp = -637934616, tmp)); - assertEquals(-1553350083, x ^= (-2056266203.094929)); - assertEquals(-0.13467351026547192, x %= ((tmp = 824736251, tmp)/(2544186314))); - assertEquals(1, x /= x); - assertEquals(1, x |= x); - assertEquals(0, x >>>= (2166609431.9515543)); - assertEquals(0, x <<= (x|(tmp = 121899222.14603412, tmp))); - assertEquals(0, x *= (1300447849.6595674)); - assertEquals(0, x %= (tmp = -2360500865.3944597, tmp)); - assertEquals(0, x %= (tmp = -1693401247, tmp)); - assertEquals(0, x >>= x); - assertEquals(0, x /= (471265307)); - assertEquals(257349748, x ^= (257349748.689448)); - assertEquals(257349748, x &= x); - assertEquals(981, x >>>= (tmp = -1959001422, tmp)); - assertEquals(0, x >>= ((-79932778.18114972)/x)); - assertEquals(0, x <<= (((-2599621472)^(tmp = 662071103, tmp))%(tmp = -2675822640.7641535, tmp))); - assertEquals(0, x &= (tmp = 2582354953.878623, tmp)); - assertEquals(0, x /= ((-953254484)/((-2571632163.376176)-(tmp = -342034471, tmp)))); - assertEquals(0, x <<= ((x-(tmp = -3013057672, tmp))&(tmp = -3204761036, tmp))); - assertEquals(0, x ^= ((x&((515934453)>>>x))/x)); - assertEquals(1, x |= ((-1914707646.2075093)>>>(tmp = -1918045025, tmp))); - assertEquals(-2002844120.8792589, x += (tmp = -2002844121.8792589, tmp)); - assertEquals(573030794, x >>>= (tmp = 1707788162, tmp)); - assertEquals(1.917619109627369, x /= ((1909436830.484202)%((123114323)<<(tmp = -1288988388.6444468, tmp)))); - assertEquals(-1400358045, x |= (-1400358046)); - assertEquals(-2043022529.4273133, x += (tmp = -642664484.4273133, tmp)); - assertEquals(-81408068.86728716, x %= (tmp = -980807230.2800131, tmp)); - assertEquals(0.1436896445024992, x /= (((tmp = 3201789924.913518, tmp)%(tmp = -962242528.6008646, tmp))^((tmp = -338830119.55884504, tmp)*(tmp = -916120166, tmp)))); - assertEquals(0.1436896445024992, x %= (tmp = 2598469263, tmp)); - assertEquals(0, x *= (x-x)); - assertEquals(-1409286144, x += (((-111514798.64745283)|(2372059654))<<(tmp = 175644313, tmp))); - assertEquals(-2393905467.0073113, x += (-984619323.0073113)); - assertEquals(-835111172.0073113, x %= (x^(-765900532.5585573))); - assertEquals(-835111172.0073113, x %= (tmp = -946478116, tmp)); - assertEquals(-100, x >>= ((-1020515908)>>(((x&((x^(169474253.53811646))>>(-221739002)))+x)*((201939882.92880356)/(tmp = -50402570, tmp))))); - assertEquals(2131506964, x &= (tmp = -2163460268, tmp)); - assertEquals(1074275840, x &= ((-1561930379.8719592)*(tmp = -2871750052.876917, tmp))); - assertEquals(-954232605.5377102, x -= (tmp = 2028508445.5377102, tmp)); - assertEquals(-29, x >>= (-279577351.87217045)); - assertEquals(-232, x <<= x); - assertEquals(-70, x |= (215185578)); - assertEquals(-1, x >>= (x>>(-1691303095))); - assertEquals(1, x /= x); - assertEquals(3149465364.2236686, x *= (3149465364.2236686)); - assertEquals(3304787832.3790073, x += (tmp = 155322468.15533853, tmp)); - assertEquals(100068712.23500109, x %= (tmp = 3204719120.1440063, tmp)); - assertEquals(91628864, x &= (tmp = 629090241, tmp)); - assertEquals(-113202292046379710, x *= (-1235443583)); - assertEquals(122, x >>>= (tmp = 3196555256, tmp)); - assertEquals(122, x >>>= (((2226535734)-x)^(2248399036.393125))); - assertEquals(6.904199169070746e-8, x /= (tmp = 1767040564.9149356, tmp)); - assertEquals(-212687449.99999994, x += ((((2244322375)*(((2515994102)^x)>>x))<<(x-(-832407685.3251972)))^(2266670502))); - assertEquals(366515938514778750, x *= (tmp = -1723260768.3940866, tmp)); - assertEquals(366515938514778750, x += ((-1643386193.9159095)/(tmp = 425161225.95316494, tmp))); - assertEquals(654872716.4123061, x /= ((-1377382984)-(tmp = -1937058061.811642, tmp))); - assertEquals(654872716, x &= x); - assertEquals(-86260926.17813063, x -= (tmp = 741133642.1781306, tmp)); - assertEquals(1052176592, x >>>= x); - assertEquals(2020882856, x ^= (-3107796616)); - assertEquals(0, x <<= ((606939871.9812952)|(tmp = -3127138319.1557302, tmp))); - assertEquals(NaN, x -= ((x%((1120711400.2242608)%x))*(tmp = -930171286.7999947, tmp))); - assertEquals(NaN, x %= (3215044180)); - assertEquals(NaN, x %= (tmp = 2882893804.20102, tmp)); - assertEquals(NaN, x %= ((217170359.5778643)^x)); - assertEquals(0, x &= ((-1095125960.9903677)>>(x^(-2227981276)))); - assertEquals(-748549860, x += (-748549860)); - assertEquals(1816208256, x <<= (-610872411.3826082)); - assertEquals(201400576, x &= (((tmp = 1910394603.4836266, tmp)<<x)^x)); - assertEquals(0, x %= x); - assertEquals(NaN, x %= x); - assertEquals(0, x <<= (((((2670901339.6696005)%(2180020861))*((2134469504)/(2237096063.0680027)))*((tmp = 1203829756, tmp)>>((765467065)+(x|(2673651811.9494815)))))<<((-1463378514)|(((x/(tmp = -1075050081, tmp))-((-879974865)+x))>>>(tmp = 2172883926, tmp))))); - assertEquals(433013198, x ^= (433013198.2833413)); - assertEquals(0, x >>= ((((-2404431196)%(x%(tmp = 1443152875.8809233, tmp)))&(x|((1414364997.0517852)/((tmp = -435854369, tmp)+(tmp = 2737625141, tmp)))))|(((tmp = 2241746562.2197237, tmp)^(tmp = -1606928010.1992552, tmp))|((tmp = -3083227418.686173, tmp)>>(tmp = -2717460410, tmp))))); - assertEquals(0, x >>= x); - assertEquals(0, x *= ((tmp = 2302521322, tmp)>>>(((((((tmp = 344089066.9725498, tmp)%(tmp = 1765830559, tmp))-x)|x)^(((-2450263325)/(tmp = 371928405.17475057, tmp))>>>(1330100413.7731652)))^(((173024329)%(tmp = -2927276187, tmp))+(x>>>(-1042229940.308507))))|(((((tmp = 379074096, tmp)+((142762508)-((-2773070834.526266)-(x&((tmp = 57957493, tmp)<<(2189553500))))))+((36991093)+(tmp = 339487168.58069587, tmp)))*(-1257565451))&(tmp = 645233114, tmp))))); - assertEquals(-2644503151.1185284, x += (-2644503151.1185284)); - assertEquals(-5289006302.237057, x += x); - assertEquals(-4008773824.2370567, x -= (tmp = -1280232478, tmp)); - assertEquals(1975449413, x |= ((tmp = 1957832005.4285066, tmp)>>((1681236712.9715524)&(-675823978)))); - assertEquals(-146472960, x <<= (-648510672.5644083)); - assertEquals(-3, x |= (((((x>>>(tmp = 2271744104, tmp))+(tmp = -210058133.30147195, tmp))+(tmp = -2827493425, tmp))/(tmp = 765962538, tmp))%(tmp = 1048631551, tmp))); - assertEquals(1, x /= x); - assertEquals(0, x >>= (1070524782.5154183)); - assertEquals(0, x <<= (462502504)); - assertEquals(0, x %= (540589670.0730014)); - assertEquals(NaN, x %= x); - assertEquals(NaN, x /= ((-1268640098)%x)); - assertEquals(NaN, x %= (1741157613.744652)); - assertEquals(NaN, x += x); - assertEquals(NaN, x %= ((x|(tmp = 1992323492.7000637, tmp))*x)); - assertEquals(NaN, x /= ((tmp = -2271503368.0341196, tmp)>>((tmp = 1224449194, tmp)>>>(tmp = 2976803997, tmp)))); - assertEquals(NaN, x += (tmp = -1078313742.1633894, tmp)); - assertEquals(NaN, x += (-787923311)); - assertEquals(NaN, x %= x); - assertEquals(-1299878219, x ^= (2995089077)); - assertEquals(536887953, x &= ((625660571.2651105)&(x^(((tmp = 950150725.2319129, tmp)+(-2122154205.466675))/(tmp = 1754964696.974752, tmp))))); - assertEquals(4096, x >>>= x); - assertEquals(1, x /= x); - assertEquals(-82508517, x ^= (((-930231800)%(tmp = -423861640.4356506, tmp))+x)); - assertEquals(-82508517, x &= (x&x)); - assertEquals(-479519, x %= ((tmp = 1861364600.595756, tmp)|x)); - assertEquals(479518, x ^= (((x>>(-1539139751.6860313))>>(tmp = -456165734, tmp))|(-2786433531))); - assertEquals(959036, x += x); - assertEquals(29, x >>>= ((tmp = -1049329009.7632706, tmp)^(((((((1117739997)/(((-841179741.4939663)*(-1211599672))>>>((-413696355)%(tmp = -1753423217.2170188, tmp))))<<(tmp = 1599076219.09274, tmp))>>>(-1382960317))^(((x^(tmp = 515115394, tmp))>>>(tmp = -388476217, tmp))>>>(x/x)))^x)<<(136327532.213817)))); - assertEquals(24, x &= (2388755418)); - assertEquals(0, x >>>= (tmp = -405535917, tmp)); - assertEquals(0, x &= (tmp = -1427139674, tmp)); - assertEquals(NaN, x /= (x^((1530470340)%x))); - assertEquals(0, x |= ((x>>(-1429690909.8472774))*((((tmp = 2033516515, tmp)/(1314782862))>>>x)>>(tmp = 1737186497.6441216, tmp)))); - assertEquals(0, x -= x); - assertEquals(0, x %= (3115422786)); - assertEquals(-0, x *= (x+(tmp = -2558930842.267017, tmp))); - assertEquals(NaN, x %= x); - assertEquals(0, x &= (2695531252.254449)); - assertEquals(-613178182, x ^= (-613178182)); - assertEquals(54, x >>>= (x%(((tmp = 2277868389, tmp)^((((tmp = -1143932265.3616111, tmp)^((x&((x-((-2100384445.7850044)|(tmp = 908075129.3456883, tmp)))*x))+(((tmp = 1031013284.0275401, tmp)*((((tmp = -233393205, tmp)>>>(tmp = -111859419, tmp))*(-1199307178))|(tmp = -1998399599, tmp)))>>>((((-731759641.9036775)>>>(tmp = 2147849691, tmp))>>>(tmp = -2121899736, tmp))>>>(x>>>x)))))>>((1900348757.360562)^(tmp = 2726336203.6149445, tmp)))>>>((x*((tmp = -2697628471.0234947, tmp)%((x^(tmp = -2751379613.9474974, tmp))*x)))+(x>>(tmp = 42868998.384643435, tmp)))))+(598988941)))); - assertEquals(34, x &= ((tmp = 2736218794.4991407, tmp)%(2169273288.1339874))); - assertEquals(2.086197133417468, x /= ((tmp = 2176358852.297597, tmp)%x)); - assertEquals(2, x <<= (((tmp = -1767330075, tmp)|(-3107230779.8512735))&x)); - assertEquals(4194304, x <<= (tmp = 1061841749.105744, tmp)); - assertEquals(48609515, x ^= (44415211.320786595)); - assertEquals(48609515, x %= (1308576139)); - assertEquals(23735, x >>>= ((-324667786)-x)); - assertEquals(23735, x <<= ((-1270911229)<<(((((tmp = -882992909.2692418, tmp)+(tmp = 394833767.947718, tmp))-x)<<(702856751))/x))); - assertEquals(-31080872939240, x *= (tmp = -1309495384, tmp)); - assertEquals(-14625.31935626114, x /= ((668084131)+(1457057357))); - assertEquals(-14625.31935626114, x %= (266351304.6585492)); - assertEquals(-12577, x |= (-945583977.619837)); - assertEquals(-4097, x |= ((tmp = -2621808583.2322493, tmp)-(tmp = -2219802863.9072213, tmp))); - assertEquals(-1004843865, x &= ((-1004839768)+((tmp = 2094772311, tmp)/(-1340720370.275643)))); - assertEquals(-31401371, x >>= ((2035921047)>>>((tmp = -1756995278, tmp)>>>(-537713689)))); - assertEquals(1791746374.016472, x -= ((tmp = -1823147745, tmp)-(x/(tmp = -1906333520, tmp)))); - assertEquals(3.7289343120517406, x /= (tmp = 480498240, tmp)); - assertEquals(7.457868624103481, x += x); - assertEquals(234881024, x <<= (-781128807.2532628)); - assertEquals(67108864, x &= (tmp = -2060391332, tmp)); - assertEquals(-605958718, x -= (673067582)); - assertEquals(-605958718, x <<= ((x%x)&((tmp = 1350579401.0801518, tmp)|x))); - assertEquals(-109268090.4715271, x %= (tmp = -496690627.5284729, tmp)); - assertEquals(-109268090, x <<= (((-2004197436.8023896)%((x|((tmp = 271117765.61283946, tmp)-((1595775845.0754795)*(555248692.2512416))))/x))<<x)); - assertEquals(-652725370, x &= (-543590449)); - assertEquals(0.321858133298825, x /= (tmp = -2027990914.2267523, tmp)); - assertEquals(1959498446, x ^= (1959498446)); - assertEquals(1959498446, x &= (x%(tmp = 3155552362.973523, tmp))); - assertEquals(14949, x >>>= ((tmp = 586618136, tmp)>>>(tmp = 699144121.9458897, tmp))); - assertEquals(-28611391568319.285, x *= (tmp = -1913933478.3811147, tmp)); - assertEquals(1680557633, x &= (((tmp = 2606436319.199714, tmp)<<(1575299025.6917372))|((-1092689109)/(735420388)))); - assertEquals(1680361024, x &= ((tmp = 1860756552.2186172, tmp)|(-360434860.1699109))); - assertEquals(820488, x >>>= (1788658731)); - assertEquals(820488, x >>= (-1555444352)); - assertEquals(2104296413, x ^= (2103543509)); - assertEquals(16843328, x &= ((x<<((-2920883149)/(1299091676)))-(((((tmp = 3199460211, tmp)+(-237287821.61504316))&(tmp = -1524515028.3596857, tmp))-(tmp = -700644414.6785603, tmp))+(-180715428.86124516)))); - assertEquals(1326969834, x |= (tmp = -2968063574.793867, tmp)); - assertEquals(0, x %= (x>>>(tmp = 1350490461.0012388, tmp))); - assertEquals(0, x &= ((-2620439260.902854)+x)); - assertEquals(-1775533561, x |= ((-1775533561)|(((x>>>((861896808.2264911)>>>(970216466.6532537)))%x)%(tmp = 2007357223.8893046, tmp)))); - assertEquals(-1775533561, x &= x); - assertEquals(-23058877.415584415, x /= ((tmp = -3002439857, tmp)>>((((x-(tmp = 1583620685.137125, tmp))|x)%(-2568798248.6863875))^x))); - assertEquals(-577.4155844151974, x %= (((-1440361053.047877)+((tmp = 821546785.0910633, tmp)-(((tmp = 1023830881.1444875, tmp)/(-754884477))+(tmp = 651938896.6258571, tmp))))>>(tmp = 346467413.8959185, tmp))); - assertEquals(-1, x >>= (tmp = 2993867511, tmp)); - assertEquals(-1, x |= (tmp = 823150253.4916545, tmp)); - assertEquals(-0, x %= x); - assertEquals(-0, x /= ((tmp = 997969036, tmp)&((((tmp = 928480121, tmp)>>(((-2610875857.086055)>>>(tmp = -2251704283, tmp))|x))+(10781750))>>x))); - assertEquals(0, x >>>= ((tmp = -1872319523, tmp)>>>(-278173884))); - assertEquals(0, x |= (x/(x*x))); - assertEquals(0, x %= ((77912826.10575807)^(tmp = 2770214585.3019757, tmp))); - assertEquals(0, x &= (tmp = 722275824, tmp)); - assertEquals(-1417226266, x |= (tmp = 2877741030.1195555, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x %= (tmp = -1740126105, tmp)); - assertEquals(910709964, x |= (tmp = 910709964, tmp)); - assertEquals(-1744830464, x <<= (tmp = -2445932551.1762686, tmp)); - assertEquals(318767104, x >>>= (tmp = -2465332061.628887, tmp)); - assertEquals(301989888, x &= (-2771167302.022801)); - assertEquals(301989888, x |= x); - assertEquals(37748736, x >>= (tmp = -835820125, tmp)); - assertEquals(1474977371, x ^= (tmp = -2857738661.6610327, tmp)); - assertEquals(470467500, x += (-1004509871)); - assertEquals(0.30466562575942585, x /= (((tmp = 1515955042, tmp)<<(x+((1607647367)-(tmp = 1427642709.697169, tmp))))^x)); - assertEquals(1.0348231148499734e-10, x /= (tmp = 2944132397, tmp)); - assertEquals(0, x >>= (x>>>(tmp = -2847037519.569043, tmp))); - assertEquals(NaN, x /= x); - assertEquals(0, x >>>= (-1817784819.9058492)); - assertEquals(0, x >>= x); - assertEquals(-0, x *= ((tmp = -1387748473, tmp)|(x+(352432111)))); - assertEquals(-0, x *= (((-2591789329)/(tmp = -2144460203, tmp))>>(tmp = -568837912.5033123, tmp))); - assertEquals(0, x <<= (-2963600437.305708)); - assertEquals(0, x &= ((588720662)>>>x)); - assertEquals(1561910729, x += (1561910729)); - assertEquals(0, x ^= x); - assertEquals(-0, x *= (-2722445702)); - assertEquals(0, x &= (tmp = -2738643199.732308, tmp)); - assertEquals(0, x /= (((1859901899.227291)>>>((tmp = -1067365693, tmp)+((-1975435278)|x)))|((1844023313.3719304)&(tmp = -624215417.0227654, tmp)))); - assertEquals(NaN, x %= x); - assertEquals(NaN, x %= (-2852766277)); - assertEquals(0, x <<= (-1482859558)); - assertEquals(0, x >>= x); - assertEquals(-1196775786, x += (tmp = -1196775786, tmp)); - assertEquals(-68176201, x |= ((tmp = 2336517643, tmp)+x)); - assertEquals(0, x ^= x); - assertEquals(0, x <<= x); - assertEquals(0, x >>= (2969141362.868086)); - assertEquals(NaN, x %= x); - assertEquals(0, x >>= ((x-((((tmp = -905994835, tmp)|(tmp = 2850569869.33876, tmp))<<((-2405056608.27147)>>(tmp = 1280271785, tmp)))&(-1942926558)))*(tmp = 707499803.177796, tmp))); - assertEquals(0, x &= ((-697565829.8780258)+((2978584888.549406)%x))); - assertEquals(0, x >>= (748642824.4181392)); - assertEquals(0, x += x); - assertEquals(0, x >>>= (-1701028721)); - assertEquals(92042539, x -= ((-92042539)|(x*(x%(-293705541.00228095))))); - assertEquals(0, x %= x); - assertEquals(0, x >>= x); - assertEquals(0, x %= (-2278672472.458228)); - assertEquals(0, x %= (((-2374117528.0359464)/((tmp = -2809986062, tmp)|(tmp = 895734980, tmp)))&(tmp = 1564711307.41494, tmp))); - assertEquals(0, x >>>= x); - assertEquals(0, x += x); - assertEquals(-0, x /= ((tmp = -2749286790.3666043, tmp)<<(x^(-2966741582.324482)))); - assertEquals(0, x *= x); - assertEquals(0, x >>>= x); - assertEquals(-1882562314, x ^= (2412404982.782115)); - assertEquals(-806620, x %= (((tmp = 1527219936.5232096, tmp)*(-1139841417))>>>(tmp = 201632907.3236668, tmp))); - assertEquals(-1613240, x += x); - assertEquals(-1664766177387640, x *= (1031939561)); - assertEquals(-9.478083550117849e+23, x *= (tmp = 569334221.1571662, tmp)); - assertEquals(-8.462574598319509e+21, x /= ((x-(tmp = -2985531211.114498, tmp))>>(tmp = 174615992.91117632, tmp))); - assertEquals(1638924288, x <<= (((((x>>((-1823401733.4788911)+((tmp = 1362371590, tmp)>>>x)))^(tmp = -56634380, tmp))/(tmp = 2387980757.1540084, tmp))%((((tmp = -3175469977, tmp)^(tmp = -1816794042, tmp))+(232726694))*(tmp = 822706176, tmp)))/(tmp = 1466729893.836311, tmp))); - assertEquals(2686072821796307000, x *= x); - assertEquals(-1007977445.9812208, x /= (-2664814408.800125)); - assertEquals(-1007977445, x &= x); - assertEquals(322314656346249100, x *= (tmp = -319763758.54942775, tmp)); - assertEquals(197436885.26815608, x /= (tmp = 1632494637, tmp)); - assertEquals(-67191339, x |= ((-399580815.1746769)/((1335558363)/(tmp = 224694526, tmp)))); - assertEquals(1229588737, x &= (tmp = 1296763683.5732255, tmp)); - assertEquals(1229588737, x -= ((((1171546503)|((tmp = -2701891308, tmp)%(-2155432197.022206)))/(-306122816.85682726))>>x)); - assertEquals(4162606632, x -= (tmp = -2933017895, tmp)); - assertEquals(1.6487311395551163, x /= (2524733434.1748486)); - assertEquals(-1929308648.9913044, x += (-1929308650.6400356)); - assertEquals(-3858617297.982609, x += x); - assertEquals(788529152, x <<= (x^(1401824663))); - assertEquals(6160384, x >>>= ((((((x>>>x)>>((((x*(tmp = -1958877151, tmp))>>>(1310891043))-(tmp = 564909413.9962088, tmp))%(-175978438)))%x)|((tmp = -1193552419.7837512, tmp)*(tmp = 1508330424.9068346, tmp)))|(1428324616.3303494))-((1828673751)/(tmp = 1281364779, tmp)))); - assertEquals(6160384, x |= x); - assertEquals(1, x /= x); - assertEquals(1, x &= (tmp = -855689741, tmp)); - assertEquals(0, x >>>= x); - assertEquals(-1088569655.3528988, x -= (tmp = 1088569655.3528988, tmp)); - assertEquals(-1088569655, x >>= ((tmp = 2429646226.626727, tmp)<<((-1539293782.4487276)>>(x^((tmp = 1140855945.537702, tmp)+x))))); - assertEquals(-311, x %= ((x/x)<<x)); - assertEquals(1.2007722007722008, x /= (x|(tmp = 448796341.87655175, tmp))); - assertEquals(3, x |= (x+x)); - assertEquals(-9.32416092168023e-10, x /= (-3217447688)); - assertEquals(0, x >>= (615837464.0921166)); - assertEquals(0, x >>>= (tmp = -2993750670.683118, tmp)); - assertEquals(0, x >>>= (x%x)); - assertEquals(1610612736, x ^= ((-1322905256.6770213)<<(-2567950598))); - assertEquals(1693676493, x ^= (83063757.63660407)); - assertEquals(-758030371, x ^= (tmp = -1239274480, tmp)); - assertEquals(-758030371, x %= (tmp = 1961339006, tmp)); - assertEquals(-1509754528, x ^= (tmp = 1960027837, tmp)); - assertEquals(-1509754528, x <<= x); - assertEquals(-1509754528, x -= (((tmp = -50690205.33559728, tmp)/((tmp = -1364565380, tmp)<<(tmp = 2585052504, tmp)))<<(tmp = -2356889596, tmp))); - assertEquals(1, x >>>= (-3204164321)); - assertEquals(1, x *= x); - assertEquals(1114370230.591965, x *= ((tmp = 1114370229.591965, tmp)+x)); - assertEquals(-4.886305275432552, x /= ((-228059887.33344483)%(2841553631.3685856))); - assertEquals(2.358309397373389e-9, x /= (((x*(tmp = 203428818.08174622, tmp))&(x-(((510438355)*x)+x)))+x)); - assertEquals(0, x >>>= ((tmp = 1444810010, tmp)&(tmp = -3135701995.2235208, tmp))); - assertEquals(0, x /= (1865982928.6819582)); - assertEquals(0, x *= x); - assertEquals(2078726016.3772051, x -= (tmp = -2078726016.3772051, tmp)); - assertEquals(1580337898, x ^= ((tmp = -2714629398.447015, tmp)^x)); - assertEquals(1268363034, x -= ((x+((tmp = 1144068248.3834887, tmp)&(-954104940.155973)))<<(tmp = 1270573731.7828264, tmp))); - assertEquals(1744830464, x <<= (((1444869551.7830744)>>>((((x+(tmp = -904688528, tmp))<<x)-((tmp = 121151912.85873199, tmp)/(tmp = -2414150217.66479, tmp)))|(((-472906698)|(3215236833.8417764))+(907737193.9056952))))-((x&(-732223723))|(-221800427.7392578)))); - assertEquals(717338523283226600, x *= (x^(tmp = -2407450097.0604715, tmp))); - assertEquals(402653184, x >>= ((-3191405201.168252)*((tmp = -1941299639.695196, tmp)|(((x>>(((3215741220)>>>x)/(x+x)))^(((tmp = -2144862025.9842231, tmp)|((tmp = -1966913385, tmp)&x))%x))*((tmp = -1124749626.6112225, tmp)/(tmp = 837842574, tmp)))))); - assertEquals(402653184, x &= ((x|x)>>x)); - assertEquals(134217728, x &= ((2720231644.3849487)*x)); - assertEquals(134217726.75839183, x -= ((2438054684.738043)/(((((-984359711)*(x|((tmp = 177559682, tmp)^x)))/(-1253443505))/((2727868438.416792)*(x+((x<<(((tmp = 3023774345, tmp)&(-705699616.0846889))/x))<<x))))^(1963626488.548761)))); - assertEquals(1, x /= x); - assertEquals(245781494, x += ((tmp = 2551445099, tmp)^(2528486814))); - assertEquals(-1474427807, x ^= (-1497868393.342241)); - assertEquals(-1057271682, x += ((((((x>>x)%(-1556081693))|(x/(((1166243186.6325684)-(((tmp = 2870118257.1019487, tmp)/(x+(-69909960)))^(2270610694.671496)))/((1463187204.5849519)-x))))-x)-(x<<(-3077313003)))%x)); - assertEquals(-1065725846, x &= ((tmp = -1808223767, tmp)|(-481628214.3871765))); - assertEquals(-1065725846, x ^= (x&(((tmp = -1785170598, tmp)-(tmp = -2525350446.346484, tmp))/((((((-1783948056)^(tmp = 3027265884.41588, tmp))|((((tmp = 2195362566.2237773, tmp)<<(-2919444619))<<((tmp = -2507253075.2897573, tmp)^(x^((tmp = 1067516137, tmp)+((667737752)^(x*(tmp = -1187604212.7293758, tmp)))))))%(-617406719.5140038)))*(tmp = 511060465.6632478, tmp))*((tmp = 2580189800.752836, tmp)|((((tmp = 2357895660, tmp)%((-814381220)*(x-((x>>>(((x<<x)<<(tmp = 1919573020, tmp))-x))>>>((-2756011312.136148)>>(tmp = -1603458856, tmp))))))/((tmp = -1609199312, tmp)&(-3127643445)))%x)))<<(-2261731798))))); - assertEquals(1.6020307924030301, x /= (tmp = -665234308.2628405, tmp)); - assertEquals(-1120020556.697667, x *= (tmp = -699125486.2321637, tmp)); - assertEquals(-215875188, x -= (((((tmp = -1307845034, tmp)>>>((((-2820720421)^x)-(((x<<x)|(tmp = -3042092997.57406, tmp))+(((-1294857544)+((tmp = -668029108.1487186, tmp)>>(x<<x)))^(912144065.5274727))))^(389671596.2983854)))|(-2774264897.146559))%(x-((tmp = 1378085269, tmp)^x)))+((-1659377450.5247462)&(((1613063452.834885)>>>((-344896580.0694165)>>>((-13450558)+x)))^x)))); - assertEquals(1, x /= x); - assertEquals(0, x >>>= (2355750790)); - assertEquals(1969435421.4409347, x += (1969435421.4409347)); - assertEquals(0, x -= x); - assertEquals(0, x >>>= (((x*((-1022802960.6953495)<<(tmp = -2848428731.8339424, tmp)))^(-1630921485))%(1532937011))); - assertEquals(0, x <<= ((x+((x^(x^(tmp = 2017651860, tmp)))&(((x<<(((tmp = -1913317290.8189478, tmp)|(x-((((x%((tmp = -3035245210, tmp)+(-2270863807)))>>>((-2351852712)*(x^(-2422943296.0239563))))&((((-1578312517)%x)*x)*(-65592270.28452802)))>>>(tmp = 1104329727.2094703, tmp))))-(tmp = -1431159990.3340137, tmp)))&x)|((tmp = -2589292678.801344, tmp)&(x+((((tmp = -2557773457.456996, tmp)>>(451910805.309445))-x)>>(((tmp = -1937832765.7654495, tmp)^x)%x)))))))%x)); - assertEquals(0, x %= (tmp = -626944459, tmp)); - assertEquals(-732310021, x |= (tmp = -732310021, tmp)); - assertEquals(-732310021, x |= x); - assertEquals(671352839, x ^= (x-((-3087309090.7153115)|x))); - assertEquals(134479872, x &= (tmp = 2357183984, tmp)); - assertEquals(18084835973136384, x *= x); - assertEquals(0, x <<= ((1040482277)-(tmp = -357113781.82650447, tmp))); - assertEquals(74957, x |= ((((tmp = -70789345.7489841, tmp)%(tmp = 1415750131, tmp))&x)|((307027314)>>(2284275468)))); - assertEquals(9, x >>>= x); - assertEquals(0, x &= (x&((x*((x*(x%x))%(x>>x)))/x))); - assertEquals(-1872875060, x |= (2422092236.6850452)); - assertEquals(9, x >>>= (-382763684)); - assertEquals(4608, x <<= x); - assertEquals(40.480234260614935, x /= (((((((tmp = 814638767.5666755, tmp)&((tmp = 2081507162, tmp)^(x>>>(1460148331.2229118))))&(tmp = 1187669197.7318723, tmp))<<(412000677.93339765))^((tmp = 556111951, tmp)>>(tmp = -2232569601.292395, tmp)))&(-3006386864))/x)); - assertEquals(32, x &= (-3053435209.383913)); - assertEquals(418357217, x ^= (418357185)); - assertEquals(204275, x >>= ((-1188650337.9010527)^((51494580)%(-2544545273)))); - assertEquals(982392804, x += (((x+(((tmp = -982596937.9757051, tmp)+x)%(-2298479347)))^((((tmp = 1610297674.0732534, tmp)>>>x)*(((x>>(-2746780903.08599))&(-2376190704.247188))^(((20545353)/(tmp = 1468302977, tmp))-(x<<x))))>>(((-1434332028.0447056)/((tmp = 1983686888, tmp)&((tmp = 2324500847, tmp)%(394330230.6163173))))%(((-1129687479.2158055)+((-3127595161)*((-3066570223)&((tmp = 3192134577.4963055, tmp)/(-2697915283.3233275)))))+(-1112243977.5306559)))))|(x&(-2622725228)))); - assertEquals(-2735750653096133600, x *= (-2784782870.9218984)); - assertEquals(-1876329472, x |= ((((((2752866171)<<(-1681590319))/x)>>((tmp = 1451415208, tmp)>>>(1126858636.6634417)))+(((tmp = 2165569430.4844217, tmp)/x)^(((tmp = -1675421843.4364457, tmp)-(-2187743422.2866993))|x)))*x)); - assertEquals(3520612287495799000, x *= x); - assertEquals(-200278016, x |= ((((-2379590931)%((((-1558827450.833285)&x)>>(-665140792))-((tmp = -445783631.05567217, tmp)+(tmp = 93938389.53113222, tmp))))/(3103476273.734701))^x)); - assertEquals(-9178285062592.75, x *= ((2042671875.7211144)%(((tmp = 589269308.0452716, tmp)/x)<<(-130695915.9934752)))); - assertEquals(60048960, x |= (x<<x)); - assertEquals(60048960, x <<= ((((((tmp = -2793966650, tmp)/(-2882180652))&(((x<<((tmp = -384468710, tmp)+(2236162820.9930468)))>>>((((969371919)>>((tmp = -3153268403.2565875, tmp)-((((573811084)/x)^(tmp = -968372697.4844134, tmp))>>>(((-3096129189)>>x)/(tmp = 830228804.6249363, tmp)))))<<(((1243972633.3592157)|x)&((-1687610429)&(tmp = -1945063977.458529, tmp))))<<(((tmp = -217456781.37068868, tmp)-(400259171.68077815))^x)))>>>x))%(((2728450651.300167)/(((-2713666705.089135)%(tmp = 740472459, tmp))^x))|x))^x)*(-2463032364))); - assertEquals(60048960, x %= (tmp = -442107222.9513445, tmp)); - assertEquals(-1573781504, x <<= (960581227)); - assertEquals(1297, x >>>= (tmp = -1692919563, tmp)); - assertEquals(1297, x &= x); - assertEquals(-3113308397155.233, x *= (tmp = -2400391979.3024154, tmp)); - assertEquals(-3115513013486.233, x -= (2204616331)); - assertEquals(-3113809649082.233, x -= (-1703364404)); - assertEquals(0, x >>>= (((-1181206665)-(550946816.586771))|(tmp = -2346300456, tmp))); - assertEquals(0, x %= (tmp = 1649529739.2785435, tmp)); - assertEquals(0, x ^= ((tmp = -2452761827.2870226, tmp)%(((1090281070.5550141)/(tmp = 992149154.6500508, tmp))*(x<<((((((x>>>x)|((tmp = -2410892363, tmp)%(tmp = 2585150431.0231533, tmp)))/x)*(tmp = 1541294271, tmp))+x)&((97566561.77126992)&((((-640933510.1287451)&(((((x>>>((-1821077041)<<((tmp = -1138504062.093695, tmp)-(tmp = -181292160, tmp))))%x)-(x>>((x&(((tmp = 1067551355, tmp)/(x|(1004837864.8550552)))&(x-(-103229639.25084043))))&((tmp = 2064184671.210937, tmp)+((((tmp = -2245728052, tmp)|(1538407002.8365717))+(x<<((x>>((76549490)/(tmp = 628901902.6084052, tmp)))<<((x<<x)^(-1907669184)))))+(-1409123688))))))>>>((((-1911547456.933543)-((-512313175)+((tmp = -2620903017, tmp)^(tmp = 2148757592.244808, tmp))))<<((-1740876865)>>>x))+((tmp = 691314720.9488736, tmp)<<(614057604.4104803))))|(x^((tmp = -3040687.291528702, tmp)/(x^(((x+(-2899641915))^((tmp = -1220211746, tmp)/x))%x))))))^(tmp = 119850608, tmp))%(2091975696)))))))); - assertEquals(291273239, x -= (tmp = -291273239, tmp)); - assertEquals(2206394018, x += (1915120779)); - assertEquals(235641480, x <<= (x&(x&(-1810963865.1415658)))); - assertEquals(28764, x >>= ((tmp = -1927011875, tmp)^((tmp = -1986461808, tmp)|((-868139264.8399222)*((421956566)%(3068424525)))))); - assertEquals(-99780626900900, x *= ((tmp = -1512869526.3223472, tmp)+(tmp = -1956071751, tmp))); - assertEquals(51218520, x &= (((-2353401311)>>>x)-(2216842509))); - assertEquals(51218520, x >>>= ((tmp = -1534539302.6990812, tmp)<<x)); - assertEquals(-2147483648, x <<= (-292608644)); - assertEquals(-2147483648, x |= ((((((x<<((-2981292735)-x))>>((tmp = 2540545320.96558, tmp)&(tmp = -2343790880, tmp)))>>>((((((x^((-172697043.94487858)/((2627260337)>>(2879112814.1247935))))&(tmp = 3000943191, tmp))<<(tmp = 1094830905, tmp))-x)>>>x)>>((((tmp = 3095796200, tmp)^(x|(tmp = 1460377694, tmp)))<<(x^(tmp = -357546193, tmp)))/((2729539495)>>x))))%(tmp = 268894171.74961245, tmp))|(x>>(tmp = 2735650924, tmp)))/(-2197885357.09768))); - assertEquals(-2147483648, x |= x); - assertEquals(-1967162776824578000, x *= (tmp = 916031551, tmp)); - assertEquals(-2147483648, x &= x); - assertEquals(-457743917756973060, x *= (tmp = 213153622, tmp)); - assertEquals(0, x >>>= ((((tmp = 2930076928.480559, tmp)+(x^x))<<(tmp = -1349755597.1280541, tmp))|(x+(2865632849)))); - assertEquals(0, x <<= ((x>>x)-(x>>(-2629977861)))); - assertEquals(0, x <<= x); - assertEquals(NaN, x /= x); - assertEquals(0, x |= x); - assertEquals(0, x >>>= x); - assertEquals(749327478, x |= ((tmp = 749327478, tmp)^(x>>(tmp = 881107862, tmp)))); - assertEquals(1897869364, x += (1148541886)); - assertEquals(463347, x >>>= (tmp = -726431220, tmp)); - assertEquals(-395990542, x += (-396453889)); - assertEquals(-2824792585.1675367, x -= (2428802043.1675367)); - assertEquals(-2147483648, x <<= (tmp = -1420072385.9175675, tmp)); - assertEquals(8388608, x >>>= (-2211390680.488455)); - assertEquals(8388608, x >>= (((x/(x|(((x^(((tmp = -2175960170.8055067, tmp)|((tmp = -1964957385.9669886, tmp)/(tmp = -475033330, tmp)))&((x|((tmp = 1386597019.2014387, tmp)>>((tmp = -2406589229.8801174, tmp)+x)))<<(tmp = -844032843.8415492, tmp))))>>(x^x))|x)))-((x&((tmp = 1858138856, tmp)*(-3156357504)))%x))<<(((2046448340)+x)/(-2645926916)))); - assertEquals(8359470765396279, x *= ((tmp = 871437183.7888144, tmp)-(-125089387.17460155))); - assertEquals(0, x ^= x); - assertEquals(-303039014, x += ((tmp = -2475713214, tmp)|(-372871718.2343409))); - assertEquals(2655126577, x -= (-2958165591)); - assertEquals(1830332793, x ^= (tmp = -212161208, tmp)); - assertEquals(1830332793, x ^= (((2352454407.0126333)<<((((tmp = 3083552367, tmp)/x)-(-1243111279))-((tmp = -1669093976, tmp)%(((-757485455)-(tmp = -116051602, tmp))<<x))))>>(((((-2235071915.9536905)>>(tmp = -1284656185, tmp))-x)>>((-1807028069.7202528)>>>((x%((tmp = -3070857953.311804, tmp)+((tmp = 2759633693.441942, tmp)%((169489938)*(-1582267384)))))<<(x^((tmp = -787578860, tmp)<<x)))))>>((x/(x|(409464362)))-(tmp = -64033017, tmp))))); - assertEquals(397605933.90319204, x %= (tmp = 716363429.548404, tmp)); - assertEquals(186400, x &= (((x%(-1745754586))>>>x)<<(x&(x&((-2163627752)-((1784050895)+(((-2864781121.899456)>>>x)&x))))))); - assertEquals(186400, x %= (tmp = -423209729, tmp)); - assertEquals(186400, x <<= ((x<<(x+(1232575114.4447284)))*x)); - assertEquals(1386299, x ^= ((tmp = -1074209615, tmp)>>>(x>>>((tmp = -1456741008.2654872, tmp)>>((1724761067)>>(-2016103779.9084842)))))); - assertEquals(347302967.20758367, x -= (-345916668.20758367)); - assertEquals(1.9325619389304094, x /= (179711170.03359854)); - assertEquals(-3703324711.628227, x *= (tmp = -1916277371, tmp)); - assertEquals(-920980517031624800, x *= (tmp = 248690187.53332615, tmp)); - assertEquals(0, x &= (((tmp = -2753945953.082594, tmp)*x)-(172907186))); - assertEquals(-0, x /= (((((-2744323543.187253)>>((tmp = 2663112845, tmp)>>(((-121791600)+(x^x))*(2758944252.4214177))))|x)/(tmp = -2746716631.6805267, tmp))-x)); - assertEquals(0, x ^= ((tmp = 983113117, tmp)&((2638307333)+((((tmp = 3076361304.56189, tmp)<<(-2663410588.5895214))%((-1109962112)-(tmp = -2381021732, tmp)))%((tmp = 410559095, tmp)&x))))); - assertEquals(0, x <<= (tmp = 1510895336.5111506, tmp)); - assertEquals(0, x <<= (tmp = -1688348296.2730422, tmp)); - assertEquals(2269471424, x -= (-2269471424)); - assertEquals(-2022580224, x ^= (x%((tmp = 160999480.21415842, tmp)&x))); - assertEquals(-2077171712, x &= (tmp = 3032415014.3817654, tmp)); - assertEquals(270727, x >>>= (2973489165.1553965)); - assertEquals(270727, x |= x); - assertEquals(-1895894537, x |= ((tmp = -1895903118.129186, tmp)|x)); - assertEquals(-1895894537, x -= ((((((((3143124509)>>>(-2866190144.8724117))*((x>>((961021882)*(tmp = 2363055833.8634424, tmp)))/((2032785518)+((2713643671.3420825)>>((-447782997.0173557)*((tmp = 1174918125.3178625, tmp)*((((tmp = -541539365.548115, tmp)%(-359633101))|(1765169562.2880063))+(tmp = -2512371966.374508, tmp))))))))/x)>>(x*((((-847238927.6399388)&(857288850))%(-2427015402))^((2221426567)%(x+x)))))>>>x)<<((tmp = 2009453564.2808268, tmp)>>((2924411494)<<(x>>(tmp = -1240031020.8711805, tmp)))))%(tmp = 3118159353, tmp))); - assertEquals(0, x ^= x); - assertEquals(0, x %= (-30151583)); - assertEquals(-1035186736, x ^= ((tmp = -517593368, tmp)<<(tmp = 3216155585, tmp))); - assertEquals(49740, x >>>= x); - assertEquals(49740, x %= (640223506)); - assertEquals(388, x >>>= ((x>>(tmp = 3161620923.50496, tmp))+(2605183207))); - assertEquals(776, x += x); - assertEquals(-97905, x ^= ((((((tmp = 145447047.8783008, tmp)^(((x>>>(tmp = 3014858214.2409887, tmp))>>>(629911626.132971))>>(((x+((369309637.229408)-x))<<(-2661038814.9204755))*(x+(x%(3025191323.4780884))))))+x)*(-482550691))|(-632782135))/x)); - assertEquals(-97905, x %= ((((-492914681)-((-2508632959.269368)&(tmp = 1209318291, tmp)))>>(-723512989.459533))>>>(((-528429623.985692)&(x^(tmp = -925044503, tmp)))-(-1696531234)))); - assertEquals(9585389025, x *= x); - assertEquals(-715425728, x <<= ((583763091)<<(-1223615295))); - assertEquals(-520093696, x <<= ((tmp = -1891357699.671592, tmp)*(((tmp = 3206095739.5163193, tmp)+(-2908596651.798733))>>>((tmp = -2820415686, tmp)>>(x|((((tmp = -566367675.6250327, tmp)*(-959117054))>>((((-187457085.89686918)*x)*(tmp = -2394776877.5373516, tmp))>>>x))|(((tmp = 80478970.46290505, tmp)<<(tmp = 2173570349.493097, tmp))-(x/((-2896765964)-((x/((tmp = 198741535.7034216, tmp)%(436741457)))%(tmp = 2936044280.0587225, tmp))))))))))); - assertEquals(-2520.5909527086624, x /= ((211290893.06029093)>>(663265322))); - assertEquals(-2520.5909527086624, x %= (x^((1057915688)<<(tmp = 1914820571.1142511, tmp)))); - assertEquals(1, x >>>= (((894963408.7746166)+(tmp = -2888351666, tmp))|x)); - assertEquals(-1989841636629996300, x += ((1424670316.224575)*((-2144149843.0876865)|((((421479301.0983993)|((3082651798)^(tmp = -271906497, tmp)))>>x)+((tmp = -178372083, tmp)%x))))); - assertEquals(17935384255.088326, x /= (((((((tmp = 1168194849.2361898, tmp)>>>(-107316520.53815603))>>>(x^(((x%((x>>>(((-2456622387)/x)&((2124689803)|(((-1130151701)^(2796315158))>>x))))-((-884686033.5491502)>>>((-2371185318.5358763)&x))))+(tmp = 558422989, tmp))|((tmp = -420359120.0596726, tmp)/((-1820568437.0587764)&(2298602280.266465))))))>>(x-((tmp = -1164568978, tmp)^x)))^x)-x)+x)); - assertEquals(134233150, x &= ((x>>(((tmp = 98498118.13041973, tmp)-(804574397))/(tmp = -1564490985.7904541, tmp)))+x)); - assertEquals(4, x >>= (449610809)); - assertEquals(1912543790, x |= (1912543790)); - assertEquals(2487274263, x += (tmp = 574730473, tmp)); - assertEquals(-2140759118, x ^= (tmp = 338055333.9701035, tmp)); - assertEquals(311607367, x += (2452366485)); - assertEquals(9509, x >>= (372113647.84365284)); - assertEquals(-2001075684.1562128, x += (-2001085193.1562128)); - assertEquals(-638703280, x ^= (((tmp = 1096152237, tmp)&x)|((2707404245.0966487)-(((tmp = 1550233654.9691348, tmp)+(tmp = 2008619647, tmp))&((tmp = -2653266325, tmp)+(tmp = -280936332, tmp)))))); - assertEquals(-101811850, x |= (-2250090202)); - assertEquals(-13, x >>= ((-561312810.0218933)|(tmp = 79838949.86521482, tmp))); - assertEquals(-13, x >>= ((tmp = -936543584, tmp)/(1180727664.1746705))); - assertEquals(-1547, x *= (((tmp = 1005197689, tmp)>>>x)>>>(tmp = 34607588, tmp))); - assertEquals(2393209, x *= x); - assertEquals(2393209, x |= x); - assertEquals(0, x >>= (-2691279235.1215696)); - assertEquals(0, x *= (((896175510.4920144)*((((tmp = 1770236555.7788959, tmp)%(537168585.7310632))/x)&(tmp = 1094337576, tmp)))&(((x-x)-x)>>x))); - assertEquals(-1922620126, x ^= (-1922620126)); - assertEquals(3.43481396325761, x /= (tmp = -559745053.6088333, tmp)); - assertEquals(0, x >>= x); - assertEquals(0, x >>>= (tmp = 2106956255.6602135, tmp)); - assertEquals(-1339003770, x ^= ((tmp = 2955963526.960022, tmp)+x)); - assertEquals(-0, x *= ((((tmp = 368669994, tmp)>>>(x*x))<<(tmp = 2355889375, tmp))&(tmp = -2267550563.9174895, tmp))); - assertEquals(0, x >>= (753848520.8946902)); - assertEquals(0, x >>>= x); - assertEquals(0, x %= ((tmp = -2872753234.2257266, tmp)|x)); - assertEquals(NaN, x %= (x>>>(tmp = 890474186.0898918, tmp))); - assertEquals(NaN, x %= ((tmp = 1341133992.284471, tmp)&(tmp = -2979219283.794898, tmp))); - assertEquals(NaN, x += (-2865467651.1743298)); - assertEquals(NaN, x += ((-1424445677)%(x^(tmp = 1150366884, tmp)))); - assertEquals(0, x &= (x+((tmp = 1499426534, tmp)+x))); - assertEquals(0, x |= (((((tmp = -2413914642, tmp)<<((x>>>x)^(1218748804)))+((((-1085643932.2642736)-(-1199134221.533854))>>(tmp = 2148778719, tmp))-((tmp = 1589158782.0040946, tmp)/(tmp = -2485474016.1575155, tmp))))>>>(x>>x))/(2230919719))); - assertEquals(0, x %= ((tmp = -2576387170.517563, tmp)>>>((tmp = -2362334915.919525, tmp)>>>(((3096453582)-(700067891.4834484))^(2396394772.9253683))))); - assertEquals(-1798103432, x ^= (((((tmp = 2396144191, tmp)*(x>>>(1512158325)))&(((-1256228298.5444434)&(((-2963136043.434966)&((tmp = 2472984854, tmp)+(tmp = -454900927, tmp)))%(tmp = 484255852.65332687, tmp)))>>((x%x)-x)))&(tmp = 929723984, tmp))^(tmp = -1798103432.5838807, tmp))); - assertEquals(-2137913344, x &= ((((x|(-2970116473))&(((x/x)/((tmp = 2853070005, tmp)>>>x))%(((tmp = -3123344846, tmp)/((2224296621.6742916)-(tmp = -2246403296.455411, tmp)))+((x&(((x^(x*(2829687641)))+x)&(tmp = 988992521, tmp)))^x))))<<((((-820608336)^(tmp = 2851897085, tmp))>>(tmp = -402427624, tmp))>>>x))-(((x*(((-2287402266.4821453)%(tmp = -520664172.1831205, tmp))^(x/(1875488837))))<<(tmp = 402393637, tmp))&(tmp = 1576638746.3047547, tmp)))); - assertEquals(-2827557853031924000, x *= (tmp = 1322578326.6507945, tmp)); - assertEquals(6.424459501778244e+27, x *= (tmp = -2272087729.3065624, tmp)); - assertEquals(-1586887483, x |= (-1586887483)); - assertEquals(-567868980691736100, x *= (tmp = 357850816, tmp)); - assertEquals(1489101591, x ^= (x%(x|(421921075)))); - assertEquals(-801213804822328000, x *= (x|(-672326904.6888077))); - assertEquals(612257233.6612054, x /= (((tmp = -350127617, tmp)>>>(-1140467595.9752212))<<((x^x)+(-3117914887)))); - assertEquals(19097.231243331422, x /= ((x^(tmp = -570012517, tmp))>>>x)); - assertEquals(0, x >>= ((x%(((-2347648358)%((x-(tmp = -456496327, tmp))|(x^(-1977407615.4582832))))<<(x/(tmp = -2021394626.214082, tmp))))%(tmp = -949323000.2442119, tmp))); - assertEquals(0, x <<= x); - assertEquals(NaN, x %= (x^(x>>(((tmp = 597147546.7701412, tmp)&(((((-972400689.6267757)|(tmp = -2390675341.6367044, tmp))|(tmp = 1890069123.9831812, tmp))<<(((1606974563)-(tmp = -2211617255.8450356, tmp))&((((x+((2433096953)&(-2527357746.681596)))*(tmp = -313956807.55609417, tmp))|((tmp = -2146031047.968496, tmp)/(tmp = 2851650714.68952, tmp)))>>(((tmp = 2630692376.6265225, tmp)-(tmp = -3162222598, tmp))>>((tmp = 1915552466, tmp)*(x>>>(-2413248225.7536864)))))))&(x%((((1218471556)|x)+(tmp = -849693122.6355379, tmp))+x))))>>>(x/((tmp = 689889363, tmp)/x)))))); - assertEquals(0, x >>>= (45649573.23297)); - assertEquals(0, x >>>= (tmp = 1084439432.771266, tmp)); - assertEquals(NaN, x /= x); - assertEquals(NaN, x *= (tmp = 1642750077, tmp)); - assertEquals(0, x >>>= (tmp = -1944001182.0778434, tmp)); - assertEquals(1682573000, x |= (tmp = -2612394296.2858696, tmp)); - assertEquals(3041823595, x -= (((tmp = 720576773, tmp)|(x^(-1068335724.2253149)))>>(x*(-2501017061)))); - assertEquals(6083647190, x += x); - assertEquals(-6536258988089986000, x *= ((tmp = 632312939.6147232, tmp)|((-1621821634)+(((tmp = -2281369913.562131, tmp)&((tmp = -381226774, tmp)|x))&(664399051))))); - assertEquals(4.272268155938712e+37, x *= x); - assertEquals(733271152, x %= (-1345127171)); - assertEquals(847089925, x ^= (tmp = 432620917.57699084, tmp)); - assertEquals(1337073824, x <<= x); - assertEquals(-25810602, x ^= (tmp = 2982414838, tmp)); - assertEquals(-25282209, x |= ((tmp = -2927596922, tmp)>>>(-2404046645.01413))); - assertEquals(639190091919681, x *= x); - assertEquals(173568320, x &= ((((tmp = -718515534.4119437, tmp)&(tmp = 2989263401, tmp))<<x)|((tmp = 537073030.5331153, tmp)-(tmp = 883595389.314624, tmp)))); - assertEquals(0, x -= x); - assertEquals(0, x >>>= (tmp = -1844717424.917882, tmp)); - assertEquals(0, x >>= (tmp = -462881544.2225325, tmp)); - assertEquals(0, x >>= x); - assertEquals(-1868450038, x ^= (2426517258.6111603)); - assertEquals(1, x /= x); - assertEquals(1175936039.4202638, x += (tmp = 1175936038.4202638, tmp)); - assertEquals(-127916015, x ^= ((x/(1841969600.3012052))-(tmp = 1099467723, tmp))); - assertEquals(395713785658171900, x *= (-3093543726)); - assertEquals(395713787128560900, x += (((((-717204758)*(tmp = -588182129.6898501, tmp))-x)+(tmp = 20638023, tmp))^x)); - assertEquals(-962609355, x |= ((x^(-3118556619.912983))<<((tmp = 876126864, tmp)&x))); - assertEquals(-962609355, x %= (tmp = -2079049990, tmp)); - assertEquals(-114583755, x -= (((-2806715240)&(((1961136061.0329285)>>>((2087162059)*x))+((tmp = -1890084022.7631018, tmp)%(tmp = 2137514142.358262, tmp))))+(x<<(tmp = 2991240918, tmp)))); - assertEquals(-425721856, x <<= x); - assertEquals(3778560, x >>>= ((x|(3198503572))>>(1158434541.1099558))); - assertEquals(3778560, x %= (tmp = -2592585378.9592104, tmp)); - assertEquals(624640, x &= (tmp = 2261638192.9864054, tmp)); - assertEquals(1249280, x += x); - assertEquals(1048576, x &= ((tmp = -2144301819.9892588, tmp)^((x-x)<<x))); - assertEquals(2097152, x <<= (x/x)); - assertEquals(5069061551149729, x *= (tmp = 2417116904.8069615, tmp)); - assertEquals(1.4836296666029616e+25, x += ((tmp = 2926833006.7121572, tmp)*x)); - assertEquals(-256, x >>= ((-469330345.3589895)%((x^(((2554170843.4978285)/(2495676674.815263))>>>x))*(-918892963)))); - assertEquals(-134217728, x <<= (x|(((((1687450853.1321645)+(tmp = 2369533014.5803776, tmp))+(tmp = -2613779445, tmp))+(tmp = -2488826226.3733397, tmp))>>(tmp = -220646936.41245174, tmp)))); - assertEquals(704164545131708400, x *= ((-2632786741)+(-2613647956))); - assertEquals(9216, x >>>= (-1925405359.657349)); - assertEquals(4491403261551.008, x *= (tmp = 487348444.1787118, tmp)); - assertEquals(4490606381829.008, x -= (tmp = 796879722, tmp)); - assertEquals(-60294056, x >>= x); - assertEquals(-3193966580.494005, x += (tmp = -3133672524.494005, tmp)); - assertEquals(550500358, x >>>= ((tmp = -2779637628.390116, tmp)-((tmp = 29230786.984039664, tmp)%(tmp = -310649504.7704866, tmp)))); - assertEquals(68812544, x >>= (-1347584797)); - assertEquals(1.2120221595741834e-11, x /= ((2791020260)*((((1964870148.6358237)^x)|(-3082869417))-((x^x)&((1234292117.8790703)<<(-1792461937.2469518)))))); - assertEquals(1.2120221595741834e-11, x %= (x-(2780439348))); - assertEquals(-1421552183, x |= (tmp = -1421552183.5930738, tmp)); - assertEquals(-1420954119, x |= ((((-2547788562.5735893)<<x)%(435385623))>>(x|x))); - assertEquals(1, x /= x); - assertEquals(1, x >>= (x>>>(((2975715011.501709)-(tmp = -1473273552.981069, tmp))/(1654883913.042487)))); - assertEquals(-65382, x ^= ((x/((tmp = -2780026200, tmp)<<x))^(((-2683084424)<<x)>>(-1716245874)))); - assertEquals(1530921106, x &= (1530940914)); - assertEquals(1, x /= x); - assertEquals(0, x >>= x); - assertEquals(0, x /= (tmp = 773741434.1972584, tmp)); - assertEquals(0, x |= x); - assertEquals(0, x <<= (-67977514.99888301)); - assertEquals(0, x %= (2496550482.524729)); - assertEquals(-0, x /= (tmp = -515040417, tmp)); - assertEquals(0, x <<= (-1673460935.2858837)); - assertEquals(-2638209488, x += (-2638209488)); - assertEquals(-2400951839498683400, x *= (910068685)); - assertEquals(1600582036, x ^= (((-1247602308.4812562)>>(((-2393714444.179732)>>>x)%(-778140635.7165127)))+(-1933914727.2268424))); - assertEquals(0, x *= ((x-x)>>(-1270234575))); - assertEquals(0, x >>>= (tmp = 3193676327.493656, tmp)); - assertEquals(0, x ^= (x>>>(1148676785.389884))); - assertEquals(0, x >>= (tmp = -2269181763.8663893, tmp)); - assertEquals(0, x >>= (3149450221)); - assertEquals(0, x >>= (1069630750)); - assertEquals(-625009654, x ^= ((-2143499112)%(-759244728.6214335))); - assertEquals(3583943, x >>>= (-2942645558.1204453)); - assertEquals(1791971, x >>= (x/x)); - assertEquals(223996, x >>= x); - assertEquals(6999, x >>= (tmp = -1051883611.9443719, tmp)); - assertEquals(1459617792, x <<= (-1572314984)); - assertEquals(2622356453.269262, x -= (tmp = -1162738661.2692618, tmp)); - assertEquals(5103676461.269262, x += (2481320008)); - assertEquals(823989684.2692623, x %= (x^(((((1048362966)*((tmp = -2423040747.6233954, tmp)>>>x))*((tmp = 2330818588.4081, tmp)>>(tmp = 103312020.98346841, tmp)))+(tmp = 2264492857.144133, tmp))>>>((tmp = 2523442834, tmp)<<x)))); - assertEquals(0, x >>>= (tmp = -2018700898.531027, tmp)); - assertEquals(NaN, x /= x); - assertEquals(0, x <<= (tmp = -2489442223, tmp)); - assertEquals(0, x >>= ((3045836220)>>>x)); - assertEquals(-1156905149, x ^= (3138062147)); - assertEquals(-0, x %= x); - assertEquals(-3118433907.512866, x -= ((tmp = 1338611238, tmp)-(-1779822669.5128663))); - assertEquals(100679693, x &= (1040565279)); - assertEquals(10136400582574248, x *= x); - assertEquals(0, x %= x); - assertEquals(2400318405, x += (2400318405)); - assertEquals(1.0036190808578471, x /= (((tmp = -2313492253.9889445, tmp)|(x-((tmp = -205459123, tmp)>>x)))+x)); - assertEquals(0, x >>>= (tmp = 882343227.1675215, tmp)); - assertEquals(0, x &= ((tmp = 2307828832.2706165, tmp)^((((((1404388047)<<((807879382)-(-2862921873)))-x)*(tmp = -1897734732, tmp))>>(tmp = 1981888881.2306776, tmp))%x))); - assertEquals(0, x <<= x); - assertEquals(0, x *= (((x*x)*((((2764801384.171454)%(x>>>x))&(384818815))+(x>>(tmp = -1481683516, tmp))))&x)); - assertEquals(0, x >>= (tmp = -2202536436, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x &= (tmp = 15161124, tmp)); - assertEquals(-1586110900, x ^= (-1586110900)); - assertEquals(-1586127952, x -= ((tmp = 560737212, tmp)%((1349529668)>>>(tmp = -1956656528, tmp)))); - assertEquals(-1174945870, x -= ((1178456190)|x)); - assertEquals(1335167624.3422346, x -= (tmp = -2510113494.3422346, tmp)); - assertEquals(1329952126.3422346, x -= (x>>x)); - assertEquals(1, x >>= x); - assertEquals(3, x |= (x<<x)); - assertEquals(3, x -= (x-x)); - assertEquals(-1938525669, x |= (tmp = 2356441625.5128202, tmp)); - assertEquals(-1938525669, x ^= ((tmp = -197149141.3622346, tmp)/(2833823156))); - assertEquals(-2.6292393147661324, x /= (737295254.2254335)); - assertEquals(2925975987.370761, x -= (-2925975990)); - assertEquals(2925975987.370761, x %= (tmp = 3041184582.8197603, tmp)); - assertEquals(-1908068660, x ^= ((tmp = -1380575181, tmp)-(2375164084.8366547))); - assertEquals(-477017165, x >>= (tmp = 2420877826.353099, tmp)); - assertEquals(-477017165, x %= ((tmp = -2919204062.3683634, tmp)-(tmp = -2263328990, tmp))); - assertEquals(-2105539936, x &= ((tmp = -1630795440, tmp)-(x&((933423833)>>(-475069901))))); - assertEquals(-4979480720, x -= (tmp = 2873940784, tmp)); - assertEquals(-4190953472, x -= (x&(tmp = -645918862.9001305, tmp))); - assertEquals(17564091004468855000, x *= x); - assertEquals(-857277134, x |= (tmp = 2363948338, tmp)); - assertEquals(1015632515, x -= (-1872909649)); - assertEquals(-1150380043, x ^= (tmp = -2014853770, tmp)); - assertEquals(1607729152, x <<= ((2194449589)+(x|(tmp = -1470075256.4605722, tmp)))); - assertEquals(1608356496, x |= ((((x|(670426524))<<((-2415862218)>>(tmp = 1572561529.9213061, tmp)))^((-1989566800.3681061)|x))&(2170270618.3401785))); - assertEquals(-1836056576, x <<= (tmp = 2906301296.540217, tmp)); - assertEquals(-2952415961567723500, x *= (tmp = 1608020145, tmp)); - assertEquals(1435500544, x <<= x); - assertEquals(700928, x >>>= (tmp = 2924829771.1804566, tmp)); - assertEquals(0, x <<= ((x^(2410009094))|(((-164334714.18698573)%(x*x))|(tmp = 2182431441.2575436, tmp)))); - assertEquals(-143321285, x ^= (tmp = -143321285, tmp)); - assertEquals(-2, x >>= x); - assertEquals(-1, x >>= (x&(1109737404))); - assertEquals(1, x >>>= x); - assertEquals(0, x ^= x); - assertEquals(-2463707358.165766, x += (-2463707358.165766)); - assertEquals(1831259938, x >>= (((((x-(tmp = 1359448920.5452857, tmp))%(tmp = -104541523, tmp))/((3133289055.9780197)*x))>>x)%x)); - assertEquals(1858895646, x ^= ((tmp = 131424376, tmp)>>(tmp = -396761023, tmp))); - assertEquals(1, x >>= x); - assertEquals(-1888369021, x |= ((tmp = -2038869285.046599, tmp)^((tmp = -1318286592.4250565, tmp)-(tmp = 2825123496, tmp)))); - assertEquals(1036458508, x <<= ((tmp = 2722401450, tmp)/((tmp = 1090712291, tmp)>>((tmp = -2155694696.9755683, tmp)*(tmp = 1661107340, tmp))))); - assertEquals(1, x /= (x%((tmp = -1716050484, tmp)+(tmp = -1683833551.797319, tmp)))); - assertEquals(0, x >>= (tmp = -2899315628, tmp)); - assertEquals(0, x |= x); - assertEquals(0, x >>>= x); - assertEquals(0, x <<= x); - assertEquals(1546062911, x |= (1546062911)); - assertEquals(1546195271, x += ((tmp = -3210667091, tmp)>>(tmp = 1323121165, tmp))); - assertEquals(3092390542, x += x); - assertEquals(-1199626354, x |= (406783756)); - assertEquals(-3650317194584908300, x *= (tmp = 3042878461.625484, tmp)); - assertEquals(-7.650495675092354e+27, x *= (2095844078)); - assertEquals(0, x >>= (tmp = 342617880.3384919, tmp)); - assertEquals(22, x ^= (((tmp = 381409558.9104688, tmp)>>((2823172888.974557)>>x))>>x)); - assertEquals(736383550, x += (736383528)); - assertEquals(0, x %= x); - assertEquals(0, x += x); - assertEquals(-1553157831, x -= (1553157831)); - assertEquals(1838556960, x <<= (3158944357.262641)); - assertEquals(5503285699.188747, x *= ((tmp = 2437440276, tmp)/(814308583.8128904))); - assertEquals(5824889900.188747, x -= (((tmp = 1171445694, tmp)-(tmp = -1584666956, tmp))^(tmp = 1217545373, tmp))); - assertEquals(747032, x >>>= (-89332085)); - assertEquals(747032, x |= (x^(x^(x>>>x)))); - assertEquals(747032, x >>>= ((-1558482440)*((tmp = -2413907480, tmp)+(3003996862.384156)))); - assertEquals(7.747761349084291e+23, x += ((tmp = 518064022.64624584, tmp)*((tmp = 2001951702, tmp)*x))); - assertEquals(0, x <<= (2769324707.5640426)); - assertEquals(NaN, x %= (((((((-2458056470.7717686)&x)>>(tmp = -361831232.42602444, tmp))*(2611108609.6727047))>>>x)/(-1713747021.8431413))*(-1143281532))); - assertEquals(NaN, x %= ((x^((-613836813)*(tmp = -3180432597.0601435, tmp)))%x)); - assertEquals(NaN, x /= ((-1607092857)^x)); - assertEquals(0, x &= (-1190719534)); - assertEquals(0, x >>>= x); - assertEquals(0, x += (x>>(642177579.1580218))); - assertEquals(-3129552333, x += (-3129552333)); - assertEquals(1165414963, x &= x); - assertEquals(2222, x >>= (((tmp = 2606317568, tmp)|x)+(tmp = 1844107136, tmp))); - assertEquals(NaN, x %= ((x^x)<<(x/(((tmp = -1362148700, tmp)&((tmp = 76371048, tmp)<<x))>>>((x^(-2605741153))>>(((tmp = -2131608159.7634726, tmp)|(((2827792229.8004875)|(((-848439251)+(-2576768890.123433))|((tmp = -2617711776, tmp)-((-199980264)&((tmp = -46967951.76266599, tmp)/(-733253537))))))*(tmp = 1820087608, tmp)))>>>(tmp = -3118359396.4298744, tmp))))))); - assertEquals(NaN, x /= ((2144871731)*x)); - assertEquals(NaN, x *= x); - assertEquals(NaN, x %= (tmp = 234811462.08692443, tmp)); - assertEquals(0, x >>>= ((1121416685)|(x^(((tmp = -2905413334, tmp)<<(tmp = -3091554324.030834, tmp))<<x)))); - assertEquals(-55938048, x |= ((tmp = -55938048, tmp)+(x*(tmp = -1518809027.2695136, tmp)))); - assertEquals(-3.3234995678333864e-10, x /= (x*(tmp = -3008876576, tmp))); - assertEquals(0, x <<= (x/((((((-2168824234.2418427)>>(((tmp = 1976810951, tmp)%x)<<(x*(x>>(x%(3146266192))))))%(tmp = 1756971968.122397, tmp))>>>(-2859440157.8352804))/(-1001406.1919288635))>>>(-1358031926)))); - assertEquals(-0, x *= (tmp = -1756000533, tmp)); - assertEquals(-0, x %= (2522761446.869926)); - assertEquals(0, x >>>= (((1087690535)>>>(2741387979))^x)); - assertEquals(0, x -= x); - assertEquals(0, x >>= (-819422694.2188396)); - assertEquals(0, x ^= x); - assertEquals(NaN, x /= x); - assertEquals(0, x &= (tmp = 86627723, tmp)); - assertEquals(0, x += x); - assertEquals(0, x %= (tmp = -2317915475, tmp)); - assertEquals(Infinity, x += (((-3072799584)^(-2487458319))/(((tmp = -3050692353, tmp)&x)>>(-777977292.8500206)))); - assertEquals(Infinity, x += x); - assertEquals(Infinity, x -= (tmp = 484428269, tmp)); - assertEquals(Infinity, x *= x); - assertEquals(Infinity, x /= (2059586218.2278104)); - assertEquals(Infinity, x *= (tmp = 415918523.8350445, tmp)); - assertEquals(-1800869091, x |= (((-1800869091)>>>(x>>>(tmp = -2832575051, tmp)))>>>x)); - assertEquals(6196126991451132000, x *= ((-1467292383.8458765)+(-1973339154.7911158))); - assertEquals(6196126992684649000, x += (1233517421)); - assertEquals(1, x /= x); - assertEquals(-7153809722216516000, x -= (((-2984550787.146106)<<(tmp = 743743974, tmp))*((3155151275)/((-1771412568.8965073)%x)))); - assertEquals(-7153809721471491000, x -= (-745024056)); - assertEquals(5.117699353102001e+37, x *= x); - assertEquals(0, x >>= x); - assertEquals(-0, x *= ((-2651785447.666973)<<(-1124902998))); - assertEquals(-0, x /= (2119202944)); - assertEquals(1042673805.5205957, x -= ((x<<x)-(tmp = 1042673805.5205957, tmp))); - assertEquals(62, x >>>= (tmp = 2769597912.977452, tmp)); - assertEquals(34, x &= ((tmp = -61541150, tmp)%(x^(-943160469)))); - assertEquals(34, x ^= ((-2625482224.4605474)<<(-2277806338.3461556))); - assertEquals(536870912, x <<= ((-2373927426.4757633)^x)); - assertEquals(536870912, x &= x); - assertEquals(512, x >>>= ((-1626769708.310139)<<((tmp = 641796314, tmp)/(721629637.3215691)))); - assertEquals(0, x <<= (-113973033)); - assertEquals(NaN, x /= x); - assertEquals(NaN, x += (-1602711788.2390788)); - assertEquals(NaN, x *= (x%x)); - assertEquals(0, x &= (x<<(x|(x>>((x>>>(x%((1182960050)^(((-220896609)-((((tmp = 1518275435.360103, tmp)/(tmp = -88234820, tmp))^x)/x))>>(3169930777.548236)))))-(tmp = -2912668817.662395, tmp)))))); - assertEquals(0, x *= ((2323969408.7524366)/(((tmp = -3089229853, tmp)>>>((((tmp = -1012580544.5631487, tmp)>>(1138049418.9023373))>>x)&x))*(tmp = 626912001, tmp)))); - assertEquals(0, x >>>= x); - assertEquals(NaN, x /= (x%(-868024322))); - assertEquals(NaN, x /= (tmp = -1749532322, tmp)); - assertEquals(1861918711, x |= (-2433048585.853014)); - assertEquals(1861918711, x >>= (((102451747)>>>((((241651917.47259736)/((((((((1759022236)^(tmp = -2592022722, tmp))+((-1748044969)>>>(704597925)))/(-1639604842))%((1349846853.7345295)<<(-729695861)))/(x>>((tmp = -2654474404.7365866, tmp)>>x)))>>>(((-480356478)|(x%((tmp = -1668269244.6979945, tmp)+(tmp = -2441424458.565183, tmp))))^((1634981212.7598324)>>>(tmp = 122455570.22000062, tmp))))<<x))*((tmp = -1058636137.5037816, tmp)+((2794083757.138838)&((x/(50081370))&x))))/x))/((tmp = -243106636, tmp)<<((x*((tmp = -648475219.5971704, tmp)>>((tmp = -1568913034, tmp)-((tmp = 911458615, tmp)|x))))>>>(tmp = 2714767933.920696, tmp))))); - assertEquals(0, x ^= x); - assertEquals(-2080484602, x |= (((1544771831.4758213)|x)^(-538113039))); - assertEquals(696451072, x <<= (tmp = -1587032689, tmp)); - assertEquals(-162595645, x += (tmp = -859046717, tmp)); - assertEquals(516546456, x >>>= x); - assertEquals(623083588, x += ((-1371850352)^(tmp = -1469933252, tmp))); - assertEquals(92342412, x %= (tmp = -132685294, tmp)); - assertEquals(500272110, x |= ((tmp = 1616032506, tmp)%((tmp = 1589569590.4269853, tmp)|(-972791738.1829333)))); - assertEquals(3247086, x %= (((tmp = 1372216208, tmp)|(-638950076.3387425))&((-2619249161.849716)&(73957896)))); - assertEquals(0, x >>>= (tmp = -1482343462.6911879, tmp)); - assertEquals(1265125662, x ^= (tmp = -3029841634, tmp)); - assertEquals(4941897, x >>>= (-2039728632)); - assertEquals(206857, x &= (tmp = 226962365.45571184, tmp)); - assertEquals(1.0925018562586405e+24, x += ((tmp = 2687424146, tmp)*(((-1998020319)%x)*(-2080331363)))); - assertEquals(-1.755270751212437e+32, x *= (-160665242)); - assertEquals(0, x <<= (3152796521.6427975)); - assertEquals(0, x ^= ((((((tmp = -855001595, tmp)<<(2007525777))-(x-(x-x)))/(3036585090.9701214))&(1827983388))*((tmp = -915604789.0515733, tmp)&(((((tmp = -806628722.7820358, tmp)%x)/(tmp = -2773117447, tmp))|x)<<(((tmp = -2902300974.7300634, tmp)|x)/(-1608133440)))))); - assertEquals(0, x |= ((((((119024954)*(((x^(tmp = 2939514414, tmp))|x)^(x-(tmp = -1597415597.6795669, tmp))))+(((tmp = -182277816.14547157, tmp)<<(((-2983451324.3908825)^(tmp = 1572568307, tmp))+(-1165604960.8619013)))/(x>>((tmp = -2127699399, tmp)>>((x^(((((tmp = -1968667383, tmp)^(tmp = 3120052415.9964113, tmp))|(((x|(((x^((tmp = 2831505153, tmp)<<((-3150506831.547093)+((x%(tmp = 383761651, tmp))%(2856803457)))))+(((tmp = -2426953997, tmp)^(tmp = -2667954801.1010714, tmp))*(tmp = -2707801631, tmp)))&(tmp = 2082935238.794707, tmp)))^((tmp = 697573323.5349133, tmp)-x))%(tmp = 661936357, tmp)))/(-1717944600.261446))>>>((2423776015.0968056)^((-1410322010)|((x<<(tmp = 2935993226, tmp))/(tmp = -1533896392, tmp))))))*(tmp = -596675330, tmp))))))>>>(((2944268153)^(x&(144579050.93126357)))/(-2123810677.2619643)))>>>(1473040195.9009588))*x)); - assertEquals(0, x /= (2877666495)); - assertEquals(2174852514, x -= (tmp = -2174852514, tmp)); - assertEquals(543713128, x >>>= x); - assertEquals(2978128878.939105, x += (tmp = 2434415750.939105, tmp)); - assertEquals(3529591145844655600, x *= (tmp = 1185170719.3753138, tmp)); - assertEquals(659, x >>>= ((((((x<<(((((-425423078)/(((tmp = 160617689.20550323, tmp)&(-1524740325.5003028))%(tmp = -1869426475, tmp)))<<(((x^(-487449247))>>>(tmp = -1962893666.7754712, tmp))%x))*x)>>((tmp = 623413085, tmp)&(x+(((((-2200726309.083274)-(x-x))+x)&(-1304849509))|((((tmp = -431896184, tmp)>>>(x>>(-1932126133)))<<((1078543321.2196498)*(-10761352)))>>(tmp = -2681391737.5003796, tmp)))))))/x)-(tmp = -1768629117, tmp))/(((((tmp = -2320718566.0664535, tmp)%x)+(-2831503351.995921))>>>(-2695416841.3578796))*(943979723)))<<x)|((652520546.7651662)>>(1045534827.6806792)))); - assertEquals(531, x &= (tmp = -293707149, tmp)); - assertEquals(0, x >>= (tmp = -678056747.5701449, tmp)); - assertEquals(1184651529.8021393, x += (tmp = 1184651529.8021393, tmp)); - assertEquals(1721719611, x |= (tmp = 1645413178, tmp)); - assertEquals(-406880257, x |= (tmp = 2268544460, tmp)); - assertEquals(-4194304, x <<= (tmp = -109701322.43455839, tmp)); - assertEquals(17592186044416, x *= x); - assertEquals(0, x ^= (x&x)); - assertEquals(0, x <<= (tmp = 1715401127, tmp)); - assertEquals(-1793087394, x |= (tmp = -1793087394.730585, tmp)); - assertEquals(-2, x >>= x); - assertEquals(263607360.10747814, x += (tmp = 263607362.10747814, tmp)); - assertEquals(1073214955, x |= (893759979.3631718)); - assertEquals(703953930, x -= ((2738450011)%(x^(tmp = 679402836, tmp)))); - assertEquals(1, x >>= (tmp = 2262515165.6670284, tmp)); - assertEquals(0, x >>= (((tmp = 747896494, tmp)^((tmp = -1005070319, tmp)+x))|x)); - assertEquals(0, x >>= ((953612771)>>>(tmp = 3066170923.3875694, tmp))); - assertEquals(-314941454, x -= (x+(((314941454)%(((tmp = 2200222912.9440064, tmp)>>>(2534128736.805429))>>>(x|((747716234)%(((tmp = -252254528, tmp)%(-1553513480.1875453))&x)))))<<x))); - assertEquals(-535686958, x &= (-522809126)); - assertEquals(0.5480312086215239, x /= (tmp = -977475278, tmp)); - assertEquals(-1199953459.6090598, x *= ((-2189571393)+((3186862741.37774)>>(tmp = -2193090564.5026345, tmp)))); - assertEquals(-1199953459.6090598, x %= ((tmp = 2986532440, tmp)*(2685122845))); - assertEquals(-1199953459.6090598, x %= (1951182743.7399902)); - assertEquals(51262285383887820, x *= (-42720228)); - assertEquals(-424776752, x |= x); - assertEquals(166221344210236600, x *= (tmp = -391314598.6158786, tmp)); - assertEquals(-1883425600, x >>= (((tmp = -1020679296, tmp)^((-1416867718)+(-1412351617)))<<(-2743753169))); - assertEquals(0, x &= (x/(-2250026610))); - assertEquals(-1111956501, x ^= (tmp = 3183010795, tmp)); - assertEquals(2012059503, x ^= (tmp = -900369276, tmp)); - assertEquals(15719214, x >>>= (tmp = -3196277049, tmp)); - assertEquals(15719214, x |= x); - assertEquals(100779035, x -= ((-1245802025)^(-2964289852))); - assertEquals(0, x >>= x); - assertEquals(0, x &= (((x<<((2361941389.708063)%x))>>((328256762.09842086)>>>((((tmp = 3094192285, tmp)-(((x>>(tmp = -2920437464, tmp))<<(tmp = -2693021467, tmp))-(x>>>((2410065554)%(x%(tmp = 2487056196.689908, tmp))))))-(tmp = -866314146, tmp))^((1754098471)-((((((-2450740191)-(tmp = 1977885539.6785035, tmp))*((tmp = -1205431332, tmp)>>>x))>>(-870601854))>>(tmp = -301859264, tmp))|((tmp = -2308971516.8301244, tmp)/x))))))&((2307007357)-((tmp = -1518812934, tmp)+(2562270162))))); - assertEquals(0, x <<= x); - assertEquals(-1802124619, x |= (-1802124619)); - assertEquals(-1802124619, x %= ((1617132364.306333)+((1678465962.079633)|((516698570)%(((569813606)*(-1800804098.6270027))%((tmp = 1976706935, tmp)-((tmp = -1830228989.5488424, tmp)>>(((x^((tmp = 1015246068.3791624, tmp)>>x))^((-2171682812.246772)-(tmp = -398330350, tmp)))&x)))))))); - assertEquals(904564673.6237984, x -= (tmp = -2706689292.6237984, tmp)); - assertEquals(818237248768128900, x *= x); - assertEquals(254842325.2585001, x %= (1550087667.9657679)); - assertEquals(-1163919360, x <<= x); - assertEquals(-3.4644526843674166, x /= ((-446801454)+(x>>>(tmp = -2025151870, tmp)))); - assertEquals(0, x &= ((((((((-1739617728)&(x&(((tmp = -2946470036.552597, tmp)/x)*x)))^(-1130501404))>>>x)/((1870230831)>>>(840301398)))%x)/x)/(-2927537567))); - assertEquals(0, x >>= x); - assertEquals(0, x >>>= (x&(x&x))); - assertEquals(0, x &= ((-579614044)-(-756012505.4048488))); - assertEquals(-2970367642, x -= (tmp = 2970367642, tmp)); - assertEquals(-415129376, x ^= (tmp = 2847041926.060355, tmp)); - assertEquals(-1505681312, x &= (tmp = -1225184902.9215767, tmp)); - assertEquals(-3174471329.5807734, x += (-1668790017.5807734)); - assertEquals(-Infinity, x /= (x>>x)); - assertEquals(NaN, x -= x); - assertEquals(0, x ^= (x^(((-1407936301.5682082)<<((x^(((tmp = 3213446217.307076, tmp)|x)|((tmp = 3219810777.3171635, tmp)/(tmp = 1561807400, tmp))))>>>((tmp = 2449910203.0949173, tmp)|((((1954662538.7453175)>>(tmp = -1711636239.9916713, tmp))>>>(tmp = 406219731.214718, tmp))<<(((-907908634.4609842)^((((((tmp = 2408712345, tmp)*(tmp = 1740346634.5154347, tmp))>>(tmp = 715783991, tmp))^(tmp = -655628853.2821262, tmp))%(tmp = 2819143280.434571, tmp))/(-1240412852)))*x)))))/x))); - assertEquals(0, x >>>= x); - assertEquals(0, x <<= x); - assertEquals(0, x >>>= (((-3198075268.8543105)>>(((((x+((tmp = -133461401.50823164, tmp)-((x&(((((tmp = 2617977319, tmp)>>((tmp = -2704719576.8734636, tmp)|((tmp = -977362542.2423751, tmp)<<(x<<(tmp = 3054487697.1441813, tmp)))))>>>((-1635655471)%x))/(-2079513672))%(tmp = 1993563806, tmp)))<<(tmp = -1310524200.6106496, tmp))))%((((-2558804500.7722936)+(tmp = -1641265491, tmp))<<((tmp = -1309608349, tmp)>>>x))/((tmp = -2306644272, tmp)<<x)))*(-2009396162.3063657))+(267343314.3720045))-(-2212612983.661479)))|x)); - assertEquals(NaN, x %= x); - assertEquals(NaN, x *= x); - assertEquals(-824822309, x |= (-824822309)); - assertEquals(-807944741, x |= (((-598067403)*((x&(tmp = 2897778389, tmp))>>>(-1322468310.3699632)))|x)); - assertEquals(90004223.44097246, x /= (((tmp = -481122620, tmp)&x)%((tmp = 1109368524, tmp)/(((-3150568522.633032)<<(tmp = 2923396776, tmp))^(x-((x/x)&(x/(-287976185.1049104)))))))); - assertEquals(0.4521931751193329, x /= (tmp = 199039323, tmp)); - assertEquals(1.8110466604491368e-10, x /= (2496860986.492693)); - assertEquals(0, x |= x); - assertEquals(-1225944576, x += ((tmp = -807700791.631221, tmp)<<((-700782615.4781106)-((((-2954619897)>>>x)<<((tmp = 997657844, tmp)>>>(1227994596)))/((-1234591654.8495834)*((tmp = -191189053.70693636, tmp)+(tmp = -3027659304, tmp))))))); - assertEquals(-1225811383, x |= (-1866233271)); - assertEquals(3069155913, x >>>= (((x/(-99524153.40911508))%(x>>>((((tmp = 2985975640, tmp)/(tmp = 2781516546.2494454, tmp))&(((2234114508)|(((x/(tmp = -1224195047, tmp))<<x)^(x>>>((537884375.5698513)+x))))^((tmp = -2144817497.5089426, tmp)|(-498079183.8178189))))>>>((x+x)&(-3086080103.6460695)))))<<(((tmp = 2151157136, tmp)*x)/(((x/x)>>>(-1149734628.4364533))-((3025445835.654089)+(tmp = 530902725.91127443, tmp)))))); - assertEquals(-1733702568, x ^= (tmp = 776361489.423534, tmp)); - assertEquals(8981504, x &= ((tmp = 2902581847, tmp)*(x-(-2697760560)))); - assertEquals(1153166.8526612986, x -= ((x/(tmp = -1375025594.5027463, tmp))+((3043576689.1538706)%(x+x)))); - assertEquals(3389855, x |= (x+x)); - assertEquals(-488458393.17759943, x += (-491848248.17759943)); - assertEquals(40982867145206920, x *= ((3132857155)|(tmp = -218356553, tmp))); - assertEquals(688, x >>= (((((tmp = 403321821, tmp)+((tmp = 2536984658, tmp)%((tmp = 2759309029.8753624, tmp)|(((tmp = 1994203554.7417293, tmp)^((704660500.434877)*(tmp = 1536292958.2691746, tmp)))+(-164139788)))))/((1205950994.1255205)+x))^((((tmp = 975272146.0133443, tmp)-(150107797))/(-1764309514))^((x>>>(x^(x^x)))+(203250124))))>>>(tmp = 1864959239.512323, tmp))); - assertEquals(10, x >>= ((tmp = 1631996431.9620514, tmp)>>x)); - assertEquals(10, x %= (tmp = 2678904916, tmp)); - assertEquals(335544320, x <<= (tmp = -2759037415.6811256, tmp)); - assertEquals(-153389967, x |= ((tmp = -2411636565, tmp)+(tmp = -2305156154, tmp))); - assertEquals(-1171, x >>= x); - assertEquals(813080576, x &= (((tmp = -65428547, tmp)&(tmp = 3163266999, tmp))<<x)); - assertEquals(4346532303, x += ((tmp = -761515569.0707853, tmp)>>>(((tmp = 143240971.0661509, tmp)<<x)*(x^((tmp = -271697192.8471005, tmp)&x))))); - assertEquals(-863299035, x ^= ((((2663001827.1492147)>>>((x/(((tmp = 482665912, tmp)-(x>>(tmp = 354425840.784659, tmp)))>>((-2012932893)>>>x)))/((tmp = -1354385830.6042836, tmp)>>>(-2149023857))))^((tmp = 585746520, tmp)+(tmp = 756104608, tmp)))^(517529841.184085))); - assertEquals(-997654012, x &= (((tmp = -404836025.15326166, tmp)+((tmp = 3035650114.0402126, tmp)<<((-1308209196)>>(tmp = 693748480, tmp))))<<(((465774671.4458921)<<x)/(1971108057)))); - assertEquals(-320581507110848260, x *= ((x-(tmp = -2266777911.7123194, tmp))^(tmp = -2810021113.304348, tmp))); - assertEquals(-320581508271196300, x += ((-1195215841.5355926)|(x-((2715907107.4276557)+(((-843426980)>>(x&(x%(tmp = -1139279208.34768, tmp))))^x))))); - assertEquals(368031616, x &= x); - assertEquals(368031616, x %= (tmp = 1211767328, tmp)); - assertEquals(-67505614939510744, x *= (tmp = -183423412.56766033, tmp)); - assertEquals(959424552, x >>= ((tmp = -171120122.5083747, tmp)/x)); - assertEquals(30949179.096774194, x /= (((x-((((x&(tmp = -180770090, tmp))<<(((tmp = -2061363045.419958, tmp)*((655711531)^((1205768703)-(tmp = 2468523718.8679857, tmp))))+(-2746704581)))+((-853685888)*(tmp = -2299124234, tmp)))|(tmp = 2429502966, tmp)))|(((-985794986.0232368)>>>(2890862426))%x))>>(tmp = 1005542138.8415397, tmp))); - assertEquals(30949179, x |= x); - assertEquals(30949179, x %= (810126097.6814196)); - assertEquals(120895, x >>= (tmp = 3065886056.1873975, tmp)); - assertEquals(1934320, x <<= (1478650660.7445493)); - assertEquals(0, x >>= (1069658046.2191329)); - assertEquals(NaN, x %= x); - assertEquals(NaN, x %= (x*x)); - assertEquals(NaN, x *= ((((2148513916)+(tmp = -210070225.85489202, tmp))>>(975470028))+((-3060642402)>>x))); - assertEquals(NaN, x *= (2888778384)); - assertEquals(NaN, x -= (294531300.16350067)); - assertEquals(-465620423, x ^= (tmp = -465620423.5891335, tmp)); - assertEquals(1613303808, x &= (-2530649850.1952305)); - assertEquals(2045458658, x |= (tmp = 432158946.5708574, tmp)); - assertEquals(0, x >>>= (2277328255.770018)); - assertEquals(0, x &= (-64904722.41319156)); - assertEquals(0, x >>= x); - assertEquals(3109394857.361766, x += (3109394857.361766)); - assertEquals(1519021650, x ^= ((tmp = -2632472653, tmp)|(tmp = 2161964921.8225584, tmp))); - assertEquals(370854, x >>>= ((1486892931.4564312)-((tmp = 3017755741.9547133, tmp)>>>x))); - assertEquals(1333145110.39802, x -= ((-1051580495.39802)-(tmp = 281193761, tmp))); - assertEquals(0, x ^= x); - assertEquals(0, x |= x); - assertEquals(0, x <<= x); - assertEquals(0, x >>>= x); - assertEquals(799202788.1455135, x -= (tmp = -799202788.1455135, tmp)); - assertEquals(1539080192, x <<= (x%(((((x-x)|(((((x%(959993901))+(tmp = -2647575570.092733, tmp))/(tmp = -2040600976.5104427, tmp))*(x*(tmp = 2785252760, tmp)))>>(-377867259)))/((x&(1549738240.013423))>>>(tmp = -1502185618, tmp)))*x)%(1159283801.0002391)))); - assertEquals(0, x >>= (-268660225)); - assertEquals(-0, x /= (-2795206270.635887)); - assertEquals(0, x >>>= (1869556260.2489955)); - assertEquals(64202212, x ^= ((((tmp = -942983515.5386059, tmp)*(((1057759788)-x)*(tmp = 2038041858, tmp)))>>x)+(tmp = 64202212, tmp))); - assertEquals(2021126977, x -= ((tmp = -2009912898, tmp)^((2240062309)%x))); - assertEquals(4332348265459724000, x *= (tmp = 2143530968, tmp)); - assertEquals(1472, x >>>= ((283380755)<<x)); - assertEquals(-1672370407872, x *= (tmp = -1136121201, tmp)); - assertEquals(338573318, x ^= (tmp = 2329579078.4832354, tmp)); - assertEquals(2377388772.1662374, x -= (tmp = -2038815454.1662374, tmp)); - assertEquals(-1.264761712403516, x /= ((((tmp = -2106209534, tmp)>>((((((tmp = 626190172, tmp)/x)>>>(-824270996.8545206))/((1258369810.9498723)-(tmp = -2947556209, tmp)))^((((366784589.24711144)|(1462064104.828938))-(1571045395.777879))<<(444685689.60103726)))>>(tmp = -2757110357.410516, tmp)))/(x>>>((tmp = 829226010, tmp)>>>(629512715))))|x)); - assertEquals(-2905481691.264762, x -= (2905481690)); - assertEquals(-1710543566.1481905, x -= (-1194938125.1165714)); - assertEquals(-3421087132.296381, x += x); - assertEquals(-884178944, x <<= ((-1820881235)|x)); - assertEquals(-884178944, x &= (x%(tmp = -2298828530, tmp))); - assertEquals(1516503040, x <<= ((tmp = -3039882653, tmp)+((tmp = 1956034508, tmp)<<(x>>(tmp = 280388051, tmp))))); - assertEquals(3033006080, x += x); - assertEquals(846431222.321887, x %= (x+(-1939718651.1609435))); - assertEquals(-846431224, x ^= ((-1742116766.54132)/x)); - assertEquals(1157918728, x &= (tmp = 1966568030, tmp)); - assertEquals(1157918728, x >>>= ((((((tmp = -2392096728.184257, tmp)*(x&(-3051259597.301086)))>>>(((tmp = 1712991918.071982, tmp)*(tmp = -714525951, tmp))-((-1784801647)>>((-1270567991)%(((214272558)/(((-3110194570)|(tmp = 2558910020, tmp))&(-1266294955.717899)))*((2654922400.609189)>>>(tmp = 370485018, tmp)))))))*(((tmp = -2621203138.1838865, tmp)%(858913517))*((tmp = -1564229442.2596471, tmp)>>((tmp = 1898557618, tmp)|(-1282356275)))))*(tmp = -1253508468, tmp))+((-361964404.75944185)|x))); - assertEquals(961668975, x += (-196249753)); - assertEquals(1, x >>= (tmp = 890453053, tmp)); - assertEquals(1, x >>= (((((tmp = 871309275, tmp)/(x>>>((tmp = 2033022083, tmp)&(tmp = -1393761939, tmp))))%((437488665.104565)^(tmp = 2808776860.4572067, tmp)))-((tmp = -359283111.49483967, tmp)<<((tmp = 2985855945, tmp)%(tmp = -596479825.9114966, tmp))))/(-1965528507))); - assertEquals(0, x >>= ((tmp = -1753776989, tmp)%(tmp = 322622654, tmp))); - assertEquals(84411424, x ^= (((x|(x|(tmp = -1617122265, tmp)))&(tmp = -313813263, tmp))&(1472888112.0258927))); - assertEquals(67633184, x &= ((1556833131.0776267)<<(x<<(1501219716.5575724)))); - assertEquals(68002293, x |= (((tmp = 188984203.0350548, tmp)>>>(tmp = 1356052777, tmp))%(x*(tmp = -2944960865, tmp)))); - assertEquals(67108864, x &= (((1046644783.9042064)<<x)+((-2796345632)>>>(((-1913290350.3687286)<<(((((tmp = -2223692353, tmp)>>x)&(x<<(x>>((((tmp = -976850020, tmp)%(tmp = 1379692507, tmp))>>>(1120103052.2077985))>>(tmp = 5592070.612784743, tmp)))))<<(x+((tmp = -3154037212.9764376, tmp)%(((x-(-1961060483.6965141))+(((1920670676)-(2852444470.7530622))/(((1445954602)>>((1353665887)>>(tmp = 111411560.64111042, tmp)))<<x)))+x))))<<((-1773130852.6651905)^((1216129132)>>(1511187313.2680469)))))|((tmp = -1107142147, tmp)|(tmp = -768165441.4956136, tmp)))))); - assertEquals(0, x -= x); - assertEquals(0, x %= (tmp = -1655707538.0778136, tmp)); - assertEquals(-184120712930843900, x += (x+((tmp = -3174410166, tmp)+((tmp = -301807453, tmp)*(tmp = 610060182.1666535, tmp))))); - assertEquals(-54598560, x >>= (-1365351357)); - assertEquals(-6763.94449950446, x /= (((-1953016847)<<((673287269.7002038)%(-558739761)))>>>(tmp = 1607754129, tmp))); - assertEquals(-1, x >>= x); - assertEquals(1, x >>>= x); - assertEquals(0, x >>>= x); - assertEquals(0, x >>= ((-384747983)+((((tmp = -949058352.381772, tmp)>>>(-1920744986))-(-882729639))^((x^((tmp = 2351364046, tmp)<<(((tmp = -3110165747, tmp)^(-1266489735))-((tmp = -371614326, tmp)>>((tmp = -2064968414, tmp)&(-2075036504.617934))))))&(((-2616501739)&(tmp = 2591437335.4029164, tmp))>>x))))); - assertEquals(0, x >>>= ((tmp = 2946468282, tmp)&((-2741453019)>>x))); - assertEquals(0, x -= ((x%(-134700915))&(-1955768279))); - assertEquals(NaN, x /= x); - assertEquals(NaN, x /= (x^(((((((tmp = 3185669685.772061, tmp)>>(tmp = -1973500738, tmp))-(tmp = -87401348.93002152, tmp))>>(tmp = -2813508730, tmp))&(tmp = -778957225, tmp))<<(x-(x&((-2821756608)+(((((tmp = 2475456548, tmp)/(tmp = 997998362, tmp))<<((tmp = -83043634, tmp)|x))%(636120329))%(tmp = -1910213427.7556462, tmp))))))%x))); - assertEquals(0, x &= x); - assertEquals(0, x <<= x); - assertEquals(0, x >>>= (x%x)); - assertEquals(0, x %= (745221113)); - assertEquals(0, x >>>= ((1467615554.7672596)|x)); - assertEquals(0, x /= (tmp = 735317995, tmp)); - assertEquals(-1513001460, x |= (2781965836)); - assertEquals(-1513001460, x |= (x%(1970577124.3780568))); - assertEquals(-0, x %= x); - assertEquals(1864972269, x ^= (-2429995027.840316)); - assertEquals(1226843341, x &= (tmp = -639621923.5135081, tmp)); - assertEquals(1226843339.3171186, x += ((1297620268.272113)/(-771070549))); - assertEquals(76677708, x >>>= (1009134980)); - assertEquals(0, x ^= x); - assertEquals(0, x ^= x); - assertEquals(NaN, x /= x); - assertEquals(716040787, x |= ((1851586229)-(1135545441.3502865))); - assertEquals(1385693184, x <<= x); - assertEquals(1321, x >>= (x^((tmp = -1576632297.0860603, tmp)>>>(405218605)))); - assertEquals(-1319012931, x |= (-1319014243)); - assertEquals(-1319012931, x >>= ((((1689898279.3580785)<<((((x^(x>>>((((tmp = 2635260332, tmp)*(tmp = 2053357650, tmp))*x)*(2856480122.339903))))>>x)&(-2382703000.077593))%(1183918594)))*(tmp = -1670081449, tmp))<<x)); - assertEquals(-528327581.7646315, x %= (tmp = -790685349.2353685, tmp)); - assertEquals(2073431790, x ^= (tmp = 2601800333, tmp)); - assertEquals(-6514722684180, x -= (((tmp = 824141806.0668694, tmp)>>>(((-1865885282.8723454)&(x&(x|((900188006.3757659)>>>(x&x)))))+(2227126244.0526423)))*x)); - assertEquals(1450593, x >>>= ((2157053647)>>(x+(-2934071355.418474)))); - assertEquals(576782336, x <<= ((1054640368.827202)&((tmp = -3182236876.434615, tmp)>>(tmp = 2129856634.0328193, tmp)))); - assertEquals(2950754326, x -= (tmp = -2373971990, tmp)); - assertEquals(738197504, x <<= (1188157369.5988827)); - assertEquals(0, x <<= (x+((tmp = -839533141, tmp)&((((((tmp = -1148768474.7306862, tmp)|(172650299))+(tmp = -2739838654, tmp))/(3132557129))%x)>>>(tmp = -1229961746.2466633, tmp))))); - assertEquals(0, x %= (tmp = -2974207636, tmp)); - assertEquals(0, x %= ((2323482163)>>>x)); - assertEquals(0, x &= (((x/(x+(x>>((tmp = 55935149, tmp)%x))))|((3109182235)>>>(tmp = 1217127738.8831062, tmp)))+((((tmp = -385114910, tmp)*((((((tmp = -2535158574.634239, tmp)&(x+x))<<(-2821692922.43476))&(-776804130.9457026))>>((-1374832535)^(tmp = 2175402162.701251, tmp)))%(-1646995095)))-(x*(tmp = -921556123, tmp)))^(79224621)))); - assertEquals(128935435, x |= ((tmp = 2279459038, tmp)%(tmp = -537630900.5271742, tmp))); - assertEquals(128935435, x /= ((((((x<<(2750024311))-((-1332480769.4784315)&(1418160003)))&(1551783357))<<(((((-2870460218.55027)|((-1958752193.7746758)&(2551525625)))>>>((((tmp = -1698256471, tmp)^(((((((((tmp = -830799466, tmp)+x)-(-111590590))+(tmp = -1105568112.3921182, tmp))/((tmp = -3058577907, tmp)|(((-1944923240.2965696)%(-2884545285))<<(tmp = -1993196044.1645615, tmp))))^(x>>(tmp = -2961488181.3795304, tmp)))&x)*x)|(((tmp = 97259132.88922262, tmp)<<((1601451019.343733)&x))*(x|x))))+((((x>>x)<<x)+(-868409202.2512136))/(((tmp = -2893170791, tmp)-((x|(-853641616))%(((tmp = 549313922, tmp)&(-768036601.6759064))%(tmp = -543862220.9338839, tmp))))-((tmp = 1639851636, tmp)+((2164412959)/(-273028039.941242))))))>>>((((-2382311775.753495)^(-2062191030.2406163))>>>(tmp = -1054563031, tmp))/(-862111938.7009578))))%x)+(-3103170117.625942)))%((tmp = -1144062234, tmp)>>x))>>>(tmp = 1216332814.00042, tmp))); - assertEquals(41.631074722901715, x /= (x&(-2542806180.962227))); - assertEquals(41.631074722901715, x %= (-14003386.556780577)); - assertEquals(8, x &= (x&((-2231622948)%(tmp = 488279963.9445952, tmp)))); - assertEquals(9.002961614252625e-9, x /= ((53802728.56204891)<<(((867697152.3709695)-(538719895.5707034))&(-631307825.4491808)))); - assertEquals(0, x >>= x); - assertEquals(-0, x *= (tmp = -785674989, tmp)); - assertEquals(-0, x += x); - assertEquals(0, x /= (-250703244)); - assertEquals(0, x <<= ((tmp = -661062581.5511999, tmp)|x)); - assertEquals(0, x &= (-1299482308)); - assertEquals(0, x &= ((-399690060)>>>(2448074202.385213))); - assertEquals(0, x &= (2574341201)); - assertEquals(0, x <<= ((x|(((tmp = 2458873162.645012, tmp)+(tmp = -1999705422.8188977, tmp))<<((x^(tmp = -392530472, tmp))>>>x)))&(((tmp = 2463000826.7781224, tmp)|(tmp = 3020656037, tmp))-x))); - assertEquals(1397603760, x += ((tmp = -1359413071, tmp)-(tmp = -2757016831, tmp))); - assertEquals(513823851, x -= (883779909)); - assertEquals(-1765712747, x ^= (2288060670.6797976)); - assertEquals(3117741504918286000, x *= x); - assertEquals(3117741506284045300, x += (1365759456)); - assertEquals(6035555595.597267, x /= (tmp = 516562470, tmp)); - assertEquals(104203275, x &= (tmp = 376835755.32434213, tmp)); - assertEquals(10858322520725624, x *= x); - assertEquals(59458951, x >>>= (153765028)); - assertEquals(49370856, x += ((tmp = -1291276092, tmp)>>x)); - assertEquals(0, x %= x); - assertEquals(0, x += x); - assertEquals(-1494589645, x -= (1494589645)); - assertEquals(-0, x %= x); - assertEquals(0, x <<= (x&((2730708043.467806)<<x))); - assertEquals(0, x /= ((tmp = -1483912394.153527, tmp)>>>((tmp = 1800568769, tmp)^((((((tmp = 1351568510, tmp)>>(tmp = -1337992543.2562337, tmp))>>>(tmp = 2602239360.40513, tmp))*x)%x)+(-2095840128.0700707))))); - assertEquals(-0, x /= ((2363946613)^(tmp = -2227868069, tmp))); - assertEquals(0, x &= ((((2634933507)<<(2798775374.140882))>>>x)>>>(((tmp = 1135200853.6396222, tmp)-(tmp = -1529829490.7007523, tmp))-(((((((((x^((x|(2135742668.591568))-(924230444.8390535)))%(tmp = -2459525610.51898, tmp))+(x&((tmp = 1177231743.809653, tmp)/(tmp = 1743270357.2735395, tmp))))|(((tmp = -1894305017, tmp)^((tmp = 1791704240, tmp)&x))%(-1569751461)))>>>(tmp = -2078321944, tmp))|x)*(((x*(tmp = -163239354, tmp))<<((tmp = 2859087562.694203, tmp)&(-657988325.9410558)))^(2508013840)))-((-243572350)+(x%((-1095206140)+((tmp = 3213566608.942816, tmp)*((2256442613)%((tmp = 1723751298, tmp)^(x-((-1145710681.2693722)|x)))))))))+(1556870627))))); - assertEquals(130883024.97423434, x -= (-130883024.97423434)); - assertEquals(0.046720352789736276, x /= (tmp = 2801413456, tmp)); - assertEquals(1806558189, x |= (tmp = 1806558189.157823, tmp)); - assertEquals(72.40475060062144, x /= (x%((1932591076.531628)>>(1982030182)))); - assertEquals(-1077558321.5975945, x += (tmp = -1077558394.002345, tmp)); - assertEquals(98187, x >>>= x); - assertEquals(97792, x &= (tmp = -1032487404, tmp)); - assertEquals(709197609, x |= (x^(709179177))); - assertEquals(11081212, x >>>= (tmp = 1412940006.169063, tmp)); - assertEquals(11081212, x &= x); - assertEquals(-1920311203, x -= ((tmp = 1931392415, tmp)<<((x%(tmp = -2873576383, tmp))%x))); - assertEquals(-1920311203, x |= (x&(-993884718.2172024))); - assertEquals(-4, x >>= (1409411613.0051966)); - assertEquals(-7947632484, x *= ((-2856731734)^((-1181032235.9132767)-((tmp = 780101930, tmp)+((tmp = -1732707132.6253016, tmp)^x))))); - assertEquals(-2016362769, x ^= (tmp = 2711125619.2455907, tmp)); - assertEquals(-61535, x >>= x); - assertEquals(-124771649, x ^= (tmp = 124726558, tmp)); - assertEquals(-1, x >>= x); - assertEquals(-0, x %= (x*x)); - assertEquals(0, x <<= x); - assertEquals(0, x /= (2444628112)); - assertEquals(0, x <<= ((-38968517.72504854)<<x)); - assertEquals(-1504619917, x |= (tmp = 2790347379, tmp)); - assertEquals(-1504619917, x &= x); - assertEquals(2790347379, x >>>= ((1825218368)<<(-1843582593.2843356))); - assertEquals(7786038495492170000, x *= x); - assertEquals(-11011696, x |= (((tmp = 2931644407.4936504, tmp)-(3077095016.001658))%(tmp = -1731851949, tmp))); - assertEquals(-107866, x %= ((-697845074.1661191)>>(772708134))); - assertEquals(356779149, x ^= (-356884949.503757)); - assertEquals(0, x %= x); - assertEquals(0, x *= ((tmp = 1542291783, tmp)^x)); - assertEquals(0, x += ((tmp = 1105314644.002441, tmp)&x)); - assertEquals(-1005882993, x ^= (-1005882993.0899806)); - assertEquals(-1301065066, x += (tmp = -295182073, tmp)); - assertEquals(-1454702592, x <<= ((-2440858737.390277)&(-1363565201.7888322))); - assertEquals(-201539012492525570, x *= ((((tmp = -1416268089, tmp)|x)-(tmp = 1669129769, tmp))&(x<<((x/(-2614041678.7423654))%x)))); - assertEquals(-2.1995276811535986e+25, x *= (x/(-1846667987.154371))); - assertEquals(0, x |= ((x*(((x>>>((tmp = 1044173034, tmp)>>>((x<<((tmp = -2906412863, tmp)%((tmp = -437401503, tmp)<<(((((x|(2167319070))<<((tmp = 2766179640.1840167, tmp)&(-2372076054)))*(tmp = -241617431.06416297, tmp))*((((((tmp = 2570465382.5574293, tmp)>>>(x/((-2851324509.354545)%x)))>>(((x+((tmp = -614687945, tmp)^x))^((((tmp = 1653437743, tmp)>>x)/(tmp = 3072995069, tmp))>>x))*(((((-290508242)>>((tmp = 2969511554, tmp)<<(tmp = 158176292.95642304, tmp)))<<(32376015))+(tmp = 2391895870.4562025, tmp))*x)))&((((x/(tmp = 365292078.53605413, tmp))>>x)/(1167322811.0008812))|(((tmp = 2487970377.365221, tmp)^x)<<((tmp = 2342607988.711308, tmp)/(((2276081555.340126)-(((tmp = -2571071930, tmp)>>(tmp = -248468735.76550984, tmp))>>>(tmp = -2862254985.608489, tmp)))^(-1312017395))))))<<x)&(2762717852.949236)))+((((-2492896493)&x)<<(-2756272781.4642315))/x)))))*(2405395452))))>>((-1433975206)/((tmp = -2064757738.6740267, tmp)<<((((tmp = -1563531255, tmp)-(-589277532.2110934))<<x)^(2249328237.0923448)))))-x))-(-225624231))); - assertEquals(0, x *= (tmp = 1657982666.2188392, tmp)); - assertEquals(86443387, x |= (tmp = 86443387.25165462, tmp)); - assertEquals(86443387, x %= (-1341731981.702294)); - assertEquals(172886774, x <<= ((-1799840391)&(1011948481.310498))); - assertEquals(-1115684864, x <<= x); - assertEquals(-2098253702059525600, x *= (1880686715.1865616)); - assertEquals(-2098253700213206300, x -= (tmp = -1846319435.0583687, tmp)); - assertEquals(570692096, x &= (((tmp = -1572055366.64332, tmp)%(tmp = 1720120910, tmp))%((x-(912386952.5959761))*(tmp = -1146251719.4027123, tmp)))); - assertEquals(603979776, x <<= ((-329752233.8144052)&(tmp = -368636559, tmp))); - assertEquals(603979776, x <<= x); - assertEquals(364791569817010200, x *= x); - assertEquals(0, x &= ((2074587775.983799)/(tmp = 438856632.76449287, tmp))); - assertEquals(0, x &= (((1509671758)*(tmp = -935801537.7325008, tmp))>>>(((tmp = -1752877566, tmp)<<x)%(tmp = -517163766, tmp)))); - assertEquals(-2031730599, x ^= ((2264285273)&(tmp = -1762662949.014101, tmp))); - assertEquals(-843578945, x %= (-1188151654)); - assertEquals(-2147483648, x <<= x); - assertEquals(-2147483648, x >>= (tmp = -3165079200.229641, tmp)); - assertEquals(-44086313.1323726, x %= ((x%(-254466243.48728585))-((x>>(-457411829.1063688))-((-2606923436.9333453)/x)))); - assertEquals(-44086313, x |= x); - assertEquals(1037812, x >>>= ((tmp = 342497258.9786743, tmp)+(1652928385.8150895))); - assertEquals(-2371695599678100, x *= (tmp = -2285284425, tmp)); - assertEquals(-2371697387004653, x += (tmp = -1787326553.0542095, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x >>= ((x^(tmp = 544039787, tmp))>>>x)); - assertEquals(0, x &= ((x%(((((((tmp = -424572417.1088555, tmp)|(-2381863189))/(tmp = -2007482475.1809125, tmp))&(((((tmp = 311016073, tmp)>>(tmp = -1548839845, tmp))+((-2557740399.7947464)<<(2399113209)))&x)>>>x))%(-297180308.7721617))-(tmp = 860906293, tmp))^x))%(-2740622304))); - assertEquals(4971841192462909000, x += ((tmp = -2723203837.572612, tmp)+((((-2909100706)+(-951999374))|(-3116735764))*(3087123539.422669)))); - assertEquals(-460, x >>= (1081807537.557404)); - assertEquals(2354165127.3906384, x += (tmp = 2354165587.3906384, tmp)); - assertEquals(357.8680960002211, x /= ((((x<<(((x&x)+(1113841407))|((x/(tmp = 384533564, tmp))>>>(-605853882))))%x)&((tmp = 2050375842, tmp)>>>x))>>(((2745147573)^x)<<(x-(900043292))))); - assertEquals(0, x *= (x>>>(-295974954.5058532))); - assertEquals(0, x *= ((-2448592125.815531)*(tmp = -94957474.8986013, tmp))); - assertEquals(0, x &= ((x>>x)^(tmp = -1335129180, tmp))); - assertEquals(395092065, x |= ((3081659156)^(tmp = -1608334475, tmp))); - assertEquals(395092065, x &= x); - assertEquals(-413337639, x += (x^(tmp = -664996071.3641524, tmp))); - assertEquals(-1604423637896759800, x *= (x>>>(tmp = 1242912352.955432, tmp))); - assertEquals(0, x &= ((((((tmp = 651293313, tmp)|(((2541604468.635497)>>>(tmp = 758815817.7145422, tmp))>>>((-1948795647)/x)))&x)/((tmp = -3161497100, tmp)+(782910972.3648237)))>>>x)%(834206255.5560443))); - assertEquals(0, x >>>= (tmp = 125945571, tmp)); - assertEquals(NaN, x -= (x%x)); - assertEquals(NaN, x %= (tmp = 282259853, tmp)); - assertEquals(NaN, x += (tmp = -2081332383, tmp)); - assertEquals(0, x >>>= (((x>>(-2298589097.7522116))|((((x>>>(x-(tmp = 755218194, tmp)))|x)%x)-(tmp = 2206031927, tmp)))>>>((((x&(x-x))^(tmp = 2836686653, tmp))*((x<<(tmp = -1624140906.4099245, tmp))>>>((2942895486)|((x>>>x)>>>(-1586571476)))))|((781668993)+(-1857786909))))); - assertEquals(0, x &= (tmp = -708084218.9248881, tmp)); - assertEquals(0, x %= (1645913394.5625715)); - assertEquals(0, x <<= ((x^((tmp = 1185413900, tmp)*((-2441179733.997965)*(tmp = 2554099020.066989, tmp))))%((1704286567.29923)/x))); - assertEquals(0, x += x); - assertEquals(0, x *= x); - assertEquals(0, x |= (x>>>(139138112.141927))); - assertEquals(0, x >>>= (tmp = 2142326564, tmp)); - assertEquals(0, x |= x); - assertEquals(-0, x /= ((((x+(2817799428))|x)%((1050079768)-(x>>>((1452893834.8981247)|((((tmp = -1737187310.889149, tmp)/(tmp = -362842139, tmp))%(1234225406))%(((x|x)*((-1055695643.739629)-((x-x)*(945954197.676585))))-(tmp = 786185315.346615, tmp)))))))<<(-173891691))); - assertEquals(0, x &= (-2842855092.319309)); - assertEquals(0, x &= ((-3188403836.570895)/x)); - assertEquals(0, x *= (x+x)); - assertEquals(NaN, x /= (x>>>(((tmp = 391037497.68871593, tmp)/((192754032)*(1382659402.5745282)))/((((-2187364928)>>>x)>>(tmp = 2563448665.7594023, tmp))^(tmp = 1500866009.7632217, tmp))))); - assertEquals(NaN, x /= ((tmp = -935036555.2500343, tmp)-(x/(((x&(x^(tmp = -3001352832.5034075, tmp)))^x)/((1122547613)>>x))))); - assertEquals(0, x >>= (tmp = -2951766379.0809536, tmp)); - assertEquals(-632945188, x ^= (-632945188.7188203)); - assertEquals(-632945188, x %= ((((((tmp = -3181527314.82724, tmp)&(2280175415))>>(x^(x|x)))^(tmp = -524233678.52970886, tmp))*x)|((tmp = 1782882786, tmp)>>>(tmp = -592607219, tmp)))); - assertEquals(404189184, x <<= ((tmp = -2761472127, tmp)^(36616299.88780403))); - assertEquals(872651572, x ^= (tmp = 739568436.6252247, tmp)); - assertEquals(13, x >>>= ((tmp = -1033843418.865577, tmp)%(x%(1247263629.0445533)))); - assertEquals(0, x >>>= x); - assertEquals(0, x >>= (3189175317)); - assertEquals(0, x &= (((2391973519.6142406)^((-2950058736.191456)|(x*x)))>>(tmp = 343822384.294345, tmp))); - assertEquals(0, x >>>= (tmp = -2306246544, tmp)); - assertEquals(-1572339598, x ^= ((tmp = 2991380083.337327, tmp)&(tmp = -1361507970, tmp))); - assertEquals(649, x >>>= ((1961407923.4950056)>>(x-(-872821523.7513013)))); - assertEquals(649, x ^= (((x&(tmp = -702931788, tmp))^(((x>>x)|(((tmp = 2710759269, tmp)/(x>>(x*((((((tmp = -2428445134.9555864, tmp)+(-1859938743))%(x<<x))*((236868604)+((tmp = -3066688385, tmp)/(787503572.8839133))))/(tmp = 3215629315, tmp))>>(-1315823020)))))%(1461368627.1293125)))>>>(tmp = -2921804417.5735087, tmp)))/(x>>>(((tmp = 2175260691.824617, tmp)/((-582958935.7628009)-((((((x>>x)|(2590503723.4810824))^(tmp = -1994324549, tmp))-(-684683327))/(tmp = -3133419531, tmp))|(tmp = -328974092.05095506, tmp))))>>(-447624639.4518213))))); - assertEquals(649, x %= ((((1854382717)|(((x+(tmp = 2568081234, tmp))-x)+((tmp = 1043086140, tmp)<<((tmp = 2979118595.0496006, tmp)+((x&(2669577199.852803))/(-2567808445.101112))))))<<((((tmp = -1471092047, tmp)&((-3099138855.21041)-((tmp = -798574377.526715, tmp)&((2255586141)<<(-1069867774)))))>>>(((x*(tmp = -2810255707.781517, tmp))/x)*(2706435744.054121)))^(394262253)))^((844325548.0612085)/(tmp = 1434691648, tmp)))); - assertEquals(823215943.1924392, x += (tmp = 823215294.1924392, tmp)); - assertEquals(536872706, x &= ((-334612686)%((1303605874)|x))); - assertEquals(-30666374.413486242, x += ((tmp = -567539080.4134862, tmp)%(tmp = -1655555936.3195171, tmp))); - assertEquals(-56438727096752984, x *= (tmp = 1840410814, tmp)); - assertEquals(-33200107.984488487, x %= (((tmp = 3007206509, tmp)-(3079337725.6659536))%(1819565202.5011497))); - assertEquals(-1214493182, x ^= (-3060193769)); - assertEquals(-1214493179.1335113, x -= ((-3218099496.595745)/(1122662554))); - assertEquals(-1214493179, x >>= ((-375364195)<<(((tmp = 619439637.8754326, tmp)>>(-1830023279.9486575))&(tmp = -1106180387.2448823, tmp)))); - assertEquals(-303623295, x >>= (-2109241374.3349872)); - assertEquals(-0, x %= x); - assertEquals(0, x |= x); - assertEquals(1917126206, x -= (-1917126206)); - assertEquals(2659779928, x -= (tmp = -742653722, tmp)); - assertEquals(-1635187368, x >>= ((tmp = -674385169, tmp)*((9848362.783326745)|(x*(55220544.00989556))))); - assertEquals(-1981113695, x ^= ((tmp = 392404985, tmp)>>(((x<<((2006207061)<<(tmp = 2558988218, tmp)))*((((tmp = 1789304307.1153054, tmp)/(2538061546))<<(tmp = 556026116, tmp))&((tmp = 1076457999.6424632, tmp)*(tmp = -1822378633.2489474, tmp))))%(((((-1117046924)&((-69013651)%(x&(((-2320327696)/(x&x))-(tmp = 2458222544, tmp)))))>>((-3092360983.0037227)/(-3171415636)))*(((tmp = 2520431213, tmp)<<(1066492762.6149663))+((tmp = 1272200889, tmp)^((1687693123.2295754)+x))))-(-1096823395))))); - assertEquals(-990556848, x >>= x); - assertEquals(981202869119695100, x *= x); - assertEquals(981202869119695100, x -= (x/x)); - assertEquals(0, x ^= (x>>x)); - assertEquals(NaN, x %= x); - assertEquals(0, x ^= x); - assertEquals(0, x *= ((((2980512718)>>>x)<<((x^(-1111233869))>>((2531466092.6036797)>>>(((tmp = -1791229364, tmp)*(-2210950307.206208))%((tmp = -806645443, tmp)<<((((((((tmp = 112334634.26187229, tmp)%(x|((((2154021796.1166573)+x)&((-1047293079.9686966)^(tmp = -1894127139, tmp)))+(tmp = 1910946653.2314827, tmp))))^(293142672.5016146))-x)<<(-1593533039.8718698))+x)>>(x<<(((46359706.50393462)&(tmp = 272146661, tmp))|(tmp = 2117690168, tmp))))%(tmp = -1784737092.4924843, tmp)))))))-(1465796246))); - assertEquals(0, x &= x); - assertEquals(NaN, x %= x); - assertEquals(0, x &= (x+(-1612418456))); - assertEquals(0, x &= ((tmp = -843964311, tmp)/x)); - assertEquals(NaN, x /= x); - assertEquals(NaN, x *= x); - assertEquals(NaN, x += (x>>>(54020240))); - assertEquals(489206868, x |= (489206868)); - assertEquals(489206868, x &= x); - assertEquals(489206848, x &= ((tmp = -1699133906.2361684, tmp)>>(tmp = 2658633814, tmp))); - assertEquals(489206848, x |= x); - assertEquals(1910559006, x -= (tmp = -1421352158, tmp)); - assertEquals(1, x >>= x); - assertEquals(0, x -= x); - assertEquals(0, x %= (x^(tmp = 2745376003.2927403, tmp))); - assertEquals(0, x %= (((tmp = 3199743302.1063356, tmp)^((-1905944176)&(x>>>(187247029.5209098))))<<((x*((-1394648387)*(1252234289)))-(3140049815)))); - assertEquals(0, x <<= (-2567872355)); - assertEquals(0, x %= (tmp = 1057707555.8604916, tmp)); - assertEquals(0, x %= ((tmp = -1877857405.0228279, tmp)>>>(((tmp = 423831184, tmp)*((tmp = -2106757468.324615, tmp)%(tmp = -1197717524.6540637, tmp)))>>(tmp = -93746263.46774769, tmp)))); - assertEquals(0, x |= x); - assertEquals(-0, x *= ((tmp = 1317609776.6323466, tmp)*(tmp = -26959885.89325118, tmp))); - assertEquals(0, x >>= (-1288116122.0091262)); - assertEquals(0, x &= ((370818172.92511404)%((tmp = -528319853.54781747, tmp)*(x/((tmp = -2839758076, tmp)^(x+(((-1258213460.041857)<<(tmp = 302017800.72064054, tmp))|((((tmp = -624254210, tmp)^((-338165065.97507)|((623392964)-x)))>>>x)%(tmp = 2767629843.0643625, tmp))))))))); - assertEquals(0, x >>>= x); - assertEquals(0, x >>>= x); - assertEquals(0, x |= ((-2001549164.1988192)*x)); - assertEquals(0, x -= x); - assertEquals(0, x *= (((((165836842.14390492)*(tmp = -3220002961, tmp))|(-2840620221.747431))%((x/(tmp = 3153915610, tmp))>>>(tmp = 2018941558, tmp)))>>>x)); - assertEquals(-0, x *= (-231994402.93764925)); - assertEquals(0, x <<= x); - assertEquals(0, x %= (tmp = 2702385056.1149964, tmp)); - assertEquals(0, x <<= (tmp = 378459323, tmp)); - assertEquals(0, x >>>= ((x&(x&(((-1014963013)<<(x&((tmp = -3110294840, tmp)|(x+(x<<(1129643420))))))+(1093795819.1853619))))+((((tmp = -2295103369.697398, tmp)&(((370501313.43019223)>>>(2465439579))/x))-x)>>x))); - assertEquals(0, x /= ((tmp = 1779625847, tmp)+(tmp = -662459654.6908865, tmp))); - assertEquals(0, x -= x); - assertEquals(0, x %= ((tmp = 2723291421, tmp)|(277246502.4027958))); - assertEquals(0, x ^= (((-2936270162)>>>((((tmp = -2019015609.1648235, tmp)|(47218153))*(-823685284))+x))&(x<<(x*(x|(((tmp = -941955398, tmp)^(tmp = -2365238993.5300865, tmp))-(778674685))))))); - assertEquals(0, x >>>= x); - assertEquals(NaN, x %= x); - assertEquals(0, x &= (-175235975.8858137)); - assertEquals(-2684493800.1062117, x += (tmp = -2684493800.1062117, tmp)); - assertEquals(-1290806265.6063132, x -= (-1393687534.4998984)); - assertEquals(-1290806265, x >>= (((x>>(tmp = -1710112056.4935386, tmp))*(586227650.2860553))<<(tmp = -2918251533.6052856, tmp))); - assertEquals(23470008, x >>>= x); - assertEquals(1668734969, x |= ((-295560682.9663689)^(x|((((tmp = -1183847364, tmp)&(3135327694))+(1679127747.1406744))-((-1895825528)%((tmp = -3180115006, tmp)+((tmp = 2373812187, tmp)|x))))))); - assertEquals(1744306169, x |= (1188503928.5009093)); - assertEquals(1744306169, x %= (tmp = -2723982401.4997177, tmp)); - assertEquals(3488612338, x += x); - assertEquals(3488612337, x += (((x/(-325849204))>>x)|(-1820624550.9149108))); - assertEquals(-1511119305, x ^= (tmp = 1778506182.2952862, tmp)); - assertEquals(-12211415, x %= (x^(tmp = -54943035, tmp))); - assertEquals(-12211415, x %= ((-1267051884)%(-643566443.0122576))); - assertEquals(-30.84976063258681, x /= (((1052047194)>>>x)&(1495698235.5117269))); - assertEquals(-61.69952126517362, x += x); - assertEquals(-244, x <<= (x^(x+(tmp = -2822258210.076373, tmp)))); - assertEquals(-6652, x &= ((tmp = 2593685093, tmp)>>((((2047688852.4609032)<<((x*(-611076291))*x))^(-2665364024.817528))>>>(165267874)))); - assertEquals(0, x -= x); - assertEquals(0, x /= (2454186758)); - assertEquals(0, x &= (tmp = -2226895206, tmp)); - assertEquals(0, x += x); - assertEquals(-21390701, x += ((-1369004846.0816503)>>(tmp = -2661552634.039692, tmp))); - assertEquals(-0.012568536912921919, x /= (1701924507.856429)); - assertEquals(7.09517966608176e-11, x /= (tmp = -177141911.8955555, tmp)); - assertEquals(0, x >>= (tmp = 231535697, tmp)); - assertEquals(1383687797, x ^= (tmp = -2911279499.568808, tmp)); - assertEquals(1383687797, x %= (tmp = -2258636646.5294995, tmp)); - assertEquals(1319, x >>= ((tmp = -2549411892.8426056, tmp)/(((((1532476676)^(153720871.82640445))+x)/(((2988190456.3206205)&(tmp = -2920873674, tmp))-(((((tmp = -1044518167.0581458, tmp)>>x)-((((tmp = -194701879.13505793, tmp)&(498352051))&((tmp = -2167339635.6529818, tmp)^(((x>>(tmp = 700159851, tmp))*(tmp = 2874921158, tmp))/x)))-((2856128689)|((-1876321441)>>>(2110732915)))))^((((tmp = -193379494.18825436, tmp)/(-3055182489.533142))<<x)+((tmp = -2286109605, tmp)>>(tmp = 698475484.3987849, tmp))))^(3182231653.500364))))|(((tmp = -194670835, tmp)>>>((786780139)%(((2114171416.2305853)^(1703145352.8143656))/x)))>>>((tmp = -3029462067, tmp)>>((67647572.02624655)&(x*(-2394283060)))))))); - assertEquals(13903855, x |= ((tmp = -2515306586, tmp)>>>x)); - assertEquals(54311, x >>>= ((-2413722658)-((tmp = -2159787584, tmp)^(tmp = 949937622.9744623, tmp)))); - assertEquals(108622, x += x); - assertEquals(1250717187, x ^= ((tmp = 842692148, tmp)+(((2649331689.694273)<<x)-(tmp = -2992181273, tmp)))); - assertEquals(4536777, x %= (tmp = 73304730, tmp)); - assertEquals(0, x -= x); - assertEquals(-580081499, x ^= ((tmp = -580081499.0170684, tmp)^(x%(tmp = -1542730817.88261, tmp)))); - assertEquals(-1382738784, x <<= x); - assertEquals(-1382738784, x <<= x); - assertEquals(2912228512, x >>>= (x*(x>>>x))); - assertEquals(-1076374105, x |= (2589443367)); - assertEquals(-0.2818750938197037, x /= (((tmp = -1559525732.9603848, tmp)|(-477068917.5483327))>>>((-688616257)*((((tmp = -1192490153.1226473, tmp)*(-502280624.0265591))<<(-442688727.4881985))%(x+(((((tmp = -2948836853.831935, tmp)-(tmp = -2850398330.910424, tmp))>>>(x>>>(-1947835558)))^x)+(x*x))))))); - assertEquals(2032826546, x |= (tmp = 2032826546.819327, tmp)); - assertEquals(3408404827.14316, x += (tmp = 1375578281.1431599, tmp)); - assertEquals(258183922.14315987, x %= (tmp = 350024545, tmp)); - assertEquals(479694848, x <<= (tmp = -481187157, tmp)); - assertEquals(-2147483648, x <<= (((tmp = -2956588045.472398, tmp)>>>(((tmp = -1838455399.1775856, tmp)&(((((tmp = -637547, tmp)/x)&(x^((-44876328.1767962)+(((-2059598286)-(1071496688))%(tmp = -1492254402, tmp)))))-(x%x))*(x|x)))>>(1226250760)))<<x)); - assertEquals(-2288163338.9020815, x -= (140679690.9020816)); - assertEquals(4954833118513997000, x *= (-2165419327.4906025)); - assertEquals(1578331238, x ^= (-2410854298.2270393)); - assertEquals(-810627292, x += (-2388958530)); - assertEquals(-810627292, x ^= ((1495296640.4087524)/(tmp = 1561790291, tmp))); - assertEquals(657116606535253200, x *= x); - assertEquals(0.675840332689047, x %= (((-1816548473)^(((tmp = -151918689.19451094, tmp)|(1819911186.535233))/((((((1514297447)+(tmp = 856485190.9684253, tmp))&(((1809369464.4363992)<<(493538496))*x))+((x*(x>>(x&(tmp = 222293461, tmp))))>>>(((784519621)|x)^((-580766922)>>(tmp = -947264116, tmp)))))>>>((((2794210354.22964)>>>(((2896952532.0183973)*((x+(tmp = -1813175940, tmp))<<(tmp = -1302618293, tmp)))&x))>>(x-(((x|((1456466890.1952953)*x))^(-169979758.19158387))-(x-x))))>>x))&(tmp = 2671604078.3026733, tmp))))/(-1701675745))); - assertEquals(0.675840332689047, x %= ((tmp = 2421871143, tmp)^x)); - assertEquals(NaN, x %= ((((tmp = 1175526323.433271, tmp)+(tmp = 2813009575.952405, tmp))%((tmp = -3112133516.3303423, tmp)&x))&((((((-424329392)^(tmp = 1430146361, tmp))+x)-(1533557337.268306))%((tmp = -3117619446, tmp)-(-3127129232)))>>>x))); - assertEquals(NaN, x += x); - assertEquals(0, x >>>= ((1710641057.7325037)%(104961723.56541145))); - assertEquals(0, x <<= (tmp = -970072906, tmp)); - assertEquals(0, x *= (87768668)); - assertEquals(-1464968122, x ^= (tmp = -1464968122, tmp)); - assertEquals(-1467983895, x ^= ((tmp = -1204896021, tmp)>>>(((91792661)&(x>>>(((-2364345606)>>>x)*x)))+x))); - assertEquals(2.991581508270506, x /= (-490704963.5591147)); - assertEquals(0, x >>>= x); - assertEquals(0, x >>= ((tmp = 639854873, tmp)%(tmp = 743486160.3597239, tmp))); - assertEquals(0, x <<= (tmp = 1045577245.3403939, tmp)); - assertEquals(0, x >>= ((tmp = -1932462290, tmp)|(tmp = 1629217987, tmp))); - assertEquals(517617438, x ^= ((tmp = 2737789043, tmp)%(tmp = -2220171604.135681, tmp))); - assertEquals(126371, x >>>= ((tmp = 205210223.69909227, tmp)-(tmp = 598118404, tmp))); - assertEquals(918548455, x |= ((918228734.8363427)+(x+x))); - assertEquals(918548455, x |= ((tmp = 599828198, tmp)>>((tmp = -851081330, tmp)|(tmp = -1152596996.8443217, tmp)))); - assertEquals(918548443.7739062, x -= ((tmp = 1497642976.2260938, tmp)%(x>>(tmp = -548469702.5849569, tmp)))); - assertEquals(0.7739062309265137, x %= (x&x)); - assertEquals(2317939163.8239403, x *= (tmp = 2995116296, tmp)); - assertEquals(1014415360, x <<= (-279972114)); - assertEquals(0, x &= ((296810932)/(x*(tmp = -2750499950, tmp)))); - assertEquals(0, x *= (x%((126285451.05086231)>>>(x*(tmp = -2789790532, tmp))))); - assertEquals(0, x >>>= ((975695102.5771483)%(x-((-1011726540)-((tmp = 2223194882, tmp)/x))))); - assertEquals(-1747794584, x |= (-1747794584.3839395)); - assertEquals(-543544679, x %= (tmp = -1204249905, tmp)); - assertEquals(-543544679, x %= (-881024001)); - assertEquals(1, x /= x); - assertEquals(-1879376393, x |= ((tmp = 161643764, tmp)|(tmp = 2281346499.9084272, tmp))); - assertEquals(1.321124264431369, x /= (-1422558379.7061746)); - assertEquals(1, x >>>= (x&(tmp = -963118950.4710281, tmp))); - assertEquals(3, x ^= ((x+x)/x)); - assertEquals(1, x /= x); - assertEquals(1, x &= (2090796073)); - assertEquals(-1284301873, x ^= (((-11041168.146357536)+(tmp = -1273260707.8134556, tmp))+x)); - assertEquals(292559045, x &= (x&((-2401110739)^((tmp = 630802904, tmp)^(((1012634447.0346229)+x)%((tmp = -1240091095, tmp)%(x/(-1483936527)))))))); - assertEquals(0, x %= x); - assertEquals(0, x /= (tmp = 613145428.3653506, tmp)); - assertEquals(0, x /= ((x-(tmp = 3116638456, tmp))*(-973300716))); - assertEquals(0, x %= (tmp = -1794741286.0464535, tmp)); - assertEquals(0, x &= x); - assertEquals(0, x >>= (-551370105.0746605)); - assertEquals(-1471996874, x ^= ((2822970422.2331414)-x)); - assertEquals(-277914313, x |= (tmp = -818980601.2544096, tmp)); - assertEquals(-34, x >>= x); - assertEquals(305422768, x -= (-305422802)); - assertEquals(-2406146240, x += (tmp = -2711569008, tmp)); - assertEquals(1073745408, x &= (tmp = -3046625618, tmp)); - assertEquals(1073745408, x <<= ((-1234108306.7646303)<<((-233519302)|x))); - assertEquals(1073745408, x %= (tmp = 1898831268, tmp)); - assertEquals(1073745408, x <<= (((tmp = 3089406038, tmp)/x)&(-2960027680))); - assertEquals(65536, x >>>= (2858188366)); - assertEquals(128, x >>>= ((-2640257239.857275)%((tmp = -3185405235.3177376, tmp)*x))); - assertEquals(128, x >>>= x); - assertEquals(128, x -= (x&(x-(tmp = -247588018, tmp)))); - assertEquals(81616906825.07776, x *= (tmp = 637632084.57092, tmp)); - assertEquals(78860097686.07776, x -= (((1507215684)^((709254783)+(((x<<x)*((-2890828152.667641)%(2537817529.2041526)))^x)))+(3114024487))); - assertEquals(-2920545695.721283, x += (((tmp = -2555437435, tmp)>>>x)-((2920546109.72129)+x))); - assertEquals(-2879412281.721283, x += ((-1662428756)>>>(tmp = -1928491386.6926208, tmp))); - assertEquals(67403845, x &= (tmp = 2921644117, tmp)); - assertEquals(16850961, x >>>= (((-1039328365)>>>(tmp = -768615112, tmp))<<((1037261855)*(tmp = -2906902831.4797926, tmp)))); - assertEquals(0, x ^= x); - assertEquals(0, x *= ((-2729056530)/((-1776175111)%(1493002300.4604707)))); - assertEquals(0, x *= (tmp = 370696035.22912216, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x |= ((((((tmp = -1541196993, tmp)^x)/(854730380.1799632))/(2879117705.492209))+((((-2892068577)^(-2460614446.1044483))>>>((743413943)<<(-1285280084.4220598)))/(tmp = -1719994579.5141463, tmp)))%(((((tmp = 2522797851.088227, tmp)<<(tmp = 2257160597.1538725, tmp))/(-680406007))&((x>>>(tmp = -260350730, tmp))^(tmp = 1920522110.852598, tmp)))>>(-697620442)))); - assertEquals(0, x &= x); - assertEquals(-591399642.958673, x += (x-(tmp = 591399642.958673, tmp))); - assertEquals(27, x >>>= (tmp = -726721317.2109983, tmp)); - assertEquals(-2043736843, x -= (2043736870)); - assertEquals(-3991674, x >>= (tmp = 1098126089, tmp)); - assertEquals(-997919, x >>= ((x%(((x*(((-1497329257.1781685)%(2334511329.2690516))/(-3072526140.6635056)))+(-1843998852))-(tmp = 240300314.34070587, tmp)))+(714080860.6032693))); - assertEquals(-0, x %= x); - assertEquals(NaN, x /= x); - assertEquals(0, x >>= (tmp = 538348328.5363884, tmp)); - assertEquals(0, x *= (800317515)); - assertEquals(0, x -= x); - assertEquals(0, x >>= (984205514)); - assertEquals(857282491, x += (tmp = 857282491, tmp)); - assertEquals(587792897, x &= (tmp = 2951307845.164059, tmp)); - assertEquals(595301269, x |= (tmp = 24285588.90314555, tmp)); - assertEquals(1190602538, x += x); - assertEquals(0, x -= x); - assertEquals(-442423060, x |= ((x^((x-(tmp = 2342497475.637024, tmp))%(-1900074414.7678084)))|((tmp = 1932380130, tmp)%(x%(2291727569.817062))))); - assertEquals(-442423060, x %= (((tmp = 703479475.545413, tmp)>>(x-x))<<(2435723056.753845))); - assertEquals(1, x /= x); - assertEquals(0, x >>= x); - assertEquals(-1265317851, x |= (tmp = -1265317851, tmp)); - assertEquals(-2, x >>= (-2015895906.8256726)); - assertEquals(-0, x %= x); - assertEquals(-0, x %= (((1219237746)+(284683029))*(((tmp = 2288119628, tmp)|(-404658161.2563329))*(-265228691.74142504)))); - assertEquals(1039509109, x -= (-1039509109)); - assertEquals(2079018218, x += x); - assertEquals(-1979.9362673719077, x /= ((3219723500)>>x)); - assertEquals(-62, x >>= ((x/(326466691))*(tmp = -607654070, tmp))); - assertEquals(-45, x |= (tmp = -2954888429.549882, tmp)); - assertEquals(-1180929712, x &= (3114037588.570232)); - assertEquals(815550480, x &= (-2302684143.3378315)); - assertEquals(815550480, x %= (-2177479570)); - assertEquals(815550480, x %= (tmp = 2895822167, tmp)); - assertEquals(815550480, x %= (-1247621230.5438688)); - assertEquals(283929811, x -= ((tmp = 251831053.17096448, tmp)|((tmp = 1140463506.004994, tmp)+(tmp = -743224673.546309, tmp)))); - assertEquals(1825767424, x <<= (((tmp = 1732353599, tmp)^(tmp = 658726044, tmp))>>>((-2827889370.932477)%(tmp = 1950139204.3291233, tmp)))); - assertEquals(1828450414, x |= (tmp = 1618538606, tmp)); - assertEquals(0, x <<= (-2411670689.045702)); - assertEquals(0, x <<= (-27744888.428537607)); - assertEquals(-0, x /= (tmp = -1597552450, tmp)); - assertEquals(0, x >>>= (((2165722776.7220936)>>>(tmp = 1233069931, tmp))>>>(-1120420811))); - assertEquals(-0, x *= ((tmp = -1505252656, tmp)>>((((3035637099.6156535)&((467761577.7669761)>>(-361034537)))^(tmp = -2347994840.6541123, tmp))*(tmp = -2191739821, tmp)))); - assertEquals(0, x &= (795727404.0738752)); - assertEquals(-0, x *= (tmp = -3125944685.3991394, tmp)); - assertEquals(-0, x *= (x&x)); - assertEquals(0, x >>= ((tmp = -2045709233, tmp)^x)); - assertEquals(NaN, x /= (x>>(x/(3102894071)))); - assertEquals(NaN, x += ((tmp = 2149079756.8941655, tmp)-(tmp = 810121645.305179, tmp))); - assertEquals(0, x >>>= (-859842989)); - assertEquals(0, x >>>= (tmp = 2530531143.9369526, tmp)); - assertEquals(0, x >>= (((-932981419.6254237)|(tmp = 1591591715, tmp))>>>(x+((3149795006)>>>(tmp = 613352154, tmp))))); - assertEquals(-4294967295, x -= ((((-2289331668)%(-282648480.0078714))>>(-1373720705.5142756))>>>((tmp = 15511563.517014384, tmp)/(360279080)))); - assertEquals(1, x &= x); - assertEquals(0, x >>= (x^(-2791872557.5190563))); - assertEquals(0, x &= ((tmp = 336466956.7847167, tmp)>>((1235728252.053619)|(x<<((1828176636.13488)%x))))); - assertEquals(-0, x *= (-364042830.8894656)); - assertEquals(0, x >>>= x); - assertEquals(-1675298680, x |= ((2323049541.321387)+(296619075))); - assertEquals(-0, x %= x); - assertEquals(-1583048579.4420977, x += (-1583048579.4420977)); - assertEquals(0, x -= x); - assertEquals(-2, x ^= ((603171992.0545617)/(((-271888695.718297)%(tmp = -400159585, tmp))^((((tmp = 1536123971, tmp)-(tmp = -2310418666.6243773, tmp))|((tmp = 2242779597.1219435, tmp)<<(tmp = 1758127684.4745512, tmp)))/x)))); - assertEquals(-2, x &= (x&x)); - assertEquals(0, x &= ((tmp = -1098806007.4049063, tmp)/(((2862384059.3229523)/((((tmp = -92960842, tmp)-(x>>(tmp = 1244068344.2269042, tmp)))&x)*(tmp = -1919148313, tmp)))<<(-2486665929)))); - assertEquals(0, x &= x); - assertEquals(-1441272634.582818, x -= (1441272634.582818)); - assertEquals(-3, x >>= (tmp = 3186393693.7727594, tmp)); - assertEquals(-1206855850, x ^= (((tmp = 607979495.303539, tmp)-(tmp = -2480131951, tmp))^(x*((tmp = 1324153477, tmp)/((1248126288)+(x|(1917331780.0741704))))))); - assertEquals(-1206855853, x ^= (x>>>(653288765.1749961))); - assertEquals(-1206857725, x &= (3149461539.6019173)); - assertEquals(3088109571, x >>>= (x*(x<<(tmp = 1543540084, tmp)))); - assertEquals(536903680, x &= (tmp = 644851760, tmp)); - assertEquals(536903674.312194, x += (((-3183290076)-((tmp = 40738191.12097299, tmp)-x))/((x>>>(3151371851.9408646))^(tmp = 472698205.22445416, tmp)))); - assertEquals(2127424750.0506563, x -= (tmp = -1590521075.7384624, tmp)); - assertEquals(2127424750.0506563, x %= (tmp = 3027273433.361373, tmp)); - assertEquals(0, x >>= (x>>(1445204441.702043))); - assertEquals(NaN, x %= (x<<x)); - assertEquals(0, x ^= ((tmp = -2903841152.136344, tmp)-(x%(2938662860)))); - assertEquals(0, x <<= (x<<x)); - assertEquals(0, x >>>= (tmp = -979481631.33442, tmp)); - assertEquals(0, x >>= x); - assertEquals(0, x &= (((x%((((((tmp = 1657446354.6820035, tmp)>>(-1916527001.2992697))/x)>>(tmp = 1450467955, tmp))&(277676820))+(x/(-945587805))))/((tmp = -690095354, tmp)^x))+(tmp = -2651195021, tmp))); - assertEquals(0, x <<= (752343428.2934296)); - assertEquals(0, x /= (tmp = 3022310299, tmp)); - assertEquals(0, x >>= (x%((388245402)>>>x))); - assertEquals(NaN, x %= x); - assertEquals(NaN, x %= ((tmp = 1205123529.8649468, tmp)>>>(-2848300932))); - assertEquals(0, x >>= ((x>>>x)<<(tmp = 487841938, tmp))); - assertEquals(0, x *= (((273436000.9463471)|(tmp = 141134074.27978027, tmp))^(tmp = 1220326800.7885802, tmp))); - assertEquals(1525600768, x |= (((x^(-2674777396))-(tmp = 1966360716.3434916, tmp))<<(794782595.9340223))); - assertEquals(761927595, x %= (tmp = -763673173, tmp)); - assertEquals(1.1353588586934338, x /= ((x&((-1897159300.4789193)*(-348338328.0939896)))&(978680905.6470605))); - assertEquals(8.631173314966319e-10, x /= (1315416592)); - assertEquals(0, x >>= ((tmp = -2581239435, tmp)-((-628818404.1122074)<<x))); - assertEquals(0, x -= x); - assertEquals(0, x *= (2925158236)); - assertEquals(0, x /= (x+(tmp = 1405531594.0181243, tmp))); - assertEquals(0, x *= (2712022631.230831)); - assertEquals(0, x >>= (tmp = 80518779.81608999, tmp)); - assertEquals(1953477932.8046472, x += (tmp = 1953477932.8046472, tmp)); - assertEquals(1953477932, x >>= (tmp = 3025539936, tmp)); - assertEquals(1953477932, x -= ((-2675119685.8812313)>>(x/(-1808264410.9754841)))); - assertEquals(1292620430, x += ((-660857502)%((((tmp = -698782819, tmp)%(tmp = 2847304199, tmp))<<(-2423443217.1315413))+x))); - assertEquals(78895, x >>>= x); - assertEquals(2, x >>= x); - assertEquals(2, x <<= (tmp = 1313641888.8301702, tmp)); - assertEquals(1857416935.2532766, x += (tmp = 1857416933.2532766, tmp)); - assertEquals(-1677721600, x <<= (tmp = -2482476902, tmp)); - assertEquals(309226853.62854385, x -= (tmp = -1986948453.6285439, tmp)); - assertEquals(33965156, x &= (2409088742)); - assertEquals(Infinity, x /= (x-(x<<((x/(tmp = -3106546671.536726, tmp))/((tmp = 2695710176, tmp)-((((-2102442864)&(857636911.7079853))/x)%(-65640292))))))); - assertEquals(1270005091, x |= (tmp = 1270005091.0081215, tmp)); - assertEquals(1270005091, x %= (tmp = -1833876598.2761571, tmp)); - assertEquals(158750636, x >>>= x); - assertEquals(-1000809106.0879555, x -= (tmp = 1159559742.0879555, tmp)); - assertEquals(72400936, x &= ((2448271389.3097963)%(tmp = 1517733861, tmp))); - assertEquals(282816, x >>= x); - assertEquals(282816, x %= (tmp = 3192677386, tmp)); - assertEquals(0.00021521351827207216, x /= (1314118194.2040696)); - assertEquals(Infinity, x /= (((tmp = 2822091386.1977024, tmp)&x)%(tmp = -3155658210, tmp))); - assertEquals(NaN, x %= (-359319199)); - assertEquals(0, x >>>= (((tmp = -2651558483, tmp)-(x<<(tmp = 2537675226.941645, tmp)))<<(tmp = 667468049.0240343, tmp))); - assertEquals(-0, x *= (tmp = -2827980482.12998, tmp)); - assertEquals(-0, x %= (((tmp = -689972329.3533998, tmp)>>>x)|(tmp = -7488144, tmp))); - assertEquals(0, x >>>= x); - assertEquals(0, x |= x); - assertEquals(-2410373675.2262926, x -= (2410373675.2262926)); - assertEquals(1840423, x >>= ((-1081642113)^x)); - assertEquals(-4829451429403412, x *= (-2624098606.35485)); - assertEquals(-94552231, x %= (tmp = -97015883, tmp)); - assertEquals(-94433287, x ^= (((tmp = -2297735280, tmp)&(((tmp = 2261074987.7072973, tmp)%((((2565078998)^(-2573247878))|x)|(((tmp = -2120919004.7239416, tmp)>>(tmp = -579224101, tmp))>>>(1905808441))))*(x|(3149383322))))>>(542664972))); - assertEquals(0, x ^= (x<<(tmp = -3112569312, tmp))); - assertEquals(0, x <<= (-2141934818.7052917)); - assertEquals(0, x >>= (tmp = -2539525922, tmp)); - assertEquals(-434467613, x ^= (tmp = -434467613, tmp)); - assertEquals(-274792709, x |= (1233452601.462551)); - assertEquals(-274726917, x |= (-2130333750)); - assertEquals(-272629761, x |= (-1516071602.5622227)); - assertEquals(-272629761, x |= ((tmp = 3012131694, tmp)&((tmp = -2595342375.8674774, tmp)-((tmp = -2710765792, tmp)>>>((x-(tmp = 2397845540, tmp))+(2496667307)))))); - assertEquals(-4194305, x |= (1343705633.165825)); - assertEquals(4190207, x >>>= ((tmp = 276587830, tmp)*((tmp = -1517753936, tmp)>>x))); - assertEquals(0, x >>= (x|((2247486919)-((-1664642412.4710495)*((((tmp = -358185292.17083216, tmp)-(tmp = -1472193444, tmp))*(tmp = 2699733752, tmp))&((x|(x<<(1137610148.1318119)))>>(((375089690.8764564)*x)&(tmp = 859788933.9560187, tmp)))))))); - assertEquals(0, x %= (3080673960)); - assertEquals(0, x >>>= (1328846190.1963305)); - assertEquals(1249447579, x |= (-3045519717.580775)); - assertEquals(-0.8743931060971377, x /= (-1428931187)); - assertEquals(1, x |= ((tmp = -1756877535.7557893, tmp)/((-142900015.93200803)<<(1414557031.347334)))); - assertEquals(759627265, x ^= (759627264.0514802)); - assertEquals(741823, x >>= (1106391210)); - assertEquals(610451, x &= ((x>>>((919849416)+((tmp = -427708986, tmp)^((x%x)|(tmp = -2853100288.932063, tmp)))))*x)); - assertEquals(372650423401, x *= x); - assertEquals(410404493, x >>>= ((((-1425086765)>>>x)>>((2813118707.914771)>>(-424850240)))^x)); - assertEquals(120511585729013, x *= ((tmp = -1889454669, tmp)>>>x)); - assertEquals(120513295294304.22, x -= (tmp = -1709565291.2115698, tmp)); - assertEquals(6164, x >>>= ((2244715719.397763)^(tmp = -741235818.6903033, tmp))); - assertEquals(937572790.468221, x -= (tmp = -937566626.468221, tmp)); - assertEquals(937572790, x |= ((2129102867.156146)*(x%x))); - assertEquals(32, x &= ((2700124055.3712993)>>>((1977241506)>>>(-2915605511)))); - assertEquals(32, x %= (tmp = -2513825862, tmp)); - assertEquals(0, x <<= (-1379604802)); - assertEquals(0, x >>>= (tmp = -1033248759, tmp)); - assertEquals(-1151517050, x ^= (3143450246)); - assertEquals(-180577, x |= ((738373819.4081701)^(-357134176))); - assertEquals(-0, x %= x); - assertEquals(-2086887759, x |= (tmp = 2208079537, tmp)); - assertEquals(-2, x >>= (1460216478.7305799)); - assertEquals(-2, x %= ((-1979700249.0593133)^(-3156454032.4790583))); - assertEquals(-256, x <<= ((1810316926)>>>(tmp = 414362256, tmp))); - assertEquals(-1, x >>= (((((((-1616428585.595561)*((tmp = 2574896242.9045777, tmp)|(86659152.37838173)))>>(((tmp = 2476869361, tmp)&((x+((tmp = -2445847462.1974697, tmp)>>(tmp = -1960643509.5255682, tmp)))+(x|(((((2231574372.778028)|(tmp = 1824767560, tmp))>>>((1108035230.2692142)|(tmp = 2354035815, tmp)))/((tmp = -2602922032, tmp)>>(-925080304.7681987)))-x))))-(x>>x)))>>>((tmp = 751425805.8402164, tmp)|(tmp = 1165240270.3437088, tmp)))-x)*(2870745939))-(x>>>((tmp = 2986532631.405425, tmp)>>>(((tmp = 2547448699, tmp)+(((((x<<(((((-2756908638.4197435)>>>(3134770084))-(-1147872642.3756688))%(x*(tmp = -282198341.6600039, tmp)))+(-770969864.2055655)))+((-2725270341)^x))/(-3093925722))>>(x&x))>>((tmp = -2705768192, tmp)>>>(((tmp = 577253091.6042917, tmp)/(((x&(((((x+x)>>>(-1000588972))/(x&(717414336)))^(tmp = 428782104.21504414, tmp))>>>(1084724288.953223)))%(tmp = -2130932217.4562194, tmp))&x))-(-286367389)))))+((x>>(tmp = 2001277117, tmp))>>((tmp = 1028512592, tmp)^((tmp = 2055148650, tmp)+((tmp = 1490798399, tmp)/(tmp = -2077566434.2678986, tmp)))))))))); - assertEquals(-1, x |= (tmp = 1542129482, tmp)); - assertEquals(-671816743, x &= (tmp = -671816743.9111726, tmp)); - assertEquals(-1840333080, x -= (1168516337)); - assertEquals(-1755382023, x |= ((((tmp = 2625163636.0142937, tmp)>>>((tmp = 1534304735, tmp)^x))-(tmp = -1959666777.9995313, tmp))%x)); - assertEquals(-1750421896, x += (x>>>(tmp = -1364828055.1003118, tmp))); - assertEquals(-72864007, x %= (tmp = 239651127, tmp)); - assertEquals(-72863956, x -= (((tmp = -1103261657.626319, tmp)*((tmp = 2789506613, tmp)+((tmp = 2294239314, tmp)>>>(2588428607.5454817))))>>x)); - assertEquals(-170337477, x -= (tmp = 97473521, tmp)); - assertEquals(-170337477, x |= (((tmp = 246292300.58998203, tmp)/(((tmp = -2664407492, tmp)|((-2416228818)^(tmp = 909802077, tmp)))%(tmp = 532643021.68109465, tmp)))/(tmp = 1015597843.8295637, tmp))); - assertEquals(1, x >>>= (((tmp = -2247554641.7422867, tmp)/(1186555294))%(tmp = -785511772.3124621, tmp))); - assertEquals(1188939891.668705, x -= (tmp = -1188939890.668705, tmp)); - assertEquals(1188939891, x &= x); - assertEquals(1188413555, x &= (((tmp = -372965330.5709038, tmp)%(((tmp = 3108909487, tmp)|(x^(-1056955571.9951684)))^(-1549217484.009048)))/(x>>>(1403428437.9368362)))); - assertEquals(-0.7343692094664643, x /= (-1618278026.4758227)); - assertEquals(0, x -= x); - assertEquals(0, x &= (-2701762139.7500515)); - assertEquals(0, x >>>= (((-1692761485.2299166)^x)+(tmp = -1221349575.938864, tmp))); - assertEquals(0, x <<= ((2148160230)<<x)); - assertEquals(0, x <<= (((x<<(-740907931.38363))&(tmp = -930960051.6095045, tmp))>>(x/((tmp = -1921545150.1239789, tmp)/(-3015379806))))); - assertEquals(0, x <<= x); - assertEquals(NaN, x /= (x|x)); - assertEquals(0, x >>= (tmp = -2265988773, tmp)); - assertEquals(-0, x *= (((x<<(-928153614))<<(-989694208))^(2544757713.481016))); - assertEquals(0, x >>= ((tmp = 578009959.5299993, tmp)>>x)); - assertEquals(0, x /= ((((tmp = 412689800.0431709, tmp)&(1630886276))*(tmp = 2028783080.7296097, tmp))/x)); - assertEquals(0, x |= ((((x*(-2197198786))>>((2719887264.761987)<<(tmp = 2253246512, tmp)))-(tmp = -150703768.07045603, tmp))/(((-3160098146)%(((((1486098047.843547)>>(((tmp = -593773744.1144242, tmp)&(x<<(2651087978)))|((-680492758.930413)>>(tmp = 88363052.13662052, tmp))))<<x)<<(tmp = 2232672341, tmp))/((x<<x)&(((((348589117.64135563)<<(-1010050456.3097556))^(x/(tmp = -2282328795, tmp)))-(tmp = 1653716293, tmp))-((3157124731)/((tmp = 3007369535.341745, tmp)%(tmp = -2246556917, tmp)))))))+x))); - assertEquals(0, x >>= ((1935211663.5568764)>>(x-(tmp = 2116580032, tmp)))); - assertEquals(-1725272693, x ^= (tmp = -1725272693, tmp)); - assertEquals(313683, x >>>= (-1782632531.2877684)); - assertEquals(0.009772287443565642, x /= (tmp = 32099240, tmp)); - assertEquals(-647945916.9902277, x += (-647945917)); - assertEquals(3647021380, x >>>= ((((((((2470411371.688199)<<x)>>x)-(x>>>((tmp = 1750747780, tmp)/x)))-x)<<(tmp = -2666186351.695101, tmp))^(((tmp = 2749205312.6666174, tmp)%x)&(2069802830.360536)))<<(tmp = 6051917.9244532585, tmp))); - assertEquals(-647939220, x |= ((x>>>((tmp = -2980404582.794245, tmp)>>>(-996846982)))^x)); - assertEquals(-572178450, x |= ((-800571300.3277931)+(tmp = 2084365671, tmp))); - assertEquals(1172311208, x &= (x&((tmp = -1207487657.8953774, tmp)^x))); - assertEquals(12176516458994, x += ((((tmp = -1534997221, tmp)%(412142731))*((tmp = 2958726303, tmp)>>(1489169839)))+(((-574726407.2051775)>>>(((1772885017)<<(947804536.9958035))>>(-2406844737)))>>x))); - assertEquals(-1480065024, x <<= x); - assertEquals(-1736999042.227129, x += (tmp = -256934018.22712898, tmp)); - assertEquals(-1338699394, x ^= ((((((x%(((tmp = -2551168455.222048, tmp)|(3213507293.930222))/((-1559278033)>>((tmp = 3107774495.3698573, tmp)-(2456375180.8660913)))))*((x*(tmp = 1088820004.8562922, tmp))+((tmp = 1850986704.9836102, tmp)%(tmp = -1226590364, tmp))))*(1786192008))&(((2193303940.310299)%(tmp = 1041726867.0602217, tmp))|((2210722848)/((-1293401295.6714435)&((tmp = 3052430315, tmp)|x)))))>>>(tmp = -2028014470.1524236, tmp))+(((1695818039.0383925)<<((1669068145)*(-2746592133.899276)))<<(tmp = 519092169, tmp)))); - assertEquals(-334674849, x >>= (1170377794)); - assertEquals(-10214, x >>= ((tmp = 1074704264.3712895, tmp)>>>((tmp = -1200860192, tmp)^((tmp = 539325023.4101218, tmp)*((tmp = -588989295, tmp)|x))))); - assertEquals(1384169472, x &= (1384171140)); - assertEquals(1384169472, x >>>= ((tmp = -2161405973.830981, tmp)*(tmp = 2054628644, tmp))); - assertEquals(1610140972, x |= (527961388)); - assertEquals(1073273198, x += ((tmp = -259650225.71344328, tmp)&(tmp = -344359694, tmp))); - assertEquals(65507, x >>= ((x<<((tmp = 2925070713.5245204, tmp)%(x+((tmp = -1229447799, tmp)/(((x/(x|(((-2337139694)|((((((2996268529.7965417)&x)%(((tmp = -1088587413, tmp)>>(-1384104418.90339))>>((tmp = -1643984822.3946526, tmp)+x)))%(((1118125268.4540217)-((((-1975051668.6652594)-(-704573232))+((tmp = 1674952373, tmp)/(tmp = 1321895696.0062659, tmp)))*(tmp = 1820002533.2021284, tmp)))>>>(tmp = -583960746.9993203, tmp)))|((tmp = -2577675508.550925, tmp)&x))/(tmp = 1459790066, tmp)))/(((((1051712301.7804044)&(tmp = -2726396354, tmp))^(tmp = 263937254.18934345, tmp))+(((x^x)*(((tmp = -2289491571, tmp)+x)%(-2239181148)))&x))>>(tmp = -1743418186.3030887, tmp)))))/(tmp = 1475718622, tmp))<<x)))))|(x&((((tmp = -2934707420, tmp)<<x)/x)^(1022527598.7386684))))); - assertEquals(2047, x >>= (x-(tmp = 2300626270, tmp))); - assertEquals(8384512, x <<= (tmp = -1917680820, tmp)); - assertEquals(0, x <<= (2393691134)); - assertEquals(0, x >>= x); - assertEquals(649995936.5853252, x -= (tmp = -649995936.5853252, tmp)); - assertEquals(649995936, x &= x); - assertEquals(-0.33672017582945424, x /= (tmp = -1930374188, tmp)); - assertEquals(-0.33672017582945424, x += (x&((1208055031)^(-2761287670.968586)))); - assertEquals(0, x |= x); - assertEquals(0, x <<= ((-2038368978)/x)); - assertEquals(0, x >>= (x&((tmp = 2481378057.738218, tmp)&(x+(1172701643))))); - assertEquals(0, x <<= ((x*(((((((tmp = 70690601.3046323, tmp)&(((((((((((x+(x+(x^(3118107461))))<<(264682213.41888392))&(tmp = -709415381.8623683, tmp))%(((((-1840054964)>>>(tmp = -405893120.89603686, tmp))|((-625507229)^(3128979265)))>>(x>>((tmp = -2480442390, tmp)*((x>>(tmp = -421414980.88330936, tmp))>>>((tmp = 1850868592, tmp)&(-2948543832.879225))))))|((2986545185)&((tmp = -1947550706, tmp)%(((tmp = 2590238422.1414256, tmp)/(((tmp = -361038812, tmp)>>x)|(((tmp = 1798444068, tmp)|((x&((tmp = -3104542069, tmp)-x))*((tmp = -1158658918, tmp)+((tmp = 2777031040.5552707, tmp)<<(-2816019335.9008327)))))<<x)))/(((2287795988.231702)/x)/(((-2588712925)>>>(2521189250))*((tmp = -2533527920, tmp)+(tmp = 1762281307.2162101, tmp)))))))))/x)/(tmp = 1047121955.5357032, tmp))|(((-121292251)<<(x^(x-(tmp = 1420006180, tmp))))%((-2278606219)>>>(((tmp = -1412487726, tmp)&(((((tmp = 253596554.16016424, tmp)/(tmp = 2083376247.0079951, tmp))^(x^((1549116789.8449988)>>>((((-1844170084)^(tmp = 1886066422, tmp))&x)<<(34918329)))))^(tmp = -440805555.3369155, tmp))-x))%(-1936512969)))))+(2911511178.4035435))|(1012059391))|(x>>>(tmp = -2551794626.158037, tmp)))+((2926596072.210515)/(tmp = -280299595.0450909, tmp))))&((tmp = 1501086971, tmp)^(tmp = 2114076983, tmp)))-((-1679390574.1466925)-(941349044)))-((x>>x)>>((-2600539474.2033434)+(tmp = 2567056503.9079475, tmp))))*(tmp = 1285896052, tmp))%(((tmp = 1191465410.7595167, tmp)>>((tmp = -2857472754, tmp)%x))>>>(((tmp = 1960819627.6552541, tmp)&(-2651207221.127376))*((((-687312743)+((x>>x)<<x))|((((((1549588195)*((tmp = 2733091019, tmp)^((527322540)<<(x>>x))))%(tmp = -2063962943, tmp))*x)*(734060600))&(-3049417708)))+(((((1084267726)+((x|x)^((tmp = -1917070472.4858549, tmp)%((690016078.9375831)*x))))%((((((tmp = -2091172769, tmp)%(2532365378))>>>(-871354260))/(tmp = 254167019.07825458, tmp))&(1330216175.9871218))>>(tmp = 1931099207, tmp)))^(-1116448185.2618852))>>((961660080.8135855)/x)))))))>>>(-1486048007.7053368))); - assertEquals(0, x >>= x); - assertEquals(0, x %= (tmp = -1202200444.6506357, tmp)); - assertEquals(-0, x *= (-527500796.4145117)); - assertEquals(0, x >>= (tmp = -2082822707, tmp)); - assertEquals(0, x *= ((-1882398459.290778)>>>x)); - assertEquals(0, x &= (x/(tmp = -1569332286.392817, tmp))); - assertEquals(-390169607, x |= (-390169607.11600184)); - assertEquals(-780339214, x += x); - assertEquals(-780339214, x %= (2765959073)); - assertEquals(-5954, x >>= (tmp = -1900007055, tmp)); - assertEquals(743563420, x &= ((((-1520146483.5367205)|(-2075330284.3762321))-(tmp = -2263151872, tmp))%(-1264641939.957402))); - assertEquals(1487126840, x += (x>>>(((x+((tmp = -1263274491, tmp)>>>x))&(470419048.0490037))%(tmp = -2642587112, tmp)))); - assertEquals(Infinity, x /= (x^x)); - assertEquals(0, x ^= ((tmp = -1436368543, tmp)+(x/(tmp = -1125415374.3297129, tmp)))); - assertEquals(0, x += x); - assertEquals(0, x <<= x); - assertEquals(0, x &= (tmp = 3101147204.2905564, tmp)); - assertEquals(0, x &= (tmp = 2914487586.606511, tmp)); - assertEquals(0, x += x); - assertEquals(0, x -= (((-1738542908.6138556)&(((x+x)-(tmp = -2801153969, tmp))%(tmp = -1206684064.1477358, tmp)))>>((-2575546469.271897)|(tmp = -2573119106, tmp)))); - assertEquals(-1468808707, x ^= (tmp = -1468808707, tmp)); - assertEquals(1357349882, x <<= (tmp = -2808501087.7003627, tmp)); - assertEquals(-572025862, x |= ((((tmp = -2415486246.573399, tmp)/((tmp = -707895732.4593301, tmp)&x))%((-1960091005.0425267)*(972618070.9166157)))-(1649962343))); - assertEquals(327213586796843100, x *= (x%(1337884626))); - assertEquals(42991616, x &= (-2905576654.1280055)); - assertEquals(-26049289585042860, x *= (-605915571.6557121)); - assertEquals(597809748, x >>= ((362850791.077795)/(tmp = 1222777657.4401796, tmp))); - assertEquals(597809748, x |= x); - assertEquals(770065246, x -= ((-711227660)|(tmp = -508554506, tmp))); - assertEquals(593000483097040500, x *= x); - assertEquals(0, x %= x); - assertEquals(0, x <<= (317862995.456813)); - assertEquals(0, x >>= ((tmp = 2518385735, tmp)+((-2973864605.267604)/(-930953312.718833)))); - assertEquals(1227822411, x ^= (x^(1227822411.8553264))); - assertEquals(1090520320, x &= (x+((((-2100097959)>>(x/(tmp = -2002285068, tmp)))/(-364207954.9242482))-((tmp = 2771293106.7927113, tmp)-(tmp = -847237774, tmp))))); - assertEquals(1090520320, x >>= (((((2439492849)<<((-2932672756.2578926)*((743648426.7224461)+((2942284935)<<((x/(((tmp = 886289462.6565771, tmp)+(-459458622.7475352))>>(tmp = -785521448.4979162, tmp)))|(tmp = -11630282.877367258, tmp))))))-(tmp = -647511106.9602091, tmp))^x)&x)); - assertEquals(115944291.48829031, x %= (243644007.12792742)); - assertEquals(1, x /= x); - assertEquals(0, x >>>= ((tmp = -819782567, tmp)%(tmp = 2774793208.1994505, tmp))); - assertEquals(0, x >>= (tmp = 721096000.2409859, tmp)); - assertEquals(0, x &= ((x%x)%x)); - assertEquals(-0, x *= ((-1670466344)<<x)); - assertEquals(0, x >>= (-677240844.904707)); - assertEquals(NaN, x %= (((((-1575993236.6126876)/(-2846264078.9581823))^((((-2220459664)-(((-1809496020)>>>(tmp = -3015964803.4566207, tmp))&x))/(tmp = -3081895596.0486784, tmp))>>>(x&x)))%(x^(-1338943139)))^(x-((((2074140963.2841332)^(tmp = 1878485274, tmp))%(((x/(-2568856967.6491556))^x)<<((x+x)^((((2139002721)|(x<<(-1356174045.840464)))>>x)-(tmp = 2305062176, tmp)))))>>>(((((x<<(tmp = -1663280319.078543, tmp))-((1498355849.4158854)-((-1321681257)>>>(tmp = -1321415088.6152222, tmp))))^(-2266278142.1584673))+(858538943))&((((x-((x|(((tmp = -1576599651, tmp)+((tmp = 1595319586, tmp)&(-2736785205.9203863)))>>((x+((-1856237826)+x))<<(tmp = -1590561854.3540869, tmp))))^(((-41283672.55606127)&(tmp = 2971132248, tmp))+x)))/(-849371349.1667476))%(x*((-1705070934.6892798)>>>x)))<<((2418200640)*x))))))); - assertEquals(0, x >>>= (tmp = 664214199.5283061, tmp)); - assertEquals(0, x <<= ((-2827299151)<<(1815817649))); - assertEquals(1405772596, x |= (tmp = 1405772596, tmp)); - assertEquals(-1483422104, x <<= (-2791499935.6822596)); - assertEquals(-45271, x >>= (1740128943.4254808)); - assertEquals(-45271, x <<= ((2072269957)-((tmp = -2553664811.4472017, tmp)*(tmp = -2502730352, tmp)))); - assertEquals(1192951471.6745887, x -= (-1192996742.6745887)); - assertEquals(-353370112, x <<= (tmp = -1410280844, tmp)); - assertEquals(0, x ^= (x%((2754092728)*(-1017564599.1094015)))); - assertEquals(-2662096003.2397957, x -= (tmp = 2662096003.2397957, tmp)); - assertEquals(-2587094028.50764, x -= (tmp = -75001974.7321558, tmp)); - assertEquals(6693055512339889000, x *= x); - assertEquals(897526784, x %= (x-((tmp = 897526813, tmp)%(-1525574090)))); - assertEquals(7011928, x >>= ((-440899641.344357)%x)); - assertEquals(8382047686388683, x += (x*(1195398423.8538609))); - assertEquals(16764095372777366, x += x); - assertEquals(16764096859576696, x -= (tmp = -1486799329.7207344, tmp)); - assertEquals(16764099774187724, x += (2914611029)); - assertEquals(16764102926624664, x -= (-3152436939.724612)); - assertEquals(-538220648, x |= x); - assertEquals(269110324, x /= (((-2114698894.6014318)/(tmp = 767687453, tmp))>>(623601568.1558858))); - assertEquals(256, x >>= x); - assertEquals(-293446891, x += (x+(-293447403))); - assertEquals(119, x >>>= ((1759400753)>>(2481263470.4489403))); - assertEquals(14, x >>= (762849027.89693)); - assertEquals(16, x += (x&(x>>(1104537666.1510491)))); - assertEquals(-12499808227.980995, x *= (tmp = -781238014.2488122, tmp)); - assertEquals(1, x /= x); - assertEquals(1, x &= x); - assertEquals(0, x >>>= ((tmp = 1513381008, tmp)|(tmp = 1593208075.7259543, tmp))); - assertEquals(0, x &= (-788154636.2843091)); - assertEquals(-0, x /= (tmp = -2124830879, tmp)); - assertEquals(0, x &= (934237436)); - assertEquals(0, x |= x); - assertEquals(-79370942.97651315, x += (-79370942.97651315)); - assertEquals(-79370942.97651315, x %= ((tmp = -2683255523, tmp)<<(tmp = 2323123280.287587, tmp))); - assertEquals(-79370942, x |= x); - assertEquals(0.05861647801688159, x /= (-1354072177.061561)); - assertEquals(0, x <<= (((((((tmp = 1989257036, tmp)&(tmp = 1565496213.6578887, tmp))&x)&(tmp = -2798643735.905287, tmp))&(2354854813.43784))%(tmp = 1118124748, tmp))<<((tmp = 2453617740, tmp)*(((tmp = 1762604500.492329, tmp)<<(-2865619363))%(((2474193854.640994)|((tmp = 1425847419.6256948, tmp)|(((-1271669386)%((x|((tmp = -2059795445.3607287, tmp)+x))*(x*x)))>>>(tmp = -2997360849.0750895, tmp))))/(tmp = 2326894252, tmp)))))); - assertEquals(0, x >>>= ((-671325215)/((-727408755.8793397)>>(tmp = 315457854, tmp)))); - assertEquals(0, x >>= (x&x)); - assertEquals(0, x <<= ((x/x)>>>(((((x&x)-((x*(((tmp = -2689062497.0087833, tmp)^x)/((-1465906334.9701924)<<(tmp = -349000262, tmp))))*x))%(1630399442.5429945))*x)+((tmp = 605234630, tmp)%(tmp = 2325750892.5065155, tmp))))); - assertEquals(0, x |= (x%((x>>(((((tmp = 1622100459, tmp)<<x)&((((((tmp = 2411490075, tmp)<<x)|x)>>((x<<x)-(-2133780459)))/x)&(x+x)))%(x/((((tmp = 580125125.5035453, tmp)>>>(-470336002.1246581))|((tmp = 871348531, tmp)*x))>>(2866448831.23781))))-((2352334552)-(-562797641.6467373))))-(x^(tmp = -681731388, tmp))))); - assertEquals(0, x <<= (tmp = -1358347010.3729038, tmp)); - assertEquals(-260967814, x |= ((tmp = -260967814.45976686, tmp)%(tmp = 1126020255.1772437, tmp))); - assertEquals(NaN, x %= ((((tmp = 3176388281, tmp)<<(tmp = 611228283.2600244, tmp))>>>((tmp = 3068009824, tmp)+(tmp = 2482705111, tmp)))>>>((tmp = -750778285.2580311, tmp)>>>x))); - assertEquals(0, x <<= (x>>>x)); - assertEquals(0, x /= (1238919162)); - assertEquals(0, x >>= (x^x)); - assertEquals(0, x &= (-2137844801)); - assertEquals(0, x >>>= (x^(x*(-1774217252)))); - assertEquals(0, x >>= x); - assertEquals(0, x |= x); - assertEquals(0, x &= (x<<(tmp = 2791377560, tmp))); - assertEquals(-1330674638.8117397, x += (tmp = -1330674638.8117397, tmp)); - assertEquals(353, x >>>= (-212202857.4320326)); - assertEquals(353, x ^= ((((x+(tmp = 1448262278, tmp))-(-3141272537))>>(tmp = 1116596587.7832575, tmp))>>>((x-(((tmp = 303953098, tmp)>>>((tmp = 691514425, tmp)/((176223098)*(((2876180016)%(-1805235275.892374))|x))))<<(((tmp = 528736141.838547, tmp)^(2556817082))*(2898381286.2846575))))|((-1445518239)&(tmp = 389789481.9604758, tmp))))); - assertEquals(0, x >>>= (-227376461.14343977)); - assertEquals(0, x <<= (tmp = -2575967504, tmp)); - assertEquals(0, x <<= (x^((-2668391896)>>((x+(tmp = 598697235.9205595, tmp))+((((-2105306785)|((-1174912319.794015)>>>(x-((148979923)%((((tmp = -2459140558.4436393, tmp)|(1265905916.494016))^(tmp = 1213922357.2230597, tmp))|(1028030636))))))%x)+(((tmp = 1393280827.0135512, tmp)^((tmp = 1210906638, tmp)+(-1572777641.1396031)))<<x)))))); - assertEquals(0, x *= (tmp = 2134187165, tmp)); - assertEquals(-1084549964, x -= (tmp = 1084549964, tmp)); - assertEquals(-2045706240, x &= ((tmp = -1250758905.7889671, tmp)*(x+(((x<<(x/(tmp = -738983664.845448, tmp)))>>>x)&(tmp = 2197525295, tmp))))); - assertEquals(-2045706240, x ^= (((522049712.14743733)>>(tmp = -2695628092, tmp))>>>(tmp = -2603972068, tmp))); - assertEquals(2249261056, x >>>= x); - assertEquals(-33291, x |= ((((1891467762)<<(184547486.213719))-((458875403.50689447)^(((x&(x*x))|x)%(-3127945140))))|(-100765232))); - assertEquals(-33291, x %= (1460486884.1367688)); - assertEquals(-1, x >>= (tmp = -2667341441, tmp)); - assertEquals(-3.6289151568259606e-10, x /= (tmp = 2755644474.4072013, tmp)); - assertEquals(-3.6289151568259606e-10, x %= (tmp = 1186700893.0751028, tmp)); - assertEquals(0, x <<= (tmp = -1199872107.9612694, tmp)); - assertEquals(371216449, x ^= ((tmp = 371324611.1357789, tmp)&(x-(x|((tmp = -518410357, tmp)>>((tmp = 687379733, tmp)/x)))))); - assertEquals(0.3561383159088311, x /= (((((x%(((((-2293101242)%((((495316779)/x)-((-3198854939.8857965)>>>((tmp = -288916023, tmp)-(x^(tmp = -2504080119.431858, tmp)))))^(-1201674989)))-((2965433901)*(405932927)))/((1974547923)|(tmp = 534069372, tmp)))-(x-((x+(-1258297330))%x))))<<(((-2648166176.4947824)^(-3043930615))&(1550481610)))<<(tmp = -3118264986.743822, tmp))<<x)|x)); - assertEquals(-46272499.15029934, x -= (tmp = 46272499.50643766, tmp)); - assertEquals(-6, x >>= ((tmp = -731454087.0621192, tmp)>>>x)); - assertEquals(-2.7207928474520667e-9, x /= (((x<<(x|((tmp = -1650731700.9540024, tmp)/(tmp = -677823292, tmp))))^((((((1972576122.928667)>>x)%(2952412902.115453))<<((-2888879343)+(tmp = -425663504, tmp)))>>>(((((tmp = 1089969932, tmp)>>>(x|((-2088509661)/(1131470551))))>>>x)+x)|(tmp = 955695979.7982506, tmp)))|(((((tmp = 826954002.6188571, tmp)^(2016485728))|((x/(((x<<(tmp = 2493217141, tmp))/(-2259979800.997408))-(tmp = -427592173.41389966, tmp)))%(((-471172918)/x)>>>((383234436.16425097)&(tmp = 1664411146.5308032, tmp)))))*(tmp = 1863669754.7545495, tmp))*(x>>(2062197604)))))>>>((x-(2624545856))*(tmp = 1025803102, tmp)))); - assertEquals(0, x >>= ((tmp = 1068702028, tmp)*(296106770))); - assertEquals(0, x ^= (x/x)); - assertEquals(85359536, x ^= (((x|(((tmp = 740629227, tmp)<<(-1107397366))%((tmp = 2315368172, tmp)>>(((-2269513683)|(-2698795048))+(-396757976)))))*(929482738.803125))^(((-1415213955.4198723)-(tmp = -2885808324, tmp))>>>((tmp = -472842353.85736656, tmp)&(tmp = 1684231312.4497018, tmp))))); - assertEquals(2075131904, x <<= x); - assertEquals(123, x >>>= (x>>>(tmp = 754093009, tmp))); - assertEquals(0, x >>= ((-2690948145)/((1988638799)+x))); - assertEquals(0, x >>>= (tmp = -798849903.2467625, tmp)); - assertEquals(NaN, x %= x); - assertEquals(NaN, x *= (2431863540.4609756)); - assertEquals(484934656, x |= ((-2322193663)*(tmp = -2754666771, tmp))); - assertEquals(-82505091404694530, x *= (tmp = -170136513, tmp)); - assertEquals(-82505090515370620, x += ((-148762237)&(tmp = 889417717, tmp))); - assertEquals(-908221124, x %= (tmp = -2346393300, tmp)); - assertEquals(-1242515799, x ^= (2083328917)); - assertEquals(-1126056310271520600, x *= ((((tmp = -3065605442, tmp)<<(-3012703413))|x)^(-2081329316.4781387))); - assertEquals(-1126056309941068000, x += ((((tmp = 1886925157, tmp)&((tmp = -163003119.31722307, tmp)/((tmp = 2094816076, tmp)>>((tmp = -706947027, tmp)^x))))^((1819889650.5261197)<<(-1641091933)))>>x)); - assertEquals(-1864360191, x |= (((x/x)|x)|x)); - assertEquals(-1864360191, x &= x); - assertEquals(-3728720382, x += x); - assertEquals(1042663165, x ^= (535165183.4230335)); - assertEquals(2644530017.8833704, x += (1601866852.8833704)); - assertEquals(-574949401, x |= ((tmp = 943193254.5210983, tmp)^((x%(tmp = -2645213497, tmp))*(-1904818769)))); - assertEquals(1763223578, x ^= ((x^(tmp = -2244359016, tmp))^(tmp = 320955522, tmp))); - assertEquals(-1.9640961474334235, x /= (tmp = -897727731.0502782, tmp)); - assertEquals(1, x >>>= (x-(-3183031393.8967886))); - assertEquals(1, x &= (tmp = 1732572051.4196641, tmp)); - assertEquals(1, x >>= (-1642797568)); - assertEquals(-2339115203.3140306, x += (-2339115204.3140306)); - assertEquals(1955852093, x ^= (((((-1469402389)/(-2648643333.1454573))>>>x)<<(x/x))>>x)); - assertEquals(-965322519, x ^= (3001399252)); - assertEquals(-2139727840, x &= (tmp = 2298411812.964484, tmp)); - assertEquals(2103328, x &= (tmp = -2488723009, tmp)); - assertEquals(1799011007, x |= (tmp = -2498057537.226923, tmp)); - assertEquals(1799011007, x |= ((-308193085)>>>x)); - assertEquals(1799011007, x |= x); - assertEquals(818879107, x ^= (1542823996.423564)); - assertEquals(-2601416919234843600, x *= ((-2357923057.076759)-x)); - assertEquals(-2601416920481796600, x -= (x|(tmp = -3048039765, tmp))); - assertEquals(-33690112, x <<= x); - assertEquals(1039491072, x &= (tmp = 1039491474.3389125, tmp)); - assertEquals(126891, x >>= (-3079837011.6151257)); - assertEquals(-163191923097543, x *= (((tmp = -2847221258.4048786, tmp)*(x-(tmp = 1527622853.5925639, tmp)))^x)); - assertEquals(753616551, x ^= (-946895202)); - assertEquals(-347691264, x <<= (tmp = -433184408.33790135, tmp)); - assertEquals(0, x <<= (x|(tmp = -1911731462.6835637, tmp))); - assertEquals(-0, x *= (tmp = -2616154415.1662617, tmp)); - assertEquals(0, x >>= x); - assertEquals(0, x -= x); - assertEquals(0, x *= (2272504250.501526)); - assertEquals(0, x ^= x); - assertEquals(NaN, x %= x); - assertEquals(0, x >>>= (2475346113)); - assertEquals(NaN, x /= (((x+(-2646140897))&(((tmp = 1039073714.142481, tmp)-x)*x))|(x*(((-1277822905.773948)>>(tmp = 2035512354.2400663, tmp))*(77938193.80013895))))); - assertEquals(0, x ^= (x<<(tmp = 2491934268, tmp))); - assertEquals(0, x &= (tmp = 569878335.4607931, tmp)); - assertEquals(-88575883, x ^= ((453890820.8012209)-((1569189876)%((-1280613677.7083852)^(-1902514249.29567))))); - assertEquals(-88575883, x %= (tmp = 257947563.19206762, tmp)); - assertEquals(-88575881.7863678, x -= ((tmp = 1257547359.029678, tmp)/(x^(tmp = 948265672.821815, tmp)))); - assertEquals(-169, x >>= (tmp = -2530523309.6703596, tmp)); - assertEquals(-1, x >>= x); - assertEquals(-1, x |= x); - assertEquals(131071, x >>>= (-673590289)); - assertEquals(1117196836, x -= (-1117065765)); - assertEquals(3092236000.7125187, x -= (-1975039164.7125185)); - assertEquals(1, x /= x); - assertEquals(-1599945863, x ^= (tmp = 2695021432.453696, tmp)); - assertEquals(940543782, x ^= (tmp = 2561494111, tmp)); - assertEquals(891400321673221800, x *= (tmp = 947749949.2662871, tmp)); - assertEquals(-1509927296, x >>= ((tmp = 1113290009, tmp)-x)); - assertEquals(-23, x >>= (tmp = 3216989626.7370152, tmp)); - assertEquals(-0, x %= x); - assertEquals(0, x <<= (431687857.15246475)); - assertEquals(-0, x /= (tmp = -1924652745.081665, tmp)); - assertEquals(0, x <<= (1312950547.2179976)); - assertEquals(0, x %= ((tmp = 2110842937.8580878, tmp)|(x<<x))); - assertEquals(0, x >>>= ((((-386879000)-((tmp = -2334036143.9396124, tmp)/((tmp = 965101904.2841234, tmp)<<(((3029227182.8426695)<<((tmp = -464466927, tmp)>>((((((tmp = 849594477.4111787, tmp)^(x&((513950657.6663146)%(x>>>x))))-((2898589263)|x))+(tmp = 2842171258.621288, tmp))>>>(tmp = -3158746843, tmp))<<(tmp = -2891369879, tmp))))-(x-(x&(tmp = -1707413686.2706504, tmp)))))))-(-2860419051))*(-1708418923))); - assertEquals(-328055783, x += ((((2857010474.8010874)|((tmp = -1415997622.320347, tmp)-(-1706423374)))%(tmp = 824357977.1339042, tmp))^(x>>(x|x)))); - assertEquals(-168539902503779140, x *= ((tmp = -1057687018, tmp)<<((1408752963)-(2030056734)))); - assertEquals(-Infinity, x /= ((x-(2232683614.320658))*(((tmp = 195551174, tmp)*((((739595970)>>>(tmp = -2218890946.8788786, tmp))>>>(((tmp = -240716255.22407627, tmp)&(((((1598029916.3478878)|((tmp = -881749732, tmp)+(x>>x)))^(4443059))<<(((tmp = 2453020763, tmp)+((x>>>(tmp = -1904203813, tmp))&(-355424604.49235344)))<<(tmp = 2814696070, tmp)))%((tmp = -250266444, tmp)>>>(((((2710614972)&(((tmp = 910572052.6994087, tmp)^(tmp = -1028443184.3220406, tmp))/((-2718010521)^(tmp = 676361106, tmp))))|x)^(-1326539884))>>(-1573782639.7129154)))))/(tmp = 1923172768, tmp)))>>>(tmp = -2858780232.4886074, tmp)))/((((((-2060319376.353397)%x)>>(tmp = -3122570085.9065285, tmp))/(tmp = -1499018723.8064275, tmp))*((-655257391)<<x))>>x)))); - assertEquals(NaN, x += ((3059633304)%((((tmp = 2538190083, tmp)*((tmp = -2386800763.356364, tmp)/x))&(1341370996))%(-2929765076.078223)))); - assertEquals(NaN, x %= ((x&(347774821))>>>(462318570.2578629))); - assertEquals(NaN, x *= ((2829810152.071517)*(tmp = 768565684.6892327, tmp))); - assertEquals(NaN, x -= x); - assertEquals(0, x >>>= (x&(tmp = 1786182552, tmp))); - assertEquals(973967377, x ^= ((tmp = 2115869489.836838, tmp)&(994956497))); - assertEquals(985246427.4230617, x += (11279050.423061728)); - assertEquals(985246427, x &= x); - assertEquals(0, x >>= ((tmp = 1090502660.1867907, tmp)>>((-1599370623.5747645)-(tmp = -1321550958, tmp)))); - assertEquals(0, x %= (tmp = -2386531950.018572, tmp)); - assertEquals(0, x >>>= x); - assertEquals(NaN, x /= x); - assertEquals(0, x >>>= (tmp = -1535987507.682257, tmp)); - assertEquals(-0, x /= (-2570639987)); - assertEquals(-542895632, x |= (tmp = -542895632, tmp)); - assertEquals(-33930977, x >>= (tmp = -861198108.1147206, tmp)); - assertEquals(-0, x %= x); - assertEquals(0, x ^= (x*(-608154714.1872904))); - assertEquals(-140011520, x |= ((tmp = 377418995, tmp)<<((1989575902)>>(tmp = -2558458031.066773, tmp)))); - assertEquals(-140026048, x -= ((((tmp = 1465272774.7540011, tmp)<<((2164701398)<<(tmp = -818119264, tmp)))>>((tmp = -1490486001, tmp)>>(664410099.6412607)))>>(x>>>(((tmp = -2438272073.2205153, tmp)%(tmp = 2142162105.4572072, tmp))-(tmp = 2259040711.6543813, tmp))))); - assertEquals(39214588236996610, x *= (x<<(-401696127.06632423))); - assertEquals(1, x /= x); - assertEquals(0, x %= x); - assertEquals(0, x *= ((tmp = -1709874807.176726, tmp)&(-2786424611))); - assertEquals(-1320474063.3408537, x += (tmp = -1320474063.3408537, tmp)); - assertEquals(88, x >>>= (tmp = -3179247911.7094674, tmp)); - assertEquals(1606348131, x += ((tmp = 1555621121.5726175, tmp)|(-3026277110.9493155))); - assertEquals(200793516, x >>>= x); - assertEquals(-2952688672.1074514, x -= (tmp = 3153482188.1074514, tmp)); - assertEquals(1342278624, x >>>= ((x>>>((tmp = 1264475713, tmp)-(-913041544)))>>>((tmp = 2008379930, tmp)%(tmp = 3105129336, tmp)))); - assertEquals(0, x ^= x); - assertEquals(0, x /= (tmp = 788363717, tmp)); - assertEquals(430466213, x -= (tmp = -430466213, tmp)); - assertEquals(164757385222499550, x *= (tmp = 382741735, tmp)); - assertEquals(164757385222499550, x %= (((tmp = 1974063648, tmp)%((806015603)>>>x))*((tmp = 2836795324, tmp)<<(tmp = -1785878767, tmp)))); - assertEquals(-190957725.86956096, x /= (x^((-2939333300.066044)-(x|(-2085991826))))); - assertEquals(-190957725.86956096, x %= (tmp = -948386352, tmp)); - assertEquals(0.6457336106922105, x /= (-295722141)); - assertEquals(0, x |= ((415991250)&((x>>(tmp = -3188277823, tmp))<<(511898664.1008285)))); - assertEquals(0, x &= ((793238922)|x)); - assertEquals(-1576701979, x ^= (2718265317)); - assertEquals(-49271937, x >>= x); - assertEquals(-49271937, x |= x); - assertEquals(-49271937, x &= x); - assertEquals(775316382, x -= (-824588319)); - assertEquals(912498176, x <<= (tmp = -2223542776.836312, tmp)); - assertEquals(0, x -= (x&((tmp = 1999412385.1074471, tmp)/(-1628205254)))); - assertEquals(0, x -= x); - assertEquals(0, x >>= (-768730139.7749677)); - assertEquals(-1861304245, x |= (((5128483)^(((tmp = -1768372004, tmp)/(x^(tmp = 1310002444.757094, tmp)))*((tmp = 188242683.09898067, tmp)^(tmp = -2263757432, tmp))))^((tmp = 2223246327, tmp)*((tmp = -2360528979, tmp)-((tmp = 2442334308, tmp)>>(458302081)))))); - assertEquals(1, x /= x); - assertEquals(2, x += x); - assertEquals(1, x /= x); - assertEquals(0, x ^= x); - assertEquals(-0, x *= (-1852374359.3930533)); - assertEquals(0, x <<= (tmp = 1223645195.148961, tmp)); - assertEquals(1789655087, x |= ((-2505312209.770559)>>x)); - assertEquals(-65568768, x <<= x); - assertEquals(4229398528, x >>>= x); - assertEquals(-8408187, x |= (-3029781627)); - assertEquals(-8408187, x |= (((2322165037)-((tmp = -1424506897.362995, tmp)%x))&x)); - assertEquals(-7884926, x += (x>>>(x|(2738095820)))); - assertEquals(-7884926, x %= (576507013)); - assertEquals(751801768, x ^= (tmp = -750241238, tmp)); - assertEquals(-1986010067668600800, x *= (tmp = -2641667195, tmp)); - assertEquals(1921196240, x ^= (x%(-1954178308))); - assertEquals(847388880, x ^= ((tmp = 1632856124, tmp)&((tmp = -1536309755, tmp)<<(tmp = -3158362800, tmp)))); - assertEquals(-469662000.6651099, x += (tmp = -1317050880.6651099, tmp)); - assertEquals(-812358332, x ^= ((-2832480471)>>>(2016495937))); - assertEquals(21, x ^= (((tmp = 1815603134.2513008, tmp)/((tmp = 147415927, tmp)%(-1059701742)))+x)); - assertEquals(-2844409139.792712, x += (tmp = -2844409160.792712, tmp)); - assertEquals(177070, x >>>= x); - assertEquals(0, x %= x); - assertEquals(0, x >>= x); - assertEquals(1459126376, x ^= (tmp = -2835840920, tmp)); - assertEquals(1459126376, x %= (-1462864282)); - assertEquals(0, x >>>= (tmp = 2922724319, tmp)); - assertEquals(338995506, x ^= (338995506.6411549)); - assertEquals(336896258, x &= (2635904967)); - assertEquals(336634112, x -= (x&(tmp = 1659656287, tmp))); - assertEquals(NaN, x %= (x-x)); - assertEquals(NaN, x /= (tmp = -674606200, tmp)); - assertEquals(NaN, x %= ((x|(2788108542))/(x+(tmp = 600941473, tmp)))); - assertEquals(0, x >>>= ((-1858251597.3970242)>>>x)); - assertEquals(1951294747, x |= (tmp = 1951294747, tmp)); - assertEquals(1951294747, x &= x); - assertEquals(-153190625, x |= (-1500095737)); - assertEquals(23467367587890624, x *= x); - assertEquals(346531290.1813514, x /= (((((-513617734.11148167)|x)/((tmp = -2042982150.1170752, tmp)%((x%((x%x)>>>(((-1369980151)&(((922678983)%(x&(tmp = -855337708, tmp)))-((tmp = -2717183760, tmp)>>>((1939904985.4701347)%(((tmp = -2473316858, tmp)&((tmp = -599556221.9046664, tmp)>>((tmp = -6352213, tmp)/x)))&x)))))%x)))/((tmp = -1842773812.8648412, tmp)>>>(((x>>>(tmp = 499774063, tmp))<<(((tmp = -1353532660.5755146, tmp)*(-3070956509))>>(((-905883994.0188017)>>(tmp = -16637173, tmp))<<((tmp = 471668537, tmp)*((tmp = -232036004.26637793, tmp)/x)))))&(tmp = 85227224, tmp))))))>>>(x|(-2528471983)))-((tmp = 1531574803, tmp)+((x>>>x)-(2889291290.158888))))); - assertEquals(-94.42225749399837, x /= (((tmp = 2381634642.1432824, tmp)>>(tmp = -2637618935, tmp))|(2307200473))); - assertEquals(-47, x >>= (1524333345.141235)); - assertEquals(-2.8699253616435082e-8, x /= (1637673252)); - assertEquals(0, x |= x); - assertEquals(1083427040, x += ((-2012055268)<<(tmp = -2192382589.6911573, tmp))); - assertEquals(1083427040, x %= (x*x)); - assertEquals(2694039776, x += ((((-1740065704.9004602)<<(-736392934))%(2781638048.424092))>>>(x&x))); - assertEquals(-1600927520, x |= ((tmp = 2904430054.869525, tmp)*(((1054051883.4751332)*x)*((-939020743)-(tmp = 1636935481.1834455, tmp))))); - assertEquals(-1600927520, x -= (x%x)); - assertEquals(3037584978216498700, x *= (tmp = -1897390694, tmp)); - assertEquals(372598954.1823988, x %= (tmp = 1553763703.5082102, tmp)); - assertEquals(-1476395008, x <<= ((x>>((tmp = 282496335.49494267, tmp)^((-1948623419.6947453)|((((((tmp = -1203306995, tmp)-(-5554612.355098486))>>>(1867254951.4836824))>>x)|(-695777865))/((-59122652.19377303)<<(-609999229.7448442))))))>>(x/(tmp = -1207010654.9993455, tmp)))); - assertEquals(-2.2540185787941605, x /= (((tmp = 1364159859.9199843, tmp)*x)>>x)); - assertEquals(-2, x |= x); - assertEquals(2241824008, x *= ((3174055292.962967)>>(((-2379151623.602476)>>(tmp = -1423760236, tmp))>>(tmp = -522536019.2225733, tmp)))); - assertEquals(-2138158385, x ^= ((x>>((((1316131966.9180691)-((x*x)>>x))>>>x)>>((-2712430284)|(((((x<<(-616185937.6090865))-(((x-(tmp = 2957048661, tmp))<<(tmp = 617564839.888214, tmp))/(x%((tmp = -447175647.9393475, tmp)<<(2203298493.460617)))))-((x&((x<<(914944265))^(((-1294901094)*((tmp = 2512344795, tmp)+((((tmp = -1227572518, tmp)%(1831277766.4920158))*((x|x)^(tmp = 2515415182.6718826, tmp)))*x)))-(961485129))))>>>(tmp = 2079018304, tmp)))>>(tmp = 734028202, tmp))^(554858721.6149715)))))-((tmp = 1312985279.5114603, tmp)^(tmp = 2450817476.179955, tmp)))); - assertEquals(2.759030298237921, x /= (x|(tmp = -775901745.3688724, tmp))); - assertEquals(8, x <<= x); - assertEquals(NaN, x %= (((x&((1792031228.831834)>>(-1174912501)))%(((-2351757750)+(tmp = -2610099430, tmp))*(-2811655968)))*(x&(tmp = -1881632878, tmp)))); - assertEquals(0, x &= ((x*(616116645.7508612))^(2789436828.536846))); - assertEquals(0, x *= x); - assertEquals(35097452, x ^= ((tmp = 1023684579, tmp)%(((x|((tmp = -757953041, tmp)+(772988909)))+(tmp = -2934577578, tmp))>>>((tmp = -1973224283, tmp)>>>((x*(2244818063.270375))|(x-(-716709285))))))); - assertEquals(0.015207441433418992, x /= (2307913014.4056892)); - assertEquals(-5865042.942076175, x -= (5865042.957283616)); - assertEquals(-67719.94207617454, x %= (((1464126615.2493973)+(398302030.0108756))>>>x)); - assertEquals(4294899577, x >>>= (x<<x)); - assertEquals(-1, x >>= (tmp = 607447902, tmp)); - assertEquals(-1, x >>= (3081219749.9119744)); - assertEquals(6.53694303504065e-10, x /= (tmp = -1529767040.4034374, tmp)); - assertEquals(6.53694303504065e-10, x %= ((tmp = 899070650.7190754, tmp)&(tmp = -1101166301, tmp))); - assertEquals(6.53694303504065e-10, x %= (tmp = -2207346460, tmp)); - assertEquals(NaN, x %= (((x&x)>>x)%(((-10980184)+x)&(tmp = -1473044870.4729445, tmp)))); - assertEquals(NaN, x -= x); - assertEquals(-1755985426, x ^= (tmp = 2538981870, tmp)); - assertEquals(-13842, x %= ((((-2258237411.3816605)+(-1325704332.0531585))<<((tmp = -877665450.1877053, tmp)>>(((((2420989037)+(2084279990.6278818))*(-327869571.9348242))+x)^x)))>>>x)); - assertEquals(1, x /= x); - assertEquals(1, x >>= ((2241312290)^(2859250114))); - assertEquals(0, x >>= x); - assertEquals(-1615631756, x |= (-1615631756.1469975)); - assertEquals(-1615631756, x |= x); - assertEquals(-627245056, x <<= ((x*(tmp = -1308330685.5971081, tmp))|(tmp = 1479586158, tmp))); - assertEquals(-627245056, x |= x); - assertEquals(1786953888, x ^= (-1340096352.1839824)); - assertEquals(1668014353, x -= (tmp = 118939535, tmp)); - assertEquals(1, x /= x); - assertEquals(-645681, x ^= ((-1322356629)>>(tmp = 1829870283, tmp))); - assertEquals(-1322354688, x <<= (-794779253)); - assertEquals(-4310084378.672725, x += (-2987729690.6727247)); - assertEquals(-8620168757.34545, x += x); - assertEquals(-8720421, x |= (tmp = -748107877.6417065, tmp)); - assertEquals(-1508858270, x ^= (1500137913)); - assertEquals(-0.825735756765112, x /= (1827289490.1767085)); - assertEquals(1253449509.1742642, x += (((tmp = 1253449509.9576545, tmp)-(((tmp = 2860243975, tmp)+(367947569.85976696))>>(((((530960315)>>>((((x%(tmp = -2203199228, tmp))<<(x*(((tmp = -117302283, tmp)/(x-((2579576936)%(-1225024012))))&(tmp = -2857767500.1967726, tmp))))/((x/((tmp = -166066119, tmp)<<x))|x))>>>x))|(((2771852372)>>(((tmp = -3103692094.1463976, tmp)-(tmp = 2867208546.069278, tmp))>>>(702718610.1963737)))|(tmp = 2680447361, tmp)))>>x)>>(-2006613979.051014))))^((-1665626277.9339101)/(x<<(tmp = 342268763, tmp))))); - assertEquals(1693336701.1742642, x += (tmp = 439887192, tmp)); - assertEquals(0.8479581831275719, x /= ((1171383583)+(((x&x)>>>(51482548.618915915))-(tmp = -825572595.1031849, tmp)))); - assertEquals(28, x |= ((tmp = -2355932919.6737213, tmp)>>(tmp = -2395605638, tmp))); - assertEquals(0, x %= x); - assertEquals(0, x -= x); - assertEquals(0, x <<= (x^((tmp = 2793423893.484949, tmp)*(1585074754.3250475)))); - assertEquals(0, x >>= (x/(x-((957719861.9175875)&(1288527195))))); - assertEquals(0, x >>>= ((-1429196921.4432657)/x)); - assertEquals(-852424225.734199, x -= (tmp = 852424225.734199, tmp)); - assertEquals(-46674433, x |= ((tmp = -2335242963, tmp)*((2135206646.2614377)>>(tmp = 505649511.8292929, tmp)))); - assertEquals(2944662357, x += (tmp = 2991336790, tmp)); - assertEquals(1404, x >>>= (849155189.1503456)); - assertEquals(-846755170, x ^= (tmp = -846753822.4471285, tmp)); - assertEquals(52615, x >>>= ((-517068110)+x)); - assertEquals(1475021859.9916897, x += (tmp = 1474969244.9916897, tmp)); - assertEquals(0, x %= x); - assertEquals(0, x %= ((539583595.8244679)*(tmp = 1469751690.9193692, tmp))); - assertEquals(0, x &= (807524227.2057163)); - assertEquals(NaN, x %= x); - assertEquals(NaN, x -= (x^((tmp = -362481588, tmp)%(2611296227)))); - assertEquals(NaN, x *= x); - assertEquals(0, x >>= ((-2519875630.999908)<<x)); - assertEquals(NaN, x %= x); - assertEquals(NaN, x += (((tmp = 2485209575, tmp)>>(tmp = 2326979823, tmp))%(x-(((-1296334640.7476478)&x)<<x)))); - assertEquals(0, x >>= (((tmp = 1370704131, tmp)^((((tmp = 793217372.7587746, tmp)>>(((-1455696484.109328)|(((((-2186284424.5379324)<<(tmp = 3052914152.254852, tmp))-(x>>(tmp = 3121403408, tmp)))+((778194280)-(((((tmp = 2398957652, tmp)-(x+(((-2592019996.937958)>>((tmp = 1648537981, tmp)>>x))<<(-677436594))))<<(39366669.09012544))|((tmp = 3133808408.9582872, tmp)-(-2987527245.010673)))*x)))|((tmp = -2178662629, tmp)<<x)))^(((tmp = 909652440.3570575, tmp)%(-2572839902.6852217))%(-1879408081))))*(tmp = -2910988598, tmp))&(((x^x)>>(2822040993))|((x*x)^(((1072489842.6785052)|(x-(((464054192.7390214)^x)<<(tmp = -2754448095, tmp))))*((tmp = -1544182396, tmp)/(tmp = -3198554481, tmp)))))))^(tmp = 1946162396.9841106, tmp))); - assertEquals(371272192, x |= (((x^((x-(x/x))&(tmp = 2370429394, tmp)))-(tmp = -403692829, tmp))*(tmp = 2808636109, tmp))); - assertEquals(929786482, x |= ((729966239.8987448)^(x-((tmp = 120127779, tmp)^((tmp = -3088531385, tmp)>>>((x+((tmp = 2364833601, tmp)>>>(((599149090.6666714)>>(tmp = 2838821032, tmp))%(tmp = -662846011, tmp))))-(tmp = 1168491221.1813436, tmp))))))); - assertEquals(-681121542, x += ((-1610909505.998718)^((tmp = -957338882, tmp)>>>(tmp = 1935594133.6531684, tmp)))); - assertEquals(-2147483648, x <<= ((tmp = 15161708, tmp)|(2453975670))); - assertEquals(-2147483648, x >>= x); - assertEquals(0, x <<= (2080486058)); - assertEquals(0, x &= (((x&(tmp = -767821326, tmp))/((tmp = 1877040536, tmp)>>>(tmp = 2378603217.75597, tmp)))*(-1601799835))); - assertEquals(0, x %= (-1820240383)); - assertEquals(1621233920, x ^= ((tmp = 820230232, tmp)*(1727283900))); - assertEquals(1621233920, x |= (x>>>x)); - assertEquals(1621233931, x += ((tmp = 794966194.9011587, tmp)>>(tmp = -597737830.5450518, tmp))); - assertEquals(1621276543, x |= (((x^((2354444886)+(tmp = 685142845.4708651, tmp)))-(tmp = 790204976.9120214, tmp))>>>((((tmp = -2792921939, tmp)/(((((tmp = -80705524, tmp)<<x)-(((((((tmp = 1951577216.379527, tmp)>>>x)%((-529882150)>>>(tmp = -1682409624, tmp)))<<((-42043756.29025769)-(-1803729173.6855814)))/(2937202170.118023))*(tmp = -1998098798.5722106, tmp))*(tmp = -2996229463.904228, tmp)))&x)>>>(-301330643)))/(-2858859382.0050273))-(tmp = 1571854256.0740635, tmp)))); - assertEquals(810638271, x >>>= (x/(1553632833))); - assertEquals(810638271, x <<= (tmp = -1467397440, tmp)); - assertEquals(-2147483648, x <<= x); - assertEquals(871068871, x ^= (tmp = 3018552519, tmp)); - assertEquals(-1073743881, x |= ((tmp = 2294122324.020989, tmp)|(tmp = -1799706842.4493146, tmp))); - assertEquals(-77816868, x += (((-2225296403)&x)>>(tmp = -2667103424.445239, tmp))); - assertEquals(-1215889, x >>= (tmp = 1876107590.8391647, tmp)); - assertEquals(-2431778, x += x); - assertEquals(4292535518, x >>>= (((x>>(-1825580683))/x)%x)); - assertEquals(4292802560, x -= (x|(1492864090))); - assertEquals(0, x -= x); - assertEquals(0, x >>= x); - assertEquals(0, x %= (tmp = 2173121205, tmp)); - assertEquals(0, x *= (x>>x)); - assertEquals(1565261471, x |= ((1565261471.323931)>>>x)); - assertEquals(0, x -= x); - assertEquals(-86980804, x |= (-86980804)); - assertEquals(-698956484, x -= (((((2754713793.1746016)*(((((-1514587465.0698888)>>(tmp = -1307050817, tmp))/(tmp = 2368054667.438519, tmp))*(-1908125943.5714772))<<(x>>>(-357164827.4932244))))+(1257487617))<<(2954979945))&(612330472))); - assertEquals(-1073741824, x <<= x); - assertEquals(54497747, x ^= (-1019244077.098908)); - assertEquals(54501375, x |= (((tmp = 1944912427, tmp)>>>x)%x)); - assertEquals(0, x -= x); - assertEquals(0, x -= x); - assertEquals(-0, x *= (-1748215388)); - assertEquals(0, x >>= x); - assertEquals(0, x >>>= (((tmp = 988769112, tmp)%(tmp = -3133658477, tmp))<<x)); - assertEquals(0, x %= (1685221089.2950323)); - assertEquals(0, x >>>= (x+((793467168)-(tmp = 135877882, tmp)))); - assertEquals(0, x %= ((tmp = -2406801984, tmp)%(tmp = -987618172, tmp))); - assertEquals(0, x *= ((-2943444887.953456)|(tmp = -2327469738.4544783, tmp))); - assertEquals(0, x >>= x); - assertEquals(-145484729.70167828, x += (tmp = -145484729.70167828, tmp)); - assertEquals(1140855872, x &= (x^(tmp = 3151437967.965556, tmp))); - assertEquals(1486808408, x += (tmp = 345952536, tmp)); - assertEquals(107846582.36594129, x %= (-1378961825.6340587)); - assertEquals(-642031616, x <<= (x+x)); - assertEquals(151747770.95108718, x *= (x/(tmp = 2716379907, tmp))); - assertEquals(192723456, x <<= (tmp = -1731167384, tmp)); - assertEquals(2151208003, x -= ((-2151208003)+x)); - assertEquals(1, x /= x); - assertEquals(1, x |= x); - assertEquals(1996766603, x |= (1996766602)); - assertEquals(895606123, x ^= (tmp = 1113972960.966081, tmp)); - assertEquals(-1500036886, x ^= (tmp = 2482412929, tmp)); - assertEquals(-1542644247, x ^= (x>>>((tmp = 51449105, tmp)>>>(((-2057313176)*x)/(-1768119916))))); - assertEquals(-1496074063273093600, x *= ((tmp = 786152274, tmp)^(387292498))); - assertEquals(-794329073, x %= (((tmp = -2314637675.617696, tmp)*((((x*(411053423.29070306))-(2889448433.4240828))/((-970630131)/(tmp = -2886607600.7423067, tmp)))<<(tmp = 1263617112.9362245, tmp)))|(2816980223.8209996))); - assertEquals(2468008436047106600, x *= (tmp = -3107035257.725115, tmp)); - assertEquals(3040956928, x >>>= ((tmp = 1514372119.1787262, tmp)*(3169809008))); - assertEquals(-19, x >>= (tmp = -266966022.10604453, tmp)); - assertEquals(-1.6505580654964654e-8, x /= ((-3143841480)>>(x-x))); - assertEquals(-2.2420284729165577e-7, x *= (x*((((703414102.2523813)%(tmp = 2989948152, tmp))-((-1583401827.2949386)^((tmp = -1916731338, tmp)%((331500653.3566053)|(((tmp = 29865940, tmp)+((tmp = -2294889418.6764183, tmp)<<(tmp = -1558629267.255229, tmp)))>>>(x*(x+x)))))))|((988977957)&(-2986790281))))); - assertEquals(0, x ^= (x/(tmp = 781117823.345541, tmp))); - assertEquals(NaN, x *= (((x^((((tmp = -2969290335, tmp)+(((((tmp = -175387021, tmp)&(tmp = -1080807973, tmp))<<(tmp = -2395571076.6876855, tmp))|((tmp = -1775289899.4106793, tmp)^x))|(-2963463918)))*(tmp = -1761443911, tmp))^(tmp = 847135725, tmp)))<<((146689636)<<x))%x)); - assertEquals(0, x ^= x); - assertEquals(1720182184, x -= (((tmp = 3184020508, tmp)|((-489485703)+(tmp = -2644503573, tmp)))&(tmp = 2575055579.6375213, tmp))); - assertEquals(1720182184, x >>= (x<<(-45408034))); - assertEquals(5.759243187540471e+27, x *= (((x&(1456298805))+(x<<(106573181)))*((566861317.2877743)+(2262937360.3733215)))); - assertEquals(5.759243187540471e+27, x -= (tmp = -1365873935, tmp)); - assertEquals(0, x <<= x); - assertEquals(0, x >>= (1960073319.3465362)); - assertEquals(0, x <<= x); - assertEquals(560463904, x += ((tmp = 1844076589.9286406, tmp)&((((((-691675777.5800121)|(-745631201))|x)+(tmp = 1504458593.2843904, tmp))-x)<<x))); - assertEquals(-513210271, x -= (x|(1052702623.7761713))); - assertEquals(3781757025, x >>>= ((-1346666404.362477)*(tmp = 2798191459, tmp))); - assertEquals(1080100929, x &= (1122097879.882534)); - assertEquals(1276833905.8093092, x *= ((1276833905.8093092)/x)); - assertEquals(1276833905.8093092, x %= (1796226525.7152414)); - assertEquals(1276833905, x <<= (((tmp = -491205007.83412814, tmp)*(tmp = 1496201476.496839, tmp))>>(x+((tmp = -854043282.114594, tmp)-((x|(tmp = -807842056, tmp))*x))))); - assertEquals(1276833905, x %= (((-1870099318)>>>(((tmp = -2689717222, tmp)/(248095232))/(tmp = 1036728800.5566598, tmp)))&(((((857866837)>>(tmp = 3034825801.740485, tmp))|(-1676371984))>>>(x<<x))%((-3035366571.0221004)*(1578324367.8819473))))); - assertEquals(1, x /= x); - assertEquals(2819223656.189109, x += (2819223655.189109)); - assertEquals(-1475743640, x >>= (((tmp = 2586723314.38089, tmp)/(x&(tmp = -697978283.9961061, tmp)))<<(x%((-1167534676)>>(x^((tmp = -284763535, tmp)*((x%x)&((((tmp = 2916973220.726839, tmp)%x)/(tmp = -1338421209.0621986, tmp))|((tmp = -834710536.803335, tmp)%x))))))))); - assertEquals(-3267683406, x -= (tmp = 1791939766, tmp)); - assertEquals(-2090420900700614100, x *= (639725653)); - assertEquals(-1540353536, x %= ((-1800269105)<<((((x&(((tmp = 1135087416.3945065, tmp)^(613708290))>>x))>>(tmp = -1234604858.7683473, tmp))^(2404822882.7666225))>>>((tmp = -287205516, tmp)-((1648853730.1462333)^((x+(x%((tmp = 359176339, tmp)%((2856479172)<<(tmp = -1995209313, tmp)))))^(((tmp = 2857919171.839304, tmp)>>>(tmp = 2779498870, tmp))>>x))))))); - assertEquals(-2093767030, x ^= (654554250.498078)); - assertEquals(1, x >>>= ((tmp = -166296226.12181997, tmp)^(x/x))); - assertEquals(-1487427474, x -= ((x<<x)|(1487427475.4063978))); - assertEquals(-1487427470.562726, x += ((-1226399959.8267038)/((tmp = 2172365551, tmp)<<x))); - assertEquals(-3457859227618939400, x *= (tmp = 2324724597.3686075, tmp)); - assertEquals(396221312, x >>= (-1354035390)); - assertEquals(0, x %= x); - assertEquals(0, x &= (tmp = 2733387603, tmp)); - assertEquals(1485905453, x |= ((((tmp = -1321532329.304437, tmp)&((((tmp = 1817382709.4180388, tmp)%(((tmp = 2089156555.7749293, tmp)-(-1555460267))|(tmp = 717392475.9986715, tmp)))%(tmp = 1976713214, tmp))^x))>>>x)+(tmp = -2812404197.002721, tmp))); - assertEquals(1485905453, x |= x); - assertEquals(-997658264, x <<= (-1409757949.6038744)); - assertEquals(-997657290, x -= ((-2041106361)>>(tmp = -2014750507, tmp))); - assertEquals(-2138512124, x &= (tmp = 2565597060, tmp)); - assertEquals(8422400, x &= ((-2819342693.5172367)*(tmp = 1441722560, tmp))); - assertEquals(111816531.81703067, x -= (-103394131.81703067)); - assertEquals(59606682.673836395, x *= ((tmp = -1451690098, tmp)/(x-(2835050651.717734)))); - assertEquals(-119213365.34767279, x *= (x|((-2656365050)/((-66180492)+(tmp = 284225706.32323086, tmp))))); - assertEquals(-232839, x >>= (1694344809.435083)); - assertEquals(-1, x >>= x); - assertEquals(1, x *= x); - assertEquals(1, x |= x); - assertEquals(0, x >>= (tmp = 397239268, tmp)); - assertEquals(-1525784563, x -= (tmp = 1525784563, tmp)); - assertEquals(-153.62740888512675, x /= (((tmp = -2040622579.5354173, tmp)*(tmp = -1149025861.549324, tmp))%(((tmp = 2981701364.0073133, tmp)*(tmp = 2993366361, tmp))|(x|(tmp = 1800299979, tmp))))); - assertEquals(-1671795135, x &= (-1671795135.6173766)); - assertEquals(-4253, x |= ((((x*((1533721762.8796673)<<((tmp = 1026164775.0081646, tmp)<<x)))<<(((x-((((x>>((((((tmp = -481536070.7067797, tmp)&(tmp = 1663121016, tmp))>>>(-2974733313.5449667))+(tmp = -493019653, tmp))>>x)&(tmp = 879307404.8600142, tmp)))>>>x)%(x-(tmp = -1806412445.788453, tmp)))%x))<<(x<<(x+x)))+x))>>((tmp = -332473688.28477216, tmp)<<((tmp = 1701065928, tmp)+(((((tmp = -2407330783, tmp)+x)-((tmp = 584100783, tmp)%(tmp = -3077106506, tmp)))^x)>>x))))<<x)); - assertEquals(-0, x %= x); - assertEquals(0, x >>>= x); - assertEquals(0, x >>>= (1578470476.6074834)); - assertEquals(0, x >>>= (974609751)); - assertEquals(-120, x += (x-((tmp = -245718438.0842378, tmp)>>>(tmp = -1870354951, tmp)))); - assertEquals(-6.134465505515781e-8, x /= (1956160645)); - assertEquals(-0, x %= x); - assertEquals(0, x *= (tmp = -399718472.70049024, tmp)); - assertEquals(-1803198769.8413258, x += (-1803198769.8413258)); - assertEquals(988624943, x ^= ((((tmp = 320776739.5608537, tmp)*(((tmp = -983452570.3150327, tmp)^x)&(tmp = -3181597938, tmp)))-(tmp = -1367913740.9036021, tmp))/(((tmp = -535854933.2943456, tmp)-(717666905.8122432))>>>(((((x^(tmp = 380453258.60062766, tmp))^(tmp = -1242333929, tmp))/((tmp = 1072416261, tmp)+(((2090466933)*(x*(tmp = -386283072, tmp)))|((tmp = 789259942, tmp)<<(tmp = -1475723636.1901488, tmp)))))>>>x)%((x>>(tmp = -1243048658.3818703, tmp))|((((((tmp = -619553509, tmp)|x)/(878117279.285609))|((x<<(x>>>(tmp = -749568437.7390883, tmp)))*x))/(tmp = 1674804407, tmp))-(x*(tmp = 1528620873, tmp)))))))); - assertEquals(988625135, x |= (x>>>(tmp = 2402222006, tmp))); - assertEquals(988625135, x %= (-2691094165.990094)); - assertEquals(0, x %= x); - assertEquals(-0, x *= (tmp = -1409904262, tmp)); - assertEquals(-0, x /= ((1176483512.8626208)<<x)); - assertEquals(0, x &= ((((1677892713.6240005)^(tmp = 2575724881, tmp))^(tmp = -2935655281.208194, tmp))*(216675668))); - assertEquals(0, x >>= (tmp = -1296960457, tmp)); - assertEquals(0, x |= x); - assertEquals(NaN, x /= x); - assertEquals(0, x <<= (x>>(-3127984289.9112387))); - assertEquals(0, x %= ((tmp = 190018725.45957255, tmp)<<((x>>>x)/x))); - assertEquals(0, x /= (1185681972)); - assertEquals(0, x &= ((tmp = -1285574617, tmp)>>x)); - assertEquals(0, x >>>= ((tmp = 2498246277.2054763, tmp)+(((tmp = 924534435, tmp)&x)>>(tmp = 1379755429, tmp)))); - assertEquals(0, x -= x); - assertEquals(0, x /= (3093439341)); - assertEquals(0, x *= (x>>>x)); - assertEquals(0, x &= (tmp = 551328367, tmp)); - assertEquals(-0, x /= (-3153411714.834353)); - assertEquals(1217585288, x ^= (tmp = -3077382008.637764, tmp)); - assertEquals(-639702017, x |= ((tmp = -640922633, tmp)%(tmp = -879654762, tmp))); - assertEquals(-1645297680, x <<= (tmp = 1418982820.8182912, tmp)); - assertEquals(-1.4059558868398736, x /= (1170234212.4674253)); - assertEquals(-2650856935.66554, x *= (1885448157)); - assertEquals(1326259953.26931, x *= (((x>>(x|(-496195134.78045774)))+((2029515886)%(tmp = 1148955580, tmp)))/(tmp = -1760016519, tmp))); - assertEquals(0, x &= (((((-273334205)+(tmp = 797224093.682485, tmp))/x)>>>((((tmp = -887577414, tmp)/x)+x)%(tmp = 720417467, tmp)))^(((x-(tmp = -309071035, tmp))>>(-3123114729.33889))/x))); - assertEquals(0, x ^= x); - assertEquals(0, x %= ((tmp = -2243857462, tmp)/((((((2642220700.6673346)&x)*(tmp = 1454878837, tmp))|((-25825087.30002737)%(851535616.3479034)))<<(tmp = -697581582, tmp))%(tmp = 2248990486, tmp)))); - assertEquals(0, x >>= (((x|(((tmp = -220437911, tmp)&((((255690498)*(((2993252642)>>>(tmp = 300426048.0338713, tmp))>>x))&((-364232989)+(x<<(-1824069275))))%(x+(tmp = 2696406059.026349, tmp))))+((tmp = 2911683270, tmp)/(tmp = 2718991915, tmp))))*(x/(((tmp = -982851060.0744538, tmp)^((-2903383954)<<((-85365803.80553412)^x)))%(1489258330.5730634))))>>>x)); - assertEquals(0.7805921633088815, x += (((-1886920875)/(-2417294156.5304217))%(tmp = -1176793645.8923106, tmp))); - assertEquals(0, x <<= x); - assertEquals(-2215008905, x -= (2215008905)); - assertEquals(1931542900, x &= (-215923724.72133207)); - assertEquals(907191462, x ^= (-3133954606.357727)); - assertEquals(453595731, x >>>= (((tmp = 2726241550, tmp)/(tmp = -332682163, tmp))*((((tmp = 2500467531, tmp)>>>(((x<<(tmp = -1847200310.4863105, tmp))/x)^x))+x)<<(191688342.22953415)))); - assertEquals(-0.21671182880645923, x /= ((((-1169180683.1316955)%x)>>>(1650525418))^((2198033206.797462)&((-6913973.910871983)%(1758398541.8440342))))); - assertEquals(-375102237.1603561, x += (tmp = -375102236.9436443, tmp)); - assertEquals(1, x &= (((84374105.89811504)|((tmp = -2480295008.926951, tmp)>>((605043461)>>(tmp = -2495122811, tmp))))>>(-2129266088))); - assertEquals(1, x |= x); - assertEquals(0.0000024171579540208214, x /= (((-2600416098)>>(-2076954196))^x)); - assertEquals(0.0000024171579540208214, x %= (tmp = -2632420148.815531, tmp)); - assertEquals(1809220936.0126908, x -= (-1809220936.0126884)); - assertEquals(1682452118.2686126, x += (((2358977542)<<(x/(tmp = -2862107929, tmp)))+(x+(x%((-3101674407)/(((x*((x>>(tmp = 630458691.3736696, tmp))>>>(tmp = -852137742, tmp)))/x)-((-1875892391.1022017)&(tmp = -1027359748.9533749, tmp)))))))); - assertEquals(1682452118, x <<= (((tmp = -80832958.07816291, tmp)>>x)%(x-((x^(x<<(tmp = -156565345, tmp)))|((tmp = -1208807363.727137, tmp)/(tmp = 2614737513.304538, tmp)))))); - assertEquals(6572078, x >>= (-1573364824)); - assertEquals(13144156, x += x); - assertEquals(1731678184, x ^= ((tmp = 593370804.9985657, tmp)|(-3124896848.53273))); - assertEquals(845545, x >>>= (tmp = -605637621.2299933, tmp)); - assertEquals(-1383361088, x ^= (tmp = -1383632087, tmp)); - assertEquals(-82545896480031520, x += ((x+(1023183845.7316296))*((((tmp = 576673669, tmp)>>(((-584800080.1625061)/(2388147521.9174623))+((((x>>>(-905032341.5830328))^(tmp = -2170356357, tmp))-x)+((136459319)+(-1799824119.689473)))))|x)&(tmp = -2688743506.0257063, tmp)))); - assertEquals(-895206176, x |= x); - assertEquals(-0, x %= x); - assertEquals(1791306023, x ^= ((tmp = -3219480856, tmp)+(tmp = 715819582.0181161, tmp))); - assertEquals(1791306023, x &= x); - assertEquals(2725167636753240600, x *= (1521330025)); - assertEquals(-281190679, x |= (tmp = -1422045975.798171, tmp)); - assertEquals(-281190679, x += (x%x)); - assertEquals(-2342097426.906673, x -= (tmp = 2060906747.906673, tmp)); - assertEquals(-4651462701.906673, x -= (2309365275)); - assertEquals(1878, x >>>= (2544974549.345834)); - assertEquals(1964, x += (x&((1067649861)>>(182139255.7513579)))); - assertEquals(2209, x += (x>>(tmp = -1775039165, tmp))); - assertEquals(0, x -= x); - assertEquals(-0, x /= (tmp = -1634697185, tmp)); - assertEquals(NaN, x /= x); - assertEquals(0, x >>>= ((tmp = 3075747652, tmp)&(tmp = 819236484, tmp))); - assertEquals(0, x /= ((1276203810.476657)%(-2434960500.784484))); - assertEquals(0, x >>>= (tmp = -503633649, tmp)); - assertEquals(-982731931, x |= (-982731931)); - assertEquals(-1965463862, x += x); - assertEquals(-0.221469672913716, x %= ((tmp = -1742292120, tmp)/x)); - assertEquals(-0.221469672913716, x %= (-2021391941.1839576)); - assertEquals(0, x <<= (((((tmp = -2802447851, tmp)>>((2534456072.6518855)&x))%(tmp = 2841162496.610816, tmp))<<((89341820)/(2565367990.0552235)))>>(tmp = 2700250984.4830647, tmp))); - assertEquals(0, x >>= x); - assertEquals(0, x >>= ((tmp = -636189745, tmp)>>>(x/(((tmp = 2634252476, tmp)%(2026595795))>>(tmp = -2048078394.743723, tmp))))); - assertEquals(NaN, x %= ((x%((((x%((tmp = -2583207106, tmp)&x))|(190357769))<<(tmp = 595856931.2599536, tmp))%x))*((-2433186614.6715775)<<((2856869562.1088696)^(tmp = 1112328003, tmp))))); - assertEquals(1621713910, x |= (tmp = 1621713910.0282416, tmp)); - assertEquals(3243427820, x += x); - assertEquals(0, x *= (x&(x-x))); - assertEquals(0, x >>>= (((2871235439)<<((x+((tmp = -1319445828.9659343, tmp)+(tmp = 1595655077.959171, tmp)))>>(tmp = -86333903, tmp)))-(x/(2907174373.268768)))); - assertEquals(0, x >>= (-1091774077.2173789)); - assertEquals(NaN, x /= x); - assertEquals(NaN, x *= (tmp = 1976023677.7015994, tmp)); - assertEquals(NaN, x -= (-3013707698)); - assertEquals(NaN, x += ((x+(((tmp = -3119865782.9691515, tmp)<<(1327383504.0158405))^(((-143382411.7239611)>>>((-2157016781)+(((-335815848)/x)<<(tmp = 1953515427, tmp))))&(-2715729178))))/(413738158.2334299))); - assertEquals(NaN, x %= x); - assertEquals(NaN, x += (-845480493)); - assertEquals(-789816013, x |= (tmp = -789816013.129916, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x <<= (3032573320)); - assertEquals(47630, x ^= ((1086705488)%((x^(tmp = -1610832418, tmp))>>>(tmp = 1136352558, tmp)))); - assertEquals(47630, x >>= (tmp = 1035320352.4269229, tmp)); - assertEquals(47630, x >>= ((((x^x)<<(x*((((x&((-1657468419)*((tmp = -674435523, tmp)&((tmp = 2992300334, tmp)|x))))*((tmp = -489509378.31950426, tmp)*(tmp = 2276316053, tmp)))>>>x)<<x)))%(tmp = -1209988989, tmp))/(tmp = -2080515253.3541622, tmp))); - assertEquals(3192518951.8129544, x += (3192471321.8129544)); - assertEquals(648116457.8129544, x %= (-2544402494)); - assertEquals(0, x -= x); - assertEquals(NaN, x /= x); - assertEquals(NaN, x /= x); - assertEquals(0, x <<= x); - assertEquals(0, x >>= x); - assertEquals(0, x *= (tmp = 30051865, tmp)); - assertEquals(0, x ^= ((x&(((x&x)>>>(((((((x+(2319551861.0414495))>>>(tmp = -3099624461, tmp))^((((tmp = 1574312763, tmp)|x)>>>((-2723797246)&(tmp = -1993956152, tmp)))|(-1830179045)))|(((((((-2545698704.3662167)>>>x)-(((-79478653)|x)%(x+(x>>((tmp = 2386405508.2180576, tmp)/x)))))>>((((-1947911815.2808042)*((x+(368522081.2884482))-(tmp = 2452991210, tmp)))>>(343556643.1123545))>>((((tmp = 1869261547.537739, tmp)>>(3193214755))|x)&(x*(2027025120)))))<<((-1149196187)>>>(814378291.8374172)))+((((((((-160721403)/(2079201480.2186408))+((x|((((tmp = -299595483.16805863, tmp)>>>((x|((x+x)/(-2359032023.9366207)))<<(tmp = -3095108545, tmp)))>>((tmp = -1547963617.9087071, tmp)*(x>>x)))&((tmp = -1568186648.7499216, tmp)+(((2646528453)^(-2004832723.0506048))>>>(tmp = -3188715603.921877, tmp)))))+(tmp = 1578824724, tmp)))^x)^x)/(tmp = -985331362, tmp))|(tmp = 445135036, tmp))<<(tmp = -73386074.43413758, tmp)))+(((-1674995105.9837937)-(tmp = 1392915573, tmp))>>x)))%(tmp = 1215953864, tmp))&((tmp = -439264643.5238693, tmp)>>>x))+(((tmp = 2311895902, tmp)|(1604405793.6399229))&(tmp = -565192829, tmp))))-x))>>(-2455985321))); - assertEquals(0, x %= ((1177798817)>>(tmp = 2081394163.5420477, tmp))); - assertEquals(0, x >>>= ((x^(tmp = -41947528.33954811, tmp))>>(x>>>((tmp = 1367644771, tmp)+x)))); - assertEquals(0, x %= ((x+((tmp = 163275724, tmp)<<((tmp = -514460883.3040788, tmp)+x)))|(tmp = -287112073.2482593, tmp))); - assertEquals(0, x &= (3067975906)); - assertEquals(201342051, x |= (tmp = 201342051, tmp)); - assertEquals(0, x %= (((((-2580351108.8990865)<<(tmp = 2675329316, tmp))&((1338398946)%((-1548041558)+((x>>(-1568233868.7366815))|((x>>((tmp = -1064582207, tmp)/(-1062237014)))>>(tmp = 854123209, tmp))))))<<(((989032887)*(1842748656))%(tmp = -1566983130, tmp)))-x)); - assertEquals(-0, x /= (tmp = -828519512.617768, tmp)); - assertEquals(0, x &= ((((1449608518)+(-1829731972))*(1828894311))*(((tmp = -1121326205.614264, tmp)^(-2057547855))<<(tmp = -2758835896, tmp)))); - assertEquals(NaN, x %= ((tmp = -2138671333, tmp)%x)); - assertEquals(0, x &= x); - assertEquals(665568613.0328879, x += (665568613.0328879)); - assertEquals(317, x >>= (2627267349.735873)); - assertEquals(0, x -= x); - assertEquals(0, x &= (((tmp = 3030611035, tmp)*(((tmp = 476143340.933007, tmp)>>(x-(2238302130.2331467)))|(x|x)))%(tmp = 320526262, tmp))); - assertEquals(0, x <<= (tmp = 729401206, tmp)); - assertEquals(0, x >>>= (1721412276)); - assertEquals(217629949.3530736, x += ((tmp = 217629949.3530736, tmp)%((-931931100.601475)%(x^(tmp = -2149340123.548764, tmp))))); - assertEquals(217629949.3530736, x %= (tmp = 2275384959.4243402, tmp)); - assertEquals(0, x >>>= (1112677437.5524077)); - assertEquals(0, x *= (500256656.7476063)); - assertEquals(0, x >>>= x); - assertEquals(0, x -= x); - assertEquals(0, x -= x); - assertEquals(0, x &= (-1076968794)); - assertEquals(0, x /= (tmp = 1774420931.0082943, tmp)); - assertEquals(0, x |= x); - assertEquals(0, x >>= x); - assertEquals(0, x %= (-2978890122.943079)); - assertEquals(-0, x /= (tmp = -2954608787, tmp)); - assertEquals(-800048201, x ^= ((tmp = -800048201.7227018, tmp)>>>((-2016227566.1480863)/(tmp = -2263395521, tmp)))); - assertEquals(3333, x >>>= (-2038839052)); - assertEquals(487957736.625432, x += (487954403.625432)); - assertEquals(-1650983426, x |= (2643918270)); - assertEquals(-1861867448, x &= (tmp = -251254199.12813115, tmp)); - assertEquals(-7.934314690172143e-18, x %= ((((x^(-703896560.6519544))>>(tmp = -1853262409, tmp))/(tmp = -1168012152.177894, tmp))/(tmp = 837616075.1097361, tmp))); - assertEquals(0, x ^= x); - assertEquals(0, x &= (tmp = -2328150260.5399947, tmp)); - assertEquals(-1954860020, x |= (tmp = 2340107276, tmp)); - assertEquals(-1954860020, x >>= ((tmp = 159177341, tmp)*(x&(-705832619)))); - assertEquals(-1954895727, x -= (x>>>((-1443742544.7183702)^((((tmp = 869581714.0137681, tmp)+x)^((x%(tmp = -1036566362.5189383, tmp))^(x%x)))>>x)))); - assertEquals(1.0241361338078498, x /= (tmp = -1908824093.2692068, tmp)); - assertEquals(16777216, x <<= (x*(((-1925197281)^(tmp = -1392300089.4750946, tmp))|x))); - assertEquals(-225882765524992, x *= (tmp = -13463662, tmp)); - assertEquals(-1845493760, x |= x); - assertEquals(-1845493760, x %= (tmp = 3181618519.786825, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x <<= x); - assertEquals(0, x >>>= x); - assertEquals(NaN, x /= (x>>>x)); - assertEquals(NaN, x %= (((((tmp = -521176477, tmp)>>(((tmp = 370693623, tmp)/(((tmp = -1181033022.4136918, tmp)>>(x|(x*(2601660441))))+(tmp = -1696992780, tmp)))|(x|(-1197454193.198036))))>>>(((2512453418.3855605)+((((((tmp = 799501914, tmp)&(((1788580469.7069902)*(((((1476778529.5109258)<<(tmp = -1873387738.3541565, tmp))-((tmp = -521988584.7945764, tmp)*(-1598785351.3914914)))&(-1899161721.8061454))&((x/x)*(690506460))))>>>((tmp = 2255896398.840741, tmp)>>((tmp = -1331486014.6180065, tmp)+(-1159698058.534132)))))*((1112115365.2633948)&((x>>((x>>(-784426389.4693215))&(-492064338.97227573)))>>x)))^((x-((tmp = 2986028023, tmp)>>(tmp = 2347380320.00517, tmp)))*(tmp = -1463851121, tmp)))*(tmp = -1059437133, tmp))%(x-(tmp = 1238739493.7636225, tmp))))^(2029235174)))*(-1923899530))>>>x)); - assertEquals(0, x >>>= (2848792983.510682)); - assertEquals(0, x >>= (((tmp = 3042817032.705198, tmp)>>>x)&((((tmp = -829389221, tmp)-((2669682285.8576303)+(tmp = 1812236814.3082042, tmp)))^x)%((tmp = -2401726554, tmp)^((tmp = 2464685683, tmp)|(-2685039620.224061)))))); - assertEquals(2069649722, x |= (2069649722.311271)); - assertEquals(NaN, x %= (((((-68757739.39282179)&(-1382816369))/(3122326124))<<(x-(-507995800.3369653)))<<(((-1962768567.343907)+((tmp = 1357057125, tmp)/x))^(tmp = 1997617124, tmp)))); - assertEquals(NaN, x += x); - assertEquals(0, x >>= (26895919)); - assertEquals(0, x >>>= x); - assertEquals(0, x %= (tmp = 1092448030, tmp)); - assertEquals(0, x <<= (tmp = -477672441.46258235, tmp)); - assertEquals(0, x /= (2113701907)); - assertEquals(0, x >>>= x); - assertEquals(NaN, x /= x); - assertEquals(1341078673, x |= (-2953888623)); - assertEquals(1341078673, x &= x); - assertEquals(0, x %= x); - assertEquals(414817852.151006, x -= (-414817852.151006)); - assertEquals(1006632960, x <<= ((((((126465614.8316778)+(x-(2511803375)))+(tmp = 1620717148.352402, tmp))*x)/(tmp = -3013745105.5275207, tmp))-((tmp = -418034061.6865432, tmp)/(-300492911)))); - assertEquals(1055624813, x |= (tmp = 921407085, tmp)); - assertEquals(-3, x |= ((((tmp = 1382397819.7507677, tmp)+(tmp = -111851147.7289567, tmp))+x)/((tmp = 247980405.7238742, tmp)^(tmp = -592156399.8577058, tmp)))); - assertEquals(35161, x &= (((((((-2973570544.725141)*(tmp = -1244715638, tmp))+x)<<(x/((x>>>(-2143371615.073137))/(226072236))))%((x-(tmp = 1971392936, tmp))^(tmp = 2653103658, tmp)))%((tmp = 2828319571.7066674, tmp)>>((1528970502)^((tmp = -55869558, tmp)%x))))>>(889380585.6738582))); - assertEquals(0, x ^= x); - assertEquals(0, x *= (2749718750)); - assertEquals(0, x >>>= ((((-1633495402.6252813)*(tmp = 2943656739.1108646, tmp))+(tmp = 977432165, tmp))&((tmp = -2338132019, tmp)*(408176349.8061733)))); - assertEquals(-1778794752, x -= (((tmp = -1391412154.5199084, tmp)-((-3172342474)|x))&(1854366052))); - assertEquals(-1778794752, x %= (tmp = 2024807296.6901965, tmp)); - assertEquals(-1114410.466337204, x %= ((tmp = -240344444.24487805, tmp)%(-47661164))); - assertEquals(-0, x %= x); - assertEquals(0, x >>= (x>>x)); - assertEquals(0, x *= x); - assertEquals(0, x /= ((-3134902611)|(tmp = -3131158951, tmp))); - assertEquals(-0, x /= (((tmp = 1430247610.634234, tmp)&x)+((tmp = -2047191110.8623483, tmp)-((((x%((((x/(tmp = -2599234213, tmp))|(tmp = 2650380060, tmp))|x)+x))>>>x)&(-1961373866))<<x)))); - assertEquals(-718394682, x -= ((x|(tmp = 1764417670.8577194, tmp))%(1046022988))); - assertEquals(3576572614, x >>>= (((tmp = 2480472883.078992, tmp)<<x)>>((2035208402.8039393)&(tmp = 492980449, tmp)))); - assertEquals(434034142, x %= (x&((x>>>(311110449.48751545))|(-243530647)))); - assertEquals(524703439.3065736, x += (((tmp = 1392771723.3065736, tmp)%(x&x))%(tmp = -2199704930, tmp))); - assertEquals(373686272, x &= (x<<((tmp = 2103372351.9456532, tmp)%(tmp = -1367109519, tmp)))); - assertEquals(373686272, x >>= x); - assertEquals(-0.12245430020241108, x /= (tmp = -3051638622.5907507, tmp)); - assertEquals(1, x /= x); - assertEquals(1, x %= (3095983855)); - assertEquals(-1454736871, x ^= (x*(tmp = -1454736872, tmp))); - assertEquals(-1454736866, x ^= (((724989405.7338341)|(tmp = -2834298786.384371, tmp))>>>(tmp = -2029602148.1758833, tmp))); - assertEquals(-1454736866, x &= x); - assertEquals(-197394432, x <<= (tmp = -1562128975, tmp)); - assertEquals(251658240, x <<= (tmp = 2126510950, tmp)); - assertEquals(3295700610.703306, x -= (tmp = -3044042370.703306, tmp)); - assertEquals(-51152917, x |= ((949179883.1784958)|(((tmp = -2046168220, tmp)>>(x/x))/(((835064313)*(tmp = 2197600689, tmp))^(((tmp = 2717104216, tmp)&x)<<(-1402661995.3845913)))))); - assertEquals(-1549204421, x ^= ((((tmp = -481013711, tmp)>>>((tmp = 119589341.80209589, tmp)%(-995489985.2905662)))-(635717011))^(x+(x*x)))); - assertEquals(-1078356672.3999934, x += (470847748.6000067)); - assertEquals(1484987268.4638166, x += (tmp = 2563343940.86381, tmp)); - assertEquals(277020804, x &= (tmp = 2532819117, tmp)); - assertEquals(-2097118208, x <<= (x>>>x)); - assertEquals(-2147483648, x <<= (tmp = 761285045, tmp)); - assertEquals(2147483648, x >>>= x); - assertEquals(-935909870282997800, x *= ((-2583300643)|x)); - assertEquals(-370753566.54721737, x %= (-1084543510.4524941)); - assertEquals(-177, x >>= (-946264747.6588805)); - assertEquals(-416077682, x ^= (tmp = 416077761, tmp)); - assertEquals(NaN, x %= ((((tmp = 779607408, tmp)*(((tmp = -3007128117, tmp)*(851442866.6153773))+x))&(1283388806))/(-876363553))); - assertEquals(NaN, x %= (x/(tmp = -1668413939.652408, tmp))); - assertEquals(-1726405921, x ^= (tmp = -1726405921, tmp)); - assertEquals(-1, x >>= ((3031008213.807012)>>x)); - assertEquals(4294967295, x >>>= ((x>>>x)&(tmp = 2788082290, tmp))); - assertEquals(8544111670008449000, x *= (tmp = 1989331020.0417833, tmp)); - assertEquals(268435456, x <<= (tmp = 3121736017.2098465, tmp)); - assertEquals(-2.1011176170964474e+26, x -= (((tmp = 1392503299, tmp)*(tmp = 1446108825.1572113, tmp))*(x^(tmp = 372776014.213725, tmp)))); - assertEquals(0, x |= x); - assertEquals(0, x >>= ((-112413907.70074797)*(-702798603))); - assertEquals(1829518838, x |= (tmp = -2465448458, tmp)); - assertEquals(57172463, x >>= ((tmp = 2979642955.241792, tmp)%(tmp = -2464398693.291434, tmp))); - assertEquals(114344926, x += x); - assertEquals(113279134, x &= (2397742238.6877637)); - assertEquals(54, x >>= (1908522709.6377516)); - assertEquals(-2.966982919573829e-7, x /= (tmp = -182003070, tmp)); - assertEquals(0, x <<= (-1078417156)); - assertEquals(-147831390, x ^= (((-147831390)>>>x)+x)); - assertEquals(0, x -= x); - assertEquals(-242221450.44696307, x -= (tmp = 242221450.44696307, tmp)); - assertEquals(-484442900, x <<= (((tmp = -2033947265.088614, tmp)&x)/(x^(tmp = -2893953848, tmp)))); - assertEquals(-3227648, x <<= (x<<((tmp = -193993010, tmp)*((983187830)|(3146465242.2783365))))); - assertEquals(-6455296, x += x); - assertEquals(-1771542585, x -= (x^(tmp = -1767335879, tmp))); - assertEquals(-0, x %= x); - assertEquals(0, x >>>= ((((tmp = -1612864670.4532743, tmp)*(tmp = 786265765.210487, tmp))*((((tmp = -893735877.3250401, tmp)*((x^(tmp = -2804782464.233885, tmp))<<x))&(x-x))^x))<<x)); - assertEquals(0, x -= (x>>>(-1648118674.380736))); - assertEquals(0, x >>= ((tmp = -2706058813.0028524, tmp)>>(2745047169))); - assertEquals(0, x += x); - assertEquals(0, x %= (-898267735.137356)); - assertEquals(0, x >>>= x); - assertEquals(0, x >>= ((265527509)/((tmp = 2190845136.7048635, tmp)+((x>>x)>>>((x%(x-x))&((((-2080184609.8989801)&((-327231633)>>>((tmp = 864849136, tmp)%(((-524363239)*(((((tmp = 2245852565.3713694, tmp)&(1918365.8978698254))>>>(tmp = -2463081769, tmp))-(((2438244059.471446)|((((-135303645.38470244)*(-861663832.2253196))%(tmp = 1273185196.0261836, tmp))|((2261539338.832875)%((320267076.2363237)+x))))>>(tmp = -2731398821, tmp)))/(tmp = -1947938611, tmp)))^x))))>>(tmp = 833666235, tmp))|x)))))); - assertEquals(-1116704570, x ^= (-1116704570)); - assertEquals(1379561710, x ^= (tmp = -280362968.19654894, tmp)); - assertEquals(-1673822208, x <<= x); - assertEquals(-1673822208, x |= (x<<(tmp = 1389479193.9038138, tmp))); - assertEquals(2559712, x >>>= (-2703763734.0354066)); - assertEquals(2593499, x ^= (x>>>((tmp = 148668150.03291285, tmp)^(tmp = -1580360304, tmp)))); - assertEquals(2070393855, x |= (tmp = -2227002907, tmp)); - assertEquals(304197770, x &= (tmp = 2453257354, tmp)); - assertEquals(304197770, x <<= ((-669331453.8814087)-(x^(x^(tmp = 33804899.98928583, tmp))))); - assertEquals(297068, x >>= x); - assertEquals(Infinity, x /= (x-x)); - assertEquals(NaN, x %= x); - assertEquals(0, x ^= x); - assertEquals(0, x %= ((tmp = 1723087085, tmp)%(2859382131.304421))); - assertEquals(0, x %= (((tmp = 2935439763, tmp)<<(-3163992768.637094))%(tmp = 67176733, tmp))); - assertEquals(0, x &= (tmp = 2480771277, tmp)); - assertEquals(0, x >>>= (x+(tmp = -3168690063, tmp))); - assertEquals(0, x *= ((tmp = -1915275449.1806245, tmp)>>>((tmp = -1644482094.1822858, tmp)/(tmp = -432927173, tmp)))); - assertEquals(0, x += (((2766509428.071809)/(x/((942453848.5423365)/(((tmp = -1284574492, tmp)&((tmp = 760186450.7301528, tmp)-(2464974117.358138)))/((x/(x|(672536969)))*(x>>(-1272232579)))))))>>(x*(-3175565978)))); - assertEquals(-1277710521, x -= (1277710521)); - assertEquals(-1277710521, x >>= (((tmp = -2349135858, tmp)-x)-x)); - assertEquals(-1277710521, x >>= ((tmp = 2135645051, tmp)*(tmp = -2468555366, tmp))); - assertEquals(-155971, x >>= (-1294859507)); - assertEquals(-0, x %= x); - assertEquals(0, x >>>= (((861078292.6597499)|(-268063679))-(((((-221864206.9494424)-(-3186868203.2201176))&(tmp = 1287132927, tmp))<<(((tmp = 1964887915, tmp)<<((25908382)^(tmp = -688293519.875164, tmp)))*(2075946055)))&(x-((x>>x)&(1395338223.7954774)))))); - assertEquals(788002218, x -= (-788002218)); - assertEquals(716399906, x &= (-1145868506)); - assertEquals(145776674, x &= (-1661931477.360386)); - assertEquals(145776674, x |= x); - assertEquals(-0.05255700469257692, x /= (tmp = -2773686873, tmp)); - assertEquals(-660918434, x |= (-660918434.2915542)); - assertEquals(1223537346, x ^= (tmp = -1871274596, tmp)); - assertEquals(305884336, x >>= (x&x)); - assertEquals(-1.1123775647978218e-8, x *= ((tmp = -793393031.4229445, tmp)/((tmp = -503919284, tmp)*(((((tmp = 429810625, tmp)>>>x)-((2091544148.870375)<<(((((x^x)%x)|x)/(-260773261))<<((tmp = -1323834653, tmp)&x))))*((-1231800099.3724015)+x))*((x+((-559726167)^x))>>>((-549148877)<<((((tmp = 1196115201, tmp)/((tmp = -2654658968.390111, tmp)%(tmp = -1044419580, tmp)))*(((((x>>>(733571228))+(2919762692.511447))/(-2718451983.570547))^x)+((2891533060.1804514)^((tmp = -2514488663, tmp)&x))))<<(tmp = -2526139641.6733007, tmp)))))))); - assertEquals(0, x >>>= x); - assertEquals(0, x *= x); - assertEquals(0, x |= x); - assertEquals(3076984066.336236, x -= ((tmp = -3076984066.336236, tmp)+((tmp = -446575828.5155368, tmp)&x))); - assertEquals(1, x /= x); - assertEquals(1513281647.839972, x *= (1513281647.839972)); - assertEquals(1251138155, x ^= ((tmp = 2124481052, tmp)&(2431937351.4392214))); - assertEquals(1, x /= x); - assertEquals(0, x &= (tmp = 627050040, tmp)); - assertEquals(497153016, x ^= (497153016)); - assertEquals(-1112801283, x |= (tmp = 2752196557, tmp)); - assertEquals(0.5735447276296568, x /= ((((tmp = -500878794, tmp)%(tmp = -2559962372.2930336, tmp))%(2661010102))+(tmp = -1439338297, tmp))); - assertEquals(1.0244795995097235e-9, x /= (559840067)); - assertEquals(0.43468811912309857, x *= (424301391)); - assertEquals(-1972757928, x ^= (tmp = -1972757928.9227014, tmp)); - assertEquals(-606757265, x ^= (tmp = -2923461577.264596, tmp)); - assertEquals(-37, x >>= (((-2736561559.7474318)%(tmp = -27668972.662741184, tmp))*(2774711606))); - assertEquals(-1923785671, x += ((-1923785597)+x)); - assertEquals(-3877639176, x += (tmp = -1953853505, tmp)); - assertEquals(-4688259242, x -= ((810620066.4394455)>>(((-1474285107.459875)>>x)/(((((-570672326.4007359)>>(tmp = -3086802075, tmp))%x)>>>(((tmp = 286938819.28193486, tmp)>>>((1712478502)>>(tmp = 3045149117.796816, tmp)))<<(tmp = 750463263.292952, tmp)))&(tmp = 2055350255.5669963, tmp))))); - assertEquals(-0, x %= x); - assertEquals(0, x <<= (1037856162.5105649)); - assertEquals(0, x *= x); - assertEquals(0, x &= (997845077.4917375)); - assertEquals(0, x *= x); - assertEquals(0, x *= x); - assertEquals(0, x <<= (((x<<x)&(57691805))>>(786927663))); - assertEquals(0, x ^= x); - assertEquals(0, x += x); - assertEquals(0, x &= (-2131910624.1429484)); - assertEquals(0, x >>>= (-43787814)); - assertEquals(-2415062021, x += (tmp = -2415062021, tmp)); - assertEquals(-4830124042, x += x); - assertEquals(-186683401, x |= (tmp = 1960135383, tmp)); - assertEquals(NaN, x *= ((tmp = -1674740173.9864025, tmp)%(((((((-432895485.7261934)-x)^x)>>>(((-1627743078.3383338)>>(179992151))<<((tmp = 911484278.0555259, tmp)|(((tmp = -3042492703, tmp)>>(((-663866035.302746)>>(((x-((440661929.50030375)>>>(tmp = 263692082, tmp)))*x)+x))/((1546004407)^(((tmp = 2023662889.1594632, tmp)*(tmp = -2456602312, tmp))+(tmp = 755602286.1810379, tmp)))))%((tmp = -336449961, tmp)|(tmp = 206780145, tmp))))))/(1068005219.1508512))<<(tmp = -474008862.6864624, tmp))/(((((((1518711056.5437899)>>>(tmp = 287418286.63085747, tmp))<<(tmp = 2823048707, tmp))^(((x<<(x^(-1600970311)))&(x>>(((tmp = 157300110.7636031, tmp)*(tmp = -3047000529, tmp))&(1743024951.3535223))))>>x))-(tmp = -2895435807, tmp))*((tmp = -314120704, tmp)&(tmp = 1759205369, tmp)))>>(tmp = 1833555960.046526, tmp))))); - assertEquals(NaN, x -= (tmp = 694955369, tmp)); - assertEquals(NaN, x *= (x%x)); - assertEquals(0, x |= x); - assertEquals(0, x ^= x); - assertEquals(0, x &= x); - assertEquals(NaN, x /= (x+x)); - assertEquals(NaN, x %= ((tmp = -1595988845, tmp)*((1754043345)>>>(-601631332)))); - assertEquals(0, x >>>= (tmp = 862768754.5445609, tmp)); - assertEquals(NaN, x /= x); - assertEquals(NaN, x %= x); - assertEquals(NaN, x *= (tmp = -1774545519, tmp)); - assertEquals(0, x >>>= (tmp = -2492937784, tmp)); - assertEquals(0, x %= ((((x<<(-1657262788.2028513))&((x^(tmp = -671811451, tmp))<<(-2984124996)))^(1455422699.7504625))-((-340550620)>>x))); - assertEquals(918278025, x ^= ((tmp = -918278027, tmp)^((tmp = 2889422870, tmp)/(tmp = -657306935.7725658, tmp)))); - assertEquals(918278025, x %= (2603186571.0582614)); - assertEquals(107034679.32509923, x %= (tmp = -811243345.6749008, tmp)); - assertEquals(53517339, x >>= (x%((((x*((tmp = -983766424, tmp)^(-1881545357.8686862)))|(tmp = -1429937087, tmp))>>((x<<x)>>((((tmp = -2347470476, tmp)&x)+((x&x)<<(396061331.6476157)))*(tmp = -3136296453.209073, tmp))))>>>(((tmp = 908427836, tmp)|(tmp = 207737064, tmp))|(((1253036041)-(tmp = 2705074182, tmp))+(-431215157.82083917)))))); - assertEquals(53477378, x &= ((((-1128036654.165636)*x)+x)>>(x>>(3080099059)))); - assertEquals(0, x >>= (-590692293)); - assertEquals(0, x %= (-2395850570.9700127)); - assertEquals(0, x *= ((tmp = 1377485272, tmp)&(1129370608))); - assertEquals(0, x += (x>>>(x%(((((tmp = -1746827236, tmp)+((tmp = -326913490, tmp)&((-58256967)&x)))*(tmp = -1176487022.001651, tmp))>>>(-2089147643))-x)))); - assertEquals(0, x <<= (tmp = 1073298160.2914447, tmp)); - assertEquals(-837811832, x ^= (-837811832)); - assertEquals(102760448, x <<= (tmp = 2833582450.4544373, tmp)); - assertEquals(0, x &= (((((((tmp = 2595641175, tmp)*x)+(tmp = -2049260172.1025927, tmp))%((2986747823)>>(tmp = -2120598518, tmp)))&((tmp = -2742408622, tmp)&x))>>x)*((1043474247.9601482)&(tmp = 1686365779.9885998, tmp)))); - assertEquals(0, x >>= ((tmp = 1717862848, tmp)-(tmp = 1077024446.4160957, tmp))); - assertEquals(NaN, x /= x); - assertEquals(NaN, x /= (-1669429787.975099)); - assertEquals(NaN, x -= (-2299895633.4807186)); - assertEquals(138173970, x ^= (138173970.56627905)); - assertEquals(-2084183776, x <<= (3073345316)); - assertEquals(-0, x %= x); - assertEquals(0, x >>= (-3080556066.068573)); - assertEquals(0, x &= ((tmp = -2587514820, tmp)*(x-((x^(1995672257))*(1125326747.2339358))))); - assertEquals(NaN, x %= x); - assertEquals(0, x >>= (tmp = 2139186585, tmp)); - assertEquals(-1904096640, x |= ((-602301360.1919911)*(-1270444810))); - assertEquals(1073741824, x <<= (tmp = -1069467849, tmp)); - assertEquals(1073741824, x ^= (x-x)); - assertEquals(536870912, x >>>= (-1579466367.160293)); - assertEquals(512, x >>= (972402804.3890183)); - assertEquals(512, x &= (tmp = 2664796831, tmp)); - assertEquals(16777216, x <<= (-2738292561)); - assertEquals(0, x >>>= ((((1397663615.3889246)|(1117420260.6730964))-(-1173734560))<<((tmp = 1007006104.0172879, tmp)<<((tmp = -623002097, tmp)%(tmp = -35829654.379403114, tmp))))); - assertEquals(1200191544, x ^= (tmp = -3094775752, tmp)); - assertEquals(71, x >>>= x); - assertEquals(71, x |= x); - assertEquals(1394763772, x += (1394763701)); - assertEquals(-1.492717171027427, x /= ((x&(tmp = 1243787435, tmp))-(2043911970.26752))); - assertEquals(-1.1002448961224718e-8, x /= ((((835185744)*(((tmp = 2165818437, tmp)^(tmp = 2567417009.1166553, tmp))/x))/x)/(((63485842.39971793)^(2668248282.597389))/x))); - assertEquals(0, x <<= (tmp = 1598238578.637568, tmp)); - assertEquals(0, x |= (x&((tmp = -1812945547.5373957, tmp)>>>x))); - assertEquals(0, x >>>= (x+(-1969679729.7299538))); - assertEquals(1582033662, x += (tmp = 1582033662, tmp)); - assertEquals(1, x >>>= x); - assertEquals(-550748739, x += ((tmp = -550748740, tmp)/(x&((2537822642.235506)^((-2167656297)%(tmp = 1161201210, tmp)))))); - assertEquals(-268921, x >>= (tmp = 1916069547.7381654, tmp)); - assertEquals(-0.00021776939364231114, x /= (tmp = 1234888868, tmp)); - assertEquals(0, x <<= (-1036375023)); - assertEquals(0, x &= ((((x/(2398886792.27443))&(x|((-1813057854.1797302)-x)))&(x/(((tmp = 3091133731.4967556, tmp)|(3013139691.823039))<<x)))>>>(2542784636.963599))); - assertEquals(0, x += ((x*x)/(tmp = 347079383, tmp))); - assertEquals(788347904, x |= ((1462257124.6374629)*((3180592147.4065146)-(x&(1922244678))))); - assertEquals(2130672735, x |= (tmp = -2846986145, tmp)); - assertEquals(-1331327970, x ^= ((656251304)-(tmp = 1489152359, tmp))); - assertEquals(-0.14377179742889856, x %= (((2889747597.813753)-(1730428996))/(((tmp = -1378710998, tmp)&x)|x))); - assertEquals(-1754612583.143772, x += ((-1754725729)^((-2285838408)>>>(1434074349)))); - assertEquals(-0, x %= x); - assertEquals(0, x &= (tmp = -1031961332, tmp)); - assertEquals(NaN, x /= x); - assertEquals(NaN, x /= (3059476325)); - assertEquals(NaN, x *= ((x*((((tmp = 13529540.462185979, tmp)&x)^((x<<(-1312696238.1628869))&(-2029766712.3852897)))>>x))/x)); - assertEquals(1657339940, x ^= ((tmp = -488956817.1491232, tmp)&(tmp = -2352413900.1983714, tmp))); - assertEquals(-530683621952432200, x *= (tmp = -320202035.2882054, tmp)); - assertEquals(229226258, x ^= ((tmp = -1263410990.026416, tmp)+(((-808046349)&(tmp = -1294442506, tmp))&((tmp = 1147437219, tmp)<<((tmp = -820299900, tmp)-(tmp = -1947748943.3443851, tmp)))))); - assertEquals(7163320, x >>= (-2631307131)); - assertEquals(-68, x |= (((-1271721343)>>x)%x)); - assertEquals(-39956523818.38862, x *= (587595938.505715)); - assertEquals(0, x -= x); - assertEquals(0, x >>>= ((x^(x+x))<<(tmp = 265212367, tmp))); - assertEquals(0, x |= (((x>>((tmp = 2294761023, tmp)/(x>>(2125624288))))&((-2125650113)|(tmp = 1014409884, tmp)))%(tmp = -527324757, tmp))); - assertEquals(0, x >>= ((tmp = 2267075595, tmp)*(-1681569641.8304193))); - assertEquals(0, x >>>= x); - assertEquals(0.5738410949707031, x -= ((tmp = -1846572645.573841, tmp)%((((((x^(((-156613905.64173532)/x)<<x))+((x|((2405109060)>>>x))^x))/(570585894.8542807))+(x&(-2544708558)))^((((tmp = -2539082152.490635, tmp)+((((-657138283)/(2204743293))-((tmp = -1422552246.565012, tmp)+x))<<(x-x)))>>(x/(x>>>(tmp = -3027022305.484394, tmp))))<<x))&((-2066650303.3258202)/(tmp = -1666842593.0050385, tmp))))); - assertEquals(0, x >>>= ((((tmp = 2473451837.613817, tmp)>>((2526373359.1434193)>>(x<<x)))+((tmp = -579162065, tmp)+((tmp = -3115798169.551487, tmp)-(tmp = 933004398.9618305, tmp))))&(tmp = 131167062, tmp))); - assertEquals(-2067675316, x ^= (-2067675316.6300585)); - assertEquals(543772, x >>>= x); - assertEquals(-1073741824, x <<= x); - assertEquals(3221225472, x >>>= ((x*(1478586441.081221))&(tmp = -3050416829.2279186, tmp))); - assertEquals(0, x ^= x); - assertEquals(0, x *= x); - assertEquals(-1017771903.0298333, x -= (1017771903.0298333)); - assertEquals(0.6404112721149928, x /= ((tmp = -144667370, tmp)^(-2849599562))); - assertEquals(-2410517638773644000, x -= (((tmp = 1759631550, tmp)*x)*((((tmp = -2949481475, tmp)>>>x)*x)|(tmp = -2977983804, tmp)))); - assertEquals(-0, x %= (x+((((tmp = -1307866327.7569134, tmp)<<((x&((tmp = -2380043169.8405933, tmp)|x))>>(472992789.7639668)))|(((((x<<(tmp = -1416427232.7298179, tmp))%(-1404989679.409946))*((x/(tmp = -992416608, tmp))/(tmp = 524646495, tmp)))-(tmp = 734405570, tmp))>>x))/(1079256317.7325506)))); - assertEquals(0, x <<= (tmp = 2459834668, tmp)); - assertEquals(-0, x /= (tmp = -1892164840.5719755, tmp)); - assertEquals(0, x >>= (x|(((1299844244)>>>(((tmp = -2422924469.9824634, tmp)|x)-((((1914590293.2194016)+(-3033885853.8243046))-((tmp = -1720088308, tmp)%x))<<(tmp = 2210817619, tmp))))<<x))); - assertEquals(0, x <<= (((tmp = 3192483902.841396, tmp)>>>(((x^(2944537154))|(tmp = -1334426566, tmp))*(((((((-2705218389)&x)+(1987320749))+(tmp = -111851605, tmp))|(2894234323))-(265580345))&x)))%(((tmp = 1431928204.6987057, tmp)&(tmp = 914901046, tmp))&(x>>>x)))); - assertEquals(0, x >>>= (tmp = 1941940941, tmp)); - assertEquals(0, x %= (3089014384)); - assertEquals(0, x += ((tmp = 2948646615, tmp)*x)); - assertEquals(-0, x /= (tmp = -1480146895, tmp)); - assertEquals(NaN, x /= x); - assertEquals(NaN, x %= (-2995257724.158043)); - assertEquals(NaN, x %= (tmp = 2714835455, tmp)); - assertEquals(NaN, x /= (tmp = -311440765.98078775, tmp)); - assertEquals(NaN, x -= (-1600234513.697098)); - assertEquals(0, x <<= x); - assertEquals(0, x <<= (-1499045929)); - assertEquals(-0, x *= (-2491783113)); - assertEquals(0, x ^= (x%((x>>(((1234398704.3681123)>>>x)%(x+x)))>>(402257223.4673699)))); - assertEquals(-643225204, x ^= (((-55960194.698637486)+((((721411198)-(((tmp = 1308676208.7953796, tmp)%(2242904895))-x))>>((((tmp = 332791012, tmp)&((tmp = -2094787948, tmp)/((x/(2427791092))^(2444944499.6414557))))%(((x+(1253986263.5049214))+(((((3135584075.248715)+((tmp = -2569819028.5414333, tmp)%(440908176.1619092)))>>>(x<<((3061615025)-x)))%x)%(x+((2369612016)*((((tmp = 1173615806, tmp)*(-1910894327))&(2428053015.077821))*(-55668334.70082307))))))<<(tmp = -2129259989.0307562, tmp)))+(1579400360)))%((-3053590451.8996153)>>x)))+(x>>(x%(x^((-1772493876)^x)))))); - assertEquals(413738663060841600, x *= x); - assertEquals(1581062538.4501781, x %= ((tmp = -1298397672.0300272, tmp)-((2237197923)+(tmp = -1385478459, tmp)))); - assertEquals(755644566.8709538, x %= (tmp = -825417971.5792243, tmp)); - assertEquals(1, x /= x); - assertEquals(0, x >>>= ((89330582)%(-1012731642.4855506))); - assertEquals(0, x >>>= x); - assertEquals(NaN, x %= ((x>>>((x/(tmp = -1848848941.2352903, tmp))>>>(tmp = -71862893, tmp)))&(-2385996598.2015553))); - assertEquals(NaN, x += (-2292484503.318904)); - assertEquals(NaN, x *= (2961064461)); - assertEquals(NaN, x += (x<<((2076798243.6442)/((tmp = -81541044.75366282, tmp)^((3041366498.551101)+((2126874365)/(tmp = -177610359, tmp))))))); - assertEquals(NaN, x %= ((x/((x/x)+x))>>>x)); - assertEquals(NaN, x /= x); - assertEquals(NaN, x += (1171761980.678)); - assertEquals(NaN, x += ((2355675823)<<(-390497521))); - assertEquals(NaN, x %= x); - assertEquals(0, x &= (tmp = -658428225.56619, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x <<= (1643310725.5713737)); - assertEquals(0, x <<= x); - assertEquals(0, x <<= (-397005335.3712895)); - assertEquals(0, x >>>= (tmp = -2804713458.166788, tmp)); - assertEquals(0, x <<= (((((((tmp = 1879988501, tmp)%(1528081313.9360204))+(1376936736))*((((x>>>((1736268617.339198)>>>(-2598735297.4277673)))<<((((((((-2742982036)/(231867353.4549594))-(875335564))<<x)|((2241386341.742653)<<((-22024910.828409433)&(x<<x))))*(-756987803.5693252))+x)^(tmp = 1084498737, tmp)))<<(1920373881.8464394))&(2370827451.82652)))&(x^(tmp = -891503574, tmp)))<<x)>>>((-1519588625.2332087)^(483024636.2600144)))); - assertEquals(52193878.40997505, x -= ((tmp = -341753803.40997505, tmp)%(tmp = -96519975, tmp))); - assertEquals(-1665844168.938803, x -= (1718038047.348778)); - assertEquals(3.6962232549405003e-19, x /= (((((-809583468.5507183)>>>((tmp = 286797763, tmp)%((1579183142.7321532)/(1853824036.001172))))<<x)>>(((x|x)^((tmp = -2641304815, tmp)<<(x<<x)))>>(((((268338128.8300134)&(-1778318362.8509881))*(751081373.346478))<<(((525066612)>>(-1139761212))*(2949167563.299916)))<<x)))+((tmp = 664905121, tmp)*((-2208280205)*(3069462420))))); - assertEquals(4710721795.110161, x += (((217604832)+((1307891481.781326)-x))+(tmp = 3185225481.328835, tmp))); - assertEquals(0, x %= x); - assertEquals(0, x -= (((x>>>(x/(tmp = 46977522.46204984, tmp)))>>(-2466993199.615269))&(tmp = 14524430.287991166, tmp))); - assertEquals(0, x >>= x); - assertEquals(0, x /= (tmp = 578120637, tmp)); - assertEquals(-17267104, x -= (((tmp = 1515285919.495792, tmp)+(((tmp = -1364790286.7057304, tmp)+((954599071)>>((897770243.1509961)*x)))^x))>>>(566027942.1732262))); - assertEquals(-17267104, x &= x); - assertEquals(189138241, x ^= ((tmp = 1565742675.9503145, tmp)-((tmp = 1737806643, tmp)|((x*(tmp = -1382435297.5955122, tmp))*(-2820516692.153056))))); - assertEquals(189138241, x %= (x*(tmp = -1670678493, tmp))); - assertEquals(1693, x %= ((-2328713314)>>>(1623637325))); - assertEquals(1693, x %= ((-1019394014)*(x|x))); - assertEquals(3386, x += x); - assertEquals(9268970871604, x *= (2737439714)); - assertEquals(-4720.120483643183, x /= (tmp = -1963714889, tmp)); - assertEquals(-1, x >>= ((x^(((-2404688047.455056)|((1439590234.6203847)<<(tmp = -2496557617, tmp)))/((x<<((tmp = 1865549512.282249, tmp)/(((360384191.55661833)>>(tmp = -1225297117.344188, tmp))>>>(2703264010.4122753))))*(1521960888.0071676))))%(tmp = 2834001448.0508294, tmp))); - assertEquals(63, x >>>= (x&(-3079339174.6490154))); - assertEquals(0, x >>>= (1039770956.6196513)); - assertEquals(0, x >>>= (-1074820214)); - assertEquals(0, x >>>= (x/x)); - assertEquals(0, x >>= ((tmp = -449117604.2811785, tmp)&x)); - assertEquals(-0, x /= (tmp = -118266935.1241343, tmp)); - assertEquals(2226140134, x += (tmp = 2226140134, tmp)); - assertEquals(2068827161, x ^= ((tmp = -1950744808.846384, tmp)>>((2258661151)^((tmp = -1118176421.8650177, tmp)<<(2828634014))))); - assertEquals(123, x >>>= (-1779624840.0515127)); - assertEquals(0, x >>>= (x|((tmp = -239082904, tmp)<<(tmp = 1404827607, tmp)))); - assertEquals(0, x >>>= x); - assertEquals(1793109749, x ^= (tmp = -2501857547.710491, tmp)); - assertEquals(855, x >>>= x); - assertEquals(0, x >>>= (-847289833)); - assertEquals(0, x %= (-2271241045)); - assertEquals(169648072, x ^= (((tmp = 169648072.66759944, tmp)^x)|x)); - assertEquals(176025927479164930, x *= ((tmp = 1111997198.8803885, tmp)<<(tmp = 2913623691, tmp))); - assertEquals(176025926613281700, x += ((tmp = -865883245, tmp)<<(x+(-2624661650)))); - assertEquals(3406506912, x >>>= ((x|(tmp = 2436016535, tmp))*(((tmp = -1222337225, tmp)<<((1765930268)&x))*(tmp = 1600702938, tmp)))); - assertEquals(1.694694170868292, x %= (x/(-1597121830.794548))); - assertEquals(0, x >>= (tmp = -2443203089, tmp)); - assertEquals(0, x >>>= (1323174858.2229874)); - assertEquals(0, x &= ((tmp = 846556929.2764134, tmp)|(((1483000635.0020065)|(-3151225553))|(tmp = -229028309, tmp)))); - assertEquals(0, x >>= x); - assertEquals(0, x >>= ((((((-2677334787)>>>x)>>((tmp = 496077992, tmp)&((((x<<(x*(tmp = 1095163344.2352686, tmp)))+(-952017952))%((x<<((x*x)/(tmp = 2983152477, tmp)))^((tmp = -939521852.1514642, tmp)^(tmp = 143967625.83755958, tmp))))*((tmp = 551827709.8366535, tmp)>>>x))))^((-1552681253.69869)-(-1874069995)))>>>(x>>(x%(tmp = -2554673215, tmp))))|(tmp = -190693051.77664518, tmp))); - assertEquals(0, x /= (tmp = 427402761.37668264, tmp)); - assertEquals(0, x <<= x); - assertEquals(0, x |= (x>>>(((((-543326164.0673618)>>>(-2344090136.707964))>>>((((-563350246.6026886)/x)/(1525481037.3332934))&(tmp = -2917983401.88958, tmp)))^(-1094667845.1208413))^x))); - assertEquals(0, x &= (1080322749.897747)); - assertEquals(0, x %= (tmp = -1572157280, tmp)); - assertEquals(0, x >>>= x); - assertEquals(0, x %= ((377280936)|x)); - assertEquals(708335912, x -= (tmp = -708335912, tmp)); - assertEquals(2766937, x >>>= x); - assertEquals(547342779, x += (tmp = 544575842, tmp)); - assertEquals(546273751, x -= ((x>>>(472833385.9560914))|((tmp = -1164832103.9970903, tmp)/(3147856452.1699758)))); - assertEquals(546273751, x &= x); - assertEquals(0, x ^= x); - assertEquals(0, x >>>= (tmp = -3181805175, tmp)); - assertEquals(-375546685, x |= (-375546685.08261824)); - assertEquals(1089992785780217200, x *= (tmp = -2902416209, tmp)); - assertEquals(0, x %= x); - assertEquals(-1854981526, x -= ((x-x)-(-1854981526))); - assertEquals(-3709963052, x += x); - assertEquals(-316772482, x %= (tmp = -1696595285, tmp)); - assertEquals(-316772482, x |= x); - assertEquals(1, x /= x); - assertEquals(0, x -= x); - assertEquals(-1418375842, x ^= (-1418375842)); - assertEquals(-2, x >>= x); - assertEquals(-4, x += x); - assertEquals(-8388608, x &= (x<<(-350555339.30086184))); - assertEquals(-16777216, x += x); - assertEquals(-0, x %= x); - assertEquals(1083355129, x += (tmp = 1083355129, tmp)); - assertEquals(0, x &= (((tmp = 389729053, tmp)-(tmp = 2944192190.0939536, tmp))/(x-(2081712461.2657034)))); - assertEquals(0, x += x); - assertEquals(-3, x += ((3147270119.5831738)>>((2455837253.1801558)%((-2100649096)>>(((290236808.01408327)|(x&((2661741230.3235292)|((tmp = 1686874589.4690177, tmp)<<x))))*(x+(tmp = 2327674670, tmp))))))); - assertEquals(-3, x %= ((x>>(((-2962686431)%x)>>((((2438370783)-(tmp = 2667305770.4839745, tmp))>>>x)>>>x)))<<((x&(tmp = 1428498616, tmp))|((tmp = 2621728539.102742, tmp)/(-204559901))))); - assertEquals(2, x ^= (x|((((tmp = 1751230118.6865973, tmp)/(-867465831.207304))>>((-808143600.0912395)+(-2882191493.0506454)))^x))); - assertEquals(2, x %= (-2015954220.2250996)); - assertEquals(0, x >>>= (tmp = 401373999, tmp)); - assertEquals(0, x >>= (2371830723)); - assertEquals(0, x >>>= ((((tmp = 2765919396, tmp)-x)-(530310269.7131671))|(tmp = -615761207.9006102, tmp))); - assertEquals(-145389011, x ^= (tmp = -145389011, tmp)); - assertEquals(-145389011, x |= x); - assertEquals(1632929832, x &= (-2518898392)); - assertEquals(4190540017.751949, x += (tmp = 2557610185.751949, tmp)); - assertEquals(4980024282.153588, x += ((1841304364.1177452)%(tmp = 1051820099.7161053, tmp))); - assertEquals(0, x >>>= (((((1379314342.4233718)>>((-2782805860)^((x%(tmp = 1328845288, tmp))>>>(tmp = 901403219.858733, tmp))))+(x/((tmp = -3078904299, tmp)/x)))/x)|(x|(1399702815)))); - assertEquals(-1820494882, x ^= (tmp = -1820494882.407127, tmp)); - assertEquals(-305870376, x %= (tmp = -757312253, tmp)); - assertEquals(-577530443, x += (x|(tmp = -1958083619.6653333, tmp))); - assertEquals(333541412591776260, x *= x); - assertEquals(-949341696, x >>= ((((1550069663)<<((x>>>(tmp = 2406565178.902887, tmp))>>>((1844746612.632984)/((tmp = 2233757197, tmp)*((-1524891464.1028347)>>(tmp = 2498623474.5616803, tmp))))))&x)<<(x&(tmp = -370379833.3884752, tmp)))); - assertEquals(-277202090, x |= ((-762200848.8405354)-(tmp = 1749136282, tmp))); - assertEquals(0.13704539927239265, x /= (tmp = -2022702633.373563, tmp)); - assertEquals(0, x -= x); - assertEquals(0, x %= ((132951580.19304836)-((427623236.27544415)-(1212242858)))); - assertEquals(0, x &= ((449148576)&(-1609588210.249217))); - assertEquals(0, x >>= x); - assertEquals(0, x -= x); - assertEquals(-0, x /= (tmp = -1640777090.9694843, tmp)); - assertEquals(0, x &= (((tmp = -1923412153, tmp)>>>((x>>(tmp = 3027958119.0651507, tmp))+(60243350)))>>(tmp = -2610106062, tmp))); - assertEquals(0, x ^= (((-186998676)/(tmp = 2697937056, tmp))-x)); - assertEquals(-1147950080, x |= ((2425449461)*(tmp = -2525854833, tmp))); - assertEquals(457688198, x ^= (2698274950.660941)); - assertEquals(8724, x %= ((1174351031)>>>((371599047.36048746)+(3025292010)))); - assertEquals(0, x <<= (tmp = -710011617, tmp)); - assertEquals(0, x >>>= (1693410026)); - assertEquals(1443005362, x ^= ((tmp = -2851961934, tmp)+((((x%x)-(tmp = 547622400, tmp))<<(((tmp = 722396486.5553623, tmp)|x)>>>((((tmp = -542268973.5080287, tmp)<<(tmp = 1347854903.771954, tmp))>>>(tmp = -889664427.7115686, tmp))&((tmp = 1549560114, tmp)*(tmp = 964918035, tmp)))))&(-2422502602.920377)))); - assertEquals(3986573462, x -= (-2543568100)); - assertEquals(7973146924, x += x); - assertEquals(-1, x >>= (-75987297)); - assertEquals(-12, x += ((2940824338.64834)>>(tmp = 3061467355, tmp))); - assertEquals(-3.8229398525977614e-8, x /= (313894554)); - assertEquals(-2.890709270374084e-17, x /= (tmp = 1322491989, tmp)); - assertEquals(0, x |= (x-x)); - assertEquals(0, x >>>= (tmp = -1205300664, tmp)); - assertEquals(-0, x /= (((2869505187.6914144)>>(tmp = 1541407065, tmp))/(((-571132581)>>>(x>>x))/((x^(170373762.8793683))>>>((((tmp = -363073421.05897164, tmp)|(((tmp = -1591421637, tmp)>>(1095719702.8838692))&(636687681.9145031)))^x)^(x|x)))))); - assertEquals(-1487828433, x ^= (-1487828433.3462324)); - assertEquals(-0, x %= x); - assertEquals(1716342498, x -= ((tmp = 2578624798, tmp)^x)); - assertEquals(1636, x >>= ((264194540)>>>(-801900756))); - assertEquals(0, x >>>= ((tmp = 2502688876, tmp)+((x<<(x|((-628272226.0338528)|((x<<(-2083074091))>>>(tmp = 1692123246.8418589, tmp)))))>>(1594759826.990993)))); - assertEquals(0, x <<= (tmp = -904399643, tmp)); - assertEquals(NaN, x /= ((x^(x-x))%((tmp = 1744962024.4882128, tmp)%x))); - assertEquals(NaN, x /= (-1013142883.1845908)); - assertEquals(NaN, x /= ((tmp = 793633198, tmp)^(-2993598490.8659954))); - assertEquals(0, x &= (x>>((tmp = 1200937851, tmp)<<(((tmp = -2807378465, tmp)&(tmp = -143778237, tmp))|(tmp = -1200772223, tmp))))); - assertEquals(0, x <<= x); - assertEquals(88144, x |= (((((tmp = 3002723937.8560686, tmp)*(tmp = -3171720774.2612267, tmp))%(((tmp = -2586705978.7271833, tmp)%((x+(-1553704278))&(2405085526.501994)))>>((-240842053)>>>(((((tmp = -1886367228.4794896, tmp)>>>x)^(tmp = 2604098316, tmp))^(tmp = 1362808529, tmp))<<((tmp = -1062263918, tmp)|((-172718753)%(tmp = -1910172365.4882073, tmp)))))))^((1444153362)>>((x&((-1205465523.2604182)^(tmp = -2062463383, tmp)))>>(tmp = 956712476, tmp))))>>((((-1004215312)^((((-1707378612.5424936)^(tmp = 2372161553, tmp))/((tmp = 1802586581, tmp)*((2082257.1896460056)&((tmp = -1270773477, tmp)^(tmp = 942517360.3447798, tmp)))))+x))%((((666494127)^(x^x))>>>(tmp = -2592829775, tmp))+((-1601528223)+((x+(tmp = -2417034771.7409983, tmp))>>>((tmp = -730673817, tmp)*x)))))>>x))); - assertEquals(-2603179111.7557006, x -= ((2603267255.755627)+(x/(1200979191.2823262)))); - assertEquals(1691788185, x >>= (tmp = 3088840032, tmp)); - assertEquals(-168382533, x |= (tmp = -780750941.4590135, tmp)); - assertEquals(-168382533, x >>= (60741120.48285198)); - assertEquals(-134287365, x |= (x*(tmp = 834637940.7151251, tmp))); - assertEquals(-1481917089, x -= (tmp = 1347629724, tmp)); - assertEquals(1, x >>>= x); - assertEquals(262144, x <<= (2680216914)); - assertEquals(1075132032, x ^= (x-((tmp = 3220359552.3398685, tmp)^(((-434474746.6039338)|((((((((tmp = 1945689314.9683735, tmp)>>(1300022273))>>>(333705550))&x)%(588357521))-(x+(x^(((tmp = -134560382, tmp)+x)-((((994246147.7195556)-(-1506599689.7383268))%(x<<x))>>((1256426985.5269494)+(tmp = 1860295952.8232574, tmp)))))))^(((tmp = 917333220.2226384, tmp)>>x)>>>(tmp = 865898066, tmp)))%((x|(x%((tmp = -2660580370, tmp)&(tmp = 2966426022, tmp))))*x)))/(((tmp = 682585452, tmp)&(-3219368609))+((tmp = -1330253964, tmp)+((x&(2857161427))/x))))))); - assertEquals(274944, x &= ((2606953028.1319966)-(-1707165702))); - assertEquals(266752, x &= ((x<<((x+(x+(x^(-1570175484))))^x))^(x+(x<<(tmp = 90330700.84649956, tmp))))); - assertEquals(266752, x &= ((((x*(tmp = 2033225408, tmp))-(x-((tmp = 1507658653, tmp)/(-3016036094))))>>>((1497480588)>>(2784070758)))|(tmp = -3025904401.93921, tmp))); - assertEquals(-1680442631, x |= ((x/(445284843))|((tmp = 2614520057.2723284, tmp)<<x))); - assertEquals(40851947, x >>>= (tmp = -1577031386.938616, tmp)); - assertEquals(2493, x >>= ((3044630989.3662357)-(-2670572992.8580284))); - assertEquals(-0.0000017317105653562252, x /= (-1439617017.9207587)); - assertEquals(0, x &= (2359806567)); - assertEquals(623768541, x ^= (623768541)); - assertEquals(1028567149.0716183, x += (((tmp = 1307794561, tmp)%(x>>x))-(-404798608.0716183))); - assertEquals(-1.2971762489811298, x /= (tmp = -792927830.6471529, tmp)); - assertEquals(-1.2971762489811298, x %= ((-2426421701.2490773)/(-689566815.3393874))); - assertEquals(-2147483648, x <<= x); - assertEquals(-2147483648, x &= (tmp = -869991477, tmp)); - assertEquals(-268435456, x >>= (1383186659)); - assertEquals(0, x -= x); - assertEquals(-2009742037, x |= (-2009742037.5389993)); - assertEquals(-1386630820, x ^= (627864695)); - assertEquals(-1033479103975173600, x *= (tmp = 745316697.9046186, tmp)); - assertEquals(-1628048487, x |= (2662654361)); - assertEquals(325551, x >>>= (340874477)); - assertEquals(-1235730537, x ^= (tmp = 3059533880.0725217, tmp)); - assertEquals(-1235730537, x %= (2247137328)); - assertEquals(-220200960, x <<= ((x>>x)-x)); - assertEquals(0, x <<= ((tmp = 337220439.90653336, tmp)|(tmp = 2901619168.375105, tmp))); - assertEquals(0, x >>>= ((-2114406183)/x)); - assertEquals(0, x %= ((1425828626.3896675)/x)); - assertEquals(0, x >>>= ((3213757494)>>>(2595550834.3436537))); - assertEquals(0, x <<= x); - assertEquals(-0, x /= ((1544519069.5634403)/((tmp = -1332146306, tmp)&(-762835430.0022461)))); - assertEquals(0, x ^= x); - assertEquals(0, x >>= (x|((((x*((-786272700)+x))<<x)+((tmp = -1868484904, tmp)-(tmp = -1692200376, tmp)))+(-1010450257.6674457)))); - assertEquals(0, x -= x); - assertEquals(0, x ^= (x>>>(706010741))); - assertEquals(-964928697, x |= (-964928697)); - assertEquals(1, x /= x); - assertEquals(0, x >>= ((((tmp = 1778003555.3780043, tmp)>>(x%((tmp = -766158535, tmp)^((-2681449292.8257303)%((x-(x|(tmp = 1966478387.2443752, tmp)))^(((tmp = -1848398085, tmp)&x)>>>(tmp = -2860470842, tmp)))))))%(tmp = 2315077030, tmp))^x)); - assertEquals(0, x ^= x); - assertEquals(-288007757, x ^= ((tmp = 183607156.1803962, tmp)-(tmp = 471614914, tmp))); - assertEquals(-270573581, x |= (tmp = -849475741.9424644, tmp)); - assertEquals(-2129929, x |= (((((1942852445)&(tmp = 1280372312, tmp))*(x*(tmp = -1601900291, tmp)))^((509080002.81080174)-(tmp = 2699498226.9164257, tmp)))>>(((-335361221)>>(tmp = 843134832, tmp))%(-35532542)))); - assertEquals(-232622355, x ^= ((-3060885134.5375547)-(((tmp = 1965966723, tmp)-((tmp = 1248630129.6970558, tmp)<<(tmp = 1859637857.5027392, tmp)))*x))); - assertEquals(-52149658093200070, x *= (224181627.31264615)); - assertEquals(-697122968, x ^= (x-(x+(tmp = 2747211186.407712, tmp)))); - assertEquals(-2146269688, x &= ((tmp = -1466710519, tmp)^(x/(1419998975)))); - assertEquals(-536567422, x >>= (((((tmp = -1760701688.999274, tmp)>>(-1821976334))/(((tmp = -1660849531, tmp)>>>x)-((x+((tmp = -2489545009.4327965, tmp)>>>((tmp = -267360771.39148235, tmp)^x)))*(((-1453528661)%x)>>>(((243967010.3118453)/((((((2977476024)>>>((-1630798246)<<x))&(591563895.2506002))*(((2668543723.9720144)>>>x)|(1600638279)))^x)>>(x<<(tmp = -152589389, tmp))))>>>(x|(2821305924.9225664)))))))+(618968002.8307843))%(tmp = -1005408074.368274, tmp))); - assertEquals(40962, x &= (114403906)); - assertEquals(19741977727890, x *= ((-2367133915.963945)>>>(-3119344126))); - assertEquals(1313341440, x <<= x); - assertEquals(626, x >>>= ((((-333992843)%(tmp = -2742280618.6046286, tmp))>>>x)|x)); - assertEquals(0, x <<= (2598188575)); - assertEquals(NaN, x %= x); - assertEquals(NaN, x %= x); - assertEquals(0, x ^= (x%((2507288229.3233204)&(tmp = -1714553169.9276752, tmp)))); - assertEquals(0, x /= ((633436914.3859445)>>>(tmp = 1579804050.6442273, tmp))); - assertEquals(0, x *= ((tmp = 1172218326, tmp)<<((tmp = -2491306095.8456626, tmp)*(((tmp = 1305371897.9753594, tmp)>>((x^(((3077992060)*x)<<(492815553.904796)))>>((652151523)|x)))%x)))); - assertEquals(0, x <<= x); - assertEquals(0, x %= (1118131711)); - assertEquals(0, x &= ((tmp = 2734673884, tmp)|(x-((tmp = 2694578672.8975897, tmp)*(((x>>(2350811280.974167))*(1052548515))&(x^(x*(tmp = -1336287059.0982835, tmp)))))))); - assertEquals(-2632782867.1256156, x += ((tmp = -2743992725.1256156, tmp)+(tmp = 111209858, tmp))); - assertEquals(-0, x %= x); - assertEquals(0, x >>>= (((tmp = -2050519887, tmp)^(106865302.74529803))>>(1642851915.2909596))); - assertEquals(-171964826, x |= (tmp = -171964826.6087358, tmp)); - assertEquals(-2.113405951193522, x /= (tmp = 81368572.80206144, tmp)); - assertEquals(3, x >>>= x); - assertEquals(0, x %= x); - assertEquals(-1717345907.837667, x += (-1717345907.837667)); - assertEquals(-100964883, x |= (tmp = -109574931.80629134, tmp)); - assertEquals(-33849857, x |= (-974111718.2433801)); - assertEquals(1, x >>>= (tmp = -2556222849.005595, tmp)); - assertEquals(1, x /= x); - assertEquals(0, x >>>= (-1796630999.4739401)); - assertEquals(0, x >>>= x); - assertEquals(2031695758, x += (((x/(((tmp = -2364918403, tmp)%(x^((tmp = 277767803.6375599, tmp)>>((((tmp = 540036080, tmp)/(x|(2665298931)))/(x|((x>>(-2035456216.6165116))<<(2143184420.5651584))))^x))))&(tmp = 927798419.8784283, tmp)))-(-2031695758))>>>x)); - assertEquals(2031695758, x |= x); - assertEquals(2031695758, x <<= (((x>>(x%x))|(tmp = -1164531232.7384055, tmp))*x)); - assertEquals(124004, x >>>= x); - assertEquals(529846352, x += ((529722348)%((2417645298.865121)|(x>>(x>>>(x+x)))))); - assertEquals(60067920, x &= (((tmp = -3166008541.8486233, tmp)-x)|(x%x))); - assertEquals(1415594240755200, x *= ((-2786707452.873729)>>(((tmp = -2369315809, tmp)*((1559868465)|(1011218835.1735028)))>>>x))); - assertEquals(1415595182259140, x += (941503939.9023957)); - assertEquals(0, x <<= ((tmp = 2887184784.265529, tmp)/(-2575891671.0881453))); - assertEquals(0, x &= ((tmp = -1546339583, tmp)>>>(tmp = -587433830, tmp))); - assertEquals(0, x *= (((tmp = 1356991166.5990682, tmp)%(tmp = -284401292, tmp))*(1869973719.9757812))); - assertEquals(NaN, x %= x); - assertEquals(0, x ^= (((tmp = 92575404.43720293, tmp)>>>(263475358.17717505))%x)); - assertEquals(0, x <<= (((561514358)*(tmp = -439584969, tmp))%((((-3005411368.7172136)+x)|(-2230472917))&x))); - assertEquals(0, x >>= ((x>>>x)-((x-(1630649280.510933))+x))); - assertEquals(0, x >>= (tmp = -1772403084.7012017, tmp)); - assertEquals(0, x *= x); - assertEquals(0, x += x); - assertEquals(0, x &= x); - assertEquals(0, x >>= (tmp = 1622680387, tmp)); - assertEquals(1033887633558225200, x -= ((-510616337)*(tmp = 2024783695, tmp))); - assertEquals(-2.8073538539158063e+27, x *= (tmp = -2715337492, tmp)); - assertEquals(-2.8073538539158063e+27, x -= ((tmp = -1664804757, tmp)&((tmp = -226616419, tmp)>>>(1006711498)))); - assertEquals(1894539615, x |= (tmp = -2400427681.1831083, tmp)); - assertEquals(7400545, x >>= (774629608.4463601)); - assertEquals(456756268, x += (449355723)); - assertEquals(285771784, x &= (-1316427366)); - assertEquals(17, x >>= ((tmp = -220509931.20787525, tmp)*(((tmp = 2518859292, tmp)+(-1477543005.1586645))>>(tmp = 3172820250.687789, tmp)))); - assertEquals(85924262443, x *= (x*((tmp = -2856669745.965829, tmp)&(((tmp = 401420695, tmp)^(tmp = 2355371132, tmp))|(tmp = 590645330.021911, tmp))))); - assertEquals(1703875715, x ^= ((-2576394029.7843904)-x)); - assertEquals(1703875715, x %= (tmp = 2234144310, tmp)); - assertEquals(271405807, x ^= (1973569132)); - assertEquals(1060178, x >>>= (tmp = -84823096, tmp)); - assertEquals(8, x >>>= (tmp = 2246120561.905554, tmp)); - assertEquals(-2846791089, x += (-2846791097)); - assertEquals(104933962, x &= (x-(-2969030955.99584))); - assertEquals(489215611.96215343, x -= (-384281649.96215343)); - assertEquals(489215611, x |= x); - assertEquals(1186191360, x <<= ((tmp = 774407142.993727, tmp)%x)); - assertEquals(1186191360, x %= (1555004022)); - assertEquals(-1697134080, x ^= (tmp = -597421568, tmp)); - assertEquals(-1102053376, x <<= ((-927370769.4059179)^((tmp = 1093490918, tmp)>>(((-2522227493.3821955)%x)+(-2657319903))))); - assertEquals(1086450058, x ^= (-23991926.187098265)); - assertEquals(1086450058, x |= x); - assertEquals(-1.6554590588410778, x /= (x|(x<<(x+x)))); - assertEquals(67108863, x >>>= ((-926530233)+x)); - assertEquals(494553310, x ^= (tmp = 512079649, tmp)); - assertEquals(207751168, x &= (2892146720.6261826)); - assertEquals(207751168, x &= x); - assertEquals(207751168, x |= x); - assertEquals(6340, x >>>= (((((x<<(x-((-2819638321)*((x<<x)+x))))>>x)+(tmp = 2016170261, tmp))+(tmp = 2755496043.772017, tmp))+(-841368625.1402085))); - assertEquals(6340, x ^= ((x/(tmp = -192734784, tmp))>>>(((-140306239)&x)-x))); - assertEquals(1, x /= x); - assertEquals(0, x >>= x); - assertEquals(26786600, x ^= (tmp = 26786600, tmp)); - assertEquals(-0.014657576899542954, x /= ((-1454855938.0338)+(-372635753.3681567))); - assertEquals(0, x &= ((tmp = 2480635933, tmp)&(-2986584704.9165974))); - assertEquals(-2108639122, x += ((tmp = 2108639123.8683565, tmp)^((-881296055)/(((x<<(2026200582))|(tmp = -862495245.138771, tmp))-(-1111596494.892467))))); - assertEquals(1893466112, x <<= (tmp = 607974481, tmp)); - assertEquals(1893466112, x |= x); - assertEquals(1133122783.997418, x += ((tmp = -760343332, tmp)-((x-(tmp = -878561823.4218843, tmp))/(tmp = -693454632.596637, tmp)))); - assertEquals(8, x >>>= (tmp = 700339003.3919828, tmp)); - assertEquals(4.605305035175536e-9, x /= (1737127060.8343256)); - assertEquals(4.605305035175536e-9, x -= ((x%(897221779))>>>x)); - assertEquals(-1864423625.5704088, x += (tmp = -1864423625.5704088, tmp)); - assertEquals(1132240092, x <<= (1304417186.1193643)); - assertEquals(-2088985380, x ^= (x<<x)); - assertEquals(-4, x >>= ((tmp = 1959823884.0935726, tmp)%(-1679792398.569136))); - assertEquals(-268435456, x <<= ((tmp = 2586838136, tmp)|((tmp = -481716750.718518, tmp)>>>((1485826674.882607)/(tmp = -2826294011, tmp))))); - assertEquals(-32768, x >>= (2060648973)); - assertEquals(1, x /= x); - assertEquals(-2838976297, x -= (tmp = 2838976298, tmp)); - assertEquals(-1382985298, x <<= ((tmp = -2104305023, tmp)&x)); - assertEquals(10, x >>>= (x+x)); - assertEquals(10, x -= (x>>>(361588901.70779836))); - assertEquals(854603510, x -= (-854603500)); - assertEquals(-557842432, x <<= (tmp = 1212985813.6094751, tmp)); - assertEquals(-459390188241943040, x *= (tmp = 823512450.6304014, tmp)); - assertEquals(-232800033621957060, x /= ((((((686635689)/(tmp = 2013252543, tmp))*(tmp = -1591617746.8678951, tmp))|(((tmp = -1777454093.5611362, tmp)>>>((tmp = 2680809394, tmp)^(((x>>((((((tmp = -265022244, tmp)%((tmp = -3075004537, tmp)>>(((((1427784269.5686688)^((tmp = -1095171528.911587, tmp)^(-942424985.7979553)))>>(-1279441481.1987405))*((2493620394)>>(-2769016043)))/(x&((tmp = 2059033657, tmp)%(((tmp = 1948606940.1488457, tmp)-(tmp = -2645984114.13219, tmp))^x))))))^x)^x)%(x%((((tmp = 3209433446.4551353, tmp)%(tmp = 1364430104.0424738, tmp))/(tmp = -2103044578.349498, tmp))+(tmp = -2613222750, tmp))))*(2099218034)))&(((tmp = -378500985.49700975, tmp)>>(((x+x)|(x%(((-1841907486)<<(-1220613546.194021))<<(tmp = -1260884176, tmp))))^(tmp = 1858784116, tmp)))>>>((x%x)%((x>>>(tmp = -2540799113.7667685, tmp))|x))))/((((tmp = 642072894.6455215, tmp)-(-324951103.6679399))*(tmp = 1424524615, tmp))+((x<<(tmp = -904578863.5945344, tmp))*(tmp = 49233475.435349464, tmp))))))<<(tmp = 1680210257, tmp)))+((tmp = -1516431503, tmp)>>>(-1105406695.3068116)))/(-275019361.6764543))); - assertEquals(192359387.42913792, x /= (-1210234846)); - assertEquals(192359387.42913792, x %= (-2920206625.0154076)); - assertEquals(192359387.42913803, x -= (((((((tmp = -1263203016.3258834, tmp)-(2432034005.6011124))&x)<<(1479434294))>>((tmp = -1695856315.523002, tmp)>>>(tmp = 557391345, tmp)))/(tmp = -1280240246.2501266, tmp))%((tmp = -2196489823.034029, tmp)>>(((x&((912221637.1101809)+((tmp = -3003677979.652423, tmp)>>(tmp = -716129460.1668484, tmp))))-((x+(x-(-2780610859)))>>>(-2445608016)))<<((x*(x+(x+(((-2124412727.9007604)%(tmp = -593539041.5539455, tmp))&(tmp = 2404054468.768749, tmp)))))%(x>>(tmp = -2913066344.404591, tmp))))))); - assertEquals(11740, x >>= (688848398.7228824)); - assertEquals(11740, x >>= ((1545765912)*(307650529.9764147))); - assertEquals(23480, x += x); - assertEquals(0, x >>>= ((tmp = 1313078391, tmp)|x)); - assertEquals(1726251264, x -= ((1939413887)<<(1004888744.2840619))); - assertEquals(765324793.5278986, x %= (960926470.4721014)); - assertEquals(747387, x >>= ((2483010044)-(tmp = -413698190, tmp))); - assertEquals(1, x /= x); - assertEquals(3016811624, x *= (3016811624)); - assertEquals(17408, x &= (((tmp = -991624868, tmp)<<(((63107932)/(tmp = 2659939199, tmp))|(tmp = -1968768911.3575773, tmp)))>>(((-2876822038.9910746)|(tmp = 2550230179.243425, tmp))<<((x*(x<<((x<<((tmp = -1627718523.616604, tmp)|((2154120561.254636)-(x%(x<<(1484563622.1791654))))))<<((((x^(tmp = 3016524169, tmp))<<(((x+(tmp = 1887816698.2455955, tmp))+x)-x))-(-3023329069))-x))))+x)))); - assertEquals(0, x <<= (((1247441062.177967)/(-1717276234))+x)); - assertEquals(0, x |= ((x%((-1648299429.4520087)>>(-137511052)))>>(tmp = 221301016.4926411, tmp))); - assertEquals(0, x /= ((-2598501544.913707)>>>(-2177037696))); - assertEquals(NaN, x %= (x>>x)); - assertEquals(0, x &= (tmp = 1852419158, tmp)); - assertEquals(-829029120, x |= (((2122339180)*((((((tmp = 768748914, tmp)<<((1008490427)&((1937367899.957056)-(((635094486)>>(((tmp = -795046025, tmp)*(2665104134.4455256))^(tmp = 706594584.2462804, tmp)))/(504397522)))))/(-556057788))>>((x/(tmp = -2732280594, tmp))-x))+(-1989667473))+(tmp = 2766802447.789895, tmp)))<<(((tmp = -2969169096, tmp)-x)+(tmp = 2093593159.0942125, tmp)))); - assertEquals(0.6451933462602606, x /= ((-1284931292)<<(x<<(tmp = 1294716764, tmp)))); - assertEquals(1515416866.520901, x *= (2348779440)); - assertEquals(-1620606242886682600, x *= ((-993898625.5357854)&(((tmp = -571100481, tmp)/x)*((2428590177.311031)%(tmp = -2671379453, tmp))))); - assertEquals(-1137472828, x %= (tmp = -1195183004, tmp)); - assertEquals(-3096634005473250000, x *= (tmp = 2722380640, tmp)); - assertEquals(-3096634003996758500, x -= (-1476491033.833419)); - assertEquals(-3096634000805538000, x += (3191220521.978341)); - assertEquals(-3096634000805468000, x += ((((tmp = -3024976741, tmp)&(952616360))|((x*(-1547952311))+(x*x)))>>>(tmp = 981373323, tmp))); - assertEquals(-3096633998655594000, x += (2149873927)); - assertEquals(-118812224101.54297, x %= (((2641881276.9898443)*(((502159480)^x)<<x))%((tmp = -2840045365.547772, tmp)*(((((-2297661528)>>>(x>>(-229103883.94961858)))&(((-1285047374.6746495)<<((-360045084)>>>((x-(tmp = -956123411.1260898, tmp))%x)))>>((tmp = -2375660287.5213504, tmp)+((((tmp = -2753478891, tmp)>>>(((tmp = 101438098, tmp)>>(((tmp = -2736502951, tmp)<<((tmp = -3084561882.368902, tmp)&(tmp = 1491700884, tmp)))|x))&(tmp = 1627412882.6404104, tmp)))>>>(tmp = 1039002116.6784904, tmp))<<((tmp = -2840130800, tmp)-(tmp = -740035567, tmp))))))&(tmp = -416316142, tmp))>>x)))); - assertEquals(86, x >>>= (tmp = -293489896.5572462, tmp)); - assertEquals(172, x += (x%((((-2635082487.364155)|((-2361650420.634912)&(-2147095650.7451198)))<<((tmp = 2258905145.9231243, tmp)%((((tmp = -1365987098.5130103, tmp)*(((((((932437391)/x)/(289270413.0780891))%(x-x))+((((2194986374.917528)>>(((((tmp = -1553805025, tmp)|x)^(((x>>(-564400586.0780811))^(tmp = 1738428582.0238137, tmp))>>(tmp = 1717774140, tmp)))&(tmp = -2789427438, tmp))%(((tmp = -1386118057, tmp)*(-2333221237.7915535))*(x>>>(((((41346648.46438944)&x)%(-478973697.6792319))|(tmp = 2108106738, tmp))/x)))))-(tmp = -133437701.64136505, tmp))>>>x))+(tmp = -1567210003, tmp))*(x+((x&x)-(2942851671)))))>>>(tmp = -446377136, tmp))*((((((tmp = 1597203255, tmp)>>>(619157171))|(-2766246629.005985))>>((tmp = 3130227370, tmp)%x))*(tmp = 2072227901.6101904, tmp))|((tmp = 1369019520, tmp)^(759659487))))))>>>x))); - assertEquals(1996475731, x ^= ((1456327892.2281098)|(1728022827))); - assertEquals(0, x %= x); - assertEquals(0, x &= (1323847974)); - assertEquals(3076829073.8848357, x += (3076829073.8848357)); - assertEquals(9569842648396755000, x *= (3110293883.2782717)); - assertEquals(9569842646260304000, x -= (2136450372.9038036)); - assertEquals(9.158188827418242e+37, x *= x); - assertEquals(0, x <<= ((x&(tmp = -2241179286, tmp))+((tmp = 2553144081, tmp)&((tmp = -1914709694, tmp)^(tmp = -1469651409.0651562, tmp))))); - assertEquals(0, x <<= x); - assertEquals(0, x /= (2177840666.276347)); - assertEquals(0, x %= (-690827104)); - assertEquals(0, x >>>= x); - assertEquals(0, x ^= x); - assertEquals(-0, x /= (tmp = -803415280, tmp)); - assertEquals(-2355576914.316743, x += (-2355576914.316743)); - assertEquals(-833671722514674000, x *= ((3053388806.692315)-(tmp = 2699474775.081724, tmp))); - assertEquals(1, x /= x); - assertEquals(1898147684, x += ((tmp = 1898147683, tmp)|(x<<x))); - assertEquals(2.192324660388075, x %= ((tmp = 2630187518, tmp)/((2868794982.790862)|(490860748)))); - assertEquals(0, x >>>= ((2751021779)/(-952522559))); - assertEquals(321040461, x ^= ((321040461.153594)-x)); - assertEquals(-2.3814602031636922, x /= ((tmp = -170472190, tmp)|x)); - assertEquals(-1, x >>= (2200125174.177402)); - assertEquals(-2964432647.9379396, x += (-2964432646.9379396)); - assertEquals(-370116502.93793964, x %= (tmp = -518863229, tmp)); - assertEquals(777927355.2283959, x -= (-1148043858.1663356)); - assertEquals(0, x *= ((tmp = 1134913539, tmp)&(((x>>>((tmp = -989822787, tmp)>>>x))%x)&(tmp = 1078636160.7313156, tmp)))); - assertEquals(-1089245637, x ^= (3205721659.3548856)); - assertEquals(-1192493056, x <<= (-1173291054)); - assertEquals(78013832, x += ((tmp = 2462999944, tmp)+x)); - assertEquals(0, x %= x); - assertEquals(0, x >>>= (1794908927.7409873)); - assertEquals(1708338504, x += ((-2586628792.3484306)<<x)); - assertEquals(12, x >>= (-545794789.3827574)); - assertEquals(0, x &= ((2753207225)<<(((-1776581207.557251)+((tmp = -2414140402, tmp)*x))+(x<<(x|(tmp = 772358560.3022032, tmp)))))); - assertEquals(0, x <<= ((tmp = -2755724712.152605, tmp)/((x>>(-732875466))&x))); - assertEquals(NaN, x *= (((tmp = 2617815318.1134562, tmp)/x)%(x|((((((-851659337.194871)<<(tmp = 2072294700, tmp))%((x+(2193880878.5566335))^((tmp = 3005338026, tmp)-(2947963290))))/x)/(x+(2091745239.4210382)))-(x>>x))))); - assertEquals(NaN, x /= (tmp = -427684595.0278094, tmp)); - assertEquals(NaN, x /= (tmp = -263945678, tmp)); - assertEquals(0, x <<= x); - assertEquals(0, x <<= x); - assertEquals(0, x -= (((x>>((x&x)-(tmp = -673697315, tmp)))>>(((1575095242.2330558)/(x-(-1816886266)))%(-1580195729)))>>>x)); - assertEquals(0, x >>>= x); - assertEquals(0, x >>= (-2815518206)); - assertEquals(0, x -= (x/(1795634670.692437))); - assertEquals(-2753579891, x += (tmp = -2753579891, tmp)); - assertEquals(2.7773776150171776, x /= (tmp = -991431585, tmp)); - assertEquals(5.554755230034355, x += x); - assertEquals(3.362161997528237e-9, x /= (1652137890.4758453)); - assertEquals(3.362161997528237e-9, x %= (tmp = -10848734.527020693, tmp)); - assertEquals(1, x /= x); - assertEquals(-2978012493, x -= (x+(2978012493))); - assertEquals(-5.158905851797543, x /= (((x+((tmp = -2548840164, tmp)>>x))<<(x^((tmp = -533281232.7294345, tmp)&x)))&(tmp = -1502692171, tmp))); - assertEquals(-5.158905851797543, x %= (-3009435255.5612025)); - assertEquals(-20971520, x <<= ((tmp = -2728812464, tmp)%(2619809573.672677))); - assertEquals(-1900019712, x &= (2398099552)); - assertEquals(-1991377, x %= ((tmp = 1562364373.7334614, tmp)>>>(((x-(-946283217))<<(-2044590694))^(((tmp = 1681238509, tmp)>>(-2801649769))-x)))); - assertEquals(1, x /= x); - assertEquals(1, x %= (x/(x-x))); - assertEquals(1.3525631913093335e-9, x /= (739336991)); - assertEquals(0, x &= ((x&(x|(-1530424204)))<<((((tmp = -295143065.9115021, tmp)>>x)+x)<<x))); - assertEquals(0, x <<= (-1311017801)); - assertEquals(-0, x /= (-667133339.1918633)); - assertEquals(1038307283, x += (1038307283)); - assertEquals(506985, x >>>= ((tmp = 1550624472.9157984, tmp)^x)); - assertEquals(506985, x >>>= ((254646626)<<(tmp = 1572845412.744642, tmp))); - assertEquals(32447040, x <<= (tmp = -2427326042, tmp)); - assertEquals(0, x -= (x<<((x|x)>>>x))); - assertEquals(0, x &= x); - assertEquals(0, x &= ((-484420357)|((tmp = 807540590.6132902, tmp)/(x/x)))); - assertEquals(-890607324, x ^= ((tmp = -890607324, tmp)>>((((-2876826295)>>x)<<((tmp = 2351495148.117994, tmp)>>(tmp = 1368611893.274765, tmp)))*(tmp = 1531795251, tmp)))); - assertEquals(-729075363, x += (x+(tmp = 1052139285, tmp))); - assertEquals(531550884933581760, x *= x); - assertEquals(1980836332, x ^= ((-746269795.2320724)-((2400458512)>>((1290672548)>>>((((1536843439.5629003)&(3185059975.158061))*(tmp = -1339249276.2667086, tmp))&x))))); - assertEquals(941373096, x %= ((x+(-451098412))^(tmp = 1725497732, tmp))); - assertEquals(-1766019323, x += (tmp = -2707392419, tmp)); - assertEquals(2528947973, x >>>= (x^(-896237435.3809054))); - assertEquals(-263192576, x <<= (-866361580)); - assertEquals(-2008, x >>= (-2608071791)); - assertEquals(-88, x %= (((-1076807218.4792447)&((tmp = 601044863, tmp)>>((tmp = 1228976729, tmp)+((((-2711426325)*x)|x)|(x%(-2700007330.3266068))))))&(tmp = 3147972836.778858, tmp))); - assertEquals(1762886843, x ^= (tmp = 2532080403, tmp)); - assertEquals(1762886843, x %= ((((((tmp = -2059247788, tmp)>>x)/x)+(x<<x))^x)>>>(-1969283040.3683646))); - assertEquals(4812334726.587896, x += (tmp = 3049447883.587897, tmp)); - assertEquals(1, x /= x); - assertEquals(1, x *= x); - assertEquals(-2150507334, x -= ((tmp = 1578221999, tmp)+(tmp = 572285336, tmp))); - assertEquals(-4546475858941548500, x *= ((tmp = -931533139.5546813, tmp)^(tmp = 3061503275, tmp))); - assertEquals(-269064192, x |= ((207217276.91936445)<<(tmp = -957353678.4997551, tmp))); - assertEquals(1, x /= x); - assertEquals(1, x <<= (((1463856021.8616743)%(x*(tmp = -2286419102, tmp)))/(-2852887593))); - assertEquals(2223868564.8383617, x *= (tmp = 2223868564.8383617, tmp)); - assertEquals(918797189.9033995, x -= ((1305071374.9349623)%(x+(2211992629)))); - assertEquals(-2212004787.4668465, x -= (tmp = 3130801977.370246, tmp)); - assertEquals(31783, x >>= (2951958960)); - assertEquals(31783, x ^= ((((tmp = -2441511566, tmp)&((tmp = 91427553.90168321, tmp)+((tmp = 3001737720.327718, tmp)%x)))>>>(-2263859841))>>>((2109161329)>>(tmp = -2816295136.7443414, tmp)))); - assertEquals(4068224, x <<= (x%((tmp = -682576250.4464607, tmp)*(x/(((x-x)>>>(x&((((x<<(x<<x))>>>((((2243036981.528562)/(((-1839328916.9411087)>>(-1907748022.162144))<<(x+x)))+((tmp = 2362574171, tmp)<<(tmp = 1987834539, tmp)))|(-444329240)))|(399451601.1717081))>>x)))&(968363335.6089249)))))); - assertEquals(0.0030991932898194294, x /= ((tmp = 1067316540.5529796, tmp)^(-2388640366))); - assertEquals(0, x >>= x); - assertEquals(0, x >>>= (tmp = -393433349.1636851, tmp)); - assertEquals(0, x *= (((x^(((1806955787.471396)<<x)^((517668047.55566347)>>>(x%(x<<(tmp = -276586733.4844558, tmp))))))%(1661242196.1472542))|x)); - assertEquals(0, x |= (x>>x)); - assertEquals(-155236210, x |= (tmp = -155236210.19366312, tmp)); - assertEquals(-606392, x >>= ((tmp = -1533446042.97781, tmp)^x)); - assertEquals(-1, x >>= (936126810)); - assertEquals(2325115611, x -= (-2325115612)); - assertEquals(0, x -= x); - assertEquals(0, x >>= (tmp = -354826623, tmp)); - assertEquals(-0, x *= (-1232528947.7321298)); - assertEquals(0, x |= x); - assertEquals(0, x <<= (((tmp = 187758893.4254812, tmp)&(x-(tmp = 648201576, tmp)))&(385106597))); - assertEquals(0, x >>= (tmp = 2554891961, tmp)); - assertEquals(-1311492611.2970417, x += (-1311492611.2970417)); - assertEquals(-688179220.3221785, x += (623313390.9748632)); - assertEquals(1416835528, x &= (tmp = 1953739224, tmp)); - assertEquals(-11.04719252755072, x /= (-128252995)); - assertEquals(-6.287413042114223e-9, x /= (tmp = 1757033052.1558928, tmp)); - assertEquals(-4231171, x |= (((((2022730885.7773404)*((-2495777565.221855)|(tmp = 274627292, tmp)))<<(-3072596920.4902725))>>>((-2215057529)+(-1134713759.4247034)))^((tmp = -1888181788, tmp)/(572025985.2748461)))); - assertEquals(-4194305, x |= ((tmp = 167328318.038759, tmp)>>>(153800904.34551537))); - assertEquals(-1316525687, x -= (1312331382)); - assertEquals(1448723245.7863903, x += (2765248932.7863903)); - assertEquals(1.7219707102205526, x /= (tmp = 841317008, tmp)); - assertEquals(1872027792.5217001, x *= (x|(tmp = 1087142645.6665378, tmp))); - assertEquals(3504488055973669400, x *= x); - assertEquals(-1075254784, x |= x); - assertEquals(-5, x >>= (((844461331.8957539)-((x&x)<<((tmp = 1443904777, tmp)+(tmp = 736164505.3670597, tmp))))-(((tmp = 1348422110, tmp)>>((tmp = -2878252514, tmp)/(-1175443113)))|((-2138724317)%(2057081133))))); - assertEquals(-3.038875804165675e-9, x /= (1645345292.8698258)); - assertEquals(1.25204541454491e-18, x /= (-2427129055.274914)); - assertEquals(-1.7151576137235622e-9, x *= (-1369884505.6247284)); - assertEquals(1590804618, x ^= (1590804618.4910607)); - assertEquals(5061318665300252000, x *= (x+x)); - assertEquals(5061318665300252000, x %= ((tmp = 1102144242, tmp)*x)); - assertEquals(-7, x >>= (2772167516.624264)); - assertEquals(16383, x >>>= (-2979259214.5855684)); - assertEquals(47108415435, x *= ((2944456517.839616)>>>(1041288554.5330646))); - assertEquals(61, x >>>= (x^(((-1305163705)<<((948566605)-x))-x))); - assertEquals(0, x %= x); - assertEquals(0, x ^= (((tmp = 1918861879.3521824, tmp)/((x%(tmp = 945292773.7188392, tmp))%(x|x)))>>x)); - assertEquals(-0, x *= ((((x|((2810775287)|(tmp = 1265530406, tmp)))^((tmp = 3198912504.175658, tmp)-(((tmp = 1422607729.281712, tmp)<<(tmp = 2969836271.8682737, tmp))&x)))<<((tmp = 844656612, tmp)*(((((tmp = -828311659, tmp)%(((-2083870654)>>>(x^(((((933133782)-(tmp = 1033670745, tmp))-(629026895.4391923))%((-605095673.8097742)*((((-227510375.38460112)*x)+x)&(((((tmp = 472873752.68609154, tmp)^(tmp = 2815407038.712165, tmp))+((x>>>((tmp = -1331030665.3510115, tmp)>>>(2281234581)))-(x>>>x)))&(tmp = -2160840573.325921, tmp))&x))))<<(tmp = 1411888595, tmp))))|(((tmp = -915703839.0444739, tmp)/((x+(418836101.8158506))%(-1112605325.4404268)))&((-3098311830.6721926)-x))))-((49446671.477988124)*(-2522433127)))+((tmp = 443068797, tmp)>>(tmp = 418030554.97275746, tmp)))*((tmp = 38931296.738208175, tmp)+(1842742215.3282685)))))-((tmp = 1325672181.205841, tmp)^(tmp = 669284428, tmp)))); - assertEquals(-0, x *= (tmp = 93843030, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x ^= x); - assertEquals(0, x <<= x); - assertEquals(0, x >>>= (x%((((((tmp = -107458601, tmp)>>(x*((x|((tmp = 2117286494, tmp)>>((x^(tmp = 114214295.42048478, tmp))>>>(tmp = 1032826615, tmp))))&((x*x)&(-225386977.67686415)))))^((-780566702.5911419)+(-1113319771)))|(((x^x)<<(1288064444))>>(-2292704291.619477)))>>(365125945))-((tmp = -1986270727.235776, tmp)/x)))); - assertEquals(-0, x *= (((-18925517.67125845)|((((-1975220517)+(tmp = -1250070128.296064, tmp))+(1085931410.5895243))<<(((x|(((x*(tmp = 160207581.50536323, tmp))|(tmp = 1798744469.7958293, tmp))-x))>>>(((x+((x%x)&((((x^x)<<((tmp = 2538012074.623554, tmp)^x))*x)&x)))/(x+(tmp = -2563837407, tmp)))/(tmp = 2189564730, tmp)))/(((-1703793330.5770798)<<((176432492)|x))<<(1347017755.345185)))))<<(((tmp = -577100582.7258489, tmp)&x)/(-31246973)))); - assertEquals(0, x >>>= x); - assertEquals(NaN, x %= ((x*(tmp = 1167625971, tmp))&(((tmp = -770445060, tmp)>>((339248786)^((2058689781.2387645)-((-2381162024)*(660448066)))))&x))); - assertEquals(NaN, x += ((3088519732.515986)-(-267270786.06493092))); - assertEquals(0, x &= (tmp = 2748768426.3393354, tmp)); - assertEquals(-1109969306, x ^= ((-1109969306)>>>x)); - assertEquals(-1109969306, x %= (tmp = 1150376563.581773, tmp)); - assertEquals(-2058145178, x &= (-2057586057)); - assertEquals(-850185626, x |= ((x^(tmp = 1223093422, tmp))&((-589909669)<<(2299786170)))); - assertEquals(1489215443, x += (2339401069)); - assertEquals(-23592960, x <<= x); - assertEquals(2063937322, x ^= (-2053296342.2317986)); - assertEquals(12922122, x %= (x^((-2259987830)>>(x*(((tmp = -799867804.7716949, tmp)&(tmp = -1068744142, tmp))*(((((1091932754.8596292)-((tmp = -1778727010, tmp)>>(((tmp = 1207737073.2689717, tmp)-(x-(tmp = -1191958946, tmp)))+(-631801383.7488799))))-(-618332177))>>>(-156558558))>>>(3032101547.6262517))))))); - assertEquals(12922122, x &= x); - assertEquals(Infinity, x /= (x%x)); - assertEquals(0, x &= (x*(-227800722.62070823))); - assertEquals(-865648691, x ^= (-865648691)); - assertEquals(1, x /= (x%(tmp = 1524739353.8907173, tmp))); - assertEquals(16, x <<= (x<<(2335214658.789205))); - assertEquals(0, x &= ((tmp = 570332368.1239192, tmp)^(-2278439501))); - assertEquals(1881145344, x -= (((-569715735.8853142)+(2093355159))<<(tmp = 2788920949, tmp))); - assertEquals(0, x ^= x); - assertEquals(NaN, x -= ((tmp = -1427789954, tmp)%((((((411038329.49866784)-x)-(x<<((-1330832247)+x)))/x)^((x*(845763550.2134092))>>(tmp = 1427987604.5938706, tmp)))>>>(1857667535)))); - assertEquals(NaN, x /= (-313793473)); - assertEquals(0, x >>>= (x/x)); - assertEquals(1869358566, x -= (-1869358566)); - assertEquals(-1901664519209545200, x += ((tmp = 944729941.3936644, tmp)*(-2012918653))); - assertEquals(-1901664519209545200, x += ((tmp = 1348246793, tmp)/(x&x))); - assertEquals(-1576791552, x &= (tmp = 2719250966.739456, tmp)); - assertEquals(-305087899, x ^= (-2955630491.030272)); - assertEquals(0, x ^= (x%(1575252839.559443))); - assertEquals(4184604407, x += ((((tmp = -244720076.17657042, tmp)|(2819320515))^((((tmp = 1222623743.9184055, tmp)*(-95662379.577173))/(x/(x+(((x-(tmp = -3024718107.6310973, tmp))^(-1494390781))&(tmp = 2284054218.8323536, tmp)))))>>>(tmp = 2090069761, tmp)))>>>(x%x))); - assertEquals(3148907440, x -= (((tmp = -332379100.7695112, tmp)-(-1145399547))^(((((((tmp = 3133792677.785844, tmp)+x)<<(2306999139.5799255))>>((tmp = -2051266106, tmp)*(((((x+(((-728654312.8954825)>>(x>>>(((x%x)&(-1587152364))|(((((-2114138294)&x)&(1547554688))^x)-(-1856094268)))))*(((-1135018784)&((x+(tmp = -1444020289, tmp))|x))+x)))>>x)&x)/(2449005489))<<((131073798.64314616)%(x>>>((-2592101383.2205048)^(tmp = -757096673.0381112, tmp)))))))^(2766467316.8307915))-(-2465892914.515834))-((((tmp = 234064056, tmp)^((x>>>(1622627548.7944543))+(-1750474146)))|(-1959662039.4687617))^((-1222880974)&(-2794536175.906498)))))); - assertEquals(-1157627488, x &= (-1156639323)); - assertEquals(-1342170624, x <<= ((x/((((1829945345.0613894)/(x*((tmp = 1278865203.0854595, tmp)/(((tmp = -2298274086.519347, tmp)+(tmp = -545203761, tmp))-(tmp = 2712195820, tmp)))))>>>((tmp = 240870798.9384452, tmp)-(tmp = -3188865300.4768195, tmp)))>>>(x%((648799266)>>>(tmp = 24460403.864815235, tmp)))))|((tmp = 232533924, tmp)|x))); - assertEquals(-2684341248, x += x); - assertEquals(1073755136, x &= (((-662718514.9245079)>>(tmp = -1915462105, tmp))+(tmp = 1478850441.8689613, tmp))); - assertEquals(-1073755136, x /= (x|((tmp = -1767915185, tmp)|((325827419.1430224)|(((-1343423676)|(tmp = -1929549501, tmp))|(-866933068.9585254)))))); - assertEquals(-1073755136, x %= ((tmp = 547342356, tmp)-((tmp = 2213249646.7047653, tmp)-((((((-2463314705)^(tmp = -993331620, tmp))^(((x%x)>>(tmp = 1798026491.3658786, tmp))-(((1024072781)/(tmp = -2407354455, tmp))%(1973295010))))<<(-1966787233))^x)|(-1787730004))))); - assertEquals(-1073754452, x |= (tmp = 3099823788.077907, tmp)); - assertEquals(-1540683096, x &= (-1540674632.7013893)); - assertEquals(-1540683052, x ^= ((tmp = -126183090, tmp)>>>((-622437575.5788481)|((((tmp = -2947914022, tmp)%(((tmp = 2512586745, tmp)>>x)>>>((27238232.23677671)/(tmp = 3203958551, tmp))))/(tmp = 2906005721.402535, tmp))^((((tmp = 1763897860.737334, tmp)^(1445562340.2485332))/x)+(-2393501217.716533)))))); - assertEquals(-1258599433, x |= (tmp = 351291767.59661686, tmp)); - assertEquals(-1241560065, x |= (626346046.5083935)); - assertEquals(-1241560065, x ^= ((2263372092)/((tmp = -2868907862, tmp)>>>x))); - assertEquals(-893685228, x -= (tmp = -347874837, tmp)); - assertEquals(3401282068, x >>>= (x*x)); - assertEquals(0, x %= x); - assertEquals(0, x >>>= x); - assertEquals(-2079237393, x ^= (tmp = 2215729903, tmp)); - assertEquals(NaN, x %= ((((tmp = 3203450436, tmp)/(2867575150.6528325))&(1864945829))&((x&((((tmp = -1927086741.3438427, tmp)|x)|(-1783290909.3240588))*((-1074778499.0697656)*(x-((tmp = -848983542.8456669, tmp)^(tmp = -1324673961, tmp))))))>>(tmp = -2144580304.245896, tmp)))); - assertEquals(-43334009, x |= (x^(-43334009.72683525))); - assertEquals(-43334009, x &= x); - assertEquals(-43334009, x %= (tmp = 1252450645.060542, tmp)); - assertEquals(-43334009, x |= (((((((tmp = 968062202, tmp)/(x|(tmp = 2766801984, tmp)))*((2173353793.938968)>>(((tmp = -2459317247, tmp)<<(tmp = -2333601397, tmp))>>>((tmp = -578254251.8969193, tmp)*(tmp = 839964110.7893236, tmp)))))&(((1675305119)&(tmp = -929153707, tmp))*((x*x)*x)))/x)|(x/(tmp = 384740559.43867135, tmp)))%(1657362591))); - assertEquals(0, x -= x); - assertEquals(0, x %= (-1334758781.1087842)); - assertEquals(0, x -= x); - assertEquals(-54, x += ((tmp = -1787151355.470972, tmp)>>((tmp = 237028977, tmp)>>(((2829473542)<<(x>>>(((((((x-(-1950724753))*(((x>>>(2807353513.6283565))<<((-583810779.1155353)>>(x*x)))>>(-1068513265)))^(x^(-696263908.5131407)))%(((tmp = -1325619399, tmp)<<((tmp = -1030194450, tmp)-x))^x))+((-2852768585.3718724)>>(tmp = -3160022361, tmp)))%(x&x))>>(tmp = 2667222702.5454206, tmp))))+((804998368.8915854)<<x))))); - assertEquals(-54, x %= (-1601267268.4306633)); - assertEquals(1, x >>>= (tmp = -543199585.579128, tmp)); - assertEquals(4.732914708226396e-10, x /= (tmp = 2112862922, tmp)); - assertEquals(-4266932650, x -= ((((x^((((tmp = 2784618443, tmp)^(tmp = -2271260297.9010153, tmp))|((((tmp = -599752639.7516592, tmp)*(2751967680.3680997))^(tmp = -1478450055.578217, tmp))*x))-x))&((tmp = -520061982, tmp)-((tmp = 1400176711.9637299, tmp)^(((2100417541)|(x+(tmp = -674592897.0420957, tmp)))>>x))))^(tmp = -365650686.7947228, tmp))>>>((-2943521813)&(((tmp = -1888789582, tmp)>>(tmp = 700459655.488978, tmp))+(tmp = -1725725703.655931, tmp))))); - assertEquals(224277168, x <<= (tmp = 2885115011.8229475, tmp)); - assertEquals(224277168, x %= (tmp = -2655345206.442777, tmp)); - assertEquals(850395136, x <<= (x-(((((-769868538.1729524)/((tmp = -298603579, tmp)%(x^x)))+((2691475692)|(((x>>>(628995710.4745524))^(x<<(((tmp = -1046054749, tmp)|(919868171))-x)))^((-1377678789.8170452)&((3065147797)%(tmp = 2638804433, tmp))))))^(tmp = -2036295169, tmp))&(((tmp = -157844758.08476114, tmp)*(tmp = -2819601496, tmp))&((((tmp = 78921441, tmp)<<(653551762.5197772))/(1801316098))*(-1479268961.8276927)))))); - assertEquals(1645565728, x ^= (tmp = 1353013024, tmp)); - assertEquals(1645565728, x >>>= x); - assertEquals(3020513544, x += (1374947816)); - assertEquals(0, x %= x); - assertEquals(0, x %= ((((((tmp = -304228072.4115715, tmp)>>>((-90523260.45975709)-(tmp = -3013349171.084838, tmp)))%((-1640997281)*((tmp = -1600634553, tmp)%((tmp = 557387864, tmp)<<((888796080.766409)|(x^((((x%(((((tmp = 1164377954.1041703, tmp)*x)|(2742407432.192806))&((tmp = 1707928950, tmp)<<(1279554132.4481683)))+(tmp = -2108725405.7752397, tmp)))%(tmp = -465060827, tmp))^((tmp = 2422773793, tmp)+x))^((((((((tmp = -1755376249, tmp)^((-267446806)^x))/(((tmp = -1808578662.4939392, tmp)+((tmp = -1997100217, tmp)+x))+(((tmp = -2469853122.411479, tmp)/x)>>(tmp = 660624616.7956645, tmp))))%((x<<((((((tmp = -1701946558, tmp)-(tmp = 133302235, tmp))>>>x)/(738231394))<<(-1060468151.4959564))&(((((-1877380837.4678264)|(tmp = 2366186363, tmp))%x)>>>(-2382914822.1745577))>>((-1874291848.9775913)<<(tmp = 2522973186, tmp)))))<<(-2672141993)))|(tmp = 732379966, tmp))%x)^x)^x))))))))%(tmp = 2385998902.7287374, tmp))*x)+(tmp = -2195749866.017106, tmp))); - assertEquals(401488, x ^= (((-320896627)>>>(tmp = 2812780333.9572906, tmp))&(tmp = -2088849328, tmp))); - assertEquals(-1661116571.0046256, x += (tmp = -1661518059.0046256, tmp)); - assertEquals(-1616122720, x <<= x); - assertEquals(-1616122720, x >>= x); - assertEquals(-390439413, x %= (tmp = -1225683307, tmp)); - assertEquals(-84189205, x |= ((x|(2054757858))^(((x<<(((x|x)|(((x>>>((-2938303938.1397676)<<((2993545056)^((tmp = -643895708.5427527, tmp)/((1371449825.5345795)-(1896270238.695752))))))-(tmp = 1061837650, tmp))+(x+(tmp = 3072396681, tmp))))>>(x-((((tmp = -1877865355.1550744, tmp)&x)%(-2766344937))>>>(2055121782)))))-((x<<x)|(tmp = -2742351880.1974454, tmp)))<<((-2600270279.219802)>>(-1625612979))))); - assertEquals(-168378410, x += x); - assertEquals(-168378410, x &= x); - assertEquals(-1534983792, x &= (-1501412943)); - assertEquals(-1821543761, x ^= (938439487)); - assertEquals(-1821543761, x &= (x^(((tmp = -4237854, tmp)>>x)/x))); - assertEquals(2358, x >>>= (2954252724.620632)); - assertEquals(4716, x <<= ((-75522382.8757689)/((tmp = 1074334479, tmp)|((tmp = -720387522, tmp)>>(x>>>(-3085295162.6877327)))))); - assertEquals(-1313079316, x |= (2981887904.020387)); - assertEquals(-1957790646, x -= (644711330)); - assertEquals(17831, x >>>= ((tmp = -2550108342, tmp)-(((tmp = 454671414.0146706, tmp)+(-661129693.9333956))>>(x>>>(((tmp = 1752959432.3473055, tmp)*(-2619510342.1812334))%(tmp = -456773274.2411971, tmp)))))); - assertEquals(689287937.6879716, x -= ((tmp = -397126863.6879716, tmp)-(((x>>x)^(x/(-1387467129.6278908)))|((x>>((tmp = -2361114214.8413954, tmp)<<(tmp = -805670024.4717407, tmp)))<<(-2724018098))))); - assertEquals(1378575875.3759432, x += x); - assertEquals(84112428460187.8, x *= (((((2681425112.3513584)%(tmp = -1757945333, tmp))|x)>>(-1793353713.0003397))%x)); - assertEquals(-3221, x >>= (-1976874128)); - assertEquals(-3221, x %= (((tmp = 2318583056.834932, tmp)|((tmp = -1016115125, tmp)+((-472566636.32567954)+x)))|(tmp = 3135899138.065598, tmp))); - assertEquals(-6596608, x <<= x); - assertEquals(-1249902592, x <<= (((tmp = -2025951709.5051148, tmp)/((-465639441)<<(-2273423897.9682302)))*((tmp = -2408892408.0294642, tmp)-(tmp = 1017739741, tmp)))); - assertEquals(73802092170444800, x *= (tmp = -59046275, tmp)); - assertEquals(-1619001344, x <<= x); - assertEquals(0, x <<= (tmp = 1610670303, tmp)); - assertEquals(-0, x *= ((((x+(tmp = 2039867675, tmp))|(tmp = 399355061, tmp))<<(1552355369.313559))^x)); - assertEquals(0, x *= x); - assertEquals(0, x >>>= (((2875576018.0610805)>>x)%(tmp = -2600467554, tmp))); - assertEquals(2290405226.139538, x -= (-2290405226.139538)); - assertEquals(0, x %= x); - assertEquals(0, x ^= (((tmp = 2542309844.485515, tmp)-x)%((-2950029429.0027323)/(tmp = 2943628481, tmp)))); - assertEquals(0, x += x); - assertEquals(0, x -= x); - assertEquals(0, x >>>= (tmp = 2337330038, tmp)); - assertEquals(0, x += (x/(((292272669.0808271)&(tmp = 2923699026.224247, tmp))^(tmp = 367745855, tmp)))); - assertEquals(0, x &= x); - assertEquals(0, x %= ((tmp = 1565155613.3644123, tmp)<<(-308403859.5844681))); - assertEquals(-1845345399.3731332, x += (tmp = -1845345399.3731332, tmp)); - assertEquals(5158590659731951000, x *= (-2795460763.8680177)); - assertEquals(-364664, x >>= (1837745292.5701954)); - assertEquals(1, x /= x); - assertEquals(-860616114.8182092, x += ((tmp = 2076961323.1817908, tmp)+(-2937577439))); - assertEquals(-860616115, x ^= ((x*(tmp = 2841422442.583121, tmp))>>>((tmp = 1929082917.9039137, tmp)>>(-2602087246.7521305)))); - assertEquals(-38387843, x |= (3114677624)); - assertEquals(2927507837, x += (tmp = 2965895680, tmp)); - assertEquals(1, x /= x); - assertEquals(-1792887531, x *= (-1792887531)); - assertEquals(-0, x %= ((x^x)+x)); - assertEquals(-0, x %= (tmp = 2800752702.562547, tmp)); - assertEquals(1384510548, x ^= (tmp = 1384510548, tmp)); - assertEquals(42251, x >>= (1645421551.363844)); - assertEquals(0, x >>>= (17537561)); - assertEquals(-2076742862, x ^= (tmp = 2218224434, tmp)); - assertEquals(-2.790313825067623, x /= (744268563.3934636)); - assertEquals(5313538, x &= (((((tmp = -2406579239.0691676, tmp)+((-1470174628)+(((tmp = -783981599, tmp)<<(tmp = -1789801141.272646, tmp))^(((((((tmp = -844643189.5616491, tmp)&(tmp = -252337862, tmp))&(x|x))%((-3159642145.7728815)+(tmp = 2149920003.9525595, tmp)))&(x>>(1737589807.9431858)))-((((((((1610161800)<<(497024994))>>x)<<x)/x)>>>x)&x)-(757420763.2141517)))-(tmp = -3061016994.9596977, tmp)))))/(tmp = 1810041920.4089384, tmp))&(tmp = 5887654.786785364, tmp))&((tmp = 1626414403.2432103, tmp)+(x%x)))); - assertEquals(-2147483648, x <<= (tmp = 1304102366.8011155, tmp)); - assertEquals(-208418816, x %= (((((-2850404799)*(x+(3158771063.226051)))*(-2017465205))/(x>>x))>>(x%(tmp = 2760203322, tmp)))); - assertEquals(-2189223477, x -= (1980804661)); - assertEquals(-859239912, x ^= (tmp = 2974421971.3544703, tmp)); - assertEquals(-1599850415, x ^= (tmp = -2475871671.140151, tmp)); - assertEquals(-1600636847, x += ((((tmp = -1311002944, tmp)<<((tmp = -1137871342, tmp)<<(tmp = 115719116, tmp)))/(413107255.6242596))<<(x>>((((-1908022173)&(((-1519897333)^((x>>(x*(tmp = -2886087774.426503, tmp)))*(tmp = 530910975, tmp)))+(-2579617265.889692)))+((2518127437.127563)>>>((tmp = 481642471.56441486, tmp)>>>(792447239))))^(x<<(248857393.6819017)))))); - assertEquals(-191, x >>= (-1591265193)); - assertEquals(-192.27421813247196, x += ((tmp = 2627329028.207775, tmp)/(tmp = -2061914644.9523563, tmp))); - assertEquals(1230613220, x ^= (tmp = 3064354212.307105, tmp)); - assertEquals(1230613220, x &= x); - assertEquals(1230613220, x %= (1833479205.1064768)); - assertEquals(1230613220, x >>>= ((((1559450742.1425748)|((2151905260.956583)*(1213275165)))%(514723483.12764716))>>>x)); - assertEquals(1230613493, x |= ((((3004939197.578903)*(tmp = -576274956, tmp))+((tmp = 1037832416.2243971, tmp)^x))>>>(tmp = 2273969109.7735467, tmp))); - assertEquals(2461226986, x += x); - assertEquals(-27981, x >>= ((692831755.8048055)^((tmp = -1593598757, tmp)%(x-((((-1470536513.882593)|((tmp = -2716394020.466401, tmp)|(tmp = 2399097686, tmp)))&x)%x))))); - assertEquals(-1.4660454948034359e+23, x *= (((x>>>((((((tmp = -3056016696, tmp)<<(-2882888332))*(2041143608.321916))&(((tmp = -634710040, tmp)|(tmp = -2559412457, tmp))>>(1916553549.7552106)))%((-2150969350.3643866)*x))<<((x*(tmp = 2657960438.247278, tmp))|x)))%((tmp = 526041379, tmp)*(tmp = 2514771352.4509397, tmp)))*(1219908294.8107886))); - assertEquals(-1.4660454948034359e+23, x -= ((1709004428)>>(((x|(-422745730.626189))%x)>>x))); - assertEquals(-2247766068, x %= (-3105435508)); - assertEquals(-386845856.0649812, x -= (-1860920211.9350188)); - assertEquals(-386846803.0649812, x -= ((((-3214465921)|((tmp = -1326329034, tmp)+(((tmp = -1203188938.9833462, tmp)%((((((-1318276502)+(x+x))^((x<<x)%(x>>>x)))+(tmp = -439689881, tmp))+((-1455448168.695214)^(x-((-388589993)>>((((940252202)^(-2218777278))|x)/(tmp = -1007511556, tmp))))))&(-140407706.28176737)))-(x/((888903270.7746506)-((tmp = -2885938478.632409, tmp)<<(((((tmp = -1750518830.270917, tmp)>>(((((((tmp = 868557365.7908674, tmp)/(tmp = -2805687195.5172157, tmp))*x)|((((((-1342484550)-((tmp = 1089284576, tmp)^(tmp = 120651272, tmp)))<<(tmp = 2230578669.4642825, tmp))-(x*x))%(x^(((tmp = -3177941534, tmp)+(x>>(-1595660968)))/(-1738933247))))>>>(tmp = 2860175623, tmp)))-(((2392690115.8475947)>>>(tmp = -1754609670.2068992, tmp))>>>(tmp = 2615573062, tmp)))-(tmp = 2590387730, tmp))^((x+((((x-(tmp = -2823664112.4548965, tmp))*(200070977))>>>(((x|((((tmp = 1361398, tmp)>>((tmp = 1649209268, tmp)%x))+x)+(x>>>(tmp = -2379989262.1245675, tmp))))|(x^((tmp = -647953298.7526417, tmp)-x)))&(tmp = -1881232501.1945808, tmp)))>>>x))%(x^(tmp = -1737853471.005935, tmp)))))>>>(427363558))>>>((tmp = -3076726422.0846386, tmp)^(-1518782569.1853383)))/x)))))))|x)>>>(1854299126))); - assertEquals(-386846803.0649812, x -= (x%x)); - assertEquals(238532, x >>>= (-448890706.10774803)); - assertEquals(232, x >>>= (-791593878)); - assertEquals(232, x <<= (((x^((x-x)&(tmp = 1219114201, tmp)))/(tmp = -427332955, tmp))%(tmp = 1076283154, tmp))); - assertEquals(210, x ^= (x>>>((2975097430)>>>x))); - assertEquals(1, x /= x); - assertEquals(2317899531, x *= (2317899531)); - assertEquals(1131786, x >>>= x); - assertEquals(2301667519.6379366, x += ((tmp = 193109669.63793683, tmp)+(tmp = 2107426064, tmp))); - assertEquals(3842614963.6379366, x += (((-1676516834)>>>(tmp = -1817478916.5658965, tmp))^(((tmp = 1122659711, tmp)>>>(tmp = -2190796437, tmp))|(tmp = -2754023244, tmp)))); - assertEquals(-452352333, x &= x); - assertEquals(-863, x >>= x); - assertEquals(-3.777863669459606e-7, x /= (2284359827.424491)); - assertEquals(-3.777863669459606e-7, x %= ((tmp = -2509759238, tmp)>>>x)); - assertEquals(0, x <<= (-814314066.6614306)); - assertEquals(0, x %= (tmp = 190720260, tmp)); - assertEquals(2301702913, x += (2301702913)); - assertEquals(-249158048, x >>= (tmp = -2392013853.302008, tmp)); - assertEquals(-249158048, x >>= x); - assertEquals(-498316096, x += x); - assertEquals(-498316096, x %= (tmp = 2981330372.914731, tmp)); - assertEquals(106616.2199211318, x *= (((((tmp = 1020104482.2766557, tmp)^((tmp = -416114189.96786, tmp)>>>(1844055704)))|(tmp = 1665418123, tmp))>>(1826111980.6564898))/(-2446724367))); - assertEquals(106616, x |= x); - assertEquals(1094927345, x -= (((-1229759420)|(741260479.7854375))-x)); - assertEquals(8353, x >>= x); - assertEquals(0, x >>>= (tmp = -327942828, tmp)); - assertEquals(-953397616.8888416, x += (tmp = -953397616.8888416, tmp)); - assertEquals(-1906641240.7776833, x += (x+((-3033450184.9106326)>>>(tmp = 2090901325.5617187, tmp)))); - assertEquals(-1906641240.7776833, x %= (tmp = 2584965124.3953505, tmp)); - assertEquals(-1098907671, x |= (tmp = -1272590495, tmp)); - assertEquals(-1.8305258600334393, x /= (600323489)); - assertEquals(-1, x &= x); - assertEquals(-1, x |= ((x+x)-x)); - assertEquals(1, x *= x); - assertEquals(867473898, x ^= (tmp = 867473899.0274491, tmp)); - assertEquals(6, x >>>= (tmp = 1174763611.341228, tmp)); - assertEquals(0, x >>= ((689882795)^(2250084531))); - assertEquals(0, x /= (tmp = 2545625607, tmp)); - assertEquals(0, x >>= x); - assertEquals(0, x += x); - assertEquals(0, x -= (x*(-1098372339.5157008))); - assertEquals(NaN, x %= x); - assertEquals(NaN, x -= (tmp = -1797344676.375759, tmp)); - assertEquals(1121476698, x |= (tmp = 1121476698, tmp)); - assertEquals(1, x /= x); - assertEquals(1, x &= (-191233693)); - assertEquals(330137888.92595553, x += (330137887.92595553)); - assertEquals(-1792236714, x ^= (tmp = 2256609910, tmp)); - assertEquals(269000724, x &= (316405813.62093115)); - assertEquals(256, x >>= x); - assertEquals(256, x %= ((2556320341.54669)|(1066176021.2344948))); - assertEquals(256, x |= x); - assertEquals(131072, x <<= ((-1650561175.8467631)|x)); - assertEquals(-286761951, x -= ((tmp = 287024095, tmp)-((-2293511421)&(x|x)))); - assertEquals(-1561852927, x &= (3002663949.0989227)); - assertEquals(-460778761, x %= (tmp = -550537083, tmp)); - assertEquals(-3023749308.0492287, x += (tmp = -2562970547.0492287, tmp)); - assertEquals(-481313332.04922867, x %= ((x|((tmp = -855929299, tmp)%((2181641323)%(x|(220607471.33018696)))))&x)); - assertEquals(17510668, x &= (tmp = 363557663, tmp)); - assertEquals(12552, x &= (3020225307)); - assertEquals(1814655896, x |= ((x<<(((-1475967464)*(-3122830185))*x))+(x^(-2480340864.2661023)))); - assertEquals(-3209124403525266400, x -= ((1146847590)*(tmp = 2798213497, tmp))); - assertEquals(-6418248807050533000, x += x); - assertEquals(1.1856589432073933e+28, x *= (-1847324681.313275)); - assertEquals(-1238853292, x ^= (-1238853292)); - assertEquals(-77428331, x >>= (x&((((2043976651.8514216)>>>x)^(x>>>(((tmp = -1785122464.9720652, tmp)%x)<<(1570073474.271266))))*x))); - assertEquals(2011, x >>>= x); - assertEquals(2011, x &= x); - assertEquals(0, x >>= (-2682377538)); - assertEquals(-1.1367252770299785, x -= (((tmp = 2704334195.566802, tmp)/(2379056972))%((((-1764065164)*((((468315142.8822602)>>((x%(((tmp = 2537190513.506641, tmp)+((x&(x|((tmp = -947458639, tmp)^(2653736677.417406))))*((x<<((1243371170.1759553)>>>(((tmp = 1572208816, tmp)<<((tmp = 963855806.1090456, tmp)>>>x))%((-3078281718.7743487)*x))))^(-1154518374))))^(-2839738226.6314087)))^((-2865141241.190915)*(-2400659423.8207664))))>>((tmp = 32940590, tmp)/(tmp = 2917024064.570817, tmp)))+(((27601850)/(tmp = 3168834986, tmp))>>x)))+(tmp = 2528181032.600125, tmp))/(3162473952)))); - assertEquals(-1697395408.7948515, x -= (1697395407.6581264)); - assertEquals(1536992607912062500, x *= (tmp = -905500627.5781817, tmp)); - assertEquals(102759872, x >>= (tmp = -707887133.4484048, tmp)); - assertEquals(102759872, x %= (tmp = -1764067619.7913327, tmp)); - assertEquals(12543, x >>>= (-144142995.1469829)); - assertEquals(-2059555229.2592103, x += ((-2059555229.2592103)-x)); - assertEquals(-537022593, x |= (tmp = -2770761410.407701, tmp)); - assertEquals(23777505, x ^= (-560496738.6854918)); - assertEquals(-64329014115772310, x *= ((tmp = -2729234369.198843, tmp)+x)); - assertEquals(189083830, x ^= (tmp = 933619934, tmp)); - assertEquals(189083830, x %= ((tmp = -2918083254, tmp)-(x|(x^(-2481479224.0329475))))); - assertEquals(378167660, x += x); - assertEquals(-0.45833387791900504, x /= ((tmp = 2727991875.241294, tmp)<<(tmp = 2570034571.9084663, tmp))); - assertEquals(0, x <<= x); - assertEquals(-0, x /= (tmp = -67528553.30662966, tmp)); - assertEquals(0, x <<= (938440044.3983492)); - assertEquals(-945479171, x ^= (tmp = -945479171, tmp)); - assertEquals(-225632619284361200, x *= (238643670.00884593)); - assertEquals(-0, x %= x); - assertEquals(-585826304, x ^= ((-1256265560)<<(tmp = 1144713549, tmp))); - assertEquals(-671583855, x ^= (183333265.1468178)); - assertEquals(-484311040, x <<= x); - assertEquals(-3969762.62295082, x /= ((((tmp = -1164308668.931008, tmp)-x)%x)>>>(((397816647)>>(-1605343671.4070785))<<x))); - assertEquals(758097879, x ^= ((tmp = -2871307491, tmp)^(-2043176492.646442))); - assertEquals(0, x *= ((x>>(tmp = 1983292927, tmp))&(tmp = -860505131.4484091, tmp))); - assertEquals(0, x <<= x); - assertEquals(0, x &= x); - assertEquals(0, x %= ((3132981707)-(-2832016477))); - assertEquals(0, x >>= (x<<((1830195133.0342631)>>>(tmp = -1003969250, tmp)))); - assertEquals(NaN, x %= x); - assertEquals(NaN, x += (tmp = 273271019.87603223, tmp)); - assertEquals(NaN, x += (625749326.1155348)); - assertEquals(0, x >>= (tmp = -531039433.3702333, tmp)); - assertEquals(0, x -= (((tmp = 2029464099, tmp)-(x-(tmp = -329058111.411458, tmp)))*(x<<x))); - assertEquals(-0, x *= ((-1112957170.5613296)|((tmp = 847344494, tmp)>>>(tmp = 2735119927, tmp)))); - assertEquals(-0, x /= (tmp = 544636506, tmp)); - assertEquals(0, x >>>= (x^(545093699))); - assertEquals(0, x %= (((tmp = -2208409647.5052004, tmp)+(3083455385.374988))+(((-482178732.7077277)*x)>>>((2661060565)*(-2125201239))))); - assertEquals(0, x >>>= (-212334007.34016395)); - assertEquals(0.7004300865203454, x -= ((2032883941)/(-2902336693.0154715))); - assertEquals(0, x <<= (x<<((265868133.50175047)>>>(1162631094)))); - assertEquals(604920272.4394834, x -= (-604920272.4394834)); - assertEquals(604920272, x &= x); - assertEquals(0, x <<= (((-1961880051.1127694)%(tmp = 1715021796, tmp))|((tmp = 2474759639.4587016, tmp)|(243416152.55635)))); - assertEquals(-46419074, x |= (((tmp = -518945938.5238774, tmp)%((x+(tmp = 242636408, tmp))+(-1974062910)))|(1546269242.0259726))); - assertEquals(-46419074, x += ((-629802130)*((tmp = -658144149, tmp)%((-905005358.5370393)>>>x)))); - assertEquals(-46419074, x |= (x%(-1103652494))); - assertEquals(7892881050983985, x *= (-170035297.36469936)); - assertEquals(1105701997.4273424, x %= ((((-490612260.0023911)>>>(tmp = 1803426906, tmp))^(x%(2725270344.2568116)))-(1010563167.8934317))); - assertEquals(1088619532, x &= (-2232199650)); - assertEquals(1073807364, x &= (-888024506.5008001)); - assertEquals(1153062254980628500, x *= x); - assertEquals(1153062255703627000, x -= (tmp = -722998613.897227, tmp)); - assertEquals(-1141418584, x |= (3017232552.4814596)); - assertEquals(-373464140, x ^= (-2914372068)); - assertEquals(994050048, x <<= x); - assertEquals(0, x ^= x); - assertEquals(0, x &= (tmp = -3166402389, tmp)); - assertEquals(0, x &= ((-1760842506.337213)|(tmp = 2538748127.795164, tmp))); - assertEquals(-0, x /= (-2635127769.808626)); - assertEquals(0, x &= ((((tmp = 1414701581, tmp)^(((2425608769)/((x<<x)^(x-x)))^((tmp = -2641946468.737288, tmp)|(tmp = -313564549.1754241, tmp))))*(tmp = -2126027460, tmp))|(-2255015479))); - assertEquals(225482894, x ^= (225482894.8767246)); - assertEquals(0, x ^= x); - assertEquals(306216231, x += (tmp = 306216231, tmp)); - assertEquals(306216231, x -= ((-465875275.19848967)&((-806775661.4260025)/((((-184966089.49763203)>>>((x>>x)+((tmp = -1951107532, tmp)|x)))%x)*((2704859526.4047284)%((x*x)>>x)))))); - assertEquals(30754, x &= (1706162402.033193)); - assertEquals(30454.010307602264, x -= (((590456519)>>>(tmp = 2713582726.8181214, tmp))/x)); - assertEquals(8419062, x |= ((2848886788)<<(tmp = 2993383029.402275, tmp))); - assertEquals(16, x >>= (tmp = -1651287021, tmp)); - assertEquals(1, x /= x); - assertEquals(-1407643485, x ^= (-1407643486)); - assertEquals(2, x >>>= (-1126004674)); - assertEquals(470812081, x ^= ((-2411718964)>>>x)); - assertEquals(550443688.6407901, x += (tmp = 79631607.6407901, tmp)); - assertEquals(3669092443.64079, x -= (-3118648755)); - assertEquals(-625874853, x <<= (((tmp = -1640437346, tmp)/(((x*x)>>>x)<<x))/x)); - assertEquals(-1431439050363516700, x *= (2287101077)); - assertEquals(-1921660672, x |= ((((((((-1912249689.9978154)&(-1676922742.5343294))*(2625527768))<<((820676465)^(((x+(tmp = -852743692, tmp))&((x-((((1361714551)/(311531668))>>>(tmp = -1330495518.8175917, tmp))<<(((tmp = 1369938417.8760853, tmp)*(-1217947853.8942266))<<(-2048029668))))-(-513455284)))>>>(tmp = 1980267333.6201067, tmp))))<<(((1503464217.2901971)>>(tmp = 2258265389, tmp))>>>(1868451148)))&(x-(x^(tmp = -1565209787, tmp))))*x)<<(tmp = -2426550685, tmp))); - assertEquals(-1921660672, x %= (((tmp = 523950472.3315773, tmp)+(((2971865706)^x)-x))&(-1773969177))); - assertEquals(420176973.1169958, x += (2341837645.116996)); - assertEquals(420176973, x >>>= (((tmp = -2485489141, tmp)<<((tmp = -2520928568.360244, tmp)+x))&(543950045.0932506))); - assertEquals(50, x ^= (x|((tmp = 2001660699.5898843, tmp)>>>(tmp = 1209151128, tmp)))); - assertEquals(138212770720.96973, x *= (2764255414.4193945)); - assertEquals(-28683, x |= (((-535647551)|x)>>((((2065261509)>>(-354214733))*x)+(-3218217378.2592907)))); - assertEquals(1627048838, x ^= (tmp = -1627044749, tmp)); - assertEquals(-839408795, x ^= (2903337187.480303)); - assertEquals(-1000652427, x += (tmp = -161243632, tmp)); - assertEquals(740237908.4196916, x += ((tmp = 1587000348, tmp)+(tmp = 153889987.41969144, tmp))); - assertEquals(Infinity, x /= (((((-615607376.1012697)&(57343184.023578644))+((-1967741575)|(-3082318496)))<<(((tmp = -958212971.99792, tmp)>>(tmp = 2962656321.3519197, tmp))-(x|(x*(969365195)))))<<(tmp = -1739470562.344624, tmp))); - assertEquals(-Infinity, x /= ((tmp = -1736849852, tmp)%x)); - assertEquals(0, x <<= x); - assertEquals(0, x %= (tmp = -226505646, tmp)); - assertEquals(1982856549, x -= (((x+(-1982856549))%(-2274946222))>>(x%(((tmp = -1289577208.9097936, tmp)>>x)^(778147661))))); - assertEquals(1648018703, x ^= ((3085618856)+((tmp = 1546283467, tmp)&(((x|((-2376306530)*(((((((tmp = -2807616416, tmp)%(((((tmp = 347097983.1491085, tmp)<<x)|(((((1135380667)/(x>>>(tmp = 1679395106, tmp)))^((1277761947)<<((tmp = -1614841203.5244312, tmp)>>x)))%((tmp = 1552249234.2065845, tmp)>>>x))>>>(tmp = -1677859287, tmp)))>>>(2605907565))/(tmp = 2291657422.221277, tmp)))%(((tmp = 425501732.6666014, tmp)>>>(1327403879.455553))+x))>>((tmp = -3075752653.2474413, tmp)&(x-(tmp = -71834630, tmp))))|((((2532199449.6500597)*(-842197612.4577162))%x)>>x))*(((1220047194.5100307)<<((tmp = 1642962251, tmp)<<((-662340)>>>((tmp = -1672316631.3251066, tmp)<<((tmp = 1762690952.542441, tmp)-(x/(1904755683.3277364)))))))>>x))|(((((tmp = 1625817700.7052522, tmp)%(tmp = -2990984460, tmp))|(2395645662))-((2619930607.550086)>>x))^(tmp = 130618712, tmp)))))&((-3142462204.4628367)/(1078126534.8819227)))%(((tmp = -256343715.2267704, tmp)+x)^(tmp = 2009243755, tmp)))))); - assertEquals(1937698223, x |= (((tmp = 866354374.7435778, tmp)+(tmp = 2751925259.3264275, tmp))%(-2252220455))); - assertEquals(0, x -= x); - assertEquals(-823946290.6515498, x -= (tmp = 823946290.6515498, tmp)); - assertEquals(706970324, x ^= (-457174758)); - assertEquals(32916, x &= (25740724)); - assertEquals(0, x >>>= ((-1658933418.6445677)|(tmp = -846929510.4794133, tmp))); - assertEquals(0, x ^= ((-834208600)/((-1256752740)&(tmp = 1973248337.8973258, tmp)))); - assertEquals(-1639195806, x += (-1639195806)); - assertEquals(-1559416478, x ^= ((tmp = 1349893449.0193534, tmp)*(tmp = 2044785568.1713037, tmp))); - assertEquals(0, x &= ((x>>(tmp = 1720833612, tmp))/((x+(-1305879952.5854573))^x))); - assertEquals(-0, x *= (tmp = -1713182743, tmp)); - assertEquals(0, x >>= x); - assertEquals(NaN, x /= (((x%((x>>>(((-1515761763.5499895)^(-3076528507.626539))<<(tmp = 1293944457.8983147, tmp)))<<(tmp = 276867491.8483894, tmp)))>>(tmp = -2831726496.6887417, tmp))%((((tmp = 1780632637.3666987, tmp)^x)%((208921173.18897665)>>(tmp = 633138136, tmp)))+x))); - assertEquals(0, x >>= (tmp = -2755513767.0561147, tmp)); - assertEquals(0, x |= x); - assertEquals(840992300.0324914, x -= ((-840992300.0324914)+x)); - assertEquals(840992300, x &= x); - assertEquals(-1094140277, x ^= (2364029095)); - assertEquals(-Infinity, x /= ((((((1257084956)<<(2009241695))>>(x+x))*x)>>>x)>>>(205318919.85870552))); - assertEquals(-Infinity, x -= (((x>>>(tmp = 3037168809.20163, tmp))&x)*(x&(((806151109)*x)-(tmp = -1741679480.58333, tmp))))); - assertEquals(400659949, x ^= (tmp = 400659949, tmp)); - assertEquals(5, x >>= (tmp = 1175519290, tmp)); - assertEquals(5, x |= x); - assertEquals(0, x >>= x); - assertEquals(0, x >>= ((1317772443)&(x<<x))); - assertEquals(-1123981819, x ^= (tmp = 3170985477, tmp)); - assertEquals(1123864651, x ^= ((x%(((x&x)&(-2606227299.7590737))<<((tmp = -2018123078.1859496, tmp)*x)))|(x+(((((1935939774.8139446)/((-1303958190)/(2802816697.32639)))<<((2880056582)*x))+x)+x)))); - assertEquals(1543368927, x |= (-2795691884)); - assertEquals(NaN, x /= (x%((tmp = -1129915114, tmp)<<x))); - assertEquals(NaN, x += (tmp = -3045743135, tmp)); - assertEquals(NaN, x -= (tmp = -2849555731.8207827, tmp)); - assertEquals(NaN, x /= (((((2127485827)>>>((((tmp = 363239924, tmp)>>x)|((((tmp = -1419142286.0523334, tmp)-(x<<x))^(tmp = -1990365089.8283136, tmp))*((tmp = 2780242444.0739098, tmp)>>>(((-2336511023.342298)&x)/(tmp = 2296926221.402897, tmp)))))>>((tmp = 1378982475.6839466, tmp)>>(tmp = -816522530, tmp))))&(x^(tmp = -1668642255.0586753, tmp)))%(((tmp = 921249300.1500335, tmp)^x)*(tmp = -2228816905, tmp)))>>x)); - assertEquals(-1460685191, x |= (tmp = 2834282105, tmp)); - assertEquals(-1463439264, x &= (tmp = 2881860064.146755, tmp)); - assertEquals(20.98100714963762, x /= (((3017150580.7875347)^((250499372.5339837)<<(tmp = -42767556.30788112, tmp)))|(x%(-2829281526)))); - assertEquals(1, x /= x); - assertEquals(2, x += x); - assertEquals(8, x <<= x); - assertEquals(0, x >>>= ((730174750)>>>x)); - assertEquals(0, x ^= x); - assertEquals(-1459637373, x ^= (2835329923.456409)); - assertEquals(-1233115861, x ^= (511678120)); - assertEquals(95682857, x >>>= ((tmp = 1534570885, tmp)|(tmp = -414425499.3786578, tmp))); - assertEquals(70254633, x &= (-1502067585)); - assertEquals(51384749748909710, x *= (tmp = 731407276, tmp)); - assertEquals(9390482.873469353, x %= (tmp = -592576964.7982686, tmp)); - assertEquals(4695241, x >>>= (tmp = -1879898431.5395758, tmp)); - assertEquals(-3129811912538149000, x += (((-727481809)^((3106908604)%x))*((((tmp = -1218123690, tmp)^(x>>((-942923806)^x)))/(x+x))>>>(-1508881888.969373)))); - assertEquals(1596870236, x ^= (-1135673764.9721224)); - assertEquals(0, x ^= x); - assertEquals(2133782410, x |= (((-2202469371)>>((tmp = 1327588406.183342, tmp)/(tmp = 253581265.7246865, tmp)))-((tmp = 2226575446.838795, tmp)^x))); - assertEquals(-81895217.83608055, x -= (tmp = 2215677627.8360806, tmp)); - assertEquals(812089344, x <<= ((tmp = 882824005, tmp)/(((x>>((((((((tmp = 1211145185, tmp)/((-137817273)-(((tmp = 2165480503.1144185, tmp)-(-1840859887.1288517))*((155886014.8393339)>>((-1984526598)<<(tmp = 1331249058.3246582, tmp))))))>>(x*x))%(2830324652))%(933701061))|(1346496215))^(tmp = -988800810, tmp))+x))>>>x)<<(-2372088384)))); - assertEquals(812089344, x <<= x); - assertEquals(8472, x %= ((((x|(((x%(tmp = 2772099481.664402, tmp))+(2894690616))-x))&(x&(((-715790638.6454093)>>(tmp = -1447931029, tmp))-(tmp = 1761027889, tmp))))^x)%(((tmp = 830969811, tmp)|x)|((-1102267929)-(3193018687))))); - assertEquals(-0.0000028559857417864914, x /= (-2966401364)); - assertEquals(0, x >>= x); - assertEquals(-701800392, x += (tmp = -701800392, tmp)); - assertEquals(2034756873, x -= (tmp = -2736557265, tmp)); - assertEquals(-0.9475075048394501, x /= (((((82879340.27231383)+((tmp = -2876678920.653639, tmp)*(-2801097850)))<<x)>>>((x<<(((((x|x)&(tmp = -1572694766, tmp))>>(x+(x/((x-(((tmp = 1435301275, tmp)|(tmp = 983577854.212041, tmp))>>(tmp = 632633852.1644179, tmp)))+x))))>>>x)|(-850932021)))>>x))<<(-821983991))); - assertEquals(0, x >>= (x>>(2424003553.0883207))); - assertEquals(2599386349, x -= (-2599386349)); - assertEquals(-68157441, x |= (((tmp = -1170343454.9327996, tmp)+((((tmp = 448468098, tmp)|(x>>(x>>(((x>>(((x/(x&(x<<x)))<<(2436876051.2588806))^(3010167261)))%((tmp = 2577616315.7538686, tmp)>>>(-2953152591.015912)))%((tmp = -1304628613, tmp)/(x&((x|((-2000952119)%((691146914)/((tmp = 1480966978.7766845, tmp)<<((tmp = 2644449477.392441, tmp)|(-2143869305.871568))))))+(tmp = -315254308, tmp))))))))&(-2060205555))|((-604140518.8186448)^(x*x))))%(x*((tmp = 1383244000.2807684, tmp)/(3195793656))))); - assertEquals(-68157441, x |= x); - assertEquals(-1, x >>= x); - assertEquals(-2147483648, x <<= x); - assertEquals(-1.5257198286933313, x /= (tmp = 1407521622, tmp)); - assertEquals(1149084989.47428, x += (((tmp = 1149084991.9004865, tmp)&x)^((((((2797053000)/(x^x))*(-2829253694))>>>((tmp = -610924351, tmp)>>x))>>>(tmp = -675681012, tmp))<<(2812852729)))); - assertEquals(0, x %= x); - assertEquals(0, x <<= ((tmp = -584069073, tmp)*(-2953140326))); - assertEquals(0, x <<= (tmp = -481515023.6404002, tmp)); - assertEquals(-1441535370, x ^= (2853431926)); - assertEquals(2853431926, x >>>= (((((((tmp = 2215663525.9620194, tmp)%((-1102832735.9274108)/x))>>x)&(3220898702.76322))&(((2077584946)*((x>>x)<<((tmp = 1845701049, tmp)-x)))/(tmp = 1947184202.5737212, tmp)))|(((tmp = 2976351488, tmp)^(-42517339))%((2648230244.410125)^(1520051731.31089))))/(1761635964))); - assertEquals(43539, x >>>= (tmp = 1361671184.7432632, tmp)); - assertEquals(21769, x >>= ((tmp = -804932298.9572575, tmp)>>((((tmp = 1749006993.253409, tmp)+(276536978))^x)|(2698166994)))); - assertEquals(1103025563, x |= (tmp = 1103007891, tmp)); - assertEquals(1327594607, x += (tmp = 224569044, tmp)); - assertEquals(1327594607, x |= x); - assertEquals(-478674944, x <<= (((672378508)&x)^(((-2070209708.6470091)|x)|(x>>>x)))); - assertEquals(-478674943, x ^= ((-1832457698.6345716)>>>((tmp = -3077714019, tmp)/(1809383028)))); - assertEquals(229129701056053250, x *= x); - assertEquals(1, x /= x); - assertEquals(2, x <<= (-1522529727)); - assertEquals(2, x &= x); - assertEquals(-2016989182, x |= ((((tmp = -1267845511, tmp)*(1225350332))+((tmp = -1397690831.5717893, tmp)>>>(tmp = -2575382994, tmp)))+x)); - assertEquals(-241, x >>= (tmp = 931869591, tmp)); - assertEquals(-1048087547, x &= (tmp = -1048087403.1163051, tmp)); - assertEquals(-4004486369.844599, x += (tmp = -2956398822.844599, tmp)); - assertEquals(-4004486368.844599, x -= (((2701878498)>>x)|(x|(-1079354967)))); - assertEquals(1, x >>= (tmp = -1583689092, tmp)); - assertEquals(1, x *= (x>>(x%x))); - assertEquals(0, x %= x); - assertEquals(-0, x *= (-120818969)); - assertEquals(0, x >>= ((tmp = 1794099660, tmp)/(((x&(((-321906091)^(tmp = -3009885933.8449526, tmp))&((tmp = -140917780, tmp)|(2037803173.4075825))))&x)&(tmp = -745357154, tmp)))); - assertEquals(0, x <<= (563984257.3493614)); - assertEquals(NaN, x %= ((((x>>(tmp = -2190891392.320677, tmp))-x)<<(462714956))<<((tmp = -84413570, tmp)|((x|(-2787022855))-((tmp = 2028532622, tmp)|(tmp = 1103757073.9178817, tmp)))))); - assertEquals(NaN, x *= ((2137674085.3142445)|((tmp = -1054749859.2353804, tmp)%x))); - assertEquals(NaN, x /= (x>>>(((((tmp = 597103360.9069608, tmp)>>>(-2850217714.1866236))-((tmp = 1125150527, tmp)*x))%(tmp = -982662312, tmp))|((x/(((968656808.6069037)*(((128484784.15362918)>>x)^x))&((((x/((((tmp = 748775979, tmp)*((x-(((tmp = 709571811.9883962, tmp)%(-2083567026))%(x/(tmp = -680467505, tmp))))/((tmp = -167543858, tmp)/(tmp = -3113588783, tmp))))/x)<<(-2605415230)))>>>(tmp = 3133054172, tmp))%(tmp = -1904650393, tmp))*((x|(-1193709562))*(tmp = -1731312795.718104, tmp)))))/((tmp = -672386301, tmp)/(tmp = 808898833.4163612, tmp)))))); - assertEquals(-9, x |= (((((tmp = 150377964.57195818, tmp)/(tmp = 2161910879.0514045, tmp))-(-2381625849))>>(-2715928517))/(((452113643)^(-2502232011))/((-3076471740)^(((tmp = 1664851172, tmp)*(((-1460011714)>>>x)<<((-2870606437)%x)))*((tmp = -2836565755.609597, tmp)-((x/(tmp = -871461415, tmp))-(2278867564)))))))); - assertEquals(-1, x >>= x); - assertEquals(-1, x |= ((-1319927272)>>>(-2866709980))); - assertEquals(-1, x >>= ((2345179803.155703)&(-978025218.2243443))); - assertEquals(1, x /= x); - assertEquals(-260730973, x |= (tmp = -260730973, tmp)); - assertEquals(1174405120, x <<= (2681054073)); - assertEquals(1174405120, x &= x); - assertEquals(1073741824, x &= (tmp = 2017166572.7622075, tmp)); - assertEquals(1073741824, x |= x); - assertEquals(168806102, x %= ((((tmp = -2939969193.950067, tmp)|((-2325174027.614815)/(-2329212715)))*(x/(((((-2927776738)/(x|x))+(x%(tmp = -3007347037.698492, tmp)))<<(-1898633380))>>(tmp = 204338085.45241892, tmp))))^x)); - assertEquals(168806102, x %= ((-832849739.5197744)&(tmp = -141908598, tmp))); - assertEquals(-401033205.05225074, x -= (tmp = 569839307.0522507, tmp)); - assertEquals(-401033205, x &= x); - assertEquals(-401130402, x ^= ((x*(tmp = 311418759.22436893, tmp))>>x)); - assertEquals(793533469, x ^= (-950312893.5201888)); - assertEquals(756, x >>>= (-1096189516)); - assertEquals(711, x += ((tmp = -753105189, tmp)>>(599823192.5381484))); - assertEquals(0, x >>>= ((tmp = -2859668634.4641137, tmp)+(-1160392986.1521513))); - assertEquals(2427599726.176195, x -= (-2427599726.176195)); - assertEquals(1942312465.2523103, x -= (485287260.92388475)); - assertEquals(0, x >>>= ((tmp = -1740656456, tmp)/(tmp = 1339746799.9335847, tmp))); - assertEquals(0, x <<= ((-7017077.38786912)*((-699490904.4551768)^x))); - assertEquals(0, x <<= (tmp = 715662384, tmp)); - assertEquals(0, x *= (x>>>(2149735450.0758677))); - assertEquals(NaN, x /= x); - assertEquals(0, x >>= ((397078885)*((851639692.8982519)-x))); - assertEquals(0, x &= (-2526654445)); - assertEquals(0, x %= (-1204924598)); - assertEquals(251639720, x ^= (x|(tmp = 251639720, tmp))); - assertEquals(695433573, x ^= (663539405)); - assertEquals(-1038050104, x -= (1733483677)); - assertEquals(0, x ^= x); - assertEquals(NaN, x %= x); - assertEquals(0, x &= (392107269)); - assertEquals(0, x %= (-3084908458.241551)); - assertEquals(0, x ^= x); - assertEquals(-2121660509, x ^= (tmp = -2121660509.7861986, tmp)); - assertEquals(2285041855588855800, x *= (x|(3209046634))); - assertEquals(54915072, x >>>= (x%(((((x%((((tmp = -1429433339.5078833, tmp)|(tmp = 2906845137, tmp))^(3207260333))&(-848438650)))-(-2721099735))&(141851917.19978714))+x)/x))); - assertEquals(54915072, x &= x); - assertEquals(54915072, x %= (x+(1855489160))); - assertEquals(70078753, x ^= ((((((-1648661736)+(x%((-1421237596)+(tmp = 2053180992.3857927, tmp))))+(tmp = 38606889, tmp))<<((-241334284)%((x>>(215316122))*(tmp = 396488307, tmp))))+((tmp = -2900704565, tmp)^x))^(((1103481003.1111188)^x)-(tmp = 1304113534, tmp)))); - assertEquals(1149501440, x <<= ((x>>(tmp = 3203172843, tmp))*(tmp = -192535531, tmp))); - assertEquals(0, x ^= x); - assertEquals(0, x >>= ((tmp = 2751499787, tmp)&((tmp = 2217654798, tmp)*(tmp = -2798728014, tmp)))); - assertEquals(NaN, x /= ((((-2019592425)>>>((((-1571930240.741224)>>>((-183952981)/((((1990518443.672842)>>(((((2051371284)%(685322833.6793983))>>>(2662885938))<<(-1212029669.6675105))|((-2790877875)<<(1546643473))))<<x)-(tmp = 804296674.4579233, tmp))))-(tmp = -417759051.68770766, tmp))/((-621859758)>>>x)))&x)<<(tmp = -48558935.55320549, tmp))); - assertEquals(0, x <<= (x&x)); - assertEquals(0, x *= (x%(tmp = 301196068, tmp))); - assertEquals(398290944, x |= (((tmp = 1904146839, tmp)+(1521017178))*(-3174245888.562067))); - assertEquals(1256401076, x ^= (1566464180)); - assertEquals(149620758, x %= ((tmp = 532626355, tmp)^(tmp = -382971203, tmp))); - assertEquals(149620791, x |= (x>>x)); - assertEquals(-0.07034576194938641, x /= ((tmp = -1977313182.7573922, tmp)-x)); - assertEquals(0, x <<= x); - assertEquals(0, x &= x); - assertEquals(0, x /= ((2182424851.139966)%(((-2768516150)+x)>>>x))); - assertEquals(0, x %= (-504299638.53962016)); - assertEquals(-0, x *= (-2915134629.6909094)); - assertEquals(0, x <<= ((tmp = 952692723.402582, tmp)%(2146335996.785011))); - assertEquals(230457472, x |= ((tmp = -574776101.8681948, tmp)*(683185125))); - assertEquals(933795934, x ^= (tmp = 974395614, tmp)); - assertEquals(933801974, x ^= (x>>>((-148683729)*(((tmp = 2912596991.415531, tmp)^(-2883672328))/x)))); - assertEquals(222, x >>= (-3060224682)); - assertEquals(27, x >>>= (1429156099.1338701)); - assertEquals(754519106, x ^= (tmp = 754519129.7281355, tmp)); - assertEquals(188629776, x >>>= ((x>>>((1247267193)<<(tmp = -936228622, tmp)))%((tmp = 978604324.8236886, tmp)*((tmp = -3018953108, tmp)^(((tmp = 259650195, tmp)>>>(tmp = 2762928902.7901163, tmp))*(x>>((tmp = 787444263.5542864, tmp)/(x>>>(((-2039193776)<<(tmp = -1408159169, tmp))-(1238893783)))))))))); - assertEquals(188629775.33987066, x += ((tmp = 1040520414, tmp)/((-1576237184)|((tmp = -970083705, tmp)&(((tmp = -312062761.12228274, tmp)|(1171754278.2968853))<<(-2069846597.7723892)))))); - assertEquals(1473670, x >>>= ((tmp = 202409672, tmp)^x)); - assertEquals(2171703268900, x *= (x>>(((tmp = 840468550, tmp)&(-3208057101.2136793))/x))); - assertEquals(0, x ^= x); - assertEquals(0, x ^= (x&((tmp = 2569871408.2405066, tmp)|((tmp = -3149374622, tmp)<<(x-(x|((tmp = -821239139.1626894, tmp)>>>x))))))); - assertEquals(NaN, x /= x); - assertEquals(NaN, x %= (tmp = 1926106354, tmp)); - assertEquals(0, x >>= ((x/(-2848416))/(tmp = 2484293767, tmp))); - assertEquals(0, x <<= ((tmp = -2484137114, tmp)>>>(tmp = -887083772.8318355, tmp))); - assertEquals(0, x >>= (tmp = -2651389432, tmp)); - assertEquals(0, x ^= x); - assertEquals(1041871201, x += ((tmp = 1041871201.9272791, tmp)|(x<<(-1136959830)))); - assertEquals(651390879501530900, x *= ((tmp = 1250424964.0346212, tmp)>>x)); - assertEquals(1965815296.245636, x %= ((2650603245.655831)+((-1610821947.8640454)>>>(((878987151.6917406)*((((784630543)%(((1448720244)>>(((tmp = 3036767847, tmp)+((tmp = 1012548422, tmp)<<(1957000200)))-x))/(x>>x)))<<((tmp = 914710268, tmp)*(((x^(1559603121))<<(tmp = 3181816736, tmp))|((-1964115655)+x))))-(-1055603890)))&(946797797.0616649))))); - assertEquals(1965815296.245636, x %= (tmp = -2601038357.593118, tmp)); - assertEquals(-769384440.872302, x += (-2735199737.117938)); - assertEquals(-769384440.872302, x %= (2193123162)); - assertEquals(1, x /= x); - assertEquals(1, x -= (((x>>>(-1968465925))*((tmp = 563037904, tmp)>>((tmp = 3009534415.769578, tmp)>>((-2567240601.7038674)<<(tmp = -1258402723.4150183, tmp)))))%(3112239470.276867))); - assertEquals(1, x |= x); - assertEquals(1505461527, x ^= (tmp = 1505461526.5858076, tmp)); - assertEquals(406553877, x &= (tmp = 2558242293, tmp)); - assertEquals(406553877, x |= x); - assertEquals(-574902339, x |= ((-709809495)%(tmp = -2880884811.410611, tmp))); - assertEquals(-20281777.349363208, x %= (22184822.46602547)); - assertEquals(1, x /= x); - assertEquals(-4360732, x ^= ((x|(tmp = 3178620274, tmp))>>(((2686286888)&(((-1107223053.8716578)/(((-2955575332.3675404)+(-2770518721))|(-2705016953.640522)))-x))^((1473641110.4633303)*((((-1466496401)<<x)+x)%(1805868749.082736)))))); - assertEquals(-1158545408, x <<= ((((x/((-2710098221.691819)-(-2421462965.788145)))/(((((x>>>(tmp = 1994541591.1032422, tmp))+(tmp = -1276676679.9747126, tmp))&((tmp = 1764029634.2493339, tmp)+((x|(tmp = -3050446156, tmp))-((tmp = -9441859, tmp)/(((-2072420232)&x)*(-1003199889))))))+(tmp = -2443230628, tmp))*x))*((x&((((x|(747566933))*(((2039741506)>>>((tmp = -2456000554, tmp)>>>(-1566360933.7788877)))^((tmp = 960600745, tmp)/x)))&(x^(((-2649310348.777452)^((2224282875)-(tmp = -2129141087.3182096, tmp)))<<((x<<x)+((-1307892509.3874407)-(x|(tmp = -2831643528.9720087, tmp)))))))/(((tmp = -35502946, tmp)<<((tmp = 1091279222, tmp)>>(((-2686069468.8930416)-x)+(tmp = 367442353.2904701, tmp))))%(1218262628))))/x))^(-919079153.7857773))); - assertEquals(747, x >>>= (1229157974)); - assertEquals(747, x |= x); - assertEquals(NaN, x %= (((3086718766.4715977)*((7912648.497568846)*((-2713828337.1659327)*(-176492425.4011252))))<<(tmp = -1074475173, tmp))); - assertEquals(0, x >>>= ((((444923201)<<x)>>>(-883391420.2142565))*((((617245412)<<x)>>>x)*(-913086143.2793813)))); - assertEquals(1941802406, x ^= (tmp = -2353164890, tmp)); - assertEquals(14, x >>>= (-1600311077.4571416)); - assertEquals(-18229482703.7246, x += (((x+(-993157139.7880647))%x)*(1862419512.1781366))); - assertEquals(-14.531388114858734, x /= ((tmp = -1649072797.951641, tmp)<<x)); - assertEquals(0, x ^= x); - assertEquals(0, x >>= ((x/x)^x)); - assertEquals(2, x ^= ((-1597416259)/(-738770020))); - assertEquals(0, x >>= (tmp = -387850072.74833393, tmp)); - assertEquals(0, x >>>= ((2491085477.186817)>>(x*(((tmp = -1592498533, tmp)+(tmp = 2086841852, tmp))&(-3174019330.8288536))))); - assertEquals(0, x >>= x); - assertEquals(0, x >>>= (tmp = -3045348659.45243, tmp)); - assertEquals(-1208573479, x |= ((3086393817)-x)); - assertEquals(1460649854142163500, x *= x); - assertEquals(1588199424, x <<= (-1902076952)); - assertEquals(1586102272, x &= (tmp = 2139876091.9142454, tmp)); - assertEquals(-460908552.5528109, x -= (tmp = 2047010824.552811, tmp)); - assertEquals(-460908552.5528109, x %= (tmp = 507904117.09368753, tmp)); - assertEquals(-460908552.5528109, x %= (2749577642.527038)); - assertEquals(234012, x >>>= (-340465746.91275)); - assertEquals(0, x >>>= x); - assertEquals(0, x %= (tmp = -2601875531, tmp)); - assertEquals(0, x %= (x|(tmp = 650979981.1158671, tmp))); - assertEquals(0, x %= (tmp = -2286020987, tmp)); - assertEquals(0, x |= x); - assertEquals(0, x &= (x|((tmp = 2568101411, tmp)-(-1438002403)))); - assertEquals(0, x >>>= (1399248574)); - assertEquals(0, x %= (-1906670287.2043698)); - assertEquals(0, x >>= (1019286379.6962404)); - assertEquals(0, x |= (x/(tmp = -82583591.62643051, tmp))); - assertEquals(NaN, x %= x); - assertEquals(NaN, x *= (x^(1874776436))); - assertEquals(NaN, x -= ((-1238826797)-(-2971588236.7228813))); - assertEquals(0, x <<= (2064632559)); - assertEquals(-0.5967273958864694, x += (((tmp = 1502995019, tmp)>>x)/(-2518729707))); - assertEquals(0, x >>>= x); - assertEquals(-0, x /= (-1923030890)); - assertEquals(NaN, x %= x); - assertEquals(0, x >>= (tmp = 1081732779.9449487, tmp)); - assertEquals(-820183066, x |= ((tmp = -3169007292.4721155, tmp)|(-1912588318))); - assertEquals(0, x -= x); - assertEquals(NaN, x %= x); - assertEquals(NaN, x /= (tmp = 287181840, tmp)); - assertEquals(0, x &= (x/((tmp = -1139766051, tmp)<<(x&(tmp = 2779004578, tmp))))); - assertEquals(0, x >>= (((tmp = -1816938028, tmp)+(-224851993.3139863))*(-2933829524))); - assertEquals(0, x |= ((((tmp = 305077929.1808746, tmp)&((x-(((((tmp = 2122810346.7475111, tmp)<<(717271979))*(tmp = 256854043.72633624, tmp))%((x+(tmp = -318657223.9992106, tmp))*((1993144830)<<(2594890698.603228))))^((((tmp = 257370667, tmp)>>>((((x^(3160746820))>>>(2049640466.8116226))>>>(2543930504.7117066))^(x-x)))^(x%(964838975)))^x)))%(x*x)))>>>x)*(tmp = -46861540, tmp))); - assertEquals(747575633, x ^= ((-2406502427)-(-3154078060.3794584))); - assertEquals(0, x *= (x%x)); - assertEquals(0, x <<= (1313773705.3087234)); - assertEquals(0, x >>>= ((x+x)>>>(3068164056))); - assertEquals(-0, x *= (tmp = -1771797797, tmp)); - assertEquals(1784146970, x ^= (tmp = 1784146970, tmp)); - assertEquals(1784146970, x >>>= (tmp = -2219972320.7195597, tmp)); - assertEquals(1744830464, x <<= ((((-2769476584)-(((1798431604)>>(tmp = 1337687914.799577, tmp))>>>((-2802941943.15014)>>x)))>>>(tmp = 646033678, tmp))-x)); - assertEquals(3044433348102455300, x *= x); - assertEquals(0, x >>= ((tmp = 1592076570.1900845, tmp)-((645774223.6317859)>>x))); - assertEquals(0, x >>= (x>>>(-3045822290.1536255))); - assertEquals(-0, x *= (tmp = -2450298800.986624, tmp)); - assertEquals(0, x >>= (tmp = 1379605393, tmp)); - assertEquals(0, x &= (((x-((((tmp = 837939461.6683749, tmp)+((((-813261853.3247359)|(x&(((-2565113940)*(tmp = -2725085381.240134, tmp))|x)))%(-1457259320))-(x+((tmp = -273947066, tmp)%((1164825698.879649)>>(1653138880.3434052))))))>>>(2823967606.411492))>>>((((((((1189235604.9646997)/(tmp = -2875620103.4002438, tmp))-(tmp = -801261493, tmp))<<(((1832556579.5095325)<<x)|((tmp = -2740330665, tmp)>>(tmp = -2352814025, tmp))))-(tmp = -1445043552.99499, tmp))&(x<<(((((445325471)*(1293047043.1808558))>>>(((1901837408.5910044)-(tmp = -2349093446.5313253, tmp))>>>(tmp = 1000847053.1861948, tmp)))*(x>>>(1771853406.6567078)))>>x)))>>>x)>>>(x^((tmp = 2813422715, tmp)-(x+(-342599947)))))))&(x>>>x))*x)); - assertEquals(NaN, x %= ((tmp = -3027713526, tmp)-((((x%(((((x/((2711155710)^(((((x>>>x)%((1098599291.155015)^(((((tmp = 1855724377.8987885, tmp)/(x|x))*((-1963179786)*((x-((-1634717702)%x))<<x)))>>(2008859507))>>((tmp = 2635024299.7983694, tmp)^(tmp = -602049246, tmp)))))*(x>>x))&(tmp = -1925103609, tmp))*((tmp = 2106913531.2828505, tmp)%((tmp = -200970069, tmp)*(-2809001910.951446))))))%x)*((1990098169)>>((x<<(2303347904.2601404))%x)))|(2767962065.9846206))+(201589933.301661)))>>(((tmp = 1921071149.5140274, tmp)>>(1054558799.1731887))|x))*(x/((((-2833879637.345674)>>>(tmp = 2849099601, tmp))%x)+(x%(x%(((tmp = 1983018049, tmp)^(tmp = -2659637454, tmp))>>((-1335497229.6945198)-(x+(((((tmp = 1136612609.848967, tmp)%(2471741030.01762))<<(x|(((tmp = 1644081190.1972675, tmp)&(-1422527338))^(2379264356.265957))))/(tmp = 2979299484.1884174, tmp))/x)))))))))*((tmp = 1858298882, tmp)^((tmp = -547417134.9651439, tmp)*x))))); - assertEquals(-7664, x |= ((2286000258.825538)>>(1716389170))); - assertEquals(-1, x >>= x); - assertEquals(-1231640486.3023372, x += ((tmp = 1231640485.3023372, tmp)*x)); - assertEquals(-2463280972.6046743, x += x); - assertEquals(1746, x >>>= x); - assertEquals(1746, x >>>= (((tmp = -562546488.0669937, tmp)*((-2475357745.8508205)&((x%(821425388.8633704))%((((-2315481592.687686)&(((tmp = 3130530521.7453523, tmp)+x)-x))^(-973033390.1773088))/x))))<<x)); - assertEquals(1746, x %= (-1544973951.076033)); - assertEquals(27936, x <<= (-525441532.33816123)); - assertEquals(27936, x %= (x*((tmp = 344991423.5336287, tmp)+(-2267207281)))); - assertEquals(27, x >>>= (tmp = 1249792906, tmp)); - assertEquals(0, x >>>= (tmp = -1068989615, tmp)); - assertEquals(0, x >>>= (tmp = 347969658.92579734, tmp)); - assertEquals(-2656611892, x -= (2656611892)); - assertEquals(1944539596, x |= (((tmp = 3000889963, tmp)-x)<<((tmp = 2917390580.5323124, tmp)^(-996041439)))); - assertEquals(1944539596, x |= x); - assertEquals(-739740167.0752468, x -= ((1712009965.0752468)+(x>>((tmp = -740611560.99014, tmp)>>>((tmp = -1033267419.6253037, tmp)&(862184116.3583733)))))); - assertEquals(-1479480334.1504936, x += x); - assertEquals(-4294967296.150494, x -= (x>>>((1219235492.3661718)&(3138970355.0665245)))); - assertEquals(0, x >>= (x*x)); - assertEquals(-0, x *= ((-2202530054.6558375)-(-676578695))); - assertEquals(-0, x %= (1336025846)); - assertEquals(0, x &= x); - assertEquals(0, x /= (1759366510)); - assertEquals(630007622, x |= (630007622)); - assertEquals(-0.22460286863455903, x /= (tmp = -2804984753, tmp)); - assertEquals(1102410276.775397, x -= (-1102410277)); - assertEquals(1102410276.775397, x %= ((((-2569525203)&x)*(x|(-1932675298)))/((-2376634450)>>>(x>>>(tmp = 936937604.9491489, tmp))))); - assertEquals(33642, x >>= (3028252527)); - assertEquals(2181106522.688034, x -= (-2181072880.688034)); - assertEquals(-2113861630, x &= (2523921542)); - assertEquals(-2147483646, x &= (-1996601566.9370148)); - assertEquals(-2147483648, x &= (tmp = -665669175.1968856, tmp)); - assertEquals(-2858673260.1367273, x -= (tmp = 711189612.1367272, tmp)); - assertEquals(350657, x >>= (tmp = -170243892.25474262, tmp)); - assertEquals(-0.0001405571562140975, x /= (-2494764474.7868776)); - assertEquals(0, x ^= x); - assertEquals(NaN, x /= ((x&(-2041236879))*((tmp = -2182530229, tmp)^((1274197078)*x)))); - assertEquals(0, x |= (x&(x-(1794950303)))); - assertEquals(1222105379, x |= (tmp = 1222105379, tmp)); - assertEquals(729884484, x ^= (tmp = 1666645607.6907792, tmp)); - assertEquals(729884484, x %= (tmp = -2896922082, tmp)); - assertEquals(8768, x &= ((tmp = 358940932, tmp)>>>(3159687631.3308897))); - assertEquals(1892384495, x |= (-2402591569)); - assertEquals(1892470533, x += ((((x^(-2266612043))>>>(tmp = -531009952, tmp))<<(x>>>((-1365315963.5698428)>>>((x+((-3168207800.184341)-(tmp = 1776222157.609917, tmp)))+(-1588857469.3596382)))))>>>x)); - assertEquals(143587205, x += (tmp = -1748883328, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x >>= (tmp = 2334880462.3195543, tmp)); - assertEquals(0, x &= ((tmp = 1819359625.4396145, tmp)|(tmp = -1323513565, tmp))); - assertEquals(-1102259874, x ^= (3192707422)); - assertEquals(2567457772588852700, x *= (-2329267202)); - assertEquals(-16783687, x |= ((-2212476227.060922)^(378973700.78452563))); - assertEquals(4278183609, x >>>= ((((((((tmp = 1766363150.197206, tmp)*(-2774552871))%x)>>>((3071429820)&((((((tmp = 351068445.27642524, tmp)<<(tmp = 2646575765, tmp))^(806452682))<<((x>>>(-2217968415.505327))<<(1564726716)))|x)-(tmp = -3110814468.9023848, tmp))))+x)^x)>>>(tmp = -617705282.0788529, tmp))>>>x)); - assertEquals(4314933530, x -= ((1032195469.789219)|(tmp = -448053861.9531791, tmp))); - assertEquals(9709850, x %= (((tmp = -3056286252.5853324, tmp)*x)&x)); - assertEquals(9709850, x %= (tmp = -2596800940, tmp)); - assertEquals(2655489828.9461126, x -= (tmp = -2645779978.9461126, tmp)); - assertEquals(369266212, x &= (((335712316.24874604)|(tmp = 33648215, tmp))-((x/(2639848695))<<((-499681175)<<(-2490554556))))); - assertEquals(-2147483648, x <<= (-834465507)); - assertEquals(1073741824, x >>>= (((tmp = 3018385473.1824775, tmp)>>(x*(-2574502558.216812)))|(((tmp = -1742844828, tmp)*(1698724455))&x))); - assertEquals(-270818218, x += (-1344560042)); - assertEquals(360710144, x <<= x); - assertEquals(0, x <<= (tmp = 612718075, tmp)); - assertEquals(0, x <<= x); - assertEquals(-0, x /= (tmp = -1922423684, tmp)); - assertEquals(-0, x *= ((((tmp = 741806213.3264687, tmp)%(-711184803.2022421))+((tmp = -3209040938, tmp)&(525355849.044886)))&(x<<(tmp = -698610297, tmp)))); - assertEquals(0, x <<= (-482471790)); - assertEquals(0, x &= ((-921538707)/(tmp = -482498765.988616, tmp))); - assertEquals(0, x ^= (x^x)); - assertEquals(-351721702, x ^= (-351721702.8850286)); - assertEquals(726242219625599900, x -= ((2064820612)*x)); - assertEquals(1452484439251199700, x += x); - assertEquals(2.52318299412847e-15, x %= ((((x<<((2508143285)+x))>>(-2493225905.011774))%(1867009511.0792103))/((((x<<(2542171236))>>((x|x)&(tmp = -384528563, tmp)))+((-1168755343)*(1731980691.6745195)))+(tmp = -1608066022.71164, tmp)))); - assertEquals(79905008, x += ((((-2702081714.590131)&(x+(tmp = -1254725471.2121565, tmp)))*(3088309981))%(((tmp = 1476844981.1453142, tmp)|((((tmp = -1243556934.7291331, tmp)%x)^(-1302096154))+((660489180)/(tmp = -681535480.8642154, tmp))))^(tmp = -8410710, tmp)))); - assertEquals(1215822204, x ^= ((-3008054900)>>>(tmp = -1990206464.460693, tmp))); - assertEquals(-394790532, x |= ((((-1334779133.2038574)+(tmp = -1407958866.832946, tmp))<<(1699208315))-(((x^(x%x))<<(3216443))>>(x+((((2576716374.3081336)|((tmp = 2316167191.348064, tmp)&((51086351.20208645)&((x|(tmp = -357261999, tmp))^(x/x)))))*(-45901631.10155654))*(((-439588079)>>>((-2358959768.7634916)|(1613636894.9373643)))+(((-908627176)<<x)%(x%((-1669567978)>>>((x>>(1289400876))+(tmp = 2726174270, tmp))))))))))); - assertEquals(-0.17717467607696327, x /= (2228255982.974148)); - assertEquals(-1905616474, x ^= (tmp = 2389350822.851587, tmp)); - assertEquals(-0, x %= x); - assertEquals(2818124981.508915, x -= (-2818124981.508915)); - assertEquals(-1476842315, x |= x); - assertEquals(73408564, x &= (-3147390604.3453345)); - assertEquals(70, x >>>= x); - assertEquals(1, x >>= x); - assertEquals(3086527319.899181, x *= (3086527319.899181)); - assertEquals(-145, x >>= x); - assertEquals(-145, x %= (tmp = -2500421077.3982406, tmp)); - assertEquals(-1, x >>= (tmp = -2970678326.712191, tmp)); - assertEquals(-1, x %= ((tmp = -535932632.4668834, tmp)+(((-1226598339.347982)<<((tmp = 616949449, tmp)/(tmp = 2779464046, tmp)))/(214578501.67984307)))); - assertEquals(1, x *= x); - assertEquals(1, x >>= ((tmp = 11080208, tmp)<<(460763913))); - assertEquals(-1.8406600706723492e-19, x /= ((tmp = -2334126306.1720915, tmp)*(tmp = 2327566272.5901165, tmp))); - assertEquals(856681434186007200, x -= ((tmp = -2286974992.8133907, tmp)*(374591518))); - assertEquals(3126084224, x >>>= x); - assertEquals(-1160460669, x |= (tmp = 181716099, tmp)); - assertEquals(873988096, x <<= (tmp = 406702419, tmp)); - assertEquals(0, x <<= ((tmp = 802107965.4672925, tmp)-((tmp = 1644174603, tmp)>>((tmp = 604679952, tmp)+(tmp = -515450096.51425123, tmp))))); - assertEquals(NaN, x %= ((x>>(tmp = 2245570378, tmp))*(tmp = 1547616585, tmp))); - assertEquals(NaN, x /= ((tmp = -776657947.0382309, tmp)&(tmp = 163929332.28270507, tmp))); - assertEquals(NaN, x *= (tmp = 243725679.78916526, tmp)); - assertEquals(NaN, x /= (x>>x)); - assertEquals(0, x <<= ((tmp = -1293291295.5735884, tmp)%(((((63309078)>>>x)&(x&(-2835108260.025297)))+x)>>>(-1317213424)))); - assertEquals(0, x *= ((((tmp = -1140319441.0068483, tmp)*(tmp = 2102496185, tmp))&(-2326380427))<<(tmp = -2765904696, tmp))); - assertEquals(0, x /= (tmp = 2709618593, tmp)); - assertEquals(0, x >>= (-1753085095.7670164)); - assertEquals(1766381484, x |= (-2528585812)); - assertEquals(1766381484, x %= (2735943476.6363373)); - assertEquals(1766381484, x %= (x*(tmp = 2701354268, tmp))); - assertEquals(-2147483648, x <<= (-323840707.4949653)); - assertEquals(4611686018427388000, x *= (x<<x)); - assertEquals(0, x <<= (3066735113)); - assertEquals(0, x ^= ((((x*x)^(tmp = -2182795086.39927, tmp))<<(x^(tmp = 1661144992.4371827, tmp)))<<((((-2885512572.176741)*(tmp = 609919485, tmp))|(tmp = 929399391.0790694, tmp))>>>((((((((((399048996)>>((-107976581.61751771)>>>x))|(((-1502100015)<<(tmp = -1108852531.9494338, tmp))&(x/(tmp = -3198795871.7239237, tmp))))+((-2627653357)>>x))>>>x)*(1066736757.2718519))%(tmp = 1326732482.201604, tmp))/(tmp = 2513496019.814191, tmp))>>>((1694891519)>>>(-2860217254.378931)))<<(tmp = 31345503, tmp))))); - assertEquals(0, x ^= (x/((-2556481161)>>>(x/(x%(x&(1302923615.7148068))))))); - assertEquals(NaN, x /= x); - assertEquals(NaN, x += (tmp = 846522031, tmp)); - assertEquals(0, x >>= (x+(-1420249556.419045))); - assertEquals(0, x ^= (((x%(-1807673170))&x)-x)); - assertEquals(-3484.311990686845, x -= ((((((-510347602.0068991)>>>x)<<((tmp = 1647999950, tmp)&(((305407727)>>((1781066601.791009)&x))<<((tmp = -998795238, tmp)%(((x/x)+x)<<(((2586995491.434947)<<x)-((((tmp = 545715607.9395425, tmp)*x)>>>x)>>>(((((2332534960.4595165)^(-3159493972.3695474))<<(tmp = 867030294, tmp))|(2950723135.753855))^(((3150916666)<<x)>>((tmp = 414988690, tmp)|((tmp = -1879594606, tmp)/(tmp = 1485647336.933429, tmp))))))))))))>>(tmp = -2676293177, tmp))%(617312699.1995015))/((((tmp = -1742121185, tmp)^((((x&x)<<(tmp = 698266916, tmp))/(-1860886248))+((-213304430)%((((((-2508973021.1333447)+(tmp = 2678876318.4903, tmp))&(tmp = -43584540, tmp))-x)^(-2251323850.4611115))-x))))>>>(tmp = 2555971284, tmp))%((((tmp = 16925106, tmp)^x)&x)|((x/((x|(tmp = -2787677257.125139, tmp))<<(-853699567)))+(tmp = -1721553520, tmp)))))); - assertEquals(-447873933.26863855, x += (-447870448.9566479)); - assertEquals(200591060101520900, x *= x); - assertEquals(200591062202483420, x -= (-2100962536)); - assertEquals(-5.261023346568228e+24, x *= ((tmp = -419641692.6377077, tmp)>>(tmp = -224703100, tmp))); - assertEquals(1269498660, x |= (195756836)); - assertEquals(1269498660, x |= x); - assertEquals(1269498660, x |= x); - assertEquals(-37.75978948486164, x /= (((tmp = -595793780, tmp)+((tmp = 2384365752, tmp)>>>(1597707155)))|((968887032)^(tmp = 2417905313.4337964, tmp)))); - assertEquals(-37.75978948486164, x %= (tmp = -1846958365.291661, tmp)); - assertEquals(1102319266.6421175, x += (1102319304.401907)); - assertEquals(-1664202255175155200, x -= ((x^(tmp = 407408729, tmp))*x)); - assertEquals(-752874653, x ^= (tmp = 314673507, tmp)); - assertEquals(-72474761, x |= (tmp = -2538726025.8884344, tmp)); - assertEquals(-72474761, x |= x); - assertEquals(-122849418, x += ((tmp = -2332080457, tmp)|(((((30496388.145492196)*(((-1654329438.451212)|(-2205923896))&(x>>(tmp = -1179784444.957002, tmp))))&(tmp = 319312118, tmp))*(651650825))|(((-2305190283)|x)>>>(-428229803))))); - assertEquals(994, x >>>= x); - assertEquals(614292, x *= (((((2565736877)/((tmp = 649009094, tmp)>>>(((x>>>(2208471260))>>(x>>>x))%x)))&(tmp = 357846438, tmp))<<(tmp = -2175355851, tmp))%x)); - assertEquals(1792008118, x |= (tmp = 1791924774.5121183, tmp)); - assertEquals(1246238208, x &= (tmp = 1264064009.9569638, tmp)); - assertEquals(-88877082, x ^= (2969289190.285704)); - assertEquals(0.044923746573582474, x /= ((tmp = -3057438043, tmp)^(-1009304907))); - assertEquals(0, x <<= ((-828383918)-((((x>>(734512101))*(tmp = -3108890379, tmp))-(x|((tmp = 3081370585.3127823, tmp)^((-271087194)-(x/(tmp = -2777995324.4073873, tmp))))))%x))); - assertEquals(1604111507.3365753, x -= (-1604111507.3365753)); - assertEquals(-1721314970, x ^= (tmp = -956686859, tmp)); - assertEquals(-102247425, x |= (tmp = -2535095555, tmp)); - assertEquals(-102247425, x %= (-955423877)); - assertEquals(1053144489850425, x *= (((tmp = 1583243590.9550207, tmp)&(1356978114.8592746))|(tmp = -10299961.622774363, tmp))); - assertEquals(-0.0043728190668037336, x /= ((-1196259252.435701)*(((-689529982)|(tmp = -1698518652.4373918, tmp))<<x))); - assertEquals(-2, x ^= (((x+(tmp = 2961627388, tmp))>>(tmp = 231666110.84104693, tmp))|x)); - assertEquals(-1, x >>= (tmp = -83214419.92958307, tmp)); - assertEquals(-1, x %= (-1303878209.6288595)); - assertEquals(2944850457.5213213, x -= (tmp = -2944850458.5213213, tmp)); - assertEquals(-1.6607884436053055, x /= (-1773164107)); - assertEquals(-0.6607884436053055, x %= ((x>>(1240245489.8629928))%(tmp = -3044136221, tmp))); - assertEquals(-0, x *= ((x*x)>>>((1069542313.7656753)+x))); - assertEquals(0, x >>>= (tmp = -202931587.00212693, tmp)); - assertEquals(-0, x *= (-375274420)); - assertEquals(0, x |= ((x/(((tmp = -876417141, tmp)*(x>>>x))&(-2406962078)))<<x)); - assertEquals(0, x &= ((tmp = -650283599.0780096, tmp)*(tmp = 513255913.34108484, tmp))); - assertEquals(3027255453.458466, x += (3027255453.458466)); - assertEquals(-12568623413253943000, x *= (((x-(198689694.92141533))|x)-x)); - assertEquals(-12568623410285185000, x -= (tmp = -2968758030.3694654, tmp)); - assertEquals(-2008903680, x &= (3111621747.7679076)); - assertEquals(-110045263.26583672, x += (tmp = 1898858416.7341633, tmp)); - assertEquals(15964, x >>>= (1141042034)); - assertEquals(31928, x += x); - assertEquals(0, x ^= x); - assertEquals(-1159866377, x |= (-1159866377)); - assertEquals(0, x ^= x); - assertEquals(3072699529.4306993, x -= (tmp = -3072699529.4306993, tmp)); - assertEquals(1, x /= x); - assertEquals(-1471195029, x |= (2823772267.429641)); - assertEquals(-4152937108, x += (-2681742079)); - assertEquals(142030188, x |= x); - assertEquals(270, x >>= (tmp = 1013826483, tmp)); - assertEquals(0, x >>>= (529670686)); - assertEquals(-2912300367, x -= (2912300367)); - assertEquals(2213791134963007500, x *= (x<<((((-3214746140)>>(tmp = -588929463, tmp))+((tmp = -3084290306, tmp)>>x))>>x))); - assertEquals(2213791133466809900, x -= (tmp = 1496197641, tmp)); - assertEquals(69834416, x >>>= (x|(((2755815509.6323137)^(x%(((x*((((tmp = 375453453, tmp)<<(x*x))>>(tmp = -973199642, tmp))*x))>>((tmp = -356288629, tmp)>>(tmp = 2879464644, tmp)))<<((((1353647167.9291127)>>>(x/x))<<((2919449101)/(2954998123.5529594)))^x))))&((-2317273650)>>>(tmp = 34560010.71060455, tmp))))); - assertEquals(69834416, x >>>= (x^(-2117657680.8646245))); - assertEquals(2217318064, x -= ((tmp = 2035883891, tmp)<<(tmp = -1884739265, tmp))); - assertEquals(-1272875686, x ^= (tmp = 805889002.7165648, tmp)); - assertEquals(-1272875686, x >>= (x&(((1750455903)*x)>>((722098015)%((tmp = 1605335626, tmp)>>(tmp = -565369634, tmp)))))); - assertEquals(-1274351316, x -= (x>>>((tmp = 2382002632, tmp)-((tmp = -2355012843, tmp)+(1465018311.6735773))))); - assertEquals(-2982908522.4418216, x -= ((tmp = 1635549038.4418216, tmp)+(((1952167017.720186)&((tmp = -2284822073.1002254, tmp)>>(-1403893917)))%(tmp = 655347757, tmp)))); - assertEquals(312, x >>>= x); - assertEquals(1248, x <<= (2376583906)); - assertEquals(0, x ^= x); - assertEquals(0, x *= ((((tmp = 1914053541.881434, tmp)>>>(tmp = 1583032186, tmp))>>>(-2511688231))%(tmp = -2647173031, tmp))); - assertEquals(0, x >>>= (tmp = -2320612994.2421227, tmp)); - assertEquals(0, x %= (((x+(tmp = -720216298.5403998, tmp))<<(414712685))>>(tmp = 480416588, tmp))); - assertEquals(0, x >>= ((((3039442014.271272)<<x)%(-2402430612.9724464))&((-2141451461.3664773)%((x>>(1361764256))/((tmp = -1723952801.9320493, tmp)%(477351810.2485285)))))); - assertEquals(-0, x /= (tmp = -1627035877, tmp)); - assertEquals(0, x >>>= (tmp = 1745193212, tmp)); - assertEquals(0, x >>>= (2309131575)); - assertEquals(NaN, x %= (((x*(tmp = -1730907131.6124666, tmp))%((((1481750041)|(x>>((((x>>>(tmp = 3128156522.5936565, tmp))/(tmp = -1277222645.9880452, tmp))^(tmp = -2327254789, tmp))+x)))>>>(-1161176960))>>>(tmp = 3135906272.5466847, tmp)))*(((((-2230902834.464362)^(1822893689.8183987))+(((tmp = 1597326356, tmp)/(x&((tmp = -3044163063.587389, tmp)>>(tmp = 2844997555, tmp))))%(x^x)))>>((x|x)/x))^(2634614167.2529745)))); - assertEquals(0, x &= (3081901595)); - assertEquals(0, x &= (-2453019214.8914948)); - assertEquals(0, x &= x); - assertEquals(0, x >>>= (-596810618.3666217)); - assertEquals(0, x >>= (((908276623)|x)/x)); - assertEquals(0, x ^= x); - assertEquals(958890056, x |= (tmp = 958890056.474458, tmp)); - assertEquals(1325436928, x <<= (tmp = -2474326583, tmp)); - assertEquals(711588532333838300, x *= ((-148161646.68183947)<<(tmp = -1149179108.8049204, tmp))); - assertEquals(0, x ^= (((2862565506)%x)/(tmp = -2865813112, tmp))); - assertEquals(-2064806628, x += (((tmp = -2677361175.7317276, tmp)/((817159440)>>>(tmp = 1895467706, tmp)))^(x|(tmp = -2309094859, tmp)))); - assertEquals(-69806982479424, x *= ((x&(tmp = 2857559765.1909904, tmp))&(-3166908966.754988))); - assertEquals(-430255744, x %= ((((((-2968574724.119535)<<x)<<((tmp = 1603913671, tmp)%((-1495838556.661653)^(tmp = 1778219751, tmp))))*(-400364265))<<((((1607866371.235576)-(1961740136))|(1259754297))&(tmp = -1018024797.1352971, tmp)))^x)); - assertEquals(6.828637393208647e-7, x /= (x*(tmp = 1464421, tmp))); - assertEquals(0, x &= x); - assertEquals(-0, x *= (((tmp = -2510016276, tmp)-(2088209546))<<((tmp = -1609442851.3789036, tmp)+(tmp = 1919930212, tmp)))); - assertEquals(-0, x %= (tmp = 1965117998, tmp)); - assertEquals(-290294792.53186846, x += ((tmp = -2361555894.5318685, tmp)%(2071261102))); - assertEquals(-70873, x >>= (tmp = 2206814124, tmp)); - assertEquals(-141746, x += x); - assertEquals(-141733.9831459089, x -= (((tmp = -806523527, tmp)>>>(tmp = 1897214891, tmp))/x)); - assertEquals(-141733.9831459089, x %= ((tmp = 1996295696, tmp)<<(tmp = 3124244672, tmp))); - assertEquals(141733.9831459089, x /= (x>>(2688555704.561076))); - assertEquals(3196954517.3075542, x -= (tmp = -3196812783.3244085, tmp)); - assertEquals(-19929155, x |= (((x|x)+x)^((tmp = 391754876, tmp)-(((((((tmp = -3051902902.5100636, tmp)*(x/(1546924993)))|(tmp = 1494375949, tmp))/((((-795378522)/(tmp = 509984856, tmp))>>>(tmp = -106173186, tmp))+x))|x)|(1916921307))>>>x)))); - assertEquals(1279271449, x &= ((tmp = 1289446971, tmp)&(tmp = 1836102619, tmp))); - assertEquals(17876992, x <<= (-207633461)); - assertEquals(0, x >>= (tmp = -903885218.9406946, tmp)); - assertEquals(0, x >>>= x); - assertEquals(-2999, x -= (((754533336.2183633)%(tmp = 557970276.0537136, tmp))>>(tmp = -1171045520, tmp))); - assertEquals(-0.000003020470363504361, x /= (tmp = 992891715.2229724, tmp)); - assertEquals(1, x /= x); - assertEquals(0.45768595820301217, x %= ((tmp = 673779031, tmp)/(tmp = -1242414872.3263657, tmp))); - assertEquals(-980843052.1872087, x += (tmp = -980843052.6448946, tmp)); - assertEquals(-Infinity, x /= ((((tmp = 317747175.8024508, tmp)&(x&(((tmp = 1632953053, tmp)>>x)/x)))%x)/(3145184986))); - assertEquals(0, x &= (x<<x)); - assertEquals(0, x ^= (x-((2969023660.5619783)/x))); - assertEquals(0, x *= x); - assertEquals(NaN, x %= (x/(((x-x)/((tmp = -1622970458.3812745, tmp)-(1626134522)))&((((((tmp = 1384729039.4149384, tmp)^(x%(tmp = -2736365959, tmp)))+((-1465172172)%x))>>(tmp = -1839184810.2603343, tmp))^(((tmp = 1756918419, tmp)>>>(x+(x%(tmp = -2011122996.9794662, tmp))))<<(-3026600748.902623)))*((tmp = -2040286580, tmp)>>(-2899217430.655154)))))); - assertEquals(0, x >>>= (tmp = 2100066003.3046467, tmp)); - assertEquals(1362012169, x ^= (tmp = 1362012169, tmp)); - assertEquals(1476312683, x |= ((457898409)>>>(-3079768830.723079))); - assertEquals(1441711, x >>>= (905040778.7770994)); - assertEquals(2078530607521, x *= x); - assertEquals(-208193103, x |= ((tmp = -241750000, tmp)^x)); - assertEquals(745036378, x ^= (((tmp = -1737151062.4726632, tmp)<<x)|(tmp = -1900321813, tmp))); - assertEquals(1744830464, x <<= x); - assertEquals(212992, x >>>= ((1210741037)-(x-(x>>>((x^(-1273817997.0036907))+((2401915056.5471)%(x<<(tmp = 1696738364.277438, tmp)))))))); - assertEquals(0.0001604311565639742, x /= (1327622418)); - assertEquals(0, x <<= (tmp = 166631979.34529006, tmp)); - assertEquals(0, x *= ((((tmp = 657814984, tmp)/(((-831055031)>>>(1531978379.1768064))|((tmp = 2470027754.302619, tmp)^(-223467597))))/(tmp = 1678697269.468965, tmp))&(tmp = -1756260071.4360774, tmp))); - assertEquals(-2049375053, x ^= (tmp = -2049375053, tmp)); - assertEquals(-1879109889, x |= (tmp = -1963586818.0436726, tmp)); - assertEquals(718239919, x ^= (tmp = -1523550640.1925273, tmp)); - assertEquals(-1361085185, x |= (-1939964707)); - assertEquals(2, x >>>= (1864136030.7395325)); - assertEquals(0.794648722849246, x %= ((-668830999)*(((-2227700170.7193384)%(x^(x>>>x)))/(tmp = 399149892, tmp)))); - assertEquals(0, x >>= x); - assertEquals(0, x *= x); - assertEquals(0, x &= ((tmp = -2389008496.5948563, tmp)|((((tmp = -2635919193.905919, tmp)*((-64464127)<<(2136112830.1317358)))>>((184057979)*(-1204959085.8362718)))>>>(-442946870.3341484)))); - assertEquals(-243793920, x -= ((tmp = 3002998032, tmp)<<((537875759)<<x))); - assertEquals(0, x -= x); - assertEquals(0, x *= ((((66852616.82442963)/((((x^x)&(2975318321.223734))+(((tmp = -1388210811.1249495, tmp)^((((-680567297.7620237)%(x-(tmp = -672906716.4672911, tmp)))-x)*(tmp = -1452125821.0132627, tmp)))*(((2770387154.5427895)%x)%x)))-x))<<((-1481832432.924325)>>(tmp = 3109693867, tmp)))>>>(x/(((((((tmp = 928294418, tmp)^(((-1018314535)/(tmp = -3167523001, tmp))%((((((tmp = -1639338126, tmp)-(tmp = -2613558829, tmp))&x)/x)%(tmp = 513624872, tmp))/((-520660667)&x))))*(2620452414))^((tmp = 2337189239.5949326, tmp)*(3200887846.7954993)))>>>((tmp = 1173330667, tmp)^x))<<x)>>(((tmp = -2475534594.982338, tmp)*x)|x))))); - assertEquals(0, x /= (2520915286)); - assertEquals(0, x &= x); - assertEquals(0, x >>= (-1908119327)); - assertEquals(0, x >>>= (tmp = 549007635, tmp)); - assertEquals(0, x >>= (-994747873.8117285)); - assertEquals(0, x <<= ((((x>>>((-3084793026.846681)%((1107295502)&(tmp = -296613957.8133817, tmp))))&((19637717.166736007)/(x+x)))+x)/(-2479724242))); - assertEquals(-695401420, x += (-695401420)); - assertEquals(-695401394, x += (x>>>(tmp = 2340097307.6556053, tmp))); - assertEquals(-555745552, x -= (x|(-483851950.68644))); - assertEquals(-17825792, x <<= x); - assertEquals(-17825792, x >>= x); - assertEquals(-17, x %= ((tmp = 1799361095, tmp)|((x>>(((-1201252592)<<((((543273288)+(-2859945716.606924))*x)<<((-3030193601)<<(3081129914.9217644))))|((1471431587.981769)>>(-246180750))))|(((tmp = -2689251055.1605787, tmp)>>x)&(((2131333169)^x)-((tmp = -951555489, tmp)/x)))))); - assertEquals(-8912896, x <<= (1146444211)); - assertEquals(2854567584, x += (tmp = 2863480480, tmp)); - assertEquals(426232502.24151134, x %= (1214167540.8792443)); - assertEquals(1806802048, x ^= (-2368317898)); - assertEquals(432537600, x <<= (tmp = 2831272652.589364, tmp)); - assertEquals(432537600, x %= (((1713810619.3880467)-x)&((-2853023009.553296)&(tmp = -3158798098.3355417, tmp)))); - assertEquals(-509804066, x += (tmp = -942341666, tmp)); - assertEquals(-509804066, x %= (-732349220)); - assertEquals(259900185710132350, x *= x); - assertEquals(711598501.7021885, x %= ((tmp = 2020395586.2280731, tmp)-(tmp = 3031459563.1386633, tmp))); - assertEquals(711598503.0618857, x += ((tmp = 967558548.4141241, tmp)/x)); - assertEquals(711598503, x &= x); - assertEquals(711598503, x ^= (((((1609355669.1963444)+((((tmp = -2660082403.258437, tmp)+(tmp = -235367868, tmp))&(x/x))*((-2595932186.69466)|((tmp = -3039202860, tmp)<<x))))>>>(-951354869))-((tmp = -691482949.6335375, tmp)/(tmp = -1735502400, tmp)))/(tmp = 798440377, tmp))); - assertEquals(558262613882868500, x *= (784519095.4299527)); - assertEquals(558262611968479000, x -= ((((tmp = 1039039153.4026555, tmp)/(-3138845051.6240187))*(tmp = 633557994, tmp))&(1981507217))); - assertEquals(1170427648, x |= ((x>>((((-1086327124)%((tmp = -1818798806.368613, tmp)^(tmp = 2183576654.9959817, tmp)))>>x)&((((((tmp = 1315985464.0330539, tmp)&(2774283689.333836))%x)*((2722693772.8994813)&(tmp = -2720671984.945404, tmp)))^(tmp = -76808019, tmp))<<((tmp = 685037799.2336662, tmp)^((tmp = 1057250849, tmp)&(tmp = 1469205111.2989025, tmp))))))+(x*(((tmp = 448288818.47173154, tmp)-(-2527606231))-((8387088.402292728)>>x))))); - assertEquals(558, x >>>= (tmp = 2732701109, tmp)); - assertEquals(558, x &= x); - assertEquals(-0.00015855057024653912, x /= ((x+(((tmp = -1963815633, tmp)-(x>>x))-((x|x)>>x)))/x)); - assertEquals(1.3458861596445712e-13, x /= (-1178038492.4116466)); - assertEquals(0, x <<= (-104550232)); - assertEquals(0, x >>>= (x>>(tmp = -255275244.12613606, tmp))); - assertEquals(0, x >>= x); - assertEquals(375, x |= ((1576819294.6991196)>>>(-2570246122))); - assertEquals(96000, x <<= ((2252913843.0150948)>>>(-49239716))); - assertEquals(6144000, x <<= ((((tmp = -2478967279, tmp)&((x%((tmp = -1705332610.8018858, tmp)+(x+(tmp = 590766349, tmp))))<<(tmp = 1759375933, tmp)))+(-2024465658.849834))&(1564539207.3650014))); - assertEquals(-1149239296, x <<= (1862803657.7241006)); - assertEquals(-9, x >>= (((tmp = 463306384.05696774, tmp)^x)|((x>>((((-2098070856.799663)<<((-2054870274.9012866)<<(((-2582579691)/(829257170.0266814))<<(((((tmp = -1753535573.7074275, tmp)<<((x>>(-197886116))%((2487188445)%(tmp = 2465391564.873364, tmp))))&(((tmp = -500069832, tmp)&(tmp = 3016637032, tmp))&((tmp = 2525942628, tmp)|((((-920996215)|x)^((((tmp = -687548533.419106, tmp)&(1423222636.058937))<<((tmp = -1096532228, tmp)>>((((tmp = -3124481449.2740726, tmp)^(tmp = 2724328271.808975, tmp))>>x)*x)))+(-1661789589.5808442)))+(((x*(tmp = -1224371664.9549093, tmp))^((tmp = 3202970043, tmp)^x))/(tmp = 131494054.58501709, tmp))))))|(((tmp = -1654136720, tmp)<<x)>>((1652979932.362416)-(tmp = -863732721, tmp))))^(-113307998)))))^(-90820449.91417909))*((tmp = 641519890, tmp)-((((x<<(tmp = 2349936514.071881, tmp))*(2324420443.587892))^x)%(x<<((tmp = -1838473742, tmp)/(((-3154172718.4274178)-x)+x)))))))|(x>>>((tmp = 2096024376.4308293, tmp)<<x))))); - assertEquals(81, x *= x); - assertEquals(81, x &= x); - assertEquals(81, x %= (tmp = 2223962994, tmp)); - assertEquals(81, x ^= ((x/(((-1606183420.099584)|(-1242175583))&(((x|((tmp = 828718431.3311573, tmp)/(x>>x)))+(((-2207542725.4531174)^(x*x))*(tmp = 551575809.955105, tmp)))/x)))&((x>>x)&x))); - assertEquals(81, x %= (tmp = 279598358.6976975, tmp)); - assertEquals(101.72338484518858, x -= (((tmp = 2452584495.44003, tmp)%((-1181192721)+(((x>>(((x&x)^x)+((x>>>((x+(-2472793823.57181))/(((2854104951)>>(-1208718359.6554642))>>>(1089411895.694705))))/(x|(-2821482890.1780205)))))^(-1786654551))/(-29404242.70557475))))/(((-4352531)<<((-1227287545)<<x))%(-2558589438)))); - assertEquals(101.72338484518858, x %= (-943645643)); - assertEquals(0, x -= x); - assertEquals(0, x >>>= (-2440404084)); - assertEquals(0, x >>= (tmp = 1029680958.405923, tmp)); - assertEquals(0, x >>>= (1213820208.7204895)); - assertEquals(-0, x /= (tmp = -103093683, tmp)); - assertEquals(0, x >>>= (-2098144813)); - assertEquals(-0, x /= (((-3087283334)+(((tmp = -3129028112.6859293, tmp)%(tmp = 2413829931.1605015, tmp))-(2578195237.8071446)))|x)); - assertEquals(-15, x |= ((((-178926550.92823577)>>>(-965071271))^((tmp = -484633724.7237625, tmp)-(tmp = 473098919.1486404, tmp)))>>((-2264998310.203265)%(tmp = -499034672, tmp)))); - assertEquals(0, x ^= x); - assertEquals(0, x >>= (((-3207915976.698118)<<(tmp = 2347058630, tmp))|(tmp = -2396250098.559627, tmp))); - assertEquals(NaN, x %= x); - assertEquals(NaN, x *= (621843222)); - assertEquals(0, x >>= (((-2409032228.7238913)*x)-(tmp = -887793239, tmp))); - assertEquals(NaN, x /= x); - assertEquals(1193017666, x ^= (tmp = 1193017666, tmp)); - assertEquals(3.5844761899682753, x /= (tmp = 332829011.206393, tmp)); - assertEquals(-888572929, x |= (((tmp = 1032409228, tmp)+(tmp = -1920982163.7853453, tmp))+x)); - assertEquals(-1817051951333455600, x *= (((-1506265102)^(tmp = -775881816, tmp))-(tmp = -32116372.59181881, tmp))); - assertEquals(-1638479616, x |= x); - assertEquals(-114489, x %= (((tmp = -247137297.37866855, tmp)>>>((((((-322805409)-x)^x)>>((((((((x>>>(tmp = -900610424.7148039, tmp))/(-1155208489.6240904))|((-2874045803)|(tmp = 3050499811, tmp)))+(x/((tmp = -613902712, tmp)^((-982142626.2892077)*((((tmp = -3201753245.6026397, tmp)|((1739238762.0423079)^x))/(243217629.47237313))^((tmp = -11944405.987132788, tmp)/(tmp = 2054031985.633406, tmp)))))))*(tmp = 2696108952.450961, tmp))*x)>>>(tmp = 3058430643.0660386, tmp))>>(x<<x)))>>(-984468302.7450335))%((tmp = 1302320585.246251, tmp)>>>x)))%(tmp = -2436842285.8208156, tmp))); - assertEquals(2047, x >>>= (2380161237)); - assertEquals(0, x >>= x); - assertEquals(0, x &= (tmp = 980821012.975836, tmp)); - assertEquals(-1090535537, x -= ((-3064511503.1214876)&((tmp = -2598316939.163751, tmp)<<((tmp = -969452391.8925576, tmp)*x)))); - assertEquals(-2181071074, x += x); - assertEquals(1, x >>>= ((2902525386.449062)>>x)); - assertEquals(1, x += (x&(tmp = -2643758684.6636515, tmp))); - assertEquals(1, x %= ((tmp = -2646526891.7004848, tmp)/x)); - assertEquals(448735695.7888887, x -= (tmp = -448735694.7888887, tmp)); - assertEquals(1, x /= x); - assertEquals(1, x >>= ((-480385726)<<(2641021142))); - assertEquals(1, x %= (375099107.9200462)); - assertEquals(1, x >>= (((x&((tmp = -2402469116.9903326, tmp)%(tmp = -2862459555.860298, tmp)))*(tmp = -2834162871.0586414, tmp))%(((x>>>(tmp = 721589907.5073895, tmp))*(x^x))%(((tmp = 2844611489.231776, tmp)^((983556913)&(906035409.6693488)))^(x>>>(1239322375)))))); - assertEquals(268435456, x <<= (tmp = 178807644.80966163, tmp)); - assertEquals(44, x %= ((tmp = 2527026779.081539, tmp)>>>(2736129559))); - assertEquals(88, x += x); - assertEquals(0, x >>>= x); - assertEquals(0, x -= x); - assertEquals(-1523121602, x |= (2771845694)); - assertEquals(-2, x >>= x); - assertEquals(-4, x += x); - assertEquals(-256, x <<= (((2522793132.8616533)>>(tmp = 77232772.94058788, tmp))+(3118669244.49152))); - assertEquals(4294967040, x >>>= x); - assertEquals(-256, x &= x); - assertEquals(1278370155.835435, x -= (-1278370411.835435)); - assertEquals(-3.488228054921667, x /= (tmp = -366481243.6881058, tmp)); - assertEquals(1.162742684973889, x /= ((x|(((((2404819175.562809)*(tmp = -2524589506, tmp))&(tmp = -675727145, tmp))>>>(x*x))&((-413250006)<<(tmp = 2408322715, tmp))))|((2940367603)>>>x))); - assertEquals(0, x >>>= ((2513665793)-(tmp = 1249857454.3367786, tmp))); - assertEquals(0, x ^= x); - assertEquals(0, x ^= x); - assertEquals(1989998348.6336238, x -= (-1989998348.6336238)); - assertEquals(903237918.986834, x %= (1086760429.6467898)); - assertEquals(-4.4185765232981975, x /= (-204418304)); - assertEquals(1471621914, x ^= (tmp = -1471621914.1771696, tmp)); - assertEquals(1471621914, x |= ((((((x<<(tmp = -2676407394.536844, tmp))%(((343324258)+(x/(x>>(((-221193011)>>>x)|x))))>>(((-2737713893)^((tmp = -49214797.00735545, tmp)+((-2818106123.172874)/(tmp = -2361786565.3028684, tmp))))<<(1859353297.6355076))))*(tmp = -751970685, tmp))|((tmp = 2502717391.425871, tmp)/(tmp = -2647169430, tmp)))*((tmp = -1647567294, tmp)&(((tmp = 1819557651, tmp)/x)>>((((-3073469753)/x)-(((tmp = -1973810496.6407511, tmp)&((x-(x+(tmp = -2986851659, tmp)))>>>(tmp = -2226975699, tmp)))|(418770782.142766)))<<x))))*(((((tmp = 125466732, tmp)/((((1453655756.398259)|(((874792086.7064595)-(194880772.91499102))>>>x))%(x<<(tmp = -1445557137, tmp)))<<x))>>>(tmp = -1953751906, tmp))/((tmp = -2140573172.2979035, tmp)*((-108581964)^x)))|(-481484013.0393069)))); - assertEquals(1454179065, x += ((tmp = 947147038.2829313, tmp)|(tmp = -154822975.3629098, tmp))); - assertEquals(1, x /= x); - assertEquals(1, x %= ((((((tmp = -2262250297.991866, tmp)-(tmp = 481953960, tmp))/(1629215187.6020458))|(2515244216))>>>((tmp = -3040594752.2184515, tmp)-(tmp = -1116041279, tmp)))^(((-182133502)-(1065160192.6609197))+(((((-1850040207)^(tmp = -1570328610, tmp))^(tmp = 20542725.09256518, tmp))*x)|(2386866629))))); - assertEquals(1, x &= (2889186303)); - assertEquals(0, x >>= (((-1323093107.050538)>>(x%x))-(((((((-1736522840)+(tmp = -2623890690.8318863, tmp))*(959395040.5565329))*(233734920))<<((x+(x%((tmp = -2370717284.4370327, tmp)%(tmp = 2109311949, tmp))))-(tmp = -1005532894, tmp)))|(861703605))>>>((2399820772)/x)))); - assertEquals(0, x >>= x); - assertEquals(57233408, x |= ((tmp = 2655923764.4179816, tmp)*(-1353634624.3025436))); - assertEquals(997939728, x |= (980552208.9005274)); - assertEquals(1859642592476610800, x *= (1863481872)); - assertEquals(-977190656, x <<= x); - assertEquals(4.378357529141239e+26, x *= ((((x/(((tmp = 2429520991, tmp)/(x/(tmp = 784592802, tmp)))-(tmp = -2704781982, tmp)))*(tmp = -2161015768.2322354, tmp))&((((-3164868762)>>(tmp = 2390893153.32907, tmp))^x)>>(-2422626718.322538)))*(tmp = 278291869, tmp))); - assertEquals(4.378357529141239e+26, x -= (1710777896.992369)); - assertEquals(0, x &= (((((tmp = -2532956158.400033, tmp)|((2195255831.279001)|(1051047432)))|(-1628591858))|(tmp = -2042607521.947963, tmp))>>((-1471225208)/(((-133621318)>>(1980416325.7358408))*((1741069593.1036062)-(x|(2133911581.991011))))))); - assertEquals(-0, x /= (-656083507)); - assertEquals(NaN, x += ((tmp = -1071410982.2789869, tmp)%x)); - assertEquals(NaN, x *= (tmp = -1513535145.3146675, tmp)); - assertEquals(0, x >>= ((2831245247.5267224)>>(x<<((x+(((3068824580.7922907)|(1708295544.275714))*((tmp = -1662930228.1170444, tmp)-(((tmp = 1979994889, tmp)<<(tmp = -1826911988, tmp))&((x/(x<<(1909384611.043981)))+(1958052414.7139997))))))<<(tmp = 2481909816.56558, tmp))))); - assertEquals(0, x *= (((tmp = -2979739958.1614842, tmp)&x)+x)); - assertEquals(-0, x *= ((-332769864.50313234)^x)); - assertEquals(0, x >>= ((((689018886.1436445)+(tmp = -2819546038.620694, tmp))|(((tmp = -1459669934.9066005, tmp)|x)/x))<<(((tmp = 2640360389, tmp)/((x%((-1947492547.9056122)%((1487212416.2083092)-(-1751984129))))^x))%(tmp = 2666842881, tmp)))); - assertEquals(-1801321460, x |= (tmp = 2493645836, tmp)); - assertEquals(-1801321460, x %= (2400405136)); - assertEquals(-2905399858195810300, x *= (tmp = 1612926911, tmp)); - assertEquals(-2905399858195810300, x -= (x>>(tmp = 1603910263.9593458, tmp))); - assertEquals(-238798848, x &= ((tmp = -2638646212.767516, tmp)/(((tmp = 1755616291.436998, tmp)>>>(tmp = 1083349775, tmp))-(x%(((tmp = 1728859105.53634, tmp)^(1931522619.0403612))/(tmp = 712460587.0025489, tmp)))))); - assertEquals(-2363873607.2302856, x += (-2125074759.230286)); - assertEquals(1712665, x &= (((117229515)>>>(((1707090894.1915488)>>>((-1696008695)>>(((-1045367326.7522249)<<(tmp = -209334716, tmp))-x)))|(-1707909786.080653)))%(1260761349.172689))); - assertEquals(1073741824, x <<= (tmp = -289437762.34742975, tmp)); - assertEquals(1073741824, x &= (tmp = 2079141140, tmp)); - assertEquals(0, x <<= ((x^(-3139646716.1615124))-(((-362323071.74237394)|(tmp = 2989896849, tmp))*(tmp = -218217991, tmp)))); - assertEquals(0, x &= (tmp = -1476835288.425903, tmp)); - assertEquals(0, x >>>= (tmp = 61945262.70868635, tmp)); - assertEquals(0, x ^= x); - assertEquals(-2735263498.7189775, x -= (2735263498.7189775)); - assertEquals(-1182289920, x <<= (x+x)); - assertEquals(-1182289580, x ^= ((2858446263.2258)>>>(2387398039.6273785))); - assertEquals(696693056, x &= ((2178665823)*(-51848583))); - assertEquals(1652555776, x <<= (((tmp = 2943916975, tmp)-((-1544273901)>>(-1671503106.2896929)))|x)); - assertEquals(6455296, x >>>= (tmp = 1492638248.675439, tmp)); - assertEquals(2097152, x &= (((x|x)*(2873891571.7000637))^((2165264807)+(tmp = 451721563, tmp)))); - assertEquals(2097152, x %= (tmp = 1089484582.1455994, tmp)); - assertEquals(2097152, x <<= x); - assertEquals(2097152, x &= ((tmp = 119096343.4032247, tmp)^((-1947874541)*x))); - assertEquals(0, x &= (tmp = 2363070677, tmp)); - assertEquals(0, x &= ((tmp = -1897325383, tmp)>>>((2368480527)>>>((tmp = 1837528979, tmp)*(-1838904077))))); - assertEquals(-1898659416, x ^= (-1898659416.1125412)); - assertEquals(-725506048, x <<= x); - assertEquals(1392943104, x <<= (295287938.9104482)); - assertEquals(-63620329, x ^= ((tmp = -3175925826.5573816, tmp)-(tmp = 2474613927, tmp))); - assertEquals(-1135111726, x -= ((tmp = -1133259081, tmp)^(((tmp = -742228219, tmp)>>((-7801909.587711811)%((tmp = -642758873, tmp)+(tmp = 2893927824.6036444, tmp))))^((tmp = -2145465178.9142997, tmp)+x)))); - assertEquals(0, x ^= x); - assertEquals(660714589, x |= (660714589)); - assertEquals(660714676, x ^= ((-376720042.8047826)>>>(2196220344))); - assertEquals(660714676, x |= ((((((((x<<(-1140465568))-(tmp = -1648489774.1573918, tmp))%(((tmp = -2955505390.573639, tmp)*x)<<((((tmp = -1769375963, tmp)*(tmp = -440619797, tmp))&((tmp = 1904284066, tmp)%(-2420852665.0629807)))+(-324601009.2063596))))>>(tmp = 2317210783.9757776, tmp))^((tmp = 750057067.4541628, tmp)^(tmp = -1391814244.7286487, tmp)))>>((344544658.6054913)%((tmp = -1508630423.218488, tmp)&(tmp = 1918909238.2974637, tmp))))>>((-647746783.685822)&(tmp = 2444858958.3595476, tmp)))&x)); - assertEquals(-962337195, x ^= (tmp = -507358495.30825853, tmp)); - assertEquals(-182008925.58535767, x %= (tmp = -195082067.35366058, tmp)); - assertEquals(502070, x >>>= (tmp = 1459732237.1447744, tmp)); - assertEquals(-2391009930.7235765, x -= (tmp = 2391512000.7235765, tmp)); - assertEquals(1568669696, x <<= x); - assertEquals(0, x <<= (tmp = -571056688.2717848, tmp)); - assertEquals(1770376226, x ^= (tmp = 1770376226.0584736, tmp)); - assertEquals(0, x ^= x); - assertEquals(0, x &= ((((x<<x)>>>x)|x)|(((tmp = -2141573723, tmp)^x)|(64299956)))); - assertEquals(0, x ^= x); - assertEquals(0, x &= x); - assertEquals(0, x <<= (1106060336.7362857)); - assertEquals(-0, x /= (x|(tmp = 2760823963, tmp))); - assertEquals(0, x <<= ((-2436225757)|(-1800598694.4062433))); - assertEquals(0, x >>>= ((-728332508.9870625)<<x)); - assertEquals(-173377680, x ^= ((tmp = -173377680, tmp)%(tmp = -2843994892, tmp))); - assertEquals(-173377680, x |= ((((-819217898)&(tmp = -1321650255, tmp))&(x+((x^x)<<((1700753064)>>((((((-1038799327)>>((782275464)^x))-(tmp = -2113814317.8539028, tmp))>>(2143804838))&x)-((2970418921)/(-3073015285.6587048)))))))&((-1759593079.4077306)%((1699128805)-((tmp = -467193967, tmp)&(((2225788267.3466334)*(((2687946762.5504274)+x)>>>x))<<(-1853556066.880512))))))); - assertEquals(-0.5520657226957338, x /= ((tmp = -755493878, tmp)&(tmp = 918108389, tmp))); - assertEquals(0.30477656217556287, x *= x); - assertEquals(0, x &= ((tmp = -2746007517, tmp)<<(2749629340))); - assertEquals(0, x ^= ((x%(tmp = 1683077876, tmp))%(-162706778))); - assertEquals(0, x *= (tmp = 10203423, tmp)); - assertEquals(119043212.1461842, x += (tmp = 119043212.1461842, tmp)); - assertEquals(587202560, x <<= (tmp = 658697910.7051642, tmp)); - assertEquals(-138689730, x |= (x-(tmp = 1296317634.5661907, tmp))); - assertEquals(-138663011, x -= ((-1751010109.5506423)>>(152829872))); - assertEquals(-138663011, x %= (-1266200468)); - assertEquals(-138663011, x &= (x|((tmp = -571277275.622529, tmp)<<x))); - assertEquals(-138663011, x >>= ((971259905.1265712)*(tmp = 2203764981, tmp))); - assertEquals(-138663011, x %= (-904715829)); - assertEquals(-138663011, x |= ((tmp = -2823047885.283391, tmp)>>>(((tmp = 533217000, tmp)|(650754598.7836078))|(-1475565890)))); - assertEquals(-1610612736, x <<= x); - assertEquals(-1610612736, x &= x); - assertEquals(163840, x >>>= (-188885010)); - assertEquals(-1224224814, x |= (tmp = 3070742482, tmp)); - assertEquals(1498726395213334500, x *= x); - assertEquals(1723591210, x |= ((tmp = 615164458, tmp)|x)); - assertEquals(1721910480, x ^= (x>>>x)); - assertEquals(4505284605.764313, x -= (tmp = -2783374125.7643127, tmp)); - assertEquals(-9504912393868483000, x *= (((tmp = 2896651872, tmp)<<(-2896385692.9017262))&(((((tmp = -2081179810.20238, tmp)|(tmp = -2484863999, tmp))>>((tmp = 1560885110.2665749, tmp)/(((tmp = 934324123.4289343, tmp)<<((tmp = -1591614157.0496385, tmp)+x))/(((x%(((tmp = 1672629986.8055913, tmp)%x)>>(tmp = 2116315086.2559657, tmp)))/(((-2687682697.5806303)>>x)/(-2034391222.5029132)))%(x-((((((tmp = 2598594967, tmp)/(((((((2950032233)%x)/x)^(tmp = -2126753451.3732262, tmp))<<(tmp = -3019113473, tmp))+(tmp = -2021220129.2320697, tmp))%((((-587645875.4666483)>>(((((x+x)+x)&(tmp = 533801785, tmp))|x)-((tmp = -2224808495.678903, tmp)/(1501942300))))>>>(-2558947646))>>((2798508249.020792)>>>x))))>>>((1060584557)/((((((((x&x)|(1426725365))>>>(tmp = 1500508838, tmp))>>(-1328705938))*((tmp = -2288009425.598777, tmp)>>>(((2586897285.9759064)%((-1605651559.2122297)>>>(tmp = 1936736684.4887302, tmp)))+((tmp = 2316261040, tmp)^(570340750.353874)))))&(x^((tmp = -2266524143, tmp)-(tmp = 2358520476, tmp))))+(tmp = 1449254900.9222453, tmp))%((-100598196)%((tmp = -2985318242.153491, tmp)>>((620722274.4565848)>>(871118975)))))))<<x)*(tmp = -1287065606.4143271, tmp))>>>(1038059916.2438471)))))))+((x/(-276990308.1264961))&(tmp = 2471016351.2195315, tmp)))|(((((tmp = -1288792769.3210807, tmp)+((tmp = -641817194, tmp)*(x<<(((-1933817364)>>(((tmp = 2084673536, tmp)|x)&x))&(tmp = -2752464480, tmp)))))%((796026752)*x))+(((tmp = -3083359669, tmp)|x)-((715303522)|(tmp = 181297266, tmp))))*(-1691520182.3207517))))); - assertEquals(0, x <<= (-2322389800)); - assertEquals(0, x *= (tmp = 3188682235, tmp)); - assertEquals(0, x |= (x>>>((tmp = -2729325231.8288336, tmp)^((-393497076.96012783)*(x/(tmp = -2198942459.9466457, tmp)))))); - assertEquals(0, x ^= x); - assertEquals(0, x %= (2835024997.4447937)); - assertEquals(0, x <<= x); - assertEquals(0, x >>= (tmp = 1109824126, tmp)); - assertEquals(0, x <<= (3013043386)); - assertEquals(206825782.74659085, x -= (-206825782.74659085)); - assertEquals(-645346761227699500, x *= (-3120243292)); - assertEquals(6825462, x >>= ((tmp = 1457908135, tmp)<<x)); - assertEquals(-612366097.9189918, x -= (619191559.9189918)); - assertEquals(-612306090.9189918, x -= ((2328676543.893506)>>x)); - assertEquals(0, x ^= (x>>(((x>>>(1856200611.2269292))&(tmp = 2003217473, tmp))%((((((-107135673)+(((3062079356.170611)<<(tmp = -676928983, tmp))>>((tmp = -1487074941.2638814, tmp)|((-1601614031)/(1317006144.5025365)))))+x)*(((1163301641)>>>(448796567))/((x%((tmp = 72293197.34410787, tmp)+(-2304112723)))/((455610361)%(-2799431520)))))>>>(-217305041.09432888))<<(x-(tmp = -2168353649, tmp)))))); - assertEquals(0, x >>= x); - assertEquals(-Infinity, x -= (((-1651597599.8950624)+(1780404320))/x)); - assertEquals(0, x <<= (tmp = 2246420272.4321294, tmp)); - assertEquals(0, x *= ((2793605382)-(tmp = -272299011, tmp))); - assertEquals(0, x *= x); - assertEquals(0, x <<= x); - assertEquals(0, x >>= (tmp = 2556413090, tmp)); - assertEquals(0, x >>= ((tmp = -1784710085, tmp)%x)); - assertEquals(0, x %= (tmp = -1929880813, tmp)); - assertEquals(0, x *= (2586983368)); - assertEquals(0, x &= x); - assertEquals(0, x <<= (-2144588807)); - assertEquals(0, x ^= ((x<<(((((((-596537598)+((x-(((((((tmp = -3179604796, tmp)/((tmp = 1156725365.3543215, tmp)>>>(tmp = -2762144319, tmp)))%(x<<x))&((tmp = 1750241928.1271567, tmp)&(x/((tmp = 1781306819, tmp)|x))))+((((2893068644)/((tmp = -576164593.9720252, tmp)<<((2724671.48995471)&(tmp = -573132475, tmp))))%(tmp = -1355625108, tmp))&(tmp = -302869512.5880568, tmp)))+x)<<x))>>((tmp = -2569172808, tmp)/x)))^x)-(tmp = -1174006275.2213159, tmp))&x)&(((((((-2303274799)>>(tmp = -814839320, tmp))/(tmp = 183887306.09810615, tmp))>>(((tmp = 1054106394.3704875, tmp)|x)>>>x))-(x-(tmp = 1313696830, tmp)))-((tmp = 2373274399.0742035, tmp)|((((tmp = -3163779539.4902935, tmp)*(tmp = -3056125181.726942, tmp))&(((x^(x^(x/((tmp = -576441696.6015451, tmp)<<(tmp = -26223719.920306206, tmp)))))>>(tmp = -2332835940, tmp))|((-146303509.41093707)&(tmp = -2676964025, tmp))))/((((x*(tmp = 1059918020, tmp))|((((2341797349)|(tmp = -744763805.1381104, tmp))<<x)+((2991320875.552578)^(2920702604.701831))))^(-1721756138))^(((tmp = -2794367554, tmp)>>((-2671235923.2097874)<<(x&((((tmp = -621472314.0859051, tmp)-(((x*x)+x)>>>((tmp = 1834038956, tmp)+x)))*x)^(tmp = -2090567586.321468, tmp)))))<<(321395210))))))>>>(tmp = -1207661719, tmp)))+(-2877264053.3805156)))/(x%(tmp = -2226991657.709366, tmp)))); - assertEquals(0, x *= (tmp = 986904991.061398, tmp)); - assertEquals(0, x -= (x%(650819306.6671969))); - assertEquals(0, x >>>= (905893666.2871252)); - assertEquals(0, x += (((tmp = 2501942710.4804144, tmp)&x)/((tmp = -851080399.1751502, tmp)-(-1168623992)))); - assertEquals(-0, x *= (tmp = -2014577821.4554045, tmp)); - assertEquals(0, x &= (tmp = 1995246018, tmp)); - assertEquals(0, x %= (1724355237.7031958)); - assertEquals(-954696411, x += (((-2825222201)+(((1662353496.1795506)>>>(x-x))|(tmp = 225015046, tmp)))^(x&x))); - assertEquals(-2158427339993389800, x *= (2260852052.1539803)); - assertEquals(19559, x >>>= (-862409169.4978967)); - assertEquals(-0.000012241163878671237, x /= (x^(tmp = 2697144215.160239, tmp))); - assertEquals(0, x -= x); - assertEquals(1448177644, x |= (tmp = 1448177644.624848, tmp)); - assertEquals(1448177644, x %= (((-1497553637.4976408)+(402228446))<<x)); - assertEquals(2304640553, x -= (-856462909)); - assertEquals(152436736, x &= ((766686903)*(((tmp = 660964683.1744609, tmp)|((((tmp = 297369746, tmp)-(x+((tmp = -2677127146, tmp)/x)))>>(((((((x%(x<<x))-(((((529254728)|((x|(-1407086127.6088922))&(tmp = -1968465008.5000398, tmp)))/(x%x))&((((-2761805265.92574)-x)*(x^(tmp = 110730179, tmp)))%((177220657.06030762)*(((2532585190.671373)/x)+(-1465143151)))))<<((tmp = -3008848338, tmp)<<(-2475597073))))|((-192996756.38619018)|((((1445996780)|(x>>>((((tmp = -2482370545.791443, tmp)*(tmp = -270543594, tmp))^x)*((1346780586)/(tmp = -625613363.885356, tmp)))))-(x<<(x/(-562307527))))&(-125701272))))*((x&x)%(tmp = 752963070, tmp)))>>>(tmp = 17419750.79086232, tmp))*x)^(x^((-157821212.04674292)-(tmp = 503849221.598824, tmp)))))-(tmp = 1479418449, tmp)))>>>((((((-78138548.2193842)<<(((2319032860.806689)-(tmp = -1564963892.5137577, tmp))>>>(-73673322.28957987)))<<((1797573493.3467085)*x))>>(tmp = 759994997, tmp))>>>(-1066441220))&(((((((tmp = 1972048857, tmp)*(((x&((-1347017320.0747669)>>>x))*(-2332716925.705054))%(-376976019.24362826)))>>>((tmp = -466479974, tmp)+x))&(-2282789473.3675604))|(((((((((269205423.7510414)-(tmp = 21919626.105656862, tmp))*((x-(tmp = -378670528, tmp))>>(tmp = -1045706598, tmp)))>>(tmp = -3062647341.234485, tmp))>>>x)|(tmp = -285399599.9386575, tmp))%(tmp = 2731214562, tmp))|((((tmp = 837093165.3438574, tmp)|(tmp = -2956931321, tmp))+((1871874558.3292787)<<((x|((tmp = -3169147427, tmp)%(((x^x)%(1479885041))%((1769991217)%(tmp = -1899472458, tmp)))))*(tmp = -837098563.71806, tmp))))>>(tmp = -1866722748, tmp)))-(2037734340.8345597)))>>((tmp = -1262019180.5332131, tmp)+(x*(1274173993.9800131))))*(tmp = 2336989321.855402, tmp)))))); - assertEquals(4, x >>= (tmp = -2577728327, tmp)); - assertEquals(16, x *= (x<<((2622323372.580596)*(tmp = -1947643367, tmp)))); - assertEquals(33554432, x <<= (tmp = -2938370507, tmp)); - assertEquals(-2399497018.987414, x -= (tmp = 2433051450.987414, tmp)); - assertEquals(1, x /= x); - assertEquals(2, x <<= x); - assertEquals(0, x >>= (x&x)); - assertEquals(0, x <<= x); -} -f(); diff --git a/deps/v8/test/mjsunit/object-define-property.js b/deps/v8/test/mjsunit/object-define-property.js index bd104aaf0b..970a803349 100644 --- a/deps/v8/test/mjsunit/object-define-property.js +++ b/deps/v8/test/mjsunit/object-define-property.js @@ -1057,7 +1057,7 @@ assertEquals(999, o[999]); // Regression test: Bizzare behavior on non-strict arguments object. -// TODO(mstarzinger): Tests disabled, see bug 2261 +// TODO(yangguo): Tests disabled, needs investigation! /* (function test(arg0) { // Here arguments[0] is a fast alias on arg0. diff --git a/deps/v8/test/mjsunit/pixel-array-rounding.js b/deps/v8/test/mjsunit/pixel-array-rounding.js index 0c307e62e5..0c307e62e5 100644..100755 --- a/deps/v8/test/mjsunit/pixel-array-rounding.js +++ b/deps/v8/test/mjsunit/pixel-array-rounding.js diff --git a/deps/v8/test/mjsunit/regexp-capture-3.js b/deps/v8/test/mjsunit/regexp-capture-3.js index b676f01c2c..b676f01c2c 100644..100755 --- a/deps/v8/test/mjsunit/regexp-capture-3.js +++ b/deps/v8/test/mjsunit/regexp-capture-3.js diff --git a/deps/v8/test/mjsunit/regress/regress-1117.js b/deps/v8/test/mjsunit/regress/regress-1117.js index b013a223ec..981a1b7a3f 100644 --- a/deps/v8/test/mjsunit/regress/regress-1117.js +++ b/deps/v8/test/mjsunit/regress/regress-1117.js @@ -25,11 +25,20 @@ // (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 we actually return the right value (-0) when we multiply // constant 0 with a negative integer. function foo(y) {return 0 * y; } -for( var i = 0; i< 1000000; i++){ - foo(42); -} assertEquals(1/foo(-42), -Infinity); +assertEquals(1/foo(-42), -Infinity); +%OptimizeFunctionOnNextCall(foo); +assertEquals(1/foo(-42), -Infinity); + +function bar(x) { return x * 0; } +assertEquals(Infinity, 1/bar(5)); +assertEquals(Infinity, 1/bar(5)); +%OptimizeFunctionOnNextCall(bar); +assertEquals(-Infinity, 1/bar(-5)); + diff --git a/deps/v8/test/mjsunit/regress/regress-121407.js b/deps/v8/test/mjsunit/regress/regress-121407.js index 25033fb525..4403708184 100644 --- a/deps/v8/test/mjsunit/regress/regress-121407.js +++ b/deps/v8/test/mjsunit/regress/regress-121407.js @@ -37,4 +37,4 @@ 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-143967.js b/deps/v8/test/mjsunit/regress/regress-143967.js new file mode 100644 index 0000000000..7c12e67153 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-143967.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. + +// Check that Accessors::FunctionGetPrototype traverses the prototype +// chain correctly and doesn't get stuck. + +var functionWithoutProto = [].filter; +var obj = Object.create(functionWithoutProto); +functionWithoutProto.__proto__ = function() {}; +assertEquals(functionWithoutProto.prototype, obj.prototype); diff --git a/deps/v8/test/mjsunit/regress/regress-1692.js b/deps/v8/test/mjsunit/regress/regress-1692.js index 06bd66cf7f..32be87f989 100644 --- a/deps/v8/test/mjsunit/regress/regress-1692.js +++ b/deps/v8/test/mjsunit/regress/regress-1692.js @@ -82,7 +82,7 @@ var o = Object("string"); // Non-string property on String object. o[10] = 42; assertTrue(o.propertyIsEnumerable(10)); -assertFalse(o.propertyIsEnumerable(0)); +assertTrue(o.propertyIsEnumerable(0)); // Fast elements. var o = [1,2,3,4,5]; diff --git a/deps/v8/test/mjsunit/regress/regress-1969.js b/deps/v8/test/mjsunit/regress/regress-1969.js deleted file mode 100644 index 2728c2cae7..0000000000 --- a/deps/v8/test/mjsunit/regress/regress-1969.js +++ /dev/null @@ -1,5045 +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. - -// Flags: --allow-natives-syntax - -f(); -f(); -%OptimizeFunctionOnNextCall(f); -var start = (new Date()).getTime(); -var array = f(); -var end = (new Date()).getTime(); - -// Assert that recompiling and executing f() takes less than a second. -assertTrue((end - start) < 1000); - -for (var i = 0; i < 5000; i++) assertEquals(0, array[i]); - -function f() { - var a = new Array(5000); - a[0]=0; - a[1]=0; - a[2]=0; - a[3]=0; - a[4]=0; - a[5]=0; - a[6]=0; - a[7]=0; - a[8]=0; - a[9]=0; - a[10]=0; - a[11]=0; - a[12]=0; - a[13]=0; - a[14]=0; - a[15]=0; - a[16]=0; - a[17]=0; - a[18]=0; - a[19]=0; - a[20]=0; - a[21]=0; - a[22]=0; - a[23]=0; - a[24]=0; - a[25]=0; - a[26]=0; - a[27]=0; - a[28]=0; - a[29]=0; - a[30]=0; - a[31]=0; - a[32]=0; - a[33]=0; - a[34]=0; - a[35]=0; - a[36]=0; - a[37]=0; - a[38]=0; - a[39]=0; - a[40]=0; - a[41]=0; - a[42]=0; - a[43]=0; - a[44]=0; - a[45]=0; - a[46]=0; - a[47]=0; - a[48]=0; - a[49]=0; - a[50]=0; - a[51]=0; - a[52]=0; - a[53]=0; - a[54]=0; - a[55]=0; - a[56]=0; - a[57]=0; - a[58]=0; - a[59]=0; - a[60]=0; - a[61]=0; - a[62]=0; - a[63]=0; - a[64]=0; - a[65]=0; - a[66]=0; - a[67]=0; - a[68]=0; - a[69]=0; - a[70]=0; - a[71]=0; - a[72]=0; - a[73]=0; - a[74]=0; - a[75]=0; - a[76]=0; - a[77]=0; - a[78]=0; - a[79]=0; - a[80]=0; - a[81]=0; - a[82]=0; - a[83]=0; - a[84]=0; - a[85]=0; - a[86]=0; - a[87]=0; - a[88]=0; - a[89]=0; - a[90]=0; - a[91]=0; - a[92]=0; - a[93]=0; - a[94]=0; - a[95]=0; - a[96]=0; - a[97]=0; - a[98]=0; - a[99]=0; - a[100]=0; - a[101]=0; - a[102]=0; - a[103]=0; - a[104]=0; - a[105]=0; - a[106]=0; - a[107]=0; - a[108]=0; - a[109]=0; - a[110]=0; - a[111]=0; - a[112]=0; - a[113]=0; - a[114]=0; - a[115]=0; - a[116]=0; - a[117]=0; - a[118]=0; - a[119]=0; - a[120]=0; - a[121]=0; - a[122]=0; - a[123]=0; - a[124]=0; - a[125]=0; - a[126]=0; - a[127]=0; - a[128]=0; - a[129]=0; - a[130]=0; - a[131]=0; - a[132]=0; - a[133]=0; - a[134]=0; - a[135]=0; - a[136]=0; - a[137]=0; - a[138]=0; - a[139]=0; - a[140]=0; - a[141]=0; - a[142]=0; - a[143]=0; - a[144]=0; - a[145]=0; - a[146]=0; - a[147]=0; - a[148]=0; - a[149]=0; - a[150]=0; - a[151]=0; - a[152]=0; - a[153]=0; - a[154]=0; - a[155]=0; - a[156]=0; - a[157]=0; - a[158]=0; - a[159]=0; - a[160]=0; - a[161]=0; - a[162]=0; - a[163]=0; - a[164]=0; - a[165]=0; - a[166]=0; - a[167]=0; - a[168]=0; - a[169]=0; - a[170]=0; - a[171]=0; - a[172]=0; - a[173]=0; - a[174]=0; - a[175]=0; - a[176]=0; - a[177]=0; - a[178]=0; - a[179]=0; - a[180]=0; - a[181]=0; - a[182]=0; - a[183]=0; - a[184]=0; - a[185]=0; - a[186]=0; - a[187]=0; - a[188]=0; - a[189]=0; - a[190]=0; - a[191]=0; - a[192]=0; - a[193]=0; - a[194]=0; - a[195]=0; - a[196]=0; - a[197]=0; - a[198]=0; - a[199]=0; - a[200]=0; - a[201]=0; - a[202]=0; - a[203]=0; - a[204]=0; - a[205]=0; - a[206]=0; - a[207]=0; - a[208]=0; - a[209]=0; - a[210]=0; - a[211]=0; - a[212]=0; - a[213]=0; - a[214]=0; - a[215]=0; - a[216]=0; - a[217]=0; - a[218]=0; - a[219]=0; - a[220]=0; - a[221]=0; - a[222]=0; - a[223]=0; - a[224]=0; - a[225]=0; - a[226]=0; - a[227]=0; - a[228]=0; - a[229]=0; - a[230]=0; - a[231]=0; - a[232]=0; - a[233]=0; - a[234]=0; - a[235]=0; - a[236]=0; - a[237]=0; - a[238]=0; - a[239]=0; - a[240]=0; - a[241]=0; - a[242]=0; - a[243]=0; - a[244]=0; - a[245]=0; - a[246]=0; - a[247]=0; - a[248]=0; - a[249]=0; - a[250]=0; - a[251]=0; - a[252]=0; - a[253]=0; - a[254]=0; - a[255]=0; - a[256]=0; - a[257]=0; - a[258]=0; - a[259]=0; - a[260]=0; - a[261]=0; - a[262]=0; - a[263]=0; - a[264]=0; - a[265]=0; - a[266]=0; - a[267]=0; - a[268]=0; - a[269]=0; - a[270]=0; - a[271]=0; - a[272]=0; - a[273]=0; - a[274]=0; - a[275]=0; - a[276]=0; - a[277]=0; - a[278]=0; - a[279]=0; - a[280]=0; - a[281]=0; - a[282]=0; - a[283]=0; - a[284]=0; - a[285]=0; - a[286]=0; - a[287]=0; - a[288]=0; - a[289]=0; - a[290]=0; - a[291]=0; - a[292]=0; - a[293]=0; - a[294]=0; - a[295]=0; - a[296]=0; - a[297]=0; - a[298]=0; - a[299]=0; - a[300]=0; - a[301]=0; - a[302]=0; - a[303]=0; - a[304]=0; - a[305]=0; - a[306]=0; - a[307]=0; - a[308]=0; - a[309]=0; - a[310]=0; - a[311]=0; - a[312]=0; - a[313]=0; - a[314]=0; - a[315]=0; - a[316]=0; - a[317]=0; - a[318]=0; - a[319]=0; - a[320]=0; - a[321]=0; - a[322]=0; - a[323]=0; - a[324]=0; - a[325]=0; - a[326]=0; - a[327]=0; - a[328]=0; - a[329]=0; - a[330]=0; - a[331]=0; - a[332]=0; - a[333]=0; - a[334]=0; - a[335]=0; - a[336]=0; - a[337]=0; - a[338]=0; - a[339]=0; - a[340]=0; - a[341]=0; - a[342]=0; - a[343]=0; - a[344]=0; - a[345]=0; - a[346]=0; - a[347]=0; - a[348]=0; - a[349]=0; - a[350]=0; - a[351]=0; - a[352]=0; - a[353]=0; - a[354]=0; - a[355]=0; - a[356]=0; - a[357]=0; - a[358]=0; - a[359]=0; - a[360]=0; - a[361]=0; - a[362]=0; - a[363]=0; - a[364]=0; - a[365]=0; - a[366]=0; - a[367]=0; - a[368]=0; - a[369]=0; - a[370]=0; - a[371]=0; - a[372]=0; - a[373]=0; - a[374]=0; - a[375]=0; - a[376]=0; - a[377]=0; - a[378]=0; - a[379]=0; - a[380]=0; - a[381]=0; - a[382]=0; - a[383]=0; - a[384]=0; - a[385]=0; - a[386]=0; - a[387]=0; - a[388]=0; - a[389]=0; - a[390]=0; - a[391]=0; - a[392]=0; - a[393]=0; - a[394]=0; - a[395]=0; - a[396]=0; - a[397]=0; - a[398]=0; - a[399]=0; - a[400]=0; - a[401]=0; - a[402]=0; - a[403]=0; - a[404]=0; - a[405]=0; - a[406]=0; - a[407]=0; - a[408]=0; - a[409]=0; - a[410]=0; - a[411]=0; - a[412]=0; - a[413]=0; - a[414]=0; - a[415]=0; - a[416]=0; - a[417]=0; - a[418]=0; - a[419]=0; - a[420]=0; - a[421]=0; - a[422]=0; - a[423]=0; - a[424]=0; - a[425]=0; - a[426]=0; - a[427]=0; - a[428]=0; - a[429]=0; - a[430]=0; - a[431]=0; - a[432]=0; - a[433]=0; - a[434]=0; - a[435]=0; - a[436]=0; - a[437]=0; - a[438]=0; - a[439]=0; - a[440]=0; - a[441]=0; - a[442]=0; - a[443]=0; - a[444]=0; - a[445]=0; - a[446]=0; - a[447]=0; - a[448]=0; - a[449]=0; - a[450]=0; - a[451]=0; - a[452]=0; - a[453]=0; - a[454]=0; - a[455]=0; - a[456]=0; - a[457]=0; - a[458]=0; - a[459]=0; - a[460]=0; - a[461]=0; - a[462]=0; - a[463]=0; - a[464]=0; - a[465]=0; - a[466]=0; - a[467]=0; - a[468]=0; - a[469]=0; - a[470]=0; - a[471]=0; - a[472]=0; - a[473]=0; - a[474]=0; - a[475]=0; - a[476]=0; - a[477]=0; - a[478]=0; - a[479]=0; - a[480]=0; - a[481]=0; - a[482]=0; - a[483]=0; - a[484]=0; - a[485]=0; - a[486]=0; - a[487]=0; - a[488]=0; - a[489]=0; - a[490]=0; - a[491]=0; - a[492]=0; - a[493]=0; - a[494]=0; - a[495]=0; - a[496]=0; - a[497]=0; - a[498]=0; - a[499]=0; - a[500]=0; - a[501]=0; - a[502]=0; - a[503]=0; - a[504]=0; - a[505]=0; - a[506]=0; - a[507]=0; - a[508]=0; - a[509]=0; - a[510]=0; - a[511]=0; - a[512]=0; - a[513]=0; - a[514]=0; - a[515]=0; - a[516]=0; - a[517]=0; - a[518]=0; - a[519]=0; - a[520]=0; - a[521]=0; - a[522]=0; - a[523]=0; - a[524]=0; - a[525]=0; - a[526]=0; - a[527]=0; - a[528]=0; - a[529]=0; - a[530]=0; - a[531]=0; - a[532]=0; - a[533]=0; - a[534]=0; - a[535]=0; - a[536]=0; - a[537]=0; - a[538]=0; - a[539]=0; - a[540]=0; - a[541]=0; - a[542]=0; - a[543]=0; - a[544]=0; - a[545]=0; - a[546]=0; - a[547]=0; - a[548]=0; - a[549]=0; - a[550]=0; - a[551]=0; - a[552]=0; - a[553]=0; - a[554]=0; - a[555]=0; - a[556]=0; - a[557]=0; - a[558]=0; - a[559]=0; - a[560]=0; - a[561]=0; - a[562]=0; - a[563]=0; - a[564]=0; - a[565]=0; - a[566]=0; - a[567]=0; - a[568]=0; - a[569]=0; - a[570]=0; - a[571]=0; - a[572]=0; - a[573]=0; - a[574]=0; - a[575]=0; - a[576]=0; - a[577]=0; - a[578]=0; - a[579]=0; - a[580]=0; - a[581]=0; - a[582]=0; - a[583]=0; - a[584]=0; - a[585]=0; - a[586]=0; - a[587]=0; - a[588]=0; - a[589]=0; - a[590]=0; - a[591]=0; - a[592]=0; - a[593]=0; - a[594]=0; - a[595]=0; - a[596]=0; - a[597]=0; - a[598]=0; - a[599]=0; - a[600]=0; - a[601]=0; - a[602]=0; - a[603]=0; - a[604]=0; - a[605]=0; - a[606]=0; - a[607]=0; - a[608]=0; - a[609]=0; - a[610]=0; - a[611]=0; - a[612]=0; - a[613]=0; - a[614]=0; - a[615]=0; - a[616]=0; - a[617]=0; - a[618]=0; - a[619]=0; - a[620]=0; - a[621]=0; - a[622]=0; - a[623]=0; - a[624]=0; - a[625]=0; - a[626]=0; - a[627]=0; - a[628]=0; - a[629]=0; - a[630]=0; - a[631]=0; - a[632]=0; - a[633]=0; - a[634]=0; - a[635]=0; - a[636]=0; - a[637]=0; - a[638]=0; - a[639]=0; - a[640]=0; - a[641]=0; - a[642]=0; - a[643]=0; - a[644]=0; - a[645]=0; - a[646]=0; - a[647]=0; - a[648]=0; - a[649]=0; - a[650]=0; - a[651]=0; - a[652]=0; - a[653]=0; - a[654]=0; - a[655]=0; - a[656]=0; - a[657]=0; - a[658]=0; - a[659]=0; - a[660]=0; - a[661]=0; - a[662]=0; - a[663]=0; - a[664]=0; - a[665]=0; - a[666]=0; - a[667]=0; - a[668]=0; - a[669]=0; - a[670]=0; - a[671]=0; - a[672]=0; - a[673]=0; - a[674]=0; - a[675]=0; - a[676]=0; - a[677]=0; - a[678]=0; - a[679]=0; - a[680]=0; - a[681]=0; - a[682]=0; - a[683]=0; - a[684]=0; - a[685]=0; - a[686]=0; - a[687]=0; - a[688]=0; - a[689]=0; - a[690]=0; - a[691]=0; - a[692]=0; - a[693]=0; - a[694]=0; - a[695]=0; - a[696]=0; - a[697]=0; - a[698]=0; - a[699]=0; - a[700]=0; - a[701]=0; - a[702]=0; - a[703]=0; - a[704]=0; - a[705]=0; - a[706]=0; - a[707]=0; - a[708]=0; - a[709]=0; - a[710]=0; - a[711]=0; - a[712]=0; - a[713]=0; - a[714]=0; - a[715]=0; - a[716]=0; - a[717]=0; - a[718]=0; - a[719]=0; - a[720]=0; - a[721]=0; - a[722]=0; - a[723]=0; - a[724]=0; - a[725]=0; - a[726]=0; - a[727]=0; - a[728]=0; - a[729]=0; - a[730]=0; - a[731]=0; - a[732]=0; - a[733]=0; - a[734]=0; - a[735]=0; - a[736]=0; - a[737]=0; - a[738]=0; - a[739]=0; - a[740]=0; - a[741]=0; - a[742]=0; - a[743]=0; - a[744]=0; - a[745]=0; - a[746]=0; - a[747]=0; - a[748]=0; - a[749]=0; - a[750]=0; - a[751]=0; - a[752]=0; - a[753]=0; - a[754]=0; - a[755]=0; - a[756]=0; - a[757]=0; - a[758]=0; - a[759]=0; - a[760]=0; - a[761]=0; - a[762]=0; - a[763]=0; - a[764]=0; - a[765]=0; - a[766]=0; - a[767]=0; - a[768]=0; - a[769]=0; - a[770]=0; - a[771]=0; - a[772]=0; - a[773]=0; - a[774]=0; - a[775]=0; - a[776]=0; - a[777]=0; - a[778]=0; - a[779]=0; - a[780]=0; - a[781]=0; - a[782]=0; - a[783]=0; - a[784]=0; - a[785]=0; - a[786]=0; - a[787]=0; - a[788]=0; - a[789]=0; - a[790]=0; - a[791]=0; - a[792]=0; - a[793]=0; - a[794]=0; - a[795]=0; - a[796]=0; - a[797]=0; - a[798]=0; - a[799]=0; - a[800]=0; - a[801]=0; - a[802]=0; - a[803]=0; - a[804]=0; - a[805]=0; - a[806]=0; - a[807]=0; - a[808]=0; - a[809]=0; - a[810]=0; - a[811]=0; - a[812]=0; - a[813]=0; - a[814]=0; - a[815]=0; - a[816]=0; - a[817]=0; - a[818]=0; - a[819]=0; - a[820]=0; - a[821]=0; - a[822]=0; - a[823]=0; - a[824]=0; - a[825]=0; - a[826]=0; - a[827]=0; - a[828]=0; - a[829]=0; - a[830]=0; - a[831]=0; - a[832]=0; - a[833]=0; - a[834]=0; - a[835]=0; - a[836]=0; - a[837]=0; - a[838]=0; - a[839]=0; - a[840]=0; - a[841]=0; - a[842]=0; - a[843]=0; - a[844]=0; - a[845]=0; - a[846]=0; - a[847]=0; - a[848]=0; - a[849]=0; - a[850]=0; - a[851]=0; - a[852]=0; - a[853]=0; - a[854]=0; - a[855]=0; - a[856]=0; - a[857]=0; - a[858]=0; - a[859]=0; - a[860]=0; - a[861]=0; - a[862]=0; - a[863]=0; - a[864]=0; - a[865]=0; - a[866]=0; - a[867]=0; - a[868]=0; - a[869]=0; - a[870]=0; - a[871]=0; - a[872]=0; - a[873]=0; - a[874]=0; - a[875]=0; - a[876]=0; - a[877]=0; - a[878]=0; - a[879]=0; - a[880]=0; - a[881]=0; - a[882]=0; - a[883]=0; - a[884]=0; - a[885]=0; - a[886]=0; - a[887]=0; - a[888]=0; - a[889]=0; - a[890]=0; - a[891]=0; - a[892]=0; - a[893]=0; - a[894]=0; - a[895]=0; - a[896]=0; - a[897]=0; - a[898]=0; - a[899]=0; - a[900]=0; - a[901]=0; - a[902]=0; - a[903]=0; - a[904]=0; - a[905]=0; - a[906]=0; - a[907]=0; - a[908]=0; - a[909]=0; - a[910]=0; - a[911]=0; - a[912]=0; - a[913]=0; - a[914]=0; - a[915]=0; - a[916]=0; - a[917]=0; - a[918]=0; - a[919]=0; - a[920]=0; - a[921]=0; - a[922]=0; - a[923]=0; - a[924]=0; - a[925]=0; - a[926]=0; - a[927]=0; - a[928]=0; - a[929]=0; - a[930]=0; - a[931]=0; - a[932]=0; - a[933]=0; - a[934]=0; - a[935]=0; - a[936]=0; - a[937]=0; - a[938]=0; - a[939]=0; - a[940]=0; - a[941]=0; - a[942]=0; - a[943]=0; - a[944]=0; - a[945]=0; - a[946]=0; - a[947]=0; - a[948]=0; - a[949]=0; - a[950]=0; - a[951]=0; - a[952]=0; - a[953]=0; - a[954]=0; - a[955]=0; - a[956]=0; - a[957]=0; - a[958]=0; - a[959]=0; - a[960]=0; - a[961]=0; - a[962]=0; - a[963]=0; - a[964]=0; - a[965]=0; - a[966]=0; - a[967]=0; - a[968]=0; - a[969]=0; - a[970]=0; - a[971]=0; - a[972]=0; - a[973]=0; - a[974]=0; - a[975]=0; - a[976]=0; - a[977]=0; - a[978]=0; - a[979]=0; - a[980]=0; - a[981]=0; - a[982]=0; - a[983]=0; - a[984]=0; - a[985]=0; - a[986]=0; - a[987]=0; - a[988]=0; - a[989]=0; - a[990]=0; - a[991]=0; - a[992]=0; - a[993]=0; - a[994]=0; - a[995]=0; - a[996]=0; - a[997]=0; - a[998]=0; - a[999]=0; - a[1000]=0; - a[1001]=0; - a[1002]=0; - a[1003]=0; - a[1004]=0; - a[1005]=0; - a[1006]=0; - a[1007]=0; - a[1008]=0; - a[1009]=0; - a[1010]=0; - a[1011]=0; - a[1012]=0; - a[1013]=0; - a[1014]=0; - a[1015]=0; - a[1016]=0; - a[1017]=0; - a[1018]=0; - a[1019]=0; - a[1020]=0; - a[1021]=0; - a[1022]=0; - a[1023]=0; - a[1024]=0; - a[1025]=0; - a[1026]=0; - a[1027]=0; - a[1028]=0; - a[1029]=0; - a[1030]=0; - a[1031]=0; - a[1032]=0; - a[1033]=0; - a[1034]=0; - a[1035]=0; - a[1036]=0; - a[1037]=0; - a[1038]=0; - a[1039]=0; - a[1040]=0; - a[1041]=0; - a[1042]=0; - a[1043]=0; - a[1044]=0; - a[1045]=0; - a[1046]=0; - a[1047]=0; - a[1048]=0; - a[1049]=0; - a[1050]=0; - a[1051]=0; - a[1052]=0; - a[1053]=0; - a[1054]=0; - a[1055]=0; - a[1056]=0; - a[1057]=0; - a[1058]=0; - a[1059]=0; - a[1060]=0; - a[1061]=0; - a[1062]=0; - a[1063]=0; - a[1064]=0; - a[1065]=0; - a[1066]=0; - a[1067]=0; - a[1068]=0; - a[1069]=0; - a[1070]=0; - a[1071]=0; - a[1072]=0; - a[1073]=0; - a[1074]=0; - a[1075]=0; - a[1076]=0; - a[1077]=0; - a[1078]=0; - a[1079]=0; - a[1080]=0; - a[1081]=0; - a[1082]=0; - a[1083]=0; - a[1084]=0; - a[1085]=0; - a[1086]=0; - a[1087]=0; - a[1088]=0; - a[1089]=0; - a[1090]=0; - a[1091]=0; - a[1092]=0; - a[1093]=0; - a[1094]=0; - a[1095]=0; - a[1096]=0; - a[1097]=0; - a[1098]=0; - a[1099]=0; - a[1100]=0; - a[1101]=0; - a[1102]=0; - a[1103]=0; - a[1104]=0; - a[1105]=0; - a[1106]=0; - a[1107]=0; - a[1108]=0; - a[1109]=0; - a[1110]=0; - a[1111]=0; - a[1112]=0; - a[1113]=0; - a[1114]=0; - a[1115]=0; - a[1116]=0; - a[1117]=0; - a[1118]=0; - a[1119]=0; - a[1120]=0; - a[1121]=0; - a[1122]=0; - a[1123]=0; - a[1124]=0; - a[1125]=0; - a[1126]=0; - a[1127]=0; - a[1128]=0; - a[1129]=0; - a[1130]=0; - a[1131]=0; - a[1132]=0; - a[1133]=0; - a[1134]=0; - a[1135]=0; - a[1136]=0; - a[1137]=0; - a[1138]=0; - a[1139]=0; - a[1140]=0; - a[1141]=0; - a[1142]=0; - a[1143]=0; - a[1144]=0; - a[1145]=0; - a[1146]=0; - a[1147]=0; - a[1148]=0; - a[1149]=0; - a[1150]=0; - a[1151]=0; - a[1152]=0; - a[1153]=0; - a[1154]=0; - a[1155]=0; - a[1156]=0; - a[1157]=0; - a[1158]=0; - a[1159]=0; - a[1160]=0; - a[1161]=0; - a[1162]=0; - a[1163]=0; - a[1164]=0; - a[1165]=0; - a[1166]=0; - a[1167]=0; - a[1168]=0; - a[1169]=0; - a[1170]=0; - a[1171]=0; - a[1172]=0; - a[1173]=0; - a[1174]=0; - a[1175]=0; - a[1176]=0; - a[1177]=0; - a[1178]=0; - a[1179]=0; - a[1180]=0; - a[1181]=0; - a[1182]=0; - a[1183]=0; - a[1184]=0; - a[1185]=0; - a[1186]=0; - a[1187]=0; - a[1188]=0; - a[1189]=0; - a[1190]=0; - a[1191]=0; - a[1192]=0; - a[1193]=0; - a[1194]=0; - a[1195]=0; - a[1196]=0; - a[1197]=0; - a[1198]=0; - a[1199]=0; - a[1200]=0; - a[1201]=0; - a[1202]=0; - a[1203]=0; - a[1204]=0; - a[1205]=0; - a[1206]=0; - a[1207]=0; - a[1208]=0; - a[1209]=0; - a[1210]=0; - a[1211]=0; - a[1212]=0; - a[1213]=0; - a[1214]=0; - a[1215]=0; - a[1216]=0; - a[1217]=0; - a[1218]=0; - a[1219]=0; - a[1220]=0; - a[1221]=0; - a[1222]=0; - a[1223]=0; - a[1224]=0; - a[1225]=0; - a[1226]=0; - a[1227]=0; - a[1228]=0; - a[1229]=0; - a[1230]=0; - a[1231]=0; - a[1232]=0; - a[1233]=0; - a[1234]=0; - a[1235]=0; - a[1236]=0; - a[1237]=0; - a[1238]=0; - a[1239]=0; - a[1240]=0; - a[1241]=0; - a[1242]=0; - a[1243]=0; - a[1244]=0; - a[1245]=0; - a[1246]=0; - a[1247]=0; - a[1248]=0; - a[1249]=0; - a[1250]=0; - a[1251]=0; - a[1252]=0; - a[1253]=0; - a[1254]=0; - a[1255]=0; - a[1256]=0; - a[1257]=0; - a[1258]=0; - a[1259]=0; - a[1260]=0; - a[1261]=0; - a[1262]=0; - a[1263]=0; - a[1264]=0; - a[1265]=0; - a[1266]=0; - a[1267]=0; - a[1268]=0; - a[1269]=0; - a[1270]=0; - a[1271]=0; - a[1272]=0; - a[1273]=0; - a[1274]=0; - a[1275]=0; - a[1276]=0; - a[1277]=0; - a[1278]=0; - a[1279]=0; - a[1280]=0; - a[1281]=0; - a[1282]=0; - a[1283]=0; - a[1284]=0; - a[1285]=0; - a[1286]=0; - a[1287]=0; - a[1288]=0; - a[1289]=0; - a[1290]=0; - a[1291]=0; - a[1292]=0; - a[1293]=0; - a[1294]=0; - a[1295]=0; - a[1296]=0; - a[1297]=0; - a[1298]=0; - a[1299]=0; - a[1300]=0; - a[1301]=0; - a[1302]=0; - a[1303]=0; - a[1304]=0; - a[1305]=0; - a[1306]=0; - a[1307]=0; - a[1308]=0; - a[1309]=0; - a[1310]=0; - a[1311]=0; - a[1312]=0; - a[1313]=0; - a[1314]=0; - a[1315]=0; - a[1316]=0; - a[1317]=0; - a[1318]=0; - a[1319]=0; - a[1320]=0; - a[1321]=0; - a[1322]=0; - a[1323]=0; - a[1324]=0; - a[1325]=0; - a[1326]=0; - a[1327]=0; - a[1328]=0; - a[1329]=0; - a[1330]=0; - a[1331]=0; - a[1332]=0; - a[1333]=0; - a[1334]=0; - a[1335]=0; - a[1336]=0; - a[1337]=0; - a[1338]=0; - a[1339]=0; - a[1340]=0; - a[1341]=0; - a[1342]=0; - a[1343]=0; - a[1344]=0; - a[1345]=0; - a[1346]=0; - a[1347]=0; - a[1348]=0; - a[1349]=0; - a[1350]=0; - a[1351]=0; - a[1352]=0; - a[1353]=0; - a[1354]=0; - a[1355]=0; - a[1356]=0; - a[1357]=0; - a[1358]=0; - a[1359]=0; - a[1360]=0; - a[1361]=0; - a[1362]=0; - a[1363]=0; - a[1364]=0; - a[1365]=0; - a[1366]=0; - a[1367]=0; - a[1368]=0; - a[1369]=0; - a[1370]=0; - a[1371]=0; - a[1372]=0; - a[1373]=0; - a[1374]=0; - a[1375]=0; - a[1376]=0; - a[1377]=0; - a[1378]=0; - a[1379]=0; - a[1380]=0; - a[1381]=0; - a[1382]=0; - a[1383]=0; - a[1384]=0; - a[1385]=0; - a[1386]=0; - a[1387]=0; - a[1388]=0; - a[1389]=0; - a[1390]=0; - a[1391]=0; - a[1392]=0; - a[1393]=0; - a[1394]=0; - a[1395]=0; - a[1396]=0; - a[1397]=0; - a[1398]=0; - a[1399]=0; - a[1400]=0; - a[1401]=0; - a[1402]=0; - a[1403]=0; - a[1404]=0; - a[1405]=0; - a[1406]=0; - a[1407]=0; - a[1408]=0; - a[1409]=0; - a[1410]=0; - a[1411]=0; - a[1412]=0; - a[1413]=0; - a[1414]=0; - a[1415]=0; - a[1416]=0; - a[1417]=0; - a[1418]=0; - a[1419]=0; - a[1420]=0; - a[1421]=0; - a[1422]=0; - a[1423]=0; - a[1424]=0; - a[1425]=0; - a[1426]=0; - a[1427]=0; - a[1428]=0; - a[1429]=0; - a[1430]=0; - a[1431]=0; - a[1432]=0; - a[1433]=0; - a[1434]=0; - a[1435]=0; - a[1436]=0; - a[1437]=0; - a[1438]=0; - a[1439]=0; - a[1440]=0; - a[1441]=0; - a[1442]=0; - a[1443]=0; - a[1444]=0; - a[1445]=0; - a[1446]=0; - a[1447]=0; - a[1448]=0; - a[1449]=0; - a[1450]=0; - a[1451]=0; - a[1452]=0; - a[1453]=0; - a[1454]=0; - a[1455]=0; - a[1456]=0; - a[1457]=0; - a[1458]=0; - a[1459]=0; - a[1460]=0; - a[1461]=0; - a[1462]=0; - a[1463]=0; - a[1464]=0; - a[1465]=0; - a[1466]=0; - a[1467]=0; - a[1468]=0; - a[1469]=0; - a[1470]=0; - a[1471]=0; - a[1472]=0; - a[1473]=0; - a[1474]=0; - a[1475]=0; - a[1476]=0; - a[1477]=0; - a[1478]=0; - a[1479]=0; - a[1480]=0; - a[1481]=0; - a[1482]=0; - a[1483]=0; - a[1484]=0; - a[1485]=0; - a[1486]=0; - a[1487]=0; - a[1488]=0; - a[1489]=0; - a[1490]=0; - a[1491]=0; - a[1492]=0; - a[1493]=0; - a[1494]=0; - a[1495]=0; - a[1496]=0; - a[1497]=0; - a[1498]=0; - a[1499]=0; - a[1500]=0; - a[1501]=0; - a[1502]=0; - a[1503]=0; - a[1504]=0; - a[1505]=0; - a[1506]=0; - a[1507]=0; - a[1508]=0; - a[1509]=0; - a[1510]=0; - a[1511]=0; - a[1512]=0; - a[1513]=0; - a[1514]=0; - a[1515]=0; - a[1516]=0; - a[1517]=0; - a[1518]=0; - a[1519]=0; - a[1520]=0; - a[1521]=0; - a[1522]=0; - a[1523]=0; - a[1524]=0; - a[1525]=0; - a[1526]=0; - a[1527]=0; - a[1528]=0; - a[1529]=0; - a[1530]=0; - a[1531]=0; - a[1532]=0; - a[1533]=0; - a[1534]=0; - a[1535]=0; - a[1536]=0; - a[1537]=0; - a[1538]=0; - a[1539]=0; - a[1540]=0; - a[1541]=0; - a[1542]=0; - a[1543]=0; - a[1544]=0; - a[1545]=0; - a[1546]=0; - a[1547]=0; - a[1548]=0; - a[1549]=0; - a[1550]=0; - a[1551]=0; - a[1552]=0; - a[1553]=0; - a[1554]=0; - a[1555]=0; - a[1556]=0; - a[1557]=0; - a[1558]=0; - a[1559]=0; - a[1560]=0; - a[1561]=0; - a[1562]=0; - a[1563]=0; - a[1564]=0; - a[1565]=0; - a[1566]=0; - a[1567]=0; - a[1568]=0; - a[1569]=0; - a[1570]=0; - a[1571]=0; - a[1572]=0; - a[1573]=0; - a[1574]=0; - a[1575]=0; - a[1576]=0; - a[1577]=0; - a[1578]=0; - a[1579]=0; - a[1580]=0; - a[1581]=0; - a[1582]=0; - a[1583]=0; - a[1584]=0; - a[1585]=0; - a[1586]=0; - a[1587]=0; - a[1588]=0; - a[1589]=0; - a[1590]=0; - a[1591]=0; - a[1592]=0; - a[1593]=0; - a[1594]=0; - a[1595]=0; - a[1596]=0; - a[1597]=0; - a[1598]=0; - a[1599]=0; - a[1600]=0; - a[1601]=0; - a[1602]=0; - a[1603]=0; - a[1604]=0; - a[1605]=0; - a[1606]=0; - a[1607]=0; - a[1608]=0; - a[1609]=0; - a[1610]=0; - a[1611]=0; - a[1612]=0; - a[1613]=0; - a[1614]=0; - a[1615]=0; - a[1616]=0; - a[1617]=0; - a[1618]=0; - a[1619]=0; - a[1620]=0; - a[1621]=0; - a[1622]=0; - a[1623]=0; - a[1624]=0; - a[1625]=0; - a[1626]=0; - a[1627]=0; - a[1628]=0; - a[1629]=0; - a[1630]=0; - a[1631]=0; - a[1632]=0; - a[1633]=0; - a[1634]=0; - a[1635]=0; - a[1636]=0; - a[1637]=0; - a[1638]=0; - a[1639]=0; - a[1640]=0; - a[1641]=0; - a[1642]=0; - a[1643]=0; - a[1644]=0; - a[1645]=0; - a[1646]=0; - a[1647]=0; - a[1648]=0; - a[1649]=0; - a[1650]=0; - a[1651]=0; - a[1652]=0; - a[1653]=0; - a[1654]=0; - a[1655]=0; - a[1656]=0; - a[1657]=0; - a[1658]=0; - a[1659]=0; - a[1660]=0; - a[1661]=0; - a[1662]=0; - a[1663]=0; - a[1664]=0; - a[1665]=0; - a[1666]=0; - a[1667]=0; - a[1668]=0; - a[1669]=0; - a[1670]=0; - a[1671]=0; - a[1672]=0; - a[1673]=0; - a[1674]=0; - a[1675]=0; - a[1676]=0; - a[1677]=0; - a[1678]=0; - a[1679]=0; - a[1680]=0; - a[1681]=0; - a[1682]=0; - a[1683]=0; - a[1684]=0; - a[1685]=0; - a[1686]=0; - a[1687]=0; - a[1688]=0; - a[1689]=0; - a[1690]=0; - a[1691]=0; - a[1692]=0; - a[1693]=0; - a[1694]=0; - a[1695]=0; - a[1696]=0; - a[1697]=0; - a[1698]=0; - a[1699]=0; - a[1700]=0; - a[1701]=0; - a[1702]=0; - a[1703]=0; - a[1704]=0; - a[1705]=0; - a[1706]=0; - a[1707]=0; - a[1708]=0; - a[1709]=0; - a[1710]=0; - a[1711]=0; - a[1712]=0; - a[1713]=0; - a[1714]=0; - a[1715]=0; - a[1716]=0; - a[1717]=0; - a[1718]=0; - a[1719]=0; - a[1720]=0; - a[1721]=0; - a[1722]=0; - a[1723]=0; - a[1724]=0; - a[1725]=0; - a[1726]=0; - a[1727]=0; - a[1728]=0; - a[1729]=0; - a[1730]=0; - a[1731]=0; - a[1732]=0; - a[1733]=0; - a[1734]=0; - a[1735]=0; - a[1736]=0; - a[1737]=0; - a[1738]=0; - a[1739]=0; - a[1740]=0; - a[1741]=0; - a[1742]=0; - a[1743]=0; - a[1744]=0; - a[1745]=0; - a[1746]=0; - a[1747]=0; - a[1748]=0; - a[1749]=0; - a[1750]=0; - a[1751]=0; - a[1752]=0; - a[1753]=0; - a[1754]=0; - a[1755]=0; - a[1756]=0; - a[1757]=0; - a[1758]=0; - a[1759]=0; - a[1760]=0; - a[1761]=0; - a[1762]=0; - a[1763]=0; - a[1764]=0; - a[1765]=0; - a[1766]=0; - a[1767]=0; - a[1768]=0; - a[1769]=0; - a[1770]=0; - a[1771]=0; - a[1772]=0; - a[1773]=0; - a[1774]=0; - a[1775]=0; - a[1776]=0; - a[1777]=0; - a[1778]=0; - a[1779]=0; - a[1780]=0; - a[1781]=0; - a[1782]=0; - a[1783]=0; - a[1784]=0; - a[1785]=0; - a[1786]=0; - a[1787]=0; - a[1788]=0; - a[1789]=0; - a[1790]=0; - a[1791]=0; - a[1792]=0; - a[1793]=0; - a[1794]=0; - a[1795]=0; - a[1796]=0; - a[1797]=0; - a[1798]=0; - a[1799]=0; - a[1800]=0; - a[1801]=0; - a[1802]=0; - a[1803]=0; - a[1804]=0; - a[1805]=0; - a[1806]=0; - a[1807]=0; - a[1808]=0; - a[1809]=0; - a[1810]=0; - a[1811]=0; - a[1812]=0; - a[1813]=0; - a[1814]=0; - a[1815]=0; - a[1816]=0; - a[1817]=0; - a[1818]=0; - a[1819]=0; - a[1820]=0; - a[1821]=0; - a[1822]=0; - a[1823]=0; - a[1824]=0; - a[1825]=0; - a[1826]=0; - a[1827]=0; - a[1828]=0; - a[1829]=0; - a[1830]=0; - a[1831]=0; - a[1832]=0; - a[1833]=0; - a[1834]=0; - a[1835]=0; - a[1836]=0; - a[1837]=0; - a[1838]=0; - a[1839]=0; - a[1840]=0; - a[1841]=0; - a[1842]=0; - a[1843]=0; - a[1844]=0; - a[1845]=0; - a[1846]=0; - a[1847]=0; - a[1848]=0; - a[1849]=0; - a[1850]=0; - a[1851]=0; - a[1852]=0; - a[1853]=0; - a[1854]=0; - a[1855]=0; - a[1856]=0; - a[1857]=0; - a[1858]=0; - a[1859]=0; - a[1860]=0; - a[1861]=0; - a[1862]=0; - a[1863]=0; - a[1864]=0; - a[1865]=0; - a[1866]=0; - a[1867]=0; - a[1868]=0; - a[1869]=0; - a[1870]=0; - a[1871]=0; - a[1872]=0; - a[1873]=0; - a[1874]=0; - a[1875]=0; - a[1876]=0; - a[1877]=0; - a[1878]=0; - a[1879]=0; - a[1880]=0; - a[1881]=0; - a[1882]=0; - a[1883]=0; - a[1884]=0; - a[1885]=0; - a[1886]=0; - a[1887]=0; - a[1888]=0; - a[1889]=0; - a[1890]=0; - a[1891]=0; - a[1892]=0; - a[1893]=0; - a[1894]=0; - a[1895]=0; - a[1896]=0; - a[1897]=0; - a[1898]=0; - a[1899]=0; - a[1900]=0; - a[1901]=0; - a[1902]=0; - a[1903]=0; - a[1904]=0; - a[1905]=0; - a[1906]=0; - a[1907]=0; - a[1908]=0; - a[1909]=0; - a[1910]=0; - a[1911]=0; - a[1912]=0; - a[1913]=0; - a[1914]=0; - a[1915]=0; - a[1916]=0; - a[1917]=0; - a[1918]=0; - a[1919]=0; - a[1920]=0; - a[1921]=0; - a[1922]=0; - a[1923]=0; - a[1924]=0; - a[1925]=0; - a[1926]=0; - a[1927]=0; - a[1928]=0; - a[1929]=0; - a[1930]=0; - a[1931]=0; - a[1932]=0; - a[1933]=0; - a[1934]=0; - a[1935]=0; - a[1936]=0; - a[1937]=0; - a[1938]=0; - a[1939]=0; - a[1940]=0; - a[1941]=0; - a[1942]=0; - a[1943]=0; - a[1944]=0; - a[1945]=0; - a[1946]=0; - a[1947]=0; - a[1948]=0; - a[1949]=0; - a[1950]=0; - a[1951]=0; - a[1952]=0; - a[1953]=0; - a[1954]=0; - a[1955]=0; - a[1956]=0; - a[1957]=0; - a[1958]=0; - a[1959]=0; - a[1960]=0; - a[1961]=0; - a[1962]=0; - a[1963]=0; - a[1964]=0; - a[1965]=0; - a[1966]=0; - a[1967]=0; - a[1968]=0; - a[1969]=0; - a[1970]=0; - a[1971]=0; - a[1972]=0; - a[1973]=0; - a[1974]=0; - a[1975]=0; - a[1976]=0; - a[1977]=0; - a[1978]=0; - a[1979]=0; - a[1980]=0; - a[1981]=0; - a[1982]=0; - a[1983]=0; - a[1984]=0; - a[1985]=0; - a[1986]=0; - a[1987]=0; - a[1988]=0; - a[1989]=0; - a[1990]=0; - a[1991]=0; - a[1992]=0; - a[1993]=0; - a[1994]=0; - a[1995]=0; - a[1996]=0; - a[1997]=0; - a[1998]=0; - a[1999]=0; - a[2000]=0; - a[2001]=0; - a[2002]=0; - a[2003]=0; - a[2004]=0; - a[2005]=0; - a[2006]=0; - a[2007]=0; - a[2008]=0; - a[2009]=0; - a[2010]=0; - a[2011]=0; - a[2012]=0; - a[2013]=0; - a[2014]=0; - a[2015]=0; - a[2016]=0; - a[2017]=0; - a[2018]=0; - a[2019]=0; - a[2020]=0; - a[2021]=0; - a[2022]=0; - a[2023]=0; - a[2024]=0; - a[2025]=0; - a[2026]=0; - a[2027]=0; - a[2028]=0; - a[2029]=0; - a[2030]=0; - a[2031]=0; - a[2032]=0; - a[2033]=0; - a[2034]=0; - a[2035]=0; - a[2036]=0; - a[2037]=0; - a[2038]=0; - a[2039]=0; - a[2040]=0; - a[2041]=0; - a[2042]=0; - a[2043]=0; - a[2044]=0; - a[2045]=0; - a[2046]=0; - a[2047]=0; - a[2048]=0; - a[2049]=0; - a[2050]=0; - a[2051]=0; - a[2052]=0; - a[2053]=0; - a[2054]=0; - a[2055]=0; - a[2056]=0; - a[2057]=0; - a[2058]=0; - a[2059]=0; - a[2060]=0; - a[2061]=0; - a[2062]=0; - a[2063]=0; - a[2064]=0; - a[2065]=0; - a[2066]=0; - a[2067]=0; - a[2068]=0; - a[2069]=0; - a[2070]=0; - a[2071]=0; - a[2072]=0; - a[2073]=0; - a[2074]=0; - a[2075]=0; - a[2076]=0; - a[2077]=0; - a[2078]=0; - a[2079]=0; - a[2080]=0; - a[2081]=0; - a[2082]=0; - a[2083]=0; - a[2084]=0; - a[2085]=0; - a[2086]=0; - a[2087]=0; - a[2088]=0; - a[2089]=0; - a[2090]=0; - a[2091]=0; - a[2092]=0; - a[2093]=0; - a[2094]=0; - a[2095]=0; - a[2096]=0; - a[2097]=0; - a[2098]=0; - a[2099]=0; - a[2100]=0; - a[2101]=0; - a[2102]=0; - a[2103]=0; - a[2104]=0; - a[2105]=0; - a[2106]=0; - a[2107]=0; - a[2108]=0; - a[2109]=0; - a[2110]=0; - a[2111]=0; - a[2112]=0; - a[2113]=0; - a[2114]=0; - a[2115]=0; - a[2116]=0; - a[2117]=0; - a[2118]=0; - a[2119]=0; - a[2120]=0; - a[2121]=0; - a[2122]=0; - a[2123]=0; - a[2124]=0; - a[2125]=0; - a[2126]=0; - a[2127]=0; - a[2128]=0; - a[2129]=0; - a[2130]=0; - a[2131]=0; - a[2132]=0; - a[2133]=0; - a[2134]=0; - a[2135]=0; - a[2136]=0; - a[2137]=0; - a[2138]=0; - a[2139]=0; - a[2140]=0; - a[2141]=0; - a[2142]=0; - a[2143]=0; - a[2144]=0; - a[2145]=0; - a[2146]=0; - a[2147]=0; - a[2148]=0; - a[2149]=0; - a[2150]=0; - a[2151]=0; - a[2152]=0; - a[2153]=0; - a[2154]=0; - a[2155]=0; - a[2156]=0; - a[2157]=0; - a[2158]=0; - a[2159]=0; - a[2160]=0; - a[2161]=0; - a[2162]=0; - a[2163]=0; - a[2164]=0; - a[2165]=0; - a[2166]=0; - a[2167]=0; - a[2168]=0; - a[2169]=0; - a[2170]=0; - a[2171]=0; - a[2172]=0; - a[2173]=0; - a[2174]=0; - a[2175]=0; - a[2176]=0; - a[2177]=0; - a[2178]=0; - a[2179]=0; - a[2180]=0; - a[2181]=0; - a[2182]=0; - a[2183]=0; - a[2184]=0; - a[2185]=0; - a[2186]=0; - a[2187]=0; - a[2188]=0; - a[2189]=0; - a[2190]=0; - a[2191]=0; - a[2192]=0; - a[2193]=0; - a[2194]=0; - a[2195]=0; - a[2196]=0; - a[2197]=0; - a[2198]=0; - a[2199]=0; - a[2200]=0; - a[2201]=0; - a[2202]=0; - a[2203]=0; - a[2204]=0; - a[2205]=0; - a[2206]=0; - a[2207]=0; - a[2208]=0; - a[2209]=0; - a[2210]=0; - a[2211]=0; - a[2212]=0; - a[2213]=0; - a[2214]=0; - a[2215]=0; - a[2216]=0; - a[2217]=0; - a[2218]=0; - a[2219]=0; - a[2220]=0; - a[2221]=0; - a[2222]=0; - a[2223]=0; - a[2224]=0; - a[2225]=0; - a[2226]=0; - a[2227]=0; - a[2228]=0; - a[2229]=0; - a[2230]=0; - a[2231]=0; - a[2232]=0; - a[2233]=0; - a[2234]=0; - a[2235]=0; - a[2236]=0; - a[2237]=0; - a[2238]=0; - a[2239]=0; - a[2240]=0; - a[2241]=0; - a[2242]=0; - a[2243]=0; - a[2244]=0; - a[2245]=0; - a[2246]=0; - a[2247]=0; - a[2248]=0; - a[2249]=0; - a[2250]=0; - a[2251]=0; - a[2252]=0; - a[2253]=0; - a[2254]=0; - a[2255]=0; - a[2256]=0; - a[2257]=0; - a[2258]=0; - a[2259]=0; - a[2260]=0; - a[2261]=0; - a[2262]=0; - a[2263]=0; - a[2264]=0; - a[2265]=0; - a[2266]=0; - a[2267]=0; - a[2268]=0; - a[2269]=0; - a[2270]=0; - a[2271]=0; - a[2272]=0; - a[2273]=0; - a[2274]=0; - a[2275]=0; - a[2276]=0; - a[2277]=0; - a[2278]=0; - a[2279]=0; - a[2280]=0; - a[2281]=0; - a[2282]=0; - a[2283]=0; - a[2284]=0; - a[2285]=0; - a[2286]=0; - a[2287]=0; - a[2288]=0; - a[2289]=0; - a[2290]=0; - a[2291]=0; - a[2292]=0; - a[2293]=0; - a[2294]=0; - a[2295]=0; - a[2296]=0; - a[2297]=0; - a[2298]=0; - a[2299]=0; - a[2300]=0; - a[2301]=0; - a[2302]=0; - a[2303]=0; - a[2304]=0; - a[2305]=0; - a[2306]=0; - a[2307]=0; - a[2308]=0; - a[2309]=0; - a[2310]=0; - a[2311]=0; - a[2312]=0; - a[2313]=0; - a[2314]=0; - a[2315]=0; - a[2316]=0; - a[2317]=0; - a[2318]=0; - a[2319]=0; - a[2320]=0; - a[2321]=0; - a[2322]=0; - a[2323]=0; - a[2324]=0; - a[2325]=0; - a[2326]=0; - a[2327]=0; - a[2328]=0; - a[2329]=0; - a[2330]=0; - a[2331]=0; - a[2332]=0; - a[2333]=0; - a[2334]=0; - a[2335]=0; - a[2336]=0; - a[2337]=0; - a[2338]=0; - a[2339]=0; - a[2340]=0; - a[2341]=0; - a[2342]=0; - a[2343]=0; - a[2344]=0; - a[2345]=0; - a[2346]=0; - a[2347]=0; - a[2348]=0; - a[2349]=0; - a[2350]=0; - a[2351]=0; - a[2352]=0; - a[2353]=0; - a[2354]=0; - a[2355]=0; - a[2356]=0; - a[2357]=0; - a[2358]=0; - a[2359]=0; - a[2360]=0; - a[2361]=0; - a[2362]=0; - a[2363]=0; - a[2364]=0; - a[2365]=0; - a[2366]=0; - a[2367]=0; - a[2368]=0; - a[2369]=0; - a[2370]=0; - a[2371]=0; - a[2372]=0; - a[2373]=0; - a[2374]=0; - a[2375]=0; - a[2376]=0; - a[2377]=0; - a[2378]=0; - a[2379]=0; - a[2380]=0; - a[2381]=0; - a[2382]=0; - a[2383]=0; - a[2384]=0; - a[2385]=0; - a[2386]=0; - a[2387]=0; - a[2388]=0; - a[2389]=0; - a[2390]=0; - a[2391]=0; - a[2392]=0; - a[2393]=0; - a[2394]=0; - a[2395]=0; - a[2396]=0; - a[2397]=0; - a[2398]=0; - a[2399]=0; - a[2400]=0; - a[2401]=0; - a[2402]=0; - a[2403]=0; - a[2404]=0; - a[2405]=0; - a[2406]=0; - a[2407]=0; - a[2408]=0; - a[2409]=0; - a[2410]=0; - a[2411]=0; - a[2412]=0; - a[2413]=0; - a[2414]=0; - a[2415]=0; - a[2416]=0; - a[2417]=0; - a[2418]=0; - a[2419]=0; - a[2420]=0; - a[2421]=0; - a[2422]=0; - a[2423]=0; - a[2424]=0; - a[2425]=0; - a[2426]=0; - a[2427]=0; - a[2428]=0; - a[2429]=0; - a[2430]=0; - a[2431]=0; - a[2432]=0; - a[2433]=0; - a[2434]=0; - a[2435]=0; - a[2436]=0; - a[2437]=0; - a[2438]=0; - a[2439]=0; - a[2440]=0; - a[2441]=0; - a[2442]=0; - a[2443]=0; - a[2444]=0; - a[2445]=0; - a[2446]=0; - a[2447]=0; - a[2448]=0; - a[2449]=0; - a[2450]=0; - a[2451]=0; - a[2452]=0; - a[2453]=0; - a[2454]=0; - a[2455]=0; - a[2456]=0; - a[2457]=0; - a[2458]=0; - a[2459]=0; - a[2460]=0; - a[2461]=0; - a[2462]=0; - a[2463]=0; - a[2464]=0; - a[2465]=0; - a[2466]=0; - a[2467]=0; - a[2468]=0; - a[2469]=0; - a[2470]=0; - a[2471]=0; - a[2472]=0; - a[2473]=0; - a[2474]=0; - a[2475]=0; - a[2476]=0; - a[2477]=0; - a[2478]=0; - a[2479]=0; - a[2480]=0; - a[2481]=0; - a[2482]=0; - a[2483]=0; - a[2484]=0; - a[2485]=0; - a[2486]=0; - a[2487]=0; - a[2488]=0; - a[2489]=0; - a[2490]=0; - a[2491]=0; - a[2492]=0; - a[2493]=0; - a[2494]=0; - a[2495]=0; - a[2496]=0; - a[2497]=0; - a[2498]=0; - a[2499]=0; - a[2500]=0; - a[2501]=0; - a[2502]=0; - a[2503]=0; - a[2504]=0; - a[2505]=0; - a[2506]=0; - a[2507]=0; - a[2508]=0; - a[2509]=0; - a[2510]=0; - a[2511]=0; - a[2512]=0; - a[2513]=0; - a[2514]=0; - a[2515]=0; - a[2516]=0; - a[2517]=0; - a[2518]=0; - a[2519]=0; - a[2520]=0; - a[2521]=0; - a[2522]=0; - a[2523]=0; - a[2524]=0; - a[2525]=0; - a[2526]=0; - a[2527]=0; - a[2528]=0; - a[2529]=0; - a[2530]=0; - a[2531]=0; - a[2532]=0; - a[2533]=0; - a[2534]=0; - a[2535]=0; - a[2536]=0; - a[2537]=0; - a[2538]=0; - a[2539]=0; - a[2540]=0; - a[2541]=0; - a[2542]=0; - a[2543]=0; - a[2544]=0; - a[2545]=0; - a[2546]=0; - a[2547]=0; - a[2548]=0; - a[2549]=0; - a[2550]=0; - a[2551]=0; - a[2552]=0; - a[2553]=0; - a[2554]=0; - a[2555]=0; - a[2556]=0; - a[2557]=0; - a[2558]=0; - a[2559]=0; - a[2560]=0; - a[2561]=0; - a[2562]=0; - a[2563]=0; - a[2564]=0; - a[2565]=0; - a[2566]=0; - a[2567]=0; - a[2568]=0; - a[2569]=0; - a[2570]=0; - a[2571]=0; - a[2572]=0; - a[2573]=0; - a[2574]=0; - a[2575]=0; - a[2576]=0; - a[2577]=0; - a[2578]=0; - a[2579]=0; - a[2580]=0; - a[2581]=0; - a[2582]=0; - a[2583]=0; - a[2584]=0; - a[2585]=0; - a[2586]=0; - a[2587]=0; - a[2588]=0; - a[2589]=0; - a[2590]=0; - a[2591]=0; - a[2592]=0; - a[2593]=0; - a[2594]=0; - a[2595]=0; - a[2596]=0; - a[2597]=0; - a[2598]=0; - a[2599]=0; - a[2600]=0; - a[2601]=0; - a[2602]=0; - a[2603]=0; - a[2604]=0; - a[2605]=0; - a[2606]=0; - a[2607]=0; - a[2608]=0; - a[2609]=0; - a[2610]=0; - a[2611]=0; - a[2612]=0; - a[2613]=0; - a[2614]=0; - a[2615]=0; - a[2616]=0; - a[2617]=0; - a[2618]=0; - a[2619]=0; - a[2620]=0; - a[2621]=0; - a[2622]=0; - a[2623]=0; - a[2624]=0; - a[2625]=0; - a[2626]=0; - a[2627]=0; - a[2628]=0; - a[2629]=0; - a[2630]=0; - a[2631]=0; - a[2632]=0; - a[2633]=0; - a[2634]=0; - a[2635]=0; - a[2636]=0; - a[2637]=0; - a[2638]=0; - a[2639]=0; - a[2640]=0; - a[2641]=0; - a[2642]=0; - a[2643]=0; - a[2644]=0; - a[2645]=0; - a[2646]=0; - a[2647]=0; - a[2648]=0; - a[2649]=0; - a[2650]=0; - a[2651]=0; - a[2652]=0; - a[2653]=0; - a[2654]=0; - a[2655]=0; - a[2656]=0; - a[2657]=0; - a[2658]=0; - a[2659]=0; - a[2660]=0; - a[2661]=0; - a[2662]=0; - a[2663]=0; - a[2664]=0; - a[2665]=0; - a[2666]=0; - a[2667]=0; - a[2668]=0; - a[2669]=0; - a[2670]=0; - a[2671]=0; - a[2672]=0; - a[2673]=0; - a[2674]=0; - a[2675]=0; - a[2676]=0; - a[2677]=0; - a[2678]=0; - a[2679]=0; - a[2680]=0; - a[2681]=0; - a[2682]=0; - a[2683]=0; - a[2684]=0; - a[2685]=0; - a[2686]=0; - a[2687]=0; - a[2688]=0; - a[2689]=0; - a[2690]=0; - a[2691]=0; - a[2692]=0; - a[2693]=0; - a[2694]=0; - a[2695]=0; - a[2696]=0; - a[2697]=0; - a[2698]=0; - a[2699]=0; - a[2700]=0; - a[2701]=0; - a[2702]=0; - a[2703]=0; - a[2704]=0; - a[2705]=0; - a[2706]=0; - a[2707]=0; - a[2708]=0; - a[2709]=0; - a[2710]=0; - a[2711]=0; - a[2712]=0; - a[2713]=0; - a[2714]=0; - a[2715]=0; - a[2716]=0; - a[2717]=0; - a[2718]=0; - a[2719]=0; - a[2720]=0; - a[2721]=0; - a[2722]=0; - a[2723]=0; - a[2724]=0; - a[2725]=0; - a[2726]=0; - a[2727]=0; - a[2728]=0; - a[2729]=0; - a[2730]=0; - a[2731]=0; - a[2732]=0; - a[2733]=0; - a[2734]=0; - a[2735]=0; - a[2736]=0; - a[2737]=0; - a[2738]=0; - a[2739]=0; - a[2740]=0; - a[2741]=0; - a[2742]=0; - a[2743]=0; - a[2744]=0; - a[2745]=0; - a[2746]=0; - a[2747]=0; - a[2748]=0; - a[2749]=0; - a[2750]=0; - a[2751]=0; - a[2752]=0; - a[2753]=0; - a[2754]=0; - a[2755]=0; - a[2756]=0; - a[2757]=0; - a[2758]=0; - a[2759]=0; - a[2760]=0; - a[2761]=0; - a[2762]=0; - a[2763]=0; - a[2764]=0; - a[2765]=0; - a[2766]=0; - a[2767]=0; - a[2768]=0; - a[2769]=0; - a[2770]=0; - a[2771]=0; - a[2772]=0; - a[2773]=0; - a[2774]=0; - a[2775]=0; - a[2776]=0; - a[2777]=0; - a[2778]=0; - a[2779]=0; - a[2780]=0; - a[2781]=0; - a[2782]=0; - a[2783]=0; - a[2784]=0; - a[2785]=0; - a[2786]=0; - a[2787]=0; - a[2788]=0; - a[2789]=0; - a[2790]=0; - a[2791]=0; - a[2792]=0; - a[2793]=0; - a[2794]=0; - a[2795]=0; - a[2796]=0; - a[2797]=0; - a[2798]=0; - a[2799]=0; - a[2800]=0; - a[2801]=0; - a[2802]=0; - a[2803]=0; - a[2804]=0; - a[2805]=0; - a[2806]=0; - a[2807]=0; - a[2808]=0; - a[2809]=0; - a[2810]=0; - a[2811]=0; - a[2812]=0; - a[2813]=0; - a[2814]=0; - a[2815]=0; - a[2816]=0; - a[2817]=0; - a[2818]=0; - a[2819]=0; - a[2820]=0; - a[2821]=0; - a[2822]=0; - a[2823]=0; - a[2824]=0; - a[2825]=0; - a[2826]=0; - a[2827]=0; - a[2828]=0; - a[2829]=0; - a[2830]=0; - a[2831]=0; - a[2832]=0; - a[2833]=0; - a[2834]=0; - a[2835]=0; - a[2836]=0; - a[2837]=0; - a[2838]=0; - a[2839]=0; - a[2840]=0; - a[2841]=0; - a[2842]=0; - a[2843]=0; - a[2844]=0; - a[2845]=0; - a[2846]=0; - a[2847]=0; - a[2848]=0; - a[2849]=0; - a[2850]=0; - a[2851]=0; - a[2852]=0; - a[2853]=0; - a[2854]=0; - a[2855]=0; - a[2856]=0; - a[2857]=0; - a[2858]=0; - a[2859]=0; - a[2860]=0; - a[2861]=0; - a[2862]=0; - a[2863]=0; - a[2864]=0; - a[2865]=0; - a[2866]=0; - a[2867]=0; - a[2868]=0; - a[2869]=0; - a[2870]=0; - a[2871]=0; - a[2872]=0; - a[2873]=0; - a[2874]=0; - a[2875]=0; - a[2876]=0; - a[2877]=0; - a[2878]=0; - a[2879]=0; - a[2880]=0; - a[2881]=0; - a[2882]=0; - a[2883]=0; - a[2884]=0; - a[2885]=0; - a[2886]=0; - a[2887]=0; - a[2888]=0; - a[2889]=0; - a[2890]=0; - a[2891]=0; - a[2892]=0; - a[2893]=0; - a[2894]=0; - a[2895]=0; - a[2896]=0; - a[2897]=0; - a[2898]=0; - a[2899]=0; - a[2900]=0; - a[2901]=0; - a[2902]=0; - a[2903]=0; - a[2904]=0; - a[2905]=0; - a[2906]=0; - a[2907]=0; - a[2908]=0; - a[2909]=0; - a[2910]=0; - a[2911]=0; - a[2912]=0; - a[2913]=0; - a[2914]=0; - a[2915]=0; - a[2916]=0; - a[2917]=0; - a[2918]=0; - a[2919]=0; - a[2920]=0; - a[2921]=0; - a[2922]=0; - a[2923]=0; - a[2924]=0; - a[2925]=0; - a[2926]=0; - a[2927]=0; - a[2928]=0; - a[2929]=0; - a[2930]=0; - a[2931]=0; - a[2932]=0; - a[2933]=0; - a[2934]=0; - a[2935]=0; - a[2936]=0; - a[2937]=0; - a[2938]=0; - a[2939]=0; - a[2940]=0; - a[2941]=0; - a[2942]=0; - a[2943]=0; - a[2944]=0; - a[2945]=0; - a[2946]=0; - a[2947]=0; - a[2948]=0; - a[2949]=0; - a[2950]=0; - a[2951]=0; - a[2952]=0; - a[2953]=0; - a[2954]=0; - a[2955]=0; - a[2956]=0; - a[2957]=0; - a[2958]=0; - a[2959]=0; - a[2960]=0; - a[2961]=0; - a[2962]=0; - a[2963]=0; - a[2964]=0; - a[2965]=0; - a[2966]=0; - a[2967]=0; - a[2968]=0; - a[2969]=0; - a[2970]=0; - a[2971]=0; - a[2972]=0; - a[2973]=0; - a[2974]=0; - a[2975]=0; - a[2976]=0; - a[2977]=0; - a[2978]=0; - a[2979]=0; - a[2980]=0; - a[2981]=0; - a[2982]=0; - a[2983]=0; - a[2984]=0; - a[2985]=0; - a[2986]=0; - a[2987]=0; - a[2988]=0; - a[2989]=0; - a[2990]=0; - a[2991]=0; - a[2992]=0; - a[2993]=0; - a[2994]=0; - a[2995]=0; - a[2996]=0; - a[2997]=0; - a[2998]=0; - a[2999]=0; - a[3000]=0; - a[3001]=0; - a[3002]=0; - a[3003]=0; - a[3004]=0; - a[3005]=0; - a[3006]=0; - a[3007]=0; - a[3008]=0; - a[3009]=0; - a[3010]=0; - a[3011]=0; - a[3012]=0; - a[3013]=0; - a[3014]=0; - a[3015]=0; - a[3016]=0; - a[3017]=0; - a[3018]=0; - a[3019]=0; - a[3020]=0; - a[3021]=0; - a[3022]=0; - a[3023]=0; - a[3024]=0; - a[3025]=0; - a[3026]=0; - a[3027]=0; - a[3028]=0; - a[3029]=0; - a[3030]=0; - a[3031]=0; - a[3032]=0; - a[3033]=0; - a[3034]=0; - a[3035]=0; - a[3036]=0; - a[3037]=0; - a[3038]=0; - a[3039]=0; - a[3040]=0; - a[3041]=0; - a[3042]=0; - a[3043]=0; - a[3044]=0; - a[3045]=0; - a[3046]=0; - a[3047]=0; - a[3048]=0; - a[3049]=0; - a[3050]=0; - a[3051]=0; - a[3052]=0; - a[3053]=0; - a[3054]=0; - a[3055]=0; - a[3056]=0; - a[3057]=0; - a[3058]=0; - a[3059]=0; - a[3060]=0; - a[3061]=0; - a[3062]=0; - a[3063]=0; - a[3064]=0; - a[3065]=0; - a[3066]=0; - a[3067]=0; - a[3068]=0; - a[3069]=0; - a[3070]=0; - a[3071]=0; - a[3072]=0; - a[3073]=0; - a[3074]=0; - a[3075]=0; - a[3076]=0; - a[3077]=0; - a[3078]=0; - a[3079]=0; - a[3080]=0; - a[3081]=0; - a[3082]=0; - a[3083]=0; - a[3084]=0; - a[3085]=0; - a[3086]=0; - a[3087]=0; - a[3088]=0; - a[3089]=0; - a[3090]=0; - a[3091]=0; - a[3092]=0; - a[3093]=0; - a[3094]=0; - a[3095]=0; - a[3096]=0; - a[3097]=0; - a[3098]=0; - a[3099]=0; - a[3100]=0; - a[3101]=0; - a[3102]=0; - a[3103]=0; - a[3104]=0; - a[3105]=0; - a[3106]=0; - a[3107]=0; - a[3108]=0; - a[3109]=0; - a[3110]=0; - a[3111]=0; - a[3112]=0; - a[3113]=0; - a[3114]=0; - a[3115]=0; - a[3116]=0; - a[3117]=0; - a[3118]=0; - a[3119]=0; - a[3120]=0; - a[3121]=0; - a[3122]=0; - a[3123]=0; - a[3124]=0; - a[3125]=0; - a[3126]=0; - a[3127]=0; - a[3128]=0; - a[3129]=0; - a[3130]=0; - a[3131]=0; - a[3132]=0; - a[3133]=0; - a[3134]=0; - a[3135]=0; - a[3136]=0; - a[3137]=0; - a[3138]=0; - a[3139]=0; - a[3140]=0; - a[3141]=0; - a[3142]=0; - a[3143]=0; - a[3144]=0; - a[3145]=0; - a[3146]=0; - a[3147]=0; - a[3148]=0; - a[3149]=0; - a[3150]=0; - a[3151]=0; - a[3152]=0; - a[3153]=0; - a[3154]=0; - a[3155]=0; - a[3156]=0; - a[3157]=0; - a[3158]=0; - a[3159]=0; - a[3160]=0; - a[3161]=0; - a[3162]=0; - a[3163]=0; - a[3164]=0; - a[3165]=0; - a[3166]=0; - a[3167]=0; - a[3168]=0; - a[3169]=0; - a[3170]=0; - a[3171]=0; - a[3172]=0; - a[3173]=0; - a[3174]=0; - a[3175]=0; - a[3176]=0; - a[3177]=0; - a[3178]=0; - a[3179]=0; - a[3180]=0; - a[3181]=0; - a[3182]=0; - a[3183]=0; - a[3184]=0; - a[3185]=0; - a[3186]=0; - a[3187]=0; - a[3188]=0; - a[3189]=0; - a[3190]=0; - a[3191]=0; - a[3192]=0; - a[3193]=0; - a[3194]=0; - a[3195]=0; - a[3196]=0; - a[3197]=0; - a[3198]=0; - a[3199]=0; - a[3200]=0; - a[3201]=0; - a[3202]=0; - a[3203]=0; - a[3204]=0; - a[3205]=0; - a[3206]=0; - a[3207]=0; - a[3208]=0; - a[3209]=0; - a[3210]=0; - a[3211]=0; - a[3212]=0; - a[3213]=0; - a[3214]=0; - a[3215]=0; - a[3216]=0; - a[3217]=0; - a[3218]=0; - a[3219]=0; - a[3220]=0; - a[3221]=0; - a[3222]=0; - a[3223]=0; - a[3224]=0; - a[3225]=0; - a[3226]=0; - a[3227]=0; - a[3228]=0; - a[3229]=0; - a[3230]=0; - a[3231]=0; - a[3232]=0; - a[3233]=0; - a[3234]=0; - a[3235]=0; - a[3236]=0; - a[3237]=0; - a[3238]=0; - a[3239]=0; - a[3240]=0; - a[3241]=0; - a[3242]=0; - a[3243]=0; - a[3244]=0; - a[3245]=0; - a[3246]=0; - a[3247]=0; - a[3248]=0; - a[3249]=0; - a[3250]=0; - a[3251]=0; - a[3252]=0; - a[3253]=0; - a[3254]=0; - a[3255]=0; - a[3256]=0; - a[3257]=0; - a[3258]=0; - a[3259]=0; - a[3260]=0; - a[3261]=0; - a[3262]=0; - a[3263]=0; - a[3264]=0; - a[3265]=0; - a[3266]=0; - a[3267]=0; - a[3268]=0; - a[3269]=0; - a[3270]=0; - a[3271]=0; - a[3272]=0; - a[3273]=0; - a[3274]=0; - a[3275]=0; - a[3276]=0; - a[3277]=0; - a[3278]=0; - a[3279]=0; - a[3280]=0; - a[3281]=0; - a[3282]=0; - a[3283]=0; - a[3284]=0; - a[3285]=0; - a[3286]=0; - a[3287]=0; - a[3288]=0; - a[3289]=0; - a[3290]=0; - a[3291]=0; - a[3292]=0; - a[3293]=0; - a[3294]=0; - a[3295]=0; - a[3296]=0; - a[3297]=0; - a[3298]=0; - a[3299]=0; - a[3300]=0; - a[3301]=0; - a[3302]=0; - a[3303]=0; - a[3304]=0; - a[3305]=0; - a[3306]=0; - a[3307]=0; - a[3308]=0; - a[3309]=0; - a[3310]=0; - a[3311]=0; - a[3312]=0; - a[3313]=0; - a[3314]=0; - a[3315]=0; - a[3316]=0; - a[3317]=0; - a[3318]=0; - a[3319]=0; - a[3320]=0; - a[3321]=0; - a[3322]=0; - a[3323]=0; - a[3324]=0; - a[3325]=0; - a[3326]=0; - a[3327]=0; - a[3328]=0; - a[3329]=0; - a[3330]=0; - a[3331]=0; - a[3332]=0; - a[3333]=0; - a[3334]=0; - a[3335]=0; - a[3336]=0; - a[3337]=0; - a[3338]=0; - a[3339]=0; - a[3340]=0; - a[3341]=0; - a[3342]=0; - a[3343]=0; - a[3344]=0; - a[3345]=0; - a[3346]=0; - a[3347]=0; - a[3348]=0; - a[3349]=0; - a[3350]=0; - a[3351]=0; - a[3352]=0; - a[3353]=0; - a[3354]=0; - a[3355]=0; - a[3356]=0; - a[3357]=0; - a[3358]=0; - a[3359]=0; - a[3360]=0; - a[3361]=0; - a[3362]=0; - a[3363]=0; - a[3364]=0; - a[3365]=0; - a[3366]=0; - a[3367]=0; - a[3368]=0; - a[3369]=0; - a[3370]=0; - a[3371]=0; - a[3372]=0; - a[3373]=0; - a[3374]=0; - a[3375]=0; - a[3376]=0; - a[3377]=0; - a[3378]=0; - a[3379]=0; - a[3380]=0; - a[3381]=0; - a[3382]=0; - a[3383]=0; - a[3384]=0; - a[3385]=0; - a[3386]=0; - a[3387]=0; - a[3388]=0; - a[3389]=0; - a[3390]=0; - a[3391]=0; - a[3392]=0; - a[3393]=0; - a[3394]=0; - a[3395]=0; - a[3396]=0; - a[3397]=0; - a[3398]=0; - a[3399]=0; - a[3400]=0; - a[3401]=0; - a[3402]=0; - a[3403]=0; - a[3404]=0; - a[3405]=0; - a[3406]=0; - a[3407]=0; - a[3408]=0; - a[3409]=0; - a[3410]=0; - a[3411]=0; - a[3412]=0; - a[3413]=0; - a[3414]=0; - a[3415]=0; - a[3416]=0; - a[3417]=0; - a[3418]=0; - a[3419]=0; - a[3420]=0; - a[3421]=0; - a[3422]=0; - a[3423]=0; - a[3424]=0; - a[3425]=0; - a[3426]=0; - a[3427]=0; - a[3428]=0; - a[3429]=0; - a[3430]=0; - a[3431]=0; - a[3432]=0; - a[3433]=0; - a[3434]=0; - a[3435]=0; - a[3436]=0; - a[3437]=0; - a[3438]=0; - a[3439]=0; - a[3440]=0; - a[3441]=0; - a[3442]=0; - a[3443]=0; - a[3444]=0; - a[3445]=0; - a[3446]=0; - a[3447]=0; - a[3448]=0; - a[3449]=0; - a[3450]=0; - a[3451]=0; - a[3452]=0; - a[3453]=0; - a[3454]=0; - a[3455]=0; - a[3456]=0; - a[3457]=0; - a[3458]=0; - a[3459]=0; - a[3460]=0; - a[3461]=0; - a[3462]=0; - a[3463]=0; - a[3464]=0; - a[3465]=0; - a[3466]=0; - a[3467]=0; - a[3468]=0; - a[3469]=0; - a[3470]=0; - a[3471]=0; - a[3472]=0; - a[3473]=0; - a[3474]=0; - a[3475]=0; - a[3476]=0; - a[3477]=0; - a[3478]=0; - a[3479]=0; - a[3480]=0; - a[3481]=0; - a[3482]=0; - a[3483]=0; - a[3484]=0; - a[3485]=0; - a[3486]=0; - a[3487]=0; - a[3488]=0; - a[3489]=0; - a[3490]=0; - a[3491]=0; - a[3492]=0; - a[3493]=0; - a[3494]=0; - a[3495]=0; - a[3496]=0; - a[3497]=0; - a[3498]=0; - a[3499]=0; - a[3500]=0; - a[3501]=0; - a[3502]=0; - a[3503]=0; - a[3504]=0; - a[3505]=0; - a[3506]=0; - a[3507]=0; - a[3508]=0; - a[3509]=0; - a[3510]=0; - a[3511]=0; - a[3512]=0; - a[3513]=0; - a[3514]=0; - a[3515]=0; - a[3516]=0; - a[3517]=0; - a[3518]=0; - a[3519]=0; - a[3520]=0; - a[3521]=0; - a[3522]=0; - a[3523]=0; - a[3524]=0; - a[3525]=0; - a[3526]=0; - a[3527]=0; - a[3528]=0; - a[3529]=0; - a[3530]=0; - a[3531]=0; - a[3532]=0; - a[3533]=0; - a[3534]=0; - a[3535]=0; - a[3536]=0; - a[3537]=0; - a[3538]=0; - a[3539]=0; - a[3540]=0; - a[3541]=0; - a[3542]=0; - a[3543]=0; - a[3544]=0; - a[3545]=0; - a[3546]=0; - a[3547]=0; - a[3548]=0; - a[3549]=0; - a[3550]=0; - a[3551]=0; - a[3552]=0; - a[3553]=0; - a[3554]=0; - a[3555]=0; - a[3556]=0; - a[3557]=0; - a[3558]=0; - a[3559]=0; - a[3560]=0; - a[3561]=0; - a[3562]=0; - a[3563]=0; - a[3564]=0; - a[3565]=0; - a[3566]=0; - a[3567]=0; - a[3568]=0; - a[3569]=0; - a[3570]=0; - a[3571]=0; - a[3572]=0; - a[3573]=0; - a[3574]=0; - a[3575]=0; - a[3576]=0; - a[3577]=0; - a[3578]=0; - a[3579]=0; - a[3580]=0; - a[3581]=0; - a[3582]=0; - a[3583]=0; - a[3584]=0; - a[3585]=0; - a[3586]=0; - a[3587]=0; - a[3588]=0; - a[3589]=0; - a[3590]=0; - a[3591]=0; - a[3592]=0; - a[3593]=0; - a[3594]=0; - a[3595]=0; - a[3596]=0; - a[3597]=0; - a[3598]=0; - a[3599]=0; - a[3600]=0; - a[3601]=0; - a[3602]=0; - a[3603]=0; - a[3604]=0; - a[3605]=0; - a[3606]=0; - a[3607]=0; - a[3608]=0; - a[3609]=0; - a[3610]=0; - a[3611]=0; - a[3612]=0; - a[3613]=0; - a[3614]=0; - a[3615]=0; - a[3616]=0; - a[3617]=0; - a[3618]=0; - a[3619]=0; - a[3620]=0; - a[3621]=0; - a[3622]=0; - a[3623]=0; - a[3624]=0; - a[3625]=0; - a[3626]=0; - a[3627]=0; - a[3628]=0; - a[3629]=0; - a[3630]=0; - a[3631]=0; - a[3632]=0; - a[3633]=0; - a[3634]=0; - a[3635]=0; - a[3636]=0; - a[3637]=0; - a[3638]=0; - a[3639]=0; - a[3640]=0; - a[3641]=0; - a[3642]=0; - a[3643]=0; - a[3644]=0; - a[3645]=0; - a[3646]=0; - a[3647]=0; - a[3648]=0; - a[3649]=0; - a[3650]=0; - a[3651]=0; - a[3652]=0; - a[3653]=0; - a[3654]=0; - a[3655]=0; - a[3656]=0; - a[3657]=0; - a[3658]=0; - a[3659]=0; - a[3660]=0; - a[3661]=0; - a[3662]=0; - a[3663]=0; - a[3664]=0; - a[3665]=0; - a[3666]=0; - a[3667]=0; - a[3668]=0; - a[3669]=0; - a[3670]=0; - a[3671]=0; - a[3672]=0; - a[3673]=0; - a[3674]=0; - a[3675]=0; - a[3676]=0; - a[3677]=0; - a[3678]=0; - a[3679]=0; - a[3680]=0; - a[3681]=0; - a[3682]=0; - a[3683]=0; - a[3684]=0; - a[3685]=0; - a[3686]=0; - a[3687]=0; - a[3688]=0; - a[3689]=0; - a[3690]=0; - a[3691]=0; - a[3692]=0; - a[3693]=0; - a[3694]=0; - a[3695]=0; - a[3696]=0; - a[3697]=0; - a[3698]=0; - a[3699]=0; - a[3700]=0; - a[3701]=0; - a[3702]=0; - a[3703]=0; - a[3704]=0; - a[3705]=0; - a[3706]=0; - a[3707]=0; - a[3708]=0; - a[3709]=0; - a[3710]=0; - a[3711]=0; - a[3712]=0; - a[3713]=0; - a[3714]=0; - a[3715]=0; - a[3716]=0; - a[3717]=0; - a[3718]=0; - a[3719]=0; - a[3720]=0; - a[3721]=0; - a[3722]=0; - a[3723]=0; - a[3724]=0; - a[3725]=0; - a[3726]=0; - a[3727]=0; - a[3728]=0; - a[3729]=0; - a[3730]=0; - a[3731]=0; - a[3732]=0; - a[3733]=0; - a[3734]=0; - a[3735]=0; - a[3736]=0; - a[3737]=0; - a[3738]=0; - a[3739]=0; - a[3740]=0; - a[3741]=0; - a[3742]=0; - a[3743]=0; - a[3744]=0; - a[3745]=0; - a[3746]=0; - a[3747]=0; - a[3748]=0; - a[3749]=0; - a[3750]=0; - a[3751]=0; - a[3752]=0; - a[3753]=0; - a[3754]=0; - a[3755]=0; - a[3756]=0; - a[3757]=0; - a[3758]=0; - a[3759]=0; - a[3760]=0; - a[3761]=0; - a[3762]=0; - a[3763]=0; - a[3764]=0; - a[3765]=0; - a[3766]=0; - a[3767]=0; - a[3768]=0; - a[3769]=0; - a[3770]=0; - a[3771]=0; - a[3772]=0; - a[3773]=0; - a[3774]=0; - a[3775]=0; - a[3776]=0; - a[3777]=0; - a[3778]=0; - a[3779]=0; - a[3780]=0; - a[3781]=0; - a[3782]=0; - a[3783]=0; - a[3784]=0; - a[3785]=0; - a[3786]=0; - a[3787]=0; - a[3788]=0; - a[3789]=0; - a[3790]=0; - a[3791]=0; - a[3792]=0; - a[3793]=0; - a[3794]=0; - a[3795]=0; - a[3796]=0; - a[3797]=0; - a[3798]=0; - a[3799]=0; - a[3800]=0; - a[3801]=0; - a[3802]=0; - a[3803]=0; - a[3804]=0; - a[3805]=0; - a[3806]=0; - a[3807]=0; - a[3808]=0; - a[3809]=0; - a[3810]=0; - a[3811]=0; - a[3812]=0; - a[3813]=0; - a[3814]=0; - a[3815]=0; - a[3816]=0; - a[3817]=0; - a[3818]=0; - a[3819]=0; - a[3820]=0; - a[3821]=0; - a[3822]=0; - a[3823]=0; - a[3824]=0; - a[3825]=0; - a[3826]=0; - a[3827]=0; - a[3828]=0; - a[3829]=0; - a[3830]=0; - a[3831]=0; - a[3832]=0; - a[3833]=0; - a[3834]=0; - a[3835]=0; - a[3836]=0; - a[3837]=0; - a[3838]=0; - a[3839]=0; - a[3840]=0; - a[3841]=0; - a[3842]=0; - a[3843]=0; - a[3844]=0; - a[3845]=0; - a[3846]=0; - a[3847]=0; - a[3848]=0; - a[3849]=0; - a[3850]=0; - a[3851]=0; - a[3852]=0; - a[3853]=0; - a[3854]=0; - a[3855]=0; - a[3856]=0; - a[3857]=0; - a[3858]=0; - a[3859]=0; - a[3860]=0; - a[3861]=0; - a[3862]=0; - a[3863]=0; - a[3864]=0; - a[3865]=0; - a[3866]=0; - a[3867]=0; - a[3868]=0; - a[3869]=0; - a[3870]=0; - a[3871]=0; - a[3872]=0; - a[3873]=0; - a[3874]=0; - a[3875]=0; - a[3876]=0; - a[3877]=0; - a[3878]=0; - a[3879]=0; - a[3880]=0; - a[3881]=0; - a[3882]=0; - a[3883]=0; - a[3884]=0; - a[3885]=0; - a[3886]=0; - a[3887]=0; - a[3888]=0; - a[3889]=0; - a[3890]=0; - a[3891]=0; - a[3892]=0; - a[3893]=0; - a[3894]=0; - a[3895]=0; - a[3896]=0; - a[3897]=0; - a[3898]=0; - a[3899]=0; - a[3900]=0; - a[3901]=0; - a[3902]=0; - a[3903]=0; - a[3904]=0; - a[3905]=0; - a[3906]=0; - a[3907]=0; - a[3908]=0; - a[3909]=0; - a[3910]=0; - a[3911]=0; - a[3912]=0; - a[3913]=0; - a[3914]=0; - a[3915]=0; - a[3916]=0; - a[3917]=0; - a[3918]=0; - a[3919]=0; - a[3920]=0; - a[3921]=0; - a[3922]=0; - a[3923]=0; - a[3924]=0; - a[3925]=0; - a[3926]=0; - a[3927]=0; - a[3928]=0; - a[3929]=0; - a[3930]=0; - a[3931]=0; - a[3932]=0; - a[3933]=0; - a[3934]=0; - a[3935]=0; - a[3936]=0; - a[3937]=0; - a[3938]=0; - a[3939]=0; - a[3940]=0; - a[3941]=0; - a[3942]=0; - a[3943]=0; - a[3944]=0; - a[3945]=0; - a[3946]=0; - a[3947]=0; - a[3948]=0; - a[3949]=0; - a[3950]=0; - a[3951]=0; - a[3952]=0; - a[3953]=0; - a[3954]=0; - a[3955]=0; - a[3956]=0; - a[3957]=0; - a[3958]=0; - a[3959]=0; - a[3960]=0; - a[3961]=0; - a[3962]=0; - a[3963]=0; - a[3964]=0; - a[3965]=0; - a[3966]=0; - a[3967]=0; - a[3968]=0; - a[3969]=0; - a[3970]=0; - a[3971]=0; - a[3972]=0; - a[3973]=0; - a[3974]=0; - a[3975]=0; - a[3976]=0; - a[3977]=0; - a[3978]=0; - a[3979]=0; - a[3980]=0; - a[3981]=0; - a[3982]=0; - a[3983]=0; - a[3984]=0; - a[3985]=0; - a[3986]=0; - a[3987]=0; - a[3988]=0; - a[3989]=0; - a[3990]=0; - a[3991]=0; - a[3992]=0; - a[3993]=0; - a[3994]=0; - a[3995]=0; - a[3996]=0; - a[3997]=0; - a[3998]=0; - a[3999]=0; - a[4000]=0; - a[4001]=0; - a[4002]=0; - a[4003]=0; - a[4004]=0; - a[4005]=0; - a[4006]=0; - a[4007]=0; - a[4008]=0; - a[4009]=0; - a[4010]=0; - a[4011]=0; - a[4012]=0; - a[4013]=0; - a[4014]=0; - a[4015]=0; - a[4016]=0; - a[4017]=0; - a[4018]=0; - a[4019]=0; - a[4020]=0; - a[4021]=0; - a[4022]=0; - a[4023]=0; - a[4024]=0; - a[4025]=0; - a[4026]=0; - a[4027]=0; - a[4028]=0; - a[4029]=0; - a[4030]=0; - a[4031]=0; - a[4032]=0; - a[4033]=0; - a[4034]=0; - a[4035]=0; - a[4036]=0; - a[4037]=0; - a[4038]=0; - a[4039]=0; - a[4040]=0; - a[4041]=0; - a[4042]=0; - a[4043]=0; - a[4044]=0; - a[4045]=0; - a[4046]=0; - a[4047]=0; - a[4048]=0; - a[4049]=0; - a[4050]=0; - a[4051]=0; - a[4052]=0; - a[4053]=0; - a[4054]=0; - a[4055]=0; - a[4056]=0; - a[4057]=0; - a[4058]=0; - a[4059]=0; - a[4060]=0; - a[4061]=0; - a[4062]=0; - a[4063]=0; - a[4064]=0; - a[4065]=0; - a[4066]=0; - a[4067]=0; - a[4068]=0; - a[4069]=0; - a[4070]=0; - a[4071]=0; - a[4072]=0; - a[4073]=0; - a[4074]=0; - a[4075]=0; - a[4076]=0; - a[4077]=0; - a[4078]=0; - a[4079]=0; - a[4080]=0; - a[4081]=0; - a[4082]=0; - a[4083]=0; - a[4084]=0; - a[4085]=0; - a[4086]=0; - a[4087]=0; - a[4088]=0; - a[4089]=0; - a[4090]=0; - a[4091]=0; - a[4092]=0; - a[4093]=0; - a[4094]=0; - a[4095]=0; - a[4096]=0; - a[4097]=0; - a[4098]=0; - a[4099]=0; - a[4100]=0; - a[4101]=0; - a[4102]=0; - a[4103]=0; - a[4104]=0; - a[4105]=0; - a[4106]=0; - a[4107]=0; - a[4108]=0; - a[4109]=0; - a[4110]=0; - a[4111]=0; - a[4112]=0; - a[4113]=0; - a[4114]=0; - a[4115]=0; - a[4116]=0; - a[4117]=0; - a[4118]=0; - a[4119]=0; - a[4120]=0; - a[4121]=0; - a[4122]=0; - a[4123]=0; - a[4124]=0; - a[4125]=0; - a[4126]=0; - a[4127]=0; - a[4128]=0; - a[4129]=0; - a[4130]=0; - a[4131]=0; - a[4132]=0; - a[4133]=0; - a[4134]=0; - a[4135]=0; - a[4136]=0; - a[4137]=0; - a[4138]=0; - a[4139]=0; - a[4140]=0; - a[4141]=0; - a[4142]=0; - a[4143]=0; - a[4144]=0; - a[4145]=0; - a[4146]=0; - a[4147]=0; - a[4148]=0; - a[4149]=0; - a[4150]=0; - a[4151]=0; - a[4152]=0; - a[4153]=0; - a[4154]=0; - a[4155]=0; - a[4156]=0; - a[4157]=0; - a[4158]=0; - a[4159]=0; - a[4160]=0; - a[4161]=0; - a[4162]=0; - a[4163]=0; - a[4164]=0; - a[4165]=0; - a[4166]=0; - a[4167]=0; - a[4168]=0; - a[4169]=0; - a[4170]=0; - a[4171]=0; - a[4172]=0; - a[4173]=0; - a[4174]=0; - a[4175]=0; - a[4176]=0; - a[4177]=0; - a[4178]=0; - a[4179]=0; - a[4180]=0; - a[4181]=0; - a[4182]=0; - a[4183]=0; - a[4184]=0; - a[4185]=0; - a[4186]=0; - a[4187]=0; - a[4188]=0; - a[4189]=0; - a[4190]=0; - a[4191]=0; - a[4192]=0; - a[4193]=0; - a[4194]=0; - a[4195]=0; - a[4196]=0; - a[4197]=0; - a[4198]=0; - a[4199]=0; - a[4200]=0; - a[4201]=0; - a[4202]=0; - a[4203]=0; - a[4204]=0; - a[4205]=0; - a[4206]=0; - a[4207]=0; - a[4208]=0; - a[4209]=0; - a[4210]=0; - a[4211]=0; - a[4212]=0; - a[4213]=0; - a[4214]=0; - a[4215]=0; - a[4216]=0; - a[4217]=0; - a[4218]=0; - a[4219]=0; - a[4220]=0; - a[4221]=0; - a[4222]=0; - a[4223]=0; - a[4224]=0; - a[4225]=0; - a[4226]=0; - a[4227]=0; - a[4228]=0; - a[4229]=0; - a[4230]=0; - a[4231]=0; - a[4232]=0; - a[4233]=0; - a[4234]=0; - a[4235]=0; - a[4236]=0; - a[4237]=0; - a[4238]=0; - a[4239]=0; - a[4240]=0; - a[4241]=0; - a[4242]=0; - a[4243]=0; - a[4244]=0; - a[4245]=0; - a[4246]=0; - a[4247]=0; - a[4248]=0; - a[4249]=0; - a[4250]=0; - a[4251]=0; - a[4252]=0; - a[4253]=0; - a[4254]=0; - a[4255]=0; - a[4256]=0; - a[4257]=0; - a[4258]=0; - a[4259]=0; - a[4260]=0; - a[4261]=0; - a[4262]=0; - a[4263]=0; - a[4264]=0; - a[4265]=0; - a[4266]=0; - a[4267]=0; - a[4268]=0; - a[4269]=0; - a[4270]=0; - a[4271]=0; - a[4272]=0; - a[4273]=0; - a[4274]=0; - a[4275]=0; - a[4276]=0; - a[4277]=0; - a[4278]=0; - a[4279]=0; - a[4280]=0; - a[4281]=0; - a[4282]=0; - a[4283]=0; - a[4284]=0; - a[4285]=0; - a[4286]=0; - a[4287]=0; - a[4288]=0; - a[4289]=0; - a[4290]=0; - a[4291]=0; - a[4292]=0; - a[4293]=0; - a[4294]=0; - a[4295]=0; - a[4296]=0; - a[4297]=0; - a[4298]=0; - a[4299]=0; - a[4300]=0; - a[4301]=0; - a[4302]=0; - a[4303]=0; - a[4304]=0; - a[4305]=0; - a[4306]=0; - a[4307]=0; - a[4308]=0; - a[4309]=0; - a[4310]=0; - a[4311]=0; - a[4312]=0; - a[4313]=0; - a[4314]=0; - a[4315]=0; - a[4316]=0; - a[4317]=0; - a[4318]=0; - a[4319]=0; - a[4320]=0; - a[4321]=0; - a[4322]=0; - a[4323]=0; - a[4324]=0; - a[4325]=0; - a[4326]=0; - a[4327]=0; - a[4328]=0; - a[4329]=0; - a[4330]=0; - a[4331]=0; - a[4332]=0; - a[4333]=0; - a[4334]=0; - a[4335]=0; - a[4336]=0; - a[4337]=0; - a[4338]=0; - a[4339]=0; - a[4340]=0; - a[4341]=0; - a[4342]=0; - a[4343]=0; - a[4344]=0; - a[4345]=0; - a[4346]=0; - a[4347]=0; - a[4348]=0; - a[4349]=0; - a[4350]=0; - a[4351]=0; - a[4352]=0; - a[4353]=0; - a[4354]=0; - a[4355]=0; - a[4356]=0; - a[4357]=0; - a[4358]=0; - a[4359]=0; - a[4360]=0; - a[4361]=0; - a[4362]=0; - a[4363]=0; - a[4364]=0; - a[4365]=0; - a[4366]=0; - a[4367]=0; - a[4368]=0; - a[4369]=0; - a[4370]=0; - a[4371]=0; - a[4372]=0; - a[4373]=0; - a[4374]=0; - a[4375]=0; - a[4376]=0; - a[4377]=0; - a[4378]=0; - a[4379]=0; - a[4380]=0; - a[4381]=0; - a[4382]=0; - a[4383]=0; - a[4384]=0; - a[4385]=0; - a[4386]=0; - a[4387]=0; - a[4388]=0; - a[4389]=0; - a[4390]=0; - a[4391]=0; - a[4392]=0; - a[4393]=0; - a[4394]=0; - a[4395]=0; - a[4396]=0; - a[4397]=0; - a[4398]=0; - a[4399]=0; - a[4400]=0; - a[4401]=0; - a[4402]=0; - a[4403]=0; - a[4404]=0; - a[4405]=0; - a[4406]=0; - a[4407]=0; - a[4408]=0; - a[4409]=0; - a[4410]=0; - a[4411]=0; - a[4412]=0; - a[4413]=0; - a[4414]=0; - a[4415]=0; - a[4416]=0; - a[4417]=0; - a[4418]=0; - a[4419]=0; - a[4420]=0; - a[4421]=0; - a[4422]=0; - a[4423]=0; - a[4424]=0; - a[4425]=0; - a[4426]=0; - a[4427]=0; - a[4428]=0; - a[4429]=0; - a[4430]=0; - a[4431]=0; - a[4432]=0; - a[4433]=0; - a[4434]=0; - a[4435]=0; - a[4436]=0; - a[4437]=0; - a[4438]=0; - a[4439]=0; - a[4440]=0; - a[4441]=0; - a[4442]=0; - a[4443]=0; - a[4444]=0; - a[4445]=0; - a[4446]=0; - a[4447]=0; - a[4448]=0; - a[4449]=0; - a[4450]=0; - a[4451]=0; - a[4452]=0; - a[4453]=0; - a[4454]=0; - a[4455]=0; - a[4456]=0; - a[4457]=0; - a[4458]=0; - a[4459]=0; - a[4460]=0; - a[4461]=0; - a[4462]=0; - a[4463]=0; - a[4464]=0; - a[4465]=0; - a[4466]=0; - a[4467]=0; - a[4468]=0; - a[4469]=0; - a[4470]=0; - a[4471]=0; - a[4472]=0; - a[4473]=0; - a[4474]=0; - a[4475]=0; - a[4476]=0; - a[4477]=0; - a[4478]=0; - a[4479]=0; - a[4480]=0; - a[4481]=0; - a[4482]=0; - a[4483]=0; - a[4484]=0; - a[4485]=0; - a[4486]=0; - a[4487]=0; - a[4488]=0; - a[4489]=0; - a[4490]=0; - a[4491]=0; - a[4492]=0; - a[4493]=0; - a[4494]=0; - a[4495]=0; - a[4496]=0; - a[4497]=0; - a[4498]=0; - a[4499]=0; - a[4500]=0; - a[4501]=0; - a[4502]=0; - a[4503]=0; - a[4504]=0; - a[4505]=0; - a[4506]=0; - a[4507]=0; - a[4508]=0; - a[4509]=0; - a[4510]=0; - a[4511]=0; - a[4512]=0; - a[4513]=0; - a[4514]=0; - a[4515]=0; - a[4516]=0; - a[4517]=0; - a[4518]=0; - a[4519]=0; - a[4520]=0; - a[4521]=0; - a[4522]=0; - a[4523]=0; - a[4524]=0; - a[4525]=0; - a[4526]=0; - a[4527]=0; - a[4528]=0; - a[4529]=0; - a[4530]=0; - a[4531]=0; - a[4532]=0; - a[4533]=0; - a[4534]=0; - a[4535]=0; - a[4536]=0; - a[4537]=0; - a[4538]=0; - a[4539]=0; - a[4540]=0; - a[4541]=0; - a[4542]=0; - a[4543]=0; - a[4544]=0; - a[4545]=0; - a[4546]=0; - a[4547]=0; - a[4548]=0; - a[4549]=0; - a[4550]=0; - a[4551]=0; - a[4552]=0; - a[4553]=0; - a[4554]=0; - a[4555]=0; - a[4556]=0; - a[4557]=0; - a[4558]=0; - a[4559]=0; - a[4560]=0; - a[4561]=0; - a[4562]=0; - a[4563]=0; - a[4564]=0; - a[4565]=0; - a[4566]=0; - a[4567]=0; - a[4568]=0; - a[4569]=0; - a[4570]=0; - a[4571]=0; - a[4572]=0; - a[4573]=0; - a[4574]=0; - a[4575]=0; - a[4576]=0; - a[4577]=0; - a[4578]=0; - a[4579]=0; - a[4580]=0; - a[4581]=0; - a[4582]=0; - a[4583]=0; - a[4584]=0; - a[4585]=0; - a[4586]=0; - a[4587]=0; - a[4588]=0; - a[4589]=0; - a[4590]=0; - a[4591]=0; - a[4592]=0; - a[4593]=0; - a[4594]=0; - a[4595]=0; - a[4596]=0; - a[4597]=0; - a[4598]=0; - a[4599]=0; - a[4600]=0; - a[4601]=0; - a[4602]=0; - a[4603]=0; - a[4604]=0; - a[4605]=0; - a[4606]=0; - a[4607]=0; - a[4608]=0; - a[4609]=0; - a[4610]=0; - a[4611]=0; - a[4612]=0; - a[4613]=0; - a[4614]=0; - a[4615]=0; - a[4616]=0; - a[4617]=0; - a[4618]=0; - a[4619]=0; - a[4620]=0; - a[4621]=0; - a[4622]=0; - a[4623]=0; - a[4624]=0; - a[4625]=0; - a[4626]=0; - a[4627]=0; - a[4628]=0; - a[4629]=0; - a[4630]=0; - a[4631]=0; - a[4632]=0; - a[4633]=0; - a[4634]=0; - a[4635]=0; - a[4636]=0; - a[4637]=0; - a[4638]=0; - a[4639]=0; - a[4640]=0; - a[4641]=0; - a[4642]=0; - a[4643]=0; - a[4644]=0; - a[4645]=0; - a[4646]=0; - a[4647]=0; - a[4648]=0; - a[4649]=0; - a[4650]=0; - a[4651]=0; - a[4652]=0; - a[4653]=0; - a[4654]=0; - a[4655]=0; - a[4656]=0; - a[4657]=0; - a[4658]=0; - a[4659]=0; - a[4660]=0; - a[4661]=0; - a[4662]=0; - a[4663]=0; - a[4664]=0; - a[4665]=0; - a[4666]=0; - a[4667]=0; - a[4668]=0; - a[4669]=0; - a[4670]=0; - a[4671]=0; - a[4672]=0; - a[4673]=0; - a[4674]=0; - a[4675]=0; - a[4676]=0; - a[4677]=0; - a[4678]=0; - a[4679]=0; - a[4680]=0; - a[4681]=0; - a[4682]=0; - a[4683]=0; - a[4684]=0; - a[4685]=0; - a[4686]=0; - a[4687]=0; - a[4688]=0; - a[4689]=0; - a[4690]=0; - a[4691]=0; - a[4692]=0; - a[4693]=0; - a[4694]=0; - a[4695]=0; - a[4696]=0; - a[4697]=0; - a[4698]=0; - a[4699]=0; - a[4700]=0; - a[4701]=0; - a[4702]=0; - a[4703]=0; - a[4704]=0; - a[4705]=0; - a[4706]=0; - a[4707]=0; - a[4708]=0; - a[4709]=0; - a[4710]=0; - a[4711]=0; - a[4712]=0; - a[4713]=0; - a[4714]=0; - a[4715]=0; - a[4716]=0; - a[4717]=0; - a[4718]=0; - a[4719]=0; - a[4720]=0; - a[4721]=0; - a[4722]=0; - a[4723]=0; - a[4724]=0; - a[4725]=0; - a[4726]=0; - a[4727]=0; - a[4728]=0; - a[4729]=0; - a[4730]=0; - a[4731]=0; - a[4732]=0; - a[4733]=0; - a[4734]=0; - a[4735]=0; - a[4736]=0; - a[4737]=0; - a[4738]=0; - a[4739]=0; - a[4740]=0; - a[4741]=0; - a[4742]=0; - a[4743]=0; - a[4744]=0; - a[4745]=0; - a[4746]=0; - a[4747]=0; - a[4748]=0; - a[4749]=0; - a[4750]=0; - a[4751]=0; - a[4752]=0; - a[4753]=0; - a[4754]=0; - a[4755]=0; - a[4756]=0; - a[4757]=0; - a[4758]=0; - a[4759]=0; - a[4760]=0; - a[4761]=0; - a[4762]=0; - a[4763]=0; - a[4764]=0; - a[4765]=0; - a[4766]=0; - a[4767]=0; - a[4768]=0; - a[4769]=0; - a[4770]=0; - a[4771]=0; - a[4772]=0; - a[4773]=0; - a[4774]=0; - a[4775]=0; - a[4776]=0; - a[4777]=0; - a[4778]=0; - a[4779]=0; - a[4780]=0; - a[4781]=0; - a[4782]=0; - a[4783]=0; - a[4784]=0; - a[4785]=0; - a[4786]=0; - a[4787]=0; - a[4788]=0; - a[4789]=0; - a[4790]=0; - a[4791]=0; - a[4792]=0; - a[4793]=0; - a[4794]=0; - a[4795]=0; - a[4796]=0; - a[4797]=0; - a[4798]=0; - a[4799]=0; - a[4800]=0; - a[4801]=0; - a[4802]=0; - a[4803]=0; - a[4804]=0; - a[4805]=0; - a[4806]=0; - a[4807]=0; - a[4808]=0; - a[4809]=0; - a[4810]=0; - a[4811]=0; - a[4812]=0; - a[4813]=0; - a[4814]=0; - a[4815]=0; - a[4816]=0; - a[4817]=0; - a[4818]=0; - a[4819]=0; - a[4820]=0; - a[4821]=0; - a[4822]=0; - a[4823]=0; - a[4824]=0; - a[4825]=0; - a[4826]=0; - a[4827]=0; - a[4828]=0; - a[4829]=0; - a[4830]=0; - a[4831]=0; - a[4832]=0; - a[4833]=0; - a[4834]=0; - a[4835]=0; - a[4836]=0; - a[4837]=0; - a[4838]=0; - a[4839]=0; - a[4840]=0; - a[4841]=0; - a[4842]=0; - a[4843]=0; - a[4844]=0; - a[4845]=0; - a[4846]=0; - a[4847]=0; - a[4848]=0; - a[4849]=0; - a[4850]=0; - a[4851]=0; - a[4852]=0; - a[4853]=0; - a[4854]=0; - a[4855]=0; - a[4856]=0; - a[4857]=0; - a[4858]=0; - a[4859]=0; - a[4860]=0; - a[4861]=0; - a[4862]=0; - a[4863]=0; - a[4864]=0; - a[4865]=0; - a[4866]=0; - a[4867]=0; - a[4868]=0; - a[4869]=0; - a[4870]=0; - a[4871]=0; - a[4872]=0; - a[4873]=0; - a[4874]=0; - a[4875]=0; - a[4876]=0; - a[4877]=0; - a[4878]=0; - a[4879]=0; - a[4880]=0; - a[4881]=0; - a[4882]=0; - a[4883]=0; - a[4884]=0; - a[4885]=0; - a[4886]=0; - a[4887]=0; - a[4888]=0; - a[4889]=0; - a[4890]=0; - a[4891]=0; - a[4892]=0; - a[4893]=0; - a[4894]=0; - a[4895]=0; - a[4896]=0; - a[4897]=0; - a[4898]=0; - a[4899]=0; - a[4900]=0; - a[4901]=0; - a[4902]=0; - a[4903]=0; - a[4904]=0; - a[4905]=0; - a[4906]=0; - a[4907]=0; - a[4908]=0; - a[4909]=0; - a[4910]=0; - a[4911]=0; - a[4912]=0; - a[4913]=0; - a[4914]=0; - a[4915]=0; - a[4916]=0; - a[4917]=0; - a[4918]=0; - a[4919]=0; - a[4920]=0; - a[4921]=0; - a[4922]=0; - a[4923]=0; - a[4924]=0; - a[4925]=0; - a[4926]=0; - a[4927]=0; - a[4928]=0; - a[4929]=0; - a[4930]=0; - a[4931]=0; - a[4932]=0; - a[4933]=0; - a[4934]=0; - a[4935]=0; - a[4936]=0; - a[4937]=0; - a[4938]=0; - a[4939]=0; - a[4940]=0; - a[4941]=0; - a[4942]=0; - a[4943]=0; - a[4944]=0; - a[4945]=0; - a[4946]=0; - a[4947]=0; - a[4948]=0; - a[4949]=0; - a[4950]=0; - a[4951]=0; - a[4952]=0; - a[4953]=0; - a[4954]=0; - a[4955]=0; - a[4956]=0; - a[4957]=0; - a[4958]=0; - a[4959]=0; - a[4960]=0; - a[4961]=0; - a[4962]=0; - a[4963]=0; - a[4964]=0; - a[4965]=0; - a[4966]=0; - a[4967]=0; - a[4968]=0; - a[4969]=0; - a[4970]=0; - a[4971]=0; - a[4972]=0; - a[4973]=0; - a[4974]=0; - a[4975]=0; - a[4976]=0; - a[4977]=0; - a[4978]=0; - a[4979]=0; - a[4980]=0; - a[4981]=0; - a[4982]=0; - a[4983]=0; - a[4984]=0; - a[4985]=0; - a[4986]=0; - a[4987]=0; - a[4988]=0; - a[4989]=0; - a[4990]=0; - a[4991]=0; - a[4992]=0; - a[4993]=0; - a[4994]=0; - a[4995]=0; - a[4996]=0; - a[4997]=0; - a[4998]=0; - a[4999]=0; - return a; -} diff --git a/deps/v8/test/mjsunit/regress/regress-1980.js b/deps/v8/test/mjsunit/regress/regress-1980.js index 49dfd063ba..d87ff45074 100644 --- a/deps/v8/test/mjsunit/regress/regress-1980.js +++ b/deps/v8/test/mjsunit/regress/regress-1980.js @@ -34,7 +34,7 @@ for (var i = 0; i < invalid_this.length; i++) { Error.prototype.toString.call(invalid_this[i]); } catch (e) { exception = true; - assertTrue("called_on_non_object" == e.type); + assertEquals("Error.prototype.toString called on non-object", e.message); } assertTrue(exception); } diff --git a/deps/v8/test/mjsunit/regress/regress-2261.js b/deps/v8/test/mjsunit/regress/regress-2261.js new file mode 100644 index 0000000000..000e07de5b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2261.js @@ -0,0 +1,113 @@ +// 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 materialization of the arguments object when deoptimizing a +// strict mode closure after modifying an argument. + +(function () { + var forceDeopt = 0; + function inner(x) { + "use strict"; + x = 2; + // Do not remove this %DebugPrint as it makes sure the deopt happens + // after the assignment and is not hoisted above the assignment. + %DebugPrint(arguments[0]); + forceDeopt + 1; + return arguments[0]; + } + + assertEquals(1, inner(1)); + assertEquals(1, inner(1)); + %OptimizeFunctionOnNextCall(inner); + assertEquals(1, inner(1)); + forceDeopt = "not a number"; + assertEquals(1, inner(1)); +})(); + + +// Test materialization of the arguments object when deoptimizing an +// inlined strict mode closure after modifying an argument. + +(function () { + var forceDeopt = 0; + function inner(x) { + "use strict"; + x = 2; + // Do not remove this %DebugPrint as it makes sure the deopt happens + // after the assignment and is not hoisted above the assignment. + %DebugPrint(arguments[0]); + forceDeopt + 1; + return arguments[0]; + } + + function outer(x) { + return inner(x); + } + + assertEquals(1, outer(1)); + assertEquals(1, outer(1)); + %OptimizeFunctionOnNextCall(outer); + assertEquals(1, outer(1)); + forceDeopt = "not a number"; + assertEquals(1, outer(1)); +})(); + + +// Test materialization of the multiple arguments objects when +// deoptimizing several inlined closure after modifying an argument. + +(function () { + var forceDeopt = 0; + function inner(x,y,z) { + "use strict"; + x = 3; + // Do not remove this %DebugPrint as it makes sure the deopt happens + // after the assignment and is not hoisted above the assignment. + %DebugPrint(arguments[0]); + forceDeopt + 1; + return arguments[0]; + } + + function middle(x) { + "use strict"; + x = 2; + return inner(10*x, 20*x, 30*x) + arguments[0]; + } + + function outer(x) { + return middle(x); + } + + assertEquals(21, outer(1)); + assertEquals(21, outer(1)); + %OptimizeFunctionOnNextCall(outer); + assertEquals(21, outer(1)); + forceDeopt = "not a number"; + assertEquals(21, outer(1)); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-2263.js b/deps/v8/test/mjsunit/regress/regress-2263.js new file mode 100644 index 0000000000..9a9db58773 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2263.js @@ -0,0 +1,30 @@ +// 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 obj = { length: { valueOf: function(){ throw { type: "length" }}}}; +var sep = { toString: function(){ throw { type: "toString" }}}; +assertThrows("Array.prototype.join.call(obj, sep)", undefined, "length"); diff --git a/deps/v8/test/mjsunit/regress-2286.js b/deps/v8/test/mjsunit/regress/regress-2286.js index 372451ec44..372451ec44 100644 --- a/deps/v8/test/mjsunit/regress-2286.js +++ b/deps/v8/test/mjsunit/regress/regress-2286.js diff --git a/deps/v8/test/mjsunit/regress/regress-2315.js b/deps/v8/test/mjsunit/regress/regress-2315.js new file mode 100644 index 0000000000..a3f9182c95 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2315.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. + +// Flags: --allow-natives-syntax + +var foo = (function() { + return eval("(function bar() { return 1; })"); +})(); + +foo(); +foo(); +%OptimizeFunctionOnNextCall(foo); +foo(); + +// Function should be optimized now. +assertTrue(%GetOptimizationStatus(foo) != 2); diff --git a/deps/v8/test/mjsunit/regress/regress-2318.js b/deps/v8/test/mjsunit/regress/regress-2318.js new file mode 100644 index 0000000000..ca67ab2ca5 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2318.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: --expose-debug-as debug --nostack-trace-on-abort + +function f() { + var i = 0; + + // Stack-allocate to reach the end of stack quickly. + var _A0 = 00; var _A1 = 01; var _A2 = 02; var _A3 = 03; var _A4 = 04; + var _B0 = 05; var _B1 = 06; var _B2 = 07; var _B3 = 08; var _B4 = 09; + var _C0 = 10; var _C1 = 11; var _C2 = 12; var _C3 = 13; var _C4 = 14; + var _D0 = 15; var _D1 = 16; var _D2 = 17; var _D3 = 18; var _D4 = 19; + var _E0 = 20; var _E1 = 21; var _E2 = 22; var _E3 = 23; var _E4 = 24; + var _F0 = 25; var _F1 = 26; var _F2 = 27; var _F3 = 28; var _F4 = 29; + var _G0 = 30; var _G1 = 31; var _G2 = 32; var _G3 = 33; var _G4 = 34; + var _H0 = 35; var _H1 = 36; var _H2 = 37; var _H3 = 38; var _H4 = 39; + var _I0 = 40; var _I1 = 41; var _I2 = 42; var _I3 = 43; var _I4 = 44; + var _J0 = 45; var _J1 = 46; var _J2 = 47; var _J3 = 48; var _J4 = 49; + var _K0 = 50; var _K1 = 51; var _K2 = 52; var _K3 = 53; var _K4 = 54; + var _L0 = 55; var _L1 = 56; var _L2 = 57; var _L3 = 58; var _L4 = 59; + var _M0 = 60; var _M1 = 61; var _M2 = 62; var _M3 = 63; var _M4 = 64; + var _N0 = 65; var _N1 = 66; var _N2 = 67; var _N3 = 68; var _N4 = 69; + var _O0 = 70; var _O1 = 71; var _O2 = 72; var _O3 = 73; var _O4 = 74; + var _P0 = 75; var _P1 = 76; var _P2 = 77; var _P3 = 78; var _P4 = 79; + var _Q0 = 80; var _Q1 = 81; var _Q2 = 82; var _Q3 = 83; var _Q4 = 84; + var _R0 = 85; var _R1 = 86; var _R2 = 87; var _R3 = 88; var _R4 = 89; + var _S0 = 90; var _S1 = 91; var _S2 = 92; var _S3 = 93; var _S4 = 94; + var _T0 = 95; var _T1 = 96; var _T2 = 97; var _T3 = 98; var _T4 = 99; + + f(); +}; + +Debug = debug.Debug; +var bp = Debug.setBreakPoint(f, 0); + +function listener(event, exec_state, event_data, data) { + result = exec_state.frame().evaluate("i").value(); +}; + +Debug.setListener(listener); +assertThrows(function() { f(); }, RangeError); diff --git a/deps/v8/test/mjsunit/regress/regress-2322.js b/deps/v8/test/mjsunit/regress/regress-2322.js new file mode 100644 index 0000000000..1195bab67c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2322.js @@ -0,0 +1,36 @@ +// 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-scoping + +"use strict"; + +assertThrows("'use strict'; for (let x in x);", ReferenceError); + +let s; +for (let pppp in {}) {}; +assertThrows(function() { pppp = true }, ReferenceError); diff --git a/deps/v8/test/mjsunit/regress/regress-2336.js b/deps/v8/test/mjsunit/regress/regress-2336.js new file mode 100644 index 0000000000..edfff60211 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2336.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: --expose-debug-as debug --expose-gc + +// Check that we can cope with a debug listener that runs in the +// GC epilogue and causes enough allocation to trigger a new GC during +// the epilogue. + +var f = eval("(function f() { return 42; })"); + +Debug = debug.Debug; + +var called = false; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.ScriptCollected) { + if (!called) { + called = true; + gc(); + } + } +}; + +Debug.scripts(); +Debug.setListener(listener); +f = void 0; +gc(); +assertTrue(called); diff --git a/deps/v8/test/mjsunit/regress/regress-2339.js b/deps/v8/test/mjsunit/regress/regress-2339.js new file mode 100644 index 0000000000..b16821dbad --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2339.js @@ -0,0 +1,59 @@ +// 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 + +/** + * The possible optimization states of a function. Must be in sync with the + * return values of Runtime_GetOptimizationStatus() in runtime.cc! + */ + +var OptimizationState = { + YES: 1, + NO: 2, + ALWAYS: 3, + NEVER: 4 +}; + +function simple() { + return simple_two_args(0, undefined); +} + +function simple_two_args(always_zero, always_undefined) { + var always_five = always_undefined || 5; + return always_zero * always_five * .5; +} + + +simple(); +simple(); +%OptimizeFunctionOnNextCall(simple); +simple(); +var raw_optimized = %GetOptimizationStatus(simple); +assertFalse(raw_optimized == OptimizationState.NO); +gc(); + diff --git a/deps/v8/test/mjsunit/regress/regress-2346.js b/deps/v8/test/mjsunit/regress/regress-2346.js new file mode 100644 index 0000000000..4c88b3e284 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2346.js @@ -0,0 +1,123 @@ +// Copyright 2010 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 file only tests very simple descriptors that always have +// configurable, enumerable, and writable set to true. +// A range of more elaborate tests are performed in +// object-define-property.js + +// Flags: --stress-runs=5 + +function get() { return x; } +function set(x) { this.x = x; } + +var obj = {x: 1}; +obj.__defineGetter__("accessor", get); +obj.__defineSetter__("accessor", set); +var a = new Array(); +a[1] = 42; +obj[1] = 42; + +var descIsData = Object.getOwnPropertyDescriptor(obj, 'x'); +assertTrue(descIsData.enumerable); +assertTrue(descIsData.writable); +assertTrue(descIsData.configurable); + +var descIsAccessor = Object.getOwnPropertyDescriptor(obj, 'accessor'); +assertTrue(descIsAccessor.enumerable); +assertTrue(descIsAccessor.configurable); +assertTrue(descIsAccessor.get == get); +assertTrue(descIsAccessor.set == set); + +var descIsNotData = Object.getOwnPropertyDescriptor(obj, 'not-x'); +assertTrue(descIsNotData == undefined); + +var descIsNotAccessor = Object.getOwnPropertyDescriptor(obj, 'not-accessor'); +assertTrue(descIsNotAccessor == undefined); + +var descArray = Object.getOwnPropertyDescriptor(a, '1'); +assertTrue(descArray.enumerable); +assertTrue(descArray.configurable); +assertTrue(descArray.writable); +assertEquals(descArray.value, 42); + +var descObjectElement = Object.getOwnPropertyDescriptor(obj, '1'); +assertTrue(descObjectElement.enumerable); +assertTrue(descObjectElement.configurable); +assertTrue(descObjectElement.writable); +assertEquals(descObjectElement.value, 42); + +// String objects. +var a = new String('foobar'); +for (var i = 0; i < a.length; i++) { + var descStringObject = Object.getOwnPropertyDescriptor(a, i); + assertTrue(descStringObject.enumerable); + assertFalse(descStringObject.configurable); + assertFalse(descStringObject.writable); + assertEquals(descStringObject.value, a.substring(i, i+1)); +} + +// Support for additional attributes on string objects. +a.x = 42; +a[10] = 'foo'; +var descStringProperty = Object.getOwnPropertyDescriptor(a, 'x'); +assertTrue(descStringProperty.enumerable); +assertTrue(descStringProperty.configurable); +assertTrue(descStringProperty.writable); +assertEquals(descStringProperty.value, 42); + +var descStringElement = Object.getOwnPropertyDescriptor(a, '10'); +assertTrue(descStringElement.enumerable); +assertTrue(descStringElement.configurable); +assertTrue(descStringElement.writable); +assertEquals(descStringElement.value, 'foo'); + +// Test that elements in the prototype chain is not returned. +var proto = {}; +proto[10] = 42; + +var objWithProto = new Array(); +objWithProto.prototype = proto; +objWithProto[0] = 'bar'; +var descWithProto = Object.getOwnPropertyDescriptor(objWithProto, '10'); +assertEquals(undefined, descWithProto); + +// Test elements on global proxy object. +var global = (function() { return this; })(); + +global[42] = 42; + +function el_getter() { return 239; }; +function el_setter() {}; +Object.defineProperty(global, '239', {get: el_getter, set: el_setter}); + +var descRegularElement = Object.getOwnPropertyDescriptor(global, '42'); +assertEquals(42, descRegularElement.value); + +var descAccessorElement = Object.getOwnPropertyDescriptor(global, '239'); +assertEquals(el_getter, descAccessorElement.get); +assertEquals(el_setter, descAccessorElement.set); diff --git a/deps/v8/test/mjsunit/regress/regress-2373.js b/deps/v8/test/mjsunit/regress/regress-2373.js new file mode 100644 index 0000000000..16a87ece6f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2373.js @@ -0,0 +1,29 @@ +// 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 o = JSON.parse('{"a":2600753951}'); +assertEquals(2600753951, o.a); diff --git a/deps/v8/test/mjsunit/regress/regress-2374.js b/deps/v8/test/mjsunit/regress/regress-2374.js new file mode 100644 index 0000000000..b12e5f28c2 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2374.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. + +var msg = '{"result":{"profile":{"head":{"functionName":"(root)","url":"","lineNumber":0,"totalTime":495.7243772462511,"selfTime":0,"numberOfCalls":0,"visible":true,"callUID":2771605942,"children":[{"functionName":"(program)","url":"","lineNumber":0,"totalTime":495.7243772462511,"selfTime":495.7243772462511,"numberOfCalls":0,"visible":true,"callUID":1902715303,"children":[]}]},"bottomUpHead":{"functionName":"(root)","url":"","lineNumber":0,"totalTime":495.7243772462511,"selfTime":0,"numberOfCalls":0,"visible":true,"callUID":2771605942,"children":[{"functionName":"(program)","url":"","lineNumber":0,"totalTime":495.7243772462511,"selfTime":495.7243772462511,"numberOfCalls":0,"visible":true,"callUID":1902715303,"children":[]}]}}},"id":41}'; + +var obj = JSON.parse(msg); +var obj2 = JSON.parse(msg); + +assertEquals(JSON.stringify(obj), JSON.stringify(obj2)); diff --git a/deps/v8/test/mjsunit/regress/regress-2398.js b/deps/v8/test/mjsunit/regress/regress-2398.js new file mode 100644 index 0000000000..1c66e7f84c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2398.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. + +"use strict"; + +var observed = false; + +var object = { get toString() { observed = true; } }; +Object.defineProperty(object, "ro", { value: 1 }); + +try { + object.ro = 2; // TypeError caused by trying to write to read-only. +} catch (e) { + e.message; // Forces formatting of the message object. +} + +assertFalse(observed); diff --git a/deps/v8/test/mjsunit/regress/regress-2410.js b/deps/v8/test/mjsunit/regress/regress-2410.js new file mode 100644 index 0000000000..c16fd14cdc --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2410.js @@ -0,0 +1,36 @@ +// 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. + +// Object.prototype should be ignored in Object.getOwnPropertyNames +// +// See http://code.google.com/p/v8/issues/detail?id=2410 for details. + +Object.defineProperty(Object.prototype, + 'thrower', + { get: function() { throw Error('bug') } }); +var obj = { thrower: 'local' }; +assertEquals(['thrower'], Object.getOwnPropertyNames(obj)); diff --git a/deps/v8/test/mjsunit/regress/regress-2416.js b/deps/v8/test/mjsunit/regress/regress-2416.js new file mode 100644 index 0000000000..02afeb9a59 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2416.js @@ -0,0 +1,75 @@ +// 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. + +assertFalse(2147483647 < -2147483648) +assertFalse(2147483647 <= -2147483648) +assertFalse(2147483647 == -2147483648) +assertTrue(2147483647 >= -2147483648) +assertTrue(2147483647 > -2147483648) + +assertTrue(-2147483648 < 2147483647) +assertTrue(-2147483648 <= 2147483647) +assertFalse(-2147483648 == 2147483647) +assertFalse(-2147483648 >= 2147483647) +assertFalse(-2147483648 > 2147483647) + +assertFalse(2147483647 < 2147483647) +assertTrue(2147483647 <= 2147483647) +assertTrue(2147483647 == 2147483647) +assertTrue(2147483647 >= 2147483647) +assertFalse(2147483647 > 2147483647) + +assertFalse(-2147483648 < -2147483648) +assertTrue(-2147483648 <= -2147483648) +assertTrue(-2147483648 == -2147483648) +assertTrue(-2147483648 >= -2147483648) +assertFalse(-2147483648 > -2147483648) + + +assertFalse(1073741823 < -1073741824) +assertFalse(1073741823 <= -1073741824) +assertFalse(1073741823 == -1073741824) +assertTrue(1073741823 >= -1073741824) +assertTrue(1073741823 > -1073741824) + +assertTrue(-1073741824 < 1073741823) +assertTrue(-1073741824 <= 1073741823) +assertFalse(-1073741824 == 1073741823) +assertFalse(-1073741824 >= 1073741823) +assertFalse(-1073741824 > 1073741823) + +assertFalse(1073741823 < 1073741823) +assertTrue(1073741823 <= 1073741823) +assertTrue(1073741823 == 1073741823) +assertTrue(1073741823 >= 1073741823) +assertFalse(1073741823 > 1073741823) + +assertFalse(-1073741824 < -1073741824) +assertTrue(-1073741824 <= -1073741824) +assertTrue(-1073741824 == -1073741824) +assertTrue(-1073741824 >= -1073741824) +assertFalse(-1073741824 > -1073741824) diff --git a/deps/v8/test/mjsunit/regress/regress-2433.js b/deps/v8/test/mjsunit/regress/regress-2433.js new file mode 100644 index 0000000000..dfe7131b59 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2433.js @@ -0,0 +1,36 @@ +// 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. + +// Transitioning from a PackedSmi to PackedDouble should fill the destination +// with holes. +// +// See http://code.google.com/p/v8/issues/detail?id=2433 for details. + +arr = []; +arr[0] = 0; +arr[0] = 1.1; +assertEquals(undefined, arr[1]); diff --git a/deps/v8/test/mjsunit/regress/regress-2437.js b/deps/v8/test/mjsunit/regress/regress-2437.js new file mode 100644 index 0000000000..06b69b23db --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2437.js @@ -0,0 +1,75 @@ +// 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 Regexp.prototype.exec +r = /a/; +r.lastIndex = 1; +r.exec("zzzz"); +assertEquals(0, r.lastIndex); + +// Test Regexp.prototype.test +r = /a/; +r.lastIndex = 1; +r.test("zzzz"); +assertEquals(0, r.lastIndex); + +// Test String.prototype.match +r = /a/; +r.lastIndex = 1; +"zzzz".match(r); +assertEquals(0, r.lastIndex); + +// Test String.prototype.replace with atomic regexp and empty string. +r = /a/; +r.lastIndex = 1; +"zzzz".replace(r, ""); +assertEquals(0, r.lastIndex); + +// Test String.prototype.replace with non-atomic regexp and empty string. +r = /\d/; +r.lastIndex = 1; +"zzzz".replace(r, ""); +assertEquals(0, r.lastIndex); + +// Test String.prototype.replace with atomic regexp and non-empty string. +r = /a/; +r.lastIndex = 1; +"zzzz".replace(r, "a"); +assertEquals(0, r.lastIndex); + +// Test String.prototype.replace with non-atomic regexp and non-empty string. +r = /\d/; +r.lastIndex = 1; +"zzzz".replace(r, "a"); +assertEquals(0, r.lastIndex); + +// Test String.prototype.replace with replacement function +r = /a/; +r.lastIndex = 1; +"zzzz".replace(r, function() { return ""; }); +assertEquals(0, r.lastIndex); + diff --git a/deps/v8/test/mjsunit/regress/regress-2438.js b/deps/v8/test/mjsunit/regress/regress-2438.js new file mode 100644 index 0000000000..3f4fd7df57 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2438.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. + +function testSideEffects(subject, re) { + var counter = 0; + var side_effect_object = { valueOf: function() { return counter++; } }; + re.lastIndex = side_effect_object; + re.exec(subject); + assertEquals(1, counter); + + re.lastIndex = side_effect_object; + re.test(subject); + assertEquals(2, counter); + + re.lastIndex = side_effect_object; + subject.match(re); + assertEquals(3, counter); + + re.lastIndex = side_effect_object; + subject.replace(re, ""); + assertEquals(4, counter); +} + +testSideEffects("zzzz", /a/); +testSideEffects("zzzz", /a/g); +testSideEffects("xaxa", /a/); +testSideEffects("xaxa", /a/g); + diff --git a/deps/v8/test/mjsunit/regress/regress-2443.js b/deps/v8/test/mjsunit/regress/regress-2443.js new file mode 100644 index 0000000000..0800c45c02 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2443.js @@ -0,0 +1,129 @@ +// 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. + +// Number.prototype methods on non-Numbers. + +assertThrows(function() { Number.prototype.toExponential.call({}) }, + TypeError); + +assertThrows(function() { Number.prototype.toPrecision.call({}) }, + TypeError); + +assertThrows(function() { Number.prototype.toFixed.call({}) }, + TypeError); + +assertThrows(function() { Number.prototype.toString.call({}) }, + TypeError); + +assertThrows(function() { Number.prototype.toLocaleString.call({}) }, + TypeError); + +assertThrows(function() { Number.prototype.ValueOf.call({}) }, + TypeError); + + +// Call on Number objects with custom valueOf method. + +var x_obj = new Number(1); +x_obj.valueOf = function() { assertUnreachable(); }; + +assertEquals("1.00e+0", + Number.prototype.toExponential.call(x_obj, 2)); + +assertEquals("1.0", + Number.prototype.toPrecision.call(x_obj, 2)); + +assertEquals("1.00", + Number.prototype.toFixed.call(x_obj, 2)); + +// Call on primitive numbers. +assertEquals("1.00e+0", + Number.prototype.toExponential.call(1, 2)); + +assertEquals("1.0", + Number.prototype.toPrecision.call(1, 2)); + +assertEquals("1.00", + Number.prototype.toFixed.call(1, 2)); + + +// toExponential and toPrecision does following steps in order +// 1) convert the argument using ToInteger +// 2) check for non-finite receiver, on which it returns, +// 3) check argument range and throw exception if out of range. +// Note that the the last two steps are reversed for toFixed. +// Luckily, the receiver is expected to be a number or number +// wrapper, so that getting its value is not observable. + +var f_flag = false; +var f_obj = { valueOf: function() { f_flag = true; return 1000; } }; + +assertEquals("NaN", + Number.prototype.toExponential.call(NaN, f_obj)); +assertTrue(f_flag); + +f_flag = false; +assertEquals("Infinity", + Number.prototype.toExponential.call(1/0, f_obj)); +assertTrue(f_flag); + +f_flag = false; +assertEquals("-Infinity", + Number.prototype.toExponential.call(-1/0, f_obj)); +assertTrue(f_flag); + +f_flag = false; +assertEquals("NaN", + Number.prototype.toPrecision.call(NaN, f_obj)); +assertTrue(f_flag); + +f_flag = false; +assertEquals("Infinity", + Number.prototype.toPrecision.call(1/0, f_obj)); +assertTrue(f_flag); + +f_flag = false; +assertEquals("-Infinity", + Number.prototype.toPrecision.call(-1/0, f_obj)); +assertTrue(f_flag); + +// The odd man out: toFixed. + +f_flag = false; +assertThrows(function() { Number.prototype.toFixed.call(NaN, f_obj) }, + RangeError); +assertTrue(f_flag); + +f_flag = false; +assertThrows(function() { Number.prototype.toFixed.call(1/0, f_obj) }, + RangeError); +assertTrue(f_flag); + +f_flag = false; +assertThrows(function() { Number.prototype.toFixed.call(-1/0, f_obj) }, + RangeError); +assertTrue(f_flag); diff --git a/deps/v8/test/mjsunit/regress/regress-2444.js b/deps/v8/test/mjsunit/regress/regress-2444.js new file mode 100644 index 0000000000..8fb8d8b52e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2444.js @@ -0,0 +1,120 @@ +// 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 flags; + +function resetFlags(size) { + flags = Array(size); + while (size--) flags[size] = 0; +} + +function assertFlags(array) { + assertArrayEquals(array, flags); +} + +function object_factory(flag_index, value, expected_flags) { + var obj = {}; + obj.valueOf = function() { + assertFlags(expected_flags); + flags[flag_index]++; + return value; + } + return obj; +} + + +assertEquals(-Infinity, Math.max()); + +resetFlags(1); +assertEquals(NaN, + Math.max(object_factory(0, NaN, [0]))); +assertFlags([1]); + +resetFlags(2); +assertEquals(NaN, + Math.max(object_factory(0, NaN, [0, 0]), + object_factory(1, 0, [1, 0]))); +assertFlags([1, 1]); + +resetFlags(3); +assertEquals(NaN, + Math.max(object_factory(0, NaN, [0, 0, 0]), + object_factory(1, 0, [1, 0, 0]), + object_factory(2, 1, [1, 1, 0]))); +assertFlags([1, 1, 1]); + +resetFlags(3); +assertEquals(NaN, + Math.max(object_factory(0, 2, [0, 0, 0]), + object_factory(1, 0, [1, 0, 0]), + object_factory(2, NaN, [1, 1, 0]))); +assertFlags([1, 1, 1]); + +resetFlags(3); +assertEquals(2, + Math.max(object_factory(0, 2, [0, 0, 0]), + object_factory(1, 0, [1, 0, 0]), + object_factory(2, 1, [1, 1, 0]))); +assertFlags([1, 1, 1]); + + +assertEquals(+Infinity, Math.min()); + +resetFlags(1); +assertEquals(NaN, + Math.min(object_factory(0, NaN, [0]))); +assertFlags([1]); + +resetFlags(2); +assertEquals(NaN, + Math.min(object_factory(0, NaN, [0, 0]), + object_factory(1, 0, [1, 0]))); +assertFlags([1, 1]); + +resetFlags(3); +assertEquals(NaN, + Math.min(object_factory(0, NaN, [0, 0, 0]), + object_factory(1, 0, [1, 0, 0]), + object_factory(2, 1, [1, 1, 0]))); +assertFlags([1, 1, 1]); + +resetFlags(3); +assertEquals(NaN, + Math.min(object_factory(0, 2, [0, 0, 0]), + object_factory(1, 0, [1, 0, 0]), + object_factory(2, NaN, [1, 1, 0]))); +assertFlags([1, 1, 1]); + +resetFlags(3); +assertEquals(0, + Math.min(object_factory(0, 2, [0, 0, 0]), + object_factory(1, 0, [1, 0, 0]), + object_factory(2, 1, [1, 1, 0]))); +assertFlags([1, 1, 1]); + + diff --git a/deps/v8/test/mjsunit/regress/regress-492.js b/deps/v8/test/mjsunit/regress/regress-492.js index a8b783b301..53b3195cfe 100644 --- a/deps/v8/test/mjsunit/regress/regress-492.js +++ b/deps/v8/test/mjsunit/regress/regress-492.js @@ -29,7 +29,7 @@ // This should not hit any asserts in debug mode on ARM. function function_with_n_args(n) { - var source = '(function f('; + var source = '(function f' + n + '('; for (var arg = 0; arg < n; arg++) { if (arg != 0) source += ','; source += 'arg' + arg; @@ -50,3 +50,41 @@ for (args = 500; args < 520; args++) { for (args = 1019; args < 1041; args++) { function_with_n_args(args); } + + +function foo( + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, + x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x +) {} + +for (var i = 0; i < 10000; ++i) foo(); diff --git a/deps/v8/test/mjsunit/regress/regress-builtin-array-op.js b/deps/v8/test/mjsunit/regress/regress-builtin-array-op.js new file mode 100644 index 0000000000..1e37af3648 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-builtin-array-op.js @@ -0,0 +1,38 @@ +// 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 invoke the correct sort function in +// array operations. + +var foo = "hest"; +Array.prototype.sort = function(fn) { foo = "fisk"; }; +Function.prototype.call = function() { foo = "caramel"; }; +var a = [2,3,1]; +a[100000] = 0; +a.join(); +assertEquals("hest", foo); + diff --git a/deps/v8/test/mjsunit/regress/regress-cnlt-elements.js b/deps/v8/test/mjsunit/regress/regress-cnlt-elements.js new file mode 100644 index 0000000000..634534c533 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-cnlt-elements.js @@ -0,0 +1,43 @@ +// 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 + +var a = JSON.parse('{"b":1,"c":2,"d":3,"e":4}'); +var b = JSON.parse('{"12040200":1, "a":2, "b":2}'); +var c = JSON.parse('{"24050300":1}'); +b = null; +gc(); +gc(); +c.a1 = 2; +c.a2 = 2; +c.a3 = 2; +c.a4 = 2; +c.a5 = 2; +c.a6 = 2; +c.a7 = 2; +c.a8 = 2; diff --git a/deps/v8/test/mjsunit/regress/regress-cnlt-enum-indices.js b/deps/v8/test/mjsunit/regress/regress-cnlt-enum-indices.js new file mode 100644 index 0000000000..03582bbbe4 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-cnlt-enum-indices.js @@ -0,0 +1,45 @@ +// 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 + +var o = {}; +var o2 = {}; + +o.a = 1; +o2.a = 1; +function f() { return 10; } +// Adds a non-field enumerable property. +Object.defineProperty(o, "b", { get: f, enumerable: true }); +Object.defineProperty(o2, "b", { get: f, enumerable: true }); +assertTrue(%HaveSameMap(o, o2)); +o.c = 2; + +for (var x in o) { } +o = null; + +gc(); diff --git a/deps/v8/test/mjsunit/regress/regress-cntl-descriptors-enum.js b/deps/v8/test/mjsunit/regress/regress-cntl-descriptors-enum.js new file mode 100644 index 0000000000..ee72fafc8a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-cntl-descriptors-enum.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: --allow-natives-syntax --expose-gc + +DontEnum = 2; + +var o = {}; +%SetProperty(o, "a", 0, DontEnum); + +var o2 = {}; +%SetProperty(o2, "a", 0, DontEnum); + +assertTrue(%HaveSameMap(o, o2)); + +o.y = 2; + +for (var v in o) { print(v); } +o = {}; +gc(); + +for (var v in o2) { print(v); } diff --git a/deps/v8/test/mjsunit/regress/regress-convert-enum.js b/deps/v8/test/mjsunit/regress/regress-convert-enum.js new file mode 100644 index 0000000000..c624cad5af --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-convert-enum.js @@ -0,0 +1,60 @@ +// 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 + +// Create a transition tree A (no descriptors) -> B (descriptor for a) -> C +// (descriptor for a and c), that all share the descriptor array [a,c]. C is the +// owner of the descriptor array. +var o = {}; +o.a = 1; +o.c = 2; + +// Add a transition B -> D where D has its own descriptor array [a,b] where b is +// a constant function. +var o1 = {}; +o1.a = 1; + +// Install an enumeration cache in the descriptor array [a,c] at map B. +for (var x in o1) { } +o1.b = function() { return 1; }; + +// Return ownership of the descriptor array [a,c] to B and trim it to [a]. +o = null; +gc(); + +// Convert the transition B -> D into a transition to B -> E so that E uses the +// instance descriptors [a,b] with b being a field. +var o2 = {}; +o2.a = 1; +o2.b = 10; + +// Create an object with map B and iterate over it. +var o3 = {}; +o3.a = 1; + +for (var y in o3) { } diff --git a/deps/v8/test/mjsunit/regress/regress-convert-enum2.js b/deps/v8/test/mjsunit/regress/regress-convert-enum2.js new file mode 100644 index 0000000000..cdc7fbe2b6 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-convert-enum2.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. + +var o = {}; +o.a = 1; +o.b = function() { return 1; }; +o.d = 2; + +for (var x in o) { } + +var o1 = {}; +o1.a = 1; +o1.b = 10; +o1.c = 20; + +var keys = ["a", "b", "c"]; + +var i = 0; +for (var y in o1) { + assertEquals(keys[i], y); + i += 1; +} diff --git a/deps/v8/test/mjsunit/regress/regress-convert-transition.js b/deps/v8/test/mjsunit/regress/regress-convert-transition.js new file mode 100644 index 0000000000..057dc8045c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-convert-transition.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 input = '{ "a1":1, "a2":1, "a3":1, "a4":1, "a5":1, "a6":1, "a7":1,\ + "a8":1, "a9":1, "a10":1, "a11":1, "a12":1, "a13":1}'; +var a = JSON.parse(input); +a.a = function() { return 10; }; + +// Force conversion of field to slow mode. +var b = JSON.parse(input); +b.a = 10; + +// Add another property to the object that would transition to a. +var c = JSON.parse(input); +c.x = 10; +assertEquals(undefined, c.a); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-119926.js b/deps/v8/test/mjsunit/regress/regress-crbug-119926.js index 26b84fad7f..1ad250a2b8 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-119926.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-119926.js @@ -25,9 +25,11 @@ // (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: --gc-global + // Test that array elements don't break upon garbage collection. var a = new Array(500); -for (var i = 0; i < 500000; i++) { +for (var i = 0; i < 100000; i++) { a[i] = new Object(); } diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-135066.js b/deps/v8/test/mjsunit/regress/regress-crbug-135066.js index 1aeca8b1a3..35e9ff8c87 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-135066.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-135066.js @@ -29,25 +29,27 @@ var filler = "//" + new Array(1024).join('x'); // Test strict eval in global context. -eval( +assertEquals(23, eval( "'use strict';" + "var x = 23;" + "var f = function bozo1() {" + " return x;" + "};" + "assertSame(23, f());" + + "f;" + filler -); +)()); // Test default eval in strict context. -(function() { +assertEquals(42, (function() { "use strict"; - eval( + return eval( "var y = 42;" + "var g = function bozo2() {" + " return y;" + "};" + "assertSame(42, g());" + + "g;" + filler - ); -})(); + )(); +})()); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-146910.js b/deps/v8/test/mjsunit/regress/regress-crbug-146910.js new file mode 100644 index 0000000000..120f809731 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-146910.js @@ -0,0 +1,38 @@ +// 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 x = []; +assertSame(0, x.length); +assertSame(undefined, x[0]); + +Object.defineProperty(x, '0', { value: 7, configurable: false }); +assertSame(1, x.length); +assertSame(7, x[0]); + +x.length = 0; +assertSame(1, x.length); +assertSame(7, x[0]); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-150545.js b/deps/v8/test/mjsunit/regress/regress-crbug-150545.js new file mode 100644 index 0000000000..68efdbf2d7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-150545.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 + +// Test that we do not generate OSR entry points that have an arguments +// stack height different from zero. The OSR machinery cannot generate +// frames for that. + +(function() { + "use strict"; + + var instantReturn = false; + function inner() { + if (instantReturn) return; + assertSame(3, arguments.length); + assertSame(1, arguments[0]); + assertSame(2, arguments[1]); + assertSame(3, arguments[2]); + } + + function outer() { + inner(1,2,3); + // Trigger OSR. + while (%GetOptimizationStatus(outer) == 2) {} + } + + outer(); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-157019.js b/deps/v8/test/mjsunit/regress/regress-crbug-157019.js new file mode 100644 index 0000000000..1c54089ff9 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-157019.js @@ -0,0 +1,54 @@ +// 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 --nocrankshaft + +function makeConstructor() { + return function() { + this.a = 1; + this.b = 2; + }; +} + +var c1 = makeConstructor(); +var o1 = new c1(); + +c1.prototype = {}; + +for (var i = 0; i < 10; i++) { + var o = new c1(); + for (var j = 0; j < 8; j++) { + o["x" + j] = 0; + } +} + +var c2 = makeConstructor(); +var o2 = new c2(); + +for (var i = 0; i < 50000; i++) { + new c2(); +} diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-157520.js b/deps/v8/test/mjsunit/regress/regress-crbug-157520.js new file mode 100644 index 0000000000..17081dfa52 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-157520.js @@ -0,0 +1,38 @@ +// 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: --nocrankshaft + +(function(){ + var f = function(arg) { + arg = 2; + return arguments[0]; + }; + for (var i = 0; i < 50000; i++) { + assertSame(2, f(1)); + } +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-158185.js b/deps/v8/test/mjsunit/regress/regress-crbug-158185.js new file mode 100644 index 0000000000..99f19c72fd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-158185.js @@ -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. + +assertEquals("0023456", + Object.keys(JSON.parse('{"0023456": 1}'))[0]); +assertEquals("1234567890123", + Object.keys(JSON.parse('{"1234567890123": 1}'))[0]); +assertEquals("123456789ABCD", + Object.keys(JSON.parse('{"123456789ABCD": 1}'))[0]); +assertEquals("12A", + Object.keys(JSON.parse('{"12A": 1}'))[0]); + +assertEquals(1, JSON.parse('{"0":1}')[0]); +assertEquals(undefined, JSON.parse('{"00":1}')[0]); + diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-160010.js b/deps/v8/test/mjsunit/regress/regress-crbug-160010.js new file mode 100644 index 0000000000..266e545325 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-160010.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. + +var str = "a"; +for (var i = 0; i < 28; i++) { + str += str; +} +JSON.stringify(str); + diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-162085.js b/deps/v8/test/mjsunit/regress/regress-crbug-162085.js new file mode 100644 index 0000000000..a53b2c9987 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-162085.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. + +// Ensure extending an empty packed smi array with a double initializes the +// array with holes. +var a = [1,2,3]; +a.length = 0; +a[0] = 1.4; +assertEquals(1.4, a[0]); +assertEquals(undefined, a[1]); +assertEquals(undefined, a[2]); +assertEquals(undefined, a[3]); + +// Ensure the double array growstub initializes the array with holes. +function grow_store(a,i,v) { + a[i] = v; +} + +var a2 = [1.3]; +grow_store(a2,1,1.4); +a2.length = 0; +grow_store(a2,0,1.5); +assertEquals(1.5, a2[0]); +assertEquals(undefined, a2[1]); +assertEquals(undefined, a2[2]); +assertEquals(undefined, a2[3]); + +// Check storing objects using the double grow stub. +var a3 = [1.3]; +var o = {}; +grow_store(a3, 1, o); +assertEquals(1.3, a3[0]); +assertEquals(o, a3[1]); + +// Ensure the double array growstub initializes the array with holes. +function grow_store2(a,i,v) { + a[i] = v; +} + +var a4 = [1.3]; +grow_store2(a4,1,1.4); +a4.length = 0; +grow_store2(a4,0,1); +assertEquals(1, a4[0]); +assertEquals(undefined, a4[1]); +assertEquals(undefined, a4[2]); +assertEquals(undefined, a4[3]); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-18639.js b/deps/v8/test/mjsunit/regress/regress-crbug-18639.js index 23e225a4f4..4f4bb7c796 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-18639.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-18639.js @@ -27,8 +27,12 @@ // See http://crbug.com/18639 -toString = toString; -__defineGetter__("z", (0).toLocaleString); -z; -z; -((0).toLocaleString)(); +try { + toString = toString; + __defineGetter__("z", (0).toLocaleString); + z; + z; + ((0).toLocaleString)(); +} catch (e) { + assertInstanceof(e, TypeError); +}
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/regress/regress-delete-empty-double.js b/deps/v8/test/mjsunit/regress/regress-delete-empty-double.js new file mode 100644 index 0000000000..f7af2b1e31 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-delete-empty-double.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. + +// Flags: --allow-natives-syntax + +a = [1.1,2.2,3.3]; +a.length = 1; +delete a[1]; + +assertTrue(%HasFastDoubleElements(a)); +assertFalse(%HasFastHoleyElements(a)); + +delete a[0]; + +assertTrue(%HasFastDoubleElements(a)); +assertTrue(%HasFastHoleyElements(a)); diff --git a/deps/v8/test/mjsunit/regress/regress-json-stringify-gc.js b/deps/v8/test/mjsunit/regress/regress-json-stringify-gc.js new file mode 100644 index 0000000000..c0a71bf4a1 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-json-stringify-gc.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. + +var a = []; +var new_space_string = ""; +for (var i = 0; i < 128; i++) { + new_space_string += String.fromCharCode((Math.random() * 26 + 65) | 0); +} +for (var i = 0; i < 10000; i++) a.push(new_space_string); + +// At some point during the first stringify, allocation causes a GC and +// new_space_string is moved to old space. Make sure that this does not +// screw up reading from the correct location. +json1 = JSON.stringify(a); +json2 = JSON.stringify(a); +assertTrue(json1 == json2, "GC caused JSON.stringify to fail."); + diff --git a/deps/v8/test/mjsunit/regress/regress-observe-empty-double-array.js b/deps/v8/test/mjsunit/regress/regress-observe-empty-double-array.js new file mode 100644 index 0000000000..aea9c73b22 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-observe-empty-double-array.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. + +// Flags: --harmony-observation --allow-natives-syntax +// +// Test passes if it does not crash. + +arr = [1.1]; +Object.observe(arr, function(){}); +arr.length = 0; +assertTrue(%HasFastDoubleElements(arr)); +// Should not crash +arr.push(1.1); diff --git a/deps/v8/test/mjsunit/regress/regress-undefined-store-keyed-fast-element.js b/deps/v8/test/mjsunit/regress/regress-undefined-store-keyed-fast-element.js new file mode 100644 index 0000000000..9e6ec9db07 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-undefined-store-keyed-fast-element.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. + +// Flags: --allow-natives-syntax + +function f(v) { + return [0.0, 0.1, 0.2, v]; +} + +assertEquals([0.0, 0.1, 0.2, NaN], f(NaN)); +assertEquals([0.0, 0.1, 0.2, NaN], f(NaN)); +%OptimizeFunctionOnNextCall(f); +assertEquals([0.0, 0.1, 0.2, undefined], f(undefined)); diff --git a/deps/v8/test/mjsunit/shift-for-integer-div.js b/deps/v8/test/mjsunit/shift-for-integer-div.js new file mode 100644 index 0000000000..0fe1262292 --- /dev/null +++ b/deps/v8/test/mjsunit/shift-for-integer-div.js @@ -0,0 +1,59 @@ +// 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 divp4(x) { + return x / 4; +} + +for (var i = 0; i < 10000; i+=4) { + assertEquals(i >> 2, divp4(i)); +} + +assertEquals(0.5, divp4(2)); + +function divn4(x) { + return x / (-4); +} + +for (var i = 0; i < 10000; i+=4) { + assertEquals(-(i >> 2), divn4(i)); +} + +assertEquals(-0, divn4(0)); + + +function divn1(x) { + return x / (-1); +} + +for (var i = 0; i < 10000; i++) { + assertEquals(-i, divn1(i)); +} + +var min_int = -(0x7FFFFFFF)-1; +assertEquals(-min_int, divn1(min_int)); + diff --git a/deps/v8/test/mjsunit/stack-traces-overflow.js b/deps/v8/test/mjsunit/stack-traces-overflow.js new file mode 100644 index 0000000000..7722e93bd2 --- /dev/null +++ b/deps/v8/test/mjsunit/stack-traces-overflow.js @@ -0,0 +1,122 @@ +// 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 rec1(a) { rec1(a+1); } +function rec2(a) { rec3(a+1); } +function rec3(a) { rec2(a+1); } + +// Test stack trace getter and setter. +try { + rec1(0); +} catch (e) { + assertTrue(e.stack.indexOf("rec1") > 0); + e.stack = "123"; + assertEquals("123", e.stack); +} + +// Test setter w/o calling the getter. +try { + rec2(0); +} catch (e) { + assertTrue(e.stack.indexOf("rec2") > 0); + assertTrue(e.stack.indexOf("rec3") > 0); + e.stack = "123"; + assertEquals("123", e.stack); +} + +// Test getter to make sure setter does not affect the boilerplate. +try { + rec1(0); +} catch (e) { + assertTrue(e.stack.indexOf("rec1") > 0); + assertInstanceof(e, RangeError); +} + + +// Check setting/getting stack property on the prototype chain. +function testErrorPrototype(prototype) { + var object = {}; + object.__proto__ = prototype; + object.stack = "123"; + assertEquals("123", object.stack); + assertTrue("123" != prototype.stack); +} + +try { + rec1(0); +} catch (e) { + e.stack; + testErrorPrototype(e); +} + +try { + rec1(0); +} catch (e) { + testErrorPrototype(e); +} + +try { + throw new Error(); +} catch (e) { + testErrorPrototype(e); +} + +Error.stackTraceLimit = 3; +try { + rec1(0); +} catch (e) { + assertEquals(4, e.stack.split('\n').length); +} + +Error.stackTraceLimit = 25.9; +try { + rec1(0); +} catch (e) { + assertEquals(26, e.stack.split('\n').length); +} + +Error.stackTraceLimit = NaN; +try { + rec1(0); +} catch (e) { + assertEquals(1, e.stack.split('\n').length); +} + +Error.stackTraceLimit = "not a number"; +try { + rec1(0); +} catch (e) { + assertEquals(undefined, e.stack); +} + +Error.stackTraceLimit = 3; +Error = ""; // Overwrite Error in the global object. +try { + rec1(0); +} catch (e) { + assertEquals(4, e.stack.split('\n').length); +} diff --git a/deps/v8/test/mjsunit/strict-mode.js b/deps/v8/test/mjsunit/strict-mode.js index 9c9bdfd52d..5fb404a799 100644 --- a/deps/v8/test/mjsunit/strict-mode.js +++ b/deps/v8/test/mjsunit/strict-mode.js @@ -1141,9 +1141,9 @@ function CheckPillDescriptor(func, name) { function strict() { "use strict"; - return_my_caller(); + return return_my_caller(); } - assertThrows(strict, TypeError); + assertSame(null, strict()); function non_strict() { return return_my_caller(); @@ -1155,32 +1155,57 @@ function CheckPillDescriptor(func, name) { (function TestNonStrictFunctionCallerPill() { function strict(n) { "use strict"; - non_strict(n); + return non_strict(n); } function recurse(n, then) { if (n > 0) { - recurse(n - 1); + return recurse(n - 1, then); } else { return then(); } } function non_strict(n) { - recurse(n, function() { non_strict.caller; }); + return recurse(n, function() { return non_strict.caller; }); } function test(n) { - try { - recurse(n, function() { strict(n); }); - } catch(e) { - return e instanceof TypeError; + return recurse(n, function() { return strict(n); }); + } + + for (var i = 0; i < 10; i ++) { + assertSame(null, test(i)); + } +})(); + + +(function TestNonStrictFunctionCallerDescriptorPill() { + function strict(n) { + "use strict"; + return non_strict(n); + } + + function recurse(n, then) { + if (n > 0) { + return recurse(n - 1, then); + } else { + return then(); } - return false; + } + + function non_strict(n) { + return recurse(n, function() { + return Object.getOwnPropertyDescriptor(non_strict, "caller").value; + }); + } + + function test(n) { + return recurse(n, function() { return strict(n); }); } for (var i = 0; i < 10; i ++) { - assertEquals(test(i), true); + assertSame(null, test(i)); } })(); diff --git a/deps/v8/test/mjsunit/string-natives.js b/deps/v8/test/mjsunit/string-natives.js new file mode 100644 index 0000000000..b1ec875420 --- /dev/null +++ b/deps/v8/test/mjsunit/string-natives.js @@ -0,0 +1,72 @@ +// 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 --allow-natives-syntax + +function test() { + var s1 = %NewString(26, true); + for (i = 0; i < 26; i++) %_OneByteSeqStringSetChar(s1, i, i+65); + assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", s1); + s1 = %TruncateString(s1, 13); + assertEquals("ABCDEFGHIJKLM", s1); + + var s2 = %NewString(26, false); + for (i = 0; i < 26; i++) %_TwoByteSeqStringSetChar(s2, i, i+65); + assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", s2); + s2 = %TruncateString(s1, 13); + assertEquals("ABCDEFGHIJKLM", s2); + + var s3 = %NewString(26, false); + for (i = 0; i < 26; i++) %_TwoByteSeqStringSetChar(s3, i, i+1000); + for (i = 0; i < 26; i++) assertEquals(s3[i], String.fromCharCode(i+1000)); + + var a = []; + for (var i = 0; i < 1000; i++) { + var s = %NewString(10000, i % 2 == 1); + a.push(s); + } + + gc(); + + for (var i = 0; i < 1000; i++) { + assertEquals(10000, a[i].length); + a[i] = %TruncateString(a[i], 5000); + } + + gc(); + + for (var i = 0; i < 1000; i++) { + assertEquals(5000, a[i].length); + } +} + + +test(); +test(); +%OptimizeFunctionOnNextCall(test); +test(); + diff --git a/deps/v8/test/mjsunit/string-split.js b/deps/v8/test/mjsunit/string-split.js index d8412f0eed..1308244cab 100644 --- a/deps/v8/test/mjsunit/string-split.js +++ b/deps/v8/test/mjsunit/string-split.js @@ -66,6 +66,23 @@ assertArrayEquals(["div", "#i", "d", ".class"], "div#id.class".split(/(?=[d#.])/ assertArrayEquals(["a", "b", "c"], "abc".split(/(?=.)/)); +assertArrayEquals(["Wenige", "sind", "auserwählt."], + "Wenige sind auserwählt.".split(" ")); + +assertArrayEquals([], "Wenige sind auserwählt.".split(" ", 0)); + +assertArrayEquals(["Wenige"], "Wenige sind auserwählt.".split(" ", 1)); + +assertArrayEquals(["Wenige", "sind"], "Wenige sind auserwählt.".split(" ", 2)); + +assertArrayEquals(["Wenige", "sind", "auserwählt."], + "Wenige sind auserwählt.".split(" ", 3)); + +assertArrayEquals(["Wenige sind auserw", "hlt."], + "Wenige sind auserwählt.".split("ä")); + +assertArrayEquals(["Wenige sind ", "."], + "Wenige sind auserwählt.".split("auserwählt")); /* "ab".split(/((?=.))/) * diff --git a/deps/v8/test/mjsunit/testcfg.py b/deps/v8/test/mjsunit/testcfg.py index 5a2f31481e..c8b972c12f 100644 --- a/deps/v8/test/mjsunit/testcfg.py +++ b/deps/v8/test/mjsunit/testcfg.py @@ -25,17 +25,87 @@ # (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 test import os -from os.path import join, dirname, exists import re -import tempfile + +from testrunner.local import testsuite +from testrunner.objects import testcase FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)") FILES_PATTERN = re.compile(r"//\s+Files:(.*)") SELF_SCRIPT_PATTERN = re.compile(r"//\s+Env: TEST_FILE_NAME") +class MjsunitTestSuite(testsuite.TestSuite): + + def __init__(self, name, root): + super(MjsunitTestSuite, self).__init__(name, root) + + def ListTests(self, context): + tests = [] + for dirname, dirs, files in os.walk(self.root): + for dotted in [x for x in dirs if x.startswith('.')]: + dirs.remove(dotted) + dirs.sort() + files.sort() + for filename in files: + if filename.endswith(".js") and filename != "mjsunit.js": + testname = join(dirname[len(self.root) + 1:], filename[:-3]) + test = testcase.TestCase(self, testname) + tests.append(test) + return tests + + def GetFlagsForTestCase(self, testcase, context): + source = self.GetSourceForTest(testcase) + flags = [] + context.mode_flags + flags_match = re.findall(FLAGS_PATTERN, source) + for match in flags_match: + flags += match.strip().split() + + files_list = [] # List of file names to append to command arguments. + files_match = FILES_PATTERN.search(source); + # Accept several lines of 'Files:'. + while True: + if files_match: + files_list += files_match.group(1).strip().split() + files_match = FILES_PATTERN.search(source, files_match.end()) + else: + break + files = [ os.path.normpath(os.path.join(self.root, '..', '..', f)) + for f in files_list ] + testfilename = os.path.join(self.root, testcase.path + self.suffix()) + if SELF_SCRIPT_PATTERN.search(source): + env = ["-e", "TEST_FILE_NAME=\"%s\"" % testfilename] + files = env + files + files.append(os.path.join(self.root, "mjsunit.js")) + files.append(testfilename) + + flags += files + if context.isolates: + flags.append("--isolate") + flags += files + + return testcase.flags + flags + + def GetSourceForTest(self, testcase): + filename = os.path.join(self.root, testcase.path + self.suffix()) + with open(filename) as f: + return f.read() + + +def GetSuite(name, root): + return MjsunitTestSuite(name, root) + + +# Deprecated definitions below. +# TODO(jkummerow): Remove when SCons is no longer supported. + + +from os.path import dirname, exists, join, normpath +import tempfile +import test + + class MjsunitTestCase(test.TestCase): def __init__(self, path, file, mode, context, config, isolates): diff --git a/deps/v8/test/mjsunit/tools/tickprocessor-test.log b/deps/v8/test/mjsunit/tools/tickprocessor-test.log index db8be79fa9..5ddad89a55 100644 --- a/deps/v8/test/mjsunit/tools/tickprocessor-test.log +++ b/deps/v8/test/mjsunit/tools/tickprocessor-test.log @@ -2,24 +2,24 @@ shared-library,"shell",0x08048000,0x081ee000 shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000 shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000 profiler,"begin",1 -code-creation,Stub,0xf540a100,474,"CEntryStub" -code-creation,Script,0xf541cd80,736,"exp.js" -code-creation,Stub,0xf541d0e0,47,"RuntimeStub_Math_exp" -code-creation,LazyCompile,0xf541d120,145,"exp native math.js:41" +code-creation,Stub,0,0xf540a100,474,"CEntryStub" +code-creation,Script,0,0xf541cd80,736,"exp.js" +code-creation,Stub,0,0xf541d0e0,47,"RuntimeStub_Math_exp" +code-creation,LazyCompile,0,0xf541d120,145,"exp native math.js:41" function-creation,0xf441d280,0xf541d120 -code-creation,LoadIC,0xf541d280,117,"j" -code-creation,LoadIC,0xf541d360,63,"i" -tick,0x80f82d1,0xffdfe880,0,0,0,0xf541ce5c -tick,0x80f89a1,0xffdfecf0,0,0,0,0xf541ce5c -tick,0x8123b5c,0xffdff1a0,0,0,0,0xf541d1a1,0xf541ceea -tick,0x8123b65,0xffdff1a0,0,0,0,0xf541d1a1,0xf541ceea -tick,0xf541d2be,0xffdff1e4,0,0,0 -tick,0xf541d320,0xffdff1dc,0,0,0 -tick,0xf541d384,0xffdff1d8,0,0,0 -tick,0xf7db94da,0xffdff0ec,0,0,0,0xf541d1a1,0xf541ceea -tick,0xf7db951c,0xffdff0f0,0,0,0,0xf541d1a1,0xf541ceea -tick,0xf7dbc508,0xffdff14c,0,0,0,0xf541d1a1,0xf541ceea -tick,0xf7dbff21,0xffdff198,0,0,0,0xf541d1a1,0xf541ceea -tick,0xf7edec90,0xffdff0ec,0,0,0,0xf541d1a1,0xf541ceea -tick,0xffffe402,0xffdff488,0,0,0 +code-creation,LoadIC,0,0xf541d280,117,"j" +code-creation,LoadIC,0,0xf541d360,63,"i" +tick,0x80f82d1,0xffdfe880,0,0,0,0,0xf541ce5c +tick,0x80f89a1,0xffdfecf0,0,0,0,0,0xf541ce5c +tick,0x8123b5c,0xffdff1a0,0,0,0,0,0xf541d1a1,0xf541ceea +tick,0x8123b65,0xffdff1a0,0,0,0,0,0xf541d1a1,0xf541ceea +tick,0xf541d2be,0xffdff1e4,0,0,0,0 +tick,0xf541d320,0xffdff1dc,0,0,0,0 +tick,0xf541d384,0xffdff1d8,0,0,0,0 +tick,0xf7db94da,0xffdff0ec,0,0,0,0,0xf541d1a1,0xf541ceea +tick,0xf7db951c,0xffdff0f0,0,0,0,0,0xf541d1a1,0xf541ceea +tick,0xf7dbc508,0xffdff14c,0,0,0,0,0xf541d1a1,0xf541ceea +tick,0xf7dbff21,0xffdff198,0,0,0,0,0xf541d1a1,0xf541ceea +tick,0xf7edec90,0xffdff0ec,0,0,0,0,0xf541d1a1,0xf541ceea +tick,0xffffe402,0xffdff488,0,0,0,0 profiler,"end" diff --git a/deps/v8/test/mjsunit/uri.js b/deps/v8/test/mjsunit/uri.js index 178ff1f2a7..fae349f439 100644 --- a/deps/v8/test/mjsunit/uri.js +++ b/deps/v8/test/mjsunit/uri.js @@ -76,3 +76,15 @@ assertEquals(cc8_2, decodeURI(encodeURI(s8)).charCodeAt(1)); assertEquals(cc9_1, decodeURI(encodeURI(s9)).charCodeAt(0)); assertEquals(cc9_2, decodeURI(encodeURI(s9)).charCodeAt(1)); assertEquals(cc10, decodeURI(encodeURI(s10)).charCodeAt(0)); + +assertEquals("", decodeURI("")); +assertEquals("", encodeURI("")); + +function test(string) { + assertEquals(string, decodeURI(encodeURI(string))); +} + +test("\u1234\u0123\uabcd"); +test("abcd"); +test("ab<\u1234\u0123"); +test("ab\u1234<\u0123"); diff --git a/deps/v8/test/mozilla/mozilla.status b/deps/v8/test/mozilla/mozilla.status index 4f2fbdea5a..f915459d61 100644 --- a/deps/v8/test/mozilla/mozilla.status +++ b/deps/v8/test/mozilla/mozilla.status @@ -212,6 +212,9 @@ js1_5/Array/regress-101964: PASS || FAIL if $mode == debug # This section is for tests that fail in both V8 and JSC. Thus they # have been determined to be incompatible between Mozilla and V8/JSC. +# toPrecision argument restricted to range 1..21 in JSC/V8 and ECMA-262 +js1_5/Regress/regress-452346: FAIL_OK + # Fail because it calls builtins as functions and do not expect the # builtin to have undefined as the receiver. ecma/String/15.5.4.6-2: FAIL_OK @@ -245,13 +248,6 @@ js1_5/Function/regress-338121-03: FAIL_OK # Expectes 'prototype' property of functions to be enumerable. js1_5/Function/10.1.6-01: FAIL_OK -# toPrecision argument restricted to range 1..21 in JSC/V8 -js1_5/Regress/regress-452346: FAIL_OK -ecma_3/Number/15.7.4.7-1: FAIL_OK - -# toExponential argument restricted to range 0..20 in JSC/V8 -ecma_3/Number/15.7.4.6-1: FAIL_OK - #:=== RegExp:=== # We don't match the syntax error message of Mozilla for invalid # RegExp flags. diff --git a/deps/v8/test/mozilla/testcfg.py b/deps/v8/test/mozilla/testcfg.py index e88164d22c..5aeac4cc67 100644 --- a/deps/v8/test/mozilla/testcfg.py +++ b/deps/v8/test/mozilla/testcfg.py @@ -26,12 +26,19 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import test import os -from os.path import join, exists +import shutil +import subprocess +import tarfile + +from testrunner.local import testsuite +from testrunner.objects import testcase + +MOZILLA_VERSION = "2010-06-29" -EXCLUDED = ['CVS'] + +EXCLUDED = ["CVS"] FRAMEWORK = """ @@ -54,6 +61,117 @@ TEST_DIRS = """ """.split() +class MozillaTestSuite(testsuite.TestSuite): + + def __init__(self, name, root): + super(MozillaTestSuite, self).__init__(name, root) + self.testroot = os.path.join(root, "data") + + def ListTests(self, context): + tests = [] + for testdir in TEST_DIRS: + current_root = os.path.join(self.testroot, testdir) + for dirname, dirs, files in os.walk(current_root): + for dotted in [x for x in dirs if x.startswith(".")]: + dirs.remove(dotted) + for excluded in EXCLUDED: + if excluded in dirs: + dirs.remove(excluded) + dirs.sort() + files.sort() + for filename in files: + if filename.endswith(".js") and not filename in FRAMEWORK: + testname = os.path.join(dirname[len(self.testroot) + 1:], + filename[:-3]) + case = testcase.TestCase(self, testname) + tests.append(case) + return tests + + def GetFlagsForTestCase(self, testcase, context): + result = [] + result += context.mode_flags + result += ["--expose-gc"] + result += [os.path.join(self.root, "mozilla-shell-emulation.js")] + testfilename = testcase.path + ".js" + testfilepath = testfilename.split(os.path.sep) + for i in xrange(len(testfilepath)): + script = os.path.join(self.testroot, + reduce(os.path.join, testfilepath[:i], ""), + "shell.js") + if os.path.exists(script): + result.append(script) + result.append(os.path.join(self.testroot, testfilename)) + return testcase.flags + result + + def GetSourceForTest(self, testcase): + filename = join(self.testroot, testcase.path + ".js") + with open(filename) as f: + return f.read() + + def IsNegativeTest(self, testcase): + return testcase.path.endswith("-n") + + def IsFailureOutput(self, output, testpath): + if output.exit_code != 0: + return True + return "FAILED!" in output.stdout + + def DownloadData(self): + old_cwd = os.getcwd() + os.chdir(os.path.abspath(self.root)) + + # Maybe we're still up to date? + versionfile = "CHECKED_OUT_VERSION" + checked_out_version = None + if os.path.exists(versionfile): + with open(versionfile) as f: + checked_out_version = f.read() + if checked_out_version == MOZILLA_VERSION: + os.chdir(old_cwd) + return + + # If we have a local archive file with the test data, extract it. + directory_name = "data" + if os.path.exists(directory_name): + os.rename(directory_name, "data.old") + archive_file = "downloaded_%s.tar.gz" % MOZILLA_VERSION + if os.path.exists(archive_file): + with tarfile.open(archive_file, "r:gz") as tar: + tar.extractall() + with open(versionfile, "w") as f: + f.write(MOZILLA_VERSION) + os.chdir(old_cwd) + return + + # No cached copy. Check out via CVS, and pack as .tar.gz for later use. + command = ("cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot" + " co -D %s mozilla/js/tests" % MOZILLA_VERSION) + code = subprocess.call(command, shell=True) + if code != 0: + os.chdir(old_cwd) + raise Exception("Error checking out Mozilla test suite!") + os.rename(join("mozilla", "js", "tests"), directory_name) + shutil.rmtree("mozilla") + with tarfile.open(archive_file, "w:gz") as tar: + tar.add("data") + with open(versionfile, "w") as f: + f.write(MOZILLA_VERSION) + os.chdir(old_cwd) + + +def GetSuite(name, root): + return MozillaTestSuite(name, root) + + +# Deprecated definitions below. +# TODO(jkummerow): Remove when SCons is no longer supported. + + +from os.path import exists +from os.path import join +import test + + class MozillaTestCase(test.TestCase): def __init__(self, filename, path, context, root, mode, framework): diff --git a/deps/v8/test/preparser/preparser.status b/deps/v8/test/preparser/preparser.status index 6f15fedd8f..40c5caf742 100644 --- a/deps/v8/test/preparser/preparser.status +++ b/deps/v8/test/preparser/preparser.status @@ -31,3 +31,8 @@ prefix preparser # escapes (we need to parse to distinguish octal escapes from valid # back-references). strict-octal-regexp: FAIL + +[ $arch == android_arm || $arch == android_ia32 ] +# Remove this once the issue above is fixed. Android test runner does not +# handle "FAIL" test expectation correctly. +strict-octal-regexp: SKIP diff --git a/deps/v8/test/preparser/testcfg.py b/deps/v8/test/preparser/testcfg.py index 88c06a31ad..61c14c9bd3 100644 --- a/deps/v8/test/preparser/testcfg.py +++ b/deps/v8/test/preparser/testcfg.py @@ -25,13 +25,109 @@ # (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 test + import os -from os.path import join, dirname, exists, isfile -import platform -import utils import re +from testrunner.local import testsuite +from testrunner.local import utils +from testrunner.objects import testcase + + +class PreparserTestSuite(testsuite.TestSuite): + def __init__(self, name, root): + super(PreparserTestSuite, self).__init__(name, root) + + def shell(self): + return "preparser" + + def _GetExpectations(self): + expects_file = join(self.root, "preparser.expectation") + expectations_map = {} + if not os.path.exists(expects_file): return expectations_map + rule_regex = re.compile("^([\w\-]+)(?::([\w\-]+))?(?::(\d+),(\d+))?$") + for line in utils.ReadLinesFrom(expects_file): + rule_match = rule_regex.match(line) + if not rule_match: continue + expects = [] + if (rule_match.group(2)): + expects += [rule_match.group(2)] + if (rule_match.group(3)): + expects += [rule_match.group(3), rule_match.group(4)] + expectations_map[rule_match.group(1)] = " ".join(expects) + return expectations_map + + def _ParsePythonTestTemplates(self, result, filename): + pathname = join(self.root, filename + ".pyt") + def Test(name, source, expectation): + source = source.replace("\n", " ") + testname = os.path.join(filename, name) + flags = ["-e", source] + if expectation: + flags += ["throws", expectation] + test = testcase.TestCase(self, testname, flags=flags) + result.append(test) + def Template(name, source): + def MkTest(replacement, expectation): + testname = name + testsource = source + for key in replacement.keys(): + testname = testname.replace("$" + key, replacement[key]); + testsource = testsource.replace("$" + key, replacement[key]); + Test(testname, testsource, expectation) + return MkTest + execfile(pathname, {"Test": Test, "Template": Template}) + + def ListTests(self, context): + expectations = self._GetExpectations() + result = [] + + # Find all .js files in this directory. + filenames = [f[:-3] for f in os.listdir(self.root) if f.endswith(".js")] + filenames.sort() + for f in filenames: + throws = expectations.get(f, None) + flags = [f + ".js"] + if throws: + flags += ["throws", throws] + test = testcase.TestCase(self, f, flags=flags) + result.append(test) + + # Find all .pyt files in this directory. + filenames = [f[:-4] for f in os.listdir(self.root) if f.endswith(".pyt")] + filenames.sort() + for f in filenames: + self._ParsePythonTestTemplates(result, f) + return result + + def GetFlagsForTestCase(self, testcase, context): + first = testcase.flags[0] + if first != "-e": + testcase.flags[0] = os.path.join(self.root, first) + return testcase.flags + + def GetSourceForTest(self, testcase): + if testcase.flags[0] == "-e": + return testcase.flags[1] + with open(testcase.flags[0]) as f: + return f.read() + + def VariantFlags(self): + return [[]]; + + +def GetSuite(name, root): + return PreparserTestSuite(name, root) + + +# Deprecated definitions below. +# TODO(jkummerow): Remove when SCons is no longer supported. + + +from os.path import join, exists, isfile +import test + + class PreparserTestCase(test.TestCase): def __init__(self, root, path, executable, mode, throws, context, source): @@ -50,7 +146,7 @@ class PreparserTestCase(test.TestCase): def HasSource(self): return self.source is not None - def GetSource(): + def GetSource(self): return self.source def BuildCommand(self, path): diff --git a/deps/v8/test/sputnik/testcfg.py b/deps/v8/test/sputnik/testcfg.py index 1032c134f6..b6f374667c 100644 --- a/deps/v8/test/sputnik/testcfg.py +++ b/deps/v8/test/sputnik/testcfg.py @@ -33,6 +33,11 @@ import test import time +def GetSuite(name, root): + # Not implemented. + return None + + class SputnikTestCase(test.TestCase): def __init__(self, case, path, context, mode): diff --git a/deps/v8/test/test262/README b/deps/v8/test/test262/README index 59e7f5eb8b..1ddbc709be 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 334 as 'data' in this directory. Using later version +at revision 360 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 334 http://hg.ecmascript.org/tests/test262 data +hg clone -r 360 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 06b43c717e..8eaa3657fa 100644 --- a/deps/v8/test/test262/test262.status +++ b/deps/v8/test/test262/test262.status @@ -39,14 +39,20 @@ S15.12.2_A1: FAIL # V8 Bug: http://code.google.com/p/v8/issues/detail?id=691 11.2.3-3_3: FAIL +# Strings that are considered canonically equivalent by the Unicode standard +# return a non-zero value on String.prototype.localeCompare calls. +# V8 Bug: http://code.google.com/p/v8/issues/detail?id=2413 +15.5.4.9_CE: FAIL + ##################### DELIBERATE INCOMPATIBILITIES ##################### -# This tests precision of Math.tan and Math.sin. The implementation for those +# This tests precision of Math functions. The implementation for those # trigonometric functions are platform/compiler dependent. Furthermore, the # expectation values by far deviates from the actual result given by an # arbitrary-precision calculator, making those tests partly bogus. -S15.8.2.16_A7: PASS || FAIL_OK -S15.8.2.18_A7: PASS || FAIL_OK +S15.8.2.8_A6: PASS || FAIL_OK # Math.exp (less precise with --fast-math) +S15.8.2.16_A7: PASS || FAIL_OK # Math.sin +S15.8.2.18_A7: PASS || FAIL_OK # Math.tan # 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 diff --git a/deps/v8/test/test262/testcfg.py b/deps/v8/test/test262/testcfg.py index c394cc8a5f..f937442f5d 100644 --- a/deps/v8/test/test262/testcfg.py +++ b/deps/v8/test/test262/testcfg.py @@ -26,19 +26,110 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import test -import os -from os.path import join, exists -import urllib import hashlib +import os import sys import tarfile +import urllib + +from testrunner.local import testsuite +from testrunner.objects import testcase + + +TEST_262_ARCHIVE_REVISION = "53c4ade82d14" # This is the r360 revision. +TEST_262_ARCHIVE_MD5 = "5fa4918b00e5d60e57bdd3c05deaeb0c" +TEST_262_URL = "http://hg.ecmascript.org/tests/test262/archive/%s.tar.bz2" +TEST_262_HARNESS = ["sta.js", "testBuiltInObject.js"] +TEST_262_SKIP = ["intl402"] + + +class Test262TestSuite(testsuite.TestSuite): + + def __init__(self, name, root): + super(Test262TestSuite, self).__init__(name, root) + self.testroot = os.path.join(root, "data", "test", "suite") + self.harness = [os.path.join(self.root, "data", "test", "harness", f) + for f in TEST_262_HARNESS] + self.harness += [os.path.join(self.root, "harness-adapt.js")] + + def CommonTestName(self, testcase): + return testcase.path.split(os.path.sep)[-1] + def ListTests(self, context): + tests = [] + for dirname, dirs, files in os.walk(self.testroot): + for dotted in [x for x in dirs if x.startswith(".")]: + dirs.remove(dotted) + for skipped in [x for x in dirs if x in TEST_262_SKIP]: + dirs.remove(skipped) + dirs.sort() + files.sort() + for filename in files: + if filename.endswith(".js"): + testname = os.path.join(dirname[len(self.testroot) + 1:], + filename[:-3]) + case = testcase.TestCase(self, testname) + tests.append(case) + return tests + + def GetFlagsForTestCase(self, testcase, context): + return (testcase.flags + context.mode_flags + self.harness + + [os.path.join(self.testroot, testcase.path + ".js")]) + + def GetSourceForTest(self, testcase): + filename = os.path.join(self.testroot, testcase.path + ".js") + with open(filename) as f: + return f.read() + + def IsNegativeTest(self, testcase): + return "@negative" in self.GetSourceForTest(testcase) + + def IsFailureOutput(self, output, testpath): + if output.exit_code != 0: + return True + return "FAILED!" in output.stdout -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'] + def DownloadData(self): + revision = TEST_262_ARCHIVE_REVISION + archive_url = TEST_262_URL % revision + archive_name = os.path.join(self.root, "test262-%s.tar.bz2" % revision) + directory_name = os.path.join(self.root, "data") + directory_old_name = os.path.join(self.root, "data.old") + if not os.path.exists(archive_name): + print "Downloading test data from %s ..." % archive_url + urllib.urlretrieve(archive_url, archive_name) + if os.path.exists(directory_name): + os.rename(directory_name, directory_old_name) + if not os.path.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(os.path.join(self.root, "test262-%s" % revision), + directory_name) + + +def GetSuite(name, root): + return Test262TestSuite(name, root) + + +# Deprecated definitions below. +# TODO(jkummerow): Remove when SCons is no longer supported. + + +from os.path import exists +from os.path import join +import test class Test262TestCase(test.TestCase): @@ -88,6 +179,8 @@ class Test262TestConfiguration(test.TestConfiguration): for root, dirs, files in os.walk(testroot): for dotted in [x for x in dirs if x.startswith('.')]: dirs.remove(dotted) + for skipped in [x for x in dirs if x in TEST_262_SKIP]: + dirs.remove(skipped) dirs.sort() root_path = root[len(self.root):].split(os.path.sep) root_path = current_path + [x for x in root_path if x] diff --git a/deps/v8/tools/android-build.sh b/deps/v8/tools/android-build.sh index e69de29bb2..e69de29bb2 100644..100755 --- a/deps/v8/tools/android-build.sh +++ b/deps/v8/tools/android-build.sh diff --git a/deps/v8/tools/android-ll-prof.sh b/deps/v8/tools/android-ll-prof.sh index 78790ecb62..436f262bb3 100644..100755 --- a/deps/v8/tools/android-ll-prof.sh +++ b/deps/v8/tools/android-ll-prof.sh @@ -60,7 +60,7 @@ adb pull /data/local/tmp/v8/v8.log . adb pull /data/local/tmp/v8/v8.log.ll . adb pull /data/perf.data . -ARCH=arm-linux-androideabi-4.4.3 +ARCH=arm-linux-androideabi-4.6 TOOLCHAIN="${ANDROID_NDK_ROOT}/toolchains/$ARCH/prebuilt/linux-x86/bin" $BASE/tools/ll_prof.py --host-root="$BASE/deploy" \ diff --git a/deps/v8/tools/android-run.py b/deps/v8/tools/android-run.py index 1693c5b064..1693c5b064 100644..100755 --- a/deps/v8/tools/android-run.py +++ b/deps/v8/tools/android-run.py diff --git a/deps/v8/tools/android-sync.sh b/deps/v8/tools/android-sync.sh index 5d4ef2effd..5d4ef2effd 100644..100755 --- a/deps/v8/tools/android-sync.sh +++ b/deps/v8/tools/android-sync.sh diff --git a/deps/v8/tools/bash-completion.sh b/deps/v8/tools/bash-completion.sh index 9f65c67731..9f65c67731 100644..100755 --- a/deps/v8/tools/bash-completion.sh +++ b/deps/v8/tools/bash-completion.sh diff --git a/deps/v8/tools/check-static-initializers.sh b/deps/v8/tools/check-static-initializers.sh index 1103a97787..1103a97787 100644..100755 --- a/deps/v8/tools/check-static-initializers.sh +++ b/deps/v8/tools/check-static-initializers.sh diff --git a/deps/v8/tools/common-includes.sh b/deps/v8/tools/common-includes.sh index 2b806caa5f..7785e9fc30 100644 --- a/deps/v8/tools/common-includes.sh +++ b/deps/v8/tools/common-includes.sh @@ -36,9 +36,7 @@ TEMP_BRANCH=$BRANCHNAME-temporary-branch-created-by-script VERSION_FILE="src/version.cc" CHANGELOG_ENTRY_FILE="$PERSISTFILE_BASENAME-changelog-entry" PATCH_FILE="$PERSISTFILE_BASENAME-patch" -PATCH_OUTPUT_FILE="$PERSISTFILE_BASENAME-patch-output" COMMITMSG_FILE="$PERSISTFILE_BASENAME-commitmsg" -TOUCHED_FILES_FILE="$PERSISTFILE_BASENAME-touched-files" TRUNK_REVISION_FILE="$PERSISTFILE_BASENAME-trunkrevision" START_STEP=0 CURRENT_STEP=0 @@ -180,26 +178,21 @@ the uploaded CL." done } -# Takes a file containing the patch to apply as first argument. -apply_patch() { - patch $REVERSE_PATCH -p1 < "$1" > "$PATCH_OUTPUT_FILE" || \ - { cat "$PATCH_OUTPUT_FILE" && die "Applying the patch failed."; } - tee < "$PATCH_OUTPUT_FILE" >(grep "patching file" \ - | awk '{print $NF}' >> "$TOUCHED_FILES_FILE") - rm "$PATCH_OUTPUT_FILE" +wait_for_resolving_conflicts() { + echo "Applying the patch \"$1\" failed. Either type \"ABORT<Return>\", or \ +resolve the conflicts, stage *all* touched files with 'git add', and \ +type \"RESOLVED<Return>\"" + unset ANSWER + while [ "$ANSWER" != "RESOLVED" ] ; do + [[ "$ANSWER" == "ABORT" ]] && die "Applying the patch failed." + [[ -n "$ANSWER" ]] && echo "That was not 'RESOLVED' or 'ABORT'." + echo -n "> " + read ANSWER + done } -stage_files() { - # Stage added and modified files. - TOUCHED_FILES=$(cat "$TOUCHED_FILES_FILE") - for FILE in $TOUCHED_FILES ; do - git add "$FILE" - done - # Stage deleted files. - DELETED_FILES=$(git status -s -uno --porcelain | grep "^ D" \ - | awk '{print $NF}') - for FILE in $DELETED_FILES ; do - git rm "$FILE" - done - rm -f "$TOUCHED_FILES_FILE" +# Takes a file containing the patch to apply as first argument. +apply_patch() { + git apply --index --reject $REVERSE_PATCH "$1" || \ + wait_for_resolving_conflicts "$1"; } diff --git a/deps/v8/tools/fuzz-harness.sh b/deps/v8/tools/fuzz-harness.sh index efbf8646ce..efbf8646ce 100644..100755 --- a/deps/v8/tools/fuzz-harness.sh +++ b/deps/v8/tools/fuzz-harness.sh diff --git a/deps/v8/tools/gen-postmortem-metadata.py b/deps/v8/tools/gen-postmortem-metadata.py index 3145610c5d..b4b79aada4 100644 --- a/deps/v8/tools/gen-postmortem-metadata.py +++ b/deps/v8/tools/gen-postmortem-metadata.py @@ -61,7 +61,7 @@ consts_misc = [ { 'name': 'StringEncodingMask', 'value': 'kStringEncodingMask' }, { 'name': 'TwoByteStringTag', 'value': 'kTwoByteStringTag' }, - { 'name': 'AsciiStringTag', 'value': 'kAsciiStringTag' }, + { 'name': 'AsciiStringTag', 'value': 'kOneByteStringTag' }, { 'name': 'StringRepresentationMask', 'value': 'kStringRepresentationMask' }, @@ -76,25 +76,13 @@ consts_misc = [ { 'name': 'SmiTag', 'value': 'kSmiTag' }, { 'name': 'SmiTagMask', 'value': 'kSmiTagMask' }, { 'name': 'SmiValueShift', 'value': 'kSmiTagSize' }, + { 'name': 'SmiShiftSize', 'value': 'kSmiShiftSize' }, { 'name': 'PointerSizeLog2', 'value': 'kPointerSizeLog2' }, - { 'name': 'transitions_idx_descriptors', - 'value': 'TransitionArray::kDescriptorsIndex' }, - - { 'name': 'prop_desc_key', - 'value': 'DescriptorArray::kDescriptorKey' }, - { 'name': 'prop_desc_details', - 'value': 'DescriptorArray::kDescriptorDetails' }, - { 'name': 'prop_desc_value', - 'value': 'DescriptorArray::kDescriptorValue' }, - { 'name': 'prop_desc_size', - 'value': 'DescriptorArray::kDescriptorSize' }, { 'name': 'prop_idx_first', 'value': 'DescriptorArray::kFirstIndex' }, { 'name': 'prop_type_field', 'value': 'FIELD' }, - { 'name': 'prop_type_first_phantom', - 'value': 'Code::MAP_TRANSITION' }, { 'name': 'prop_type_mask', 'value': 'PropertyDetails::TypeField::kMask' }, @@ -116,14 +104,13 @@ extras_accessors = [ 'JSObject, elements, Object, kElementsOffset', 'FixedArray, data, uintptr_t, kHeaderSize', 'Map, instance_attributes, int, kInstanceAttributesOffset', - 'Map, transitions, uintptr_t, kTransitionsOrBackPointerOffset', 'Map, inobject_properties, int, kInObjectPropertiesOffset', 'Map, instance_size, int, kInstanceSizeOffset', 'HeapNumber, value, double, kValueOffset', 'ConsString, first, String, kFirstOffset', 'ConsString, second, String, kSecondOffset', 'ExternalString, resource, Object, kResourceOffset', - 'SeqAsciiString, chars, char, kHeaderSize', + 'SeqOneByteString, chars, char, kHeaderSize', 'SharedFunctionInfo, code, Code, kCodeOffset', 'Code, instruction_start, uintptr_t, kHeaderSize', 'Code, instruction_size, int, kInstructionSizeOffset', @@ -137,7 +124,7 @@ extras_accessors = [ expected_classes = [ 'ConsString', 'FixedArray', 'HeapNumber', 'JSArray', 'JSFunction', 'JSObject', 'JSRegExp', 'JSValue', 'Map', 'Oddball', 'Script', - 'SeqAsciiString', 'SharedFunctionInfo' + 'SeqOneByteString', 'SharedFunctionInfo' ]; @@ -302,7 +289,7 @@ def load_objects(): cctype.find('Sliced') == -1): if (cctype.find('Ascii') != -1): cctype = re.sub('AsciiString$', - 'SeqAsciiString', cctype); + 'SeqOneByteString', cctype); else: cctype = re.sub('String$', 'SeqString', cctype); diff --git a/deps/v8/tools/grokdump.py b/deps/v8/tools/grokdump.py index 5d9a053afd..b51e4e0e7f 100755 --- a/deps/v8/tools/grokdump.py +++ b/deps/v8/tools/grokdump.py @@ -27,17 +27,18 @@ # (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 bisect import cmd +import codecs import ctypes +import disasm import mmap import optparse import os -import disasm -import sys -import types -import codecs import re import struct +import sys +import types USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] @@ -180,6 +181,11 @@ MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([ ("rva", ctypes.c_uint32) ]) +MINIDUMP_STRING = Descriptor([ + ("length", ctypes.c_uint32), + ("buffer", lambda t: ctypes.c_uint8 * (t.length + 2)) +]) + MINIDUMP_DIRECTORY = Descriptor([ ("stream_type", ctypes.c_uint32), ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype) @@ -400,6 +406,24 @@ MINIDUMP_THREAD_LIST = Descriptor([ ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) ]) +MINIDUMP_RAW_MODULE = Descriptor([ + ("base_of_image", ctypes.c_uint64), + ("size_of_image", ctypes.c_uint32), + ("checksum", ctypes.c_uint32), + ("time_date_stamp", ctypes.c_uint32), + ("module_name_rva", ctypes.c_uint32), + ("version_info", ctypes.c_uint32 * 13), + ("cv_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype), + ("misc_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype), + ("reserved0", ctypes.c_uint32 * 2), + ("reserved1", ctypes.c_uint32 * 2) +]) + +MINIDUMP_MODULE_LIST = Descriptor([ + ("number_of_modules", ctypes.c_uint32), + ("modules", lambda t: MINIDUMP_RAW_MODULE.ctype * t.number_of_modules) +]) + MINIDUMP_RAW_SYSTEM_INFO = Descriptor([ ("processor_architecture", ctypes.c_uint16) ]) @@ -407,6 +431,20 @@ MINIDUMP_RAW_SYSTEM_INFO = Descriptor([ MD_CPU_ARCHITECTURE_X86 = 0 MD_CPU_ARCHITECTURE_AMD64 = 9 +class FuncSymbol: + def __init__(self, start, size, name): + self.start = start + self.end = self.start + size + self.name = name + + def __cmp__(self, other): + if isinstance(other, FuncSymbol): + return self.start - other.start + return self.start - other + + def Covers(self, addr): + return (self.start <= addr) and (addr < self.end) + class MinidumpReader(object): """Minidump (.dmp) reader.""" @@ -430,8 +468,13 @@ class MinidumpReader(object): self.exception_context = None self.memory_list = None self.memory_list64 = None + self.module_list = None self.thread_map = {} + self.symdir = options.symdir + self.modules_with_symbols = [] + self.symbols = [] + # Find MDRawSystemInfo stream and determine arch. for d in directories: if d.stream_type == MD_SYSTEM_INFO_STREAM: @@ -461,6 +504,11 @@ class MinidumpReader(object): for thread in thread_list.threads: DebugPrint(thread) self.thread_map[thread.id] = thread + elif d.stream_type == MD_MODULE_LIST_STREAM: + assert self.module_list is None + self.module_list = MINIDUMP_MODULE_LIST.Read( + self.minidump, d.location.rva) + assert ctypes.sizeof(self.module_list) == d.location.data_size elif d.stream_type == MD_MEMORY_LIST_STREAM: print >>sys.stderr, "Warning: This is not a full minidump!" assert self.memory_list is None @@ -644,6 +692,66 @@ class MinidumpReader(object): def Register(self, name): return self.exception_context.__getattribute__(name) + def ReadMinidumpString(self, rva): + string = bytearray(MINIDUMP_STRING.Read(self.minidump, rva).buffer) + string = string.decode("utf16") + return string[0:len(string) - 1] + + # Load FUNC records from a BreakPad symbol file + # + # http://code.google.com/p/google-breakpad/wiki/SymbolFiles + # + def _LoadSymbolsFrom(self, symfile, baseaddr): + print "Loading symbols from %s" % (symfile) + funcs = [] + with open(symfile) as f: + for line in f: + result = re.match( + r"^FUNC ([a-f0-9]+) ([a-f0-9]+) ([a-f0-9]+) (.*)$", line) + if result is not None: + start = int(result.group(1), 16) + size = int(result.group(2), 16) + name = result.group(4).rstrip() + bisect.insort_left(self.symbols, + FuncSymbol(baseaddr + start, size, name)) + print " ... done" + + def TryLoadSymbolsFor(self, modulename, module): + try: + symfile = os.path.join(self.symdir, + modulename.replace('.', '_') + ".pdb.sym") + self._LoadSymbolsFrom(symfile, module.base_of_image) + self.modules_with_symbols.append(module) + except Exception as e: + print " ... failure (%s)" % (e) + + # Returns true if address is covered by some module that has loaded symbols. + def _IsInModuleWithSymbols(self, addr): + for module in self.modules_with_symbols: + start = module.base_of_image + end = start + module.size_of_image + if (start <= addr) and (addr < end): + return True + return False + + # Find symbol covering the given address and return its name in format + # <symbol name>+<offset from the start> + def FindSymbol(self, addr): + if not self._IsInModuleWithSymbols(addr): + return None + + i = bisect.bisect_left(self.symbols, addr) + symbol = None + if (0 < i) and self.symbols[i - 1].Covers(addr): + symbol = self.symbols[i - 1] + elif (i < len(self.symbols)) and self.symbols[i].Covers(addr): + symbol = self.symbols[i] + else: + return None + diff = addr - symbol.start + return "%s+0x%x" % (symbol.name, diff) + + # List of V8 instance types. Obtained by adding the code below to any .cc file. # @@ -755,80 +863,83 @@ INSTANCE_TYPES = { # } # printf("}\n"); KNOWN_MAPS = { - 0x08081: (134, "ByteArrayMap"), - 0x080a1: (128, "MetaMap"), - 0x080c1: (130, "OddballMap"), - 0x080e1: (163, "FixedArrayMap"), - 0x08101: (68, "AsciiSymbolMap"), - 0x08121: (132, "HeapNumberMap"), - 0x08141: (135, "FreeSpaceMap"), - 0x08161: (146, "OnePointerFillerMap"), - 0x08181: (146, "TwoPointerFillerMap"), - 0x081a1: (131, "GlobalPropertyCellMap"), - 0x081c1: (164, "SharedFunctionInfoMap"), - 0x081e1: (4, "AsciiStringMap"), - 0x08201: (163, "GlobalContextMap"), - 0x08221: (129, "CodeMap"), - 0x08241: (163, "ScopeInfoMap"), - 0x08261: (163, "FixedCOWArrayMap"), - 0x08281: (145, "FixedDoubleArrayMap"), - 0x082a1: (163, "HashTableMap"), - 0x082c1: (0, "StringMap"), - 0x082e1: (64, "SymbolMap"), - 0x08301: (1, "ConsStringMap"), - 0x08321: (5, "ConsAsciiStringMap"), - 0x08341: (3, "SlicedStringMap"), - 0x08361: (7, "SlicedAsciiStringMap"), - 0x08381: (65, "ConsSymbolMap"), - 0x083a1: (69, "ConsAsciiSymbolMap"), - 0x083c1: (66, "ExternalSymbolMap"), - 0x083e1: (74, "ExternalSymbolWithAsciiDataMap"), - 0x08401: (70, "ExternalAsciiSymbolMap"), - 0x08421: (2, "ExternalStringMap"), - 0x08441: (10, "ExternalStringWithAsciiDataMap"), - 0x08461: (6, "ExternalAsciiStringMap"), - 0x08481: (82, "ShortExternalSymbolMap"), - 0x084a1: (90, "ShortExternalSymbolWithAsciiDataMap"), - 0x084c1: (86, "ShortExternalAsciiSymbolMap"), - 0x084e1: (18, "ShortExternalStringMap"), - 0x08501: (26, "ShortExternalStringWithAsciiDataMap"), - 0x08521: (22, "ShortExternalAsciiStringMap"), - 0x08541: (0, "UndetectableStringMap"), - 0x08561: (4, "UndetectableAsciiStringMap"), - 0x08581: (144, "ExternalPixelArrayMap"), - 0x085a1: (136, "ExternalByteArrayMap"), - 0x085c1: (137, "ExternalUnsignedByteArrayMap"), - 0x085e1: (138, "ExternalShortArrayMap"), - 0x08601: (139, "ExternalUnsignedShortArrayMap"), - 0x08621: (140, "ExternalIntArrayMap"), - 0x08641: (141, "ExternalUnsignedIntArrayMap"), - 0x08661: (142, "ExternalFloatArrayMap"), - 0x08681: (143, "ExternalDoubleArrayMap"), - 0x086a1: (163, "NonStrictArgumentsElementsMap"), - 0x086c1: (163, "FunctionContextMap"), - 0x086e1: (163, "CatchContextMap"), - 0x08701: (163, "WithContextMap"), - 0x08721: (163, "BlockContextMap"), - 0x08741: (163, "ModuleContextMap"), - 0x08761: (165, "JSMessageObjectMap"), - 0x08781: (133, "ForeignMap"), - 0x087a1: (170, "NeanderMap"), - 0x087c1: (158, "PolymorphicCodeCacheMap"), - 0x087e1: (156, "ScriptMap"), - 0x08801: (147, "AccessorInfoMap"), - 0x08821: (148, "AccessorPairMap"), - 0x08841: (149, "AccessCheckInfoMap"), - 0x08861: (150, "InterceptorInfoMap"), - 0x08881: (151, "CallHandlerInfoMap"), - 0x088a1: (152, "FunctionTemplateInfoMap"), - 0x088c1: (153, "ObjectTemplateInfoMap"), - 0x088e1: (154, "SignatureInfoMap"), - 0x08901: (155, "TypeSwitchInfoMap"), - 0x08921: (157, "CodeCacheMap"), - 0x08941: (159, "TypeFeedbackInfoMap"), - 0x08961: (160, "AliasedArgumentsEntryMap"), - 0x08981: (161, "DebugInfoMap"), - 0x089a1: (162, "BreakPointInfoMap"), + 0x08081: (128, "MetaMap"), + 0x080a5: (163, "FixedArrayMap"), + 0x080c9: (130, "OddballMap"), + 0x080ed: (163, "FixedCOWArrayMap"), + 0x08111: (163, "ScopeInfoMap"), + 0x08135: (132, "HeapNumberMap"), + 0x08159: (133, "ForeignMap"), + 0x0817d: (64, "SymbolMap"), + 0x081a1: (68, "AsciiSymbolMap"), + 0x081c5: (65, "ConsSymbolMap"), + 0x081e9: (69, "ConsAsciiSymbolMap"), + 0x0820d: (66, "ExternalSymbolMap"), + 0x08231: (74, "ExternalSymbolWithAsciiDataMap"), + 0x08255: (70, "ExternalAsciiSymbolMap"), + 0x08279: (82, "ShortExternalSymbolMap"), + 0x0829d: (90, "ShortExternalSymbolWithAsciiDataMap"), + 0x082c1: (86, "ShortExternalAsciiSymbolMap"), + 0x082e5: (0, "StringMap"), + 0x08309: (4, "AsciiStringMap"), + 0x0832d: (1, "ConsStringMap"), + 0x08351: (5, "ConsAsciiStringMap"), + 0x08375: (3, "SlicedStringMap"), + 0x08399: (7, "SlicedAsciiStringMap"), + 0x083bd: (2, "ExternalStringMap"), + 0x083e1: (10, "ExternalStringWithAsciiDataMap"), + 0x08405: (6, "ExternalAsciiStringMap"), + 0x08429: (18, "ShortExternalStringMap"), + 0x0844d: (26, "ShortExternalStringWithAsciiDataMap"), + 0x08471: (22, "ShortExternalAsciiStringMap"), + 0x08495: (0, "UndetectableStringMap"), + 0x084b9: (4, "UndetectableAsciiStringMap"), + 0x084dd: (145, "FixedDoubleArrayMap"), + 0x08501: (134, "ByteArrayMap"), + 0x08525: (135, "FreeSpaceMap"), + 0x08549: (144, "ExternalPixelArrayMap"), + 0x0856d: (136, "ExternalByteArrayMap"), + 0x08591: (137, "ExternalUnsignedByteArrayMap"), + 0x085b5: (138, "ExternalShortArrayMap"), + 0x085d9: (139, "ExternalUnsignedShortArrayMap"), + 0x085fd: (140, "ExternalIntArrayMap"), + 0x08621: (141, "ExternalUnsignedIntArrayMap"), + 0x08645: (142, "ExternalFloatArrayMap"), + 0x08669: (163, "NonStrictArgumentsElementsMap"), + 0x0868d: (143, "ExternalDoubleArrayMap"), + 0x086b1: (129, "CodeMap"), + 0x086d5: (131, "GlobalPropertyCellMap"), + 0x086f9: (146, "OnePointerFillerMap"), + 0x0871d: (146, "TwoPointerFillerMap"), + 0x08741: (147, "AccessorInfoMap"), + 0x08765: (148, "AccessorPairMap"), + 0x08789: (149, "AccessCheckInfoMap"), + 0x087ad: (150, "InterceptorInfoMap"), + 0x087d1: (151, "CallHandlerInfoMap"), + 0x087f5: (152, "FunctionTemplateInfoMap"), + 0x08819: (153, "ObjectTemplateInfoMap"), + 0x0883d: (154, "SignatureInfoMap"), + 0x08861: (155, "TypeSwitchInfoMap"), + 0x08885: (156, "ScriptMap"), + 0x088a9: (157, "CodeCacheMap"), + 0x088cd: (158, "PolymorphicCodeCacheMap"), + 0x088f1: (159, "TypeFeedbackInfoMap"), + 0x08915: (160, "AliasedArgumentsEntryMap"), + 0x08939: (161, "DebugInfoMap"), + 0x0895d: (162, "BreakPointInfoMap"), + 0x08981: (163, "HashTableMap"), + 0x089a5: (163, "FunctionContextMap"), + 0x089c9: (163, "CatchContextMap"), + 0x089ed: (163, "WithContextMap"), + 0x08a11: (163, "BlockContextMap"), + 0x08a35: (163, "ModuleContextMap"), + 0x08a59: (163, "GlobalContextMap"), + 0x08a7d: (163, "NativeContextMap"), + 0x08aa1: (164, "SharedFunctionInfoMap"), + 0x08ac5: (165, "JSMessageObjectMap"), + 0x08ae9: (170, "ExternalMap"), + 0x08b0d: (170, "NeanderMap"), + 0x08b31: (170, ""), } @@ -1639,6 +1750,11 @@ CONTEXT_FOR_ARCH = { ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] } +KNOWN_MODULES = {'chrome.exe', 'chrome.dll'} + +def GetModuleName(reader, module): + name = reader.ReadMinidumpString(module.module_name_rva) + return str(os.path.basename(str(name).replace("\\", "/"))) def AnalyzeMinidump(options, minidump_name): reader = MinidumpReader(options, minidump_name) @@ -1657,6 +1773,13 @@ def AnalyzeMinidump(options, minidump_name): # TODO(vitalyr): decode eflags. print " eflags: %s" % bin(reader.exception_context.eflags)[2:] print + print " modules:" + for module in reader.module_list.modules: + name = GetModuleName(reader, module) + if name in KNOWN_MODULES: + print " %s at %08X" % (name, module.base_of_image) + reader.TryLoadSymbolsFor(name, module) + print stack_top = reader.ExceptionSP() stack_bottom = exception_thread.stack.start + \ @@ -1669,6 +1792,9 @@ def AnalyzeMinidump(options, minidump_name): heap = V8Heap(reader, stack_map) print "Disassembly around exception.eip:" + eip_symbol = reader.FindSymbol(reader.ExceptionIP()) + if eip_symbol is not None: + print eip_symbol disasm_start = reader.ExceptionIP() - EIP_PROXIMITY disasm_bytes = 2 * EIP_PROXIMITY if (options.full): @@ -1697,8 +1823,10 @@ def AnalyzeMinidump(options, minidump_name): 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)) + maybe_symbol = reader.FindSymbol(maybe_address) + print "%s: %s %s" % (reader.FormatIntPtr(slot), + reader.FormatIntPtr(maybe_address), + maybe_symbol or "") if heap_object: heap_object.Print(Printer()) print @@ -1712,6 +1840,8 @@ if __name__ == "__main__": help="start an interactive inspector shell") parser.add_option("-f", "--full", dest="full", action="store_true", help="dump all information contained in the minidump") + parser.add_option("--symdir", dest="symdir", default=".", + help="directory containing *.pdb.sym file with symbols") 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 5d3cad526f..aad07c7094 100644 --- a/deps/v8/tools/gyp/v8.gyp +++ b/deps/v8/tools/gyp/v8.gyp @@ -69,6 +69,14 @@ ], }, 'conditions': [ + ['OS=="android"', { + 'libraries': [ + '-llog', + ], + 'include_dirs': [ + 'src/common/android/include', + ], + }], ['OS=="mac"', { 'xcode_settings': { 'OTHER_LDFLAGS': ['-dynamiclib', '-all_load'] @@ -353,6 +361,7 @@ '../../src/isolate.cc', '../../src/isolate.h', '../../src/json-parser.h', + '../../src/json-stringifier.h', '../../src/jsregexp.cc', '../../src/jsregexp.h', '../../src/lazy-instance.h', @@ -678,14 +687,6 @@ 'libraries': [ '-L/usr/local/lib -lexecinfo', ]}, - }], - ['OS=="dragonflybsd"', { - 'link_settings': { - 'libraries': [ - '-pthread', - ]}, - }], - ['OS=="freebsd" or OS=="dragonflybsd"', { 'sources': [ '../../src/platform-freebsd.cc', '../../src/platform-posix.cc' @@ -738,9 +739,6 @@ '../../src/win32-math.h', ], 'msvs_disabled_warnings': [4351, 4355, 4800], - 'direct_dependent_settings': { - 'msvs_disabled_warnings': [4351, 4355, 4800], - }, 'link_settings': { 'libraries': [ '-lwinmm.lib', '-lws2_32.lib' ], }, @@ -754,8 +752,7 @@ ['v8_postmortem_support=="true"', { 'sources': [ '<(SHARED_INTERMEDIATE_DIR)/debug-support.cc', - ], - 'dependencies': ['postmortem-metadata'] + ] }], ], }, @@ -791,6 +788,7 @@ '../../src/macros.py', '../../src/proxy.js', '../../src/collection.js', + '../../src/object-observe.js' ], }, 'actions': [ @@ -804,7 +802,7 @@ '<(SHARED_INTERMEDIATE_DIR)/libraries.cc', ], 'action': [ - '<(python)', + 'python', '../../tools/js2c.py', '<@(_outputs)', 'CORE', @@ -822,7 +820,7 @@ '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc', ], 'action': [ - '<(python)', + 'python', '../../tools/js2c.py', '<@(_outputs)', 'EXPERIMENTAL', @@ -852,7 +850,7 @@ '<(SHARED_INTERMEDIATE_DIR)/debug-support.cc', ], 'action': [ - '<(python)', + 'python', '../../tools/gen-postmortem-metadata.py', '<@(_outputs)', '<@(heapobject_files)' diff --git a/deps/v8/tools/ll_prof.py b/deps/v8/tools/ll_prof.py index 3afe179d2f..216929d1e2 100755 --- a/deps/v8/tools/ll_prof.py +++ b/deps/v8/tools/ll_prof.py @@ -45,7 +45,7 @@ USAGE="""usage: %prog [OPTION]... Analyses V8 and perf logs to produce profiles. Perf logs can be collected using a command like: - $ perf record -R -e cycles -c 10000 -f -i ./shell bench.js --ll-prof + $ perf record -R -e cycles -c 10000 -f -i ./d8 bench.js --ll-prof # -R: collect all data # -e cycles: use cpu-cycles event (run "perf list" for details) # -c 10000: write a sample after each 10000 events @@ -54,6 +54,16 @@ Perf logs can be collected using a command like: # --ll-prof shell flag enables the right V8 logs This will produce a binary trace file (perf.data) that %prog can analyse. +IMPORTANT: + The kernel has an internal maximum for events per second, it is 100K by + default. That's not enough for "-c 10000". Set it to some higher value: + $ echo 10000000 | sudo tee /proc/sys/kernel/perf_event_max_sample_rate + You can also make the warning about kernel address maps go away: + $ echo 0 | sudo tee /proc/sys/kernel/kptr_restrict + +We have a convenience script that handles all of the above for you: + $ tools/run-llprof.sh ./d8 bench.js + Examples: # Print flat profile with annotated disassembly for the 10 top # symbols. Use default log names and include the snapshot log. @@ -75,6 +85,10 @@ class Code(object): """Code object.""" _id = 0 + UNKNOWN = 0 + V8INTERNAL = 1 + FULL_CODEGEN = 2 + OPTIMIZED = 3 def __init__(self, name, start_address, end_address, origin, origin_offset): self.id = Code._id @@ -88,6 +102,14 @@ class Code(object): self.self_ticks = 0 self.self_ticks_map = None self.callee_ticks = None + if name.startswith("LazyCompile:*"): + self.codetype = Code.OPTIMIZED + elif name.startswith("LazyCompile:"): + self.codetype = Code.FULL_CODEGEN + elif name.startswith("v8::internal::"): + self.codetype = Code.V8INTERNAL + else: + self.codetype = Code.UNKNOWN def AddName(self, name): assert self.name != name @@ -185,7 +207,7 @@ class Code(object): class CodePage(object): """Group of adjacent code objects.""" - SHIFT = 12 # 4K pages + SHIFT = 20 # 1M pages SIZE = (1 << SHIFT) MASK = ~(SIZE - 1) @@ -507,6 +529,7 @@ class Descriptor(object): # for the gory details. +# Reference: struct perf_file_header in kernel/tools/perf/util/header.h TRACE_HEADER_DESC = Descriptor([ ("magic", "u64"), ("size", "u64"), @@ -520,6 +543,7 @@ TRACE_HEADER_DESC = Descriptor([ ]) +# Reference: /usr/include/linux/perf_event.h PERF_EVENT_ATTR_DESC = Descriptor([ ("type", "u32"), ("size", "u32"), @@ -529,12 +553,13 @@ PERF_EVENT_ATTR_DESC = Descriptor([ ("read_format", "u64"), ("flags", "u64"), ("wakeup_events_or_watermark", "u32"), - ("bt_type", "u32"), + ("bp_type", "u32"), ("bp_addr", "u64"), - ("bp_len", "u64"), + ("bp_len", "u64") ]) +# Reference: /usr/include/linux/perf_event.h PERF_EVENT_HEADER_DESC = Descriptor([ ("type", "u32"), ("misc", "u16"), @@ -542,6 +567,7 @@ PERF_EVENT_HEADER_DESC = Descriptor([ ]) +# Reference: kernel/events/core.c PERF_MMAP_EVENT_BODY_DESC = Descriptor([ ("pid", "u32"), ("tid", "u32"), @@ -566,6 +592,7 @@ PERF_SAMPLE_STREAM_ID = 1 << 9 PERF_SAMPLE_RAW = 1 << 10 +# Reference: /usr/include/perf_event.h, the comment for PERF_RECORD_SAMPLE. PERF_SAMPLE_EVENT_BODY_FIELDS = [ ("ip", "u64", PERF_SAMPLE_IP), ("pid", "u32", PERF_SAMPLE_TID), @@ -702,8 +729,12 @@ class LibraryRepo(object): # Unfortunately, section headers span two lines, so we have to # keep the just seen section name (from the first line in each # section header) in the after_section variable. + if mmap_info.filename.endswith(".ko"): + dynamic_symbols = "" + else: + dynamic_symbols = "-T" process = subprocess.Popen( - "%s -h -t -T -C %s" % (OBJDUMP_BIN, mmap_info.filename), + "%s -h -t %s -C %s" % (OBJDUMP_BIN, dynamic_symbols, mmap_info.filename), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pipe = process.stdout after_section = None @@ -795,7 +826,7 @@ def PrintReport(code_map, library_repo, arch, ticks, options): code.PrintAnnotated(arch, options) print print "Ticks per library:" - mmap_infos = [m for m in library_repo.infos] + mmap_infos = [m for m in library_repo.infos if m.ticks > 0] mmap_infos.sort(key=lambda m: m.ticks, reverse=True) for mmap_info in mmap_infos: mmap_ticks = mmap_info.ticks @@ -885,6 +916,9 @@ if __name__ == "__main__": ticks = 0 missed_ticks = 0 really_missed_ticks = 0 + optimized_ticks = 0 + generated_ticks = 0 + v8_internal_ticks = 0 mmap_time = 0 sample_time = 0 @@ -928,6 +962,12 @@ if __name__ == "__main__": code = code_map.Find(sample.ip) if code: code.Tick(sample.ip) + if code.codetype == Code.OPTIMIZED: + optimized_ticks += 1 + elif code.codetype == Code.FULL_CODEGEN: + generated_ticks += 1 + elif code.codetype == Code.V8INTERNAL: + v8_internal_ticks += 1 else: missed_ticks += 1 if not library_repo.Tick(sample.ip) and not code: @@ -947,12 +987,21 @@ if __name__ == "__main__": PrintReport(code_map, library_repo, log_reader.arch, ticks, options) if not options.quiet: + def PrintTicks(number, total, description): + print("%10d %5.1f%% ticks in %s" % + (number, 100.0*number/total, description)) print print "Stats:" print "%10d total trace events" % events print "%10d total ticks" % ticks print "%10d ticks not in symbols" % missed_ticks - print "%10d unaccounted ticks" % really_missed_ticks + unaccounted = "unaccounted ticks" + if really_missed_ticks > 0: + unaccounted += " (probably in the kernel, try --kernel)" + PrintTicks(really_missed_ticks, ticks, unaccounted) + PrintTicks(optimized_ticks, ticks, "ticks in optimized code") + PrintTicks(generated_ticks, ticks, "ticks in other lazily compiled code") + PrintTicks(v8_internal_ticks, ticks, "ticks in v8::internal::*") print "%10d total symbols" % len([c for c in code_map.AllCode()]) print "%10d used symbols" % len([c for c in code_map.UsedCode()]) print "%9.2fs library processing time" % mmap_time diff --git a/deps/v8/tools/merge-to-branch.sh b/deps/v8/tools/merge-to-branch.sh index aa590a313c..e0011edff0 100644..100755 --- a/deps/v8/tools/merge-to-branch.sh +++ b/deps/v8/tools/merge-to-branch.sh @@ -186,7 +186,6 @@ if [ $START_STEP -le $CURRENT_STEP ] ; then if [ -n "$EXTRA_PATCH" ] ; then apply_patch "$EXTRA_PATCH" fi - stage_files fi let CURRENT_STEP+=1 @@ -205,8 +204,9 @@ if [ $START_STEP -le $CURRENT_STEP ] ; then your EDITOR on $VERSION_FILE so you can make arbitrary changes. When \ you're done, save the file and exit your EDITOR.)" if [ $? -eq 0 ] ; then + echo $NEWPATCH $VERSION_FILE sed -e "/#define PATCH_LEVEL/s/[0-9]*$/$NEWPATCH/" \ - -i "$VERSION_FILE" + -i.bak "$VERSION_FILE" || die "Could not increment patch level" else $EDITOR "$VERSION_FILE" fi diff --git a/deps/v8/tools/plot-timer-events b/deps/v8/tools/plot-timer-events new file mode 100755 index 0000000000..581e0ae333 --- /dev/null +++ b/deps/v8/tools/plot-timer-events @@ -0,0 +1,71 @@ +#!/bin/sh + +# find the name of the log file to process, it must not start with a dash. +log_file="v8.log" +for arg in "$@" +do + if ! expr "X${arg}" : "^X-" > /dev/null; then + log_file=${arg} + fi +done + +tools_path=`cd $(dirname "$0");pwd` +if [ ! "$D8_PATH" ]; then + d8_public=`which d8` + if [ -x "$d8_public" ]; then D8_PATH=$(dirname "$d8_public"); fi +fi +[ -n "$D8_PATH" ] || D8_PATH=$tools_path/.. +d8_exec=$D8_PATH/d8 + +if [ ! -x "$d8_exec" ]; then + D8_PATH=`pwd`/out/native + d8_exec=$D8_PATH/d8 +fi + +if [ ! -x "$d8_exec" ]; then + d8_exec=`grep -m 1 -o '".*/d8"' $log_file | sed 's/"//g'` +fi + +if [ ! -x "$d8_exec" ]; then + echo "d8 shell not found in $D8_PATH" + echo "To build, execute 'make native' from the V8 directory" + exit 1 +fi + +if [ -n "$DISTORTION" ]; then + distortion=$DISTORTION +else + # Try to find out how much the instrumentation overhead is. + calibration_log=calibration.log + calibration_script="for (var i = 0; i < 1000000; i++) print();" + + $d8_exec --nocrankshaft --prof --logfile $calibration_log \ + --log-timer-events -e "$calibration_script" > /dev/null + t_1=`grep "V8.Execute" $calibration_log | tail -n1 | awk -F, '{print $4}'` + n_1=`grep "timer-event" $calibration_log | wc -l` + + $d8_exec --nocrankshaft --prof --logfile $calibration_log \ + --log-internal-timer-events -e "$calibration_script" > /dev/null + t_2=`grep "V8.Execute" $calibration_log | tail -n1 | awk -F, '{print $4}'` + n_2=`grep "timer-event" $calibration_log | wc -l` + + rm $calibration_log + + # Overhead in picoseconds. + distortion=`echo "1000*($t_1 - $t_2)/($n_1 - $n_2)" | bc` +fi + +if [ -n "$PLOT_RANGE" ]; then + plot_range=$PLOT_RANGE +else + plot_range=auto,auto +fi + +echo "DISTORTION=$distortion" +echo "PLOT_RANGE=$plot_range" + +echo -e "plot-range,$plot_range\ndistortion,$distortion" | cat - $log_file | + $d8_exec $tools_path/csvparser.js \ + $tools_path/splaytree.js $tools_path/codemap.js \ + $tools_path/logreader.js $tools_path/plot-timer-events.js \ + 2>/dev/null | gnuplot > timer-events.png diff --git a/deps/v8/tools/plot-timer-events.js b/deps/v8/tools/plot-timer-events.js new file mode 100644 index 0000000000..4b17e76740 --- /dev/null +++ b/deps/v8/tools/plot-timer-events.js @@ -0,0 +1,576 @@ +// 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 kV8BinarySuffixes = ["/d8", "/libv8.so"]; +var kStackFrames = 8; + +var kTimerEventWidth = 0.33; +var kExecutionFrameWidth = 0.2; +var kStackFrameWidth = 0.1; +var kGapWidth = 0.05; + +var kPauseTolerance = 0.1; // Milliseconds. +var kY1Offset = 10; + +var kResX = 1600; +var kResY = 600; +var kPauseLabelPadding = 5; +var kNumPauseLabels = 7; +var kTickHalfDuration = 0.5; // Milliseconds +var kCodeKindLabelPadding = 100; + +var num_timer_event = kY1Offset + 0.5; + + +function TimerEvent(color, pause, no_execution) { + this.color = color; + this.pause = pause; + this.ranges = []; + this.no_execution = no_execution; + this.index = ++num_timer_event; +} + + +var TimerEvents = { + 'V8.Execute': new TimerEvent("#000000", false, false), + 'V8.External': new TimerEvent("#3399FF", false, true), + 'V8.CompileFullCode': new TimerEvent("#CC0000", true, true), + 'V8.RecompileSynchronous': new TimerEvent("#CC0044", true, true), + 'V8.RecompileParallel': new TimerEvent("#CC4499", false, false), + 'V8.CompileEval': new TimerEvent("#CC4400", true, true), + 'V8.Parse': new TimerEvent("#00CC00", true, true), + 'V8.PreParse': new TimerEvent("#44CC00", true, true), + 'V8.ParseLazy': new TimerEvent("#00CC44", true, true), + 'V8.GCScavenger': new TimerEvent("#0044CC", true, true), + 'V8.GCCompactor': new TimerEvent("#4444CC", true, true), + 'V8.GCContext': new TimerEvent("#4400CC", true, true), +} + +var kExecutionEvent = TimerEvents['V8.Execute']; + + +function CodeKind(color, kinds) { + this.color = color; + this.in_execution = []; + this.stack_frames = []; + for (var i = 0; i < kStackFrames; i++) this.stack_frames.push([]); + this.kinds = kinds; +} + + +var CodeKinds = { + 'external ': new CodeKind("#3399FF", [-3]), + 'reg.exp. ': new CodeKind("#0000FF", [-2]), + 'runtime ': new CodeKind("#000000", [-1]), + 'full code': new CodeKind("#DD0000", [0]), + 'opt code ': new CodeKind("#00EE00", [1]), + 'code stub': new CodeKind("#FF00FF", [2]), + 'built-in ': new CodeKind("#AA00AA", [3]), + 'inl.cache': new CodeKind("#4444AA", [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]), +} + + +var xrange_start = Infinity; +var xrange_end = 0; +var obj_index = 0; +var execution_pauses = []; +var code_map = new CodeMap(); + +var xrange_start_override = undefined; +var xrange_end_override = undefined; +var distortion_per_entry = 0.005; // Milliseconds + +var sort_by_start = []; +var sort_by_end = []; +var sorted_ticks = []; + + +function Range(start, end) { + // Everthing from here are in milliseconds. + this.start = start; + this.end = end; +} + + +function Tick(tick) { + this.tick = tick; +} + + +Range.prototype.duration = function() { return this.end - this.start; } + + +function ProcessTimerEvent(name, start, length) { + var event = TimerEvents[name]; + if (event === undefined) return; + start /= 1000; // Convert to milliseconds. + length /= 1000; + var end = start + length; + var range = new Range(start, end); + event.ranges.push(range); + sort_by_start.push(range); + sort_by_end.push(range); +} + + +function ProcessCodeCreateEvent(type, kind, address, size, name) { + var code_entry = new CodeMap.CodeEntry(size, name); + code_entry.kind = kind; + code_map.addCode(address, code_entry); +} + + +function ProcessCodeMoveEvent(from, to) { + code_map.moveCode(from, to); +} + + +function ProcessCodeDeleteEvent(address) { + code_map.deleteCode(address); +} + + +function ProcessSharedLibrary(name, start, end) { + var code_entry = new CodeMap.CodeEntry(end - start, name); + code_entry.kind = -3; // External code kind. + for (var i = 0; i < kV8BinarySuffixes.length; i++) { + var suffix = kV8BinarySuffixes[i]; + if (name.indexOf(suffix, name.length - suffix.length) >= 0) { + code_entry.kind = -1; // V8 runtime code kind. + break; + } + } + code_map.addLibrary(start, code_entry); +} + + +function FindCodeKind(kind) { + for (name in CodeKinds) { + if (CodeKinds[name].kinds.indexOf(kind) >= 0) { + return CodeKinds[name]; + } + } +} + + +function ProcessTickEvent(pc, sp, timer, unused_x, unused_y, vmstate, stack) { + timer /= 1000; + var tick = new Tick(timer); + + var entered = false; + var entry = code_map.findEntry(pc); + if (entry) { + FindCodeKind(entry.kind).in_execution.push(tick); + entered = true; + } + + for (var i = 0; i < kStackFrames; i++) { + if (!stack[i]) break; + var entry = code_map.findEntry(stack[i]); + if (entry) { + FindCodeKind(entry.kind).stack_frames[i].push(tick); + entered = true; + } + } + + if (entered) sorted_ticks.push(tick); +} + + +function ProcessDistortion(distortion_in_picoseconds) { + distortion_per_entry = distortion_in_picoseconds / 1000000; +} + + +function ProcessPlotRange(start, end) { + xrange_start_override = start; + xrange_end_override = end; +} + + +function Undistort() { + // Undistort timers wrt instrumentation overhead. + sort_by_start.sort(function(a, b) { return b.start - a.start; }); + sort_by_end.sort(function(a, b) { return b.end - a.end; }); + sorted_ticks.sort(function(a, b) { return b.tick - a.tick; }); + var distortion = 0; + + var next_start = sort_by_start.pop(); + var next_end = sort_by_end.pop(); + var next_tick = sorted_ticks.pop(); + + function UndistortTicksUntil(tick) { + while (next_tick) { + if (next_tick.tick > tick) return; + next_tick.tick -= distortion; + next_tick = sorted_ticks.pop(); + } + } + + while (true) { + var next_start_start = next_start ? next_start.start : Infinity; + var next_end_end = next_end ? next_end.end : Infinity; + if (!next_start && !next_end) { + UndistortTicksUntil(Infinity); + break; + } + if (next_start_start <= next_end_end) { + UndistortTicksUntil(next_start_start); + // Undistort the start time stamp. + next_start.start -= distortion; + next_start = sort_by_start.pop(); + } else { + // Undistort the end time stamp. We completely attribute the overhead + // to the point when we stop and log the timer, so we increase the + // distortion only here. + UndistortTicksUntil(next_end_end); + next_end.end -= distortion; + distortion += distortion_per_entry; + next_end = sort_by_end.pop(); + } + } + + sort_by_start = undefined; + sort_by_end = undefined; + sorted_ticks = undefined; + + // Make sure that start <= end applies for every range. + for (name in TimerEvents) { + var ranges = TimerEvents[name].ranges; + for (var j = 0; j < ranges.length; j++) { + if (ranges[j].end < ranges[j].start) ranges[j].end = ranges[j].start; + } + } +} + + +function CollectData() { + // Collect data from log. + var logreader = new LogReader( + { 'timer-event' : { parsers: [null, parseInt, parseInt], + processor: ProcessTimerEvent }, + 'shared-library': { parsers: [null, parseInt, parseInt], + processor: ProcessSharedLibrary }, + 'code-creation': { parsers: [null, parseInt, parseInt, parseInt, null], + processor: ProcessCodeCreateEvent }, + 'code-move': { parsers: [parseInt, parseInt], + processor: ProcessCodeMoveEvent }, + 'code-delete': { parsers: [parseInt], + processor: ProcessCodeDeleteEvent }, + 'tick': { parsers: [parseInt, parseInt, parseInt, + null, null, parseInt, 'var-args'], + processor: ProcessTickEvent }, + 'distortion': { parsers: [parseInt], + processor: ProcessDistortion }, + 'plot-range': { parsers: [parseInt, parseInt], + processor: ProcessPlotRange }, + }); + + var line; + while (line = readline()) { + logreader.processLogLine(line); + } + + Undistort(); + + // Figure out plot range. + var execution_ranges = kExecutionEvent.ranges; + for (var i = 0; i < execution_ranges.length; i++) { + if (execution_ranges[i].start < xrange_start) { + xrange_start = execution_ranges[i].start; + } + if (execution_ranges[i].end > xrange_end) { + xrange_end = execution_ranges[i].end; + } + } + + // Collect execution pauses. + for (name in TimerEvents) { + var event = TimerEvents[name]; + if (!event.pause) continue; + var ranges = event.ranges; + for (var j = 0; j < ranges.length; j++) execution_pauses.push(ranges[j]); + } + execution_pauses = MergeRanges(execution_pauses); + + // Knock out time not spent in javascript execution. Note that this also + // includes time spent external code, which do not contribute to execution + // pauses. + var exclude_ranges = []; + for (name in TimerEvents) { + var event = TimerEvents[name]; + if (!event.no_execution) continue; + var ranges = event.ranges; + // Add ranges of this event to the pause list. + for (var j = 0; j < ranges.length; j++) { + exclude_ranges.push(ranges[j]); + } + } + + kExecutionEvent.ranges = MergeRanges(kExecutionEvent.ranges); + exclude_ranges = MergeRanges(exclude_ranges); + kExecutionEvent.ranges = ExcludeRanges(kExecutionEvent.ranges, + exclude_ranges); +} + + +function DrawBar(row, color, start, end, width) { + obj_index++; + command = "set object " + obj_index + " rect"; + command += " from " + start + ", " + (row - width); + command += " to " + end + ", " + (row + width); + command += " fc rgb \"" + color + "\""; + print(command); +} + + +function TicksToRanges(ticks) { + var ranges = []; + for (var i = 0; i < ticks.length; i++) { + var tick = ticks[i].tick; + ranges.push(new Range(tick - kTickHalfDuration, tick + kTickHalfDuration)); + } + return ranges; +} + + +function MergeRanges(ranges) { + ranges.sort(function(a, b) { return a.start - b.start; }); + var result = []; + var j = 0; + for (var i = 0; i < ranges.length; i = j) { + var merge_start = ranges[i].start; + if (merge_start > xrange_end) break; // Out of plot range. + var merge_end = ranges[i].end; + for (j = i + 1; j < ranges.length; j++) { + var next_range = ranges[j]; + // Don't merge ranges if there is no overlap (including merge tolerance). + if (next_range.start > merge_end + kPauseTolerance) break; + // Merge ranges. + if (next_range.end > merge_end) { // Extend range end. + merge_end = next_range.end; + } + } + if (merge_end < xrange_start) continue; // Out of plot range. + if (merge_end < merge_start) continue; // Not an actual range. + result.push(new Range(merge_start, merge_end)); + } + return result; +} + + +function ExcludeRanges(include, exclude) { + // We assume that both input lists are sorted and merged with MergeRanges. + var result = []; + var exclude_index = 0; + var include_index = 0; + var include_start, include_end, exclude_start, exclude_end; + + function NextInclude() { + if (include_index >= include.length) return false; + include_start = include[include_index].start; + include_end = include[include_index].end; + include_index++; + return true; + } + + function NextExclude() { + if (exclude_index >= exclude.length) { + // No more exclude, finish by repeating case (2). + exclude_start = Infinity; + exclude_end = Infinity; + return false; + } + exclude_start = exclude[exclude_index].start; + exclude_end = exclude[exclude_index].end; + exclude_index++; + return true; + } + + if (!NextInclude() || !NextExclude()) return include; + + while (true) { + if (exclude_end <= include_start) { + // (1) Exclude and include do not overlap. + // Include ##### + // Exclude ## + NextExclude(); + } else if (include_end <= exclude_start) { + // (2) Exclude and include do not overlap. + // Include ##### + // Exclude ### + result.push(new Range(include_start, include_end)); + if (!NextInclude()) break; + } else if (exclude_start <= include_start && + exclude_end < include_end && + include_start < exclude_end) { + // (3) Exclude overlaps with begin of include. + // Include ####### + // Exclude ##### + // Result #### + include_start = exclude_end; + NextExclude(); + } else if (include_start < exclude_start && + include_end <= exclude_end && + exclude_start < include_end) { + // (4) Exclude overlaps with end of include. + // Include ####### + // Exclude ##### + // Result #### + result.push(new Range(include_start, exclude_start)); + if (!NextInclude()) break; + } else if (exclude_start > include_start && exclude_end < include_end) { + // (5) Exclude splits include into two parts. + // Include ####### + // Exclude ## + // Result ## ### + result.push(new Range(include_start, exclude_start)); + include_start = exclude_end; + NextExclude(); + } else if (exclude_start <= include_start && exclude_end >= include_end) { + // (6) Exclude entirely covers include. + // Include ###### + // Exclude ######### + if (!NextInclude()) break; + } else { + throw new Error("this should not happen!"); + } + } + + return result; +} + + +function GnuplotOutput() { + xrange_start = (xrange_start_override || xrange_start_override == 0) + ? xrange_start_override : xrange_start; + xrange_end = (xrange_end_override || xrange_end_override == 0) + ? xrange_end_override : xrange_end; + print("set terminal pngcairo size " + kResX + "," + kResY + + " enhanced font 'Helvetica,10'"); + print("set yrange [0:" + (num_timer_event + 1) + "]"); + print("set xlabel \"execution time in ms\""); + print("set xrange [" + xrange_start + ":" + xrange_end + "]"); + print("set style fill pattern 2 bo 1"); + print("set style rect fs solid 1 noborder"); + print("set style line 1 lt 1 lw 1 lc rgb \"#000000\""); + print("set xtics out nomirror"); + print("unset key"); + + // Name Y-axis. + var ytics = []; + for (name in TimerEvents) { + var index = TimerEvents[name].index; + ytics.push('"' + name + '"' + ' ' + index); + } + ytics.push('"code kind being executed"' + ' ' + (kY1Offset - 1)); + ytics.push('"top ' + kStackFrames + ' js stack frames"' + ' ' + + (kY1Offset - 2)); + ytics.push('"pause times" 0'); + print("set ytics out nomirror (" + ytics.join(', ') + ")"); + + // Plot timeline. + for (var name in TimerEvents) { + var event = TimerEvents[name]; + var ranges = MergeRanges(event.ranges); + for (var i = 0; i < ranges.length; i++) { + DrawBar(event.index, event.color, + ranges[i].start, ranges[i].end, + kTimerEventWidth); + } + } + + // Plot code kind gathered from ticks. + for (var name in CodeKinds) { + var code_kind = CodeKinds[name]; + var offset = kY1Offset - 1; + // Top most frame. + var row = MergeRanges(TicksToRanges(code_kind.in_execution)); + for (var j = 0; j < row.length; j++) { + DrawBar(offset, code_kind.color, + row[j].start, row[j].end, kExecutionFrameWidth); + } + offset = offset - 2 * kExecutionFrameWidth - kGapWidth; + // Javascript frames. + for (var i = 0; i < kStackFrames; i++) { + offset = offset - 2 * kStackFrameWidth - kGapWidth; + row = MergeRanges(TicksToRanges(code_kind.stack_frames[i])); + for (var j = 0; j < row.length; j++) { + DrawBar(offset, code_kind.color, + row[j].start, row[j].end, kStackFrameWidth); + } + } + } + + // Add labels as legend for code kind colors. + var padding = kCodeKindLabelPadding * (xrange_end - xrange_start) / kResX; + var label_x = xrange_start; + var label_y = kY1Offset; + for (var name in CodeKinds) { + label_x += padding; + print("set label \"" + name + "\" at " + label_x + "," + label_y + + " textcolor rgb \"" + CodeKinds[name].color + "\"" + + " font \"Helvetica,9'\""); + } + + if (execution_pauses.length == 0) { + // Force plot and return without plotting execution pause impulses. + print("plot 1/0"); + return; + } + + // Label the longest pauses. + execution_pauses.sort( + function(a, b) { return b.duration() - a.duration(); }); + + var max_pause_time = execution_pauses[0].duration(); + padding = kPauseLabelPadding * (xrange_end - xrange_start) / kResX; + var y_scale = kY1Offset / max_pause_time / 2; + for (var i = 0; i < execution_pauses.length && i < kNumPauseLabels; i++) { + var pause = execution_pauses[i]; + var label_content = (pause.duration() | 0) + " ms"; + var label_x = pause.end + padding; + var label_y = Math.max(1, (pause.duration() * y_scale)); + print("set label \"" + label_content + "\" at " + + label_x + "," + label_y + " font \"Helvetica,7'\""); + } + + // Scale second Y-axis appropriately. + var y2range = max_pause_time * num_timer_event / kY1Offset * 2; + print("set y2range [0:" + y2range + "]"); + // Plot graph with impulses as data set. + print("plot '-' using 1:2 axes x1y2 with impulses ls 1"); + for (var i = 0; i < execution_pauses.length; i++) { + var pause = execution_pauses[i]; + print(pause.end + " " + pause.duration()); + } + print("e"); +} + + +CollectData(); +GnuplotOutput(); diff --git a/deps/v8/tools/presubmit.py b/deps/v8/tools/presubmit.py index a0b81e85f4..efa8724e76 100755 --- a/deps/v8/tools/presubmit.py +++ b/deps/v8/tools/presubmit.py @@ -307,6 +307,7 @@ class SourceProcessor(SourceFileProcessor): or (name == 'DerivedSources')) IGNORE_COPYRIGHTS = ['cpplint.py', + 'daemon.py', 'earley-boyer.js', 'raytrace.js', 'crypto.js', diff --git a/deps/v8/tools/push-to-trunk.sh b/deps/v8/tools/push-to-trunk.sh index a193d57384..8512d12877 100755 --- a/deps/v8/tools/push-to-trunk.sh +++ b/deps/v8/tools/push-to-trunk.sh @@ -268,7 +268,6 @@ if [ $START_STEP -le $CURRENT_STEP ] ; then echo ">>> Step $CURRENT_STEP: Apply squashed changes." rm -f "$TOUCHED_FILES_FILE" apply_patch "$PATCH_FILE" - stage_files rm -f "$PATCH_FILE" fi diff --git a/deps/v8/tools/run-llprof.sh b/deps/v8/tools/run-llprof.sh new file mode 100755 index 0000000000..d526170d1f --- /dev/null +++ b/deps/v8/tools/run-llprof.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# +# 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. + +########## Global variable definitions + +# Ensure that <your CPU clock> / $SAMPLE_EVERY_N_CYCLES < $MAXIMUM_SAMPLE_RATE. +MAXIMUM_SAMPLE_RATE=10000000 +SAMPLE_EVERY_N_CYCLES=10000 +SAMPLE_RATE_CONFIG_FILE="/proc/sys/kernel/perf_event_max_sample_rate" +KERNEL_MAP_CONFIG_FILE="/proc/sys/kernel/kptr_restrict" + +########## Usage + +usage() { +cat << EOF +usage: $0 <benchmark_command> + +Executes <benchmark_command> under observation by the kernel's "perf" \ +framework, then calls the low level tick processor to analyze the results. +EOF +} + +if [ $# -eq 0 ] || [ "$1" == "-h" ] || [ "$1" == "--help" ] ; then + usage + exit 1 +fi + +########## Actual script execution + +ACTUAL_SAMPLE_RATE=$(cat $SAMPLE_RATE_CONFIG_FILE) +if [ "$ACTUAL_SAMPLE_RATE" -lt "$MAXIMUM_SAMPLE_RATE" ] ; then + echo "Setting appropriate maximum sample rate..." + echo $MAXIMUM_SAMPLE_RATE | sudo tee $SAMPLE_RATE_CONFIG_FILE +fi + +ACTUAL_KERNEL_MAP_RESTRICTION=$(cat $KERNEL_MAP_CONFIG_FILE) +if [ "$ACTUAL_KERNEL_MAP_RESTRICTION" -ne "0" ] ; then + echo "Disabling kernel address map restriction..." + echo 0 | sudo tee $KERNEL_MAP_CONFIG_FILE +fi + +echo "Running benchmark..." +perf record -R -e cycles -c $SAMPLE_EVERY_N_CYCLES -f -i $@ --ll-prof diff --git a/deps/v8/tools/run-tests.py b/deps/v8/tools/run-tests.py new file mode 100755 index 0000000000..c09ea064d9 --- /dev/null +++ b/deps/v8/tools/run-tests.py @@ -0,0 +1,369 @@ +#!/usr/bin/env python +# +# 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. + + +import multiprocessing +import optparse +import os +from os.path import join +import subprocess +import sys +import time + +from testrunner.local import execution +from testrunner.local import progress +from testrunner.local import testsuite +from testrunner.local import utils +from testrunner.local import verbose +from testrunner.network import network_execution +from testrunner.objects import context + + +ARCH_GUESS = utils.DefaultArch() +DEFAULT_TESTS = ["mjsunit", "cctest", "message", "preparser"] +TIMEOUT_DEFAULT = 60 +TIMEOUT_SCALEFACTOR = {"debug" : 4, + "release" : 1 } + +# Use this to run several variants of the tests. +VARIANT_FLAGS = [[], + ["--stress-opt", "--always-opt"], + ["--nocrankshaft"]] +MODE_FLAGS = { + "debug" : ["--nobreak-on-abort", "--nodead-code-elimination", + "--enable-slow-asserts", "--debug-code", "--verify-heap"], + "release" : ["--nobreak-on-abort", "--nodead-code-elimination"]} + +SUPPORTED_ARCHS = ["android_arm", + "android_ia32", + "arm", + "ia32", + "mipsel", + "x64"] +# Double the timeout for these: +SLOW_ARCHS = ["android_arm", + "android_ia32", + "arm", + "mipsel"] + + +def BuildOptions(): + result = optparse.OptionParser() + result.add_option("--arch", + help=("The architecture to run tests for, " + "'auto' or 'native' for auto-detect"), + default="ia32,x64,arm") + result.add_option("--arch-and-mode", + help="Architecture and mode in the format 'arch.mode'", + default=None) + result.add_option("--buildbot", + help="Adapt to path structure used on buildbots", + default=False, action="store_true") + result.add_option("--cat", help="Print the source of the tests", + default=False, action="store_true") + result.add_option("--command-prefix", + help="Prepended to each shell command used to run a test", + default="") + result.add_option("--download-data", help="Download missing test suite data", + default=False, action="store_true") + result.add_option("--extra-flags", + help="Additional flags to pass to each test command", + default="") + result.add_option("--isolates", help="Whether to test isolates", + default=False, action="store_true") + result.add_option("-j", help="The number of parallel tasks to run", + default=0, type="int") + result.add_option("-m", "--mode", + help="The test modes in which to run (comma-separated)", + default="release,debug") + result.add_option("--no-network", "--nonetwork", + help="Don't distribute tests on the network", + default=(utils.GuessOS() != "linux"), + dest="no_network", action="store_true") + result.add_option("--no-presubmit", "--nopresubmit", + help='Skip presubmit checks', + default=False, dest="no_presubmit", action="store_true") + result.add_option("--no-stress", "--nostress", + help="Don't run crankshaft --always-opt --stress-op test", + default=False, dest="no_stress", action="store_true") + result.add_option("--outdir", help="Base directory with compile output", + default="out") + result.add_option("-p", "--progress", + help=("The style of progress indicator" + " (verbose, dots, color, mono)"), + choices=progress.PROGRESS_INDICATORS.keys(), default="mono") + result.add_option("--report", help="Print a summary of the tests to be run", + default=False, action="store_true") + result.add_option("--shard-count", + help="Split testsuites into this number of shards", + default=1, type="int") + result.add_option("--shard-run", + help="Run this shard from the split up tests.", + default=1, type="int") + result.add_option("--shell", help="DEPRECATED! use --shell-dir", default="") + result.add_option("--shell-dir", help="Directory containing executables", + default="") + result.add_option("--stress-only", + help="Only run tests with --always-opt --stress-opt", + default=False, action="store_true") + result.add_option("--time", help="Print timing information after running", + default=False, action="store_true") + result.add_option("-t", "--timeout", help="Timeout in seconds", + default= -1, type="int") + result.add_option("-v", "--verbose", help="Verbose output", + default=False, action="store_true") + result.add_option("--valgrind", help="Run tests through valgrind", + default=False, action="store_true") + result.add_option("--warn-unused", help="Report unused rules", + default=False, action="store_true") + return result + + +def ProcessOptions(options): + global VARIANT_FLAGS + + # Architecture and mode related stuff. + if options.arch_and_mode: + tokens = options.arch_and_mode.split(".") + options.arch = tokens[0] + options.mode = tokens[1] + options.mode = options.mode.split(",") + for mode in options.mode: + if not mode in ["debug", "release"]: + print "Unknown mode %s" % mode + return False + if options.arch in ["auto", "native"]: + options.arch = ARCH_GUESS + options.arch = options.arch.split(",") + for arch in options.arch: + if not arch in SUPPORTED_ARCHS: + print "Unknown architecture %s" % arch + return False + + # Special processing of other options, sorted alphabetically. + + if options.buildbot: + # Buildbots run presubmit tests as a separate step. + options.no_presubmit = True + options.no_network = True + if options.command_prefix: + print("Specifying --command-prefix disables network distribution, " + "running tests locally.") + options.no_network = True + if options.j == 0: + options.j = multiprocessing.cpu_count() + if options.no_stress: + VARIANT_FLAGS = [[], ["--nocrankshaft"]] + if not options.shell_dir: + if options.shell: + print "Warning: --shell is deprecated, use --shell-dir instead." + options.shell_dir = os.path.dirname(options.shell) + if options.stress_only: + VARIANT_FLAGS = [["--stress-opt", "--always-opt"]] + if options.valgrind: + run_valgrind = os.path.join("tools", "run-valgrind.py") + # This is OK for distributed running, so we don't need to set no_network. + options.command_prefix = ("python -u " + run_valgrind + + options.command_prefix) + return True + + +def ShardTests(tests, shard_count, shard_run): + if shard_count < 2: + return tests + if shard_run < 1 or shard_run > shard_count: + print "shard-run not a valid number, should be in [1:shard-count]" + print "defaulting back to running all tests" + return tests + count = 0 + shard = [] + for test in tests: + if count % shard_count == shard_run - 1: + shard.append(test) + count += 1 + return shard + + +def Main(): + parser = BuildOptions() + (options, args) = parser.parse_args() + if not ProcessOptions(options): + parser.print_help() + return 1 + + exit_code = 0 + workspace = os.path.abspath(join(os.path.dirname(sys.argv[0]), "..")) + if not options.no_presubmit: + print ">>> running presubmit tests" + code = subprocess.call( + [sys.executable, join(workspace, "tools", "presubmit.py")]) + exit_code = code + + suite_paths = utils.GetSuitePaths(join(workspace, "test")) + + if len(args) == 0: + suite_paths = [ s for s in suite_paths if s in DEFAULT_TESTS ] + else: + args_suites = set() + for arg in args: + suite = arg.split(os.path.sep)[0] + if not suite in args_suites: + args_suites.add(suite) + suite_paths = [ s for s in suite_paths if s in args_suites ] + + suites = [] + for root in suite_paths: + suite = testsuite.TestSuite.LoadTestSuite( + os.path.join(workspace, "test", root)) + if suite: + suites.append(suite) + + if options.download_data: + for s in suites: + s.DownloadData() + + for mode in options.mode: + for arch in options.arch: + code = Execute(arch, mode, args, options, suites, workspace) + exit_code = exit_code or code + return exit_code + + +def Execute(arch, mode, args, options, suites, workspace): + print(">>> Running tests for %s.%s" % (arch, mode)) + + shell_dir = options.shell_dir + if not shell_dir: + if options.buildbot: + shell_dir = os.path.join(workspace, options.outdir, mode) + mode = mode.lower() + else: + shell_dir = os.path.join(workspace, options.outdir, + "%s.%s" % (arch, mode)) + shell_dir = os.path.relpath(shell_dir) + + # Populate context object. + mode_flags = MODE_FLAGS[mode] + timeout = options.timeout + if timeout == -1: + # Simulators are slow, therefore allow a longer default timeout. + if arch in SLOW_ARCHS: + timeout = 2 * TIMEOUT_DEFAULT; + else: + timeout = TIMEOUT_DEFAULT; + + timeout *= TIMEOUT_SCALEFACTOR[mode] + ctx = context.Context(arch, mode, shell_dir, + mode_flags, options.verbose, + timeout, options.isolates, + options.command_prefix, + options.extra_flags) + + # Find available test suites and read test cases from them. + variables = { + "mode": mode, + "arch": arch, + "system": utils.GuessOS(), + "isolates": options.isolates + } + all_tests = [] + num_tests = 0 + test_id = 0 + for s in suites: + s.ReadStatusFile(variables) + s.ReadTestCases(ctx) + if len(args) > 0: + s.FilterTestCasesByArgs(args) + all_tests += s.tests + s.FilterTestCasesByStatus(options.warn_unused) + if options.cat: + verbose.PrintTestSource(s.tests) + continue + variant_flags = s.VariantFlags() or VARIANT_FLAGS + s.tests = [ t.CopyAddingFlags(v) for t in s.tests for v in variant_flags ] + s.tests = ShardTests(s.tests, options.shard_count, options.shard_run) + num_tests += len(s.tests) + for t in s.tests: + t.id = test_id + test_id += 1 + + if options.cat: + return 0 # We're done here. + + if options.report: + verbose.PrintReport(all_tests) + + if num_tests == 0: + print "No tests to run." + return 0 + + # Run the tests, either locally or distributed on the network. + try: + start_time = time.time() + progress_indicator = progress.PROGRESS_INDICATORS[options.progress]() + + run_networked = not options.no_network + if not run_networked: + print("Network distribution disabled, running tests locally.") + elif utils.GuessOS() != "linux": + print("Network distribution is only supported on Linux, sorry!") + run_networked = False + peers = [] + if run_networked: + peers = network_execution.GetPeers() + if not peers: + print("No connection to distribution server; running tests locally.") + run_networked = False + elif len(peers) == 1: + print("No other peers on the network; running tests locally.") + run_networked = False + elif num_tests <= 100: + print("Less than 100 tests, running them locally.") + run_networked = False + + if run_networked: + runner = network_execution.NetworkedRunner(suites, progress_indicator, + ctx, peers, workspace) + else: + runner = execution.Runner(suites, progress_indicator, ctx) + + exit_code = runner.Run(options.j) + if runner.terminate: + return exit_code + overall_duration = time.time() - start_time + except KeyboardInterrupt: + return 1 + + if options.time: + verbose.PrintTestDurations(suites, overall_duration) + return exit_code + + +if __name__ == "__main__": + sys.exit(Main()) diff --git a/deps/v8/tools/status-file-converter.py b/deps/v8/tools/status-file-converter.py new file mode 100755 index 0000000000..ba063ee8c7 --- /dev/null +++ b/deps/v8/tools/status-file-converter.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# +# 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. + + +import sys +from testrunner.local import old_statusfile + +if len(sys.argv) != 2: + print "Usage: %s foo.status" % sys.argv[0] + print "Will read foo.status and print the converted version to stdout." + sys.exit(1) + +print old_statusfile.ConvertNotation(sys.argv[1]).GetOutput() diff --git a/deps/v8/tools/test-server.py b/deps/v8/tools/test-server.py new file mode 100755 index 0000000000..df547ed94d --- /dev/null +++ b/deps/v8/tools/test-server.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python +# +# 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. + + +import os +import subprocess +import sys + + +PIDFILE = "/tmp/v8-distributed-testing-server.pid" +ROOT = os.path.abspath(os.path.dirname(sys.argv[0])) + + +def _PrintUsage(): + print("""Usage: python %s COMMAND + +Where COMMAND can be any of: + start Starts the server. Forks to the background. + stop Stops the server. + restart Stops, then restarts the server. + setup Creates or updates the environment for the server to run. + update Alias for "setup". + trust <keyfile> Adds the given public key to the list of trusted keys. + help Displays this help text. + """ % sys.argv[0]) + + +def _IsDaemonRunning(): + return os.path.exists(PIDFILE) + + +def _Cmd(cmd): + code = subprocess.call(cmd, shell=True) + if code != 0: + print("Command '%s' returned error code %d" % (cmd, code)) + sys.exit(code) + + +def Update(): + # Create directory for private data storage. + data_dir = os.path.join(ROOT, "data") + if not os.path.exists(data_dir): + os.makedirs(data_dir) + + # Create directory for trusted public keys of peers (and self). + trusted_dir = os.path.join(ROOT, "trusted") + if not os.path.exists(trusted_dir): + os.makedirs(trusted_dir) + + # Install UltraJSON. It is much faster than Python's builtin json. + try: + import ujson #@UnusedImport + except ImportError: + # Install pip if it doesn't exist. + code = subprocess.call("which pip > /dev/null", shell=True) + if code != 0: + apt_get_code = subprocess.call("which apt-get > /dev/null", shell=True) + if apt_get_code == 0: + print("Installing pip...") + _Cmd("sudo apt-get install python-pip") + else: + print("Please install pip on your machine. You can get it at: " + "http://www.pip-installer.org/en/latest/installing.html " + "or via your distro's package manager.") + sys.exit(1) + print("Using pip to install UltraJSON...") + _Cmd("sudo pip install ujson") + + # Make sure we have a key pair for signing binaries. + privkeyfile = os.path.expanduser("~/.ssh/v8_dtest") + if not os.path.exists(privkeyfile): + _Cmd("ssh-keygen -t rsa -f %s -N '' -q" % privkeyfile) + fingerprint = subprocess.check_output("ssh-keygen -lf %s" % privkeyfile, + shell=True) + fingerprint = fingerprint.split(" ")[1].replace(":", "")[:16] + pubkeyfile = os.path.join(trusted_dir, "%s.pem" % fingerprint) + if (not os.path.exists(pubkeyfile) or + os.path.getmtime(pubkeyfile) < os.path.getmtime(privkeyfile)): + _Cmd("openssl rsa -in %s -out %s -pubout" % (privkeyfile, pubkeyfile)) + with open(pubkeyfile, "a") as f: + f.write(fingerprint + "\n") + datafile = os.path.join(data_dir, "mypubkey") + with open(datafile, "w") as f: + f.write(fingerprint + "\n") + + # Check out or update the server implementation in the current directory. + testrunner_dir = os.path.join(ROOT, "testrunner") + if os.path.exists(os.path.join(testrunner_dir, "server/daemon.py")): + _Cmd("cd %s; svn up" % testrunner_dir) + else: + path = ("http://v8.googlecode.com/svn/branches/bleeding_edge/" + "tools/testrunner") + _Cmd("svn checkout --force %s %s" % (path, testrunner_dir)) + + # Update this very script. + path = ("http://v8.googlecode.com/svn/branches/bleeding_edge/" + "tools/test-server.py") + scriptname = os.path.abspath(sys.argv[0]) + _Cmd("svn cat %s > %s" % (path, scriptname)) + + # The testcfg.py files currently need to be able to import the old test.py + # script, so we temporarily need to make that available. + # TODO(jkummerow): Remove this when removing test.py. + for filename in ("test.py", "utils.py"): + url = ("http://v8.googlecode.com/svn/branches/bleeding_edge/" + "tools/%s" % filename) + filepath = os.path.join(os.path.dirname(scriptname), filename) + _Cmd("svn cat %s > %s" % (url, filepath)) + + # Check out or update V8. + v8_dir = os.path.join(ROOT, "v8") + if os.path.exists(v8_dir): + _Cmd("cd %s; git fetch" % v8_dir) + else: + _Cmd("git clone git://github.com/v8/v8.git %s" % v8_dir) + + print("Finished.") + + +# Handle "setup" here, because when executing that we can't import anything +# else yet. +if __name__ == "__main__" and len(sys.argv) == 2: + if sys.argv[1] in ("setup", "update"): + if _IsDaemonRunning(): + print("Please stop the server before updating. Exiting.") + sys.exit(1) + Update() + sys.exit(0) + # Other parameters are handled below. + + +#========================================================== +# At this point we can assume that the implementation is available, +# so we can import it. +try: + from testrunner.server import constants + from testrunner.server import local_handler + from testrunner.server import main +except Exception, e: + print(e) + print("Failed to import implementation. Have you run 'setup'?") + sys.exit(1) + + +def _StartDaemon(daemon): + if not os.path.isdir(os.path.join(ROOT, "v8")): + print("No 'v8' working directory found. Have you run 'setup'?") + sys.exit(1) + daemon.start() + + +if __name__ == "__main__": + if len(sys.argv) == 2: + arg = sys.argv[1] + if arg == "start": + daemon = main.Server(PIDFILE, ROOT) + _StartDaemon(daemon) + elif arg == "stop": + daemon = main.Server(PIDFILE, ROOT) + daemon.stop() + elif arg == "restart": + daemon = main.Server(PIDFILE, ROOT) + daemon.stop() + _StartDaemon(daemon) + elif arg in ("help", "-h", "--help"): + _PrintUsage() + elif arg == "status": + if not _IsDaemonRunning(): + print("Server not running.") + else: + print(local_handler.LocalQuery([constants.REQUEST_STATUS])) + else: + print("Unknown command") + _PrintUsage() + sys.exit(2) + elif len(sys.argv) == 3: + arg = sys.argv[1] + if arg == "approve": + filename = sys.argv[2] + if not os.path.exists(filename): + print("%s does not exist.") + sys.exit(1) + filename = os.path.abspath(filename) + if _IsDaemonRunning(): + response = local_handler.LocalQuery([constants.ADD_TRUSTED, filename]) + else: + daemon = main.Server(PIDFILE, ROOT) + response = daemon.CopyToTrusted(filename) + print("Added certificate %s to trusted certificates." % response) + else: + print("Unknown command") + _PrintUsage() + sys.exit(2) + else: + print("Unknown command") + _PrintUsage() + sys.exit(2) + sys.exit(0) diff --git a/deps/v8/tools/test.py b/deps/v8/tools/test.py index c361f93737..b3b62b3a63 100755 --- a/deps/v8/tools/test.py +++ b/deps/v8/tools/test.py @@ -684,8 +684,9 @@ SUFFIX = { 'debug' : '_g', 'release' : '' } FLAGS = { - 'debug' : ['--nobreak-on-abort', '--enable-slow-asserts', '--debug-code', '--verify-heap'], - 'release' : ['--nobreak-on-abort']} + 'debug' : ['--nobreak-on-abort', '--nodead-code-elimination', + '--enable-slow-asserts', '--debug-code', '--verify-heap'], + 'release' : ['--nobreak-on-abort', '--nodead-code-elimination']} TIMEOUT_SCALEFACTOR = { 'debug' : 4, 'release' : 1 } @@ -1370,8 +1371,9 @@ def GetSpecialCommandProcessor(value): else: pos = value.find('@') import urllib - prefix = urllib.unquote(value[:pos]).split() - suffix = urllib.unquote(value[pos+1:]).split() + import shlex + prefix = shlex.split(urllib.unquote(value[:pos])) + suffix = shlex.split(urllib.unquote(value[pos+1:])) def ExpandCommand(args): return prefix + args + suffix return ExpandCommand diff --git a/deps/v8/tools/testrunner/README b/deps/v8/tools/testrunner/README new file mode 100644 index 0000000000..8f0c01f52a --- /dev/null +++ b/deps/v8/tools/testrunner/README @@ -0,0 +1,174 @@ +Test suite runner for V8, including support for distributed running. +==================================================================== + + +Local usage instructions: +========================= + +Run the main script with --help to get detailed usage instructions: + +$ tools/run-tests.py --help + +The interface is mostly the same as it was for the old test runner. +You'll likely want something like this: + +$ tools/run-tests.py --nonetwork --arch ia32 --mode release + +--nonetwork is the default on Mac and Windows. If you don't specify --arch +and/or --mode, all available values will be used and run in turn (e.g., +omitting --mode from the above example will run ia32 in both Release and Debug +modes). + + +Networked usage instructions: +============================= + +Networked running is only supported on Linux currently. Make sure that all +machines participating in the cluster are binary-compatible (e.g. mixing +Ubuntu Lucid and Precise doesn't work). + +Setup: +------ + +1.) Copy tools/test-server.py to a new empty directory anywhere on your hard + drive (preferably not inside your V8 checkout just to keep things clean). + Please do create a copy, not just a symlink. + +2.) Navigate to the new directory and let the server setup itself: + +$ ./test-server.py setup + + This will install PIP and UltraJSON, create a V8 working directory, and + generate a keypair. + +3.) Swap public keys with someone who's already part of the networked cluster. + +$ cp trusted/`cat data/mypubkey`.pem /where/peers/can/see/it/myname.pem +$ ./test-server.py approve /wherever/they/put/it/yourname.pem + + +Usage: +------ + +1.) Start your server: + +$ ./test-server.py start + +2.) (Optionally) inspect the server's status: + +$ ./test-server.py status + +3.) From your regular V8 working directory, run tests: + +$ tool/run-tests.py --arch ia32 --mode debug + +4.) (Optionally) enjoy the speeeeeeeeeeeeeeeed + + +Architecture overview: +====================== + +Code organization: +------------------ + +This section is written from the point of view of the tools/ directory. + +./run-tests.py: + Main script. Parses command-line options and drives the test execution + procedure from a high level. Imports the actual implementation of all + steps from the testrunner/ directory. + +./test-server.py: + Interface to interact with the server. Contains code to setup the server's + working environment and can start and stop server daemon processes. + Imports some stuff from the testrunner/server/ directory. + +./testrunner/local/*: + Implementation needed to run tests locally. Used by run-tests.py. Inspired by + (and partly copied verbatim from) the original test.py script. + +./testrunner/local/old_statusfile.py: + Provides functionality to read an old-style <testsuite>.status file and + convert it to new-style syntax. This can be removed once the new-style + syntax becomes authoritative (and old-style syntax is no longer supported). + ./status-file-converter.py provides a stand-alone interface to this. + +./testrunner/objects/*: + A bunch of data container classes, used by the scripts in the various other + directories; serializable for transmission over the network. + +./testrunner/network/*: + Equivalents and extensions of some of the functionality in ./testrunner/local/ + as required when dispatching tests to peers on the network. + +./testrunner/network/network_execution.py: + Drop-in replacement for ./testrunner/local/execution that distributes + test jobs to network peers instead of running them locally. + +./testrunner/network/endpoint.py: + Receiving end of a network distributed job, uses the implementation + in ./testrunner/local/execution.py for actually running the tests. + +./testrunner/server/*: + Implementation of the daemon that accepts and runs test execution jobs from + peers on the network. Should ideally have no dependencies on any of the other + directories, but that turned out to be impractical, so there are a few + exceptions. + +./testrunner/server/compression.py: + Defines a wrapper around Python TCP sockets that provides JSON based + serialization, gzip based compression, and ensures message completeness. + + +Networking architecture: +------------------------ + +The distribution stuff is designed to be a layer between deciding which tests +to run on the one side, and actually running them on the other. The frontend +that the user interacts with is the same for local and networked execution, +and the actual test execution and result gathering code is the same too. + +The server daemon starts four separate servers, each listening on another port: +- "Local": Communication with a run-tests.py script running on the same host. + The test driving script e.g. needs to ask for available peers. It then talks + to those peers directly (one of them will be the locally running server). +- "Work": Listens for test job requests from run-tests.py scripts on the network + (including localhost). Accepts an arbitrary number of connections at the + same time, but only works on them in a serialized fashion. +- "Status": Used for communication with other servers on the network, e.g. for + exchanging trusted public keys to create the transitive trust closure. +- "Discovery": Used to detect presence of other peers on the network. + In contrast to the other three, this uses UDP (as opposed to TCP). + + +Give us a diagram! We love diagrams! +------------------------------------ + . + Machine A . Machine B + . ++------------------------------+ . +| run-tests.py | . +| with flag: | . +|--nonetwork --network | . +| | / | | . +| | / | | . +| v / v | . +|BACKEND / distribution | . ++--------- / --------| \ ------+ . + / | \_____________________ + / | . \ + / | . \ ++----- v ----------- v --------+ . +---- v -----------------------+ +| LocalHandler | WorkHandler | . | WorkHandler | LocalHandler | +| | | | . | | | | +| | v | . | v | | +| | BACKEND | . | BACKEND | | +|------------- +---------------| . |---------------+--------------| +| Discovery | StatusHandler <----------> StatusHandler | Discovery | ++---- ^ -----------------------+ . +-------------------- ^ -------+ + | . | + +---------------------------------------------------------+ + +Note that the three occurrences of "BACKEND" are the same code +(testrunner/local/execution.py and its imports), but running from three +distinct directories (and on two different machines). diff --git a/deps/v8/tools/testrunner/__init__.py b/deps/v8/tools/testrunner/__init__.py new file mode 100644 index 0000000000..202a262709 --- /dev/null +++ b/deps/v8/tools/testrunner/__init__.py @@ -0,0 +1,26 @@ +# 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. diff --git a/deps/v8/tools/testrunner/local/__init__.py b/deps/v8/tools/testrunner/local/__init__.py new file mode 100644 index 0000000000..202a262709 --- /dev/null +++ b/deps/v8/tools/testrunner/local/__init__.py @@ -0,0 +1,26 @@ +# 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. diff --git a/deps/v8/tools/testrunner/local/commands.py b/deps/v8/tools/testrunner/local/commands.py new file mode 100644 index 0000000000..01f170dc87 --- /dev/null +++ b/deps/v8/tools/testrunner/local/commands.py @@ -0,0 +1,153 @@ +# 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. + + +import os +import signal +import subprocess +import sys +import tempfile +import time + +from ..local import utils +from ..objects import output + + +def KillProcessWithID(pid): + if utils.IsWindows(): + os.popen('taskkill /T /F /PID %d' % pid) + else: + os.kill(pid, signal.SIGTERM) + + +MAX_SLEEP_TIME = 0.1 +INITIAL_SLEEP_TIME = 0.0001 +SLEEP_TIME_FACTOR = 1.25 + +SEM_INVALID_VALUE = -1 +SEM_NOGPFAULTERRORBOX = 0x0002 # Microsoft Platform SDK WinBase.h + + +def Win32SetErrorMode(mode): + prev_error_mode = SEM_INVALID_VALUE + try: + import ctypes + prev_error_mode = \ + ctypes.windll.kernel32.SetErrorMode(mode) #@UndefinedVariable + except ImportError: + pass + return prev_error_mode + + +def RunProcess(verbose, timeout, args, **rest): + if verbose: print "#", " ".join(args) + popen_args = args + prev_error_mode = SEM_INVALID_VALUE + if utils.IsWindows(): + popen_args = subprocess.list2cmdline(args) + # Try to change the error mode to avoid dialogs on fatal errors. Don't + # touch any existing error mode flags by merging the existing error mode. + # See http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx. + error_mode = SEM_NOGPFAULTERRORBOX + prev_error_mode = Win32SetErrorMode(error_mode) + Win32SetErrorMode(error_mode | prev_error_mode) + process = subprocess.Popen( + shell=utils.IsWindows(), + args=popen_args, + **rest + ) + if (utils.IsWindows() and prev_error_mode != SEM_INVALID_VALUE): + Win32SetErrorMode(prev_error_mode) + # Compute the end time - if the process crosses this limit we + # consider it timed out. + if timeout is None: end_time = None + else: end_time = time.time() + timeout + timed_out = False + # Repeatedly check the exit code from the process in a + # loop and keep track of whether or not it times out. + exit_code = None + sleep_time = INITIAL_SLEEP_TIME + try: + while exit_code is None: + if (not end_time is None) and (time.time() >= end_time): + # Kill the process and wait for it to exit. + KillProcessWithID(process.pid) + exit_code = process.wait() + timed_out = True + else: + exit_code = process.poll() + time.sleep(sleep_time) + sleep_time = sleep_time * SLEEP_TIME_FACTOR + if sleep_time > MAX_SLEEP_TIME: + sleep_time = MAX_SLEEP_TIME + return (exit_code, timed_out) + except KeyboardInterrupt: + raise + + +def PrintError(string): + sys.stderr.write(string) + sys.stderr.write("\n") + + +def CheckedUnlink(name): + # On Windows, when run with -jN in parallel processes, + # OS often fails to unlink the temp file. Not sure why. + # Need to retry. + # Idea from https://bugs.webkit.org/attachment.cgi?id=75982&action=prettypatch + retry_count = 0 + while retry_count < 30: + try: + os.unlink(name) + return + except OSError, e: + retry_count += 1 + time.sleep(retry_count * 0.1) + PrintError("os.unlink() " + str(e)) + + +def Execute(args, verbose=False, timeout=None): + args = [ c for c in args if c != "" ] + (fd_out, outname) = tempfile.mkstemp() + (fd_err, errname) = tempfile.mkstemp() + try: + (exit_code, timed_out) = RunProcess( + verbose, + timeout, + args=args, + stdout=fd_out, + stderr=fd_err + ) + except: + raise + os.close(fd_out) + os.close(fd_err) + out = file(outname).read() + errors = file(errname).read() + CheckedUnlink(outname) + CheckedUnlink(errname) + return output.Output(exit_code, timed_out, out, errors) diff --git a/deps/v8/tools/testrunner/local/execution.py b/deps/v8/tools/testrunner/local/execution.py new file mode 100644 index 0000000000..6004367913 --- /dev/null +++ b/deps/v8/tools/testrunner/local/execution.py @@ -0,0 +1,182 @@ +# 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. + + +import multiprocessing +import os +import threading +import time + +from . import commands +from . import utils + + +BREAK_NOW = -1 +EXCEPTION = -2 + + +class Job(object): + def __init__(self, command, dep_command, test_id, timeout, verbose): + self.command = command + self.dep_command = dep_command + self.id = test_id + self.timeout = timeout + self.verbose = verbose + + +def RunTest(job): + try: + start_time = time.time() + if job.dep_command is not None: + dep_output = commands.Execute(job.dep_command, job.verbose, job.timeout) + # TODO(jkummerow): We approximate the test suite specific function + # IsFailureOutput() by just checking the exit code here. Currently + # only cctests define dependencies, for which this simplification is + # correct. + if dep_output.exit_code != 0: + return (job.id, dep_output, time.time() - start_time) + output = commands.Execute(job.command, job.verbose, job.timeout) + return (job.id, output, time.time() - start_time) + except KeyboardInterrupt: + return (-1, BREAK_NOW, 0) + except Exception, e: + print(">>> EXCEPTION: %s" % e) + return (-1, EXCEPTION, 0) + + +class Runner(object): + + def __init__(self, suites, progress_indicator, context): + self.tests = [ t for s in suites for t in s.tests ] + self._CommonInit(len(self.tests), progress_indicator, context) + + def _CommonInit(self, num_tests, progress_indicator, context): + self.indicator = progress_indicator + progress_indicator.runner = self + self.context = context + self.succeeded = 0 + self.total = num_tests + self.remaining = num_tests + self.failed = [] + self.crashed = 0 + self.terminate = False + self.lock = threading.Lock() + + def Run(self, jobs): + self.indicator.Starting() + self._RunInternal(jobs) + self.indicator.Done() + if self.failed: + return 1 + return 0 + + def _RunInternal(self, jobs): + pool = multiprocessing.Pool(processes=jobs) + test_map = {} + queue = [] + queued_exception = None + for test in self.tests: + assert test.id >= 0 + test_map[test.id] = test + try: + command = self.GetCommand(test) + except Exception, e: + # If this failed, save the exception and re-raise it later (after + # all other tests have had a chance to run). + queued_exception = e + continue + timeout = self.context.timeout + if ("--stress-opt" in test.flags or + "--stress-opt" in self.context.mode_flags or + "--stress-opt" in self.context.extra_flags): + timeout *= 4 + if test.dependency is not None: + dep_command = [ c.replace(test.path, test.dependency) for c in command ] + else: + dep_command = None + job = Job(command, dep_command, test.id, timeout, self.context.verbose) + queue.append(job) + try: + kChunkSize = 1 + it = pool.imap_unordered(RunTest, queue, kChunkSize) + for result in it: + test_id = result[0] + if test_id < 0: + if result[1] == BREAK_NOW: + self.terminate = True + else: + continue + if self.terminate: + pool.terminate() + pool.join() + raise BreakNowException("User pressed Ctrl+C or IO went wrong") + test = test_map[test_id] + self.indicator.AboutToRun(test) + test.output = result[1] + test.duration = result[2] + if test.suite.HasUnexpectedOutput(test): + self.failed.append(test) + if test.output.HasCrashed(): + self.crashed += 1 + else: + self.succeeded += 1 + self.remaining -= 1 + self.indicator.HasRun(test) + except KeyboardInterrupt: + pool.terminate() + pool.join() + raise + except Exception, e: + print("Exception: %s" % e) + pool.terminate() + pool.join() + raise + if queued_exception: + raise queued_exception + return + + + def GetCommand(self, test): + d8testflag = [] + shell = test.suite.shell() + if shell == "d8": + d8testflag = ["--test"] + if utils.IsWindows(): + shell += ".exe" + cmd = ([self.context.command_prefix] + + [os.path.abspath(os.path.join(self.context.shell_dir, shell))] + + d8testflag + + test.suite.GetFlagsForTestCase(test, self.context) + + [self.context.extra_flags]) + return cmd + + +class BreakNowException(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) diff --git a/deps/v8/tools/testrunner/local/old_statusfile.py b/deps/v8/tools/testrunner/local/old_statusfile.py new file mode 100644 index 0000000000..a16941b83b --- /dev/null +++ b/deps/v8/tools/testrunner/local/old_statusfile.py @@ -0,0 +1,460 @@ +# 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. + + +import cStringIO +import re + +# These outcomes can occur in a TestCase's outcomes list: +SKIP = 'SKIP' +FAIL = 'FAIL' +PASS = 'PASS' +OKAY = 'OKAY' +TIMEOUT = 'TIMEOUT' +CRASH = 'CRASH' +SLOW = 'SLOW' +# These are just for the status files and are mapped below in DEFS: +FAIL_OK = 'FAIL_OK' +PASS_OR_FAIL = 'PASS_OR_FAIL' + +KEYWORDS = {SKIP: SKIP, + FAIL: FAIL, + PASS: PASS, + OKAY: OKAY, + TIMEOUT: TIMEOUT, + CRASH: CRASH, + SLOW: SLOW, + FAIL_OK: FAIL_OK, + PASS_OR_FAIL: PASS_OR_FAIL} + +class Expression(object): + pass + + +class Constant(Expression): + + def __init__(self, value): + self.value = value + + def Evaluate(self, env, defs): + return self.value + + +class Variable(Expression): + + def __init__(self, name): + self.name = name + + def GetOutcomes(self, env, defs): + if self.name in env: return set([env[self.name]]) + else: return set([]) + + def Evaluate(self, env, defs): + return env[self.name] + + def __str__(self): + return self.name + + def string(self, logical): + return self.__str__() + + +class Outcome(Expression): + + def __init__(self, name): + self.name = name + + def GetOutcomes(self, env, defs): + if self.name in defs: + return defs[self.name].GetOutcomes(env, defs) + else: + return set([self.name]) + + def __str__(self): + if self.name in KEYWORDS: + return "%s" % KEYWORDS[self.name] + return "'%s'" % self.name + + def string(self, logical): + if logical: + return "%s" % self.name + return self.__str__() + + +class Operation(Expression): + + def __init__(self, left, op, right): + self.left = left + self.op = op + self.right = right + + def Evaluate(self, env, defs): + if self.op == '||' or self.op == ',': + return self.left.Evaluate(env, defs) or self.right.Evaluate(env, defs) + elif self.op == 'if': + return False + elif self.op == '==': + return not self.left.GetOutcomes(env, defs).isdisjoint(self.right.GetOutcomes(env, defs)) + elif self.op == '!=': + return self.left.GetOutcomes(env, defs).isdisjoint(self.right.GetOutcomes(env, defs)) + else: + assert self.op == '&&' + return self.left.Evaluate(env, defs) and self.right.Evaluate(env, defs) + + def GetOutcomes(self, env, defs): + if self.op == '||' or self.op == ',': + return self.left.GetOutcomes(env, defs) | self.right.GetOutcomes(env, defs) + elif self.op == 'if': + if self.right.Evaluate(env, defs): return self.left.GetOutcomes(env, defs) + else: return set([]) + else: + assert self.op == '&&' + return self.left.GetOutcomes(env, defs) & self.right.GetOutcomes(env, defs) + + def __str__(self): + return self.string(False) + + def string(self, logical=False): + if self.op == 'if': + return "['%s', %s]" % (self.right.string(True), self.left.string(logical)) + elif self.op == "||" or self.op == ",": + if logical: + return "%s or %s" % (self.left.string(True), self.right.string(True)) + else: + return "%s, %s" % (self.left, self.right) + elif self.op == "&&": + return "%s and %s" % (self.left.string(True), self.right.string(True)) + return "%s %s %s" % (self.left.string(logical), self.op, + self.right.string(logical)) + + +def IsAlpha(string): + for char in string: + if not (char.isalpha() or char.isdigit() or char == '_'): + return False + return True + + +class Tokenizer(object): + """A simple string tokenizer that chops expressions into variables, + parens and operators""" + + def __init__(self, expr): + self.index = 0 + self.expr = expr + self.length = len(expr) + self.tokens = None + + def Current(self, length=1): + if not self.HasMore(length): return "" + return self.expr[self.index:self.index + length] + + def HasMore(self, length=1): + return self.index < self.length + (length - 1) + + def Advance(self, count=1): + self.index = self.index + count + + def AddToken(self, token): + self.tokens.append(token) + + def SkipSpaces(self): + while self.HasMore() and self.Current().isspace(): + self.Advance() + + def Tokenize(self): + self.tokens = [ ] + while self.HasMore(): + self.SkipSpaces() + if not self.HasMore(): + return None + if self.Current() == '(': + self.AddToken('(') + self.Advance() + elif self.Current() == ')': + self.AddToken(')') + self.Advance() + elif self.Current() == '$': + self.AddToken('$') + self.Advance() + elif self.Current() == ',': + self.AddToken(',') + self.Advance() + elif IsAlpha(self.Current()): + buf = "" + while self.HasMore() and IsAlpha(self.Current()): + buf += self.Current() + self.Advance() + self.AddToken(buf) + elif self.Current(2) == '&&': + self.AddToken('&&') + self.Advance(2) + elif self.Current(2) == '||': + self.AddToken('||') + self.Advance(2) + elif self.Current(2) == '==': + self.AddToken('==') + self.Advance(2) + elif self.Current(2) == '!=': + self.AddToken('!=') + self.Advance(2) + else: + return None + return self.tokens + + +class Scanner(object): + """A simple scanner that can serve out tokens from a given list""" + + def __init__(self, tokens): + self.tokens = tokens + self.length = len(tokens) + self.index = 0 + + def HasMore(self): + return self.index < self.length + + def Current(self): + return self.tokens[self.index] + + def Advance(self): + self.index = self.index + 1 + + +def ParseAtomicExpression(scan): + if scan.Current() == "true": + scan.Advance() + return Constant(True) + elif scan.Current() == "false": + scan.Advance() + return Constant(False) + elif IsAlpha(scan.Current()): + name = scan.Current() + scan.Advance() + return Outcome(name) + elif scan.Current() == '$': + scan.Advance() + if not IsAlpha(scan.Current()): + return None + name = scan.Current() + scan.Advance() + return Variable(name.lower()) + elif scan.Current() == '(': + scan.Advance() + result = ParseLogicalExpression(scan) + if (not result) or (scan.Current() != ')'): + return None + scan.Advance() + return result + else: + return None + + +BINARIES = ['==', '!='] +def ParseOperatorExpression(scan): + left = ParseAtomicExpression(scan) + if not left: return None + while scan.HasMore() and (scan.Current() in BINARIES): + op = scan.Current() + scan.Advance() + right = ParseOperatorExpression(scan) + if not right: + return None + left = Operation(left, op, right) + return left + + +def ParseConditionalExpression(scan): + left = ParseOperatorExpression(scan) + if not left: return None + while scan.HasMore() and (scan.Current() == 'if'): + scan.Advance() + right = ParseOperatorExpression(scan) + if not right: + return None + left = Operation(left, 'if', right) + return left + + +LOGICALS = ["&&", "||", ","] +def ParseLogicalExpression(scan): + left = ParseConditionalExpression(scan) + if not left: return None + while scan.HasMore() and (scan.Current() in LOGICALS): + op = scan.Current() + scan.Advance() + right = ParseConditionalExpression(scan) + if not right: + return None + left = Operation(left, op, right) + return left + + +def ParseCondition(expr): + """Parses a logical expression into an Expression object""" + tokens = Tokenizer(expr).Tokenize() + if not tokens: + print "Malformed expression: '%s'" % expr + return None + scan = Scanner(tokens) + ast = ParseLogicalExpression(scan) + if not ast: + print "Malformed expression: '%s'" % expr + return None + if scan.HasMore(): + print "Malformed expression: '%s'" % expr + return None + return ast + + +class Section(object): + """A section of the configuration file. Sections are enabled or + disabled prior to running the tests, based on their conditions""" + + def __init__(self, condition): + self.condition = condition + self.rules = [ ] + + def AddRule(self, rule): + self.rules.append(rule) + + +class Rule(object): + """A single rule that specifies the expected outcome for a single + test.""" + + def __init__(self, raw_path, path, value): + self.raw_path = raw_path + self.path = path + self.value = value + + def GetOutcomes(self, env, defs): + return self.value.GetOutcomes(env, defs) + + def Contains(self, path): + if len(self.path) > len(path): + return False + for i in xrange(len(self.path)): + if not self.path[i].match(path[i]): + return False + return True + + +HEADER_PATTERN = re.compile(r'\[([^]]+)\]') +RULE_PATTERN = re.compile(r'\s*([^: ]*)\s*:(.*)') +DEF_PATTERN = re.compile(r'^def\s*(\w+)\s*=(.*)$') +PREFIX_PATTERN = re.compile(r'^\s*prefix\s+([\w\_\.\-\/]+)$') + + +class ConvertNotation(object): + def __init__(self, path): + self.path = path + self.indent = "" + self.comment = [] + self.init = False + self.section = False + self.out = cStringIO.StringIO() + + def OpenGlobal(self): + if self.init: return + self.WriteComment() + print >> self.out, "[" + self.init = True + + def CloseGlobal(self): + if not self.init: return + print >> self.out, "]" + self.init = False + + def OpenSection(self, condition="ALWAYS"): + if self.section: return + self.OpenGlobal() + if type(condition) != str: + condition = "'%s'" % condition.string(True) + print >> self.out, "%s[%s, {" % (self.indent, condition) + self.indent += " " * 2 + self.section = condition + + def CloseSection(self): + if not self.section: return + self.indent = self.indent[:-2] + print >> self.out, "%s}], # %s" % (self.indent, self.section) + self.section = False + + def WriteComment(self): + if not self.comment: return + for c in self.comment: + if len(c.strip()) == 0: + print >> self.out, "" + else: + print >> self.out, "%s%s" % (self.indent, c), + self.comment = [] + + def GetOutput(self): + with open(self.path) as f: + for line in f: + if line[0] == '#': + self.comment += [line] + continue + if len(line.strip()) == 0: + self.comment += [line] + continue + header_match = HEADER_PATTERN.match(line) + if header_match: + condition = ParseCondition(header_match.group(1).strip()) + self.CloseSection() + self.WriteComment() + self.OpenSection(condition) + continue + rule_match = RULE_PATTERN.match(line) + if rule_match: + self.OpenSection() + self.WriteComment() + path = rule_match.group(1).strip() + value_str = rule_match.group(2).strip() + comment = "" + if '#' in value_str: + pos = value_str.find('#') + comment = " %s" % value_str[pos:].strip() + value_str = value_str[:pos].strip() + value = ParseCondition(value_str) + print >> self.out, ("%s'%s': [%s],%s" % + (self.indent, path, value, comment)) + continue + def_match = DEF_PATTERN.match(line) + if def_match: + # Custom definitions are deprecated. + continue + prefix_match = PREFIX_PATTERN.match(line) + if prefix_match: + continue + print "Malformed line: '%s'." % line + self.CloseSection() + self.CloseGlobal() + result = self.out.getvalue() + self.out.close() + return result diff --git a/deps/v8/tools/testrunner/local/progress.py b/deps/v8/tools/testrunner/local/progress.py new file mode 100644 index 0000000000..9075a954fa --- /dev/null +++ b/deps/v8/tools/testrunner/local/progress.py @@ -0,0 +1,238 @@ +# 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. + + +import sys +import time + +def EscapeCommand(command): + parts = [] + for part in command: + if ' ' in part: + # Escape spaces. We may need to escape more characters for this + # to work properly. + parts.append('"%s"' % part) + else: + parts.append(part) + return " ".join(parts) + + +class ProgressIndicator(object): + + def __init__(self): + self.runner = None + + def Starting(self): + pass + + def Done(self): + pass + + def AboutToRun(self, test): + pass + + def HasRun(self, test): + pass + + def PrintFailureHeader(self, test): + if test.suite.IsNegativeTest(test): + negative_marker = '[negative] ' + else: + negative_marker = '' + print "=== %(label)s %(negative)s===" % { + 'label': test.GetLabel(), + 'negative': negative_marker + } + + +class SimpleProgressIndicator(ProgressIndicator): + """Abstract base class for {Verbose,Dots}ProgressIndicator""" + + def Starting(self): + print 'Running %i tests' % self.runner.total + + def Done(self): + print + for failed in self.runner.failed: + self.PrintFailureHeader(failed) + if failed.output.stderr: + print "--- stderr ---" + print failed.output.stderr.strip() + if failed.output.stdout: + print "--- stdout ---" + print failed.output.stdout.strip() + print "Command: %s" % EscapeCommand(self.runner.GetCommand(failed)) + if failed.output.HasCrashed(): + print "--- CRASHED ---" + if failed.output.HasTimedOut(): + print "--- TIMEOUT ---" + if len(self.runner.failed) == 0: + print "===" + print "=== All tests succeeded" + print "===" + else: + print + print "===" + print "=== %i tests failed" % len(self.runner.failed) + if self.runner.crashed > 0: + print "=== %i tests CRASHED" % self.runner.crashed + print "===" + + +class VerboseProgressIndicator(SimpleProgressIndicator): + + def AboutToRun(self, test): + print 'Starting %s...' % test.GetLabel() + sys.stdout.flush() + + def HasRun(self, test): + if test.suite.HasUnexpectedOutput(test): + if test.output.HasCrashed(): + outcome = 'CRASH' + else: + outcome = 'FAIL' + else: + outcome = 'pass' + print 'Done running %s: %s' % (test.GetLabel(), outcome) + + +class DotsProgressIndicator(SimpleProgressIndicator): + + def HasRun(self, test): + total = self.runner.succeeded + len(self.runner.failed) + if (total > 1) and (total % 50 == 1): + sys.stdout.write('\n') + if test.suite.HasUnexpectedOutput(test): + if test.output.HasCrashed(): + sys.stdout.write('C') + sys.stdout.flush() + elif test.output.HasTimedOut(): + sys.stdout.write('T') + sys.stdout.flush() + else: + sys.stdout.write('F') + sys.stdout.flush() + else: + sys.stdout.write('.') + sys.stdout.flush() + + +class CompactProgressIndicator(ProgressIndicator): + """Abstract base class for {Color,Monochrome}ProgressIndicator""" + + def __init__(self, templates): + super(CompactProgressIndicator, self).__init__() + self.templates = templates + self.last_status_length = 0 + self.start_time = time.time() + + def Done(self): + self.PrintProgress('Done') + print "" # Line break. + + def AboutToRun(self, test): + self.PrintProgress(test.GetLabel()) + + def HasRun(self, test): + if test.suite.HasUnexpectedOutput(test): + self.ClearLine(self.last_status_length) + self.PrintFailureHeader(test) + stdout = test.output.stdout.strip() + if len(stdout): + print self.templates['stdout'] % stdout + stderr = test.output.stderr.strip() + if len(stderr): + print self.templates['stderr'] % stderr + print "Command: %s" % EscapeCommand(self.runner.GetCommand(test)) + if test.output.HasCrashed(): + print "exit code: %d" % test.output.exit_code + print "--- CRASHED ---" + if test.output.HasTimedOut(): + print "--- TIMEOUT ---" + + def Truncate(self, string, length): + if length and (len(string) > (length - 3)): + return string[:(length - 3)] + "..." + else: + return string + + def PrintProgress(self, name): + self.ClearLine(self.last_status_length) + elapsed = time.time() - self.start_time + status = self.templates['status_line'] % { + 'passed': self.runner.succeeded, + 'remaining': (((self.runner.total - self.runner.remaining) * 100) // + self.runner.total), + 'failed': len(self.runner.failed), + 'test': name, + 'mins': int(elapsed) / 60, + 'secs': int(elapsed) % 60 + } + status = self.Truncate(status, 78) + self.last_status_length = len(status) + print status, + sys.stdout.flush() + + +class ColorProgressIndicator(CompactProgressIndicator): + + def __init__(self): + templates = { + 'status_line': ("[%(mins)02i:%(secs)02i|" + "\033[34m%%%(remaining) 4d\033[0m|" + "\033[32m+%(passed) 4d\033[0m|" + "\033[31m-%(failed) 4d\033[0m]: %(test)s"), + 'stdout': "\033[1m%s\033[0m", + 'stderr': "\033[31m%s\033[0m", + } + super(ColorProgressIndicator, self).__init__(templates) + + def ClearLine(self, last_line_length): + print "\033[1K\r", + + +class MonochromeProgressIndicator(CompactProgressIndicator): + + def __init__(self): + templates = { + 'status_line': ("[%(mins)02i:%(secs)02i|%%%(remaining) 4d|" + "+%(passed) 4d|-%(failed) 4d]: %(test)s"), + 'stdout': '%s', + 'stderr': '%s', + } + super(MonochromeProgressIndicator, self).__init__(templates) + + def ClearLine(self, last_line_length): + print ("\r" + (" " * last_line_length) + "\r"), + + +PROGRESS_INDICATORS = { + 'verbose': VerboseProgressIndicator, + 'dots': DotsProgressIndicator, + 'color': ColorProgressIndicator, + 'mono': MonochromeProgressIndicator +} diff --git a/deps/v8/tools/testrunner/local/statusfile.py b/deps/v8/tools/testrunner/local/statusfile.py new file mode 100644 index 0000000000..bf1de45f66 --- /dev/null +++ b/deps/v8/tools/testrunner/local/statusfile.py @@ -0,0 +1,145 @@ +# 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. + + +# These imports are required for the on-demand conversion from +# old to new status file format. +from os.path import exists +from os.path import getmtime + +from . import old_statusfile + + +# These outcomes can occur in a TestCase's outcomes list: +SKIP = "SKIP" +FAIL = "FAIL" +PASS = "PASS" +OKAY = "OKAY" +TIMEOUT = "TIMEOUT" +CRASH = "CRASH" +SLOW = "SLOW" +# These are just for the status files and are mapped below in DEFS: +FAIL_OK = "FAIL_OK" +PASS_OR_FAIL = "PASS_OR_FAIL" + +ALWAYS = "ALWAYS" + +KEYWORDS = {} +for key in [SKIP, FAIL, PASS, OKAY, TIMEOUT, CRASH, SLOW, FAIL_OK, + PASS_OR_FAIL, ALWAYS]: + KEYWORDS[key] = key + +DEFS = {FAIL_OK: [FAIL, OKAY], + PASS_OR_FAIL: [PASS, FAIL]} + +# Support arches, modes to be written as keywords instead of strings. +VARIABLES = {ALWAYS: True} +for var in ["debug", "release", "android_arm", "android_ia32", "arm", "ia32", + "mipsel", "x64"]: + VARIABLES[var] = var + + +def DoSkip(outcomes): + return SKIP in outcomes or SLOW in outcomes + + +def IsFlaky(outcomes): + return ((PASS in outcomes) and (FAIL in outcomes) and + (not CRASH in outcomes) and (not OKAY in outcomes)) + + +def IsFailOk(outcomes): + return (FAIL in outcomes) and (OKAY in outcomes) + + +def _AddOutcome(result, new): + global DEFS + if new in DEFS: + mapped = DEFS[new] + if type(mapped) == list: + for m in mapped: + _AddOutcome(result, m) + elif type(mapped) == str: + _AddOutcome(result, mapped) + else: + result.add(new) + + +def _ParseOutcomeList(rule, outcomes, target_dict, variables): + result = set([]) + if type(outcomes) == str: + outcomes = [outcomes] + for item in outcomes: + if type(item) == str: + _AddOutcome(result, item) + elif type(item) == list: + if not eval(item[0], variables): continue + for outcome in item[1:]: + assert type(outcome) == str + _AddOutcome(result, outcome) + else: + assert False + if len(result) == 0: return + if rule in target_dict: + target_dict[rule] |= result + else: + target_dict[rule] = result + + +def ReadStatusFile(path, variables): + # As long as the old-format .status files are authoritative, just + # create the converted version on demand and cache it to speed up + # subsequent runs. + if path.endswith(".status"): + newpath = path + "2" + if not exists(newpath) or getmtime(newpath) < getmtime(path): + print "Converting status file." + converted = old_statusfile.ConvertNotation(path).GetOutput() + with open(newpath, 'w') as f: + f.write(converted) + path = newpath + + with open(path) as f: + global KEYWORDS + contents = eval(f.read(), KEYWORDS) + + rules = {} + wildcards = {} + variables.update(VARIABLES) + for section in contents: + assert type(section) == list + assert len(section) == 2 + if not eval(section[0], variables): continue + section = section[1] + assert type(section) == dict + for rule in section: + assert type(rule) == str + if rule[-1] == '*': + _ParseOutcomeList(rule, section[rule], wildcards, variables) + else: + _ParseOutcomeList(rule, section[rule], rules, variables) + return rules, wildcards diff --git a/deps/v8/tools/testrunner/local/testsuite.py b/deps/v8/tools/testrunner/local/testsuite.py new file mode 100644 index 0000000000..de5cddd115 --- /dev/null +++ b/deps/v8/tools/testrunner/local/testsuite.py @@ -0,0 +1,184 @@ +# 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. + + +import imp +import os + +from . import statusfile + +class TestSuite(object): + + @staticmethod + def LoadTestSuite(root): + name = root.split(os.path.sep)[-1] + f = None + try: + (f, pathname, description) = imp.find_module("testcfg", [root]) + module = imp.load_module("testcfg", f, pathname, description) + suite = module.GetSuite(name, root) + finally: + if f: + f.close() + return suite + + def __init__(self, name, root): + self.name = name # string + self.root = root # string containing path + self.tests = None # list of TestCase objects + self.rules = None # dictionary mapping test path to list of outcomes + self.wildcards = None # dictionary mapping test paths to list of outcomes + self.total_duration = None # float, assigned on demand + + def shell(self): + return "d8" + + def suffix(self): + return ".js" + + def status_file(self): + return "%s/%s.status" % (self.root, self.name) + + # Used in the status file and for stdout printing. + def CommonTestName(self, testcase): + return testcase.path + + def ListTests(self, context): + raise NotImplementedError + + def VariantFlags(self): + return None + + def DownloadData(self): + pass + + def ReadStatusFile(self, variables): + (self.rules, self.wildcards) = \ + statusfile.ReadStatusFile(self.status_file(), variables) + + def ReadTestCases(self, context): + self.tests = self.ListTests(context) + + def FilterTestCasesByStatus(self, warn_unused_rules): + filtered = [] + used_rules = set() + for t in self.tests: + testname = self.CommonTestName(t) + if testname in self.rules: + used_rules.add(testname) + outcomes = self.rules[testname] + t.outcomes = outcomes # Even for skipped tests, as the TestCase + # object stays around and PrintReport() uses it. + if statusfile.DoSkip(outcomes): + continue # Don't add skipped tests to |filtered|. + if len(self.wildcards) != 0: + skip = False + for rule in self.wildcards: + assert rule[-1] == '*' + if testname.startswith(rule[:-1]): + used_rules.add(rule) + outcomes = self.wildcards[rule] + t.outcomes = outcomes + if statusfile.DoSkip(outcomes): + skip = True + break # "for rule in self.wildcards" + if skip: continue # "for t in self.tests" + filtered.append(t) + self.tests = filtered + + if not warn_unused_rules: + return + + for rule in self.rules: + if rule not in used_rules: + print("Unused rule: %s -> %s" % (rule, self.rules[rule])) + for rule in self.wildcards: + if rule not in used_rules: + print("Unused rule: %s -> %s" % (rule, self.wildcards[rule])) + + def FilterTestCasesByArgs(self, args): + filtered = [] + filtered_args = [] + for a in args: + argpath = a.split(os.path.sep) + if argpath[0] != self.name: + continue + if len(argpath) == 1 or (len(argpath) == 2 and argpath[1] == '*'): + return # Don't filter, run all tests in this suite. + path = os.path.sep.join(argpath[1:]) + if path[-1] == '*': + path = path[:-1] + filtered_args.append(path) + for t in self.tests: + for a in filtered_args: + if t.path.startswith(a): + filtered.append(t) + break + self.tests = filtered + + def GetFlagsForTestCase(self, testcase, context): + raise NotImplementedError + + def GetSourceForTest(self, testcase): + return "(no source available)" + + def IsFailureOutput(self, output, testpath): + return output.exit_code != 0 + + def IsNegativeTest(self, testcase): + return False + + def HasFailed(self, testcase): + execution_failed = self.IsFailureOutput(testcase.output, testcase.path) + if self.IsNegativeTest(testcase): + return not execution_failed + else: + return execution_failed + + def HasUnexpectedOutput(self, testcase): + if testcase.output.HasCrashed(): + outcome = statusfile.CRASH + elif testcase.output.HasTimedOut(): + outcome = statusfile.TIMEOUT + elif self.HasFailed(testcase): + outcome = statusfile.FAIL + else: + outcome = statusfile.PASS + if not testcase.outcomes: + return outcome != statusfile.PASS + return not outcome in testcase.outcomes + + def StripOutputForTransmit(self, testcase): + if not self.HasUnexpectedOutput(testcase): + testcase.output.stdout = "" + testcase.output.stderr = "" + + def CalculateTotalDuration(self): + self.total_duration = 0.0 + for t in self.tests: + self.total_duration += t.duration + return self.total_duration diff --git a/deps/v8/tools/testrunner/local/utils.py b/deps/v8/tools/testrunner/local/utils.py new file mode 100644 index 0000000000..b7caa121f3 --- /dev/null +++ b/deps/v8/tools/testrunner/local/utils.py @@ -0,0 +1,108 @@ +# 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. + + +import os +from os.path import exists +from os.path import isdir +from os.path import join +import platform +import re + + +def GetSuitePaths(test_root): + def IsSuite(path): + return isdir(path) and exists(join(path, 'testcfg.py')) + return [ f for f in os.listdir(test_root) if IsSuite(join(test_root, f)) ] + + +# Reads a file into an array of strings +def ReadLinesFrom(name): + lines = [] + with open(name) as f: + for line in f: + if line.startswith('#'): continue + if '#' in line: + line = line[:line.find('#')] + line = line.strip() + if not line: continue + lines.append(line) + return lines + + +def GuessOS(): + system = platform.system() + if system == 'Linux': + return 'linux' + elif system == 'Darwin': + return 'macos' + elif system.find('CYGWIN') >= 0: + return 'cygwin' + elif system == 'Windows' or system == 'Microsoft': + # On Windows Vista platform.system() can return 'Microsoft' with some + # versions of Python, see http://bugs.python.org/issue1082 + return 'win32' + elif system == 'FreeBSD': + return 'freebsd' + elif system == 'OpenBSD': + return 'openbsd' + elif system == 'SunOS': + return 'solaris' + elif system == 'NetBSD': + return 'netbsd' + else: + return None + + +# This will default to building the 32 bit VM even on machines that are +# capable of running the 64 bit VM. +def DefaultArch(): + machine = platform.machine() + machine = machine.lower() # Windows 7 capitalizes 'AMD64'. + if machine.startswith('arm'): + return 'arm' + elif (not machine) or (not re.match('(x|i[3-6])86$', machine) is None): + return 'ia32' + elif machine == 'i86pc': + return 'ia32' + elif machine == 'x86_64': + return 'ia32' + elif machine == 'amd64': + return 'ia32' + else: + return None + + +def GuessWordsize(): + if '64' in platform.machine(): + return '64' + else: + return '32' + + +def IsWindows(): + return GuessOS() == 'win32' diff --git a/deps/v8/tools/testrunner/local/verbose.py b/deps/v8/tools/testrunner/local/verbose.py new file mode 100644 index 0000000000..f693467523 --- /dev/null +++ b/deps/v8/tools/testrunner/local/verbose.py @@ -0,0 +1,99 @@ +# 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. + + +import sys +import time + +from . import statusfile + + +REPORT_TEMPLATE = ( +"""Total: %(total)i tests + * %(skipped)4d tests will be skipped + * %(timeout)4d tests are expected to timeout sometimes + * %(nocrash)4d tests are expected to be flaky but not crash + * %(pass)4d tests are expected to pass + * %(fail_ok)4d tests are expected to fail that we won't fix + * %(fail)4d tests are expected to fail that we should fix""") + + +def PrintReport(tests): + total = len(tests) + skipped = timeout = nocrash = passes = fail_ok = fail = 0 + for t in tests: + if "outcomes" not in dir(t) or not t.outcomes: + passes += 1 + continue + o = t.outcomes + if statusfile.DoSkip(o): + skipped += 1 + continue + if statusfile.TIMEOUT in o: timeout += 1 + if statusfile.IsFlaky(o): nocrash += 1 + if list(o) == [statusfile.PASS]: passes += 1 + if statusfile.IsFailOk(o): fail_ok += 1 + if list(o) == [statusfile.FAIL]: fail += 1 + print REPORT_TEMPLATE % { + "total": total, + "skipped": skipped, + "timeout": timeout, + "nocrash": nocrash, + "pass": passes, + "fail_ok": fail_ok, + "fail": fail + } + + +def PrintTestSource(tests): + for test in tests: + suite = test.suite + source = suite.GetSourceForTest(test).strip() + if len(source) > 0: + print "--- begin source: %s/%s ---" % (suite.name, test.path) + print source + print "--- end source: %s/%s ---" % (suite.name, test.path) + + +def FormatTime(d): + millis = round(d * 1000) % 1000 + return time.strftime("%M:%S.", time.gmtime(d)) + ("%03i" % millis) + + +def PrintTestDurations(suites, overall_time): + # Write the times to stderr to make it easy to separate from the + # test output. + print + sys.stderr.write("--- Total time: %s ---\n" % FormatTime(overall_time)) + timed_tests = [ t for s in suites for t in s.tests + if t.duration is not None ] + timed_tests.sort(lambda a, b: cmp(b.duration, a.duration)) + index = 1 + for entry in timed_tests[:20]: + t = FormatTime(entry.duration) + sys.stderr.write("%4i (%s) %s\n" % (index, t, entry.GetLabel())) + index += 1 diff --git a/deps/v8/tools/testrunner/network/__init__.py b/deps/v8/tools/testrunner/network/__init__.py new file mode 100644 index 0000000000..202a262709 --- /dev/null +++ b/deps/v8/tools/testrunner/network/__init__.py @@ -0,0 +1,26 @@ +# 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. diff --git a/deps/v8/tools/testrunner/network/distro.py b/deps/v8/tools/testrunner/network/distro.py new file mode 100644 index 0000000000..9d5a471d44 --- /dev/null +++ b/deps/v8/tools/testrunner/network/distro.py @@ -0,0 +1,90 @@ +# 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. + + +class Shell(object): + def __init__(self, shell): + self.shell = shell + self.tests = [] + self.total_duration = 0.0 + + def AddSuite(self, suite): + self.tests += suite.tests + self.total_duration += suite.total_duration + + def SortTests(self): + self.tests.sort(cmp=lambda x, y: cmp(x.duration, y.duration)) + + +def Assign(suites, peers): + total_work = 0.0 + for s in suites: + total_work += s.CalculateTotalDuration() + + total_power = 0.0 + for p in peers: + p.assigned_work = 0.0 + total_power += p.jobs * p.relative_performance + for p in peers: + p.needed_work = total_work * p.jobs * p.relative_performance / total_power + + shells = {} + for s in suites: + shell = s.shell() + if not shell in shells: + shells[shell] = Shell(shell) + shells[shell].AddSuite(s) + # Convert |shells| to list and sort it, shortest total_duration first. + shells = [ shells[s] for s in shells ] + shells.sort(cmp=lambda x, y: cmp(x.total_duration, y.total_duration)) + # Sort tests within each shell, longest duration last (so it's + # pop()'ed first). + for s in shells: s.SortTests() + # Sort peers, least needed_work first. + peers.sort(cmp=lambda x, y: cmp(x.needed_work, y.needed_work)) + index = 0 + for shell in shells: + while len(shell.tests) > 0: + while peers[index].needed_work <= 0: + index += 1 + if index == len(peers): + print("BIG FAT WARNING: Assigning tests to peers failed. " + "Remaining tests: %d. Going to slow mode." % len(shell.tests)) + # Pick the least-busy peer. Sorting the list for each test + # is terribly slow, but this is just an emergency fallback anyway. + peers.sort(cmp=lambda x, y: cmp(x.needed_work, y.needed_work)) + peers[0].ForceAddOneTest(shell.tests.pop(), shell) + # If the peer already has a shell assigned and would need this one + # and then yet another, try to avoid it. + peer = peers[index] + if (shell.total_duration < peer.needed_work and + len(peer.shells) > 0 and + index < len(peers) - 1 and + shell.total_duration <= peers[index + 1].needed_work): + peers[index + 1].AddTests(shell) + else: + peer.AddTests(shell) diff --git a/deps/v8/tools/testrunner/network/endpoint.py b/deps/v8/tools/testrunner/network/endpoint.py new file mode 100644 index 0000000000..5dc2b9f902 --- /dev/null +++ b/deps/v8/tools/testrunner/network/endpoint.py @@ -0,0 +1,124 @@ +# 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. + + +import multiprocessing +import os +import Queue +import threading +import time + +from ..local import execution +from ..local import progress +from ..local import testsuite +from ..local import utils +from ..server import compression + + +class EndpointProgress(progress.ProgressIndicator): + def __init__(self, sock, server, ctx): + super(EndpointProgress, self).__init__() + self.sock = sock + self.server = server + self.context = ctx + self.results_queue = [] # Accessors must synchronize themselves. + self.sender_lock = threading.Lock() + self.senderthread = threading.Thread(target=self._SenderThread) + self.senderthread.start() + + def HasRun(self, test): + # The runners that call this have a lock anyway, so this is safe. + self.results_queue.append(test) + + def _SenderThread(self): + keep_running = True + tests = [] + self.sender_lock.acquire() + while keep_running: + time.sleep(0.1) + # This should be "atomic enough" without locking :-) + # (We don't care which list any new elements get appended to, as long + # as we don't lose any and the last one comes last.) + current = self.results_queue + self.results_queue = [] + for c in current: + if c is None: + keep_running = False + else: + tests.append(c) + if keep_running and len(tests) < 1: + continue # Wait for more results. + if len(tests) < 1: break # We're done here. + result = [] + for t in tests: + result.append(t.PackResult()) + try: + compression.Send(result, self.sock) + except: + self.runner.terminate = True + for t in tests: + self.server.CompareOwnPerf(t, self.context.arch, self.context.mode) + tests = [] + self.sender_lock.release() + + +def Execute(workspace, ctx, tests, sock, server): + suite_paths = utils.GetSuitePaths(os.path.join(workspace, "test")) + suites = [] + for root in suite_paths: + suite = testsuite.TestSuite.LoadTestSuite( + os.path.join(workspace, "test", root)) + if suite: + suites.append(suite) + + suites_dict = {} + for s in suites: + suites_dict[s.name] = s + s.tests = [] + for t in tests: + suite = suites_dict[t.suite] + t.suite = suite + suite.tests.append(t) + + suites = [ s for s in suites if len(s.tests) > 0 ] + for s in suites: + s.DownloadData() + + progress_indicator = EndpointProgress(sock, server, ctx) + runner = execution.Runner(suites, progress_indicator, ctx) + try: + runner.Run(server.jobs) + except IOError, e: + if e.errno == 2: + message = ("File not found: %s, maybe you forgot to 'git add' it?" % + e.filename) + else: + message = "%s" % e + compression.Send([[-1, message]], sock) + progress_indicator.HasRun(None) # Sentinel to signal the end. + progress_indicator.sender_lock.acquire() # Released when sending is done. + progress_indicator.sender_lock.release() diff --git a/deps/v8/tools/testrunner/network/network_execution.py b/deps/v8/tools/testrunner/network/network_execution.py new file mode 100644 index 0000000000..ddb59e60b7 --- /dev/null +++ b/deps/v8/tools/testrunner/network/network_execution.py @@ -0,0 +1,253 @@ +# 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. + + +import os +import socket +import subprocess +import threading +import time + +from . import distro +from . import perfdata +from ..local import execution +from ..objects import peer +from ..objects import workpacket +from ..server import compression +from ..server import constants +from ..server import local_handler +from ..server import signatures + + +def GetPeers(): + data = local_handler.LocalQuery([constants.REQUEST_PEERS]) + if not data: return [] + return [ peer.Peer.Unpack(p) for p in data ] + + +class NetworkedRunner(execution.Runner): + def __init__(self, suites, progress_indicator, context, peers, workspace): + self.suites = suites + num_tests = 0 + datapath = os.path.join("out", "testrunner_data") + self.perf_data_manager = perfdata.PerfDataManager(datapath) + self.perfdata = self.perf_data_manager.GetStore(context.arch, context.mode) + for s in suites: + for t in s.tests: + t.duration = self.perfdata.FetchPerfData(t) or 1.0 + num_tests += len(s.tests) + self._CommonInit(num_tests, progress_indicator, context) + self.tests = [] # Only used if we need to fall back to local execution. + self.tests_lock = threading.Lock() + self.peers = peers + self.pubkey_fingerprint = None # Fetched later. + self.base_rev = subprocess.check_output( + "cd %s; git log -1 --format=%%H --grep=git-svn-id" % workspace, + shell=True).strip() + self.base_svn_rev = subprocess.check_output( + "cd %s; git log -1 %s" # Get commit description. + " | grep -e '^\s*git-svn-id:'" # Extract "git-svn-id" line. + " | awk '{print $2}'" # Extract "repository@revision" part. + " | sed -e 's/.*@//'" % # Strip away "repository@". + (workspace, self.base_rev), shell=True).strip() + self.patch = subprocess.check_output( + "cd %s; git diff %s" % (workspace, self.base_rev), shell=True) + self.binaries = {} + self.initialization_lock = threading.Lock() + self.initialization_lock.acquire() # Released when init is done. + self._OpenLocalConnection() + self.local_receiver_thread = threading.Thread( + target=self._ListenLocalConnection) + self.local_receiver_thread.daemon = True + self.local_receiver_thread.start() + self.initialization_lock.acquire() + self.initialization_lock.release() + + def _OpenLocalConnection(self): + self.local_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + code = self.local_socket.connect_ex(("localhost", constants.CLIENT_PORT)) + if code != 0: + raise RuntimeError("Failed to connect to local server") + compression.Send([constants.REQUEST_PUBKEY_FINGERPRINT], self.local_socket) + + def _ListenLocalConnection(self): + release_lock_countdown = 1 # Pubkey. + self.local_receiver = compression.Receiver(self.local_socket) + while not self.local_receiver.IsDone(): + data = self.local_receiver.Current() + if data[0] == constants.REQUEST_PUBKEY_FINGERPRINT: + pubkey = data[1] + if not pubkey: raise RuntimeError("Received empty public key") + self.pubkey_fingerprint = pubkey + release_lock_countdown -= 1 + if release_lock_countdown == 0: + self.initialization_lock.release() + release_lock_countdown -= 1 # Prevent repeated triggering. + self.local_receiver.Advance() + + def Run(self, jobs): + self.indicator.Starting() + need_libv8 = False + for s in self.suites: + shell = s.shell() + if shell not in self.binaries: + path = os.path.join(self.context.shell_dir, shell) + # Check if this is a shared library build. + try: + ldd = subprocess.check_output("ldd %s | grep libv8\\.so" % (path), + shell=True) + ldd = ldd.strip().split(" ") + assert ldd[0] == "libv8.so" + assert ldd[1] == "=>" + need_libv8 = True + binary_needs_libv8 = True + libv8 = signatures.ReadFileAndSignature(ldd[2]) + except: + binary_needs_libv8 = False + binary = signatures.ReadFileAndSignature(path) + if binary[0] is None: + print("Error: Failed to create signature.") + assert binary[1] != 0 + return binary[1] + binary.append(binary_needs_libv8) + self.binaries[shell] = binary + if need_libv8: + self.binaries["libv8.so"] = libv8 + distro.Assign(self.suites, self.peers) + # Spawn one thread for each peer. + threads = [] + for p in self.peers: + thread = threading.Thread(target=self._TalkToPeer, args=[p]) + threads.append(thread) + thread.start() + try: + for thread in threads: + # Use a timeout so that signals (Ctrl+C) will be processed. + thread.join(timeout=10000000) + self._AnalyzePeerRuntimes() + except KeyboardInterrupt: + self.terminate = True + raise + except Exception, _e: + # If there's an exception we schedule an interruption for any + # remaining threads... + self.terminate = True + # ...and then reraise the exception to bail out. + raise + compression.Send(constants.END_OF_STREAM, self.local_socket) + self.local_socket.close() + if self.tests: + self._RunInternal(jobs) + self.indicator.Done() + return not self.failed + + def _TalkToPeer(self, peer): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(self.context.timeout + 10) + code = sock.connect_ex((peer.address, constants.PEER_PORT)) + if code == 0: + try: + peer.runtime = None + start_time = time.time() + packet = workpacket.WorkPacket(peer=peer, context=self.context, + base_revision=self.base_svn_rev, + patch=self.patch, + pubkey=self.pubkey_fingerprint) + data, test_map = packet.Pack(self.binaries) + compression.Send(data, sock) + compression.Send(constants.END_OF_STREAM, sock) + rec = compression.Receiver(sock) + while not rec.IsDone() and not self.terminate: + data_list = rec.Current() + for data in data_list: + test_id = data[0] + if test_id < 0: + # The peer is reporting an error. + with self.lock: + print("\nPeer %s reports error: %s" % (peer.address, data[1])) + continue + test = test_map.pop(test_id) + test.MergeResult(data) + try: + self.perfdata.UpdatePerfData(test) + except Exception, e: + print("UpdatePerfData exception: %s" % e) + pass # Just keep working. + with self.lock: + perf_key = self.perfdata.GetKey(test) + compression.Send( + [constants.INFORM_DURATION, perf_key, test.duration, + self.context.arch, self.context.mode], + self.local_socket) + self.indicator.AboutToRun(test) + if test.suite.HasUnexpectedOutput(test): + self.failed.append(test) + if test.output.HasCrashed(): + self.crashed += 1 + else: + self.succeeded += 1 + self.remaining -= 1 + self.indicator.HasRun(test) + rec.Advance() + peer.runtime = time.time() - start_time + except KeyboardInterrupt: + sock.close() + raise + except Exception, e: + print("Got exception: %s" % e) + pass # Fall back to local execution. + else: + compression.Send([constants.UNRESPONSIVE_PEER, peer.address], + self.local_socket) + sock.close() + if len(test_map) > 0: + # Some tests have not received any results. Run them locally. + print("\nNo results for %d tests, running them locally." % len(test_map)) + self._EnqueueLocally(test_map) + + def _EnqueueLocally(self, test_map): + with self.tests_lock: + for test in test_map: + self.tests.append(test_map[test]) + + def _AnalyzePeerRuntimes(self): + total_runtime = 0.0 + total_work = 0.0 + for p in self.peers: + if p.runtime is None: + return + total_runtime += p.runtime + total_work += p.assigned_work + for p in self.peers: + p.assigned_work /= total_work + p.runtime /= total_runtime + perf_correction = p.assigned_work / p.runtime + old_perf = p.relative_performance + p.relative_performance = (old_perf + perf_correction) / 2.0 + compression.Send([constants.UPDATE_PERF, p.address, + p.relative_performance], + self.local_socket) diff --git a/deps/v8/tools/testrunner/network/perfdata.py b/deps/v8/tools/testrunner/network/perfdata.py new file mode 100644 index 0000000000..2979dc4866 --- /dev/null +++ b/deps/v8/tools/testrunner/network/perfdata.py @@ -0,0 +1,120 @@ +# 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. + + +import os +import shelve +import threading + + +class PerfDataEntry(object): + def __init__(self): + self.avg = 0.0 + self.count = 0 + + def AddResult(self, result): + kLearnRateLimiter = 99 # Greater value means slower learning. + # We use an approximation of the average of the last 100 results here: + # The existing average is weighted with kLearnRateLimiter (or less + # if there are fewer data points). + effective_count = min(self.count, kLearnRateLimiter) + self.avg = self.avg * effective_count + result + self.count = effective_count + 1 + self.avg /= self.count + + +class PerfDataStore(object): + def __init__(self, datadir, arch, mode): + filename = os.path.join(datadir, "%s.%s.perfdata" % (arch, mode)) + self.database = shelve.open(filename, protocol=2) + self.closed = False + self.lock = threading.Lock() + + def __del__(self): + self.close() + + def close(self): + if self.closed: return + self.database.close() + self.closed = True + + def GetKey(self, test): + """Computes the key used to access data for the given testcase.""" + flags = "".join(test.flags) + return str("%s.%s.%s" % (test.suitename(), test.path, flags)) + + def FetchPerfData(self, test): + """Returns the observed duration for |test| as read from the store.""" + key = self.GetKey(test) + if key in self.database: + return self.database[key].avg + return None + + def UpdatePerfData(self, test): + """Updates the persisted value in the store with test.duration.""" + testkey = self.GetKey(test) + self.RawUpdatePerfData(testkey, test.duration) + + def RawUpdatePerfData(self, testkey, duration): + with self.lock: + if testkey in self.database: + entry = self.database[testkey] + else: + entry = PerfDataEntry() + entry.AddResult(duration) + self.database[testkey] = entry + + +class PerfDataManager(object): + def __init__(self, datadir): + self.datadir = os.path.abspath(datadir) + if not os.path.exists(self.datadir): + os.makedirs(self.datadir) + self.stores = {} # Keyed by arch, then mode. + self.closed = False + self.lock = threading.Lock() + + def __del__(self): + self.close() + + def close(self): + if self.closed: return + for arch in self.stores: + modes = self.stores[arch] + for mode in modes: + store = modes[mode] + store.close() + self.closed = True + + def GetStore(self, arch, mode): + with self.lock: + if not arch in self.stores: + self.stores[arch] = {} + modes = self.stores[arch] + if not mode in modes: + modes[mode] = PerfDataStore(self.datadir, arch, mode) + return modes[mode] diff --git a/deps/v8/tools/testrunner/objects/__init__.py b/deps/v8/tools/testrunner/objects/__init__.py new file mode 100644 index 0000000000..202a262709 --- /dev/null +++ b/deps/v8/tools/testrunner/objects/__init__.py @@ -0,0 +1,26 @@ +# 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. diff --git a/deps/v8/tools/testrunner/objects/context.py b/deps/v8/tools/testrunner/objects/context.py new file mode 100644 index 0000000000..b72284b648 --- /dev/null +++ b/deps/v8/tools/testrunner/objects/context.py @@ -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. + + +class Context(): + def __init__(self, arch, mode, shell_dir, mode_flags, verbose, timeout, + isolates, command_prefix, extra_flags): + self.arch = arch + self.mode = mode + self.shell_dir = shell_dir + self.mode_flags = mode_flags + self.verbose = verbose + self.timeout = timeout + self.isolates = isolates + self.command_prefix = command_prefix + self.extra_flags = extra_flags + + def Pack(self): + return [self.arch, self.mode, self.mode_flags, self.timeout, self.isolates, + self.extra_flags] + + @staticmethod + def Unpack(packed): + # For the order of the fields, refer to Pack() above. + return Context(packed[0], packed[1], None, packed[2], False, + packed[3], packed[4], "", packed[5]) diff --git a/deps/v8/tools/testrunner/objects/output.py b/deps/v8/tools/testrunner/objects/output.py new file mode 100644 index 0000000000..87b4c84e19 --- /dev/null +++ b/deps/v8/tools/testrunner/objects/output.py @@ -0,0 +1,60 @@ +# 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. + + +import signal + +from ..local import utils + +class Output(object): + + def __init__(self, exit_code, timed_out, stdout, stderr): + self.exit_code = exit_code + self.timed_out = timed_out + self.stdout = stdout + self.stderr = stderr + + def HasCrashed(self): + if utils.IsWindows(): + return 0x80000000 & self.exit_code and not (0x3FFFFF00 & self.exit_code) + else: + # Timed out tests will have exit_code -signal.SIGTERM. + if self.timed_out: + return False + return (self.exit_code < 0 and + self.exit_code != -signal.SIGABRT) + + def HasTimedOut(self): + return self.timed_out + + def Pack(self): + return [self.exit_code, self.timed_out, self.stdout, self.stderr] + + @staticmethod + def Unpack(packed): + # For the order of the fields, refer to Pack() above. + return Output(packed[0], packed[1], packed[2], packed[3]) diff --git a/deps/v8/tools/testrunner/objects/peer.py b/deps/v8/tools/testrunner/objects/peer.py new file mode 100644 index 0000000000..18a6bec7a8 --- /dev/null +++ b/deps/v8/tools/testrunner/objects/peer.py @@ -0,0 +1,80 @@ +# 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. + + +class Peer(object): + def __init__(self, address, jobs, rel_perf, pubkey): + self.address = address # string: IP address + self.jobs = jobs # integer: number of CPUs + self.relative_performance = rel_perf + self.pubkey = pubkey # string: pubkey's fingerprint + self.shells = set() # set of strings + self.needed_work = 0 + self.assigned_work = 0 + self.tests = [] # list of TestCase objects + self.trusting_me = False # This peer trusts my public key. + self.trusted = False # I trust this peer's public key. + + def __str__(self): + return ("Peer at %s, jobs: %d, performance: %.2f, trust I/O: %s/%s" % + (self.address, self.jobs, self.relative_performance, + self.trusting_me, self.trusted)) + + def AddTests(self, shell): + """Adds tests from |shell| to this peer. + + Stops when self.needed_work reaches zero, or when all of shell's tests + are assigned.""" + assert self.needed_work > 0 + if shell.shell not in self.shells: + self.shells.add(shell.shell) + while len(shell.tests) > 0 and self.needed_work > 0: + t = shell.tests.pop() + self.needed_work -= t.duration + self.assigned_work += t.duration + shell.total_duration -= t.duration + self.tests.append(t) + + def ForceAddOneTest(self, test, shell): + """Forcibly adds another test to this peer, disregarding needed_work.""" + if shell.shell not in self.shells: + self.shells.add(shell.shell) + self.needed_work -= test.duration + self.assigned_work += test.duration + shell.total_duration -= test.duration + self.tests.append(test) + + + def Pack(self): + """Creates a JSON serializable representation of this Peer.""" + return [self.address, self.jobs, self.relative_performance] + + @staticmethod + def Unpack(packed): + """Creates a Peer object built from a packed representation.""" + pubkey_dummy = "" # Callers of this don't care (only the server does). + return Peer(packed[0], packed[1], packed[2], pubkey_dummy) diff --git a/deps/v8/tools/testrunner/objects/testcase.py b/deps/v8/tools/testrunner/objects/testcase.py new file mode 100644 index 0000000000..cfc522ea73 --- /dev/null +++ b/deps/v8/tools/testrunner/objects/testcase.py @@ -0,0 +1,83 @@ +# 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. + + +from . import output + +class TestCase(object): + def __init__(self, suite, path, flags=[], dependency=None): + self.suite = suite # TestSuite object + self.path = path # string, e.g. 'div-mod', 'test-api/foo' + self.flags = flags # list of strings, flags specific to this test case + self.dependency = dependency # |path| for testcase that must be run first + self.outcomes = None + self.output = None + self.id = None # int, used to map result back to TestCase instance + self.duration = None # assigned during execution + + def CopyAddingFlags(self, flags): + copy = TestCase(self.suite, self.path, self.flags + flags, self.dependency) + copy.outcomes = self.outcomes + return copy + + def PackTask(self): + """ + Extracts those parts of this object that are required to run the test + and returns them as a JSON serializable object. + """ + assert self.id is not None + return [self.suitename(), self.path, self.flags, + self.dependency, list(self.outcomes or []), self.id] + + @staticmethod + def UnpackTask(task): + """Creates a new TestCase object based on packed task data.""" + # For the order of the fields, refer to PackTask() above. + test = TestCase(str(task[0]), task[1], task[2], task[3]) + test.outcomes = set(task[4]) + test.id = task[5] + return test + + def SetSuiteObject(self, suites): + self.suite = suites[self.suite] + + def PackResult(self): + """Serializes the output of the TestCase after it has run.""" + self.suite.StripOutputForTransmit(self) + return [self.id, self.output.Pack(), self.duration] + + def MergeResult(self, result): + """Applies the contents of a Result to this object.""" + assert result[0] == self.id + self.output = output.Output.Unpack(result[1]) + self.duration = result[2] + + def suitename(self): + return self.suite.name + + def GetLabel(self): + return self.suitename() + "/" + self.suite.CommonTestName(self) diff --git a/deps/v8/tools/testrunner/objects/workpacket.py b/deps/v8/tools/testrunner/objects/workpacket.py new file mode 100644 index 0000000000..d07efe76ec --- /dev/null +++ b/deps/v8/tools/testrunner/objects/workpacket.py @@ -0,0 +1,90 @@ +# 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. + + +from . import context +from . import testcase + +class WorkPacket(object): + def __init__(self, peer=None, context=None, tests=None, binaries=None, + base_revision=None, patch=None, pubkey=None): + self.peer = peer + self.context = context + self.tests = tests + self.binaries = binaries + self.base_revision = base_revision + self.patch = patch + self.pubkey_fingerprint = pubkey + + def Pack(self, binaries_dict): + """ + Creates a JSON serializable object containing the data of this + work packet. + """ + need_libv8 = False + binaries = [] + for shell in self.peer.shells: + prefetched_binary = binaries_dict[shell] + binaries.append({"name": shell, + "blob": prefetched_binary[0], + "sign": prefetched_binary[1]}) + if prefetched_binary[2]: + need_libv8 = True + if need_libv8: + libv8 = binaries_dict["libv8.so"] + binaries.append({"name": "libv8.so", + "blob": libv8[0], + "sign": libv8[1]}) + tests = [] + test_map = {} + for t in self.peer.tests: + test_map[t.id] = t + tests.append(t.PackTask()) + result = { + "binaries": binaries, + "pubkey": self.pubkey_fingerprint, + "context": self.context.Pack(), + "base_revision": self.base_revision, + "patch": self.patch, + "tests": tests + } + return result, test_map + + @staticmethod + def Unpack(packed): + """ + Creates a WorkPacket object from the given packed representation. + """ + binaries = packed["binaries"] + pubkey_fingerprint = packed["pubkey"] + ctx = context.Context.Unpack(packed["context"]) + base_revision = packed["base_revision"] + patch = packed["patch"] + tests = [ testcase.TestCase.UnpackTask(t) for t in packed["tests"] ] + return WorkPacket(context=ctx, tests=tests, binaries=binaries, + base_revision=base_revision, patch=patch, + pubkey=pubkey_fingerprint) diff --git a/deps/v8/tools/testrunner/server/__init__.py b/deps/v8/tools/testrunner/server/__init__.py new file mode 100644 index 0000000000..202a262709 --- /dev/null +++ b/deps/v8/tools/testrunner/server/__init__.py @@ -0,0 +1,26 @@ +# 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. diff --git a/deps/v8/tools/testrunner/server/compression.py b/deps/v8/tools/testrunner/server/compression.py new file mode 100644 index 0000000000..ce90c4f597 --- /dev/null +++ b/deps/v8/tools/testrunner/server/compression.py @@ -0,0 +1,112 @@ +# 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. + + +import cStringIO as StringIO +try: + import ujson as json +except ImportError: + print("You should install UltraJSON, it is much faster!") + import json +import os +import struct +import zlib + +from . import constants + +def Send(obj, sock): + """ + Sends a JSON encodable object over the specified socket (zlib-compressed). + """ + obj = json.dumps(obj) + compression_level = 2 # 1 = fastest, 9 = best compression + compressed = zlib.compress(obj, compression_level) + payload = struct.pack('>i', len(compressed)) + compressed + sock.sendall(payload) + + +class Receiver(object): + def __init__(self, sock): + self.sock = sock + self.data = StringIO.StringIO() + self.datalength = 0 + self._next = self._GetNext() + + def IsDone(self): + return self._next == None + + def Current(self): + return self._next + + def Advance(self): + try: + self._next = self._GetNext() + except: + raise + + def _GetNext(self): + try: + while self.datalength < constants.SIZE_T: + try: + chunk = self.sock.recv(8192) + except: + raise + if not chunk: return None + self._AppendData(chunk) + size = self._PopData(constants.SIZE_T) + size = struct.unpack(">i", size)[0] + while self.datalength < size: + try: + chunk = self.sock.recv(8192) + except: + raise + if not chunk: return None + self._AppendData(chunk) + result = self._PopData(size) + result = zlib.decompress(result) + result = json.loads(result) + if result == constants.END_OF_STREAM: + return None + return result + except: + raise + + def _AppendData(self, new): + self.data.seek(0, os.SEEK_END) + self.data.write(new) + self.datalength += len(new) + + def _PopData(self, length): + self.data.seek(0) + chunk = self.data.read(length) + remaining = self.data.read() + self.data.close() + self.data = StringIO.StringIO() + self.data.write(remaining) + assert self.datalength - length == len(remaining) + self.datalength = len(remaining) + return chunk diff --git a/deps/v8/tools/testrunner/server/constants.py b/deps/v8/tools/testrunner/server/constants.py new file mode 100644 index 0000000000..5aefcbad0d --- /dev/null +++ b/deps/v8/tools/testrunner/server/constants.py @@ -0,0 +1,51 @@ +# 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. + + +CLIENT_PORT = 9991 # Port for the local client to connect to. +PEER_PORT = 9992 # Port for peers on the network to connect to. +PRESENCE_PORT = 9993 # Port for presence daemon. +STATUS_PORT = 9994 # Port for network requests not related to workpackets. + +END_OF_STREAM = "end of dtest stream" # Marker for end of network requests. +SIZE_T = 4 # Number of bytes used for network request size header. + +# Messages understood by the local request handler. +ADD_TRUSTED = "add trusted" +INFORM_DURATION = "inform about duration" +REQUEST_PEERS = "get peers" +UNRESPONSIVE_PEER = "unresponsive peer" +REQUEST_PUBKEY_FINGERPRINT = "get pubkey fingerprint" +REQUEST_STATUS = "get status" +UPDATE_PERF = "update performance" + +# Messages understood by the status request handler. +LIST_TRUSTED_PUBKEYS = "list trusted pubkeys" +GET_SIGNED_PUBKEY = "pass on signed pubkey" +NOTIFY_NEW_TRUSTED = "new trusted peer" +TRUST_YOU_NOW = "trust you now" +DO_YOU_TRUST = "do you trust" diff --git a/deps/v8/tools/testrunner/server/daemon.py b/deps/v8/tools/testrunner/server/daemon.py new file mode 100644 index 0000000000..baa66fbea9 --- /dev/null +++ b/deps/v8/tools/testrunner/server/daemon.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python + +# This code has been written by Sander Marechal and published at: +# http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ +# where the author has placed it in the public domain (see comment #6 at +# http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/#c6 +# ). +# Some minor modifications have been made by the V8 authors. The work remains +# in the public domain. + +import atexit +import os +from signal import SIGTERM +from signal import SIGINT +import sys +import time + + +class Daemon(object): + """ + A generic daemon class. + + Usage: subclass the Daemon class and override the run() method + """ + def __init__(self, pidfile, stdin='/dev/null', + stdout='/dev/null', stderr='/dev/null'): + self.stdin = stdin + self.stdout = stdout + self.stderr = stderr + self.pidfile = pidfile + + def daemonize(self): + """ + do the UNIX double-fork magic, see Stevens' "Advanced + Programming in the UNIX Environment" for details (ISBN 0201563177) + http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 + """ + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError, e: + sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) + sys.exit(1) + + # decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError, e: + sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) + sys.exit(1) + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = file(self.stdin, 'r') + so = file(self.stdout, 'a+') + se = file(self.stderr, 'a+', 0) + # TODO: (debug) re-enable this! + #os.dup2(si.fileno(), sys.stdin.fileno()) + #os.dup2(so.fileno(), sys.stdout.fileno()) + #os.dup2(se.fileno(), sys.stderr.fileno()) + + # write pidfile + atexit.register(self.delpid) + pid = str(os.getpid()) + file(self.pidfile, 'w+').write("%s\n" % pid) + + def delpid(self): + os.remove(self.pidfile) + + def start(self): + """ + Start the daemon + """ + # Check for a pidfile to see if the daemon already runs + try: + pf = file(self.pidfile, 'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if pid: + message = "pidfile %s already exist. Daemon already running?\n" + sys.stderr.write(message % self.pidfile) + sys.exit(1) + + # Start the daemon + self.daemonize() + self.run() + + def stop(self): + """ + Stop the daemon + """ + # Get the pid from the pidfile + try: + pf = file(self.pidfile, 'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if not pid: + message = "pidfile %s does not exist. Daemon not running?\n" + sys.stderr.write(message % self.pidfile) + return # not an error in a restart + + # Try killing the daemon process + try: + # Give the process a one-second chance to exit gracefully. + os.kill(pid, SIGINT) + time.sleep(1) + while 1: + os.kill(pid, SIGTERM) + time.sleep(0.1) + except OSError, err: + err = str(err) + if err.find("No such process") > 0: + if os.path.exists(self.pidfile): + os.remove(self.pidfile) + else: + print str(err) + sys.exit(1) + + def restart(self): + """ + Restart the daemon + """ + self.stop() + self.start() + + def run(self): + """ + You should override this method when you subclass Daemon. It will be + called after the process has been daemonized by start() or restart(). + """ diff --git a/deps/v8/tools/testrunner/server/local_handler.py b/deps/v8/tools/testrunner/server/local_handler.py new file mode 100644 index 0000000000..3b3ac495d0 --- /dev/null +++ b/deps/v8/tools/testrunner/server/local_handler.py @@ -0,0 +1,119 @@ +# 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. + + +import socket +import SocketServer +import StringIO + +from . import compression +from . import constants + + +def LocalQuery(query): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + code = sock.connect_ex(("localhost", constants.CLIENT_PORT)) + if code != 0: return None + compression.Send(query, sock) + compression.Send(constants.END_OF_STREAM, sock) + rec = compression.Receiver(sock) + data = None + while not rec.IsDone(): + data = rec.Current() + assert data[0] == query[0] + data = data[1] + rec.Advance() + sock.close() + return data + + +class LocalHandler(SocketServer.BaseRequestHandler): + def handle(self): + rec = compression.Receiver(self.request) + while not rec.IsDone(): + data = rec.Current() + action = data[0] + + if action == constants.REQUEST_PEERS: + with self.server.daemon.peer_list_lock: + response = [ p.Pack() for p in self.server.daemon.peers + if p.trusting_me ] + compression.Send([action, response], self.request) + + elif action == constants.UNRESPONSIVE_PEER: + self.server.daemon.DeletePeer(data[1]) + + elif action == constants.REQUEST_PUBKEY_FINGERPRINT: + compression.Send([action, self.server.daemon.pubkey_fingerprint], + self.request) + + elif action == constants.REQUEST_STATUS: + compression.Send([action, self._GetStatusMessage()], self.request) + + elif action == constants.ADD_TRUSTED: + fingerprint = self.server.daemon.CopyToTrusted(data[1]) + compression.Send([action, fingerprint], self.request) + + elif action == constants.INFORM_DURATION: + test_key = data[1] + test_duration = data[2] + arch = data[3] + mode = data[4] + self.server.daemon.AddPerfData(test_key, test_duration, arch, mode) + + elif action == constants.UPDATE_PERF: + address = data[1] + perf = data[2] + self.server.daemon.UpdatePeerPerformance(data[1], data[2]) + + rec.Advance() + compression.Send(constants.END_OF_STREAM, self.request) + + def _GetStatusMessage(self): + sio = StringIO.StringIO() + sio.write("Peers:\n") + with self.server.daemon.peer_list_lock: + for p in self.server.daemon.peers: + sio.write("%s\n" % p) + sio.write("My own jobs: %d, relative performance: %.2f\n" % + (self.server.daemon.jobs, self.server.daemon.relative_perf)) + # Low-priority TODO: Return more information. Ideas: + # - currently running anything, + # - time since last job, + # - time since last repository fetch + # - number of workpackets/testcases handled since startup + # - slowest test(s) + result = sio.getvalue() + sio.close() + return result + + +class LocalSocketServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): + def __init__(self, daemon): + SocketServer.TCPServer.__init__(self, ("localhost", constants.CLIENT_PORT), + LocalHandler) + self.daemon = daemon diff --git a/deps/v8/tools/testrunner/server/main.py b/deps/v8/tools/testrunner/server/main.py new file mode 100644 index 0000000000..1000713ca9 --- /dev/null +++ b/deps/v8/tools/testrunner/server/main.py @@ -0,0 +1,245 @@ +# 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. + + +import multiprocessing +import os +import shutil +import subprocess +import threading +import time + +from . import daemon +from . import local_handler +from . import presence_handler +from . import signatures +from . import status_handler +from . import work_handler +from ..network import perfdata + + +class Server(daemon.Daemon): + + def __init__(self, pidfile, root, stdin="/dev/null", + stdout="/dev/null", stderr="/dev/null"): + super(Server, self).__init__(pidfile, stdin, stdout, stderr) + self.root = root + self.local_handler = None + self.local_handler_thread = None + self.work_handler = None + self.work_handler_thread = None + self.status_handler = None + self.status_handler_thread = None + self.presence_daemon = None + self.presence_daemon_thread = None + self.peers = [] + self.jobs = multiprocessing.cpu_count() + self.peer_list_lock = threading.Lock() + self.perf_data_lock = None + self.presence_daemon_lock = None + self.datadir = os.path.join(self.root, "data") + pubkey_fingerprint_filename = os.path.join(self.datadir, "mypubkey") + with open(pubkey_fingerprint_filename) as f: + self.pubkey_fingerprint = f.read().strip() + self.relative_perf_filename = os.path.join(self.datadir, "myperf") + if os.path.exists(self.relative_perf_filename): + with open(self.relative_perf_filename) as f: + try: + self.relative_perf = float(f.read()) + except: + self.relative_perf = 1.0 + else: + self.relative_perf = 1.0 + + def run(self): + os.nice(20) + self.ip = presence_handler.GetOwnIP() + self.perf_data_manager = perfdata.PerfDataManager(self.datadir) + self.perf_data_lock = threading.Lock() + + self.local_handler = local_handler.LocalSocketServer(self) + self.local_handler_thread = threading.Thread( + target=self.local_handler.serve_forever) + self.local_handler_thread.start() + + self.work_handler = work_handler.WorkSocketServer(self) + self.work_handler_thread = threading.Thread( + target=self.work_handler.serve_forever) + self.work_handler_thread.start() + + self.status_handler = status_handler.StatusSocketServer(self) + self.status_handler_thread = threading.Thread( + target=self.status_handler.serve_forever) + self.status_handler_thread.start() + + self.presence_daemon = presence_handler.PresenceDaemon(self) + self.presence_daemon_thread = threading.Thread( + target=self.presence_daemon.serve_forever) + self.presence_daemon_thread.start() + + self.presence_daemon.FindPeers() + time.sleep(0.5) # Give those peers some time to reply. + + with self.peer_list_lock: + for p in self.peers: + if p.address == self.ip: continue + status_handler.RequestTrustedPubkeys(p, self) + + while True: + try: + self.PeriodicTasks() + time.sleep(60) + except Exception, e: + print("MAIN LOOP EXCEPTION: %s" % e) + self.Shutdown() + break + except KeyboardInterrupt: + self.Shutdown() + break + + def Shutdown(self): + with open(self.relative_perf_filename, "w") as f: + f.write("%s" % self.relative_perf) + self.presence_daemon.shutdown() + self.presence_daemon.server_close() + self.local_handler.shutdown() + self.local_handler.server_close() + self.work_handler.shutdown() + self.work_handler.server_close() + self.status_handler.shutdown() + self.status_handler.server_close() + + def PeriodicTasks(self): + # If we know peers we don't trust, see if someone else trusts them. + with self.peer_list_lock: + for p in self.peers: + if p.trusted: continue + if self.IsTrusted(p.pubkey): + p.trusted = True + status_handler.ITrustYouNow(p) + continue + for p2 in self.peers: + if not p2.trusted: continue + status_handler.TryTransitiveTrust(p2, p.pubkey, self) + # TODO: Ping for more peers waiting to be discovered. + # TODO: Update the checkout (if currently idle). + + def AddPeer(self, peer): + with self.peer_list_lock: + for p in self.peers: + if p.address == peer.address: + return + self.peers.append(peer) + if peer.trusted: + status_handler.ITrustYouNow(peer) + + def DeletePeer(self, peer_address): + with self.peer_list_lock: + for i in xrange(len(self.peers)): + if self.peers[i].address == peer_address: + del self.peers[i] + return + + def MarkPeerAsTrusting(self, peer_address): + with self.peer_list_lock: + for p in self.peers: + if p.address == peer_address: + p.trusting_me = True + break + + def UpdatePeerPerformance(self, peer_address, performance): + with self.peer_list_lock: + for p in self.peers: + if p.address == peer_address: + p.relative_performance = performance + + def CopyToTrusted(self, pubkey_filename): + with open(pubkey_filename, "r") as f: + lines = f.readlines() + fingerprint = lines[-1].strip() + target_filename = self._PubkeyFilename(fingerprint) + shutil.copy(pubkey_filename, target_filename) + with self.peer_list_lock: + for peer in self.peers: + if peer.address == self.ip: continue + if peer.pubkey == fingerprint: + status_handler.ITrustYouNow(peer) + else: + result = self.SignTrusted(fingerprint) + status_handler.NotifyNewTrusted(peer, result) + return fingerprint + + def _PubkeyFilename(self, pubkey_fingerprint): + return os.path.join(self.root, "trusted", "%s.pem" % pubkey_fingerprint) + + def IsTrusted(self, pubkey_fingerprint): + return os.path.exists(self._PubkeyFilename(pubkey_fingerprint)) + + def ListTrusted(self): + path = os.path.join(self.root, "trusted") + if not os.path.exists(path): return [] + return [ f[:-4] for f in os.listdir(path) if f.endswith(".pem") ] + + def SignTrusted(self, pubkey_fingerprint): + if not self.IsTrusted(pubkey_fingerprint): + return [] + filename = self._PubkeyFilename(pubkey_fingerprint) + result = signatures.ReadFileAndSignature(filename) # Format: [key, sig]. + return [pubkey_fingerprint, result[0], result[1], self.pubkey_fingerprint] + + def AcceptNewTrusted(self, data): + # The format of |data| matches the return value of |SignTrusted()|. + if not data: return + fingerprint = data[0] + pubkey = data[1] + signature = data[2] + signer = data[3] + if not self.IsTrusted(signer): + return + if self.IsTrusted(fingerprint): + return # Already trust this guy. + filename = self._PubkeyFilename(fingerprint) + signer_pubkeyfile = self._PubkeyFilename(signer) + if not signatures.VerifySignature(filename, pubkey, signature, + signer_pubkeyfile): + return + return # Nothing more to do. + + def AddPerfData(self, test_key, duration, arch, mode): + data_store = self.perf_data_manager.GetStore(arch, mode) + data_store.RawUpdatePerfData(str(test_key), duration) + + def CompareOwnPerf(self, test, arch, mode): + data_store = self.perf_data_manager.GetStore(arch, mode) + observed = data_store.FetchPerfData(test) + if not observed: return + own_perf_estimate = observed / test.duration + with self.perf_data_lock: + kLearnRateLimiter = 9999 + self.relative_perf *= kLearnRateLimiter + self.relative_perf += own_perf_estimate + self.relative_perf /= (kLearnRateLimiter + 1) diff --git a/deps/v8/tools/testrunner/server/presence_handler.py b/deps/v8/tools/testrunner/server/presence_handler.py new file mode 100644 index 0000000000..1dc2ef163a --- /dev/null +++ b/deps/v8/tools/testrunner/server/presence_handler.py @@ -0,0 +1,120 @@ +# 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. + + +import socket +import SocketServer +import threading +try: + import ujson as json +except: + import json + +from . import constants +from ..objects import peer + + +STARTUP_REQUEST = "V8 test peer starting up" +STARTUP_RESPONSE = "Let's rock some tests!" +EXIT_REQUEST = "V8 testing peer going down" + + +def GetOwnIP(): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + ip = s.getsockname()[0] + s.close() + return ip + + +class PresenceHandler(SocketServer.BaseRequestHandler): + + def handle(self): + data = json.loads(self.request[0].strip()) + + if data[0] == STARTUP_REQUEST: + jobs = data[1] + relative_perf = data[2] + pubkey_fingerprint = data[3] + trusted = self.server.daemon.IsTrusted(pubkey_fingerprint) + response = [STARTUP_RESPONSE, self.server.daemon.jobs, + self.server.daemon.relative_perf, + self.server.daemon.pubkey_fingerprint, trusted] + response = json.dumps(response) + self.server.SendTo(self.client_address[0], response) + p = peer.Peer(self.client_address[0], jobs, relative_perf, + pubkey_fingerprint) + p.trusted = trusted + self.server.daemon.AddPeer(p) + + elif data[0] == STARTUP_RESPONSE: + jobs = data[1] + perf = data[2] + pubkey_fingerprint = data[3] + p = peer.Peer(self.client_address[0], jobs, perf, pubkey_fingerprint) + p.trusted = self.server.daemon.IsTrusted(pubkey_fingerprint) + p.trusting_me = data[4] + self.server.daemon.AddPeer(p) + + elif data[0] == EXIT_REQUEST: + self.server.daemon.DeletePeer(self.client_address[0]) + if self.client_address[0] == self.server.daemon.ip: + self.server.shutdown_lock.release() + + +class PresenceDaemon(SocketServer.ThreadingMixIn, SocketServer.UDPServer): + def __init__(self, daemon): + self.daemon = daemon + address = (daemon.ip, constants.PRESENCE_PORT) + SocketServer.UDPServer.__init__(self, address, PresenceHandler) + self.shutdown_lock = threading.Lock() + + def shutdown(self): + self.shutdown_lock.acquire() + self.SendToAll(json.dumps([EXIT_REQUEST])) + self.shutdown_lock.acquire() + self.shutdown_lock.release() + SocketServer.UDPServer.shutdown(self) + + def SendTo(self, target, message): + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.sendto(message, (target, constants.PRESENCE_PORT)) + sock.close() + + def SendToAll(self, message): + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + ip = self.daemon.ip.split(".") + for i in range(1, 254): + ip[-1] = str(i) + sock.sendto(message, (".".join(ip), constants.PRESENCE_PORT)) + sock.close() + + def FindPeers(self): + request = [STARTUP_REQUEST, self.daemon.jobs, self.daemon.relative_perf, + self.daemon.pubkey_fingerprint] + request = json.dumps(request) + self.SendToAll(request) diff --git a/deps/v8/tools/testrunner/server/signatures.py b/deps/v8/tools/testrunner/server/signatures.py new file mode 100644 index 0000000000..9957a18a26 --- /dev/null +++ b/deps/v8/tools/testrunner/server/signatures.py @@ -0,0 +1,63 @@ +# 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. + + +import base64 +import os +import subprocess + + +def ReadFileAndSignature(filename): + with open(filename, "rb") as f: + file_contents = base64.b64encode(f.read()) + signature_file = filename + ".signature" + if (not os.path.exists(signature_file) or + os.path.getmtime(signature_file) < os.path.getmtime(filename)): + private_key = "~/.ssh/v8_dtest" + code = subprocess.call("openssl dgst -out %s -sign %s %s" % + (signature_file, private_key, filename), + shell=True) + if code != 0: return [None, code] + with open(signature_file) as f: + signature = base64.b64encode(f.read()) + return [file_contents, signature] + + +def VerifySignature(filename, file_contents, signature, pubkeyfile): + with open(filename, "wb") as f: + f.write(base64.b64decode(file_contents)) + signature_file = filename + ".foreign_signature" + with open(signature_file, "wb") as f: + f.write(base64.b64decode(signature)) + code = subprocess.call("openssl dgst -verify %s -signature %s %s" % + (pubkeyfile, signature_file, filename), + shell=True) + matched = (code == 0) + if not matched: + os.remove(signature_file) + os.remove(filename) + return matched diff --git a/deps/v8/tools/testrunner/server/status_handler.py b/deps/v8/tools/testrunner/server/status_handler.py new file mode 100644 index 0000000000..3f2271dc69 --- /dev/null +++ b/deps/v8/tools/testrunner/server/status_handler.py @@ -0,0 +1,112 @@ +# 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. + + +import socket +import SocketServer + +from . import compression +from . import constants + + +def _StatusQuery(peer, query): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + code = sock.connect_ex((peer.address, constants.STATUS_PORT)) + if code != 0: + # TODO(jkummerow): disconnect (after 3 failures?) + return + compression.Send(query, sock) + compression.Send(constants.END_OF_STREAM, sock) + rec = compression.Receiver(sock) + data = None + while not rec.IsDone(): + data = rec.Current() + assert data[0] == query[0] + data = data[1] + rec.Advance() + sock.close() + return data + + +def RequestTrustedPubkeys(peer, server): + pubkey_list = _StatusQuery(peer, [constants.LIST_TRUSTED_PUBKEYS]) + for pubkey in pubkey_list: + if server.IsTrusted(pubkey): continue + result = _StatusQuery(peer, [constants.GET_SIGNED_PUBKEY, pubkey]) + server.AcceptNewTrusted(result) + + +def NotifyNewTrusted(peer, data): + _StatusQuery(peer, [constants.NOTIFY_NEW_TRUSTED] + data) + + +def ITrustYouNow(peer): + _StatusQuery(peer, [constants.TRUST_YOU_NOW]) + + +def TryTransitiveTrust(peer, pubkey, server): + if _StatusQuery(peer, [constants.DO_YOU_TRUST, pubkey]): + result = _StatusQuery(peer, [constants.GET_SIGNED_PUBKEY, pubkey]) + server.AcceptNewTrusted(result) + + +class StatusHandler(SocketServer.BaseRequestHandler): + def handle(self): + rec = compression.Receiver(self.request) + while not rec.IsDone(): + data = rec.Current() + action = data[0] + + if action == constants.LIST_TRUSTED_PUBKEYS: + response = self.server.daemon.ListTrusted() + compression.Send([action, response], self.request) + + elif action == constants.GET_SIGNED_PUBKEY: + response = self.server.daemon.SignTrusted(data[1]) + compression.Send([action, response], self.request) + + elif action == constants.NOTIFY_NEW_TRUSTED: + self.server.daemon.AcceptNewTrusted(data[1:]) + pass # No response. + + elif action == constants.TRUST_YOU_NOW: + self.server.daemon.MarkPeerAsTrusting(self.client_address[0]) + pass # No response. + + elif action == constants.DO_YOU_TRUST: + response = self.server.daemon.IsTrusted(data[1]) + compression.Send([action, response], self.request) + + rec.Advance() + compression.Send(constants.END_OF_STREAM, self.request) + + +class StatusSocketServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): + def __init__(self, daemon): + address = (daemon.ip, constants.STATUS_PORT) + SocketServer.TCPServer.__init__(self, address, StatusHandler) + self.daemon = daemon diff --git a/deps/v8/tools/testrunner/server/work_handler.py b/deps/v8/tools/testrunner/server/work_handler.py new file mode 100644 index 0000000000..6bf7d43cf9 --- /dev/null +++ b/deps/v8/tools/testrunner/server/work_handler.py @@ -0,0 +1,150 @@ +# 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. + + +import os +import SocketServer +import stat +import subprocess +import threading + +from . import compression +from . import constants +from . import signatures +from ..network import endpoint +from ..objects import workpacket + + +class WorkHandler(SocketServer.BaseRequestHandler): + + def handle(self): + rec = compression.Receiver(self.request) + while not rec.IsDone(): + data = rec.Current() + with self.server.job_lock: + self._WorkOnWorkPacket(data) + rec.Advance() + + def _WorkOnWorkPacket(self, data): + server_root = self.server.daemon.root + v8_root = os.path.join(server_root, "v8") + os.chdir(v8_root) + packet = workpacket.WorkPacket.Unpack(data) + self.ctx = packet.context + self.ctx.shell_dir = os.path.join("out", + "%s.%s" % (self.ctx.arch, self.ctx.mode)) + if not os.path.isdir(self.ctx.shell_dir): + os.makedirs(self.ctx.shell_dir) + for binary in packet.binaries: + if not self._UnpackBinary(binary, packet.pubkey_fingerprint): + return + + if not self._CheckoutRevision(packet.base_revision): + return + + if not self._ApplyPatch(packet.patch): + return + + tests = packet.tests + endpoint.Execute(v8_root, self.ctx, tests, self.request, self.server.daemon) + self._SendResponse() + + def _SendResponse(self, error_message=None): + try: + if error_message: + compression.Send([[-1, error_message]], self.request) + compression.Send(constants.END_OF_STREAM, self.request) + return + except Exception, e: + pass # Peer is gone. There's nothing we can do. + # Clean up. + self._Call("git checkout -f") + self._Call("git clean -f -d") + self._Call("rm -rf %s" % self.ctx.shell_dir) + + def _UnpackBinary(self, binary, pubkey_fingerprint): + binary_name = binary["name"] + if binary_name == "libv8.so": + libdir = os.path.join(self.ctx.shell_dir, "lib.target") + if not os.path.exists(libdir): os.makedirs(libdir) + target = os.path.join(libdir, binary_name) + else: + target = os.path.join(self.ctx.shell_dir, binary_name) + pubkeyfile = "../trusted/%s.pem" % pubkey_fingerprint + if not signatures.VerifySignature(target, binary["blob"], + binary["sign"], pubkeyfile): + self._SendResponse("Signature verification failed") + return False + os.chmod(target, stat.S_IRWXU) + return True + + def _CheckoutRevision(self, base_svn_revision): + get_hash_cmd = ( + "git log -1 --format=%%H --remotes --grep='^git-svn-id:.*@%s'" % + base_svn_revision) + try: + base_revision = subprocess.check_output(get_hash_cmd, shell=True) + if not base_revision: raise ValueError + except: + self._Call("git fetch") + try: + base_revision = subprocess.check_output(get_hash_cmd, shell=True) + if not base_revision: raise ValueError + except: + self._SendResponse("Base revision not found.") + return False + code = self._Call("git checkout -f %s" % base_revision) + if code != 0: + self._SendResponse("Error trying to check out base revision.") + return False + code = self._Call("git clean -f -d") + if code != 0: + self._SendResponse("Failed to reset checkout") + return False + return True + + def _ApplyPatch(self, patch): + if not patch: return True # Just skip if the patch is empty. + patchfilename = "_dtest_incoming_patch.patch" + with open(patchfilename, "w") as f: + f.write(patch) + code = self._Call("git apply %s" % patchfilename) + if code != 0: + self._SendResponse("Error applying patch.") + return False + return True + + def _Call(self, cmd): + return subprocess.call(cmd, shell=True) + + +class WorkSocketServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): + def __init__(self, daemon): + address = (daemon.ip, constants.PEER_PORT) + SocketServer.TCPServer.__init__(self, address, WorkHandler) + self.job_lock = threading.Lock() + self.daemon = daemon diff --git a/deps/v8/tools/tickprocessor.js b/deps/v8/tools/tickprocessor.js index 4c4886d878..7530c6b37d 100644 --- a/deps/v8/tools/tickprocessor.js +++ b/deps/v8/tools/tickprocessor.js @@ -73,7 +73,7 @@ function parseState(s) { function SnapshotLogProcessor() { LogReader.call(this, { 'code-creation': { - parsers: [null, parseInt, parseInt, null, 'var-args'], + parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'], processor: this.processCodeCreation }, 'code-move': { parsers: [parseInt, parseInt], processor: this.processCodeMove }, @@ -107,7 +107,7 @@ inherits(SnapshotLogProcessor, LogReader); SnapshotLogProcessor.prototype.processCodeCreation = function( - type, start, size, name, maybe_func) { + type, kind, start, size, name, maybe_func) { if (maybe_func.length) { var funcAddr = parseInt(maybe_func[0]); var state = parseState(maybe_func[1]); @@ -156,7 +156,7 @@ function TickProcessor( 'shared-library': { parsers: [null, parseInt, parseInt], processor: this.processSharedLibrary }, 'code-creation': { - parsers: [null, parseInt, parseInt, null, 'var-args'], + parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'], processor: this.processCodeCreation }, 'code-move': { parsers: [parseInt, parseInt], processor: this.processCodeMove }, @@ -167,7 +167,7 @@ function TickProcessor( 'snapshot-pos': { parsers: [parseInt, parseInt], processor: this.processSnapshotPosition }, 'tick': { - parsers: [parseInt, parseInt, parseInt, + parsers: [parseInt, parseInt, parseInt, parseInt, parseInt, parseInt, 'var-args'], processor: this.processTick }, 'heap-sample-begin': { parsers: [null, null, parseInt], @@ -231,8 +231,9 @@ TickProcessor.VmStates = { JS: 0, GC: 1, COMPILER: 2, - OTHER: 3, - EXTERNAL: 4 + PARALLEL_COMPILER: 3, + OTHER: 4, + EXTERNAL: 5 }; @@ -308,7 +309,7 @@ TickProcessor.prototype.processSharedLibrary = function( TickProcessor.prototype.processCodeCreation = function( - type, start, size, name, maybe_func) { + type, kind, start, size, name, maybe_func) { name = this.deserializedEntriesNames_[start] || name; if (maybe_func.length) { var funcAddr = parseInt(maybe_func[0]); @@ -349,6 +350,7 @@ TickProcessor.prototype.includeTick = function(vmState) { TickProcessor.prototype.processTick = function(pc, sp, + ns_since_start, is_external_callback, tos_or_external_callback, vmState, |