deps: upgrade v8 to 3.18.0
authorBen Noordhuis <info@bnoordhuis.nl>
Wed, 17 Apr 2013 14:10:37 +0000 (16:10 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Wed, 17 Apr 2013 14:10:37 +0000 (16:10 +0200)
288 files changed:
deps/v8/ChangeLog
deps/v8/Makefile
deps/v8/Makefile.nacl [new file with mode: 0644]
deps/v8/PRESUBMIT.py
deps/v8/build/common.gypi
deps/v8/build/standalone.gypi
deps/v8/include/v8-preparser.h
deps/v8/include/v8-profiler.h
deps/v8/include/v8.h
deps/v8/preparser/preparser-process.cc
deps/v8/preparser/preparser.gyp
deps/v8/src/accessors.cc
deps/v8/src/accessors.h
deps/v8/src/allocation.cc
deps/v8/src/api.cc
deps/v8/src/api.h
deps/v8/src/arguments.h
deps/v8/src/arm/assembler-arm-inl.h
deps/v8/src/arm/assembler-arm.cc
deps/v8/src/arm/assembler-arm.h
deps/v8/src/arm/code-stubs-arm.cc
deps/v8/src/arm/code-stubs-arm.h
deps/v8/src/arm/codegen-arm.cc
deps/v8/src/arm/constants-arm.cc
deps/v8/src/arm/constants-arm.h
deps/v8/src/arm/deoptimizer-arm.cc
deps/v8/src/arm/disasm-arm.cc
deps/v8/src/arm/frames-arm.h
deps/v8/src/arm/full-codegen-arm.cc
deps/v8/src/arm/lithium-arm.cc
deps/v8/src/arm/lithium-arm.h
deps/v8/src/arm/lithium-codegen-arm.cc
deps/v8/src/arm/lithium-codegen-arm.h
deps/v8/src/arm/lithium-gap-resolver-arm.cc
deps/v8/src/arm/macro-assembler-arm.cc
deps/v8/src/arm/macro-assembler-arm.h
deps/v8/src/arm/simulator-arm.cc
deps/v8/src/arm/simulator-arm.h
deps/v8/src/arm/stub-cache-arm.cc
deps/v8/src/array.js
deps/v8/src/assembler.cc
deps/v8/src/assembler.h
deps/v8/src/ast.cc
deps/v8/src/ast.h
deps/v8/src/atomicops_internals_x86_gcc.cc
deps/v8/src/atomicops_internals_x86_gcc.h
deps/v8/src/bignum.cc
deps/v8/src/bootstrapper.cc
deps/v8/src/builtins-decls.h [new file with mode: 0644]
deps/v8/src/builtins.cc
deps/v8/src/builtins.h
deps/v8/src/code-stubs-hydrogen.cc
deps/v8/src/code-stubs.cc
deps/v8/src/code-stubs.h
deps/v8/src/collection.js
deps/v8/src/compiler.cc
deps/v8/src/contexts.h
deps/v8/src/conversions-inl.h
deps/v8/src/cpu-profiler.cc
deps/v8/src/cpu-profiler.h
deps/v8/src/d8.cc
deps/v8/src/d8.gyp
deps/v8/src/date.js
deps/v8/src/debug.cc
deps/v8/src/deoptimizer.cc
deps/v8/src/deoptimizer.h
deps/v8/src/disassembler.cc
deps/v8/src/elements.cc
deps/v8/src/execution.cc
deps/v8/src/execution.h
deps/v8/src/factory.cc
deps/v8/src/flag-definitions.h
deps/v8/src/flags.cc
deps/v8/src/frames.h
deps/v8/src/full-codegen.cc
deps/v8/src/full-codegen.h
deps/v8/src/gdb-jit.cc
deps/v8/src/generator.js [new file with mode: 0644]
deps/v8/src/global-handles.h
deps/v8/src/globals.h
deps/v8/src/handles-inl.h
deps/v8/src/handles.cc
deps/v8/src/handles.h
deps/v8/src/heap-inl.h
deps/v8/src/heap-snapshot-generator.cc
deps/v8/src/heap.cc
deps/v8/src/heap.h
deps/v8/src/hydrogen-instructions.cc
deps/v8/src/hydrogen-instructions.h
deps/v8/src/hydrogen.cc
deps/v8/src/hydrogen.h
deps/v8/src/ia32/assembler-ia32.cc
deps/v8/src/ia32/assembler-ia32.h
deps/v8/src/ia32/builtins-ia32.cc
deps/v8/src/ia32/code-stubs-ia32.cc
deps/v8/src/ia32/codegen-ia32.cc
deps/v8/src/ia32/cpu-ia32.cc
deps/v8/src/ia32/deoptimizer-ia32.cc
deps/v8/src/ia32/frames-ia32.h
deps/v8/src/ia32/full-codegen-ia32.cc
deps/v8/src/ia32/lithium-codegen-ia32.cc
deps/v8/src/ia32/lithium-codegen-ia32.h
deps/v8/src/ia32/lithium-gap-resolver-ia32.cc
deps/v8/src/ia32/lithium-ia32.cc
deps/v8/src/ia32/lithium-ia32.h
deps/v8/src/ia32/macro-assembler-ia32.cc
deps/v8/src/ia32/macro-assembler-ia32.h
deps/v8/src/ia32/stub-cache-ia32.cc
deps/v8/src/ic.cc
deps/v8/src/isolate.cc
deps/v8/src/isolate.h
deps/v8/src/json-parser.h
deps/v8/src/json-stringifier.h
deps/v8/src/json.js
deps/v8/src/jsregexp.cc
deps/v8/src/list-inl.h
deps/v8/src/lithium-allocator.cc
deps/v8/src/lithium-allocator.h
deps/v8/src/liveedit.cc
deps/v8/src/log-utils.cc
deps/v8/src/log.cc
deps/v8/src/log.h
deps/v8/src/macro-assembler.h
deps/v8/src/mark-compact.cc
deps/v8/src/math.js
deps/v8/src/messages.js
deps/v8/src/mips/assembler-mips-inl.h
deps/v8/src/mips/assembler-mips.cc
deps/v8/src/mips/assembler-mips.h
deps/v8/src/mips/code-stubs-mips.cc
deps/v8/src/mips/code-stubs-mips.h
deps/v8/src/mips/codegen-mips.cc
deps/v8/src/mips/constants-mips.h
deps/v8/src/mips/deoptimizer-mips.cc
deps/v8/src/mips/disasm-mips.cc
deps/v8/src/mips/frames-mips.h
deps/v8/src/mips/full-codegen-mips.cc
deps/v8/src/mips/lithium-codegen-mips.cc
deps/v8/src/mips/lithium-codegen-mips.h
deps/v8/src/mips/lithium-gap-resolver-mips.cc
deps/v8/src/mips/lithium-mips.cc
deps/v8/src/mips/lithium-mips.h
deps/v8/src/mips/macro-assembler-mips.cc
deps/v8/src/mips/simulator-mips.cc
deps/v8/src/mips/simulator-mips.h
deps/v8/src/mips/stub-cache-mips.cc
deps/v8/src/objects-debug.cc
deps/v8/src/objects-inl.h
deps/v8/src/objects-printer.cc
deps/v8/src/objects-visiting.cc
deps/v8/src/objects.cc
deps/v8/src/objects.h
deps/v8/src/parser.cc
deps/v8/src/parser.h
deps/v8/src/platform-cygwin.cc
deps/v8/src/platform-freebsd.cc
deps/v8/src/platform-linux.cc
deps/v8/src/platform-macos.cc
deps/v8/src/platform-nullos.cc
deps/v8/src/platform-openbsd.cc
deps/v8/src/platform-posix.cc
deps/v8/src/platform-solaris.cc
deps/v8/src/platform-win32.cc
deps/v8/src/platform.h
deps/v8/src/preparse-data.cc
deps/v8/src/preparser-api.cc
deps/v8/src/preparser.cc
deps/v8/src/preparser.h
deps/v8/src/prettyprinter.cc
deps/v8/src/profile-generator.cc
deps/v8/src/proxy.js
deps/v8/src/regexp-macro-assembler-irregexp.cc
deps/v8/src/regexp-stack.cc
deps/v8/src/regexp.js
deps/v8/src/runtime-profiler.cc
deps/v8/src/runtime-profiler.h
deps/v8/src/runtime.cc
deps/v8/src/runtime.h
deps/v8/src/sampler.cc [new file with mode: 0644]
deps/v8/src/sampler.h [new file with mode: 0644]
deps/v8/src/scanner.h
deps/v8/src/scopes.cc
deps/v8/src/scopes.h
deps/v8/src/serialize.h
deps/v8/src/spaces.cc
deps/v8/src/spaces.h
deps/v8/src/string-stream.cc
deps/v8/src/string.js
deps/v8/src/stub-cache.cc
deps/v8/src/stub-cache.h
deps/v8/src/symbol.js
deps/v8/src/third_party/vtune/ittnotify_config.h [new file with mode: 0644]
deps/v8/src/third_party/vtune/ittnotify_types.h [new file with mode: 0644]
deps/v8/src/third_party/vtune/jitprofiling.cc [new file with mode: 0644]
deps/v8/src/third_party/vtune/jitprofiling.h [new file with mode: 0644]
deps/v8/src/third_party/vtune/v8-vtune.h [new file with mode: 0644]
deps/v8/src/third_party/vtune/v8vtune.gyp [new file with mode: 0644]
deps/v8/src/third_party/vtune/vtune-jit.cc [new file with mode: 0644]
deps/v8/src/third_party/vtune/vtune-jit.h [new file with mode: 0644]
deps/v8/src/typedarray.js
deps/v8/src/unicode-inl.h
deps/v8/src/uri.js
deps/v8/src/utils.cc
deps/v8/src/utils.h
deps/v8/src/v8.cc
deps/v8/src/v8conversions.h
deps/v8/src/v8globals.h
deps/v8/src/v8natives.js
deps/v8/src/v8utils.cc
deps/v8/src/v8utils.h
deps/v8/src/version.cc
deps/v8/src/x64/assembler-x64.cc
deps/v8/src/x64/assembler-x64.h
deps/v8/src/x64/builtins-x64.cc
deps/v8/src/x64/code-stubs-x64.cc
deps/v8/src/x64/deoptimizer-x64.cc
deps/v8/src/x64/frames-x64.h
deps/v8/src/x64/full-codegen-x64.cc
deps/v8/src/x64/lithium-codegen-x64.cc
deps/v8/src/x64/lithium-codegen-x64.h
deps/v8/src/x64/lithium-x64.cc
deps/v8/src/x64/lithium-x64.h
deps/v8/src/x64/macro-assembler-x64.cc
deps/v8/src/x64/stub-cache-x64.cc
deps/v8/test/cctest/cctest.cc
deps/v8/test/cctest/cctest.gyp
deps/v8/test/cctest/cctest.h
deps/v8/test/cctest/cctest.status
deps/v8/test/cctest/test-api.cc
deps/v8/test/cctest/test-assembler-arm.cc
deps/v8/test/cctest/test-assembler-ia32.cc
deps/v8/test/cctest/test-assembler-mips.cc
deps/v8/test/cctest/test-assembler-x64.cc
deps/v8/test/cctest/test-compiler.cc
deps/v8/test/cctest/test-cpu-profiler.cc
deps/v8/test/cctest/test-decls.cc
deps/v8/test/cctest/test-disasm-arm.cc
deps/v8/test/cctest/test-disasm-ia32.cc
deps/v8/test/cctest/test-disasm-mips.cc
deps/v8/test/cctest/test-disasm-x64.cc
deps/v8/test/cctest/test-func-name-inference.cc
deps/v8/test/cctest/test-global-handles.cc [new file with mode: 0644]
deps/v8/test/cctest/test-heap-profiler.cc
deps/v8/test/cctest/test-heap.cc
deps/v8/test/cctest/test-log-stack-tracer.cc
deps/v8/test/cctest/test-log.cc
deps/v8/test/cctest/test-mark-compact.cc
deps/v8/test/cctest/test-parsing.cc
deps/v8/test/cctest/test-platform-win32.cc
deps/v8/test/cctest/test-profile-generator.cc
deps/v8/test/cctest/test-strings.cc
deps/v8/test/cctest/test-symbols.cc
deps/v8/test/cctest/test-utils.cc
deps/v8/test/cctest/testcfg.py
deps/v8/test/message/testcfg.py
deps/v8/test/mjsunit/allocation-site-info.js
deps/v8/test/mjsunit/bugs/bug-2615.js [new file with mode: 0644]
deps/v8/test/mjsunit/builtins.js
deps/v8/test/mjsunit/external-array-no-sse2.js [new file with mode: 0644]
deps/v8/test/mjsunit/harmony/collections.js
deps/v8/test/mjsunit/harmony/generators-objects.js [new file with mode: 0644]
deps/v8/test/mjsunit/harmony/generators-parsing.js
deps/v8/test/mjsunit/harmony/generators-runtime.js [new file with mode: 0644]
deps/v8/test/mjsunit/harmony/symbols.js
deps/v8/test/mjsunit/harmony/typedarrays.js
deps/v8/test/mjsunit/mjsunit.status
deps/v8/test/mjsunit/object-define-property.js
deps/v8/test/mjsunit/pixel-array-rounding.js
deps/v8/test/mjsunit/proto-poison.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/readonly5.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-2273.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-2595.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-2606.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-2612.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-2618.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-2624.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-581.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-crbug-229923.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-json-stringify-gc.js
deps/v8/tools/gyp/v8.gyp
deps/v8/tools/mingw-generate-makefiles.sh [new file with mode: 0755]
deps/v8/tools/nacl-run.py [new file with mode: 0755]
deps/v8/tools/presubmit.py
deps/v8/tools/run-tests.py
deps/v8/tools/testrunner/local/junit_output.py [new file with mode: 0644]
deps/v8/tools/testrunner/local/progress.py
deps/v8/tools/testrunner/local/statusfile.py
deps/v8/tools/tickprocessor.js

index 5bd017f..70aa73a 100644 (file)
@@ -1,3 +1,22 @@
+2013-04-17: Version 3.18.0
+
+        Enabled pretenuring of fast literals in high promotion mode.
+
+        Removed preparser library; link preparser executable against full V8.
+
+        Fixed set-up of intrinsic's 'constructor' properties.
+        (Chromium issue 229445)
+
+        ES6 symbols: extended V8 API to support symbols (issue 2158).
+
+        Removed ARM support for VFP2.
+
+        Made __proto__ a real JavaScript accessor property.
+        (issue 1949 and issue 2606)
+
+        Performance and stability improvements on all platforms.
+
+
 2013-04-04: Version 3.17.16
 
         Stack trace API: poison stack frames below the first strict mode frame.
index 8e550d0..a46b333 100644 (file)
@@ -36,6 +36,7 @@ TESTFLAGS ?=
 ANDROID_NDK_ROOT ?=
 ANDROID_TOOLCHAIN ?=
 ANDROID_V8 ?= /data/local/v8
+NACL_SDK_ROOT ?=
 
 # Special build flags. Use them like this: "make library=shared"
 
@@ -83,22 +84,18 @@ endif
 ifeq ($(gdbjit), on)
   GYPFLAGS += -Dv8_enable_gdbjit=1
 endif
-# vfp2=off
-ifeq ($(vfp2), off)
-  GYPFLAGS += -Dv8_can_use_vfp2_instructions=false
-else
-  GYPFLAGS += -Dv8_can_use_vfp2_instructions=true -Darm_fpu=vfpv2
-endif
-# vfp3=off
-ifeq ($(vfp3), off)
-  GYPFLAGS += -Dv8_can_use_vfp3_instructions=false
-else
-  GYPFLAGS += -Dv8_can_use_vfp3_instructions=true -Darm_fpu=vfpv3
+# vtunejit=on
+ifeq ($(vtunejit), on)
+  GYPFLAGS += -Dv8_enable_vtunejit=1
 endif
 # debuggersupport=off
 ifeq ($(debuggersupport), off)
   GYPFLAGS += -Dv8_enable_debugger_support=0
 endif
+# unalignedaccess=on
+ifeq ($(unalignedaccess), on)
+  GYPFLAGS += -Dv8_can_use_unaligned_accesses=true
+endif
 # soname_version=1.2.3
 ifdef soname_version
   GYPFLAGS += -Dsoname_version=$(soname_version)
@@ -119,13 +116,66 @@ endif
 ifeq ($(regexp), interpreted)
   GYPFLAGS += -Dv8_interpreted_regexp=1
 endif
-# hardfp=on
-ifeq ($(hardfp), on)
-  GYPFLAGS += -Dv8_use_arm_eabi_hardfloat=true
-endif
-# armv7=false
+# arm specific flags.
+# armv7=false/true
 ifeq ($(armv7), false)
   GYPFLAGS += -Darmv7=0
+else
+ifeq ($(armv7), true)
+  GYPFLAGS += -Darmv7=1
+endif
+endif
+# vfp2=off. Deprecated, use armfpu=
+# vfp3=off. Deprecated, use armfpu=
+ifeq ($(vfp3), off)
+  GYPFLAGS += -Darm_fpu=vfp
+endif
+# hardfp=on/off. Deprecated, use armfloatabi
+ifeq ($(hardfp),on)
+  GYPFLAGS += -Darm_float_abi=hard
+else
+ifeq ($(hardfp),off)
+  GYPFLAGS += -Darm_float_abi=softfp
+endif
+endif
+# armneon=on/off
+ifeq ($(armneon), on)
+  GYPFLAGS += -Darm_neon=1
+endif
+# fpu: armfpu=xxx
+# xxx: vfp, vfpv3-d16, vfpv3, neon.
+ifeq ($(armfpu),)
+ifneq ($(vfp3), off)
+  GYPFLAGS += -Darm_fpu=default
+endif
+else
+  GYPFLAGS += -Darm_fpu=$(armfpu)
+endif
+# float abi: armfloatabi=softfp/hard
+ifeq ($(armfloatabi),)
+ifeq ($(hardfp),)
+  GYPFLAGS += -Darm_float_abi=default
+endif
+else
+  GYPFLAGS += -Darm_float_abi=$(armfloatabi)
+endif
+# armthumb=on/off
+ifeq ($(armthumb), off)
+  GYPFLAGS += -Darm_thumb=0
+else
+ifeq ($(armthumb), on)
+  GYPFLAGS += -Darm_thumb=1
+endif
+endif
+# armtest=on
+# With this flag set, by default v8 will only use features implied
+# by the compiler (no probe). This is done by modifying the default
+# values of enable_armv7, enable_vfp2, enable_vfp3 and enable_32dregs.
+# Modifying these flags when launching v8 will enable the probing for
+# the specified values.
+# When using the simulator, this flag is implied.
+ifeq ($(armtest), on)
+  GYPFLAGS += -Darm_test=on
 endif
 
 # ----------------- available targets: --------------------
@@ -136,6 +186,7 @@ endif
 # - "native": current host's architecture, release mode
 # - any of the above with .check appended, e.g. "ia32.release.check"
 # - "android": cross-compile for Android/ARM
+# - "nacl" : cross-compile for Native Client (ia32 and x64)
 # - default (no target specified): build all DEFAULT_ARCHES and MODES
 # - "check": build all targets and run all tests
 # - "<arch>.clean" for any <arch> in ARCHES
@@ -149,19 +200,27 @@ ARCHES = ia32 x64 arm mipsel
 DEFAULT_ARCHES = ia32 x64 arm
 MODES = release debug
 ANDROID_ARCHES = android_ia32 android_arm android_mipsel
+NACL_ARCHES = nacl_ia32 nacl_x64
 
 # List of files that trigger Makefile regeneration:
 GYPFILES = build/all.gyp build/common.gypi build/standalone.gypi \
            preparser/preparser.gyp samples/samples.gyp src/d8.gyp \
            test/cctest/cctest.gyp tools/gyp/v8.gyp
 
+# If vtunejit=on, the v8vtune.gyp will be appended.
+ifeq ($(vtunejit), on)
+  GYPFILES += src/third_party/vtune/v8vtune.gyp
+endif
 # Generates all combinations of ARCHES and MODES, e.g. "ia32.release".
 BUILDS = $(foreach mode,$(MODES),$(addsuffix .$(mode),$(ARCHES)))
 ANDROID_BUILDS = $(foreach mode,$(MODES), \
                    $(addsuffix .$(mode),$(ANDROID_ARCHES)))
+NACL_BUILDS = $(foreach mode,$(MODES), \
+                   $(addsuffix .$(mode),$(NACL_ARCHES)))
 # Generates corresponding test targets, e.g. "ia32.release.check".
 CHECKS = $(addsuffix .check,$(BUILDS))
 ANDROID_CHECKS = $(addsuffix .check,$(ANDROID_BUILDS))
+NACL_CHECKS = $(addsuffix .check,$(NACL_BUILDS))
 # File where previously used GYPFLAGS are stored.
 ENVFILE = $(OUTDIR)/environment
 
@@ -169,7 +228,9 @@ ENVFILE = $(OUTDIR)/environment
         $(ARCHES) $(MODES) $(BUILDS) $(CHECKS) $(addsuffix .clean,$(ARCHES)) \
         $(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES)) \
         $(ANDROID_ARCHES) $(ANDROID_BUILDS) $(ANDROID_CHECKS) \
-        must-set-ANDROID_NDK_ROOT_OR_TOOLCHAIN
+        must-set-ANDROID_NDK_ROOT_OR_TOOLCHAIN \
+        $(NACL_ARCHES) $(NACL_BUILDS) $(NACL_CHECKS) \
+        must-set-NACL_SDK_ROOT
 
 # Target definitions. "all" is the default.
 all: $(MODES)
@@ -213,6 +274,16 @@ $(ANDROID_BUILDS): $(GYPFILES) $(ENVFILE) build/android.gypi \
                OUTDIR="$(OUTDIR)" \
                GYPFLAGS="$(GYPFLAGS)"
 
+$(NACL_ARCHES): $(addprefix $$@.,$(MODES))
+
+$(NACL_BUILDS): $(GYPFILES) $(ENVFILE) \
+                  Makefile.nacl must-set-NACL_SDK_ROOT
+       @$(MAKE) -f Makefile.nacl $@ \
+               ARCH="$(basename $@)" \
+               MODE="$(subst .,,$(suffix $@))" \
+               OUTDIR="$(OUTDIR)" \
+               GYPFLAGS="$(GYPFLAGS)"
+
 # Test targets.
 check: all
        @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
@@ -244,12 +315,21 @@ $(addsuffix .check, $(ANDROID_BUILDS)): $$(basename $$@).sync
 $(addsuffix .check, $(ANDROID_ARCHES)): \
                 $(addprefix $$(basename $$@).,$(MODES)).check
 
+$(addsuffix .check, $(NACL_BUILDS)): $$(basename $$@)
+       @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+            --arch-and-mode=$(basename $@) \
+            --timeout=600 --nopresubmit \
+            --command-prefix="tools/nacl-run.py"
+
+$(addsuffix .check, $(NACL_ARCHES)): \
+                $(addprefix $$(basename $$@).,$(MODES)).check
+
 native.check: native
        @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR)/native \
            --arch-and-mode=. $(TESTFLAGS)
 
 # Clean targets. You can clean each architecture individually, or everything.
-$(addsuffix .clean, $(ARCHES) $(ANDROID_ARCHES)):
+$(addsuffix .clean, $(ARCHES) $(ANDROID_ARCHES) $(NACL_ARCHES)):
        rm -f $(OUTDIR)/Makefile.$(basename $@)
        rm -rf $(OUTDIR)/$(basename $@).release
        rm -rf $(OUTDIR)/$(basename $@).debug
@@ -260,7 +340,7 @@ native.clean:
        rm -rf $(OUTDIR)/native
        find $(OUTDIR) -regex '.*\(host\|target\).native\.mk' -delete
 
-clean: $(addsuffix .clean, $(ARCHES) $(ANDROID_ARCHES)) native.clean
+clean: $(addsuffix .clean, $(ARCHES) $(ANDROID_ARCHES) $(NACL_ARCHES)) native.clean
 
 # GYP file generation targets.
 OUT_MAKEFILES = $(addprefix $(OUTDIR)/Makefile.,$(ARCHES))
@@ -283,6 +363,18 @@ ifndef ANDROID_TOOLCHAIN
 endif
 endif
 
+# Note that NACL_SDK_ROOT must be set to point to an appropriate
+# Native Client SDK before using this makefile. You can download
+# an SDK here:
+#   https://developers.google.com/native-client/sdk/download
+# The path indicated by NACL_SDK_ROOT will typically end with
+# a folder for a pepper version such as "pepper_25" that should
+# have "tools" and "toolchain" subdirectories.
+must-set-NACL_SDK_ROOT:
+ifndef NACL_SDK_ROOT
+         $(error NACL_SDK_ROOT must be set)
+endif
+
 # Replaces the old with the new environment file if they're different, which
 # will trigger GYP to regenerate Makefiles.
 $(ENVFILE): $(ENVFILE).new
diff --git a/deps/v8/Makefile.nacl b/deps/v8/Makefile.nacl
new file mode 100644 (file)
index 0000000..e8fc3d2
--- /dev/null
@@ -0,0 +1,96 @@
+#
+# Copyright 2013 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.
+
+# Those definitions should be consistent with the main Makefile
+NACL_ARCHES = nacl_ia32 nacl_x64
+MODES = release debug
+
+# Generates all combinations of NACL ARCHES and MODES,
+# e.g. "nacl_ia32.release" or "nacl_x64.release"
+NACL_BUILDS = $(foreach mode,$(MODES), \
+                   $(addsuffix .$(mode),$(NACL_ARCHES)))
+
+HOST_OS = $(shell uname -s | sed -e 's/Linux/linux/;s/Darwin/mac/')
+ifeq ($(HOST_OS), linux)
+  TOOLCHAIN_DIR = linux_x86_glibc
+else
+  ifeq ($(HOST_OS), mac)
+    TOOLCHAIN_DIR = mac_x86_glibc
+  else
+    $(error Host platform "${HOST_OS}" is not supported)
+  endif
+endif
+
+TOOLCHAIN_PATH = ${NACL_SDK_ROOT}/toolchain
+NACL_TOOLCHAIN ?= ${TOOLCHAIN_PATH}/${TOOLCHAIN_DIR}
+
+ifeq ($(ARCH), nacl_ia32)
+  GYPENV = nacl_target_arch=nacl_ia32 v8_target_arch=arm v8_host_arch=ia32
+  TOOLCHAIN_ARCH = x86-4.4
+  NACL_CC = "$(NACL_TOOLCHAIN)/bin/i686-nacl-gcc"
+  NACL_CXX = "$(NACL_TOOLCHAIN)/bin/i686-nacl-g++"
+  NACL_LINK = "$(NACL_TOOLCHAIN)/bin/i686-nacl-g++"
+else
+  ifeq ($(ARCH), nacl_x64)
+    GYPENV = nacl_target_arch=nacl_x64 v8_target_arch=arm v8_host_arch=ia32
+    TOOLCHAIN_ARCH = x86-4.4
+    NACL_CC = "$(NACL_TOOLCHAIN)/bin/x86_64-nacl-gcc"
+    NACL_CXX = "$(NACL_TOOLCHAIN)/bin/x86_64-nacl-g++"
+    NACL_LINK = "$(NACL_TOOLCHAIN)/bin/x86_64-nacl-g++"
+  else
+    $(error Target architecture "${ARCH}" is not supported)
+  endif
+endif
+
+ifeq ($(wildcard $(NACL_TOOLCHAIN)),)
+  $(error Cannot find Native Client toolchain in "${NACL_TOOLCHAIN}")
+endif
+
+# For mksnapshot host generation.
+GYPENV += host_os=${HOST_OS}
+
+NACL_MAKEFILES = $(addprefix $(OUTDIR)/Makefile.,$(NACL_ARCHES))
+.SECONDEXPANSION:
+# For some reason the $$(basename $$@) expansion didn't work here...
+$(NACL_BUILDS): $(NACL_MAKEFILES)
+       @$(MAKE) -C "$(OUTDIR)" -f Makefile.$(basename $@) \
+                   CXX=${NACL_CXX} \
+                   LINK=${NACL_LINK} \
+                   BUILDTYPE=$(shell echo $(subst .,,$(suffix $@)) | \
+                               python -c "print raw_input().capitalize()") \
+                   builddir="$(shell pwd)/$(OUTDIR)/$@"
+
+# NACL GYP file generation targets.
+$(NACL_MAKEFILES):
+       @GYP_GENERATORS=make \
+       GYP_DEFINES="${GYPENV}" \
+       CC=${NACL_CC} \
+       CXX=${NACL_CXX} \
+       build/gyp/gyp --generator-output="${OUTDIR}" build/all.gyp \
+                     -Ibuild/standalone.gypi --depth=. \
+                     -S.$(subst .,,$(suffix $@)) $(GYPFLAGS)
index 0077be9..7d66203 100644 (file)
@@ -53,6 +53,7 @@ def _CommonChecks(input_api, output_api):
   results = []
   results.extend(input_api.canned_checks.CheckOwners(
       input_api, output_api, source_file_filter=None))
+  results.extend(_V8PresubmitChecks(input_api, output_api))
   return results
 
 
@@ -67,5 +68,4 @@ def CheckChangeOnCommit(input_api, output_api):
   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
index 38ed4f4..0b1f397 100644 (file)
     'CXX%': '${CXX:-$(which g++)}',  # Used to assemble a shell command.
     'v8_compress_startup_data%': 'off',
     'v8_target_arch%': '<(target_arch)',
+    # Native Client builds currently use the V8 ARM JIT and
+    # arm/simulator-arm.cc to defer the significant effort required
+    # for NaCl JIT support. The nacl_target_arch variable provides
+    # the 'true' target arch for places in this file that need it.
+    # TODO(bradchen): get rid of nacl_target_arch when someday
+    # NaCl V8 builds stop using the ARM simulator
+    'nacl_target_arch%': 'none',     # must be set externally
 
     # Setting 'v8_can_use_unaligned_accesses' to 'true' will allow the code
     # generated by V8 to do unaligned memory access, and setting it to 'false'
     # access is allowed for all CPUs.
     'v8_can_use_unaligned_accesses%': 'default',
 
-    # 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
-    # probing when running on the target.
-    'v8_can_use_vfp2_instructions%': 'false',
-    'v8_can_use_vfp3_instructions%': 'false',
-
     # Setting 'v8_can_use_vfp32dregs' to 'true' will cause V8 to use the VFP
     # registers d16-d31 in the generated code, both in the snapshot and for the
     # ARM target. Leaving the default value of 'false' will avoid the use of
     # these registers in the snapshot and use CPU feature probing when running
     # on the target.
     'v8_can_use_vfp32dregs%': 'false',
+    'arm_test%': 'off',
 
     # Similar to vfp but on MIPS.
     'v8_can_use_fpu_instructions%': 'true',
 
-    # Setting v8_use_arm_eabi_hardfloat to true will turn on V8 support for ARM
-    # EABI calling convention where double arguments are passed in VFP
-    # registers. Note that the GCC flag '-mfloat-abi=hard' should be used as
-    # well when compiling for the ARM target.
-    'v8_use_arm_eabi_hardfloat%': 'false',
-
     # Similar to the ARM hard float ABI but on MIPS.
     'v8_use_mips_abi_hardfloat%': 'true',
 
         'defines': [
           'V8_TARGET_ARCH_ARM',
         ],
+        'variables': {
+          'armsimulator': '<!($(echo <(CXX)) -v 2>&1 | grep -q "^Target: arm" && echo "no" || echo "yes")',
+        },
         'conditions': [
-          ['armv7==1', {
-            'defines': [
-              'CAN_USE_ARMV7_INSTRUCTIONS=1',
-            ],
-          }],
           [ 'v8_can_use_unaligned_accesses=="true"', {
             'defines': [
               'CAN_USE_UNALIGNED_ACCESSES=1',
             ],
-          }],
-          [ 'v8_can_use_unaligned_accesses=="false"', {
+          }, {
             'defines': [
               'CAN_USE_UNALIGNED_ACCESSES=0',
             ],
           }],
-          # 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',
-            ],
-          }],
-          # 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',
-            ],
-          }],
-          [ 'v8_use_arm_eabi_hardfloat=="true"', {
-            'defines': [
-              'USE_EABI_HARDFLOAT=1',
-              'CAN_USE_VFP2_INSTRUCTIONS',
-            ],
+          ['armsimulator=="no"', {
             'target_conditions': [
               ['_toolset=="target"', {
-                'cflags': ['-mfloat-abi=hard',],
+                'conditions': [
+                  [ 'armv7==1', {
+                    'cflags': ['-march=armv7-a',],
+                  }],
+                  [ 'armv7==1 or armv7=="default"', {
+                    'conditions': [
+                      [ 'arm_neon==1', {
+                        'cflags': ['-mfpu=neon',],
+                      },
+                      {
+                        'conditions': [
+                          [ 'arm_fpu!="default"', {
+                            'cflags': ['-mfpu=<(arm_fpu)',],
+                          }],
+                        ]
+                      }],
+                    ]
+                  }],
+                  [ 'arm_float_abi!="default"', {
+                    'cflags': ['-mfloat-abi=<(arm_float_abi)',],
+                  }],
+                  [ 'arm_thumb==1', {
+                    'cflags': ['-mthumb',],
+                  }],
+                  [ 'arm_thumb==0', {
+                    'cflags': ['-marm',],
+                  }],
+                ],
               }],
             ],
-          }, {
-            'defines': [
-              'USE_EABI_HARDFLOAT=0',
+            'conditions': [
+              [ 'arm_test=="on"', {
+                'defines': [
+                  'ARM_TEST',
+                ],
+              }],
             ],
           }],
-          [ 'v8_can_use_vfp32dregs=="true"', {
+          ['armsimulator=="yes"', {
             'defines': [
-              'CAN_USE_VFP32DREGS',
+              'ARM_TEST',
             ],
+            'conditions': [
+              [ 'armv7==1 or armv7=="default"', {
+                'defines': [
+                  'CAN_USE_ARMV7_INSTRUCTIONS=1',
+                ],
+                'conditions': [
+                  [ 'arm_fpu=="default"', {
+                    'defines': [
+                      'CAN_USE_VFP3_INSTRUCTIONS',
+                    ],
+                  }],
+                  [ 'arm_fpu=="vfpv3-d16"', {
+                    'defines': [
+                      'CAN_USE_VFP3_INSTRUCTIONS',
+                    ],
+                  }],
+                  [ 'arm_fpu=="vfpv3"', {
+                    'defines': [
+                      'CAN_USE_VFP3_INSTRUCTIONS',
+                      'CAN_USE_VFP32DREGS',
+                    ],
+                  }],
+                  [ 'arm_fpu=="neon" or arm_neon==1', {
+                    'defines': [
+                      'CAN_USE_VFP3_INSTRUCTIONS',
+                      'CAN_USE_VFP32DREGS',
+                    ],
+                  }],
+                ],
+              }],
+              [ 'arm_float_abi=="hard"', {
+                'defines': [
+                  'USE_EABI_HARDFLOAT=1',
+                ],
+              }],
+              [ 'arm_float_abi=="softfp" or arm_float_abi=="default"', {
+                'defines': [
+                  'USE_EABI_HARDFLOAT=0',
+                ],
+              }],
+            ]
           }],
         ],
       }],  # v8_target_arch=="arm"
               'clang%': 0,
             },
             'conditions': [
-              ['OS!="android" or clang==1', {
+              ['(OS!="android" or clang==1) and \
+                nacl_target_arch!="nacl_x64"', {
                 'cflags': [ '<(m32flag)' ],
                 'ldflags': [ '<(m32flag)' ],
               }],
           }],
           ['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': [
index 749755c..dde0575 100644 (file)
       }],
     ],
     # Default ARM variable settings.
-    'armv7%': 1,
+    'armv7%': 'default',
     'arm_neon%': 0,
     'arm_fpu%': 'vfpv3',
+    'arm_float_abi%': 'default',
+    'arm_thumb': 'default',
   },
   'target_defaults': {
     'default_configuration': 'Debug',
index 389949d..3e39823 100644 (file)
@@ -115,4 +115,6 @@ PreParserData V8EXPORT Preparse(UnicodeInputStream* input,
 
 }  // namespace v8.
 
+#undef V8EXPORT
+
 #endif  // PREPARSER_H
index 68f377c..5c5c7a9 100644 (file)
@@ -173,7 +173,7 @@ class V8EXPORT CpuProfiler {
    */
 
   /** Deprecated. Use GetProfileCount instead. */
-  static int GetProfilesCount();
+  V8_DEPRECATED(static int GetProfilesCount());
   /**
    * Returns the number of profiles collected (doesn't include
    * profiles that are being collected at the moment of call.)
@@ -181,25 +181,26 @@ class V8EXPORT CpuProfiler {
   int GetProfileCount();
 
   /** Deprecated. Use GetCpuProfile instead. */
-  static const CpuProfile* GetProfile(
+  V8_DEPRECATED(static const CpuProfile* GetProfile(
       int index,
-      Handle<Value> security_token = Handle<Value>());
+      Handle<Value> security_token = Handle<Value>()));
   /** Returns a profile by index. */
   const CpuProfile* GetCpuProfile(
       int index,
       Handle<Value> security_token = Handle<Value>());
 
   /** Deprecated. Use FindProfile instead. */
-  static const CpuProfile* FindProfile(
+  V8_DEPRECATED(static const CpuProfile* FindProfile(
       unsigned uid,
-      Handle<Value> security_token = Handle<Value>());
+      Handle<Value> security_token = Handle<Value>()));
   /** Returns a profile by uid. */
   const CpuProfile* FindCpuProfile(
       unsigned uid,
       Handle<Value> security_token = Handle<Value>());
 
   /** Deprecated. Use StartCpuProfiling instead. */
-  static void StartProfiling(Handle<String> title, bool record_samples = false);
+  V8_DEPRECATED(static void StartProfiling(Handle<String> title,
+                                           bool record_samples = false));
   /**
    * Starts collecting CPU profile. Title may be an empty string. It
    * is allowed to have several profiles being collected at
@@ -214,9 +215,9 @@ class V8EXPORT CpuProfiler {
   void StartCpuProfiling(Handle<String> title, bool record_samples = false);
 
   /** Deprecated. Use StopCpuProfiling instead. */
-  static const CpuProfile* StopProfiling(
+  V8_DEPRECATED(static const CpuProfile* StopProfiling(
       Handle<String> title,
-      Handle<Value> security_token = Handle<Value>());
+      Handle<Value> security_token = Handle<Value>()));
   /**
    * Stops collecting CPU profile with a given title and returns it.
    * If the title given is empty, finishes the last profile started.
@@ -226,7 +227,7 @@ class V8EXPORT CpuProfiler {
       Handle<Value> security_token = Handle<Value>());
 
   /** Deprecated. Use DeleteAllCpuProfiles instead. */
-  static void DeleteAllProfiles();
+  V8_DEPRECATED(static void DeleteAllProfiles());
   /**
    * Deletes all existing profiles, also cancelling all profiling
    * activity.  All previously returned pointers to profiles and their
@@ -425,22 +426,23 @@ class V8EXPORT HeapProfiler {
       (uint16_t class_id, Handle<Value> wrapper);
 
   /** Deprecated. Use GetSnapshotCount instead. */
-  static int GetSnapshotsCount();
+  V8_DEPRECATED(static int GetSnapshotsCount());
   /** Returns the number of snapshots taken. */
   int GetSnapshotCount();
 
   /** Deprecated. Use GetHeapSnapshot instead. */
-  static const HeapSnapshot* GetSnapshot(int index);
+  V8_DEPRECATED(static const HeapSnapshot* GetSnapshot(int index));
   /** Returns a snapshot by index. */
   const HeapSnapshot* GetHeapSnapshot(int index);
 
   /** Deprecated. Use FindHeapSnapshot instead. */
-  static const HeapSnapshot* FindSnapshot(unsigned uid);
+  V8_DEPRECATED(static const HeapSnapshot* FindSnapshot(unsigned uid));
   /** Returns a profile by uid. */
   const HeapSnapshot* FindHeapSnapshot(unsigned uid);
 
   /** Deprecated. Use GetObjectId instead. */
-  static SnapshotObjectId GetSnapshotObjectId(Handle<Value> value);
+  V8_DEPRECATED(static SnapshotObjectId GetSnapshotObjectId(
+      Handle<Value> value));
   /**
    * Returns SnapshotObjectId for a heap object referenced by |value| if
    * it has been seen by the heap profiler, kUnknownObjectId otherwise.
@@ -469,11 +471,11 @@ class V8EXPORT HeapProfiler {
   };
 
   /** Deprecated. Use TakeHeapSnapshot instead. */
-  static const HeapSnapshot* TakeSnapshot(
+  V8_DEPRECATED(static const HeapSnapshot* TakeSnapshot(
       Handle<String> title,
       HeapSnapshot::Type type = HeapSnapshot::kFull,
       ActivityControl* control = NULL,
-      ObjectNameResolver* global_object_name_resolver = NULL);
+      ObjectNameResolver* global_object_name_resolver = NULL));
   /**
    * Takes a heap snapshot and returns it. Title may be an empty string.
    */
@@ -484,7 +486,7 @@ class V8EXPORT HeapProfiler {
 
 
   /** Deprecated. Use StartTrackingHeapObjects instead. */
-  static void StartHeapObjectsTracking();
+  V8_DEPRECATED(static void StartHeapObjectsTracking());
   /**
    * Starts tracking of heap objects population statistics. After calling
    * this method, all heap objects relocations done by the garbage collector
@@ -493,7 +495,8 @@ class V8EXPORT HeapProfiler {
   void StartTrackingHeapObjects();
 
   /** Deprecated. Use GetHeapStats instead. */
-  static SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
+  V8_DEPRECATED(static SnapshotObjectId PushHeapObjectsStats(
+      OutputStream* stream));
   /**
    * Adds a new time interval entry to the aggregated statistics array. The
    * time interval entry contains information on the current heap objects
@@ -509,7 +512,7 @@ class V8EXPORT HeapProfiler {
   SnapshotObjectId GetHeapStats(OutputStream* stream);
 
   /** Deprecated. Use StopTrackingHeapObjects instead. */
-  static void StopHeapObjectsTracking();
+  V8_DEPRECATED(static void StopHeapObjectsTracking());
   /**
    * Stops tracking of heap objects population statistics, cleans up all
    * collected data. StartHeapObjectsTracking must be called again prior to
@@ -518,7 +521,7 @@ class V8EXPORT HeapProfiler {
   void StopTrackingHeapObjects();
 
   /** Deprecated. Use DeleteAllHeapSnapshots instead. */
-  static void DeleteAllSnapshots();
+  V8_DEPRECATED(static void DeleteAllSnapshots());
   /**
    * Deletes all snapshots taken. All previously returned pointers to
    * snapshots and their contents become invalid after this call.
@@ -526,9 +529,9 @@ class V8EXPORT HeapProfiler {
   void DeleteAllHeapSnapshots();
 
   /** Deprecated. Use SetWrapperClassInfoProvider instead. */
-  static void DefineWrapperClass(
+  V8_DEPRECATED(static void DefineWrapperClass(
       uint16_t class_id,
-      WrapperInfoCallback callback);
+      WrapperInfoCallback callback));
   /** Binds a callback to embedder's class ID. */
   void SetWrapperClassInfoProvider(
       uint16_t class_id,
@@ -544,10 +547,10 @@ class V8EXPORT HeapProfiler {
   /**
    * Deprecated. Returns the number of currently existing persistent handles.
    */
-  static int GetPersistentHandleCount();
+  V8_DEPRECATED(static int GetPersistentHandleCount());
 
   /** Deprecated. Use GetHeapProfilerMemorySize instead. */
-  static size_t GetMemorySizeUsedByProfiler();
+  V8_DEPRECATED(static size_t GetMemorySizeUsedByProfiler());
   /** Returns memory used for profiler internal data and snapshots. */
   size_t GetProfilerMemorySize();
 
index 9adb1c0..e1c0203 100644 (file)
@@ -127,6 +127,8 @@ class StackFrame;
 class StackTrace;
 class String;
 class StringObject;
+class Symbol;
+class SymbolObject;
 class Uint32;
 class Utils;
 class Value;
@@ -764,6 +766,17 @@ class V8EXPORT Script {
    * debugger API.
    */
   void SetData(Handle<String> data);
+
+  /**
+   * Returns the name value of one Script.
+   */
+  Handle<Value> GetScriptName();
+
+  /**
+   * Returns zero based line number of the code_pos location in the script.
+   * -1 will be returned if no information available.
+   */
+  int GetLineNumber(int code_pos);
 };
 
 
@@ -973,6 +986,12 @@ class V8EXPORT Value : public Data {
   V8_INLINE(bool IsString() const);
 
   /**
+   * Returns true if this value is a symbol.
+   * This is an experimental feature.
+   */
+  bool IsSymbol() const;
+
+  /**
    * Returns true if this value is a function.
    */
   bool IsFunction() const;
@@ -1033,6 +1052,12 @@ class V8EXPORT Value : public Data {
   bool IsStringObject() const;
 
   /**
+   * Returns true if this value is a Symbol object.
+   * This is an experimental feature.
+   */
+  bool IsSymbolObject() const;
+
+  /**
    * Returns true if this value is a NativeError.
    */
   bool IsNativeError() const;
@@ -1311,7 +1336,11 @@ class V8EXPORT String : public Primitive {
   /** Allocates a new string from 16-bit character codes.*/
   static Local<String> New(const uint16_t* data, int length = -1);
 
-  /** Creates a symbol. Returns one if it exists already.*/
+  /**
+   * Creates an internalized string (historically called a "symbol",
+   * not to be confused with ES6 symbols). Returns one if it exists already.
+   * TODO(rossberg): Deprecate me when the new string API is here.
+   */
   static Local<String> NewSymbol(const char* data, int length = -1);
 
   /**
@@ -1450,6 +1479,29 @@ class V8EXPORT String : public Primitive {
 
 
 /**
+ * A JavaScript symbol (ECMA-262 edition 6)
+ *
+ * This is an experimental feature. Use at your own risk.
+ */
+class V8EXPORT Symbol : public Primitive {
+ public:
+  // Returns the print name string of the symbol, or undefined if none.
+  Local<Value> Name() const;
+
+  // Create a symbol without a print name.
+  static Local<Symbol> New(Isolate* isolate);
+
+  // Create a symbol with a print name.
+  static Local<Symbol> New(Isolate *isolate, const char* data, int length = -1);
+
+  V8_INLINE(static Symbol* Cast(v8::Value* obj));
+ private:
+  Symbol();
+  static void CheckCast(v8::Value* obj);
+};
+
+
+/**
  * A JavaScript number value (ECMA-262, 4.3.20)
  */
 class V8EXPORT Number : public Primitive {
@@ -1590,11 +1642,9 @@ class V8EXPORT Object : public Value {
    */
   PropertyAttribute GetPropertyAttributes(Handle<Value> key);
 
-  // TODO(1245389): Replace the type-specific versions of these
-  // functions with generic ones that accept a Handle<Value> key.
-  bool Has(Handle<String> key);
+  bool Has(Handle<Value> key);
 
-  bool Delete(Handle<String> key);
+  bool Delete(Handle<Value> key);
 
   // Delete a property on this object bypassing interceptors and
   // ignoring dont-delete attributes.
@@ -1982,6 +2032,27 @@ class V8EXPORT StringObject : public Object {
 
 
 /**
+ * A Symbol object (ECMA-262 edition 6).
+ *
+ * This is an experimental feature. Use at your own risk.
+ */
+class V8EXPORT SymbolObject : public Object {
+ public:
+  static Local<Value> New(Isolate* isolate, Handle<Symbol> value);
+
+  /**
+   * Returns the Symbol held by the object.
+   */
+  Local<Symbol> SymbolValue() const;
+
+  V8_INLINE(static SymbolObject* Cast(v8::Value* obj));
+
+ private:
+  static void CheckCast(v8::Value* obj);
+};
+
+
+/**
  * An instance of the built-in RegExp constructor (ECMA-262, 15.10).
  */
 class V8EXPORT RegExp : public Object {
@@ -3036,6 +3107,9 @@ class V8EXPORT Isolate {
    */
   CpuProfiler* GetCpuProfiler();
 
+  /** Returns the context that is on the top of the stack. */
+  Local<Context> GetCurrentContext();
+
  private:
   Isolate();
   Isolate(const Isolate&);
@@ -3864,11 +3938,11 @@ class V8EXPORT Context {
    */
   void ReattachGlobal(Handle<Object> global_object);
 
-  /** Creates a new context.
+  /**
+   * Creates a new context and returns a handle to the newly allocated
+   * context.
    *
-   * Returns a persistent handle to the newly allocated context. This
-   * persistent handle has to be disposed when the context is no
-   * longer used so the context can be garbage collected.
+   * \param isolate The isolate in which to create the context.
    *
    * \param extensions An optional extension configuration containing
    * the extensions to be installed in the newly created context.
@@ -3882,6 +3956,14 @@ class V8EXPORT Context {
    * template. The state of the global object will be completely reset
    * and only object identify will remain.
    */
+  static Local<Context> New(
+      Isolate* isolate,
+      ExtensionConfiguration* extensions = NULL,
+      Handle<ObjectTemplate> global_template = Handle<ObjectTemplate>(),
+      Handle<Value> global_object = Handle<Value>());
+
+  /** Deprecated. Use Isolate version instead. */
+  // TODO(mstarzinger): Put this behind the V8_DEPRECATED guard.
   static Persistent<Context> New(
       ExtensionConfiguration* extensions = NULL,
       Handle<ObjectTemplate> global_template = Handle<ObjectTemplate>(),
@@ -3890,7 +3972,8 @@ class V8EXPORT Context {
   /** Returns the last entered context. */
   static Local<Context> GetEntered();
 
-  /** Returns the context that is on the top of the stack. */
+  // TODO(svenpanne) Actually deprecate this.
+  /** Deprecated. Use Isolate::GetCurrentContext instead. */
   static Local<Context> GetCurrent();
 
   /**
@@ -4301,7 +4384,7 @@ class Internals {
   static const int kNullValueRootIndex = 7;
   static const int kTrueValueRootIndex = 8;
   static const int kFalseValueRootIndex = 9;
-  static const int kEmptyStringRootIndex = 119;
+  static const int kEmptyStringRootIndex = 118;
 
   static const int kNodeClassIdOffset = 1 * kApiPointerSize;
   static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
@@ -4847,6 +4930,14 @@ bool Value::QuickIsString() const {
 }
 
 
+Symbol* Symbol::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+  CheckCast(value);
+#endif
+  return static_cast<Symbol*>(value);
+}
+
+
 Number* Number::Cast(v8::Value* value) {
 #ifdef V8_ENABLE_CHECKS
   CheckCast(value);
@@ -4879,6 +4970,14 @@ StringObject* StringObject::Cast(v8::Value* value) {
 }
 
 
+SymbolObject* SymbolObject::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+  CheckCast(value);
+#endif
+  return static_cast<SymbolObject*>(value);
+}
+
+
 NumberObject* NumberObject::Cast(v8::Value* value) {
 #ifdef V8_ENABLE_CHECKS
   CheckCast(value);
index 1bcc804..b816744 100644 (file)
@@ -30,6 +30,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "../include/v8.h"
 #include "../include/v8stdint.h"
 #include "../include/v8-preparser.h"
 
@@ -37,8 +38,7 @@
 
 namespace i = v8::internal;
 
-// This file is only used for testing the stand-alone preparser
-// library.
+// This file is only used for testing the preparser.
 // The first argument must be the path of a JavaScript source file, or
 // the flags "-e" and the next argument is then the source of a JavaScript
 // program.
@@ -320,6 +320,8 @@ int main(int argc, const char* argv[]) {
   ExceptionExpectation expects =
       ParseExpectation(argc - arg_index, argv + arg_index);
 
+  v8::V8::Initialize();
+
   ScopedPointer<uint8_t> buffer;
   size_t length;
 
index 0b03382..863a2ff 100644 (file)
     {
       'target_name': 'preparser',
       'type': 'executable',
-      'dependencies': [
-        '../tools/gyp/v8.gyp:preparser_lib',
+      'conditions': [
+        # preparser can't link against a shared library, so link against
+        # the underlying static targets.
+        ['v8_use_snapshot=="true"', {
+          'dependencies': ['../tools/gyp/v8.gyp:v8_snapshot'],
+        }, {
+          'dependencies': [
+            '../tools/gyp/v8.gyp:v8_nosnapshot.<(v8_target_arch)',
+          ],
+        }],
+      ],
+      'include_dirs+': [
+        '../src',
       ],
       'sources': [
         'preparser-process.cc',
+        '../include/v8-preparser.h',
+        '../src/preparser-api.cc',
       ],
     },
   ],
index 57062be..0b0f9b0 100644 (file)
@@ -783,64 +783,6 @@ const AccessorDescriptor Accessors::FunctionCaller = {
 
 
 //
-// Accessors::ObjectPrototype
-//
-
-
-static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate,
-                                                       Object* receiver) {
-  Object* current = receiver->GetPrototype(isolate);
-  while (current->IsJSObject() &&
-         JSObject::cast(current)->map()->is_hidden_prototype()) {
-    current = current->GetPrototype(isolate);
-  }
-  return current;
-}
-
-
-MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
-  return GetPrototypeSkipHiddenPrototypes(Isolate::Current(), receiver);
-}
-
-
-MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver_raw,
-                                           Object* value_raw,
-                                           void*) {
-  const bool kSkipHiddenPrototypes = true;
-  // To be consistent with other Set functions, return the value.
-  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, isolate);
-  Handle<Object> old_value(GetPrototypeSkipHiddenPrototypes(isolate, *receiver),
-                           isolate);
-
-  MaybeObject* result = receiver->SetPrototype(*value, kSkipHiddenPrototypes);
-  Handle<Object> hresult;
-  if (!result->ToHandle(&hresult, isolate)) return result;
-
-  Handle<Object> new_value(GetPrototypeSkipHiddenPrototypes(isolate, *receiver),
-                           isolate);
-  if (!new_value->SameValue(*old_value)) {
-    JSObject::EnqueueChangeRecord(receiver, "prototype",
-                                  isolate->factory()->proto_string(),
-                                  old_value);
-  }
-  return *hresult;
-}
-
-
-const AccessorDescriptor Accessors::ObjectPrototype = {
-  ObjectGetPrototype,
-  ObjectSetPrototype,
-  0
-};
-
-
-//
 // Accessors::MakeModuleExport
 //
 
index 250f742..0740d92 100644 (file)
@@ -56,8 +56,7 @@ namespace internal {
   V(ScriptContextData)              \
   V(ScriptEvalFromScript)           \
   V(ScriptEvalFromScriptPosition)   \
-  V(ScriptEvalFromFunctionName)     \
-  V(ObjectPrototype)
+  V(ScriptEvalFromFunctionName)
 
 // Accessors contains all predefined proxy accessors.
 
@@ -111,10 +110,6 @@ class Accessors : public AllStatic {
   static MaybeObject* ScriptGetEvalFromScript(Object* object, void*);
   static MaybeObject* ScriptGetEvalFromScriptPosition(Object* object, void*);
   static MaybeObject* ScriptGetEvalFromFunctionName(Object* object, void*);
-  static MaybeObject* ObjectGetPrototype(Object* receiver, void*);
-  static MaybeObject* ObjectSetPrototype(JSObject* receiver,
-                                         Object* value,
-                                         void*);
 
   // Helper functions.
   static Object* FlattenNumber(Object* value);
index 6c7a08c..94aaad3 100644 (file)
@@ -28,8 +28,8 @@
 #include "allocation.h"
 
 #include <stdlib.h>  // For free, malloc.
-#include <string.h>  // For memcpy.
 #include "checks.h"
+#include "platform.h"
 #include "utils.h"
 
 namespace v8 {
@@ -85,7 +85,7 @@ void AllStatic::operator delete(void* p) {
 char* StrDup(const char* str) {
   int length = StrLength(str);
   char* result = NewArray<char>(length + 1);
-  memcpy(result, str, length);
+  OS::MemCopy(result, str, length);
   result[length] = '\0';
   return result;
 }
@@ -95,7 +95,7 @@ char* StrNDup(const char* str, int n) {
   int length = StrLength(str);
   if (n < length) length = n;
   char* result = NewArray<char>(length + 1);
-  memcpy(result, str, length);
+  OS::MemCopy(result, str, length);
   result[length] = '\0';
   return result;
 }
index 65663ba..dddcd7d 100644 (file)
@@ -1655,7 +1655,7 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
 ScriptData* ScriptData::PreCompile(const char* input, int length) {
   i::Utf8ToUtf16CharacterStream stream(
       reinterpret_cast<const unsigned char*>(input), length);
-  return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
+  return i::PreParserApi::PreParse(&stream);
 }
 
 
@@ -1664,10 +1664,10 @@ ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
   if (str->IsExternalTwoByteString()) {
     i::ExternalTwoByteStringUtf16CharacterStream stream(
       i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length());
-    return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
+    return i::PreParserApi::PreParse(&stream);
   } else {
     i::GenericStringUtf16CharacterStream stream(str, 0, str->length());
-    return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
+    return i::PreParserApi::PreParse(&stream);
   }
 }
 
@@ -1686,7 +1686,8 @@ ScriptData* ScriptData::New(const char* data, int length) {
   }
   // Copy the data to align it.
   unsigned* deserialized_data = i::NewArray<unsigned>(deserialized_data_length);
-  i::OS::MemCopy(deserialized_data, data, length);
+  i::CopyBytes(reinterpret_cast<char*>(deserialized_data),
+               data, static_cast<size_t>(length));
 
   return new i::ScriptDataImpl(
       i::Vector<unsigned>(deserialized_data, deserialized_data_length));
@@ -1852,6 +1853,34 @@ Local<Value> Script::Id() {
 }
 
 
+int Script::GetLineNumber(int code_pos) {
+  i::Isolate* isolate = i::Isolate::Current();
+  ON_BAILOUT(isolate, "v8::Script::GetLineNumber()", return -1);
+  LOG_API(isolate, "Script::GetLineNumber");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsScript()) {
+    i::Handle<i::Script> script = i::Handle<i::Script>(i::Script::cast(*obj));
+    return i::GetScriptLineNumber(script, code_pos);
+  } else {
+    return -1;
+  }
+}
+
+
+Handle<Value> Script::GetScriptName() {
+  i::Isolate* isolate = i::Isolate::Current();
+  ON_BAILOUT(isolate, "v8::Script::GetName()", return Handle<String>());
+  LOG_API(isolate, "Script::GetName");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsScript()) {
+    i::Object* name = i::Script::cast(*obj)->name();
+    return Utils::ToLocal(i::Handle<i::Object>(name, isolate));
+  } else {
+    return Handle<String>();
+  }
+}
+
+
 void Script::SetData(v8::Handle<String> data) {
   i::Isolate* isolate = i::Isolate::Current();
   ON_BAILOUT(isolate, "v8::Script::SetData()", return);
@@ -2367,6 +2396,12 @@ bool Value::FullIsString() const {
 }
 
 
+bool Value::IsSymbol() const {
+  if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsSymbol()")) return false;
+  return Utils::OpenHandle(this)->IsSymbol();
+}
+
+
 bool Value::IsArray() const {
   if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsArray()")) return false;
   return Utils::OpenHandle(this)->IsJSArray();
@@ -2451,6 +2486,16 @@ bool Value::IsStringObject() const {
 }
 
 
+bool Value::IsSymbolObject() const {
+  // TODO(svenpanne): these and other test functions should be written such
+  // that they do not use Isolate::Current().
+  i::Isolate* isolate = i::Isolate::Current();
+  if (IsDeadCheck(isolate, "v8::Value::IsSymbolObject()")) return false;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  return obj->HasSpecificClassOf(isolate->heap()->Symbol_string());
+}
+
+
 bool Value::IsNumberObject() const {
   i::Isolate* isolate = i::Isolate::Current();
   if (IsDeadCheck(isolate, "v8::Value::IsNumberObject()")) return false;
@@ -2664,6 +2709,15 @@ void v8::String::CheckCast(v8::Value* that) {
 }
 
 
+void v8::Symbol::CheckCast(v8::Value* that) {
+  if (IsDeadCheck(i::Isolate::Current(), "v8::Symbol::Cast()")) return;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsSymbol(),
+           "v8::Symbol::Cast()",
+           "Could not convert to symbol");
+}
+
+
 void v8::Number::CheckCast(v8::Value* that) {
   if (IsDeadCheck(i::Isolate::Current(), "v8::Number::Cast()")) return;
   i::Handle<i::Object> obj = Utils::OpenHandle(that);
@@ -2711,6 +2765,16 @@ void v8::StringObject::CheckCast(v8::Value* that) {
 }
 
 
+void v8::SymbolObject::CheckCast(v8::Value* that) {
+  i::Isolate* isolate = i::Isolate::Current();
+  if (IsDeadCheck(isolate, "v8::SymbolObject::Cast()")) return;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Symbol_string()),
+           "v8::SymbolObject::Cast()",
+           "Could not convert to SymbolObject");
+}
+
+
 void v8::NumberObject::CheckCast(v8::Value* that) {
   i::Isolate* isolate = i::Isolate::Current();
   if (IsDeadCheck(isolate, "v8::NumberObject::Cast()")) return;
@@ -3079,13 +3143,13 @@ PropertyAttribute v8::Object::GetPropertyAttributes(v8::Handle<Value> key) {
   i::HandleScope scope(isolate);
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
-  if (!key_obj->IsString()) {
+  if (!key_obj->IsName()) {
     EXCEPTION_PREAMBLE(isolate);
     key_obj = i::Execution::ToString(key_obj, &has_pending_exception);
     EXCEPTION_BAILOUT_CHECK(isolate, static_cast<PropertyAttribute>(NONE));
   }
-  i::Handle<i::String> key_string = i::Handle<i::String>::cast(key_obj);
-  PropertyAttributes result = self->GetPropertyAttribute(*key_string);
+  i::Handle<i::Name> key_name = i::Handle<i::Name>::cast(key_obj);
+  PropertyAttributes result = self->GetPropertyAttribute(*key_name);
   if (result == ABSENT) return static_cast<PropertyAttribute>(NONE);
   return static_cast<PropertyAttribute>(result);
 }
@@ -3215,7 +3279,7 @@ Local<String> v8::Object::ObjectProtoToString() {
 
       // Write prefix.
       char* ptr = buf.start();
-      memcpy(ptr, prefix, prefix_len * v8::internal::kCharSize);
+      i::OS::MemCopy(ptr, prefix, prefix_len * v8::internal::kCharSize);
       ptr += prefix_len;
 
       // Write real content.
@@ -3223,7 +3287,7 @@ Local<String> v8::Object::ObjectProtoToString() {
       ptr += str_len;
 
       // Write postfix.
-      memcpy(ptr, postfix, postfix_len * v8::internal::kCharSize);
+      i::OS::MemCopy(ptr, postfix, postfix_len * v8::internal::kCharSize);
 
       // Copy the buffer into a heap-allocated string and return it.
       Local<String> result = v8::String::New(buf.start(), buf_len);
@@ -3255,24 +3319,32 @@ Local<String> v8::Object::GetConstructorName() {
 }
 
 
-bool v8::Object::Delete(v8::Handle<String> key) {
+bool v8::Object::Delete(v8::Handle<Value> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::Delete()", return false);
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
-  return i::JSObject::DeleteProperty(self, key_obj)->IsTrue();
+  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+  EXCEPTION_PREAMBLE(isolate);
+  i::Handle<i::Object> obj = i::DeleteProperty(self, key_obj);
+  has_pending_exception = obj.is_null();
+  EXCEPTION_BAILOUT_CHECK(isolate, false);
+  return obj->IsTrue();
 }
 
 
-bool v8::Object::Has(v8::Handle<String> key) {
+bool v8::Object::Has(v8::Handle<Value> key) {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
   ON_BAILOUT(isolate, "v8::Object::Has()", return false);
   ENTER_V8(isolate);
-  i::Handle<i::JSObject> self = Utils::OpenHandle(this);
-  i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
-  return self->HasProperty(*key_obj);
+  i::Handle<i::JSReceiver> self = Utils::OpenHandle(this);
+  i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+  EXCEPTION_PREAMBLE(isolate);
+  i::Handle<i::Object> obj = i::HasProperty(self, key_obj);
+  has_pending_exception = obj.is_null();
+  EXCEPTION_BAILOUT_CHECK(isolate, false);
+  return obj->IsTrue();
 }
 
 
@@ -3352,15 +3424,16 @@ bool v8::Object::HasRealNamedProperty(Handle<String> key) {
   ON_BAILOUT(isolate, "v8::Object::HasRealNamedProperty()",
              return false);
   return Utils::OpenHandle(this)->HasRealNamedProperty(
+      isolate,
       *Utils::OpenHandle(*key));
 }
 
 
 bool v8::Object::HasRealIndexedProperty(uint32_t index) {
-  ON_BAILOUT(Utils::OpenHandle(this)->GetIsolate(),
-             "v8::Object::HasRealIndexedProperty()",
+  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+  ON_BAILOUT(isolate, "v8::Object::HasRealIndexedProperty()",
              return false);
-  return Utils::OpenHandle(this)->HasRealElementProperty(index);
+  return Utils::OpenHandle(this)->HasRealElementProperty(isolate, index);
 }
 
 
@@ -3371,6 +3444,7 @@ bool v8::Object::HasRealNamedCallbackProperty(Handle<String> key) {
              return false);
   ENTER_V8(isolate);
   return Utils::OpenHandle(this)->HasRealNamedCallbackProperty(
+      isolate,
       *Utils::OpenHandle(*key));
 }
 
@@ -4591,6 +4665,15 @@ const v8::String::ExternalAsciiStringResource*
 }
 
 
+Local<Value> Symbol::Name() const {
+  if (IsDeadCheck(i::Isolate::Current(), "v8::Symbol::Name()"))
+    return Local<Value>();
+  i::Handle<i::Symbol> sym = Utils::OpenHandle(this);
+  i::Handle<i::Object> name(sym->name(), sym->GetIsolate());
+  return Utils::ToLocal(name);
+}
+
+
 double Number::Value() const {
   if (IsDeadCheck(i::Isolate::Current(), "v8::Number::Value()")) return 0;
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
@@ -4861,18 +4944,14 @@ static i::Handle<i::FunctionTemplateInfo>
 }
 
 
-Persistent<Context> v8::Context::New(
+static i::Handle<i::Context> CreateEnvironment(
+    i::Isolate* isolate,
     v8::ExtensionConfiguration* extensions,
     v8::Handle<ObjectTemplate> global_template,
     v8::Handle<Value> global_object) {
-  i::Isolate::EnsureDefaultIsolate();
-  i::Isolate* isolate = i::Isolate::Current();
-  EnsureInitializedForIsolate(isolate, "v8::Context::New()");
-  LOG_API(isolate, "Context::New");
-  ON_BAILOUT(isolate, "v8::Context::New()", return Persistent<Context>());
+  i::Handle<i::Context> env;
 
   // Enter V8 via an ENTER_V8 scope.
-  i::Handle<i::Context> env;
   {
     ENTER_V8(isolate);
     v8::Handle<ObjectTemplate> proxy_template = global_template;
@@ -4927,10 +5006,43 @@ Persistent<Context> v8::Context::New(
   }
   // Leave V8.
 
-  if (env.is_null()) {
-    return Persistent<Context>();
-  }
-  return Persistent<Context>(Utils::ToLocal(env));
+  return env;
+}
+
+
+Persistent<Context> v8::Context::New(
+    v8::ExtensionConfiguration* extensions,
+    v8::Handle<ObjectTemplate> global_template,
+    v8::Handle<Value> global_object) {
+  i::Isolate::EnsureDefaultIsolate();
+  i::Isolate* isolate = i::Isolate::Current();
+  Isolate* external_isolate = reinterpret_cast<Isolate*>(isolate);
+  EnsureInitializedForIsolate(isolate, "v8::Context::New()");
+  LOG_API(isolate, "Context::New");
+  ON_BAILOUT(isolate, "v8::Context::New()", return Persistent<Context>());
+  i::HandleScope scope(isolate);
+  i::Handle<i::Context> env =
+      CreateEnvironment(isolate, extensions, global_template, global_object);
+  if (env.is_null()) return Persistent<Context>();
+  return Persistent<Context>::New(external_isolate, Utils::ToLocal(env));
+}
+
+
+Local<Context> v8::Context::New(
+    v8::Isolate* external_isolate,
+    v8::ExtensionConfiguration* extensions,
+    v8::Handle<ObjectTemplate> global_template,
+    v8::Handle<Value> global_object) {
+  i::Isolate::EnsureDefaultIsolate();
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate);
+  EnsureInitializedForIsolate(isolate, "v8::Context::New()");
+  LOG_API(isolate, "Context::New");
+  ON_BAILOUT(isolate, "v8::Context::New()", return Local<Context>());
+  i::HandleScope scope(isolate);
+  i::Handle<i::Context> env =
+      CreateEnvironment(isolate, extensions, global_template, global_object);
+  if (env.is_null()) return Local<Context>();
+  return Utils::ToLocal(scope.CloseAndEscape(env));
 }
 
 
@@ -5005,10 +5117,7 @@ v8::Local<v8::Context> Context::GetCurrent() {
   if (IsDeadCheck(isolate, "v8::Context::GetCurrent()")) {
     return Local<Context>();
   }
-  i::Handle<i::Object> current = isolate->native_context();
-  if (current.is_null()) return Local<Context>();
-  i::Handle<i::Context> context = i::Handle<i::Context>::cast(current);
-  return Utils::ToLocal(context);
+  return reinterpret_cast<Isolate*>(isolate)->GetCurrentContext();
 }
 
 
@@ -5429,6 +5538,29 @@ Local<v8::String> v8::StringObject::StringValue() const {
 }
 
 
+Local<v8::Value> v8::SymbolObject::New(Isolate* isolate, Handle<Symbol> value) {
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  EnsureInitializedForIsolate(i_isolate, "v8::SymbolObject::New()");
+  LOG_API(i_isolate, "SymbolObject::New");
+  ENTER_V8(i_isolate);
+  i::Handle<i::Object> obj =
+      i_isolate->factory()->ToObject(Utils::OpenHandle(*value));
+  return Utils::ToLocal(obj);
+}
+
+
+Local<v8::Symbol> v8::SymbolObject::SymbolValue() const {
+  i::Isolate* isolate = i::Isolate::Current();
+  if (IsDeadCheck(isolate, "v8::SymbolObject::SymbolValue()"))
+    return Local<v8::Symbol>();
+  LOG_API(isolate, "SymbolObject::SymbolValue");
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
+  return Utils::ToLocal(
+      i::Handle<i::Symbol>(i::Symbol::cast(jsvalue->value())));
+}
+
+
 Local<v8::Value> v8::Date::New(double time) {
   i::Isolate* isolate = i::Isolate::Current();
   EnsureInitializedForIsolate(isolate, "v8::Date::New()");
@@ -5610,6 +5742,30 @@ Local<String> v8::String::NewSymbol(const char* data, int length) {
 }
 
 
+Local<Symbol> v8::Symbol::New(Isolate* isolate) {
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  EnsureInitializedForIsolate(i_isolate, "v8::Symbol::New()");
+  LOG_API(i_isolate, "Symbol::New()");
+  ENTER_V8(i_isolate);
+  i::Handle<i::Symbol> result = i_isolate->factory()->NewSymbol();
+  return Utils::ToLocal(result);
+}
+
+
+Local<Symbol> v8::Symbol::New(Isolate* isolate, const char* data, int length) {
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+  EnsureInitializedForIsolate(i_isolate, "v8::Symbol::New()");
+  LOG_API(i_isolate, "Symbol::New(char)");
+  ENTER_V8(i_isolate);
+  if (length == -1) length = i::StrLength(data);
+  i::Handle<i::String> name = i_isolate->factory()->NewStringFromUtf8(
+      i::Vector<const char>(data, length));
+  i::Handle<i::Symbol> result = i_isolate->factory()->NewSymbol();
+  result->set_name(*name);
+  return Utils::ToLocal(result);
+}
+
+
 Local<Number> v8::Number::New(double value) {
   i::Isolate* isolate = i::Isolate::Current();
   EnsureInitializedForIsolate(isolate, "v8::Number::New()");
@@ -5813,6 +5969,15 @@ CpuProfiler* Isolate::GetCpuProfiler() {
 }
 
 
+v8::Local<v8::Context> Isolate::GetCurrentContext() {
+  i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(this);
+  i::Handle<i::Object> current = internal_isolate->native_context();
+  if (current.is_null()) return Local<Context>();
+  i::Handle<i::Context> context = i::Handle<i::Context>::cast(current);
+  return Utils::ToLocal(context);
+}
+
+
 void V8::SetGlobalGCPrologueCallback(GCCallback callback) {
   i::Isolate* isolate = i::Isolate::Current();
   if (IsDeadCheck(isolate, "v8::V8::SetGlobalGCPrologueCallback()")) return;
@@ -7086,7 +7251,7 @@ char* HandleScopeImplementer::ArchiveThread(char* storage) {
   v8::ImplementationUtilities::HandleScopeData* current =
       isolate_->handle_scope_data();
   handle_scope_data_ = *current;
-  memcpy(storage, this, sizeof(*this));
+  OS::MemCopy(storage, this, sizeof(*this));
 
   ResetAfterArchive();
   current->Initialize();
@@ -7101,7 +7266,7 @@ int HandleScopeImplementer::ArchiveSpacePerThread() {
 
 
 char* HandleScopeImplementer::RestoreThread(char* storage) {
-  memcpy(this, storage, sizeof(*this));
+  OS::MemCopy(this, storage, sizeof(*this));
   *isolate_->handle_scope_data() = handle_scope_data_;
   return storage + ArchiveSpacePerThread();
 }
index d73646d..0cd16f1 100644 (file)
@@ -171,6 +171,7 @@ class RegisteredExtension {
   V(Object, JSObject)                          \
   V(Array, JSArray)                            \
   V(String, String)                            \
+  V(Symbol, Symbol)                            \
   V(Script, Object)                            \
   V(Function, JSFunction)                      \
   V(Message, JSObject)                         \
@@ -196,6 +197,8 @@ class Utils {
       v8::internal::Handle<v8::internal::JSFunction> obj);
   static inline Local<String> ToLocal(
       v8::internal::Handle<v8::internal::String> obj);
+  static inline Local<Symbol> ToLocal(
+      v8::internal::Handle<v8::internal::Symbol> obj);
   static inline Local<RegExp> ToLocal(
       v8::internal::Handle<v8::internal::JSRegExp> obj);
   static inline Local<Object> ToLocal(
@@ -268,6 +271,7 @@ MAKE_TO_LOCAL(ToLocal, Context, Context)
 MAKE_TO_LOCAL(ToLocal, Object, Value)
 MAKE_TO_LOCAL(ToLocal, JSFunction, Function)
 MAKE_TO_LOCAL(ToLocal, String, String)
+MAKE_TO_LOCAL(ToLocal, Symbol, Symbol)
 MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
 MAKE_TO_LOCAL(ToLocal, JSObject, Object)
 MAKE_TO_LOCAL(ToLocal, JSArray, Array)
index f8fb00c..1423d56 100644 (file)
@@ -115,15 +115,18 @@ class CustomArguments : public Relocatable {
 
 
 #define DECLARE_RUNTIME_FUNCTION(Type, Name)    \
-Type Name(Arguments args, Isolate* isolate)
-
-
-#define RUNTIME_FUNCTION(Type, Name)            \
-Type Name(Arguments args, Isolate* isolate)
-
-
-#define RUNTIME_ARGUMENTS(isolate, args) args, isolate
-
+Type Name(int args_length, Object** args_object, Isolate* isolate)
+
+#define RUNTIME_FUNCTION(Type, Name)                                  \
+static Type __RT_impl_##Name(Arguments args, Isolate* isolate);       \
+Type Name(int args_length, Object** args_object, Isolate* isolate) {  \
+  Arguments args(args_length, args_object);                           \
+  return __RT_impl_##Name(args, isolate);                             \
+}                                                                     \
+static Type __RT_impl_##Name(Arguments args, Isolate* isolate)
+
+#define RUNTIME_ARGUMENTS(isolate, args) \
+  args.length(), args.arguments(), isolate
 
 } }  // namespace v8::internal
 
index 123013b..0f9630b 100644 (file)
@@ -48,29 +48,17 @@ namespace internal {
 
 
 int Register::NumAllocatableRegisters() {
-  if (CpuFeatures::IsSupported(VFP2)) {
-    return kMaxNumAllocatableRegisters;
-  } else {
-    return kMaxNumAllocatableRegisters - kGPRsPerNonVFP2Double;
-  }
+  return kMaxNumAllocatableRegisters;
 }
 
 
 int DwVfpRegister::NumRegisters() {
-  if (CpuFeatures::IsSupported(VFP2)) {
-    return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
-  } else {
-    return 1;
-  }
+  return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
 }
 
 
 int DwVfpRegister::NumAllocatableRegisters() {
-  if (CpuFeatures::IsSupported(VFP2)) {
-    return NumRegisters() - kNumReservedRegisters;
-  } else {
-    return 1;
-  }
+  return NumRegisters() - kNumReservedRegisters;
 }
 
 
index 1574d51..bc21b64 100644 (file)
@@ -63,29 +63,21 @@ ExternalReference ExternalReference::cpu_features() {
 static unsigned CpuFeaturesImpliedByCompiler() {
   unsigned answer = 0;
 #ifdef CAN_USE_ARMV7_INSTRUCTIONS
-  answer |= 1u << ARMv7;
+  if (FLAG_enable_armv7) {
+    answer |= 1u << ARMv7;
+  }
 #endif  // CAN_USE_ARMV7_INSTRUCTIONS
 #ifdef CAN_USE_VFP3_INSTRUCTIONS
-  answer |= 1u << VFP3 | 1u << VFP2 | 1u << ARMv7;
+  if (FLAG_enable_vfp3) {
+    answer |= 1u << VFP3 | 1u << ARMv7;
+  }
 #endif  // CAN_USE_VFP3_INSTRUCTIONS
-#ifdef CAN_USE_VFP2_INSTRUCTIONS
-  answer |= 1u << VFP2;
-#endif  // CAN_USE_VFP2_INSTRUCTIONS
 #ifdef CAN_USE_VFP32DREGS
-  answer |= 1u << VFP32DREGS;
+  if (FLAG_enable_32dregs) {
+    answer |= 1u << VFP32DREGS;
+  }
 #endif  // CAN_USE_VFP32DREGS
-
-#ifdef __arm__
-  // If the compiler is allowed to use VFP then we can use VFP too in our code
-  // generation even when generating snapshots. ARMv7 and hardware floating
-  // point support implies VFPv3, see ARM DDI 0406B, page A1-6.
-#if defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(__VFP_FP__) \
-    && !defined(__SOFTFP__)
-  answer |= 1u << VFP3 | 1u << ARMv7 | 1u << VFP2;
-#endif  // defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(__VFP_FP__)
-        // && !defined(__SOFTFP__)
-#endif  // _arm__
-  if (answer & (1u << ARMv7)) {
+  if ((answer & (1u << ARMv7)) && FLAG_enable_unaligned_accesses) {
     answer |= 1u << UNALIGNED_ACCESSES;
   }
 
@@ -94,18 +86,13 @@ static unsigned CpuFeaturesImpliedByCompiler() {
 
 
 const char* DwVfpRegister::AllocationIndexToString(int index) {
-  if (CpuFeatures::IsSupported(VFP2)) {
-    ASSERT(index >= 0 && index < NumAllocatableRegisters());
-    ASSERT(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
-           kNumReservedRegisters - 1);
-    if (index >= kDoubleRegZero.code())
-      index += kNumReservedRegisters;
-
-    return VFPRegisters::Name(index, true);
-  } else {
-    ASSERT(index == 0);
-    return "sfpd0";
-  }
+  ASSERT(index >= 0 && index < NumAllocatableRegisters());
+  ASSERT(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
+         kNumReservedRegisters - 1);
+  if (index >= kDoubleRegZero.code())
+    index += kNumReservedRegisters;
+
+  return VFPRegisters::Name(index, true);
 }
 
 
@@ -124,6 +111,8 @@ void CpuFeatures::Probe() {
 
   if (Serializer::enabled()) {
     // No probing for features if we might serialize (generate snapshot).
+    printf("   ");
+    PrintFeatures();
     return;
   }
 
@@ -133,8 +122,7 @@ void CpuFeatures::Probe() {
   if (FLAG_enable_vfp3) {
     supported_ |=
         static_cast<uint64_t>(1) << VFP3 |
-        static_cast<uint64_t>(1) << ARMv7 |
-        static_cast<uint64_t>(1) << VFP2;
+        static_cast<uint64_t>(1) << ARMv7;
   }
   // For the simulator=arm build, use ARMv7 when FLAG_enable_armv7 is enabled
   if (FLAG_enable_armv7) {
@@ -153,48 +141,127 @@ void CpuFeatures::Probe() {
     supported_ |= static_cast<uint64_t>(1) << VFP32DREGS;
   }
 
+  if (FLAG_enable_unaligned_accesses) {
+    supported_ |= static_cast<uint64_t>(1) << UNALIGNED_ACCESSES;
+  }
+
 #else  // __arm__
   // Probe for additional features not already known to be available.
-  if (!IsSupported(VFP3) && OS::ArmCpuHasFeature(VFP3)) {
+  if (!IsSupported(VFP3) && FLAG_enable_vfp3 && OS::ArmCpuHasFeature(VFP3)) {
     // This implementation also sets the VFP flags if runtime
-    // detection of VFP returns true. VFPv3 implies ARMv7 and VFP2, see ARM DDI
+    // detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI
     // 0406B, page A1-6.
     found_by_runtime_probing_only_ |=
         static_cast<uint64_t>(1) << VFP3 |
-        static_cast<uint64_t>(1) << ARMv7 |
-        static_cast<uint64_t>(1) << VFP2;
-  } else if (!IsSupported(VFP2) && OS::ArmCpuHasFeature(VFP2)) {
-    found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << VFP2;
+        static_cast<uint64_t>(1) << ARMv7;
   }
 
-  if (!IsSupported(ARMv7) && OS::ArmCpuHasFeature(ARMv7)) {
+  if (!IsSupported(ARMv7) && FLAG_enable_armv7 && OS::ArmCpuHasFeature(ARMv7)) {
     found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << ARMv7;
   }
 
-  if (!IsSupported(SUDIV) && OS::ArmCpuHasFeature(SUDIV)) {
+  if (!IsSupported(SUDIV) && FLAG_enable_sudiv && OS::ArmCpuHasFeature(SUDIV)) {
     found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << SUDIV;
   }
 
-  if (!IsSupported(UNALIGNED_ACCESSES) && OS::ArmCpuHasFeature(ARMv7)) {
+  if (!IsSupported(UNALIGNED_ACCESSES) && FLAG_enable_unaligned_accesses
+      && OS::ArmCpuHasFeature(ARMv7)) {
     found_by_runtime_probing_only_ |=
         static_cast<uint64_t>(1) << UNALIGNED_ACCESSES;
   }
 
   if (OS::GetCpuImplementer() == QUALCOMM_IMPLEMENTER &&
-      OS::ArmCpuHasFeature(ARMv7)) {
+      FLAG_enable_movw_movt && OS::ArmCpuHasFeature(ARMv7)) {
     found_by_runtime_probing_only_ |=
         static_cast<uint64_t>(1) << MOVW_MOVT_IMMEDIATE_LOADS;
   }
 
-  if (!IsSupported(VFP32DREGS) && OS::ArmCpuHasFeature(VFP32DREGS)) {
+  if (!IsSupported(VFP32DREGS) && FLAG_enable_32dregs
+      && OS::ArmCpuHasFeature(VFP32DREGS)) {
     found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << VFP32DREGS;
   }
 
   supported_ |= found_by_runtime_probing_only_;
 #endif
 
-  // Assert that VFP3 implies VFP2 and ARMv7.
-  ASSERT(!IsSupported(VFP3) || (IsSupported(VFP2) && IsSupported(ARMv7)));
+  // Assert that VFP3 implies ARMv7.
+  ASSERT(!IsSupported(VFP3) || IsSupported(ARMv7));
+}
+
+
+void CpuFeatures::PrintTarget() {
+  const char* arm_arch = NULL;
+  const char* arm_test = "";
+  const char* arm_fpu = "";
+  const char* arm_thumb = "";
+  const char* arm_float_abi = NULL;
+
+#if defined CAN_USE_ARMV7_INSTRUCTIONS
+  arm_arch = "arm v7";
+#else
+  arm_arch = "arm v6";
+#endif
+
+#ifdef __arm__
+
+# ifdef ARM_TEST
+  arm_test = " test";
+# endif
+# if defined __ARM_NEON__
+  arm_fpu = " neon";
+# elif defined CAN_USE_VFP3_INSTRUCTIONS
+  arm_fpu = " vfp3";
+# else
+  arm_fpu = " vfp2";
+# endif
+# if (defined __thumb__) || (defined __thumb2__)
+  arm_thumb = " thumb";
+# endif
+  arm_float_abi = OS::ArmUsingHardFloat() ? "hard" : "softfp";
+
+#else  // __arm__
+
+  arm_test = " simulator";
+# if defined CAN_USE_VFP3_INSTRUCTIONS
+#  if defined CAN_USE_VFP32DREGS
+  arm_fpu = " vfp3";
+#  else
+  arm_fpu = " vfp3-d16";
+#  endif
+# else
+  arm_fpu = " vfp2";
+# endif
+# if USE_EABI_HARDFLOAT == 1
+  arm_float_abi = "hard";
+# else
+  arm_float_abi = "softfp";
+# endif
+
+#endif  // __arm__
+
+  printf("target%s %s%s%s %s\n",
+         arm_test, arm_arch, arm_fpu, arm_thumb, arm_float_abi);
+}
+
+
+void CpuFeatures::PrintFeatures() {
+  printf(
+    "ARMv7=%d VFP3=%d VFP32DREGS=%d SUDIV=%d UNALIGNED_ACCESSES=%d "
+    "MOVW_MOVT_IMMEDIATE_LOADS=%d",
+    CpuFeatures::IsSupported(ARMv7),
+    CpuFeatures::IsSupported(VFP3),
+    CpuFeatures::IsSupported(VFP32DREGS),
+    CpuFeatures::IsSupported(SUDIV),
+    CpuFeatures::IsSupported(UNALIGNED_ACCESSES),
+    CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS));
+#ifdef __arm__
+  bool eabi_hardfloat = OS::ArmUsingHardFloat();
+#elif USE_EABI_HARDFLOAT
+  bool eabi_hardfloat = true;
+#else
+  bool eabi_hardfloat = false;
+#endif
+    printf(" USE_EABI_HARDFLOAT=%d\n", eabi_hardfloat);
 }
 
 
@@ -1763,7 +1830,6 @@ void Assembler::vldr(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-924.
   // cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) |
   // Vd(15-12) | 1011(11-8) | offset
-  ASSERT(IsEnabled(VFP2));
   int u = 1;
   if (offset < 0) {
     offset = -offset;
@@ -1807,7 +1873,6 @@ void Assembler::vldr(const SwVfpRegister dst,
   // Instruction details available in ARM DDI 0406A, A8-628.
   // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
   // Vdst(15-12) | 1010(11-8) | offset
-  ASSERT(IsEnabled(VFP2));
   int u = 1;
   if (offset < 0) {
     offset = -offset;
@@ -1851,7 +1916,6 @@ void Assembler::vstr(const DwVfpRegister src,
   // Instruction details available in ARM DDI 0406C.b, A8-1082.
   // cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) |
   // Vd(15-12) | 1011(11-8) | (offset/4)
-  ASSERT(IsEnabled(VFP2));
   int u = 1;
   if (offset < 0) {
     offset = -offset;
@@ -1895,7 +1959,6 @@ void Assembler::vstr(const SwVfpRegister src,
   // Instruction details available in ARM DDI 0406A, A8-786.
   // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
   // Vdst(15-12) | 1010(11-8) | (offset/4)
-  ASSERT(IsEnabled(VFP2));
   int u = 1;
   if (offset < 0) {
     offset = -offset;
@@ -1938,7 +2001,6 @@ void  Assembler::vldm(BlockAddrMode am,
   // Instruction details available in ARM DDI 0406C.b, A8-922.
   // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
   // first(15-12) | 1011(11-8) | (count * 2)
-  ASSERT(IsEnabled(VFP2));
   ASSERT_LE(first.code(), last.code());
   ASSERT(am == ia || am == ia_w || am == db_w);
   ASSERT(!base.is(pc));
@@ -1960,7 +2022,6 @@ void  Assembler::vstm(BlockAddrMode am,
   // Instruction details available in ARM DDI 0406C.b, A8-1080.
   // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
   // first(15-12) | 1011(11-8) | (count * 2)
-  ASSERT(IsEnabled(VFP2));
   ASSERT_LE(first.code(), last.code());
   ASSERT(am == ia || am == ia_w || am == db_w);
   ASSERT(!base.is(pc));
@@ -1981,7 +2042,6 @@ void  Assembler::vldm(BlockAddrMode am,
   // Instruction details available in ARM DDI 0406A, A8-626.
   // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
   // first(15-12) | 1010(11-8) | (count/2)
-  ASSERT(IsEnabled(VFP2));
   ASSERT_LE(first.code(), last.code());
   ASSERT(am == ia || am == ia_w || am == db_w);
   ASSERT(!base.is(pc));
@@ -2002,7 +2062,6 @@ void  Assembler::vstm(BlockAddrMode am,
   // Instruction details available in ARM DDI 0406A, A8-784.
   // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
   // first(15-12) | 1011(11-8) | (count/2)
-  ASSERT(IsEnabled(VFP2));
   ASSERT_LE(first.code(), last.code());
   ASSERT(am == ia || am == ia_w || am == db_w);
   ASSERT(!base.is(pc));
@@ -2016,7 +2075,7 @@ void  Assembler::vstm(BlockAddrMode am,
 
 static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
   uint64_t i;
-  memcpy(&i, &d, 8);
+  OS::MemCopy(&i, &d, 8);
 
   *lo = i & 0xffffffff;
   *hi = i >> 32;
@@ -2076,8 +2135,6 @@ static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
 void Assembler::vmov(const DwVfpRegister dst,
                      double imm,
                      const Register scratch) {
-  ASSERT(IsEnabled(VFP2));
-
   uint32_t enc;
   if (CpuFeatures::IsSupported(VFP3) && FitsVMOVDoubleImmediate(imm, &enc)) {
     // The double can be encoded in the instruction.
@@ -2148,7 +2205,6 @@ void Assembler::vmov(const SwVfpRegister dst,
                      const Condition cond) {
   // Sd = Sm
   // Instruction details available in ARM DDI 0406B, A8-642.
-  ASSERT(IsEnabled(VFP2));
   int sd, d, sm, m;
   dst.split_code(&sd, &d);
   src.split_code(&sm, &m);
@@ -2163,7 +2219,6 @@ void Assembler::vmov(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-938.
   // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
   // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
-  ASSERT(IsEnabled(VFP2));
   int vd, d;
   dst.split_code(&vd, &d);
   int vm, m;
@@ -2181,7 +2236,6 @@ void Assembler::vmov(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-940.
   // cond(31-28) | 1110(27-24) | 0(23) | opc1=0index(22-21) | 0(20) |
   // Vd(19-16) | Rt(15-12) | 1011(11-8) | D(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
-  ASSERT(IsEnabled(VFP2));
   ASSERT(index.index == 0 || index.index == 1);
   int vd, d;
   dst.split_code(&vd, &d);
@@ -2198,7 +2252,6 @@ void Assembler::vmov(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-948.
   // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
   // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
-  ASSERT(IsEnabled(VFP2));
   ASSERT(!src1.is(pc) && !src2.is(pc));
   int vm, m;
   dst.split_code(&vm, &m);
@@ -2215,7 +2268,6 @@ void Assembler::vmov(const Register dst1,
   // Instruction details available in ARM DDI 0406C.b, A8-948.
   // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
   // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
-  ASSERT(IsEnabled(VFP2));
   ASSERT(!dst1.is(pc) && !dst2.is(pc));
   int vm, m;
   src.split_code(&vm, &m);
@@ -2231,7 +2283,6 @@ void Assembler::vmov(const SwVfpRegister dst,
   // Instruction details available in ARM DDI 0406A, A8-642.
   // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
   // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
-  ASSERT(IsEnabled(VFP2));
   ASSERT(!src.is(pc));
   int sn, n;
   dst.split_code(&sn, &n);
@@ -2246,7 +2297,6 @@ void Assembler::vmov(const Register dst,
   // Instruction details available in ARM DDI 0406A, A8-642.
   // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
   // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
-  ASSERT(IsEnabled(VFP2));
   ASSERT(!dst.is(pc));
   int sn, n;
   src.split_code(&sn, &n);
@@ -2371,7 +2421,6 @@ void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
                              const SwVfpRegister src,
                              VFPConversionMode mode,
                              const Condition cond) {
-  ASSERT(IsEnabled(VFP2));
   emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
 }
 
@@ -2380,7 +2429,6 @@ void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
                              const SwVfpRegister src,
                              VFPConversionMode mode,
                              const Condition cond) {
-  ASSERT(IsEnabled(VFP2));
   emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
 }
 
@@ -2389,7 +2437,6 @@ void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
                              const SwVfpRegister src,
                              VFPConversionMode mode,
                              const Condition cond) {
-  ASSERT(IsEnabled(VFP2));
   emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
 }
 
@@ -2398,7 +2445,6 @@ void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
                              VFPConversionMode mode,
                              const Condition cond) {
-  ASSERT(IsEnabled(VFP2));
   emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
 }
 
@@ -2407,7 +2453,6 @@ void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
                              VFPConversionMode mode,
                              const Condition cond) {
-  ASSERT(IsEnabled(VFP2));
   emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
 }
 
@@ -2416,7 +2461,6 @@ void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
                              const SwVfpRegister src,
                              VFPConversionMode mode,
                              const Condition cond) {
-  ASSERT(IsEnabled(VFP2));
   emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
 }
 
@@ -2425,7 +2469,6 @@ void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
                              VFPConversionMode mode,
                              const Condition cond) {
-  ASSERT(IsEnabled(VFP2));
   emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
 }
 
@@ -2436,7 +2479,6 @@ void Assembler::vneg(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-968.
   // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
   // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
-  ASSERT(IsEnabled(VFP2));
   int vd, d;
   dst.split_code(&vd, &d);
   int vm, m;
@@ -2453,7 +2495,6 @@ void Assembler::vabs(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-524.
   // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
   // 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
-  ASSERT(IsEnabled(VFP2));
   int vd, d;
   dst.split_code(&vd, &d);
   int vm, m;
@@ -2472,7 +2513,6 @@ void Assembler::vadd(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-830.
   // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
   // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
-  ASSERT(IsEnabled(VFP2));
   int vd, d;
   dst.split_code(&vd, &d);
   int vn, n;
@@ -2493,7 +2533,6 @@ void Assembler::vsub(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-1086.
   // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
   // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
-  ASSERT(IsEnabled(VFP2));
   int vd, d;
   dst.split_code(&vd, &d);
   int vn, n;
@@ -2514,7 +2553,6 @@ void Assembler::vmul(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-960.
   // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
   // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
-  ASSERT(IsEnabled(VFP2));
   int vd, d;
   dst.split_code(&vd, &d);
   int vn, n;
@@ -2571,7 +2609,6 @@ void Assembler::vdiv(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-882.
   // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
   // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
-  ASSERT(IsEnabled(VFP2));
   int vd, d;
   dst.split_code(&vd, &d);
   int vn, n;
@@ -2590,7 +2627,6 @@ void Assembler::vcmp(const DwVfpRegister src1,
   // Instruction details available in ARM DDI 0406C.b, A8-864.
   // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
   // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
-  ASSERT(IsEnabled(VFP2));
   int vd, d;
   src1.split_code(&vd, &d);
   int vm, m;
@@ -2607,7 +2643,6 @@ void Assembler::vcmp(const DwVfpRegister src1,
   // Instruction details available in ARM DDI 0406C.b, A8-864.
   // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
   // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
-  ASSERT(IsEnabled(VFP2));
   ASSERT(src2 == 0.0);
   int vd, d;
   src1.split_code(&vd, &d);
@@ -2619,7 +2654,6 @@ void Assembler::vmsr(Register dst, Condition cond) {
   // Instruction details available in ARM DDI 0406A, A8-652.
   // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
   // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
-  ASSERT(IsEnabled(VFP2));
   emit(cond | 0xE*B24 | 0xE*B20 |  B16 |
        dst.code()*B12 | 0xA*B8 | B4);
 }
@@ -2629,7 +2663,6 @@ void Assembler::vmrs(Register dst, Condition cond) {
   // Instruction details available in ARM DDI 0406A, A8-652.
   // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
   // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
-  ASSERT(IsEnabled(VFP2));
   emit(cond | 0xE*B24 | 0xF*B20 |  B16 |
        dst.code()*B12 | 0xA*B8 | B4);
 }
@@ -2641,7 +2674,6 @@ void Assembler::vsqrt(const DwVfpRegister dst,
   // Instruction details available in ARM DDI 0406C.b, A8-1058.
   // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
   // Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
-  ASSERT(IsEnabled(VFP2));
   int vd, d;
   dst.split_code(&vd, &d);
   int vm, m;
@@ -2747,9 +2779,9 @@ void Assembler::GrowBuffer() {
   // Copy the data.
   int pc_delta = desc.buffer - buffer_;
   int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
-  memmove(desc.buffer, buffer_, desc.instr_size);
-  memmove(reloc_info_writer.pos() + rc_delta,
-          reloc_info_writer.pos(), desc.reloc_size);
+  OS::MemMove(desc.buffer, buffer_, desc.instr_size);
+  OS::MemMove(reloc_info_writer.pos() + rc_delta,
+              reloc_info_writer.pos(), desc.reloc_size);
 
   // Switch buffers.
   DeleteArray(buffer_);
@@ -2998,7 +3030,7 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
 
       const double double_data = rinfo.data64();
       uint64_t uint_data = 0;
-      memcpy(&uint_data, &double_data, sizeof(double_data));
+      OS::MemCopy(&uint_data, &double_data, sizeof(double_data));
       emit(uint_data & 0xFFFFFFFF);
       emit(uint_data >> 32);
     }
index 045638e..0aecbcd 100644 (file)
@@ -55,16 +55,15 @@ class CpuFeatures : public AllStatic {
   // is enabled (snapshots must be portable).
   static void Probe();
 
+  // Display target use when compiling.
+  static void PrintTarget();
+
+  // Display features.
+  static void PrintFeatures();
+
   // Check whether a feature is supported by the target CPU.
   static bool IsSupported(CpuFeature f) {
     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;
-    }
-    if (f == VFP32DREGS && !FLAG_enable_32dregs) return false;
     return (supported_ & (1u << f)) != 0;
   }
 
@@ -117,7 +116,6 @@ struct Register {
   static const int kNumRegisters = 16;
   static const int kMaxNumAllocatableRegisters = 8;
   static const int kSizeInBytes = 4;
-  static const int kGPRsPerNonVFP2Double = 2;
 
   inline static int NumAllocatableRegisters();
 
@@ -214,6 +212,7 @@ const Register pc  = { kRegister_pc_Code };
 
 // Single word VFP register.
 struct SwVfpRegister {
+  static const int kSizeInBytes = 4;
   bool is_valid() const { return 0 <= code_ && code_ < 32; }
   bool is(SwVfpRegister reg) const { return code_ == reg.code_; }
   int code() const {
@@ -244,6 +243,7 @@ struct DwVfpRegister {
   static const int kNumReservedRegisters = 2;
   static const int kMaxNumAllocatableRegisters = kMaxNumRegisters -
       kNumReservedRegisters;
+  static const int kSizeInBytes = 8;
 
   // Note: the number of registers can be different at snapshot and run-time.
   // Any code included in the snapshot must be able to run both with 16 or 32
@@ -370,9 +370,6 @@ const DwVfpRegister d29 = { 29 };
 const DwVfpRegister d30 = { 30 };
 const DwVfpRegister d31 = { 31 };
 
-const Register sfpd_lo  = { kRegister_r6_Code };
-const Register sfpd_hi  = { kRegister_r7_Code };
-
 // Aliases for double registers.  Defined using #define instead of
 // "static const DwVfpRegister&" because Clang complains otherwise when a
 // compilation unit that includes this header doesn't use the variables.
index d982f27..1db4152 100644 (file)
@@ -30,6 +30,7 @@
 #if defined(V8_TARGET_ARCH_ARM)
 
 #include "bootstrapper.h"
+#include "builtins-decls.h"
 #include "code-stubs.h"
 #include "regexp-macro-assembler.h"
 #include "stub-cache.h"
@@ -38,6 +39,18 @@ namespace v8 {
 namespace internal {
 
 
+void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { r3, r2, r1 };
+  descriptor->register_param_count_ = 3;
+  descriptor->register_params_ = registers;
+  descriptor->stack_parameter_count_ = NULL;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
+}
+
+
 void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
@@ -133,7 +146,6 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
                                     Label* lhs_not_nan,
                                     Label* slow,
                                     bool strict);
-static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond);
 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
                                            Register lhs,
                                            Register rhs);
@@ -181,9 +193,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
 
   __ IncrementCounter(counters->fast_new_closure_total(), 1, r6, r7);
 
-  int map_index = (language_mode_ == CLASSIC_MODE)
-      ? Context::FUNCTION_MAP_INDEX
-      : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
+  int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
 
   // Compute the function map in the current native context and set that
   // as the map of the allocated object.
@@ -403,153 +413,6 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
 }
 
 
-static void GenerateFastCloneShallowArrayCommon(
-    MacroAssembler* masm,
-    int length,
-    FastCloneShallowArrayStub::Mode mode,
-    AllocationSiteMode allocation_site_mode,
-    Label* fail) {
-  // Registers on entry:
-  //
-  // r3: boilerplate literal array.
-  ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
-
-  // All sizes here are multiples of kPointerSize.
-  int elements_size = 0;
-  if (length > 0) {
-    elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
-        ? FixedDoubleArray::SizeFor(length)
-        : FixedArray::SizeFor(length);
-  }
-
-  int size = JSArray::kSize;
-  int allocation_info_start = size;
-  if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-    size += AllocationSiteInfo::kSize;
-  }
-  size += elements_size;
-
-  // Allocate both the JS array and the elements array in one big
-  // allocation. This avoids multiple limit checks.
-  AllocationFlags flags = TAG_OBJECT;
-  if (mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS) {
-    flags = static_cast<AllocationFlags>(DOUBLE_ALIGNMENT | flags);
-  }
-  __ Allocate(size, r0, r1, r2, fail, flags);
-
-  if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-    __ mov(r2, Operand(Handle<Map>(masm->isolate()->heap()->
-                                   allocation_site_info_map())));
-    __ str(r2, FieldMemOperand(r0, allocation_info_start));
-    __ str(r3, FieldMemOperand(r0, allocation_info_start + kPointerSize));
-  }
-
-  // Copy the JS array part.
-  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
-    if ((i != JSArray::kElementsOffset) || (length == 0)) {
-      __ ldr(r1, FieldMemOperand(r3, i));
-      __ str(r1, FieldMemOperand(r0, i));
-    }
-  }
-
-  if (length > 0) {
-    // Get hold of the elements array of the boilerplate and setup the
-    // elements pointer in the resulting object.
-    __ ldr(r3, FieldMemOperand(r3, JSArray::kElementsOffset));
-    if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-      __ add(r2, r0, Operand(JSArray::kSize + AllocationSiteInfo::kSize));
-    } else {
-      __ add(r2, r0, Operand(JSArray::kSize));
-    }
-    __ str(r2, FieldMemOperand(r0, JSArray::kElementsOffset));
-
-    // Copy the elements array.
-    ASSERT((elements_size % kPointerSize) == 0);
-    __ CopyFields(r2, r3, r1.bit(), elements_size / kPointerSize);
-  }
-}
-
-void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
-  // Stack layout on entry:
-  //
-  // [sp]: constant elements.
-  // [sp + kPointerSize]: literal index.
-  // [sp + (2 * kPointerSize)]: literals array.
-
-  // Load boilerplate object into r3 and check if we need to create a
-  // boilerplate.
-  Label slow_case;
-  __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
-  __ ldr(r0, MemOperand(sp, 1 * kPointerSize));
-  __ add(r3, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
-  __ ldr(r3, MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
-  __ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
-  __ b(eq, &slow_case);
-
-  FastCloneShallowArrayStub::Mode mode = mode_;
-  if (mode == CLONE_ANY_ELEMENTS) {
-    Label double_elements, check_fast_elements;
-    __ ldr(r0, FieldMemOperand(r3, JSArray::kElementsOffset));
-    __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
-    __ CompareRoot(r0, Heap::kFixedCOWArrayMapRootIndex);
-    __ b(ne, &check_fast_elements);
-    GenerateFastCloneShallowArrayCommon(masm, 0, COPY_ON_WRITE_ELEMENTS,
-                                        allocation_site_mode_,
-                                        &slow_case);
-    // Return and remove the on-stack parameters.
-    __ add(sp, sp, Operand(3 * kPointerSize));
-    __ Ret();
-
-    __ bind(&check_fast_elements);
-    __ CompareRoot(r0, Heap::kFixedArrayMapRootIndex);
-    __ b(ne, &double_elements);
-    GenerateFastCloneShallowArrayCommon(masm, length_, CLONE_ELEMENTS,
-                                        allocation_site_mode_,
-                                        &slow_case);
-    // Return and remove the on-stack parameters.
-    __ add(sp, sp, Operand(3 * kPointerSize));
-    __ Ret();
-
-    __ bind(&double_elements);
-    mode = CLONE_DOUBLE_ELEMENTS;
-    // Fall through to generate the code to handle double elements.
-  }
-
-  if (FLAG_debug_code) {
-    const char* message;
-    Heap::RootListIndex expected_map_index;
-    if (mode == CLONE_ELEMENTS) {
-      message = "Expected (writable) fixed array";
-      expected_map_index = Heap::kFixedArrayMapRootIndex;
-    } else if (mode == CLONE_DOUBLE_ELEMENTS) {
-      message = "Expected (writable) fixed double array";
-      expected_map_index = Heap::kFixedDoubleArrayMapRootIndex;
-    } else {
-      ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
-      message = "Expected copy-on-write fixed array";
-      expected_map_index = Heap::kFixedCOWArrayMapRootIndex;
-    }
-    __ push(r3);
-    __ ldr(r3, FieldMemOperand(r3, JSArray::kElementsOffset));
-    __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
-    __ CompareRoot(r3, expected_map_index);
-    __ Assert(eq, message);
-    __ pop(r3);
-  }
-
-  GenerateFastCloneShallowArrayCommon(masm, length_, mode,
-                                      allocation_site_mode_,
-                                      &slow_case);
-
-  // Return and remove the on-stack parameters.
-  __ add(sp, sp, Operand(3 * kPointerSize));
-  __ Ret();
-
-  __ bind(&slow_case);
-  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
-}
-
-
 // Takes a Smi and converts to an IEEE 64 bit floating point value in two
 // registers.  The format is 1 sign bit, 11 exponent bits (biased 1023) and
 // 52 fraction bits (20 in the first word, 32 in the second).  Zeros is a
@@ -650,30 +513,15 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
                                    FloatingPointHelper::Destination destination,
                                    Register scratch1,
                                    Register scratch2) {
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    __ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
-    __ vmov(d7.high(), scratch1);
-    __ vcvt_f64_s32(d7, d7.high());
-    __ mov(scratch1, Operand(r1, ASR, kSmiTagSize));
-    __ vmov(d6.high(), scratch1);
-    __ vcvt_f64_s32(d6, d6.high());
-    if (destination == kCoreRegisters) {
-      __ vmov(r2, r3, d7);
-      __ vmov(r0, r1, d6);
-    }
-  } else {
-    ASSERT(destination == kCoreRegisters);
-    // Write Smi from r0 to r3 and r2 in double format.
-    __ mov(scratch1, Operand(r0));
-    ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2);
-    __ push(lr);
-    __ Call(stub1.GetCode(masm->isolate()));
-    // Write Smi from r1 to r1 and r0 in double format.
-    __ mov(scratch1, Operand(r1));
-    ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2);
-    __ Call(stub2.GetCode(masm->isolate()));
-    __ pop(lr);
+  __ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
+  __ vmov(d7.high(), scratch1);
+  __ vcvt_f64_s32(d7, d7.high());
+  __ mov(scratch1, Operand(r1, ASR, kSmiTagSize));
+  __ vmov(d6.high(), scratch1);
+  __ vcvt_f64_s32(d6, d6.high());
+  if (destination == kCoreRegisters) {
+    __ vmov(r2, r3, d7);
+    __ vmov(r0, r1, d6);
   }
 }
 
@@ -700,9 +548,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
   __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
 
   // Handle loading a double from a heap number.
-  if (CpuFeatures::IsSupported(VFP2) &&
-      destination == kVFPRegisters) {
-    CpuFeatureScope scope(masm, VFP2);
+  if (destination == kVFPRegisters) {
     // Load the double from tagged HeapNumber to double register.
     __ sub(scratch1, object, Operand(kHeapObjectTag));
     __ vldr(dst, scratch1, HeapNumber::kValueOffset);
@@ -715,23 +561,12 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
 
   // Handle loading a double from a smi.
   __ bind(&is_smi);
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    // Convert smi to double using VFP instructions.
-    __ vmov(dst.high(), scratch1);
-    __ vcvt_f64_s32(dst, dst.high());
-    if (destination == kCoreRegisters) {
-      // Load the converted smi to dst1 and dst2 in double format.
-      __ vmov(dst1, dst2, dst);
-    }
-  } else {
-    ASSERT(destination == kCoreRegisters);
-    // Write smi to dst1 and dst2 double format.
-    __ mov(scratch1, Operand(object));
-    ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
-    __ push(lr);
-    __ Call(stub.GetCode(masm->isolate()));
-    __ pop(lr);
+  // Convert smi to double using VFP instructions.
+  __ vmov(dst.high(), scratch1);
+  __ vcvt_f64_s32(dst, dst.high());
+  if (destination == kCoreRegisters) {
+    // Load the converted smi to dst1 and dst2 in double format.
+    __ vmov(dst1, dst2, dst);
   }
 
   __ bind(&done);
@@ -778,62 +613,10 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm,
 
   Label done;
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    __ vmov(single_scratch, int_scratch);
-    __ vcvt_f64_s32(double_dst, single_scratch);
-    if (destination == kCoreRegisters) {
-      __ vmov(dst_mantissa, dst_exponent, double_dst);
-    }
-  } else {
-    Label fewer_than_20_useful_bits;
-    // Expected output:
-    // |       dst_exponent      |       dst_mantissa      |
-    // | s |   exp   |              mantissa               |
-
-    // Check for zero.
-    __ cmp(int_scratch, Operand::Zero());
-    __ mov(dst_exponent, int_scratch);
-    __ mov(dst_mantissa, int_scratch);
-    __ b(eq, &done);
-
-    // Preload the sign of the value.
-    __ 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(dst_mantissa, int_scratch, scratch2);
-    __ rsb(dst_mantissa, dst_mantissa, Operand(31));
-
-    // Set the exponent.
-    __ 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, dst_mantissa));
-
-    __ cmp(dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord));
-    // Get the number of bits to set in the lower part of the mantissa.
-    __ sub(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord),
-           SetCC);
-    __ b(mi, &fewer_than_20_useful_bits);
-    // Set the higher 20 bits of the mantissa.
-    __ orr(dst_exponent, dst_exponent, Operand(int_scratch, LSR, scratch2));
-    __ rsb(scratch2, scratch2, Operand(32));
-    __ mov(dst_mantissa, Operand(int_scratch, LSL, scratch2));
-    __ b(&done);
-
-    __ bind(&fewer_than_20_useful_bits);
-    __ rsb(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord));
-    __ mov(scratch2, Operand(int_scratch, LSL, scratch2));
-    __ orr(dst_exponent, dst_exponent, scratch2);
-    // Set dst1 to 0.
-    __ mov(dst_mantissa, Operand::Zero());
+  __ vmov(single_scratch, int_scratch);
+  __ vcvt_f64_s32(double_dst, single_scratch);
+  if (destination == kCoreRegisters) {
+    __ vmov(dst_mantissa, dst_exponent, double_dst);
   }
   __ bind(&done);
 }
@@ -872,65 +655,17 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
   __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
 
   // Load the number.
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    // Load the double value.
-    __ sub(scratch1, object, Operand(kHeapObjectTag));
-    __ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
-
-    __ TestDoubleIsInt32(double_dst, double_scratch);
-    // Jump to not_int32 if the operation did not succeed.
-    __ b(ne, not_int32);
+  // Load the double value.
+  __ sub(scratch1, object, Operand(kHeapObjectTag));
+  __ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
 
-    if (destination == kCoreRegisters) {
-      __ vmov(dst_mantissa, dst_exponent, double_dst);
-    }
-
-  } else {
-    ASSERT(!scratch1.is(object) && !scratch2.is(object));
-    // 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.
-    Label zero;
-    __ bic(scratch1, dst_exponent, Operand(HeapNumber::kSignMask));
-    __ orr(scratch1, scratch1, Operand(dst_mantissa));
-    __ cmp(scratch1, Operand::Zero());
-    __ 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.
-    Label restore_input_and_miss;
-    DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2,
-                         &restore_input_and_miss);
-
-    // 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);
+  __ TestDoubleIsInt32(double_dst, double_scratch);
+  // Jump to not_int32 if the operation did not succeed.
+  __ b(ne, not_int32);
 
-    __ bind(&zero);
-    if (save_registers) {
-      __ Drop(2);
-    }
+  if (destination == kCoreRegisters) {
+    __ vmov(dst_mantissa, dst_exponent, double_dst);
   }
-
   __ bind(&done);
 }
 
@@ -963,43 +698,13 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
 
   // Object is a heap number.
   // Convert the floating point value to a 32-bit integer.
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-
-    // Load the double value.
-    __ sub(scratch1, object, Operand(kHeapObjectTag));
-    __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
+  // Load the double value.
+  __ sub(scratch1, object, Operand(kHeapObjectTag));
+  __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
 
-    __ TryDoubleToInt32Exact(dst, double_scratch0, double_scratch1);
-    // Jump to not_int32 if the operation did not succeed.
-    __ b(ne, not_int32);
-  } else {
-    // Load the double value in the destination registers.
-    __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
-    __ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
-
-    // Check for 0 and -0.
-    __ bic(dst, scratch1, Operand(HeapNumber::kSignMask));
-    __ orr(dst, scratch2, Operand(dst));
-    __ cmp(dst, Operand::Zero());
-    __ b(eq, &done);
-
-    DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32);
-
-    // Registers state after DoubleIs32BitInteger.
-    // dst: mantissa[51:20].
-    // scratch2: 1
-
-    // Shift back the higher bits of the mantissa.
-    __ mov(dst, Operand(dst, LSR, scratch3));
-    // Set the implicit first bit.
-    __ rsb(scratch3, scratch3, Operand(32));
-    __ orr(dst, dst, Operand(scratch2, LSL, scratch3));
-    // Set the sign.
-    __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
-    __ tst(scratch1, Operand(HeapNumber::kSignMask));
-    __ rsb(dst, dst, Operand::Zero(), LeaveCC, mi);
-  }
+  __ TryDoubleToInt32Exact(dst, double_scratch0, double_scratch1);
+  // Jump to not_int32 if the operation did not succeed.
+  __ b(ne, not_int32);
   __ b(&done);
 
   __ bind(&maybe_undefined);
@@ -1093,7 +798,6 @@ void FloatingPointHelper::CallCCodeForDoubleOperation(
   __ push(lr);
   __ PrepareCallCFunction(0, 2, scratch);
   if (masm->use_eabi_hardfloat()) {
-    CpuFeatureScope scope(masm, VFP2);
     __ vmov(d0, r0, r1);
     __ vmov(d1, r2, r3);
   }
@@ -1105,7 +809,6 @@ void FloatingPointHelper::CallCCodeForDoubleOperation(
   // Store answer in the overwritable heap number. Double returned in
   // registers r0 and r1 or in d0.
   if (masm->use_eabi_hardfloat()) {
-    CpuFeatureScope scope(masm, VFP2);
     __ vstr(d0,
             FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
   } else {
@@ -1318,23 +1021,11 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
   }
 
   // Lhs is a smi, rhs is a number.
-  if (CpuFeatures::IsSupported(VFP2)) {
-    // Convert lhs to a double in d7.
-    CpuFeatureScope scope(masm, VFP2);
-    __ SmiToDoubleVFPRegister(lhs, d7, r7, s15);
-    // Load the double from rhs, tagged HeapNumber r0, to d6.
-    __ sub(r7, rhs, Operand(kHeapObjectTag));
-    __ vldr(d6, r7, HeapNumber::kValueOffset);
-  } else {
-    __ push(lr);
-    // Convert lhs to a double in r2, r3.
-    __ mov(r7, Operand(lhs));
-    ConvertToDoubleStub stub1(r3, r2, r7, r6);
-    __ Call(stub1.GetCode(masm->isolate()));
-    // Load rhs to a double in r0, r1.
-    __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset));
-    __ pop(lr);
-  }
+  // Convert lhs to a double in d7.
+  __ SmiToDoubleVFPRegister(lhs, d7, r7, s15);
+  // Load the double from rhs, tagged HeapNumber r0, to d6.
+  __ sub(r7, rhs, Operand(kHeapObjectTag));
+  __ vldr(d6, r7, HeapNumber::kValueOffset);
 
   // We now have both loaded as doubles but we can skip the lhs nan check
   // since it's a smi.
@@ -1358,23 +1049,11 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
   }
 
   // Rhs is a smi, lhs is a heap number.
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    // Load the double from lhs, tagged HeapNumber r1, to d7.
-    __ sub(r7, lhs, Operand(kHeapObjectTag));
-    __ vldr(d7, r7, HeapNumber::kValueOffset);
-    // Convert rhs to a double in d6              .
-    __ SmiToDoubleVFPRegister(rhs, d6, r7, s13);
-  } else {
-    __ push(lr);
-    // Load lhs to a double in r2, r3.
-    __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset));
-    // Convert rhs to a double in r0, r1.
-    __ mov(r7, Operand(rhs));
-    ConvertToDoubleStub stub2(r1, r0, r7, r6);
-    __ Call(stub2.GetCode(masm->isolate()));
-    __ pop(lr);
-  }
+  // Load the double from lhs, tagged HeapNumber r1, to d7.
+  __ sub(r7, lhs, Operand(kHeapObjectTag));
+  __ vldr(d7, r7, HeapNumber::kValueOffset);
+  // Convert rhs to a double in d6              .
+  __ SmiToDoubleVFPRegister(rhs, d6, r7, s13);
   // Fall through to both_loaded_as_doubles.
 }
 
@@ -1431,60 +1110,6 @@ void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) {
 
 
 // See comment at call site.
-static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm,
-                                          Condition cond) {
-  bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
-  Register rhs_exponent = exp_first ? r0 : r1;
-  Register lhs_exponent = exp_first ? r2 : r3;
-  Register rhs_mantissa = exp_first ? r1 : r0;
-  Register lhs_mantissa = exp_first ? r3 : r2;
-
-  // r0, r1, r2, r3 have the two doubles.  Neither is a NaN.
-  if (cond == eq) {
-    // Doubles are not equal unless they have the same bit pattern.
-    // Exception: 0 and -0.
-    __ cmp(rhs_mantissa, Operand(lhs_mantissa));
-    __ orr(r0, rhs_mantissa, Operand(lhs_mantissa), LeaveCC, ne);
-    // Return non-zero if the numbers are unequal.
-    __ Ret(ne);
-
-    __ sub(r0, rhs_exponent, Operand(lhs_exponent), SetCC);
-    // If exponents are equal then return 0.
-    __ Ret(eq);
-
-    // Exponents are unequal.  The only way we can return that the numbers
-    // are equal is if one is -0 and the other is 0.  We already dealt
-    // with the case where both are -0 or both are 0.
-    // We start by seeing if the mantissas (that are equal) or the bottom
-    // 31 bits of the rhs exponent are non-zero.  If so we return not
-    // equal.
-    __ orr(r4, lhs_mantissa, Operand(lhs_exponent, LSL, kSmiTagSize), SetCC);
-    __ mov(r0, Operand(r4), LeaveCC, ne);
-    __ Ret(ne);
-    // Now they are equal if and only if the lhs exponent is zero in its
-    // low 31 bits.
-    __ mov(r0, Operand(rhs_exponent, LSL, kSmiTagSize));
-    __ Ret();
-  } else {
-    // Call a native function to do a comparison between two non-NaNs.
-    // Call C routine that may not cause GC or other trouble.
-    __ push(lr);
-    __ PrepareCallCFunction(0, 2, r5);
-    if (masm->use_eabi_hardfloat()) {
-      CpuFeatureScope scope(masm, VFP2);
-      __ vmov(d0, r0, r1);
-      __ vmov(d1, r2, r3);
-    }
-
-    AllowExternalCallThatCantCauseGC scope(masm);
-    __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()),
-                     0, 2);
-    __ pop(pc);  // Return.
-  }
-}
-
-
-// See comment at call site.
 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
                                            Register lhs,
                                            Register rhs) {
@@ -1547,16 +1172,10 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
 
   // Both are heap numbers.  Load them up then jump to the code we have
   // for that.
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    __ sub(r7, rhs, Operand(kHeapObjectTag));
-    __ vldr(d6, r7, HeapNumber::kValueOffset);
-    __ sub(r7, lhs, Operand(kHeapObjectTag));
-    __ vldr(d7, r7, HeapNumber::kValueOffset);
-  } else {
-    __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset));
-    __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset));
-  }
+  __ sub(r7, rhs, Operand(kHeapObjectTag));
+  __ vldr(d6, r7, HeapNumber::kValueOffset);
+  __ sub(r7, lhs, Operand(kHeapObjectTag));
+  __ vldr(d7, r7, HeapNumber::kValueOffset);
   __ jmp(both_loaded_as_doubles);
 }
 
@@ -1637,42 +1256,37 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
   Label load_result_from_cache;
   if (!object_is_smi) {
     __ JumpIfSmi(object, &is_smi);
-    if (CpuFeatures::IsSupported(VFP2)) {
-      CpuFeatureScope scope(masm, VFP2);
-      __ CheckMap(object,
-                  scratch1,
-                  Heap::kHeapNumberMapRootIndex,
-                  not_found,
-                  DONT_DO_SMI_CHECK);
-
-      STATIC_ASSERT(8 == kDoubleSize);
-      __ add(scratch1,
-             object,
-             Operand(HeapNumber::kValueOffset - kHeapObjectTag));
-      __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit());
-      __ eor(scratch1, scratch1, Operand(scratch2));
-      __ and_(scratch1, scratch1, Operand(mask));
-
-      // Calculate address of entry in string cache: each entry consists
-      // of two pointer sized fields.
-      __ add(scratch1,
-             number_string_cache,
-             Operand(scratch1, LSL, kPointerSizeLog2 + 1));
-
-      Register probe = mask;
-      __ ldr(probe,
-             FieldMemOperand(scratch1, FixedArray::kHeaderSize));
-      __ JumpIfSmi(probe, not_found);
-      __ sub(scratch2, object, Operand(kHeapObjectTag));
-      __ vldr(d0, scratch2, HeapNumber::kValueOffset);
-      __ sub(probe, probe, Operand(kHeapObjectTag));
-      __ vldr(d1, probe, HeapNumber::kValueOffset);
-      __ VFPCompareAndSetFlags(d0, d1);
-      __ b(ne, not_found);  // The cache did not contain this value.
-      __ b(&load_result_from_cache);
-    } else {
-      __ b(not_found);
-    }
+    __ CheckMap(object,
+                scratch1,
+                Heap::kHeapNumberMapRootIndex,
+                not_found,
+                DONT_DO_SMI_CHECK);
+
+    STATIC_ASSERT(8 == kDoubleSize);
+    __ add(scratch1,
+           object,
+           Operand(HeapNumber::kValueOffset - kHeapObjectTag));
+    __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit());
+    __ eor(scratch1, scratch1, Operand(scratch2));
+    __ and_(scratch1, scratch1, Operand(mask));
+
+    // Calculate address of entry in string cache: each entry consists
+    // of two pointer sized fields.
+    __ add(scratch1,
+           number_string_cache,
+           Operand(scratch1, LSL, kPointerSizeLog2 + 1));
+
+    Register probe = mask;
+    __ ldr(probe,
+           FieldMemOperand(scratch1, FixedArray::kHeaderSize));
+    __ JumpIfSmi(probe, not_found);
+    __ sub(scratch2, object, Operand(kHeapObjectTag));
+    __ vldr(d0, scratch2, HeapNumber::kValueOffset);
+    __ sub(probe, probe, Operand(kHeapObjectTag));
+    __ vldr(d1, probe, HeapNumber::kValueOffset);
+    __ VFPCompareAndSetFlags(d0, d1);
+    __ b(ne, not_found);  // The cache did not contain this value.
+    __ b(&load_result_from_cache);
   }
 
   __ bind(&is_smi);
@@ -1787,37 +1401,27 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
   // The arguments have been converted to doubles and stored in d6 and d7, if
   // VFP3 is supported, or in r0, r1, r2, and r3.
   Isolate* isolate = masm->isolate();
-  if (CpuFeatures::IsSupported(VFP2)) {
-    __ bind(&lhs_not_nan);
-    CpuFeatureScope scope(masm, VFP2);
-    Label no_nan;
-    // ARMv7 VFP3 instructions to implement double precision comparison.
-    __ VFPCompareAndSetFlags(d7, d6);
-    Label nan;
-    __ b(vs, &nan);
-    __ mov(r0, Operand(EQUAL), LeaveCC, eq);
-    __ mov(r0, Operand(LESS), LeaveCC, lt);
-    __ mov(r0, Operand(GREATER), LeaveCC, gt);
-    __ Ret();
+  __ bind(&lhs_not_nan);
+  Label no_nan;
+  // ARMv7 VFP3 instructions to implement double precision comparison.
+  __ VFPCompareAndSetFlags(d7, d6);
+  Label nan;
+  __ b(vs, &nan);
+  __ mov(r0, Operand(EQUAL), LeaveCC, eq);
+  __ mov(r0, Operand(LESS), LeaveCC, lt);
+  __ mov(r0, Operand(GREATER), LeaveCC, gt);
+  __ Ret();
 
-    __ bind(&nan);
-    // 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) {
-      __ mov(r0, Operand(GREATER));
-    } else {
-      __ mov(r0, Operand(LESS));
-    }
-    __ Ret();
+  __ bind(&nan);
+  // 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) {
+    __ mov(r0, Operand(GREATER));
   } 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);
-    // Compares two doubles in r0, r1, r2, r3 that are not NaNs.  Returns the
-    // answer.  Never falls through.
-    EmitTwoNonNanDoubleComparison(masm, cc);
+    __ mov(r0, Operand(LESS));
   }
+  __ Ret();
 
   __ bind(&not_smis);
   // At this point we know we are dealing with two different objects,
@@ -1914,7 +1518,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
   // we cannot call anything that could cause a GC from this stub.
   Label patch;
   const Register map = r9.is(tos_) ? r7 : r9;
-  const Register temp = map;
 
   // undefined -> false.
   CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
@@ -1957,9 +1560,9 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
 
   if (types_.Contains(STRING)) {
     // String value -> false iff empty.
-  __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
-  __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
-  __ Ret(lt);  // the string length is OK as the return value
+    __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
+    __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
+    __ Ret(lt);  // the string length is OK as the return value
   }
 
   if (types_.Contains(HEAP_NUMBER)) {
@@ -1968,55 +1571,13 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
     __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
     __ b(ne, &not_heap_number);
 
-    if (CpuFeatures::IsSupported(VFP2)) {
-      CpuFeatureScope scope(masm, VFP2);
-
-      __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
-      __ VFPCompareAndSetFlags(d1, 0.0);
-      // "tos_" is a register, and contains a non zero value by default.
-      // Hence we only need to overwrite "tos_" with zero to return false for
-      // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
-      __ mov(tos_, Operand::Zero(), LeaveCC, eq);  // for FP_ZERO
-      __ mov(tos_, Operand::Zero(), LeaveCC, vs);  // for FP_NAN
-    } else {
-      Label done, not_nan, not_zero;
-      __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
-      // -0 maps to false:
-      __ bic(
-          temp, temp, Operand(HeapNumber::kSignMask, RelocInfo::NONE32), SetCC);
-      __ b(ne, &not_zero);
-      // If exponent word is zero then the answer depends on the mantissa word.
-      __ ldr(tos_, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
-      __ jmp(&done);
-
-      // Check for NaN.
-      __ bind(&not_zero);
-      // We already zeroed the sign bit, now shift out the mantissa so we only
-      // have the exponent left.
-      __ mov(temp, Operand(temp, LSR, HeapNumber::kMantissaBitsInTopWord));
-      unsigned int shifted_exponent_mask =
-          HeapNumber::kExponentMask >> HeapNumber::kMantissaBitsInTopWord;
-      __ cmp(temp, Operand(shifted_exponent_mask, RelocInfo::NONE32));
-      __ b(ne, &not_nan);  // If exponent is not 0x7ff then it can't be a NaN.
-
-      // Reload exponent word.
-      __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
-      __ tst(temp, Operand(HeapNumber::kMantissaMask, RelocInfo::NONE32));
-      // If mantissa is not zero then we have a NaN, so return 0.
-      __ mov(tos_, Operand::Zero(), LeaveCC, ne);
-      __ b(ne, &done);
-
-      // Load mantissa word.
-      __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
-      __ cmp(temp, Operand::Zero());
-      // If mantissa is not zero then we have a NaN, so return 0.
-      __ mov(tos_, Operand::Zero(), LeaveCC, ne);
-      __ b(ne, &done);
-
-      __ bind(&not_nan);
-      __ mov(tos_, Operand(1, RelocInfo::NONE32));
-      __ bind(&done);
-    }
+    __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
+    __ VFPCompareAndSetFlags(d1, 0.0);
+    // "tos_" is a register, and contains a non zero value by default.
+    // Hence we only need to overwrite "tos_" with zero to return false for
+    // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
+    __ mov(tos_, Operand::Zero(), LeaveCC, eq);  // for FP_ZERO
+    __ mov(tos_, Operand::Zero(), LeaveCC, vs);  // for FP_NAN
     __ Ret();
     __ bind(&not_heap_number);
   }
@@ -2069,7 +1630,6 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
   const Register scratch = r1;
 
   if (save_doubles_ == kSaveFPRegs) {
-    CpuFeatureScope scope(masm, VFP2);
     // Check CPU flags for number of registers, setting the Z condition flag.
     __ CheckFor32DRegs(scratch);
 
@@ -2089,8 +1649,6 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
       ExternalReference::store_buffer_overflow_function(masm->isolate()),
       argument_count);
   if (save_doubles_ == kSaveFPRegs) {
-    CpuFeatureScope scope(masm, VFP2);
-
     // Check CPU flags for number of registers, setting the Z condition flag.
     __ CheckFor32DRegs(scratch);
 
@@ -2315,19 +1873,10 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
     __ bind(&heapnumber_allocated);
   }
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    // Convert the int32 in r1 to the heap number in r0. r2 is corrupted.
-    CpuFeatureScope scope(masm, VFP2);
-    __ vmov(s0, r1);
-    __ vcvt_f64_s32(d0, s0);
-    __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
-    __ Ret();
-  } else {
-    // WriteInt32ToHeapNumberStub does not trigger GC, so we do not
-    // have to set up a frame.
-    WriteInt32ToHeapNumberStub stub(r1, r0, r2);
-    __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
-  }
+  __ vmov(s0, r1);
+  __ vcvt_f64_s32(d0, s0);
+  __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
+  __ Ret();
 }
 
 
@@ -2383,7 +1932,7 @@ void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
 
 
 void BinaryOpStub::Initialize() {
-  platform_specific_bit_ = CpuFeatures::IsSupported(VFP2);
+  platform_specific_bit_ = true;  // VFP2 is a base requirement for V8
 }
 
 
@@ -2662,7 +2211,6 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
       // Load left and right operands into d6 and d7 or r0/r1 and r2/r3
       // depending on whether VFP3 is available or not.
       FloatingPointHelper::Destination destination =
-          CpuFeatures::IsSupported(VFP2) &&
           op != Token::MOD ?
           FloatingPointHelper::kVFPRegisters :
           FloatingPointHelper::kCoreRegisters;
@@ -2706,7 +2254,6 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
         // Using VFP registers:
         // d6: Left value
         // d7: Right value
-        CpuFeatureScope scope(masm, VFP2);
         switch (op) {
           case Token::ADD:
             __ vadd(d5, d6, d7);
@@ -2797,11 +2344,7 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
           // The code below for writing into heap numbers isn't capable of
           // writing the register as an unsigned int so we go to slow case if we
           // hit this case.
-          if (CpuFeatures::IsSupported(VFP2)) {
-            __ b(mi, &result_not_a_smi);
-          } else {
-            __ b(mi, not_numbers);
-          }
+          __ b(mi, &result_not_a_smi);
           break;
         case Token::SHL:
           // Use only the 5 least significant bits of the shift count.
@@ -2837,25 +2380,17 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
       // result.
       __ mov(r0, Operand(r5));
 
-      if (CpuFeatures::IsSupported(VFP2)) {
-        // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
-        // mentioned above SHR needs to always produce a positive result.
-        CpuFeatureScope scope(masm, VFP2);
-        __ vmov(s0, r2);
-        if (op == Token::SHR) {
-          __ vcvt_f64_u32(d0, s0);
-        } else {
-          __ vcvt_f64_s32(d0, s0);
-        }
-        __ sub(r3, r0, Operand(kHeapObjectTag));
-        __ vstr(d0, r3, HeapNumber::kValueOffset);
-        __ Ret();
+      // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
+      // mentioned above SHR needs to always produce a positive result.
+      __ vmov(s0, r2);
+      if (op == Token::SHR) {
+        __ vcvt_f64_u32(d0, s0);
       } else {
-        // Tail call that writes the int32 in r2 to the heap number in r0, using
-        // r3 as scratch. r0 is preserved and returned.
-        WriteInt32ToHeapNumberStub stub(r2, r0, r3);
-        __ TailCallStub(&stub);
+        __ vcvt_f64_s32(d0, s0);
       }
+      __ sub(r3, r0, Operand(kHeapObjectTag));
+      __ vstr(d0, r3, HeapNumber::kValueOffset);
+      __ Ret();
       break;
     }
     default:
@@ -3001,8 +2536,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
       // 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.
-      FloatingPointHelper::Destination destination =
-          (CpuFeatures::IsSupported(VFP2) && op_ != Token::MOD)
+      FloatingPointHelper::Destination destination = (op_ != Token::MOD)
               ? FloatingPointHelper::kVFPRegisters
               : FloatingPointHelper::kCoreRegisters;
 
@@ -3032,7 +2566,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
                                                    &transition);
 
       if (destination == FloatingPointHelper::kVFPRegisters) {
-        CpuFeatureScope scope(masm, VFP2);
         Label return_heap_number;
         switch (op_) {
           case Token::ADD:
@@ -3200,17 +2733,9 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
           // We only get a negative result if the shift value (r2) is 0.
           // This result cannot be respresented as a signed 32-bit integer, try
           // to return a heap number if we can.
-          // The non vfp2 code does not support this special case, so jump to
-          // runtime if we don't support it.
-          if (CpuFeatures::IsSupported(VFP2)) {
-            __ b(mi, (result_type_ <= BinaryOpIC::INT32)
-                      ? &transition
-                      : &return_heap_number);
-          } else {
-            __ b(mi, (result_type_ <= BinaryOpIC::INT32)
-                      ? &transition
-                      : &call_runtime);
-          }
+          __ b(mi, (result_type_ <= BinaryOpIC::INT32)
+               ? &transition
+               : &return_heap_number);
           break;
         case Token::SHL:
           __ and_(r2, r2, Operand(0x1f));
@@ -3238,31 +2763,22 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
                                                 &call_runtime,
                                                 mode_);
 
-      if (CpuFeatures::IsSupported(VFP2)) {
-        CpuFeatureScope scope(masm, VFP2);
-        if (op_ != Token::SHR) {
-          // Convert the result to a floating point value.
-          __ vmov(double_scratch.low(), r2);
-          __ vcvt_f64_s32(double_scratch, double_scratch.low());
-        } else {
-          // The result must be interpreted as an unsigned 32-bit integer.
-          __ vmov(double_scratch.low(), r2);
-          __ vcvt_f64_u32(double_scratch, double_scratch.low());
-        }
-
-        // Store the result.
-        __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
-        __ vstr(double_scratch, r0, HeapNumber::kValueOffset);
-        __ mov(r0, heap_number_result);
-        __ Ret();
+      if (op_ != Token::SHR) {
+        // Convert the result to a floating point value.
+        __ vmov(double_scratch.low(), r2);
+        __ vcvt_f64_s32(double_scratch, double_scratch.low());
       } else {
-        // Tail call that writes the int32 in r2 to the heap number in r0, using
-        // r3 as scratch. r0 is preserved and returned.
-        __ mov(r0, r5);
-        WriteInt32ToHeapNumberStub stub(r2, r0, r3);
-        __ TailCallStub(&stub);
+        // The result must be interpreted as an unsigned 32-bit integer.
+        __ vmov(double_scratch.low(), r2);
+        __ vcvt_f64_u32(double_scratch, double_scratch.low());
       }
 
+      // Store the result.
+      __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
+      __ vstr(double_scratch, r0, HeapNumber::kValueOffset);
+      __ mov(r0, heap_number_result);
+      __ Ret();
+
       break;
     }
 
@@ -3441,100 +2957,96 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
   const Register cache_entry = r0;
   const bool tagged = (argument_type_ == TAGGED);
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    if (tagged) {
-      // Argument is a number and is on stack and in r0.
-      // Load argument and check if it is a smi.
-      __ JumpIfNotSmi(r0, &input_not_smi);
-
-      // Input is a smi. Convert to double and load the low and high words
-      // of the double into r2, r3.
-      __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
-      __ b(&loaded);
-
-      __ bind(&input_not_smi);
-      // Check if input is a HeapNumber.
-      __ CheckMap(r0,
-                  r1,
-                  Heap::kHeapNumberMapRootIndex,
-                  &calculate,
-                  DONT_DO_SMI_CHECK);
-      // Input is a HeapNumber. Load it to a double register and store the
-      // low and high words into r2, r3.
-      __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
-      __ vmov(r2, r3, d0);
-    } else {
-      // Input is untagged double in d2. Output goes to d2.
-      __ vmov(r2, r3, d2);
-    }
-    __ bind(&loaded);
-    // r2 = low 32 bits of double value
-    // r3 = high 32 bits of double value
-    // Compute hash (the shifts are arithmetic):
-    //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
-    __ eor(r1, r2, Operand(r3));
-    __ eor(r1, r1, Operand(r1, ASR, 16));
-    __ eor(r1, r1, Operand(r1, ASR, 8));
-    ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
-    __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
-
-    // r2 = low 32 bits of double value.
-    // r3 = high 32 bits of double value.
-    // r1 = TranscendentalCache::hash(double value).
-    Isolate* isolate = masm->isolate();
-    ExternalReference cache_array =
-        ExternalReference::transcendental_cache_array_address(isolate);
-    __ mov(cache_entry, Operand(cache_array));
-    // cache_entry points to cache array.
-    int cache_array_index
-        = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
-    __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
-    // r0 points to the cache for the type type_.
-    // If NULL, the cache hasn't been initialized yet, so go through runtime.
-    __ cmp(cache_entry, Operand::Zero());
-    __ b(eq, &invalid_cache);
+  if (tagged) {
+    // Argument is a number and is on stack and in r0.
+    // Load argument and check if it is a smi.
+    __ JumpIfNotSmi(r0, &input_not_smi);
+
+    // Input is a smi. Convert to double and load the low and high words
+    // of the double into r2, r3.
+    __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
+    __ b(&loaded);
+
+    __ bind(&input_not_smi);
+    // Check if input is a HeapNumber.
+    __ CheckMap(r0,
+                r1,
+                Heap::kHeapNumberMapRootIndex,
+                &calculate,
+                DONT_DO_SMI_CHECK);
+    // Input is a HeapNumber. Load it to a double register and store the
+    // low and high words into r2, r3.
+    __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
+    __ vmov(r2, r3, d0);
+  } else {
+    // Input is untagged double in d2. Output goes to d2.
+    __ vmov(r2, r3, d2);
+  }
+  __ bind(&loaded);
+  // r2 = low 32 bits of double value
+  // r3 = high 32 bits of double value
+  // Compute hash (the shifts are arithmetic):
+  //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
+  __ eor(r1, r2, Operand(r3));
+  __ eor(r1, r1, Operand(r1, ASR, 16));
+  __ eor(r1, r1, Operand(r1, ASR, 8));
+  ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
+  __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
+
+  // r2 = low 32 bits of double value.
+  // r3 = high 32 bits of double value.
+  // r1 = TranscendentalCache::hash(double value).
+  Isolate* isolate = masm->isolate();
+  ExternalReference cache_array =
+      ExternalReference::transcendental_cache_array_address(isolate);
+  __ mov(cache_entry, Operand(cache_array));
+  // cache_entry points to cache array.
+  int cache_array_index
+      = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
+  __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
+  // r0 points to the cache for the type type_.
+  // If NULL, the cache hasn't been initialized yet, so go through runtime.
+  __ cmp(cache_entry, Operand::Zero());
+  __ b(eq, &invalid_cache);
 
 #ifdef DEBUG
-    // Check that the layout of cache elements match expectations.
-    { TranscendentalCache::SubCache::Element test_elem[2];
-      char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
-      char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
-      char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
-      char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
-      char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
-      CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer.
-      CHECK_EQ(0, elem_in0 - elem_start);
-      CHECK_EQ(kIntSize, elem_in1 - elem_start);
-      CHECK_EQ(2 * kIntSize, elem_out - elem_start);
-    }
+  // Check that the layout of cache elements match expectations.
+  { TranscendentalCache::SubCache::Element test_elem[2];
+    char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
+    char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
+    char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
+    char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
+    char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
+    CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer.
+    CHECK_EQ(0, elem_in0 - elem_start);
+    CHECK_EQ(kIntSize, elem_in1 - elem_start);
+    CHECK_EQ(2 * kIntSize, elem_out - elem_start);
+  }
 #endif
 
-    // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
-    __ add(r1, r1, Operand(r1, LSL, 1));
-    __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
-    // Check if cache matches: Double value is stored in uint32_t[2] array.
-    __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
-    __ cmp(r2, r4);
-    __ cmp(r3, r5, eq);
-    __ b(ne, &calculate);
-    // Cache hit. Load result, cleanup and return.
-    Counters* counters = masm->isolate()->counters();
-    __ IncrementCounter(
-        counters->transcendental_cache_hit(), 1, scratch0, scratch1);
-    if (tagged) {
-      // Pop input value from stack and load result into r0.
-      __ pop();
-      __ mov(r0, Operand(r6));
-    } else {
-      // Load result into d2.
-       __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
-    }
-    __ Ret();
-  }  // if (CpuFeatures::IsSupported(VFP3))
+  // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
+  __ add(r1, r1, Operand(r1, LSL, 1));
+  __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
+  // Check if cache matches: Double value is stored in uint32_t[2] array.
+  __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
+  __ cmp(r2, r4);
+  __ cmp(r3, r5, eq);
+  __ b(ne, &calculate);
+  // Cache hit. Load result, cleanup and return.
+  Counters* counters = masm->isolate()->counters();
+  __ IncrementCounter(
+      counters->transcendental_cache_hit(), 1, scratch0, scratch1);
+  if (tagged) {
+    // Pop input value from stack and load result into r0.
+    __ pop();
+    __ mov(r0, Operand(r6));
+  } else {
+    // Load result into d2.
+    __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
+  }
+  __ Ret();
 
   __ bind(&calculate);
-  Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(
       counters->transcendental_cache_miss(), 1, scratch0, scratch1);
   if (tagged) {
@@ -3543,9 +3055,6 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
         ExternalReference(RuntimeFunction(), masm->isolate());
     __ TailCallExternalReference(runtime_function, 1, 1);
   } else {
-    ASSERT(CpuFeatures::IsSupported(VFP2));
-    CpuFeatureScope scope(masm, VFP2);
-
     Label no_update;
     Label skip_cache;
 
@@ -3605,7 +3114,6 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
 
 void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
                                                     Register scratch) {
-  ASSERT(masm->IsEnabled(VFP2));
   Isolate* isolate = masm->isolate();
 
   __ push(lr);
@@ -3666,7 +3174,6 @@ void InterruptStub::Generate(MacroAssembler* masm) {
 
 
 void MathPowStub::Generate(MacroAssembler* masm) {
-  CpuFeatureScope vfp2_scope(masm, VFP2);
   const Register base = r1;
   const Register exponent = r2;
   const Register heapnumbermap = r5;
@@ -3879,14 +3386,13 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   CEntryStub::GenerateAheadOfTime(isolate);
   WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
   StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+  StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
 }
 
 
 void CodeStub::GenerateFPStubs(Isolate* isolate) {
-  SaveFPRegsMode mode = CpuFeatures::IsSupported(VFP2)
-      ? kSaveFPRegs
-      : kDontSaveFPRegs;
+  SaveFPRegsMode mode = kSaveFPRegs;
   CEntryStub save_doubles(1, mode);
   StoreBufferOverflowStub stub(mode);
   // These stubs might already be in the snapshot, detect that and don't
@@ -3895,11 +3401,13 @@ void CodeStub::GenerateFPStubs(Isolate* isolate) {
   Code* save_doubles_code;
   if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
     save_doubles_code = *save_doubles.GetCode(isolate);
-    save_doubles_code->set_is_pregenerated(true);
-
-    Code* store_buffer_overflow_code = *stub.GetCode(isolate);
-    store_buffer_overflow_code->set_is_pregenerated(true);
   }
+  Code* store_buffer_overflow_code;
+  if (!stub.FindCodeInCache(&store_buffer_overflow_code, isolate)) {
+      store_buffer_overflow_code = *stub.GetCode(isolate);
+  }
+  save_doubles_code->set_is_pregenerated(true);
+  store_buffer_overflow_code->set_is_pregenerated(true);
   isolate->set_fp_stubs_generated(true);
 }
 
@@ -3989,6 +3497,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
     masm->Jump(r5);
   }
 
+  __ VFPEnsureFPSCRState(r2);
+
   if (always_allocate) {
     // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
     // though (contain the result).
@@ -4024,11 +3534,18 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   // Special handling of out of memory exceptions.
   JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
 
-  // Retrieve the pending exception and clear the variable.
-  __ mov(r3, Operand(isolate->factory()->the_hole_value()));
+  // Retrieve the pending exception.
   __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
                                        isolate)));
   __ ldr(r0, MemOperand(ip));
+
+  // See if we just retrieved an OOM exception.
+  JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
+
+  // Clear the pending exception.
+  __ mov(r3, Operand(isolate->factory()->the_hole_value()));
+  __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                       isolate)));
   __ str(r3, MemOperand(ip));
 
   // Special handling of termination exceptions which are uncatchable
@@ -4146,13 +3663,11 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
   // Save callee-saved registers (incl. cp and fp), sp, and lr
   __ stm(db_w, sp, kCalleeSaved | lr.bit());
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    // Save callee-saved vfp registers.
-    __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
-    // Set up the reserved register for 0.0.
-    __ vmov(kDoubleRegZero, 0.0);
-  }
+  // Save callee-saved vfp registers.
+  __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
+  // Set up the reserved register for 0.0.
+  __ vmov(kDoubleRegZero, 0.0);
+  __ VFPEnsureFPSCRState(r4);
 
   // Get address of argv, see stm above.
   // r0: code entry
@@ -4162,9 +3677,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
 
   // Set up argv in r4.
   int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
-  if (CpuFeatures::IsSupported(VFP2)) {
-    offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
-  }
+  offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
   __ ldr(r4, MemOperand(sp, offset_to_argv));
 
   // Push a frame with special values setup to mark it as an entry frame.
@@ -4300,11 +3813,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
   }
 #endif
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    // Restore callee-saved vfp registers.
-    __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
-  }
+  // Restore callee-saved vfp registers.
+  __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
 
   __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
 }
@@ -4948,7 +4458,7 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
       Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX)));
 
   // Copy the JS object part.
-  __ CopyFields(r0, r4, r3.bit(), JSObject::kHeaderSize / kPointerSize);
+  __ CopyFields(r0, r4, d0, s0, JSObject::kHeaderSize / kPointerSize);
 
   // Get the length (smi tagged) and set that as an in-object property too.
   STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
@@ -7009,50 +6519,46 @@ void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
   }
 
   // Inlining the double comparison and falling back to the general compare
-  // stub if NaN is involved or VFP2 is unsupported.
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-
-    // 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);
+  // stub if NaN is involved.
+  // 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);
 
-    __ bind(&done);
-    // Compare operands.
-    __ VFPCompareAndSetFlags(d0, d1);
+  __ bind(&done);
+  // Compare operands.
+  __ VFPCompareAndSetFlags(d0, d1);
 
-    // Don't base result on status bits when a NaN is involved.
-    __ b(vs, &unordered);
+  // Don't base result on status bits when a NaN is involved.
+  __ b(vs, &unordered);
 
-    // Return a result of -1, 0, or 1, based on status bits.
-    __ mov(r0, Operand(EQUAL), LeaveCC, eq);
-    __ mov(r0, Operand(LESS), LeaveCC, lt);
-    __ mov(r0, Operand(GREATER), LeaveCC, gt);
-    __ Ret();
-  }
+  // Return a result of -1, 0, or 1, based on status bits.
+  __ mov(r0, Operand(EQUAL), LeaveCC, eq);
+  __ mov(r0, Operand(LESS), LeaveCC, lt);
+  __ mov(r0, Operand(GREATER), LeaveCC, gt);
+  __ Ret();
 
   __ bind(&unordered);
   __ bind(&generic_stub);
@@ -7343,6 +6849,7 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
   __ Jump(target);  // Call the C++ function.
   ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta,
             masm->SizeOfCodeGeneratedSince(&start));
+  __ VFPEnsureFPSCRState(r2);
 }
 
 
@@ -7662,11 +7169,6 @@ bool RecordWriteStub::IsPregenerated() {
 }
 
 
-bool StoreBufferOverflowStub::IsPregenerated() {
-  return save_doubles_ == kDontSaveFPRegs || ISOLATE->fp_stubs_generated();
-}
-
-
 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
     Isolate* isolate) {
   StoreBufferOverflowStub stub1(kDontSaveFPRegs);
@@ -7689,7 +7191,7 @@ void RecordWriteStub::GenerateFixedRegStubsAheadOfTime(Isolate* isolate) {
 
 
 bool CodeStub::CanUseFPRegisters() {
-  return CpuFeatures::IsSupported(VFP2);
+  return true;  // VFP2 is a base requirement for V8
 }
 
 
@@ -7948,16 +7450,14 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
   __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
   __ StoreNumberToDoubleElements(r0, r3,
                                  // Overwrites all regs after this.
-                                 r5, r6, r7, r9, r2,
+                                 r5, r9, r6, r7, r2,
                                  &slow_elements);
   __ Ret();
 }
 
 
 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
-  ASSERT(!Serializer::enabled());
-  bool save_fp_regs = CpuFeatures::IsSupported(VFP2);
-  CEntryStub ces(1, save_fp_regs ? kSaveFPRegs : kDontSaveFPRegs);
+  CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
   __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
   int parameter_count_offset =
       StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
index 61ecc97..741ff9c 100644 (file)
@@ -61,11 +61,11 @@ class TranscendentalCacheStub: public PlatformCodeStub {
 class StoreBufferOverflowStub: public PlatformCodeStub {
  public:
   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
-      : save_doubles_(save_fp) { }
+      : save_doubles_(save_fp) {}
 
   void Generate(MacroAssembler* masm);
 
-  virtual bool IsPregenerated();
+  virtual bool IsPregenerated() { return true; }
   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
   virtual bool SometimesSetsUpAFrame() { return false; }
 
@@ -471,7 +471,6 @@ class RecordWriteStub: public PlatformCodeStub {
       if (mode == kSaveFPRegs) {
         // Number of d-regs not known at snapshot time.
         ASSERT(!Serializer::enabled());
-        CpuFeatureScope scope(masm, VFP2);
         masm->sub(sp,
                   sp,
                   Operand(kDoubleSize * (DwVfpRegister::NumRegisters() - 1)));
@@ -489,7 +488,6 @@ class RecordWriteStub: public PlatformCodeStub {
       if (mode == kSaveFPRegs) {
         // Number of d-regs not known at snapshot time.
         ASSERT(!Serializer::enabled());
-        CpuFeatureScope scope(masm, VFP2);
         // Restore all VFP registers except d0.
         // TODO(hans): We should probably restore d0 too. And maybe use vldm.
         for (int i = DwVfpRegister::NumRegisters() - 1; i > 0; i--) {
index 1c82946..9d773d4 100644 (file)
@@ -62,7 +62,6 @@ double fast_exp_simulator(double x) {
 
 
 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));
@@ -72,7 +71,6 @@ UnaryMathFunction CreateExpFunction() {
   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
 
   {
-    CpuFeatureScope use_vfp(&masm, VFP2);
     DwVfpRegister input = d0;
     DwVfpRegister result = d1;
     DwVfpRegister double_scratch1 = d2;
@@ -185,7 +183,6 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   //  -- r4    : scratch (elements)
   // -----------------------------------
   Label loop, entry, convert_hole, gc_required, only_change_map, done;
-  bool vfp2_supported = CpuFeatures::IsSupported(VFP2);
 
   if (mode == TRACK_ALLOCATION_SITE) {
     __ TestJSArrayForAllocationSiteInfo(r2, r4);
@@ -248,7 +245,6 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   // r5: kHoleNanUpper32
   // r6: end of destination FixedDoubleArray, not tagged
   // r7: begin of FixedDoubleArray element fields, not tagged
-  if (!vfp2_supported) __ Push(r1, r0);
 
   __ b(&entry);
 
@@ -276,23 +272,10 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   __ UntagAndJumpIfNotSmi(r9, r9, &convert_hole);
 
   // Normal smi, convert to double and store.
-  if (vfp2_supported) {
-    CpuFeatureScope scope(masm, VFP2);
-    __ vmov(s0, r9);
-    __ vcvt_f64_s32(d0, s0);
-    __ vstr(d0, r7, 0);
-    __ add(r7, r7, Operand(8));
-  } else {
-    FloatingPointHelper::ConvertIntToDouble(masm,
-                                            r9,
-                                            FloatingPointHelper::kCoreRegisters,
-                                            d0,
-                                            r0,
-                                            r1,
-                                            lr,
-                                            s0);
-    __ Strd(r0, r1, MemOperand(r7, 8, PostIndex));
-  }
+  __ vmov(s0, r9);
+  __ vcvt_f64_s32(d0, s0);
+  __ vstr(d0, r7, 0);
+  __ add(r7, r7, Operand(8));
   __ b(&entry);
 
   // Hole found, store the-hole NaN.
@@ -310,7 +293,6 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   __ cmp(r7, r6);
   __ b(lt, &loop);
 
-  if (!vfp2_supported) __ Pop(r1, r0);
   __ pop(lr);
   __ bind(&done);
 }
index cdca1f5..a130484 100644 (file)
@@ -51,7 +51,7 @@ double Instruction::DoubleImmedVmov() const {
 
   uint64_t imm = high16 << 48;
   double d;
-  memcpy(&d, &imm, 8);
+  OS::MemCopy(&d, &imm, 8);
   return d;
 }
 
index 004165a..747dc56 100644 (file)
     defined(__ARM_ARCH_7R__) || \
     defined(__ARM_ARCH_7__)
 # define CAN_USE_ARMV7_INSTRUCTIONS 1
+#ifndef CAN_USE_VFP3_INSTRUCTIONS
+# define CAN_USE_VFP3_INSTRUCTIONS
+#endif
 #endif
 
-#if defined(__ARM_ARCH_6__) ||   \
-    defined(__ARM_ARCH_6J__) ||  \
-    defined(__ARM_ARCH_6K__) ||  \
-    defined(__ARM_ARCH_6Z__) ||  \
+#if defined(__ARM_ARCH_6__)   ||   \
+    defined(__ARM_ARCH_6J__)  ||  \
+    defined(__ARM_ARCH_6K__)  ||  \
+    defined(__ARM_ARCH_6Z__)  ||  \
     defined(__ARM_ARCH_6ZK__) || \
     defined(__ARM_ARCH_6T2__) || \
     defined(CAN_USE_ARMV7_INSTRUCTIONS)
 # define CAN_USE_ARMV6_INSTRUCTIONS 1
 #endif
 
-#if defined(__ARM_ARCH_5T__)             || \
-    defined(__ARM_ARCH_5TE__)            || \
-    defined(__ARM_ARCH_5TEJ__)           || \
+#if defined(__ARM_ARCH_5__)    || \
+    defined(__ARM_ARCH_5T__)   || \
+    defined(__ARM_ARCH_5TE__)  || \
+    defined(__ARM_ARCH_5TEJ__) || \
     defined(CAN_USE_ARMV6_INSTRUCTIONS)
 # define CAN_USE_ARMV5_INSTRUCTIONS 1
 # define CAN_USE_THUMB_INSTRUCTIONS 1
@@ -403,6 +407,7 @@ const uint32_t kVFPOverflowExceptionBit = 1 << 2;
 const uint32_t kVFPUnderflowExceptionBit = 1 << 3;
 const uint32_t kVFPInexactExceptionBit = 1 << 4;
 const uint32_t kVFPFlushToZeroMask = 1 << 24;
+const uint32_t kVFPDefaultNaNModeControlBit = 1 << 25;
 
 const uint32_t kVFPNConditionFlagBit = 1 << 31;
 const uint32_t kVFPZConditionFlagBit = 1 << 30;
index 9bcc1ac..25ad85c 100644 (file)
@@ -117,45 +117,39 @@ void Deoptimizer::DeoptimizeFunctionWithPreparedFunctionList(
 
 static const int32_t kBranchBeforeInterrupt =  0x5a000004;
 
-
-void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
-                                        Address pc_after,
-                                        Code* check_code,
-                                        Code* replacement_code) {
-  const int kInstrSize = Assembler::kInstrSize;
-  // 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)));
-  ASSERT_EQ(kBranchBeforeInterrupt,
-            Memory::int32_at(pc_after - 3 * kInstrSize));
-
-  // We patch the code to the following form:
-  //
-  //  <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
-  // and overwrite the constant containing the
-  // address of the stack check stub.
-
-  // Replace conditional jump with NOP.
+// The back edge bookkeeping code matches the pattern:
+//
+//  <decrement profiling counter>
+//  2a 00 00 01       bpl ok
+//  e5 9f c? ??       ldr ip, [pc, <interrupt stub address>]
+//  e1 2f ff 3c       blx ip
+//  ok-label
+//
+// We patch the code to the following form:
+//
+//  <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
+//  ok-label
+
+void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
+                                       Address pc_after,
+                                       Code* interrupt_code,
+                                       Code* replacement_code) {
+  ASSERT(!InterruptCodeIsPatched(unoptimized_code,
+                                 pc_after,
+                                 interrupt_code,
+                                 replacement_code));
+  static const int kInstrSize = Assembler::kInstrSize;
+  // Turn the jump into nops.
   CodePatcher patcher(pc_after - 3 * kInstrSize, 1);
   patcher.masm()->nop();
-
-  // Replace the stack check address in the constant pool
-  // with the entry address of the replacement code.
-  uint32_t stack_check_address_offset = Memory::uint16_at(pc_after -
+  // Replace the call address.
+  uint32_t interrupt_address_offset = Memory::uint16_at(pc_after -
       2 * kInstrSize) & 0xfff;
-  Address stack_check_address_pointer = pc_after + stack_check_address_offset;
-  ASSERT(Memory::uint32_at(stack_check_address_pointer) ==
-         reinterpret_cast<uint32_t>(check_code->entry()));
-  Memory::uint32_at(stack_check_address_pointer) =
+  Address interrupt_address_pointer = pc_after + interrupt_address_offset;
+  Memory::uint32_at(interrupt_address_pointer) =
       reinterpret_cast<uint32_t>(replacement_code->entry());
 
   unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
@@ -163,34 +157,61 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
 }
 
 
-void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
+void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
+                                        Address pc_after,
+                                        Code* interrupt_code,
+                                        Code* replacement_code) {
+  ASSERT(InterruptCodeIsPatched(unoptimized_code,
+                                pc_after,
+                                interrupt_code,
+                                replacement_code));
+  static const int kInstrSize = Assembler::kInstrSize;
+  // Restore the original jump.
+  CodePatcher patcher(pc_after - 3 * kInstrSize, 1);
+  patcher.masm()->b(4 * kInstrSize, pl);  // ok-label is 4 instructions later.
+  ASSERT_EQ(kBranchBeforeInterrupt,
+            Memory::int32_at(pc_after - 3 * kInstrSize));
+  // Restore the original call address.
+  uint32_t interrupt_address_offset = Memory::uint16_at(pc_after -
+      2 * kInstrSize) & 0xfff;
+  Address interrupt_address_pointer = pc_after + interrupt_address_offset;
+  Memory::uint32_at(interrupt_address_pointer) =
+      reinterpret_cast<uint32_t>(interrupt_code->entry());
+
+  interrupt_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+      unoptimized_code, pc_after - 2 * kInstrSize, interrupt_code);
+}
+
+
+#ifdef DEBUG
+bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
                                          Address pc_after,
-                                         Code* check_code,
+                                         Code* interrupt_code,
                                          Code* replacement_code) {
-  const int kInstrSize = Assembler::kInstrSize;
+  static const int kInstrSize = Assembler::kInstrSize;
   ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp);
-  ASSERT(Assembler::IsLdrPcImmediateOffset(
-      Assembler::instr_at(pc_after - 2 * kInstrSize)));
 
-  // Replace NOP with conditional jump.
-  CodePatcher patcher(pc_after - 3 * kInstrSize, 1);
-  patcher.masm()->b(+16, pl);
-  ASSERT_EQ(kBranchBeforeInterrupt,
-            Memory::int32_at(pc_after - 3 * kInstrSize));
+  uint32_t interrupt_address_offset =
+      Memory::uint16_at(pc_after - 2 * kInstrSize) & 0xfff;
+  Address interrupt_address_pointer = pc_after + interrupt_address_offset;
 
-  // Replace the stack check address in the constant pool
-  // with the entry address of the replacement code.
-  uint32_t stack_check_address_offset = Memory::uint16_at(pc_after -
-      2 * kInstrSize) & 0xfff;
-  Address stack_check_address_pointer = pc_after + stack_check_address_offset;
-  ASSERT(Memory::uint32_at(stack_check_address_pointer) ==
-         reinterpret_cast<uint32_t>(replacement_code->entry()));
-  Memory::uint32_at(stack_check_address_pointer) =
-      reinterpret_cast<uint32_t>(check_code->entry());
-
-  check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
-      unoptimized_code, pc_after - 2 * kInstrSize, check_code);
+  if (Assembler::IsNop(Assembler::instr_at(pc_after - 3 * kInstrSize))) {
+    ASSERT(Assembler::IsLdrPcImmediateOffset(
+        Assembler::instr_at(pc_after - 2 * kInstrSize)));
+    ASSERT(reinterpret_cast<uint32_t>(replacement_code->entry()) ==
+           Memory::uint32_at(interrupt_address_pointer));
+    return true;
+  } else {
+    ASSERT(Assembler::IsLdrPcImmediateOffset(
+        Assembler::instr_at(pc_after - 2 * kInstrSize)));
+    ASSERT_EQ(kBranchBeforeInterrupt,
+              Memory::int32_at(pc_after - 3 * kInstrSize));
+    ASSERT(reinterpret_cast<uint32_t>(interrupt_code->entry()) ==
+           Memory::uint32_at(interrupt_address_pointer));
+    return false;
+  }
 }
+#endif  // DEBUG
 
 
 static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
@@ -594,23 +615,18 @@ void Deoptimizer::EntryGenerator::Generate() {
   const int kDoubleRegsSize =
       kDoubleSize * DwVfpRegister::kMaxNumAllocatableRegisters;
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm(), VFP2);
-    // Save all allocatable VFP registers before messing with them.
-    ASSERT(kDoubleRegZero.code() == 14);
-    ASSERT(kScratchDoubleReg.code() == 15);
+  // Save all allocatable VFP registers before messing with them.
+  ASSERT(kDoubleRegZero.code() == 14);
+  ASSERT(kScratchDoubleReg.code() == 15);
 
-    // Check CPU flags for number of registers, setting the Z condition flag.
-    __ CheckFor32DRegs(ip);
+  // Check CPU flags for number of registers, setting the Z condition flag.
+  __ CheckFor32DRegs(ip);
 
-    // Push registers d0-d13, and possibly d16-d31, on the stack.
-    // If d16-d31 are not pushed, decrease the stack pointer instead.
-    __ vstm(db_w, sp, d16, d31, ne);
-    __ sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq);
-    __ vstm(db_w, sp, d0, d13);
-  } else {
-    __ sub(sp, sp, Operand(kDoubleRegsSize));
-  }
+  // Push registers d0-d13, and possibly d16-d31, on the stack.
+  // If d16-d31 are not pushed, decrease the stack pointer instead.
+  __ vstm(db_w, sp, d16, d31, ne);
+  __ sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq);
+  __ vstm(db_w, sp, d0, d13);
 
   // Push all 16 registers (needed to populate FrameDescription::registers_).
   // TODO(1588) Note that using pc with stm is deprecated, so we should perhaps
@@ -669,17 +685,14 @@ void Deoptimizer::EntryGenerator::Generate() {
     __ str(r2, MemOperand(r1, offset));
   }
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm(), VFP2);
-    // Copy VFP registers to
-    // double_registers_[DoubleRegister::kMaxNumAllocatableRegisters]
-    int double_regs_offset = FrameDescription::double_registers_offset();
-    for (int i = 0; i < DwVfpRegister::kMaxNumAllocatableRegisters; ++i) {
-      int dst_offset = i * kDoubleSize + double_regs_offset;
-      int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
-      __ vldr(d0, sp, src_offset);
-      __ vstr(d0, r1, dst_offset);
-    }
+  // Copy VFP registers to
+  // double_registers_[DoubleRegister::kMaxNumAllocatableRegisters]
+  int double_regs_offset = FrameDescription::double_registers_offset();
+  for (int i = 0; i < DwVfpRegister::kMaxNumAllocatableRegisters; ++i) {
+    int dst_offset = i * kDoubleSize + double_regs_offset;
+    int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
+    __ vldr(d0, sp, src_offset);
+    __ vstr(d0, r1, dst_offset);
   }
 
   // Remove the bailout id, eventually return address, and the saved registers
@@ -749,21 +762,18 @@ void Deoptimizer::EntryGenerator::Generate() {
   __ cmp(r4, r1);
   __ b(lt, &outer_push_loop);
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm(), VFP2);
-    // Check CPU flags for number of registers, setting the Z condition flag.
-    __ CheckFor32DRegs(ip);
+  // Check CPU flags for number of registers, setting the Z condition flag.
+  __ CheckFor32DRegs(ip);
 
-    __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset()));
-    int src_offset = FrameDescription::double_registers_offset();
-    for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) {
-      if (i == kDoubleRegZero.code()) continue;
-      if (i == kScratchDoubleReg.code()) continue;
+  __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset()));
+  int src_offset = FrameDescription::double_registers_offset();
+  for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) {
+    if (i == kDoubleRegZero.code()) continue;
+    if (i == kScratchDoubleReg.code()) continue;
 
-      const DwVfpRegister reg = DwVfpRegister::from_code(i);
-      __ vldr(reg, r1, src_offset, i < 16 ? al : ne);
-      src_offset += kDoubleSize;
-    }
+    const DwVfpRegister reg = DwVfpRegister::from_code(i);
+    __ vldr(reg, r1, src_offset, i < 16 ? al : ne);
+    src_offset += kDoubleSize;
   }
 
   // Push state, pc, and continuation from the last output frame.
index dec62b3..b84d355 100644 (file)
@@ -1561,8 +1561,9 @@ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
     buffer[0] = '\0';
     byte* prev_pc = pc;
     pc += d.InstructionDecode(buffer, pc);
-    fprintf(f, "%p    %08x      %s\n",
-            prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
+    v8::internal::PrintF(
+        f, "%p    %08x      %s\n",
+        prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
   }
 }
 
index 30f4057..19b29b8 100644 (file)
@@ -100,18 +100,6 @@ const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
 // ----------------------------------------------------
 
 
-class StackHandlerConstants : public AllStatic {
- public:
-  static const int kNextOffset     = 0 * kPointerSize;
-  static const int kCodeOffset     = 1 * kPointerSize;
-  static const int kStateOffset    = 2 * kPointerSize;
-  static const int kContextOffset  = 3 * kPointerSize;
-  static const int kFPOffset       = 4 * kPointerSize;
-
-  static const int kSize = kFPOffset + kPointerSize;
-};
-
-
 class EntryFrameConstants : public AllStatic {
  public:
   static const int kCallerFPOffset      = -3 * kPointerSize;
index 6086645..ba0f141 100644 (file)
@@ -162,8 +162,6 @@ void FullCodeGenerator::Generate() {
   // the frame (that is done below).
   FrameScope frame_scope(masm_, StackFrame::MANUAL);
 
-  int locals_count = info->scope()->num_stack_slots();
-
   info->set_prologue_offset(masm_->pc_offset());
   {
     PredictableCodeSizeScope predictible_code_size_scope(
@@ -179,6 +177,9 @@ void FullCodeGenerator::Generate() {
   }
 
   { Comment cmnt(masm_, "[ Allocate locals");
+    int locals_count = info->scope()->num_stack_slots();
+    // Generators allocate locals, if any, in context slots.
+    ASSERT(!info->function()->is_generator() || locals_count == 0);
     for (int i = 0; i < locals_count; i++) {
       __ push(ip);
     }
@@ -313,7 +314,7 @@ void FullCodeGenerator::Generate() {
   EmitReturnSequence();
 
   // Force emit the constant pool, so it doesn't get emitted in the middle
-  // of the stack check table.
+  // of the back edge table.
   masm()->CheckConstPool(true, false);
 }
 
@@ -350,7 +351,7 @@ void FullCodeGenerator::EmitProfilingCounterReset() {
 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
                                                 Label* back_edge_target) {
   Comment cmnt(masm_, "[ Back edge bookkeeping");
-  // Block literal pools whilst emitting stack check code.
+  // Block literal pools whilst emitting back edge code.
   Assembler::BlockConstPoolScope block_const_pool(masm_);
   Label ok;
 
@@ -1268,7 +1269,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
       !pretenure &&
       scope()->is_function_scope() &&
       info->num_literals() == 0) {
-    FastNewClosureStub stub(info->language_mode());
+    FastNewClosureStub stub(info->language_mode(), info->is_generator());
     __ mov(r0, Operand(info));
     __ push(r0);
     __ CallStub(&stub);
@@ -1562,7 +1563,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
   // r0: Newly allocated regexp.
   // r5: Materialized regexp.
   // r2: temp.
-  __ CopyFields(r0, r5, r2.bit(), size / kPointerSize);
+  __ CopyFields(r0, r5, d0, s0, size / kPointerSize);
   context()->Plug(r0);
 }
 
@@ -1727,7 +1728,6 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
   __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
   __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
   __ mov(r1, Operand(constant_elements));
-  __ Push(r3, r2, r1);
   if (has_fast_elements && constant_elements_values->map() ==
       isolate()->heap()->fixed_cow_array_map()) {
     FastCloneShallowArrayStub stub(
@@ -1738,8 +1738,11 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
     __ IncrementCounter(
         isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2);
   } else if (expr->depth() > 1) {
+    __ Push(r3, r2, r1);
     __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
-  } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+  } else if (Serializer::enabled() ||
+      length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+    __ Push(r3, r2, r1);
     __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
   } else {
     ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
@@ -3024,37 +3027,26 @@ void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
   // Convert 32 random bits in r0 to 0.(32 random bits) in a double
   // by computing:
   // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
-  if (CpuFeatures::IsSupported(VFP2)) {
-    __ PrepareCallCFunction(1, r0);
-    __ ldr(r0,
-           ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
-    __ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset));
-    __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
-
-    CpuFeatureScope scope(masm(), VFP2);
-    // 0x41300000 is the top half of 1.0 x 2^20 as a double.
-    // Create this constant using mov/orr to avoid PC relative load.
-    __ mov(r1, Operand(0x41000000));
-    __ orr(r1, r1, Operand(0x300000));
-    // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
-    __ vmov(d7, r0, r1);
-    // Move 0x4130000000000000 to VFP.
-    __ mov(r0, Operand::Zero());
-    __ vmov(d8, r0, r1);
-    // Subtract and store the result in the heap number.
-    __ vsub(d7, d7, d8);
-    __ sub(r0, r4, Operand(kHeapObjectTag));
-    __ vstr(d7, r0, HeapNumber::kValueOffset);
-    __ mov(r0, r4);
-  } else {
-    __ PrepareCallCFunction(2, r0);
-    __ ldr(r1,
-           ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
-    __ mov(r0, Operand(r4));
-    __ ldr(r1, FieldMemOperand(r1, GlobalObject::kNativeContextOffset));
-    __ CallCFunction(
-        ExternalReference::fill_heap_number_with_random_function(isolate()), 2);
-  }
+  __ PrepareCallCFunction(1, r0);
+  __ ldr(r0,
+         ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
+  __ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset));
+  __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
+
+  // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+  // Create this constant using mov/orr to avoid PC relative load.
+  __ mov(r1, Operand(0x41000000));
+  __ orr(r1, r1, Operand(0x300000));
+  // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
+  __ vmov(d7, r0, r1);
+  // Move 0x4130000000000000 to VFP.
+  __ mov(r0, Operand::Zero());
+  __ vmov(d8, r0, r1);
+  // Subtract and store the result in the heap number.
+  __ vsub(d7, d7, d8);
+  __ sub(r0, r4, Operand(kHeapObjectTag));
+  __ vstr(d7, r0, HeapNumber::kValueOffset);
+  __ mov(r0, r4);
 
   context()->Plug(r0);
 }
@@ -3191,12 +3183,8 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
   ASSERT(args->length() == 2);
   VisitForStackValue(args->at(0));
   VisitForStackValue(args->at(1));
-  if (CpuFeatures::IsSupported(VFP2)) {
-    MathPowStub stub(MathPowStub::ON_STACK);
-    __ CallStub(&stub);
-  } else {
-    __ CallRuntime(Runtime::kMath_pow, 2);
-  }
+  MathPowStub stub(MathPowStub::ON_STACK);
+  __ CallStub(&stub);
   context()->Plug(r0);
 }
 
index f2b65ef..f6029b5 100644 (file)
@@ -302,17 +302,6 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
 }
 
 
-void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
-  stream->Add("/%s ", hydrogen()->OpName());
-  value()->PrintTo(stream);
-}
-
-
-void LMathExp::PrintDataTo(StringStream* stream) {
-  value()->PrintTo(stream);
-}
-
-
 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
   context()->PrintTo(stream);
   stream->Add("[%d]", slot_index());
@@ -1124,47 +1113,101 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
 
 
 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
-  BuiltinFunctionId op = instr->op();
-  if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
-    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);
-    LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
-    return DefineFixedDouble(result, d2);
-  } else {
-    LOperand* input = UseRegister(instr->value());
-
-    LOperand* temp = (op == kMathRound) ? FixedTemp(d3) : NULL;
-    LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
-    switch (op) {
-      case kMathAbs:
-        return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
-      case kMathFloor:
-        return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
-      case kMathSqrt:
-        return DefineAsRegister(result);
-      case kMathRound:
-        return AssignEnvironment(DefineAsRegister(result));
-      default:
-        UNREACHABLE();
-        return NULL;
-    }
+  switch (instr->op()) {
+    case kMathFloor: return DoMathFloor(instr);
+    case kMathRound: return DoMathRound(instr);
+    case kMathAbs: return DoMathAbs(instr);
+    case kMathLog: return DoMathLog(instr);
+    case kMathSin: return DoMathSin(instr);
+    case kMathCos: return DoMathCos(instr);
+    case kMathTan: return DoMathTan(instr);
+    case kMathExp: return DoMathExp(instr);
+    case kMathSqrt: return DoMathSqrt(instr);
+    case kMathPowHalf: return DoMathPowHalf(instr);
+    default:
+      UNREACHABLE();
+      return NULL;
   }
 }
 
 
+LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LMathFloor* result = new(zone()) LMathFloor(input);
+  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LOperand* temp = FixedTemp(d3);
+  LMathRound* result = new(zone()) LMathRound(input, temp);
+  return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LMathAbs* result = new(zone()) LMathAbs(input);
+  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), d2);
+  LMathLog* result = new(zone()) LMathLog(input);
+  return MarkAsCall(DefineFixedDouble(result, d2), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), d2);
+  LMathSin* result = new(zone()) LMathSin(input);
+  return MarkAsCall(DefineFixedDouble(result, d2), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), d2);
+  LMathCos* result = new(zone()) LMathCos(input);
+  return MarkAsCall(DefineFixedDouble(result, d2), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), d2);
+  LMathTan* result = new(zone()) LMathTan(input);
+  return MarkAsCall(DefineFixedDouble(result, d2), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
+  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);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LMathSqrt* result = new(zone()) LMathSqrt(input);
+  return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), d2);
+  LOperand* temp = FixedTemp(d3);
+  LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
+  return DefineFixedDouble(result, d2);
+}
+
+
 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
   ASSERT(instr->key()->representation().IsTagged());
   argument_count_ -= instr->argument_count();
@@ -1933,7 +1976,7 @@ LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
   LUnallocated* temp1 = TempRegister();
   LOperand* temp2 = TempRegister();
   LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2);
-  return AssignEnvironment(Define(result, temp1));
+  return AssignEnvironment(result);
 }
 
 
@@ -2133,16 +2176,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
         (instr->representation().IsDouble() &&
          ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
           (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
-    // float->double conversion on non-VFP2 requires an extra scratch
-    // register. For convenience, just mark the elements register as "UseTemp"
-    // so that it can be used as a temp during the float->double conversion
-    // after it's no longer needed after the float load.
-    bool needs_temp =
-        !CpuFeatures::IsSupported(VFP2) &&
-        (elements_kind == EXTERNAL_FLOAT_ELEMENTS);
-    LOperand* external_pointer = needs_temp
-        ? UseTempRegister(instr->elements())
-        : UseRegister(instr->elements());
+    LOperand* external_pointer = UseRegister(instr->elements());
     result = new(zone()) LLoadKeyed(external_pointer, key);
   }
 
@@ -2341,11 +2375,6 @@ LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
-  return MarkAsCall(DefineFixed(new(zone()) LFastLiteral, r0), instr);
-}
-
-
 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
   return MarkAsCall(DefineFixed(new(zone()) LArrayLiteral, r0), instr);
 }
index 207faf4..6486cad 100644 (file)
@@ -97,7 +97,6 @@ class LCodeGen;
   V(DoubleToI)                                  \
   V(DummyUse)                                   \
   V(ElementsKind)                               \
-  V(FastLiteral)                                \
   V(FixedArrayBaseLength)                       \
   V(FunctionLiteral)                            \
   V(GetCachedArrayIndex)                        \
@@ -134,9 +133,18 @@ class LCodeGen;
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MapEnumLength)                              \
+  V(MathAbs)                                    \
+  V(MathCos)                                    \
   V(MathExp)                                    \
+  V(MathFloor)                                  \
   V(MathFloorOfDiv)                             \
+  V(MathLog)                                    \
   V(MathMinMax)                                 \
+  V(MathPowHalf)                                \
+  V(MathRound)                                  \
+  V(MathSin)                                    \
+  V(MathSqrt)                                   \
+  V(MathTan)                                    \
   V(ModI)                                       \
   V(MulI)                                       \
   V(MultiplyAddD)                               \
@@ -181,7 +189,6 @@ class LCodeGen;
   V(TrapAllocationMemento)                      \
   V(Typeof)                                     \
   V(TypeofIsAndBranch)                          \
-  V(UnaryMathOperation)                         \
   V(UnknownOSRValue)                            \
   V(ValueOf)                                    \
   V(ForInPrepareMap)                            \
@@ -703,9 +710,22 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
 };
 
 
-class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> {
+class LMathFloor: public LTemplateInstruction<1, 1, 0> {
  public:
-  LUnaryMathOperation(LOperand* value, LOperand* temp) {
+  explicit LMathFloor(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathRound: public LTemplateInstruction<1, 1, 1> {
+ public:
+  LMathRound(LOperand* value, LOperand* temp) {
     inputs_[0] = value;
     temps_[0] = temp;
   }
@@ -713,11 +733,69 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> {
   LOperand* value() { return inputs_[0]; }
   LOperand* temp() { return temps_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
+  DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
   DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
 
-  virtual void PrintDataTo(StringStream* stream);
-  BuiltinFunctionId op() const { return hydrogen()->op(); }
+
+class LMathAbs: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathAbs(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathLog: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathLog(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathSin: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathSin(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathSin, "math-sin")
+};
+
+
+class LMathCos: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathCos(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathCos, "math-cos")
+};
+
+
+class LMathTan: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathTan(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathTan, "math-tan")
 };
 
 
@@ -740,8 +818,32 @@ class LMathExp: public LTemplateInstruction<1, 1, 3> {
   LOperand* double_temp() { return temps_[2]; }
 
   DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+};
 
-  virtual void PrintDataTo(StringStream* stream);
+
+class LMathSqrt: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathSqrt(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
+};
+
+
+class LMathPowHalf: public LTemplateInstruction<1, 1, 1> {
+ public:
+  LMathPowHalf(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
 };
 
 
@@ -1310,7 +1412,7 @@ class LMathMinMax: public LTemplateInstruction<1, 2, 0> {
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
   DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
 };
 
@@ -2074,7 +2176,13 @@ class LStoreKeyed: public LTemplateInstruction<0, 3, 0> {
   DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
 
   virtual void PrintDataTo(StringStream* stream);
-  bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); }
+  bool NeedsCanonicalization() {
+    if (hydrogen()->value()->IsAdd() || hydrogen()->value()->IsSub() ||
+        hydrogen()->value()->IsMul() || hydrogen()->value()->IsDiv()) {
+      return false;
+    }
+    return hydrogen()->NeedsCanonicalization();
+  }
   uint32_t additional_index() const { return hydrogen()->index_offset(); }
 };
 
@@ -2239,7 +2347,7 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> {
 };
 
 
-class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 2> {
+class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> {
  public:
   LCheckPrototypeMaps(LOperand* temp, LOperand* temp2)  {
     temps_[0] = temp;
@@ -2355,13 +2463,6 @@ class LAllocate: public LTemplateInstruction<1, 2, 2> {
 };
 
 
-class LFastLiteral: public LTemplateInstruction<1, 0, 0> {
- public:
-  DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
-  DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
-};
-
-
 class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
  public:
   DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
@@ -2611,6 +2712,17 @@ class LChunkBuilder BASE_EMBEDDED {
   static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
   static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
 
+  LInstruction* DoMathFloor(HUnaryMathOperation* instr);
+  LInstruction* DoMathRound(HUnaryMathOperation* instr);
+  LInstruction* DoMathAbs(HUnaryMathOperation* instr);
+  LInstruction* DoMathLog(HUnaryMathOperation* instr);
+  LInstruction* DoMathSin(HUnaryMathOperation* instr);
+  LInstruction* DoMathCos(HUnaryMathOperation* instr);
+  LInstruction* DoMathTan(HUnaryMathOperation* instr);
+  LInstruction* DoMathExp(HUnaryMathOperation* instr);
+  LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
+  LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
+
  private:
   enum Status {
     UNUSED,
index 7bb3535..a19015d 100644 (file)
@@ -113,7 +113,7 @@ void LCodeGen::Comment(const char* format, ...) {
   // issues when the stack allocated buffer goes out of scope.
   size_t length = builder.position();
   Vector<char> copy = Vector<char>::New(length + 1);
-  memcpy(copy.start(), builder.Finalize(), copy.length());
+  OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
   masm()->RecordComment(copy.start());
 }
 
@@ -195,8 +195,7 @@ bool LCodeGen::GeneratePrologue() {
     }
   }
 
-  if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm(), VFP2);
+  if (info()->saves_caller_doubles()) {
     Comment(";;; Save clobbered callee double registers");
     int count = 0;
     BitVector* doubles = chunk()->allocated_double_registers();
@@ -852,7 +851,9 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
   }
 
   ASSERT(FLAG_deopt_every_n_times < 2);  // Other values not supported on ARM.
-  if (FLAG_deopt_every_n_times == 1 && info_->opt_count() == id) {
+  if (FLAG_deopt_every_n_times == 1 &&
+      !info()->IsStub() &&
+      info()->opt_count() == id) {
     __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
     return;
   }
@@ -1209,8 +1210,6 @@ void LCodeGen::DoModI(LModI* instr) {
 
     Label vfp_modulo, both_positive, right_negative;
 
-    CpuFeatureScope scope(masm(), VFP2);
-
     // Check for x % 0.
     if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
       __ cmp(right, Operand::Zero());
@@ -1615,7 +1614,6 @@ void LCodeGen::DoDeferredBinaryOpStub(LPointerMap* pointer_map,
                                       LOperand* left_argument,
                                       LOperand* right_argument,
                                       Token::Value op) {
-  CpuFeatureScope vfp_scope(masm(), VFP2);
   Register left = ToRegister(left_argument);
   Register right = ToRegister(right_argument);
 
@@ -1901,7 +1899,6 @@ void LCodeGen::DoConstantI(LConstantI* instr) {
 void LCodeGen::DoConstantD(LConstantD* instr) {
   ASSERT(instr->result()->IsDoubleRegister());
   DwVfpRegister result = ToDoubleRegister(instr->result());
-  CpuFeatureScope scope(masm(), VFP2);
   double v = instr->value();
   __ Vmov(result, v, scratch0());
 }
@@ -2072,7 +2069,6 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
     __ mov(result_reg, right_op, LeaveCC, NegateCondition(condition));
   } else {
     ASSERT(instr->hydrogen()->representation().IsDouble());
-    CpuFeatureScope scope(masm(), VFP2);
     DwVfpRegister left_reg = ToDoubleRegister(left);
     DwVfpRegister right_reg = ToDoubleRegister(right);
     DwVfpRegister result_reg = ToDoubleRegister(instr->result());
@@ -2118,7 +2114,6 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
 
 
 void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   DwVfpRegister left = ToDoubleRegister(instr->left());
   DwVfpRegister right = ToDoubleRegister(instr->right());
   DwVfpRegister result = ToDoubleRegister(instr->result());
@@ -2209,7 +2204,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
     __ cmp(reg, Operand::Zero());
     EmitBranch(true_block, false_block, ne);
   } else if (r.IsDouble()) {
-    CpuFeatureScope scope(masm(), VFP2);
     DwVfpRegister reg = ToDoubleRegister(instr->value());
     Register scratch = scratch0();
 
@@ -2301,7 +2295,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
       }
 
       if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
-        CpuFeatureScope scope(masm(), VFP2);
         // heap number -> false iff +0, -0, or NaN.
         DwVfpRegister dbl_scratch = double_scratch0();
         Label not_heap_number;
@@ -2381,7 +2374,6 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
     EmitGoto(next_block);
   } else {
     if (instr->is_double()) {
-      CpuFeatureScope scope(masm(), VFP2);
       // Compare left and right operands as doubles and load the
       // resulting flags into the normal status register.
       __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right));
@@ -2936,8 +2928,7 @@ void LCodeGen::DoReturn(LReturn* instr) {
     __ push(r0);
     __ CallRuntime(Runtime::kTraceExit, 1);
   }
-  if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm(), VFP2);
+  if (info()->saves_caller_doubles()) {
     ASSERT(NeedsEagerFrame());
     BitVector* doubles = chunk()->allocated_double_registers();
     BitVector::Iterator save_iterator(doubles);
@@ -3319,58 +3310,11 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
         ? Operand(constant_key << element_size_shift)
         : Operand(key, LSL, shift_size);
     __ add(scratch0(), external_pointer, operand);
-    if (CpuFeatures::IsSupported(VFP2)) {
-      CpuFeatureScope scope(masm(), VFP2);
-      if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
-        __ vldr(kScratchDoubleReg.low(), scratch0(), additional_offset);
-        __ vcvt_f64_f32(result, kScratchDoubleReg.low());
-      } else  {  // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
-        __ vldr(result, scratch0(), additional_offset);
-      }
-    } else {
-      if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
-        Register value = external_pointer;
-        __ ldr(value, MemOperand(scratch0(), additional_offset));
-        __ and_(sfpd_lo, value, Operand(kBinary32MantissaMask));
-
-        __ mov(scratch0(), Operand(value, LSR, kBinary32MantissaBits));
-        __ and_(scratch0(), scratch0(),
-                Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
-
-        Label exponent_rebiased;
-        __ teq(scratch0(), Operand(0x00));
-        __ b(eq, &exponent_rebiased);
-
-        __ teq(scratch0(), Operand(0xff));
-        __ mov(scratch0(), Operand(0x7ff), LeaveCC, eq);
-        __ b(eq, &exponent_rebiased);
-
-        // Rebias exponent.
-        __ add(scratch0(),
-               scratch0(),
-               Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
-
-        __ bind(&exponent_rebiased);
-        __ and_(sfpd_hi, value, Operand(kBinary32SignMask));
-        __ orr(sfpd_hi, sfpd_hi,
-               Operand(scratch0(), LSL, HeapNumber::kMantissaBitsInTopWord));
-
-        // Shift mantissa.
-        static const int kMantissaShiftForHiWord =
-            kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
-        static const int kMantissaShiftForLoWord =
-            kBitsPerInt - kMantissaShiftForHiWord;
-
-        __ orr(sfpd_hi, sfpd_hi,
-               Operand(sfpd_lo, LSR, kMantissaShiftForHiWord));
-        __ mov(sfpd_lo, Operand(sfpd_lo, LSL, kMantissaShiftForLoWord));
-
-      } else {
-        __ ldr(sfpd_lo, MemOperand(scratch0(), additional_offset));
-        __ ldr(sfpd_hi, MemOperand(scratch0(),
-                                   additional_offset + kPointerSize));
-      }
+    if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+      __ vldr(kScratchDoubleReg.low(), scratch0(), additional_offset);
+      __ vcvt_f64_f32(result, kScratchDoubleReg.low());
+    } else  {  // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
+      __ vldr(result, scratch0(), additional_offset);
     }
   } else {
     Register result = ToRegister(instr->result());
@@ -3444,23 +3388,12 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
   if (!key_is_constant) {
     __ add(elements, elements, Operand(key, LSL, shift_size));
   }
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm(), VFP2);
-    __ add(elements, elements, Operand(base_offset));
-    __ vldr(result, elements, 0);
-    if (instr->hydrogen()->RequiresHoleCheck()) {
-      __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
-      __ cmp(scratch, Operand(kHoleNanUpper32));
-      DeoptimizeIf(eq, instr->environment());
-    }
-  } else {
-      __ ldr(sfpd_hi, MemOperand(elements, base_offset + kPointerSize));
-      __ ldr(sfpd_lo, MemOperand(elements, base_offset));
-    if (instr->hydrogen()->RequiresHoleCheck()) {
-      ASSERT(kPointerSize == sizeof(kHoleNanLower32));
-      __ cmp(sfpd_hi, Operand(kHoleNanUpper32));
-      DeoptimizeIf(eq, instr->environment());
-    }
+  __ add(elements, elements, Operand(base_offset));
+  __ vldr(result, elements, 0);
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
+    __ cmp(scratch, Operand(kHoleNanUpper32));
+    DeoptimizeIf(eq, instr->environment());
   }
 }
 
@@ -3821,7 +3754,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
 }
 
 
-void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
+void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
   Register input = ToRegister(instr->value());
   Register result = ToRegister(instr->result());
   Register scratch = scratch0();
@@ -3887,7 +3820,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
   Register input = ToRegister(instr->value());
   Register result = ToRegister(instr->result());
   __ cmp(input, Operand::Zero());
@@ -3901,20 +3834,18 @@ void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
   // Class for deferred case.
   class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
    public:
-    DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
-                                    LUnaryMathOperation* instr)
+    DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
         : LDeferredCode(codegen), instr_(instr) { }
     virtual void Generate() {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
     virtual LInstruction* instr() { return instr_; }
    private:
-    LUnaryMathOperation* instr_;
+    LMathAbs* instr_;
   };
 
   Representation r = instr->hydrogen()->value()->representation();
@@ -3938,8 +3869,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathFloor(LMathFloor* instr) {
   DwVfpRegister input = ToDoubleRegister(instr->value());
   Register result = ToRegister(instr->result());
   Register input_high = scratch0();
@@ -3961,8 +3891,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathRound(LMathRound* instr) {
   DwVfpRegister input = ToDoubleRegister(instr->value());
   Register result = ToRegister(instr->result());
   DwVfpRegister double_scratch1 = ToDoubleRegister(instr->temp());
@@ -4001,16 +3930,14 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
   DwVfpRegister input = ToDoubleRegister(instr->value());
   DwVfpRegister result = ToDoubleRegister(instr->result());
   __ vsqrt(result, input);
 }
 
 
-void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
+void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
   DwVfpRegister input = ToDoubleRegister(instr->value());
   DwVfpRegister result = ToDoubleRegister(instr->result());
   DwVfpRegister temp = ToDoubleRegister(instr->temp());
@@ -4032,7 +3959,6 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
 
 
 void LCodeGen::DoPower(LPower* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   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.
@@ -4065,7 +3991,6 @@ void LCodeGen::DoPower(LPower* instr) {
 
 
 void LCodeGen::DoRandom(LRandom* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   class DeferredDoRandom: public LDeferredCode {
    public:
     DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
@@ -4144,7 +4069,6 @@ void LCodeGen::DoDeferredRandom(LRandom* instr) {
 
 
 void LCodeGen::DoMathExp(LMathExp* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   DwVfpRegister input = ToDoubleRegister(instr->value());
   DwVfpRegister result = ToDoubleRegister(instr->result());
   DwVfpRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
@@ -4158,7 +4082,7 @@ void LCodeGen::DoMathExp(LMathExp* instr) {
 }
 
 
-void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathLog(LMathLog* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(d2));
   TranscendentalCacheStub stub(TranscendentalCache::LOG,
                                TranscendentalCacheStub::UNTAGGED);
@@ -4166,7 +4090,7 @@ void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathTan(LMathTan* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(d2));
   TranscendentalCacheStub stub(TranscendentalCache::TAN,
                                TranscendentalCacheStub::UNTAGGED);
@@ -4174,7 +4098,7 @@ void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathCos(LMathCos* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(d2));
   TranscendentalCacheStub stub(TranscendentalCache::COS,
                                TranscendentalCacheStub::UNTAGGED);
@@ -4182,7 +4106,7 @@ void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSin(LMathSin* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(d2));
   TranscendentalCacheStub stub(TranscendentalCache::SIN,
                                TranscendentalCacheStub::UNTAGGED);
@@ -4190,42 +4114,6 @@ void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
-  switch (instr->op()) {
-    case kMathAbs:
-      DoMathAbs(instr);
-      break;
-    case kMathFloor:
-      DoMathFloor(instr);
-      break;
-    case kMathRound:
-      DoMathRound(instr);
-      break;
-    case kMathSqrt:
-      DoMathSqrt(instr);
-      break;
-    case kMathPowHalf:
-      DoMathPowHalf(instr);
-      break;
-    case kMathCos:
-      DoMathCos(instr);
-      break;
-    case kMathSin:
-      DoMathSin(instr);
-      break;
-    case kMathTan:
-      DoMathTan(instr);
-      break;
-    case kMathLog:
-      DoMathLog(instr);
-      break;
-    default:
-      Abort("Unimplemented type of LUnaryMathOperation.");
-      UNREACHABLE();
-  }
-}
-
-
 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   ASSERT(ToRegister(instr->function()).is(r1));
   ASSERT(instr->HasPointerMap());
@@ -4442,7 +4330,6 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
 
 
 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   Register external_pointer = ToRegister(instr->elements());
   Register key = no_reg;
   ElementsKind elements_kind = instr->elements_kind();
@@ -4463,7 +4350,6 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
 
   if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
       elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
-    CpuFeatureScope scope(masm(), VFP3);
     DwVfpRegister value(ToDoubleRegister(instr->value()));
     Operand operand(key_is_constant
                     ? Operand(constant_key << element_size_shift)
@@ -4513,7 +4399,6 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
 
 
 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   DwVfpRegister value = ToDoubleRegister(instr->value());
   Register elements = ToRegister(instr->elements());
   Register key = no_reg;
@@ -4545,18 +4430,14 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
   }
 
   if (instr->NeedsCanonicalization()) {
-    // Check for NaN. All NaNs must be canonicalized.
-    __ VFPCompareAndSetFlags(value, value);
-    Label after_canonicalization;
-
-    // Only load canonical NaN if the comparison above set the overflow.
-    __ b(vc, &after_canonicalization);
-    __ Vmov(value,
-            FixedDoubleArray::canonical_not_the_hole_nan_as_double());
-
-    __ bind(&after_canonicalization);
+    // Force a canonical NaN.
+    if (masm()->emit_debug_code()) {
+      __ vmrs(ip);
+      __ tst(ip, Operand(kVFPDefaultNaNModeControlBit));
+      __ Assert(ne, "Default NaN mode not set");
+    }
+    __ VFPCanonicalizeNaN(value);
   }
-
   __ vstr(value, scratch, instr->additional_index() << element_size_shift);
 }
 
@@ -4814,7 +4695,6 @@ void LCodeGen::DoStringLength(LStringLength* instr) {
 
 
 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   LOperand* input = instr->value();
   ASSERT(input->IsRegister() || input->IsStackSlot());
   LOperand* output = instr->result();
@@ -4832,7 +4712,6 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
 
 
 void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   LOperand* input = instr->value();
   LOperand* output = instr->result();
 
@@ -4894,43 +4773,6 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
 }
 
 
-// Convert unsigned integer with specified number of leading zeroes in binary
-// representation to IEEE 754 double.
-// Integer to convert is passed in register src.
-// Resulting double is returned in registers hiword:loword.
-// This functions does not work correctly for 0.
-static void GenerateUInt2Double(MacroAssembler* masm,
-                                Register src,
-                                Register hiword,
-                                Register loword,
-                                Register scratch,
-                                int leading_zeroes) {
-  const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
-  const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
-
-  const int mantissa_shift_for_hi_word =
-      meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
-  const int mantissa_shift_for_lo_word =
-      kBitsPerInt - mantissa_shift_for_hi_word;
-  masm->mov(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
-  if (mantissa_shift_for_hi_word > 0) {
-    masm->mov(loword, Operand(src, LSL, mantissa_shift_for_lo_word));
-    masm->orr(hiword, scratch,
-              Operand(src, LSR, mantissa_shift_for_hi_word));
-  } else {
-    masm->mov(loword, Operand::Zero());
-    masm->orr(hiword, scratch,
-              Operand(src, LSL, -mantissa_shift_for_hi_word));
-  }
-
-  // If least significant bit of biased exponent was not 1 it was corrupted
-  // by most significant bit of mantissa so we should fix that.
-  if (!(biased_exponent & 1)) {
-    masm->bic(hiword, hiword, Operand(1 << HeapNumber::kExponentShift));
-  }
-}
-
-
 void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
                                     LOperand* value,
                                     IntegerSignedness signedness) {
@@ -4952,35 +4794,11 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
       __ SmiUntag(src, dst);
       __ eor(src, src, Operand(0x80000000));
     }
-    if (CpuFeatures::IsSupported(VFP2)) {
-      CpuFeatureScope scope(masm(), VFP2);
-      __ vmov(flt_scratch, src);
-      __ vcvt_f64_s32(dbl_scratch, flt_scratch);
-    } else {
-      FloatingPointHelper::Destination dest =
-          FloatingPointHelper::kCoreRegisters;
-      FloatingPointHelper::ConvertIntToDouble(masm(), src, dest, d0,
-                                              sfpd_lo, sfpd_hi,
-                                              scratch0(), s0);
-    }
+    __ vmov(flt_scratch, src);
+    __ vcvt_f64_s32(dbl_scratch, flt_scratch);
   } else {
-    if (CpuFeatures::IsSupported(VFP2)) {
-      CpuFeatureScope scope(masm(), VFP2);
-      __ vmov(flt_scratch, src);
-      __ vcvt_f64_u32(dbl_scratch, flt_scratch);
-    } else {
-      Label no_leading_zero, convert_done;
-      __ tst(src, Operand(0x80000000));
-      __ b(ne, &no_leading_zero);
-
-      // Integer has one leading zeros.
-      GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, r9, 1);
-      __ b(&convert_done);
-
-      __ bind(&no_leading_zero);
-      GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, r9, 0);
-      __ bind(&convert_done);
-    }
+    __ vmov(flt_scratch, src);
+    __ vcvt_f64_u32(dbl_scratch, flt_scratch);
   }
 
   if (FLAG_inline_new) {
@@ -4996,30 +4814,16 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
   // TODO(3095996): Put a valid pointer value in the stack slot where the result
   // register is stored, as this register is in the pointer map, but contains an
   // integer value.
-  if (!CpuFeatures::IsSupported(VFP2)) {
-    // Preserve sfpd_lo.
-    __ mov(r9, sfpd_lo);
-  }
   __ mov(ip, Operand::Zero());
   __ StoreToSafepointRegisterSlot(ip, dst);
   CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
   __ Move(dst, r0);
-  if (!CpuFeatures::IsSupported(VFP2)) {
-    // Restore sfpd_lo.
-    __ mov(sfpd_lo, r9);
-  }
   __ sub(dst, dst, Operand(kHeapObjectTag));
 
   // Done. Put the value in dbl_scratch into the value of the allocated heap
   // number.
   __ bind(&done);
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm(), VFP2);
-    __ vstr(dbl_scratch, dst, HeapNumber::kValueOffset);
-  } else {
-    __ str(sfpd_lo, MemOperand(dst, HeapNumber::kMantissaOffset));
-    __ str(sfpd_hi, MemOperand(dst, HeapNumber::kExponentOffset));
-  }
+  __ vstr(dbl_scratch, dst, HeapNumber::kValueOffset);
   __ add(dst, dst, Operand(kHeapObjectTag));
   __ StoreToSafepointRegisterSlot(dst, dst);
 }
@@ -5052,45 +4856,16 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
   Label no_special_nan_handling;
   Label done;
   if (convert_hole) {
-    if (CpuFeatures::IsSupported(VFP2)) {
-      CpuFeatureScope scope(masm(), VFP2);
-      DwVfpRegister input_reg = ToDoubleRegister(instr->value());
-      __ VFPCompareAndSetFlags(input_reg, input_reg);
-      __ b(vc, &no_special_nan_handling);
-      __ vmov(reg, scratch0(), input_reg);
-      __ cmp(scratch0(), Operand(kHoleNanUpper32));
-      Label canonicalize;
-      __ b(ne, &canonicalize);
-      __ Move(reg, factory()->the_hole_value());
-      __ b(&done);
-      __ bind(&canonicalize);
-      __ Vmov(input_reg,
-              FixedDoubleArray::canonical_not_the_hole_nan_as_double(),
-              no_reg);
-    } else {
-      Label not_hole;
-      __ cmp(sfpd_hi, Operand(kHoleNanUpper32));
-      __ b(ne, &not_hole);
-      __ Move(reg, factory()->the_hole_value());
-      __ b(&done);
-      __ bind(&not_hole);
-      __ and_(scratch, sfpd_hi, Operand(0x7ff00000));
-      __ cmp(scratch, Operand(0x7ff00000));
-      __ b(ne, &no_special_nan_handling);
-      Label special_nan_handling;
-      __ tst(sfpd_hi, Operand(0x000FFFFF));
-      __ b(ne, &special_nan_handling);
-      __ cmp(sfpd_lo, Operand(0));
-      __ b(eq, &no_special_nan_handling);
-      __ bind(&special_nan_handling);
-      double canonical_nan =
-          FixedDoubleArray::canonical_not_the_hole_nan_as_double();
-      uint64_t casted_nan = BitCast<uint64_t>(canonical_nan);
-      __ mov(sfpd_lo,
-             Operand(static_cast<uint32_t>(casted_nan & 0xFFFFFFFF)));
-      __ mov(sfpd_hi,
-             Operand(static_cast<uint32_t>(casted_nan >> 32)));
-    }
+    DwVfpRegister input_reg = ToDoubleRegister(instr->value());
+    __ VFPCompareAndSetFlags(input_reg, input_reg);
+    __ b(vc, &no_special_nan_handling);
+    __ vmov(scratch, input_reg.high());
+    __ cmp(scratch, Operand(kHoleNanUpper32));
+    // If not the hole NaN, force the NaN to be canonical.
+    __ VFPCanonicalizeNaN(input_reg, ne);
+    __ b(ne, &no_special_nan_handling);
+    __ Move(reg, factory()->the_hole_value());
+    __ b(&done);
   }
 
   __ bind(&no_special_nan_handling);
@@ -5104,13 +4879,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
     __ jmp(deferred->entry());
   }
   __ bind(deferred->exit());
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm(), VFP2);
-    __ vstr(input_reg, reg, HeapNumber::kValueOffset);
-  } else {
-    __ str(sfpd_lo, MemOperand(reg, HeapNumber::kValueOffset));
-    __ str(sfpd_hi, MemOperand(reg, HeapNumber::kValueOffset + kPointerSize));
-  }
+  __ vstr(input_reg, reg, HeapNumber::kValueOffset);
   // Now that we have finished with the object's real address tag it
   __ add(reg, reg, Operand(kHeapObjectTag));
   __ bind(&done);
@@ -5160,7 +4929,6 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
   Register scratch = scratch0();
   SwVfpRegister flt_scratch = double_scratch0().low();
   ASSERT(!result_reg.is(double_scratch0()));
-  CpuFeatureScope scope(masm(), VFP2);
 
   Label load_smi, heap_number, done;
 
@@ -5249,7 +5017,6 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
   __ cmp(scratch1, Operand(ip));
 
   if (instr->truncating()) {
-    CpuFeatureScope scope(masm(), VFP2);
     Register scratch3 = ToRegister(instr->temp2());
     ASSERT(!scratch3.is(input_reg) &&
            !scratch3.is(scratch1) &&
@@ -5270,11 +5037,10 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
     __ sub(scratch1, input_reg, Operand(kHeapObjectTag));
     __ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset);
 
-    __ ECMAToInt32VFP(input_reg, double_scratch2, double_scratch,
-                      scratch1, scratch2, scratch3);
+    __ ECMAToInt32(input_reg, double_scratch2, double_scratch,
+                   scratch1, scratch2, scratch3);
 
   } else {
-    CpuFeatureScope scope(masm(), VFP3);
     // Deoptimize if we don't have a heap number.
     DeoptimizeIf(ne, instr->environment());
 
@@ -5369,8 +5135,8 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
 
   if (instr->truncating()) {
     Register scratch3 = ToRegister(instr->temp2());
-    __ ECMAToInt32VFP(result_reg, double_input, double_scratch,
-                      scratch1, scratch2, scratch3);
+    __ ECMAToInt32(result_reg, double_input, double_scratch,
+                   scratch1, scratch2, scratch3);
   } else {
     __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
     // Deoptimize if the input wasn't a int32 (inside a double).
@@ -5486,7 +5252,6 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
 
 
 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
-  CpuFeatureScope vfp_scope(masm(), VFP2);
   DwVfpRegister value_reg = ToDoubleRegister(instr->unclamped());
   Register result_reg = ToRegister(instr->result());
   DwVfpRegister temp_reg = ToDoubleRegister(instr->temp());
@@ -5495,7 +5260,6 @@ void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
 
 
 void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   Register unclamped_reg = ToRegister(instr->unclamped());
   Register result_reg = ToRegister(instr->result());
   __ ClampUint8(result_reg, unclamped_reg);
@@ -5503,7 +5267,6 @@ void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
 
 
 void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
-  CpuFeatureScope scope(masm(), VFP2);
   Register scratch = scratch0();
   Register input_reg = ToRegister(instr->unclamped());
   Register result_reg = ToRegister(instr->result());
@@ -5541,7 +5304,6 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
 
 
 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
-  ASSERT(instr->temp()->Equals(instr->result()));
   Register prototype_reg = ToRegister(instr->temp());
   Register map_reg = ToRegister(instr->temp2());
 
@@ -5554,8 +5316,6 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
     for (int i = 0; i < maps->length(); i++) {
       prototype_maps_.Add(maps->at(i), info()->zone());
     }
-    __ LoadHeapObject(prototype_reg,
-                      prototypes->at(prototypes->length() - 1));
   } else {
     for (int i = 0; i < prototypes->length(); i++) {
       __ LoadHeapObject(prototype_reg, prototypes->at(i));
@@ -5671,11 +5431,11 @@ void LCodeGen::DoAllocate(LAllocate* instr) {
   if (instr->hydrogen()->MustAllocateDoubleAligned()) {
     flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
   }
+  if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+    flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+  }
   if (instr->size()->IsConstantOperand()) {
     int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
-    if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
-      flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
-    }
     __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
   } else {
     Register size = ToRegister(instr->size());
@@ -5703,7 +5463,13 @@ void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
   PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
   __ SmiTag(size, size);
   __ push(size);
-  CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
+  if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+    CallRuntimeFromDeferred(
+        Runtime::kAllocateInOldPointerSpace, 1, instr);
+  } else {
+    CallRuntimeFromDeferred(
+        Runtime::kAllocateInNewSpace, 1, instr);
+  }
   __ StoreToSafepointRegisterSlot(r0, result);
 }
 
@@ -5737,7 +5503,6 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
   // Boilerplate already exists, constant elements are never accessed.
   // Pass an empty fixed array.
   __ mov(r1, Operand(isolate()->factory()->empty_fixed_array()));
-  __ Push(r3, r2, r1);
 
   // Pick the right runtime function or stub to call.
   int length = instr->hydrogen()->length();
@@ -5748,8 +5513,10 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
     FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
     CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
   } else if (instr->hydrogen()->depth() > 1) {
+    __ Push(r3, r2, r1);
     CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
   } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+    __ Push(r3, r2, r1);
     CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
   } else {
     FastCloneShallowArrayStub::Mode mode =
@@ -5762,170 +5529,6 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
 }
 
 
-void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
-                            Register result,
-                            Register source,
-                            int* offset,
-                            AllocationSiteMode mode) {
-  ASSERT(!source.is(r2));
-  ASSERT(!result.is(r2));
-
-  bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
-      object->map()->CanTrackAllocationSite();
-
-  // Only elements backing stores for non-COW arrays need to be copied.
-  Handle<FixedArrayBase> elements(object->elements());
-  bool has_elements = elements->length() > 0 &&
-      elements->map() != isolate()->heap()->fixed_cow_array_map();
-
-  // Increase the offset so that subsequent objects end up right after
-  // this object and its backing store.
-  int object_offset = *offset;
-  int object_size = object->map()->instance_size();
-  int elements_size = has_elements ? elements->Size() : 0;
-  int elements_offset = *offset + object_size;
-  if (create_allocation_site_info) {
-    elements_offset += AllocationSiteInfo::kSize;
-    *offset += AllocationSiteInfo::kSize;
-  }
-
-  *offset += object_size + elements_size;
-
-  // Copy object header.
-  ASSERT(object->properties()->length() == 0);
-  int inobject_properties = object->map()->inobject_properties();
-  int header_size = object_size - inobject_properties * kPointerSize;
-  for (int i = 0; i < header_size; i += kPointerSize) {
-    if (has_elements && i == JSObject::kElementsOffset) {
-      __ add(r2, result, Operand(elements_offset));
-    } else {
-      __ ldr(r2, FieldMemOperand(source, i));
-    }
-    __ str(r2, FieldMemOperand(result, object_offset + i));
-  }
-
-  // Copy in-object properties.
-  for (int i = 0; i < inobject_properties; i++) {
-    int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
-    Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
-                                          isolate());
-    if (value->IsJSObject()) {
-      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
-      __ add(r2, result, Operand(*offset));
-      __ str(r2, FieldMemOperand(result, total_offset));
-      __ LoadHeapObject(source, value_object);
-      EmitDeepCopy(value_object, result, source, offset,
-                   DONT_TRACK_ALLOCATION_SITE);
-    } else if (value->IsHeapObject()) {
-      __ LoadHeapObject(r2, Handle<HeapObject>::cast(value));
-      __ str(r2, FieldMemOperand(result, total_offset));
-    } else {
-      __ mov(r2, Operand(value));
-      __ str(r2, FieldMemOperand(result, total_offset));
-    }
-  }
-
-  // Build Allocation Site Info if desired
-  if (create_allocation_site_info) {
-    __ mov(r2, Operand(Handle<Map>(isolate()->heap()->
-                                   allocation_site_info_map())));
-    __ str(r2, FieldMemOperand(result, object_size));
-    __ str(source, FieldMemOperand(result, object_size + kPointerSize));
-  }
-
-  if (has_elements) {
-    // Copy elements backing store header.
-    __ LoadHeapObject(source, elements);
-    for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
-      __ ldr(r2, FieldMemOperand(source, i));
-      __ str(r2, FieldMemOperand(result, elements_offset + i));
-    }
-
-    // Copy elements backing store content.
-    int elements_length = has_elements ? elements->length() : 0;
-    if (elements->IsFixedDoubleArray()) {
-      Handle<FixedDoubleArray> double_array =
-          Handle<FixedDoubleArray>::cast(elements);
-      for (int i = 0; i < elements_length; i++) {
-        int64_t value = double_array->get_representation(i);
-        // We only support little endian mode...
-        int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
-        int32_t value_high = static_cast<int32_t>(value >> 32);
-        int total_offset =
-            elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
-        __ mov(r2, Operand(value_low));
-        __ str(r2, FieldMemOperand(result, total_offset));
-        __ mov(r2, Operand(value_high));
-        __ str(r2, FieldMemOperand(result, total_offset + 4));
-      }
-    } else if (elements->IsFixedArray()) {
-      Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
-      for (int i = 0; i < elements_length; i++) {
-        int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
-        Handle<Object> value(fast_elements->get(i), isolate());
-        if (value->IsJSObject()) {
-          Handle<JSObject> value_object = Handle<JSObject>::cast(value);
-          __ add(r2, result, Operand(*offset));
-          __ str(r2, FieldMemOperand(result, total_offset));
-          __ LoadHeapObject(source, value_object);
-          EmitDeepCopy(value_object, result, source, offset,
-                       DONT_TRACK_ALLOCATION_SITE);
-        } else if (value->IsHeapObject()) {
-          __ LoadHeapObject(r2, Handle<HeapObject>::cast(value));
-          __ str(r2, FieldMemOperand(result, total_offset));
-        } else {
-          __ mov(r2, Operand(value));
-          __ str(r2, FieldMemOperand(result, total_offset));
-        }
-      }
-    } else {
-      UNREACHABLE();
-    }
-  }
-}
-
-
-void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
-  int size = instr->hydrogen()->total_size();
-  ElementsKind boilerplate_elements_kind =
-      instr->hydrogen()->boilerplate()->GetElementsKind();
-
-  // Deopt if the array literal boilerplate ElementsKind is of a type different
-  // than the expected one. The check isn't necessary if the boilerplate has
-  // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
-  if (CanTransitionToMoreGeneralFastElementsKind(
-          boilerplate_elements_kind, true)) {
-    __ LoadHeapObject(r1, instr->hydrogen()->boilerplate());
-    // Load map into r2.
-    __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
-    // Load the map's "bit field 2".
-    __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
-    // Retrieve elements_kind from bit field 2.
-    __ ubfx(r2, r2, Map::kElementsKindShift, Map::kElementsKindBitCount);
-    __ cmp(r2, Operand(boilerplate_elements_kind));
-    DeoptimizeIf(ne, instr->environment());
-  }
-
-  // Allocate all objects that are part of the literal in one big
-  // allocation. This avoids multiple limit checks.
-  Label allocated, runtime_allocate;
-  __ Allocate(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
-  __ jmp(&allocated);
-
-  __ bind(&runtime_allocate);
-  __ mov(r0, Operand(Smi::FromInt(size)));
-  __ push(r0);
-  CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
-
-  __ bind(&allocated);
-  int offset = 0;
-  __ LoadHeapObject(r1, instr->hydrogen()->boilerplate());
-  EmitDeepCopy(instr->hydrogen()->boilerplate(), r0, r1, &offset,
-               instr->hydrogen()->allocation_site_mode());
-  ASSERT_EQ(size, offset);
-}
-
-
 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
   Handle<FixedArray> literals(instr->environment()->closure()->literals());
   Handle<FixedArray> constant_properties =
@@ -6002,17 +5605,8 @@ void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
 
   __ bind(&allocated);
   // Copy the content into the newly allocated memory.
-  // (Unroll copy loop once for better throughput).
-  for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
-    __ ldr(r3, FieldMemOperand(r1, i));
-    __ ldr(r2, FieldMemOperand(r1, i + kPointerSize));
-    __ str(r3, FieldMemOperand(r0, i));
-    __ str(r2, FieldMemOperand(r0, i + kPointerSize));
-  }
-  if ((size % (2 * kPointerSize)) != 0) {
-    __ ldr(r3, FieldMemOperand(r1, size - kPointerSize));
-    __ str(r3, FieldMemOperand(r0, size - kPointerSize));
-  }
+  __ CopyFields(r0, r1, double_scratch0(), double_scratch0().low(),
+                size / kPointerSize);
 }
 
 
@@ -6022,7 +5616,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
   Handle<SharedFunctionInfo> shared_info = instr->shared_info();
   bool pretenure = instr->hydrogen()->pretenure();
   if (!pretenure && shared_info->num_literals() == 0) {
-    FastNewClosureStub stub(shared_info->language_mode());
+    FastNewClosureStub stub(shared_info->language_mode(),
+                            shared_info->is_generator());
     __ mov(r1, Operand(shared_info));
     __ push(r1);
     CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
index 686241d..3e24dae 100644 (file)
@@ -137,7 +137,7 @@ class LCodeGen BASE_EMBEDDED {
                             IntegerSignedness signedness);
 
   void DoDeferredTaggedToI(LTaggedToI* instr);
-  void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
+  void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
   void DoDeferredStackCheck(LStackCheck* instr);
   void DoDeferredRandom(LRandom* instr);
   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
@@ -294,17 +294,7 @@ class LCodeGen BASE_EMBEDDED {
   Register ToRegister(int index) const;
   DwVfpRegister ToDoubleRegister(int index) const;
 
-  // Specific math operations - used from DoUnaryMathOperation.
-  void EmitIntegerMathAbs(LUnaryMathOperation* instr);
-  void DoMathAbs(LUnaryMathOperation* instr);
-  void DoMathFloor(LUnaryMathOperation* instr);
-  void DoMathRound(LUnaryMathOperation* instr);
-  void DoMathSqrt(LUnaryMathOperation* instr);
-  void DoMathPowHalf(LUnaryMathOperation* instr);
-  void DoMathLog(LUnaryMathOperation* instr);
-  void DoMathTan(LUnaryMathOperation* instr);
-  void DoMathCos(LUnaryMathOperation* instr);
-  void DoMathSin(LUnaryMathOperation* instr);
+  void EmitIntegerMathAbs(LMathAbs* instr);
 
   // Support for recording safepoint and position information.
   void RecordSafepoint(LPointerMap* pointers,
index a65ab7e..596d58f 100644 (file)
@@ -171,10 +171,8 @@ void LGapResolver::BreakCycle(int index) {
   } else if (source->IsStackSlot()) {
     __ ldr(kSavedValueRegister, cgen_->ToMemOperand(source));
   } else if (source->IsDoubleRegister()) {
-    CpuFeatureScope scope(cgen_->masm(), VFP2);
     __ vmov(kScratchDoubleReg, cgen_->ToDoubleRegister(source));
   } else if (source->IsDoubleStackSlot()) {
-    CpuFeatureScope scope(cgen_->masm(), VFP2);
     __ vldr(kScratchDoubleReg, cgen_->ToMemOperand(source));
   } else {
     UNREACHABLE();
@@ -194,10 +192,8 @@ void LGapResolver::RestoreValue() {
   } else if (saved_destination_->IsStackSlot()) {
     __ str(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_));
   } else if (saved_destination_->IsDoubleRegister()) {
-    CpuFeatureScope scope(cgen_->masm(), VFP2);
     __ vmov(cgen_->ToDoubleRegister(saved_destination_), kScratchDoubleReg);
   } else if (saved_destination_->IsDoubleStackSlot()) {
-    CpuFeatureScope scope(cgen_->masm(), VFP2);
     __ vstr(kScratchDoubleReg, cgen_->ToMemOperand(saved_destination_));
   } else {
     UNREACHABLE();
@@ -233,8 +229,7 @@ void LGapResolver::EmitMove(int index) {
       MemOperand destination_operand = cgen_->ToMemOperand(destination);
       if (in_cycle_) {
         if (!destination_operand.OffsetIsUint12Encodable()) {
-          CpuFeatureScope scope(cgen_->masm(), VFP2);
-            // ip is overwritten while saving the value to the destination.
+          // ip is overwritten while saving the value to the destination.
           // Therefore we can't use ip.  It is OK if the read from the source
           // destroys ip, since that happens before the value is read.
           __ vldr(kScratchDoubleReg.low(), source_operand);
@@ -272,7 +267,6 @@ void LGapResolver::EmitMove(int index) {
     }
 
   } else if (source->IsDoubleRegister()) {
-    CpuFeatureScope scope(cgen_->masm(), VFP2);
     DwVfpRegister source_register = cgen_->ToDoubleRegister(source);
     if (destination->IsDoubleRegister()) {
       __ vmov(cgen_->ToDoubleRegister(destination), source_register);
@@ -282,8 +276,7 @@ void LGapResolver::EmitMove(int index) {
     }
 
   } else if (source->IsDoubleStackSlot()) {
-    CpuFeatureScope scope(cgen_->masm(), VFP2);
-      MemOperand source_operand = cgen_->ToMemOperand(source);
+    MemOperand source_operand = cgen_->ToMemOperand(source);
     if (destination->IsDoubleRegister()) {
       __ vldr(cgen_->ToDoubleRegister(destination), source_operand);
     } else {
index bacf570..7df0c0a 100644 (file)
@@ -291,8 +291,6 @@ void MacroAssembler::Move(Register dst, Register src, Condition cond) {
 
 
 void MacroAssembler::Move(DwVfpRegister dst, DwVfpRegister src) {
-  ASSERT(CpuFeatures::IsSupported(VFP2));
-  CpuFeatureScope scope(this, VFP2);
   if (!dst.is(src)) {
     vmov(dst, src);
   }
@@ -775,6 +773,23 @@ void MacroAssembler::Strd(Register src1, Register src2,
 }
 
 
+void MacroAssembler::VFPEnsureFPSCRState(Register scratch) {
+  // If needed, restore wanted bits of FPSCR.
+  Label fpscr_done;
+  vmrs(scratch);
+  tst(scratch, Operand(kVFPDefaultNaNModeControlBit));
+  b(ne, &fpscr_done);
+  orr(scratch, scratch, Operand(kVFPDefaultNaNModeControlBit));
+  vmsr(scratch);
+  bind(&fpscr_done);
+}
+
+void MacroAssembler::VFPCanonicalizeNaN(const DwVfpRegister value,
+                                        const Condition cond) {
+  vsub(value, value, kDoubleRegZero, cond);
+}
+
+
 void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1,
                                            const DwVfpRegister src2,
                                            const Condition cond) {
@@ -811,7 +826,6 @@ void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
 void MacroAssembler::Vmov(const DwVfpRegister dst,
                           const double imm,
                           const Register scratch) {
-  ASSERT(IsEnabled(VFP2));
   static const DoubleRepresentation minus_zero(-0.0);
   static const DoubleRepresentation zero(0.0);
   DoubleRepresentation value(imm);
@@ -873,7 +887,6 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
 
   // Optionally save all double registers.
   if (save_doubles) {
-    CpuFeatureScope scope(this, VFP2);
     // Check CPU flags for number of registers, setting the Z condition flag.
     CheckFor32DRegs(ip);
 
@@ -938,7 +951,6 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles,
                                     Register argument_count) {
   // Optionally restore all double registers.
   if (save_doubles) {
-    CpuFeatureScope scope(this, VFP2);
     // Calculate the stack location of the saved doubles and restore them.
     const int offset = 2 * kPointerSize;
     sub(r3, fp,
@@ -975,7 +987,6 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles,
 }
 
 void MacroAssembler::GetCFunctionDoubleResult(const DwVfpRegister dst) {
-  ASSERT(CpuFeatures::IsSupported(VFP2));
   if (use_eabi_hardfloat()) {
     Move(dst, d0);
   } else {
@@ -1402,7 +1413,6 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
 
   // Check the context is a native context.
   if (emit_debug_code()) {
-    // TODO(119): avoid push(holder_reg)/pop(holder_reg)
     // Cannot use ip as a temporary in this verification code. Due to the fact
     // that ip is clobbered as part of cmp with an object Operand.
     push(holder_reg);  // Temporarily save holder on the stack.
@@ -1421,7 +1431,6 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
 
   // Check the context is a native context.
   if (emit_debug_code()) {
-    // TODO(119): avoid push(holder_reg)/pop(holder_reg)
     // Cannot use ip as a temporary in this verification code. Due to the fact
     // that ip is clobbered as part of cmp with an object Operand.
     push(holder_reg);  // Temporarily save holder on the stack.
@@ -1991,7 +2000,7 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
                                                  Register scratch4,
                                                  Label* fail,
                                                  int elements_offset) {
-  Label smi_value, maybe_nan, have_double_value, is_nan, done;
+  Label smi_value, store;
   Register mantissa_reg = scratch2;
   Register exponent_reg = scratch3;
 
@@ -2005,73 +2014,28 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
            fail,
            DONT_DO_SMI_CHECK);
 
-  // Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
-  // in the exponent.
-  mov(scratch1, Operand(kNaNOrInfinityLowerBoundUpper32));
-  ldr(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
-  cmp(exponent_reg, scratch1);
-  b(ge, &maybe_nan);
-
-  ldr(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
-
-  bind(&have_double_value);
-  add(scratch1, elements_reg,
-      Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
-  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);
-
-  bind(&maybe_nan);
-  // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
-  // it's an Infinity, and the non-NaN code path applies.
-  b(gt, &is_nan);
-  ldr(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
-  cmp(mantissa_reg, Operand::Zero());
-  b(eq, &have_double_value);
-  bind(&is_nan);
-  // Load canonical NaN for storing into the double array.
-  uint64_t nan_int64 = BitCast<uint64_t>(
-      FixedDoubleArray::canonical_not_the_hole_nan_as_double());
-  mov(mantissa_reg, Operand(static_cast<uint32_t>(nan_int64)));
-  mov(exponent_reg, Operand(static_cast<uint32_t>(nan_int64 >> 32)));
-  jmp(&have_double_value);
+  vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
+  // Force a canonical NaN.
+  if (emit_debug_code()) {
+    vmrs(ip);
+    tst(ip, Operand(kVFPDefaultNaNModeControlBit));
+    Assert(ne, "Default NaN mode not set");
+  }
+  VFPCanonicalizeNaN(d0);
+  b(&store);
 
   bind(&smi_value);
+  Register untagged_value = scratch1;
+  SmiUntag(untagged_value, value_reg);
+  FloatingPointHelper::ConvertIntToDouble(
+          this, untagged_value, FloatingPointHelper::kVFPRegisters, d0,
+          mantissa_reg, exponent_reg, scratch4, s2);
+
+  bind(&store);
   add(scratch1, elements_reg,
-      Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag -
-              elements_offset));
-  add(scratch1, scratch1,
       Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
-  // scratch1 is now effective address of the double element
-
-  FloatingPointHelper::Destination destination;
-  if (CpuFeatures::IsSupported(VFP2)) {
-    destination = FloatingPointHelper::kVFPRegisters;
-  } else {
-    destination = FloatingPointHelper::kCoreRegisters;
-  }
-
-  Register untagged_value = elements_reg;
-  SmiUntag(untagged_value, value_reg);
-  FloatingPointHelper::ConvertIntToDouble(this,
-                                          untagged_value,
-                                          destination,
-                                          d0,
-                                          mantissa_reg,
-                                          exponent_reg,
-                                          scratch4,
-                                          s2);
-  if (destination == FloatingPointHelper::kVFPRegisters) {
-    CpuFeatureScope scope(this, VFP2);
-    vstr(d0, scratch1, 0);
-  } else {
-    str(mantissa_reg, MemOperand(scratch1, 0));
-    str(exponent_reg, MemOperand(scratch1, Register::kSizeInBytes));
-  }
-  bind(&done);
+  vstr(d0, FieldMemOperand(scratch1,
+                           FixedDoubleArray::kHeaderSize - elements_offset));
 }
 
 
@@ -2425,9 +2389,6 @@ void MacroAssembler::SmiToDoubleVFPRegister(Register smi,
 void MacroAssembler::TestDoubleIsInt32(DwVfpRegister double_input,
                                        DwVfpRegister double_scratch) {
   ASSERT(!double_input.is(double_scratch));
-  ASSERT(CpuFeatures::IsSupported(VFP2));
-  CpuFeatureScope scope(this, VFP2);
-
   vcvt_s32_f64(double_scratch.low(), double_input);
   vcvt_f64_s32(double_scratch, double_scratch.low());
   VFPCompareAndSetFlags(double_input, double_scratch);
@@ -2438,9 +2399,6 @@ void MacroAssembler::TryDoubleToInt32Exact(Register result,
                                            DwVfpRegister double_input,
                                            DwVfpRegister double_scratch) {
   ASSERT(!double_input.is(double_scratch));
-  ASSERT(CpuFeatures::IsSupported(VFP2));
-  CpuFeatureScope scope(this, VFP2);
-
   vcvt_s32_f64(double_scratch.low(), double_input);
   vmov(result, double_scratch.low());
   vcvt_f64_s32(double_scratch, double_scratch.low());
@@ -2456,8 +2414,6 @@ void MacroAssembler::TryInt32Floor(Register result,
                                    Label* exact) {
   ASSERT(!result.is(input_high));
   ASSERT(!double_input.is(double_scratch));
-  ASSERT(CpuFeatures::IsSupported(VFP2));
-  CpuFeatureScope scope(this, VFP2);
   Label negative, exception;
 
   // Test for NaN and infinities.
@@ -2502,26 +2458,18 @@ void MacroAssembler::ECMAConvertNumberToInt32(Register source,
                                               Register scratch,
                                               DwVfpRegister double_scratch1,
                                               DwVfpRegister double_scratch2) {
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(this, VFP2);
-    vldr(double_scratch1, FieldMemOperand(source, HeapNumber::kValueOffset));
-    ECMAToInt32VFP(result, double_scratch1, double_scratch2,
-                   scratch, input_high, input_low);
-  } else {
-    Ldrd(input_low, input_high,
-         FieldMemOperand(source, HeapNumber::kValueOffset));
-    ECMAToInt32NoVFP(result, scratch, input_high, input_low);
-  }
+  vldr(double_scratch1, FieldMemOperand(source, HeapNumber::kValueOffset));
+  ECMAToInt32(result, double_scratch1, double_scratch2,
+              scratch, input_high, input_low);
 }
 
 
-void MacroAssembler::ECMAToInt32VFP(Register result,
-                                    DwVfpRegister double_input,
-                                    DwVfpRegister double_scratch,
-                                    Register scratch,
-                                    Register input_high,
-                                    Register input_low) {
-  CpuFeatureScope scope(this, VFP2);
+void MacroAssembler::ECMAToInt32(Register result,
+                                 DwVfpRegister double_input,
+                                 DwVfpRegister double_scratch,
+                                 Register scratch,
+                                 Register input_high,
+                                 Register input_low) {
   ASSERT(!input_high.is(result));
   ASSERT(!input_low.is(result));
   ASSERT(!input_low.is(input_high));
@@ -2561,58 +2509,6 @@ void MacroAssembler::ECMAToInt32VFP(Register result,
 }
 
 
-void MacroAssembler::ECMAToInt32NoVFP(Register result,
-                                      Register scratch,
-                                      Register input_high,
-                                      Register input_low) {
-  ASSERT(!result.is(scratch));
-  ASSERT(!result.is(input_high));
-  ASSERT(!result.is(input_low));
-  ASSERT(!scratch.is(input_high));
-  ASSERT(!scratch.is(input_low));
-  ASSERT(!input_high.is(input_low));
-
-  Label both, out_of_range, negate, done;
-
-  Ubfx(scratch, input_high,
-       HeapNumber::kExponentShift, HeapNumber::kExponentBits);
-  // Load scratch with exponent.
-  sub(scratch, scratch, Operand(HeapNumber::kExponentBias));
-  // If exponent is negative, 0 < input < 1, the result is 0.
-  // If exponent is greater than or equal to 84, the 32 less significant
-  // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
-  // the result is 0.
-  // This test also catch Nan and infinities which also return 0.
-  cmp(scratch, Operand(84));
-  // We do an unsigned comparison so negative numbers are treated as big
-  // positive number and the two tests above are done in one test.
-  b(hs, &out_of_range);
-
-  // Load scratch with 20 - exponent.
-  rsb(scratch, scratch, Operand(20), SetCC);
-  b(mi, &both);
-
-  // Test 0 and -0.
-  bic(result, input_high, Operand(HeapNumber::kSignMask));
-  orr(result, result, Operand(input_low), SetCC);
-  b(eq, &done);
-  // 0 <= exponent <= 20, shift only input_high.
-  // Scratch contains: 20 - exponent.
-  Ubfx(result, input_high,
-       0, HeapNumber::kMantissaBitsInTopWord);
-  // Set the implicit 1 before the mantissa part in input_high.
-  orr(result, result, Operand(1 << HeapNumber::kMantissaBitsInTopWord));
-  mov(result, Operand(result, LSR, scratch));
-  b(&negate);
-
-  bind(&both);
-  // Restore scratch to exponent - 1 to be consistent with ECMAToInt32VFP.
-  rsb(scratch, scratch, Operand(19));
-  ECMAToInt32Tail(result, scratch, input_high, input_low,
-                  &out_of_range, &negate, &done);
-}
-
-
 void MacroAssembler::ECMAToInt32Tail(Register result,
                                      Register scratch,
                                      Register input_high,
@@ -2715,10 +2611,7 @@ void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
   const Runtime::Function* function = Runtime::FunctionForId(id);
   mov(r0, Operand(function->nargs));
   mov(r1, Operand(ExternalReference(function, isolate())));
-  SaveFPRegsMode mode = CpuFeatures::IsSupported(VFP2)
-      ? kSaveFPRegs
-      : kDontSaveFPRegs;
-  CEntryStub stub(1, mode);
+  CEntryStub stub(1, kSaveFPRegs);
   CallStub(&stub);
 }
 
@@ -3244,27 +3137,24 @@ void MacroAssembler::AllocateHeapNumberWithValue(Register result,
 // Copies a fixed number of fields of heap objects from src to dst.
 void MacroAssembler::CopyFields(Register dst,
                                 Register src,
-                                RegList temps,
+                                DwVfpRegister double_scratch,
+                                SwVfpRegister single_scratch,
                                 int field_count) {
-  // At least one bit set in the first 15 registers.
-  ASSERT((temps & ((1 << 15) - 1)) != 0);
-  ASSERT((temps & dst.bit()) == 0);
-  ASSERT((temps & src.bit()) == 0);
-  // Primitive implementation using only one temporary register.
-
-  Register tmp = no_reg;
-  // Find a temp register in temps list.
-  for (int i = 0; i < 15; i++) {
-    if ((temps & (1 << i)) != 0) {
-      tmp.set_code(i);
-      break;
-    }
+  int double_count = field_count / (DwVfpRegister::kSizeInBytes / kPointerSize);
+  for (int i = 0; i < double_count; i++) {
+    vldr(double_scratch, FieldMemOperand(src, i * DwVfpRegister::kSizeInBytes));
+    vstr(double_scratch, FieldMemOperand(dst, i * DwVfpRegister::kSizeInBytes));
   }
-  ASSERT(!tmp.is(no_reg));
 
-  for (int i = 0; i < field_count; i++) {
-    ldr(tmp, FieldMemOperand(src, i * kPointerSize));
-    str(tmp, FieldMemOperand(dst, i * kPointerSize));
+  STATIC_ASSERT(SwVfpRegister::kSizeInBytes == kPointerSize);
+  STATIC_ASSERT(2 * SwVfpRegister::kSizeInBytes == DwVfpRegister::kSizeInBytes);
+
+  int remain = field_count % (DwVfpRegister::kSizeInBytes / kPointerSize);
+  if (remain != 0) {
+    vldr(single_scratch,
+         FieldMemOperand(src, (field_count - 1) * kPointerSize));
+    vstr(single_scratch,
+         FieldMemOperand(dst, (field_count - 1) * kPointerSize));
   }
 }
 
@@ -3463,7 +3353,6 @@ void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
 
 
 void MacroAssembler::SetCallCDoubleArguments(DwVfpRegister dreg) {
-  ASSERT(CpuFeatures::IsSupported(VFP2));
   if (use_eabi_hardfloat()) {
     Move(d0, dreg);
   } else {
@@ -3474,7 +3363,6 @@ void MacroAssembler::SetCallCDoubleArguments(DwVfpRegister dreg) {
 
 void MacroAssembler::SetCallCDoubleArguments(DwVfpRegister dreg1,
                                              DwVfpRegister dreg2) {
-  ASSERT(CpuFeatures::IsSupported(VFP2));
   if (use_eabi_hardfloat()) {
     if (dreg2.is(d0)) {
       ASSERT(!dreg1.is(d1));
@@ -3493,7 +3381,6 @@ void MacroAssembler::SetCallCDoubleArguments(DwVfpRegister dreg1,
 
 void MacroAssembler::SetCallCDoubleArguments(DwVfpRegister dreg,
                                              Register reg) {
-  ASSERT(CpuFeatures::IsSupported(VFP2));
   if (use_eabi_hardfloat()) {
     Move(d0, dreg);
     Move(r0, reg);
index 958fcac..86ae8f2 100644 (file)
@@ -460,6 +460,19 @@ class MacroAssembler: public Assembler {
             const MemOperand& dst,
             Condition cond = al);
 
+  // Ensure that FPSCR contains values needed by JavaScript.
+  // We need the NaNModeControlBit to be sure that operations like
+  // vadd and vsub generate the Canonical NaN (if a NaN must be generated).
+  // In VFP3 it will be always the Canonical NaN.
+  // In VFP2 it will be either the Canonical NaN or the negative version
+  // of the Canonical NaN. It doesn't matter if we have two values. The aim
+  // is to be sure to never generate the hole NaN.
+  void VFPEnsureFPSCRState(Register scratch);
+
+  // If the value is a NaN, canonicalize the value else, do nothing.
+  void VFPCanonicalizeNaN(const DwVfpRegister value,
+                          const Condition cond = al);
+
   // Compare double values and move the result to the normal condition flags.
   void VFPCompareAndSetFlags(const DwVfpRegister src1,
                              const DwVfpRegister src2,
@@ -743,7 +756,11 @@ class MacroAssembler: public Assembler {
                                    Label* gc_required);
 
   // Copies a fixed number of fields of heap objects from src to dst.
-  void CopyFields(Register dst, Register src, RegList temps, int field_count);
+  void CopyFields(Register dst,
+                  Register src,
+                  DwVfpRegister double_scratch,
+                  SwVfpRegister single_scratch,
+                  int field_count);
 
   // Copies a number of bytes from src to dst. All registers are clobbered. On
   // exit src and dst will point to the place just after where the last byte was
@@ -969,20 +986,12 @@ class MacroAssembler: public Assembler {
   // Performs a truncating conversion of a floating point number as used by
   // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
   // Exits with 'result' holding the answer and all other registers clobbered.
-  void ECMAToInt32VFP(Register result,
-                      DwVfpRegister double_input,
-                      DwVfpRegister double_scratch,
-                      Register scratch,
-                      Register input_high,
-                      Register input_low);
-
-  // Performs a truncating conversion of a floating point number as used by
-  // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
-  // Exits with 'result' holding the answer.
-  void ECMAToInt32NoVFP(Register result,
-                        Register scratch,
-                        Register input_high,
-                        Register input_low);
+  void ECMAToInt32(Register result,
+                   DwVfpRegister double_input,
+                   DwVfpRegister double_scratch,
+                   Register scratch,
+                   Register input_high,
+                   Register input_low);
 
   // Count leading zeros in a 32 bit word.  On ARM5 and later it uses the clz
   // instruction.  On pre-ARM5 hardware this routine gives the wrong answer
@@ -1140,7 +1149,9 @@ class MacroAssembler: public Assembler {
 
   // EABI variant for double arguments in use.
   bool use_eabi_hardfloat() {
-#if USE_EABI_HARDFLOAT
+#ifdef __arm__
+    return OS::ArmUsingHardFloat();
+#elif USE_EABI_HARDFLOAT
     return true;
 #else
     return false;
index 2551e14..ad4d77d 100644 (file)
@@ -721,7 +721,7 @@ void Simulator::CheckICache(v8::internal::HashMap* i_cache,
                  Instruction::kInstrSize) == 0);
   } else {
     // Cache miss.  Load memory into the cache.
-    memcpy(cached_line, line, CachePage::kLineLength);
+    OS::MemCopy(cached_line, line, CachePage::kLineLength);
     *cache_valid_byte = CachePage::LINE_VALID;
   }
 }
@@ -773,6 +773,7 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
   c_flag_FPSCR_ = false;
   v_flag_FPSCR_ = false;
   FPSCR_rounding_mode_ = RZ;
+  FPSCR_default_NaN_mode_ = true;
 
   inv_op_vfp_flag_ = false;
   div_zero_vfp_flag_ = false;
@@ -902,8 +903,8 @@ double Simulator::get_double_from_register_pair(int reg) {
   // Read the bits from the unsigned integer register_[] array
   // into the double precision floating point value and return it.
   char buffer[2 * sizeof(vfp_registers_[0])];
-  memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
-  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
+  OS::MemCopy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
+  OS::MemCopy(&dm_val, buffer, 2 * sizeof(registers_[0]));
   return(dm_val);
 }
 
@@ -953,9 +954,9 @@ void Simulator::SetVFPRegister(int reg_index, const InputType& value) {
   if (register_size == 2) ASSERT(reg_index < DwVfpRegister::NumRegisters());
 
   char buffer[register_size * sizeof(vfp_registers_[0])];
-  memcpy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
-  memcpy(&vfp_registers_[reg_index * register_size], buffer,
-         register_size * sizeof(vfp_registers_[0]));
+  OS::MemCopy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
+  OS::MemCopy(&vfp_registers_[reg_index * register_size], buffer,
+              register_size * sizeof(vfp_registers_[0]));
 }
 
 
@@ -967,64 +968,34 @@ ReturnType Simulator::GetFromVFPRegister(int reg_index) {
 
   ReturnType value = 0;
   char buffer[register_size * sizeof(vfp_registers_[0])];
-  memcpy(buffer, &vfp_registers_[register_size * reg_index],
-         register_size * sizeof(vfp_registers_[0]));
-  memcpy(&value, buffer, register_size * sizeof(vfp_registers_[0]));
+  OS::MemCopy(buffer, &vfp_registers_[register_size * reg_index],
+              register_size * sizeof(vfp_registers_[0]));
+  OS::MemCopy(&value, buffer, register_size * sizeof(vfp_registers_[0]));
   return value;
 }
 
 
-// For use in calls that take two double values, constructed either
+// Runtime FP routines take up to two double arguments and zero
+// or one integer arguments. All are constructed here,
 // from r0-r3 or d0 and d1.
-void Simulator::GetFpArgs(double* x, double* y) {
+void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
   if (use_eabi_hardfloat()) {
     *x = vfp_registers_[0];
     *y = vfp_registers_[1];
+    *z = registers_[1];
   } else {
     // We use a char buffer to get around the strict-aliasing rules which
     // otherwise allow the compiler to optimize away the copy.
     char buffer[sizeof(*x)];
     // Registers 0 and 1 -> x.
-    memcpy(buffer, registers_, sizeof(*x));
-    memcpy(x, buffer, sizeof(*x));
+    OS::MemCopy(buffer, registers_, sizeof(*x));
+    OS::MemCopy(x, buffer, sizeof(*x));
     // Registers 2 and 3 -> y.
-    memcpy(buffer, registers_ + 2, sizeof(*y));
-    memcpy(y, buffer, sizeof(*y));
-  }
-}
-
-// For use in calls that take one double value, constructed either
-// from r0 and r1 or d0.
-void Simulator::GetFpArgs(double* x) {
-  if (use_eabi_hardfloat()) {
-    *x = vfp_registers_[0];
-  } else {
-    // We use a char buffer to get around the strict-aliasing rules which
-    // otherwise allow the compiler to optimize away the copy.
-    char buffer[sizeof(*x)];
-    // Registers 0 and 1 -> x.
-    memcpy(buffer, registers_, sizeof(*x));
-    memcpy(x, buffer, sizeof(*x));
-  }
-}
-
-
-// For use in calls that take one double value constructed either
-// from r0 and r1 or d0 and one integer value.
-void Simulator::GetFpArgs(double* x, int32_t* y) {
-  if (use_eabi_hardfloat()) {
-    *x = vfp_registers_[0];
-    *y = registers_[1];
-  } else {
-    // We use a char buffer to get around the strict-aliasing rules which
-    // otherwise allow the compiler to optimize away the copy.
-    char buffer[sizeof(*x)];
-    // Registers 0 and 1 -> x.
-    memcpy(buffer, registers_, sizeof(*x));
-    memcpy(x, buffer, sizeof(*x));
-    // Register 2 -> y.
-    memcpy(buffer, registers_ + 2, sizeof(*y));
-    memcpy(y, buffer, sizeof(*y));
+    OS::MemCopy(buffer, registers_ + 2, sizeof(*y));
+    OS::MemCopy(y, buffer, sizeof(*y));
+    // Register 2 -> z.
+    OS::MemCopy(buffer, registers_ + 2, sizeof(*z));
+    OS::MemCopy(z, buffer, sizeof(*z));
   }
 }
 
@@ -1033,14 +1004,14 @@ void Simulator::GetFpArgs(double* x, int32_t* y) {
 void Simulator::SetFpResult(const double& result) {
   if (use_eabi_hardfloat()) {
     char buffer[2 * sizeof(vfp_registers_[0])];
-    memcpy(buffer, &result, sizeof(buffer));
+    OS::MemCopy(buffer, &result, sizeof(buffer));
     // Copy result to d0.
-    memcpy(vfp_registers_, buffer, sizeof(buffer));
+    OS::MemCopy(vfp_registers_, buffer, sizeof(buffer));
   } else {
     char buffer[2 * sizeof(registers_[0])];
-    memcpy(buffer, &result, sizeof(buffer));
+    OS::MemCopy(buffer, &result, sizeof(buffer));
     // Copy result to r0 and r1.
-    memcpy(registers_, buffer, sizeof(buffer));
+    OS::MemCopy(registers_, buffer, sizeof(buffer));
   }
 }
 
@@ -1619,12 +1590,12 @@ void Simulator::HandleVList(Instruction* instr) {
           ReadW(reinterpret_cast<int32_t>(address + 1), instr)
         };
         double d;
-        memcpy(&d, data, 8);
+        OS::MemCopy(&d, data, 8);
         set_d_register_from_double(reg, d);
       } else {
         int32_t data[2];
         double d = get_double_from_d_register(reg);
-        memcpy(data, &d, 8);
+        OS::MemCopy(data, &d, 8);
         WriteW(reinterpret_cast<int32_t>(address), data[0], instr);
         WriteW(reinterpret_cast<int32_t>(address + 1), data[1], instr);
       }
@@ -1647,10 +1618,12 @@ typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
                                         int32_t arg3,
                                         int32_t arg4,
                                         int32_t arg5);
-typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
-                                         int32_t arg1,
-                                         int32_t arg2,
-                                         int32_t arg3);
+
+// These prototypes handle the four types of FP calls.
+typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPCall)(double darg0);
+typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
 
 // This signature supports direct call in to API function native callback
 // (refer to InvocationCallback in v8.h).
@@ -1716,27 +1689,27 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
       intptr_t external =
           reinterpret_cast<intptr_t>(redirection->external_function());
       if (fp_call) {
+        double dval0, dval1;  // one or two double parameters
+        int32_t ival;         // zero or one integer parameters
+        int64_t iresult = 0;  // integer return value
+        double dresult = 0;   // double return value
+        GetFpArgs(&dval0, &dval1, &ival);
         if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
-          SimulatorRuntimeFPCall target =
-              reinterpret_cast<SimulatorRuntimeFPCall>(external);
-          double dval0, dval1;
-          int32_t ival;
+          SimulatorRuntimeCall generic_target =
+            reinterpret_cast<SimulatorRuntimeCall>(external);
           switch (redirection->type()) {
           case ExternalReference::BUILTIN_FP_FP_CALL:
           case ExternalReference::BUILTIN_COMPARE_CALL:
-            GetFpArgs(&dval0, &dval1);
             PrintF("Call to host function at %p with args %f, %f",
-                FUNCTION_ADDR(target), dval0, dval1);
+                   FUNCTION_ADDR(generic_target), dval0, dval1);
             break;
           case ExternalReference::BUILTIN_FP_CALL:
-            GetFpArgs(&dval0);
             PrintF("Call to host function at %p with arg %f",
-                FUNCTION_ADDR(target), dval0);
+                FUNCTION_ADDR(generic_target), dval0);
             break;
           case ExternalReference::BUILTIN_FP_INT_CALL:
-            GetFpArgs(&dval0, &ival);
             PrintF("Call to host function at %p with args %f, %d",
-                FUNCTION_ADDR(target), dval0, ival);
+                   FUNCTION_ADDR(generic_target), dval0, ival);
             break;
           default:
             UNREACHABLE();
@@ -1748,22 +1721,54 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
           PrintF("\n");
         }
         CHECK(stack_aligned);
-        if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
+        switch (redirection->type()) {
+        case ExternalReference::BUILTIN_COMPARE_CALL: {
+          SimulatorRuntimeCompareCall target =
+            reinterpret_cast<SimulatorRuntimeCompareCall>(external);
+          iresult = target(dval0, dval1);
+          set_register(r0, static_cast<int32_t>(iresult));
+          set_register(r1, static_cast<int32_t>(iresult >> 32));
+          break;
+        }
+        case ExternalReference::BUILTIN_FP_FP_CALL: {
+          SimulatorRuntimeFPFPCall target =
+            reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
+          dresult = target(dval0, dval1);
+          SetFpResult(dresult);
+          break;
+        }
+        case ExternalReference::BUILTIN_FP_CALL: {
           SimulatorRuntimeFPCall target =
-              reinterpret_cast<SimulatorRuntimeFPCall>(external);
-          double result = target(arg0, arg1, arg2, arg3);
-          SetFpResult(result);
-        } else {
-          SimulatorRuntimeCall target =
-              reinterpret_cast<SimulatorRuntimeCall>(external);
-          int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
-          int32_t lo_res = static_cast<int32_t>(result);
-          int32_t hi_res = static_cast<int32_t>(result >> 32);
-          if (::v8::internal::FLAG_trace_sim) {
-            PrintF("Returned %08x\n", lo_res);
+            reinterpret_cast<SimulatorRuntimeFPCall>(external);
+          dresult = target(dval0);
+          SetFpResult(dresult);
+          break;
+        }
+        case ExternalReference::BUILTIN_FP_INT_CALL: {
+          SimulatorRuntimeFPIntCall target =
+            reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
+          dresult = target(dval0, ival);
+          SetFpResult(dresult);
+          break;
+        }
+        default:
+          UNREACHABLE();
+          break;
+        }
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          switch (redirection->type()) {
+          case ExternalReference::BUILTIN_COMPARE_CALL:
+            PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
+            break;
+          case ExternalReference::BUILTIN_FP_FP_CALL:
+          case ExternalReference::BUILTIN_FP_CALL:
+          case ExternalReference::BUILTIN_FP_INT_CALL:
+            PrintF("Returned %f\n", dresult);
+            break;
+          default:
+            UNREACHABLE();
+            break;
           }
-          set_register(r0, lo_res);
-          set_register(r1, hi_res);
         }
       } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
         SimulatorRuntimeDirectApiCall target =
@@ -1864,6 +1869,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
 }
 
 
+double Simulator::canonicalizeNaN(double value) {
+  return (FPSCR_default_NaN_mode_ && isnan(value)) ?
+    FixedDoubleArray::canonical_not_the_hole_nan_as_double() : value;
+}
+
 // Stop helper functions.
 bool Simulator::isStopInstruction(Instruction* instr) {
   return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
@@ -2724,11 +2734,13 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
         // vabs
         double dm_value = get_double_from_d_register(vm);
         double dd_value = fabs(dm_value);
+        dd_value = canonicalizeNaN(dd_value);
         set_d_register_from_double(vd, dd_value);
       } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
         // vneg
         double dm_value = get_double_from_d_register(vm);
         double dd_value = -dm_value;
+        dd_value = canonicalizeNaN(dd_value);
         set_d_register_from_double(vd, dd_value);
       } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
         DecodeVCVTBetweenDoubleAndSingle(instr);
@@ -2744,6 +2756,7 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
         // vsqrt
         double dm_value = get_double_from_d_register(vm);
         double dd_value = sqrt(dm_value);
+        dd_value = canonicalizeNaN(dd_value);
         set_d_register_from_double(vd, dd_value);
       } else if (instr->Opc3Value() == 0x0) {
         // vmov immediate.
@@ -2765,12 +2778,14 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
         double dn_value = get_double_from_d_register(vn);
         double dm_value = get_double_from_d_register(vm);
         double dd_value = dn_value - dm_value;
+        dd_value = canonicalizeNaN(dd_value);
         set_d_register_from_double(vd, dd_value);
       } else {
         // vadd
         double dn_value = get_double_from_d_register(vn);
         double dm_value = get_double_from_d_register(vm);
         double dd_value = dn_value + dm_value;
+        dd_value = canonicalizeNaN(dd_value);
         set_d_register_from_double(vd, dd_value);
       }
     } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
@@ -2782,6 +2797,7 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
       double dn_value = get_double_from_d_register(vn);
       double dm_value = get_double_from_d_register(vm);
       double dd_value = dn_value * dm_value;
+      dd_value = canonicalizeNaN(dd_value);
       set_d_register_from_double(vd, dd_value);
     } else if ((instr->Opc1Value() == 0x0)) {
       // vmla, vmls
@@ -2799,9 +2815,13 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
       // result with too high precision.
       set_d_register_from_double(vd, dn_val * dm_val);
       if (is_vmls) {
-        set_d_register_from_double(vd, dd_val - get_double_from_d_register(vd));
+        set_d_register_from_double(
+          vd,
+          canonicalizeNaN(dd_val - get_double_from_d_register(vd)));
       } else {
-        set_d_register_from_double(vd, dd_val + get_double_from_d_register(vd));
+        set_d_register_from_double(
+          vd,
+          canonicalizeNaN(dd_val + get_double_from_d_register(vd)));
       }
     } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
       // vdiv
@@ -2813,6 +2833,7 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
       double dm_value = get_double_from_d_register(vm);
       double dd_value = dn_value / dm_value;
       div_zero_vfp_flag_ = (dm_value == 0);
+      dd_value = canonicalizeNaN(dd_value);
       set_d_register_from_double(vd, dd_value);
     } else {
       UNIMPLEMENTED();  // Not used by V8.
@@ -2828,9 +2849,9 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
       int vd = instr->Bits(19, 16) | (instr->Bit(7) << 4);
       double dd_value = get_double_from_d_register(vd);
       int32_t data[2];
-      memcpy(data, &dd_value, 8);
+      OS::MemCopy(data, &dd_value, 8);
       data[instr->Bit(21)] = get_register(instr->RtValue());
-      memcpy(&dd_value, data, 8);
+      OS::MemCopy(&dd_value, data, 8);
       set_d_register_from_double(vd, dd_value);
     } else if ((instr->VLValue() == 0x1) &&
                (instr->VCValue() == 0x0) &&
@@ -2846,6 +2867,7 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
                          (z_flag_FPSCR_ << 30) |
                          (c_flag_FPSCR_ << 29) |
                          (v_flag_FPSCR_ << 28) |
+                         (FPSCR_default_NaN_mode_ << 25) |
                          (inexact_vfp_flag_ << 4) |
                          (underflow_vfp_flag_ << 3) |
                          (overflow_vfp_flag_ << 2) |
@@ -2868,6 +2890,7 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
         z_flag_FPSCR_ = (rt_value >> 30) & 1;
         c_flag_FPSCR_ = (rt_value >> 29) & 1;
         v_flag_FPSCR_ = (rt_value >> 28) & 1;
+        FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
         inexact_vfp_flag_ = (rt_value >> 4) & 1;
         underflow_vfp_flag_ = (rt_value >> 3) & 1;
         overflow_vfp_flag_ = (rt_value >> 2) & 1;
@@ -3179,13 +3202,13 @@ void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
           if (instr->HasL()) {
             int32_t data[2];
             double d = get_double_from_d_register(vm);
-            memcpy(data, &d, 8);
+            OS::MemCopy(data, &d, 8);
             set_register(rt, data[0]);
             set_register(rn, data[1]);
           } else {
             int32_t data[] = { get_register(rt), get_register(rn) };
             double d;
-            memcpy(&d, data, 8);
+            OS::MemCopy(&d, data, 8);
             set_d_register_from_double(vm, d);
           }
         }
@@ -3208,13 +3231,13 @@ void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
             ReadW(address + 4, instr)
           };
           double val;
-          memcpy(&val, data, 8);
+          OS::MemCopy(&val, data, 8);
           set_d_register_from_double(vd, val);
         } else {
           // Store double to memory: vstr.
           int32_t data[2];
           double val = get_double_from_d_register(vd);
-          memcpy(data, &val, 8);
+          OS::MemCopy(data, &val, 8);
           WriteW(address, data[0], instr);
           WriteW(address + 4, data[1], instr);
         }
@@ -3437,9 +3460,9 @@ double Simulator::CallFP(byte* entry, double d0, double d1) {
   } else {
     int buffer[2];
     ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0));
-    memcpy(buffer, &d0, sizeof(d0));
+    OS::MemCopy(buffer, &d0, sizeof(d0));
     set_dw_register(0, buffer);
-    memcpy(buffer, &d1, sizeof(d1));
+    OS::MemCopy(buffer, &d1, sizeof(d1));
     set_dw_register(2, buffer);
   }
   CallInternal(entry);
index b918ecf..45ae999 100644 (file)
@@ -274,6 +274,7 @@ class Simulator {
   // Support for VFP.
   void Compute_FPSCR_Flags(double val1, double val2);
   void Copy_FPSCR_to_APSR();
+  inline double canonicalizeNaN(double value);
 
   // Helper functions to decode common "addressing" modes
   int32_t GetShiftRm(Instruction* instr, bool* carry_out);
@@ -347,10 +348,8 @@ class Simulator {
       void* external_function,
       v8::internal::ExternalReference::Type type);
 
-  // For use in calls that take double value arguments.
-  void GetFpArgs(double* x, double* y);
-  void GetFpArgs(double* x);
-  void GetFpArgs(double* x, int32_t* y);
+  // Handle arguments and return value for runtime FP functions.
+  void GetFpArgs(double* x, double* y, int32_t* z);
   void SetFpResult(const double& result);
   void TrashCallerSaveRegisters();
 
@@ -381,6 +380,7 @@ class Simulator {
 
   // VFP rounding mode. See ARM DDI 0406B Page A2-29.
   VFPRoundingMode FPSCR_rounding_mode_;
+  bool FPSCR_default_NaN_mode_;
 
   // VFP FP exception flags architecture state.
   bool inv_op_vfp_flag_;
index f2d45e1..f22acb4 100644 (file)
@@ -417,30 +417,48 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
 }
 
 
-// Generate StoreField code, value is passed in r0 register.
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+static void GenerateCheckPropertyCell(MacroAssembler* masm,
+                                      Handle<GlobalObject> global,
+                                      Handle<Name> name,
+                                      Register scratch,
+                                      Label* miss) {
+  Handle<JSGlobalPropertyCell> cell =
+      GlobalObject::EnsurePropertyCell(global, name);
+  ASSERT(cell->value()->IsTheHole());
+  __ mov(scratch, Operand(cell));
+  __ ldr(scratch,
+         FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+  __ cmp(scratch, ip);
+  __ b(ne, miss);
+}
+
+
+// Generate StoreTransition code, value is passed in r0 register.
 // When leaving generated code after success, the receiver_reg and name_reg
 // may be clobbered.  Upon branch to miss_label, the receiver and name
 // registers have their original values.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
-                                      Handle<JSObject> object,
-                                      LookupResult* lookup,
-                                      Handle<Map> transition,
-                                      Handle<Name> name,
-                                      Register receiver_reg,
-                                      Register name_reg,
-                                      Register value_reg,
-                                      Register scratch1,
-                                      Register scratch2,
-                                      Label* miss_label,
-                                      Label* miss_restore_name) {
+void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+                                           Handle<JSObject> object,
+                                           LookupResult* lookup,
+                                           Handle<Map> transition,
+                                           Handle<Name> name,
+                                           Register receiver_reg,
+                                           Register name_reg,
+                                           Register value_reg,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           Label* miss_label,
+                                           Label* miss_restore_name) {
   // r0 : value
   Label exit;
 
   // Check that the map of the object hasn't changed.
-  CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
-                                             : REQUIRE_EXACT_MAP;
   __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
-              DO_SMI_CHECK, mode);
+              DO_SMI_CHECK, REQUIRE_EXACT_MAP);
 
   // Perform global security token check if needed.
   if (object->IsJSGlobalProxy()) {
@@ -448,7 +466,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
   }
 
   // Check that we are allowed to write this.
-  if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
+  if (object->GetPrototype()->IsJSObject()) {
     JSObject* holder;
     // holder == object indicates that no property was found.
     if (lookup->holder() != *object) {
@@ -466,12 +484,18 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     // If no property was found, and the holder (the last object in the
     // prototype chain) is in slow mode, we need to do a negative lookup on the
     // holder.
-    if (lookup->holder() == *object &&
-        !holder->HasFastProperties() &&
-        !holder->IsJSGlobalProxy() &&
-        !holder->IsJSGlobalObject()) {
-      GenerateDictionaryNegativeLookup(
-          masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+    if (lookup->holder() == *object) {
+      if (holder->IsJSGlobalObject()) {
+        GenerateCheckPropertyCell(
+            masm,
+            Handle<GlobalObject>(GlobalObject::cast(holder)),
+            name,
+            scratch1,
+            miss_restore_name);
+      } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+        GenerateDictionaryNegativeLookup(
+            masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+      }
     }
   }
 
@@ -480,7 +504,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
   // Perform map transition for the receiver if necessary.
-  if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
+  if (object->map()->unused_property_fields() == 0) {
     // The properties must be extended before we can store the value.
     // We jump to a runtime call that extends the properties array.
     __ push(receiver_reg);
@@ -494,33 +518,113 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     return;
   }
 
-  int index;
-  if (!transition.is_null()) {
-    // Update the map of the object.
-    __ mov(scratch1, Operand(transition));
-    __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+  // Update the map of the object.
+  __ mov(scratch1, Operand(transition));
+  __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+
+  // Update the write barrier for the map field and pass the now unused
+  // name_reg as scratch register.
+  __ RecordWriteField(receiver_reg,
+                      HeapObject::kMapOffset,
+                      scratch1,
+                      name_reg,
+                      kLRHasNotBeenSaved,
+                      kDontSaveFPRegs,
+                      OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+
+  int index = transition->instance_descriptors()->GetFieldIndex(
+      transition->LastAdded());
 
-    // Update the write barrier for the map field and pass the now unused
-    // name_reg as scratch register.
+  // Adjust for the number of properties stored in the object. Even in the
+  // face of a transition we can use the old map here because the size of the
+  // object and the number of in-object properties is not going to change.
+  index -= object->map()->inobject_properties();
+
+  // TODO(verwaest): Share this code as a code stub.
+  if (index < 0) {
+    // Set the property straight into the object.
+    int offset = object->map()->instance_size() + (index * kPointerSize);
+    __ str(value_reg, FieldMemOperand(receiver_reg, offset));
+
+    // Skip updating write barrier if storing a smi.
+    __ JumpIfSmi(value_reg, &exit);
+
+    // Update the write barrier for the array address.
+    // Pass the now unused name_reg as a scratch register.
+    __ mov(name_reg, value_reg);
     __ RecordWriteField(receiver_reg,
-                        HeapObject::kMapOffset,
-                        scratch1,
+                        offset,
                         name_reg,
+                        scratch1,
                         kLRHasNotBeenSaved,
-                        kDontSaveFPRegs,
-                        OMIT_REMEMBERED_SET,
-                        OMIT_SMI_CHECK);
-    index = transition->instance_descriptors()->GetFieldIndex(
-        transition->LastAdded());
+                        kDontSaveFPRegs);
   } else {
-    index = lookup->GetFieldIndex().field_index();
+    // Write to the properties array.
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
+    // Get the properties array
+    __ ldr(scratch1,
+           FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
+    __ str(value_reg, FieldMemOperand(scratch1, offset));
+
+    // Skip updating write barrier if storing a smi.
+    __ JumpIfSmi(value_reg, &exit);
+
+    // Update the write barrier for the array address.
+    // Ok to clobber receiver_reg and name_reg, since we return.
+    __ mov(name_reg, value_reg);
+    __ RecordWriteField(scratch1,
+                        offset,
+                        name_reg,
+                        receiver_reg,
+                        kLRHasNotBeenSaved,
+                        kDontSaveFPRegs);
   }
 
+  // Return the value (register r0).
+  ASSERT(value_reg.is(r0));
+  __ bind(&exit);
+  __ Ret();
+}
+
+
+// Generate StoreField code, value is passed in r0 register.
+// When leaving generated code after success, the receiver_reg and name_reg
+// may be clobbered.  Upon branch to miss_label, the receiver and name
+// registers have their original values.
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+                                      Handle<JSObject> object,
+                                      LookupResult* lookup,
+                                      Register receiver_reg,
+                                      Register name_reg,
+                                      Register value_reg,
+                                      Register scratch1,
+                                      Register scratch2,
+                                      Label* miss_label) {
+  // r0 : value
+  Label exit;
+
+  // Check that the map of the object hasn't changed.
+  __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
+              DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+
+  // Perform global security token check if needed.
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+  int index = lookup->GetFieldIndex().field_index();
+
   // Adjust for the number of properties stored in the object. Even in the
   // face of a transition we can use the old map here because the size of the
   // object and the number of in-object properties is not going to change.
   index -= object->map()->inobject_properties();
 
+  // TODO(verwaest): Share this code as a code stub.
   if (index < 0) {
     // Set the property straight into the object.
     int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -926,26 +1030,6 @@ class CallInterceptorCompiler BASE_EMBEDDED {
 };
 
 
-// Generate code to check that a global property cell is empty. Create
-// the property cell at compilation time if no cell exists for the
-// property.
-static void GenerateCheckPropertyCell(MacroAssembler* masm,
-                                      Handle<GlobalObject> global,
-                                      Handle<Name> name,
-                                      Register scratch,
-                                      Label* miss) {
-  Handle<JSGlobalPropertyCell> cell =
-      GlobalObject::EnsurePropertyCell(global, name);
-  ASSERT(cell->value()->IsTheHole());
-  __ mov(scratch, Operand(cell));
-  __ ldr(scratch,
-         FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
-  __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
-  __ cmp(scratch, ip);
-  __ b(ne, miss);
-}
-
-
 // Calls GenerateCheckPropertyCell for each global object in the prototype chain
 // from object to (but not including) holder.
 static void GenerateCheckPropertyCells(MacroAssembler* masm,
@@ -975,66 +1059,11 @@ static void StoreIntAsFloat(MacroAssembler* masm,
                             Register dst,
                             Register wordoffset,
                             Register ival,
-                            Register fval,
-                            Register scratch1,
-                            Register scratch2) {
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    __ vmov(s0, ival);
-    __ add(scratch1, dst, Operand(wordoffset, LSL, 2));
-    __ vcvt_f32_s32(s0, s0);
-    __ vstr(s0, scratch1, 0);
-  } else {
-    Label not_special, done;
-    // Move sign bit from source to destination.  This works because the sign
-    // bit in the exponent word of the double has the same position and polarity
-    // as the 2's complement sign bit in a Smi.
-    ASSERT(kBinary32SignMask == 0x80000000u);
-
-    __ and_(fval, ival, Operand(kBinary32SignMask), SetCC);
-    // Negate value if it is negative.
-    __ rsb(ival, ival, Operand::Zero(), LeaveCC, ne);
-
-    // We have -1, 0 or 1, which we treat specially. Register ival contains
-    // absolute value: it is either equal to 1 (special case of -1 and 1),
-    // greater than 1 (not a special case) or less than 1 (special case of 0).
-    __ cmp(ival, Operand(1));
-    __ b(gt, &not_special);
-
-    // For 1 or -1 we need to or in the 0 exponent (biased).
-    static const uint32_t exponent_word_for_1 =
-        kBinary32ExponentBias << kBinary32ExponentShift;
-
-    __ orr(fval, fval, Operand(exponent_word_for_1), LeaveCC, eq);
-    __ b(&done);
-
-    __ bind(&not_special);
-    // Count leading zeros.
-    // Gets the wrong answer for 0, but we already checked for that case above.
-    Register zeros = scratch2;
-    __ CountLeadingZeros(zeros, ival, scratch1);
-
-    // Compute exponent and or it into the exponent register.
-    __ rsb(scratch1,
-           zeros,
-           Operand((kBitsPerInt - 1) + kBinary32ExponentBias));
-
-    __ orr(fval,
-           fval,
-           Operand(scratch1, LSL, kBinary32ExponentShift));
-
-    // Shift up the source chopping the top bit off.
-    __ add(zeros, zeros, Operand(1));
-    // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
-    __ mov(ival, Operand(ival, LSL, zeros));
-    // And the top (top 20 bits).
-    __ orr(fval,
-           fval,
-           Operand(ival, LSR, kBitsPerInt - kBinary32MantissaBits));
-
-    __ bind(&done);
-    __ str(fval, MemOperand(dst, wordoffset, LSL, 2));
-  }
+                            Register scratch1) {
+  __ vmov(s0, ival);
+  __ add(scratch1, dst, Operand(wordoffset, LSL, 2));
+  __ vcvt_f32_s32(s0, s0);
+  __ vstr(s0, scratch1, 0);
 }
 
 
@@ -1225,7 +1254,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     Handle<GlobalObject> global) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
+  HandlerFrontendHeader(object, receiver(), last, name, &miss);
 
   // If the last object in the prototype chain is a global object,
   // check that the global property cell is empty.
@@ -1233,13 +1262,6 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
   }
 
-  if (!last->HasFastProperties()) {
-    __ ldr(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset));
-    __ ldr(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset));
-    __ cmp(scratch2(), Operand(isolate()->factory()->null_value()));
-    __ b(ne, &miss);
-  }
-
   HandlerFrontendFooter(success, &miss);
 }
 
@@ -1599,7 +1621,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
 
       __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
       __ StoreNumberToDoubleElements(
-          r4, r0, elements, r3, r5, r2, r9,
+          r4, r0, elements, r5, r2, r3, r9,
           &call_builtin, argc * kDoubleSize);
 
       // Save new length.
@@ -2089,11 +2111,6 @@ Handle<Code> CallStubCompiler::CompileMathFloorCall(
   //  -- sp[argc * 4]           : receiver
   // -----------------------------------
 
-  if (!CpuFeatures::IsSupported(VFP2)) {
-    return Handle<Code>::null();
-  }
-
-  CpuFeatureScope scope_vfp2(masm(), VFP2);
   const int argc = arguments().immediate();
   // If the object is not a JSObject or we got an unexpected number of
   // arguments, bail out to the regular call.
@@ -3133,36 +3150,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
 }
 
 
-static bool IsElementTypeSigned(ElementsKind elements_kind) {
-  switch (elements_kind) {
-    case EXTERNAL_BYTE_ELEMENTS:
-    case EXTERNAL_SHORT_ELEMENTS:
-    case EXTERNAL_INT_ELEMENTS:
-      return true;
-
-    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-    case EXTERNAL_UNSIGNED_INT_ELEMENTS:
-    case EXTERNAL_PIXEL_ELEMENTS:
-      return false;
-
-    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();
-      return false;
-  }
-  return false;
-}
-
-
 static void GenerateSmiKeyCheck(MacroAssembler* masm,
                                 Register key,
                                 Register scratch0,
@@ -3170,29 +3157,23 @@ static void GenerateSmiKeyCheck(MacroAssembler* masm,
                                 DwVfpRegister double_scratch0,
                                 DwVfpRegister double_scratch1,
                                 Label* fail) {
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(masm, VFP2);
-    Label key_ok;
-    // Check for smi or a smi inside a heap number.  We convert the heap
-    // number and check if the conversion is exact and fits into the smi
-    // range.
-    __ JumpIfSmi(key, &key_ok);
-    __ CheckMap(key,
-                scratch0,
-                Heap::kHeapNumberMapRootIndex,
-                fail,
-                DONT_DO_SMI_CHECK);
-    __ sub(ip, key, Operand(kHeapObjectTag));
-    __ vldr(double_scratch0, ip, HeapNumber::kValueOffset);
-    __ TryDoubleToInt32Exact(scratch0, double_scratch0, double_scratch1);
-    __ b(ne, fail);
-    __ TrySmiTag(scratch0, fail, scratch1);
-    __ mov(key, scratch0);
-    __ bind(&key_ok);
-  } else {
-    // Check that the key is a smi.
-    __ JumpIfNotSmi(key, fail);
-  }
+  Label key_ok;
+  // Check for smi or a smi inside a heap number.  We convert the heap
+  // number and check if the conversion is exact and fits into the smi
+  // range.
+  __ JumpIfSmi(key, &key_ok);
+  __ CheckMap(key,
+              scratch0,
+              Heap::kHeapNumberMapRootIndex,
+              fail,
+              DONT_DO_SMI_CHECK);
+  __ sub(ip, key, Operand(kHeapObjectTag));
+  __ vldr(double_scratch0, ip, HeapNumber::kValueOffset);
+  __ TryDoubleToInt32Exact(scratch0, double_scratch0, double_scratch1);
+  __ b(ne, fail);
+  __ TrySmiTag(scratch0, fail, scratch1);
+  __ mov(key, scratch0);
+  __ bind(&key_ok);
 }
 
 
@@ -3262,28 +3243,18 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
     case EXTERNAL_FLOAT_ELEMENTS:
       // Perform int-to-float conversion and store to memory.
       __ SmiUntag(r4, key);
-      StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
+      StoreIntAsFloat(masm, r3, r4, r5, r7);
       break;
     case EXTERNAL_DOUBLE_ELEMENTS:
       __ add(r3, r3, Operand(key, LSL, 2));
       // r3: effective address of the double element
       FloatingPointHelper::Destination destination;
-      if (CpuFeatures::IsSupported(VFP2)) {
-        destination = FloatingPointHelper::kVFPRegisters;
-      } else {
-        destination = FloatingPointHelper::kCoreRegisters;
-      }
+      destination = FloatingPointHelper::kVFPRegisters;
       FloatingPointHelper::ConvertIntToDouble(
           masm, r5, destination,
           d0, r6, r7,  // These are: double_dst, dst_mantissa, dst_exponent.
           r4, s2);  // These are: scratch2, single_scratch.
-      if (destination == FloatingPointHelper::kVFPRegisters) {
-        CpuFeatureScope scope(masm, VFP2);
-        __ vstr(d0, r3, 0);
-      } else {
-        __ str(r6, MemOperand(r3, 0));
-        __ str(r7, MemOperand(r3, Register::kSizeInBytes));
-      }
+      __ vstr(d0, r3, 0);
       break;
     case FAST_ELEMENTS:
     case FAST_SMI_ELEMENTS:
@@ -3313,201 +3284,59 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
     // The WebGL specification leaves the behavior of storing NaN and
     // +/-Infinity into integer arrays basically undefined. For more
     // reproducible behavior, convert these to zero.
-    if (CpuFeatures::IsSupported(VFP2)) {
-      CpuFeatureScope scope(masm, VFP2);
-
-      if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
-        // vldr requires offset to be a multiple of 4 so we can not
-        // include -kHeapObjectTag into it.
-        __ sub(r5, r0, Operand(kHeapObjectTag));
-        __ vldr(d0, r5, HeapNumber::kValueOffset);
-        __ add(r5, r3, Operand(key, LSL, 1));
-        __ vcvt_f32_f64(s0, d0);
-        __ vstr(s0, r5, 0);
-      } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
-        __ sub(r5, r0, Operand(kHeapObjectTag));
-        __ vldr(d0, r5, HeapNumber::kValueOffset);
-        __ add(r5, r3, Operand(key, LSL, 2));
-        __ vstr(d0, r5, 0);
-      } else {
-        // Hoisted load.  vldr requires offset to be a multiple of 4 so we can
-        // not include -kHeapObjectTag into it.
-        __ sub(r5, value, Operand(kHeapObjectTag));
-        __ vldr(d0, r5, HeapNumber::kValueOffset);
-        __ ECMAToInt32VFP(r5, d0, d1, r6, r7, r9);
-
-        switch (elements_kind) {
-          case EXTERNAL_BYTE_ELEMENTS:
-          case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-            __ strb(r5, MemOperand(r3, key, LSR, 1));
-            break;
-          case EXTERNAL_SHORT_ELEMENTS:
-          case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-            __ strh(r5, MemOperand(r3, key, LSL, 0));
-            break;
-          case EXTERNAL_INT_ELEMENTS:
-          case EXTERNAL_UNSIGNED_INT_ELEMENTS:
-            __ str(r5, MemOperand(r3, key, LSL, 1));
-            break;
-          case EXTERNAL_PIXEL_ELEMENTS:
-          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;
-        }
-      }
 
-      // Entry registers are intact, r0 holds the value which is the return
-      // value.
-      __ Ret();
+    if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+      // vldr requires offset to be a multiple of 4 so we can not
+      // include -kHeapObjectTag into it.
+      __ sub(r5, r0, Operand(kHeapObjectTag));
+      __ vldr(d0, r5, HeapNumber::kValueOffset);
+      __ add(r5, r3, Operand(key, LSL, 1));
+      __ vcvt_f32_f64(s0, d0);
+      __ vstr(s0, r5, 0);
+    } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
+      __ sub(r5, r0, Operand(kHeapObjectTag));
+      __ vldr(d0, r5, HeapNumber::kValueOffset);
+      __ add(r5, r3, Operand(key, LSL, 2));
+      __ vstr(d0, r5, 0);
     } else {
-      // VFP3 is not available do manual conversions.
-      __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
-      __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
-
-      if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
-        Label done, nan_or_infinity_or_zero;
-        static const int kMantissaInHiWordShift =
-            kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
-        static const int kMantissaInLoWordShift =
-            kBitsPerInt - kMantissaInHiWordShift;
-
-        // Test for all special exponent values: zeros, subnormal numbers, NaNs
-        // and infinities. All these should be converted to 0.
-        __ mov(r7, Operand(HeapNumber::kExponentMask));
-        __ and_(r9, r5, Operand(r7), SetCC);
-        __ b(eq, &nan_or_infinity_or_zero);
-
-        __ teq(r9, Operand(r7));
-        __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq);
-        __ b(eq, &nan_or_infinity_or_zero);
-
-        // Rebias exponent.
-        __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
-        __ add(r9,
-               r9,
-               Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
-
-        __ cmp(r9, Operand(kBinary32MaxExponent));
-        __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt);
-        __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt);
-        __ b(gt, &done);
-
-        __ cmp(r9, Operand(kBinary32MinExponent));
-        __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt);
-        __ b(lt, &done);
-
-        __ and_(r7, r5, Operand(HeapNumber::kSignMask));
-        __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
-        __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift));
-        __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift));
-        __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
-
-        __ bind(&done);
-        __ str(r5, MemOperand(r3, key, LSL, 1));
-        // Entry registers are intact, r0 holds the value which is the return
-        // value.
-        __ Ret();
-
-        __ bind(&nan_or_infinity_or_zero);
-        __ and_(r7, r5, Operand(HeapNumber::kSignMask));
-        __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
-        __ orr(r9, r9, r7);
-        __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
-        __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
-        __ b(&done);
-      } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
-        __ add(r7, r3, Operand(key, LSL, 2));
-        // r7: effective address of destination element.
-        __ str(r6, MemOperand(r7, 0));
-        __ str(r5, MemOperand(r7, Register::kSizeInBytes));
-        __ Ret();
-      } else {
-        bool is_signed_type = IsElementTypeSigned(elements_kind);
-        int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
-        int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
-
-        Label done, sign;
-
-        // Test for all special exponent values: zeros, subnormal numbers, NaNs
-        // and infinities. All these should be converted to 0.
-        __ mov(r7, Operand(HeapNumber::kExponentMask));
-        __ and_(r9, r5, Operand(r7), SetCC);
-        __ mov(r5, Operand::Zero(), LeaveCC, eq);
-        __ b(eq, &done);
-
-        __ teq(r9, Operand(r7));
-        __ mov(r5, Operand::Zero(), LeaveCC, eq);
-        __ b(eq, &done);
-
-        // Unbias exponent.
-        __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
-        __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC);
-        // If exponent is negative then result is 0.
-        __ mov(r5, Operand::Zero(), LeaveCC, mi);
-        __ b(mi, &done);
-
-        // If exponent is too big then result is minimal value.
-        __ cmp(r9, Operand(meaningfull_bits - 1));
-        __ mov(r5, Operand(min_value), LeaveCC, ge);
-        __ b(ge, &done);
-
-        __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC);
-        __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
-        __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
-
-        __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
-        __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
-        __ b(pl, &sign);
-
-        __ rsb(r9, r9, Operand::Zero());
-        __ mov(r5, Operand(r5, LSL, r9));
-        __ rsb(r9, r9, Operand(meaningfull_bits));
-        __ orr(r5, r5, Operand(r6, LSR, r9));
-
-        __ bind(&sign);
-        __ teq(r7, Operand::Zero());
-        __ rsb(r5, r5, Operand::Zero(), LeaveCC, ne);
-
-        __ bind(&done);
-        switch (elements_kind) {
-          case EXTERNAL_BYTE_ELEMENTS:
-          case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-            __ strb(r5, MemOperand(r3, key, LSR, 1));
-            break;
-          case EXTERNAL_SHORT_ELEMENTS:
-          case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-            __ strh(r5, MemOperand(r3, key, LSL, 0));
-            break;
-          case EXTERNAL_INT_ELEMENTS:
-          case EXTERNAL_UNSIGNED_INT_ELEMENTS:
-            __ str(r5, MemOperand(r3, key, LSL, 1));
-            break;
-          case EXTERNAL_PIXEL_ELEMENTS:
-          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;
-        }
+      // Hoisted load.  vldr requires offset to be a multiple of 4 so we can
+      // not include -kHeapObjectTag into it.
+      __ sub(r5, value, Operand(kHeapObjectTag));
+      __ vldr(d0, r5, HeapNumber::kValueOffset);
+      __ ECMAToInt32(r5, d0, d1, r6, r7, r9);
+
+      switch (elements_kind) {
+        case EXTERNAL_BYTE_ELEMENTS:
+        case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+          __ strb(r5, MemOperand(r3, key, LSR, 1));
+          break;
+        case EXTERNAL_SHORT_ELEMENTS:
+        case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+          __ strh(r5, MemOperand(r3, key, LSL, 0));
+          break;
+        case EXTERNAL_INT_ELEMENTS:
+        case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+          __ str(r5, MemOperand(r3, key, LSL, 1));
+          break;
+        case EXTERNAL_PIXEL_ELEMENTS:
+        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;
       }
     }
+
+    // Entry registers are intact, r0 holds the value which is the return
+    // value.
+    __ Ret();
   }
 
   // Slow case, key and receiver still in r0 and r1.
@@ -3757,9 +3586,9 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
                                  // All registers after this are overwritten.
                                  elements_reg,
                                  scratch1,
-                                 scratch2,
                                  scratch3,
                                  scratch4,
+                                 scratch2,
                                  &transition_elements_kind);
   __ Ret();
 
index 936d008..54f0b48 100644 (file)
@@ -1017,7 +1017,7 @@ function ArrayFilter(f, receiver) {
   }
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver)) {
+  } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
     receiver = ToObject(receiver);
   }
 
@@ -1068,9 +1068,10 @@ function ArrayForEach(f, receiver) {
   }
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver)) {
+  } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
     receiver = ToObject(receiver);
   }
+
   if (%DebugCallbackSupportsStepping(f)) {
     for (var i = 0; i < length; i++) {
       if (i in array) {
@@ -1111,7 +1112,7 @@ function ArraySome(f, receiver) {
   }
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver)) {
+  } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
     receiver = ToObject(receiver);
   }
 
@@ -1154,7 +1155,7 @@ function ArrayEvery(f, receiver) {
   }
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver)) {
+  } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
     receiver = ToObject(receiver);
   }
 
@@ -1196,7 +1197,7 @@ function ArrayMap(f, receiver) {
   }
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver)) {
+  } else if (!IS_SPEC_OBJECT(receiver) && %IsClassicModeFunction(f)) {
     receiver = ToObject(receiver);
   }
 
@@ -1453,8 +1454,10 @@ function ArrayIsArray(obj) {
 
 
 // -------------------------------------------------------------------
+
 function SetUpArray() {
   %CheckIsBootstrapping();
+
   // Set up non-enumerable constructor property on the Array.prototype
   // object.
   %SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
index deef28b..5bde8c5 100644 (file)
@@ -191,11 +191,9 @@ CpuFeatureScope::CpuFeatureScope(AssemblerBase* assembler, CpuFeature f)
   uint64_t mask = static_cast<uint64_t>(1) << f;
   // TODO(svenpanne) This special case below doesn't belong here!
 #if V8_TARGET_ARCH_ARM
-  // VFP2 and ARMv7 are implied by VFP3.
+  // ARMv7 is implied by VFP3.
   if (f == VFP3) {
-    mask |=
-        static_cast<uint64_t>(1) << VFP2 |
-        static_cast<uint64_t>(1) << ARMv7;
+    mask |= static_cast<uint64_t>(1) << ARMv7;
   }
 #endif
   assembler_->set_enabled_cpu_features(old_enabled_ | mask);
@@ -1191,6 +1189,20 @@ ExternalReference ExternalReference::old_pointer_space_allocation_limit_address(
 }
 
 
+ExternalReference ExternalReference::old_data_space_allocation_top_address(
+    Isolate* isolate) {
+  return ExternalReference(
+      isolate->heap()->OldDataSpaceAllocationTopAddress());
+}
+
+
+ExternalReference ExternalReference::old_data_space_allocation_limit_address(
+    Isolate* isolate) {
+  return ExternalReference(
+      isolate->heap()->OldDataSpaceAllocationLimitAddress());
+}
+
+
 ExternalReference ExternalReference::handle_scope_level_address(
     Isolate* isolate) {
   return ExternalReference(HandleScope::current_level_address(isolate));
index e26b525..381ae0a 100644 (file)
@@ -753,6 +753,10 @@ class ExternalReference BASE_EMBEDDED {
       Isolate* isolate);
   static ExternalReference old_pointer_space_allocation_limit_address(
       Isolate* isolate);
+  static ExternalReference old_data_space_allocation_top_address(
+      Isolate* isolate);
+  static ExternalReference old_data_space_allocation_limit_address(
+      Isolate* isolate);
 
   static ExternalReference double_fp_operation(Token::Value operation,
                                                Isolate* isolate);
index 7d7a5b2..e8b065c 100644 (file)
@@ -509,6 +509,11 @@ bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
   }
   LookupResult lookup(type->GetIsolate());
   while (true) {
+    // If a dictionary map is found in the prototype chain before the actual
+    // target, a new target can always appear. In that case, bail out.
+    // TODO(verwaest): Alternatively a runtime negative lookup on the normal
+    // receiver or prototype could be added.
+    if (type->is_dictionary_map()) return false;
     type->LookupDescriptor(NULL, *name, &lookup);
     if (lookup.IsFound()) {
       switch (lookup.type()) {
@@ -534,7 +539,6 @@ bool Call::ComputeTarget(Handle<Map> type, Handle<String> name) {
     if (!type->prototype()->IsJSObject()) return false;
     // Go up the prototype chain, recording where we are currently.
     holder_ = Handle<JSObject>(JSObject::cast(type->prototype()));
-    if (!holder_->HasFastProperties()) return false;
     type = Handle<Map>(holder()->map());
   }
 }
index dddfc83..b733138 100644 (file)
@@ -1811,7 +1811,8 @@ class CountOperation: public Expression {
   Token::Value op_;
   bool is_prefix_ : 1;
   bool is_monomorphic_ : 1;
-  KeyedAccessStoreMode store_mode_: 4;
+  KeyedAccessStoreMode store_mode_ : 5;  // Windows treats as signed,
+                                         // must have extra bit.
   Expression* expression_;
   int pos_;
   const BailoutId assignment_id_;
@@ -1953,7 +1954,8 @@ class Assignment: public Expression {
   const BailoutId assignment_id_;
 
   bool is_monomorphic_ : 1;
-  KeyedAccessStoreMode store_mode_ : 4;
+  KeyedAccessStoreMode store_mode_ : 5;  // Windows treats as signed,
+                                         // must have extra bit.
   SmallMapList receiver_types_;
 };
 
@@ -1962,21 +1964,25 @@ class Yield: public Expression {
  public:
   DECLARE_NODE_TYPE(Yield)
 
+  Expression* generator_object() const { return generator_object_; }
   Expression* expression() const { return expression_; }
   bool is_delegating_yield() const { return is_delegating_yield_; }
   virtual int position() const { return pos_; }
 
  protected:
   Yield(Isolate* isolate,
+        Expression* generator_object,
         Expression* expression,
         bool is_delegating_yield,
         int pos)
       : Expression(isolate),
+        generator_object_(generator_object),
         expression_(expression),
         is_delegating_yield_(is_delegating_yield),
         pos_(pos) { }
 
  private:
+  Expression* generator_object_;
   Expression* expression_;
   bool is_delegating_yield_;
   int pos_;
@@ -2958,9 +2964,12 @@ class AstNodeFactory BASE_EMBEDDED {
     VISIT_AND_RETURN(Assignment, assign)
   }
 
-  Yield* NewYield(Expression* expression, bool is_delegating_yield, int pos) {
-    Yield* yield =
-        new(zone_) Yield(isolate_, expression, is_delegating_yield, pos);
+  Yield* NewYield(Expression *generator_object,
+                  Expression* expression,
+                  bool is_delegating_yield,
+                  int pos) {
+    Yield* yield = new(zone_) Yield(
+        isolate_, generator_object, expression, is_delegating_yield, pos);
     VISIT_AND_RETURN(Yield, yield)
   }
 
index 181c202..b5078cf 100644 (file)
@@ -31,6 +31,7 @@
 #include <string.h>
 
 #include "atomicops.h"
+#include "platform.h"
 
 // This file only makes sense with atomicops_internals_x86_gcc.h -- it
 // depends on structs that are defined in that file.  If atomicops.h
@@ -84,9 +85,9 @@ void AtomicOps_Internalx86CPUFeaturesInit() {
   // Get vendor string (issue CPUID with eax = 0)
   cpuid(eax, ebx, ecx, edx, 0);
   char vendor[13];
-  memcpy(vendor, &ebx, 4);
-  memcpy(vendor + 4, &edx, 4);
-  memcpy(vendor + 8, &ecx, 4);
+  v8::internal::OS::MemCopy(vendor, &ebx, 4);
+  v8::internal::OS::MemCopy(vendor + 4, &edx, 4);
+  v8::internal::OS::MemCopy(vendor + 8, &ecx, 4);
   vendor[12] = 0;
 
   // get feature flags in ecx/edx, and family/model in eax
index 6e55b50..e58d598 100644 (file)
@@ -168,7 +168,7 @@ inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
   return *ptr;
 }
 
-#if defined(__x86_64__)
+#if defined(__x86_64__) && defined(V8_HOST_ARCH_64_BIT)
 
 // 64-bit low-level operations on 64-bit platform.
 
index 9436322..c8b61ee 100644 (file)
@@ -735,6 +735,13 @@ void Bignum::BigitsShiftLeft(int shift_amount) {
 
 
 void Bignum::SubtractTimes(const Bignum& other, int factor) {
+#ifdef DEBUG
+  Bignum a, b;
+  a.AssignBignum(*this);
+  b.AssignBignum(other);
+  b.MultiplyByUInt32(factor);
+  a.SubtractBignum(b);
+#endif
   ASSERT(exponent_ <= other.exponent_);
   if (factor < 3) {
     for (int i = 0; i < factor; ++i) {
@@ -758,9 +765,9 @@ void Bignum::SubtractTimes(const Bignum& other, int factor) {
     Chunk difference = bigits_[i] - borrow;
     bigits_[i] = difference & kBigitMask;
     borrow = difference >> (kChunkSize - 1);
-    ++i;
   }
   Clamp();
+  ASSERT(Bignum::Equal(a, *this));
 }
 
 
index f57a1f6..12f0cda 100644 (file)
@@ -199,6 +199,8 @@ class Genesis BASE_EMBEDDED {
                                           const char* name,
                                           ElementsKind elements_kind);
   bool InstallNatives();
+
+  void InstallTypedArray(const char* name);
   bool InstallExperimentalNatives();
   void InstallBuiltinFunctionIds();
   void InstallJSFunctionResultCaches();
@@ -303,14 +305,11 @@ Handle<Context> Bootstrapper::CreateEnvironment(
     v8::ExtensionConfiguration* extensions) {
   HandleScope scope(isolate_);
   Genesis genesis(isolate_, global_object, global_template, extensions);
-  if (!genesis.result().is_null()) {
-    Handle<Object> ctx(isolate_->global_handles()->Create(*genesis.result()));
-    Handle<Context> env = Handle<Context>::cast(ctx);
-    if (InstallExtensions(env, extensions)) {
-      return env;
-    }
+  Handle<Context> env = genesis.result();
+  if (env.is_null() || !InstallExtensions(env, extensions)) {
+    return Handle<Context>();
   }
-  return Handle<Context>();
+  return scope.CloseAndEscape(env);
 }
 
 
@@ -477,25 +476,10 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
     native_context()->set_object_function(*object_fun);
 
     // Allocate a new prototype for the object function.
-    Handle<Map> object_prototype_map =
-        factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
-    Handle<DescriptorArray> prototype_descriptors(
-        factory->NewDescriptorArray(0, 1));
-    DescriptorArray::WhitenessWitness witness(*prototype_descriptors);
-
-    Handle<Foreign> object_prototype(
-        factory->NewForeign(&Accessors::ObjectPrototype));
-    PropertyAttributes attribs = static_cast<PropertyAttributes>(DONT_ENUM);
-    object_prototype_map->set_instance_descriptors(*prototype_descriptors);
-
-    {  // Add __proto__.
-      CallbacksDescriptor d(heap->proto_string(), *object_prototype, attribs);
-      object_prototype_map->AppendDescriptor(&d, witness);
-    }
-
-    Handle<JSObject> prototype = factory->NewJSObjectFromMap(
-        object_prototype_map,
+    Handle<JSObject> prototype = factory->NewJSObject(
+        isolate->object_function(),
         TENURED);
+
     native_context()->set_initial_object_prototype(*prototype);
     SetPrototype(object_fun, prototype);
   }
@@ -1276,6 +1260,14 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
 }
 
 
+void Genesis::InstallTypedArray(const char* name) {
+  Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
+  InstallFunction(global, name, JS_TYPED_ARRAY_TYPE,
+                  JSTypedArray::kSize, isolate()->initial_object_prototype(),
+                  Builtins::kIllegal, true);
+}
+
+
 void Genesis::InitializeExperimentalGlobal() {
   Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
 
@@ -1293,33 +1285,80 @@ void Genesis::InitializeExperimentalGlobal() {
 
   if (FLAG_harmony_collections) {
     {  // -- S e t
-      Handle<JSObject> prototype =
-          factory()->NewJSObject(isolate()->object_function(), TENURED);
       InstallFunction(global, "Set", JS_SET_TYPE, JSSet::kSize,
-                      prototype, Builtins::kIllegal, true);
+                      isolate()->initial_object_prototype(),
+                      Builtins::kIllegal, true);
     }
     {  // -- M a p
-      Handle<JSObject> prototype =
-          factory()->NewJSObject(isolate()->object_function(), TENURED);
       InstallFunction(global, "Map", JS_MAP_TYPE, JSMap::kSize,
-                      prototype, Builtins::kIllegal, true);
+                      isolate()->initial_object_prototype(),
+                      Builtins::kIllegal, true);
     }
     {  // -- W e a k M a p
-      Handle<JSObject> prototype =
-          factory()->NewJSObject(isolate()->object_function(), TENURED);
       InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
-                      prototype, Builtins::kIllegal, true);
+                      isolate()->initial_object_prototype(),
+                      Builtins::kIllegal, true);
     }
   }
 
   if (FLAG_harmony_typed_arrays) {
-    { // -- A r r a y B u f f e r
-      Handle<JSObject> prototype =
-          factory()->NewJSObject(isolate()->object_function(), TENURED);
+    {  // -- A r r a y B u f f e r
       InstallFunction(global, "__ArrayBuffer", JS_ARRAY_BUFFER_TYPE,
-                      JSArrayBuffer::kSize, prototype,
+                      JSArrayBuffer::kSize,
+                      isolate()->initial_object_prototype(),
                       Builtins::kIllegal, true);
     }
+    {
+      // -- T y p e d A r r a y s
+      InstallTypedArray("__Int8Array");
+      InstallTypedArray("__Uint8Array");
+      InstallTypedArray("__Int16Array");
+      InstallTypedArray("__Uint16Array");
+      InstallTypedArray("__Int32Array");
+      InstallTypedArray("__Uint32Array");
+      InstallTypedArray("__Float32Array");
+      InstallTypedArray("__Float64Array");
+    }
+  }
+
+  if (FLAG_harmony_generators) {
+    // Create generator meta-objects and install them on the builtins object.
+    Handle<JSObject> builtins(native_context()->builtins());
+    Handle<JSObject> generator_object_prototype =
+        factory()->NewJSObject(isolate()->object_function(), TENURED);
+    Handle<JSFunction> generator_function_prototype =
+        InstallFunction(builtins, "GeneratorFunctionPrototype",
+                        JS_FUNCTION_TYPE, JSFunction::kHeaderSize,
+                        generator_object_prototype, Builtins::kIllegal,
+                        false);
+    InstallFunction(builtins, "GeneratorFunction",
+                    JS_FUNCTION_TYPE, JSFunction::kSize,
+                    generator_function_prototype, Builtins::kIllegal,
+                    false);
+
+    // Create maps for generator functions and their prototypes.  Store those
+    // maps in the native context.
+    Handle<Map> function_map(native_context()->function_map());
+    Handle<Map> generator_function_map = factory()->CopyMap(function_map);
+    generator_function_map->set_prototype(*generator_function_prototype);
+    native_context()->set_generator_function_map(*generator_function_map);
+
+    Handle<Map> strict_mode_function_map(
+        native_context()->strict_mode_function_map());
+    Handle<Map> strict_mode_generator_function_map = factory()->CopyMap(
+        strict_mode_function_map);
+    strict_mode_generator_function_map->set_prototype(
+        *generator_function_prototype);
+    native_context()->set_strict_mode_generator_function_map(
+        *strict_mode_generator_function_map);
+
+    Handle<Map> object_map(native_context()->object_function()->initial_map());
+    Handle<Map> generator_object_prototype_map = factory()->CopyMap(
+        object_map, 0);
+    generator_object_prototype_map->set_prototype(
+        *generator_object_prototype);
+    native_context()->set_generator_object_prototype_map(
+        *generator_object_prototype_map);
   }
 }
 
@@ -1933,6 +1972,11 @@ bool Genesis::InstallExperimentalNatives() {
                "native typedarray.js") == 0) {
       if (!CompileExperimentalBuiltin(isolate(), i)) return false;
     }
+    if (FLAG_harmony_generators &&
+        strcmp(ExperimentalNatives::GetScriptName(i).start(),
+               "native generator.js") == 0) {
+      if (!CompileExperimentalBuiltin(isolate(), i)) return false;
+    }
   }
 
   InstallExperimentalNativeFunctions();
diff --git a/deps/v8/src/builtins-decls.h b/deps/v8/src/builtins-decls.h
new file mode 100644 (file)
index 0000000..beb5dd1
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2013 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_BUILTINS_DECLS_H_
+#define V8_BUILTINS_DECLS_H_
+
+#include "arguments.h"
+
+namespace v8 {
+namespace internal {
+
+DECLARE_RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure);
+
+} }  // namespace v8::internal
+
+#endif  // V8_BUILTINS_DECLS_H_
index f8d562b..56c0501 100644 (file)
@@ -125,23 +125,31 @@ BUILTIN_LIST_C(DEF_ARG_TYPE)
 
 #ifdef DEBUG
 
-#define BUILTIN(name)                                      \
-  MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
-      name##ArgumentsType args, Isolate* isolate);         \
-  MUST_USE_RESULT static MaybeObject* Builtin_##name(      \
-      name##ArgumentsType args, Isolate* isolate) {        \
-    ASSERT(isolate == Isolate::Current());                 \
-    args.Verify();                                         \
-    return Builtin_Impl_##name(args, isolate);             \
-  }                                                        \
-  MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
+#define BUILTIN(name)                                            \
+  MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name(       \
+      name##ArgumentsType args, Isolate* isolate);               \
+  MUST_USE_RESULT static MaybeObject* Builtin_##name(            \
+      int args_length, Object** args_object, Isolate* isolate) { \
+    name##ArgumentsType args(args_length, args_object);          \
+    ASSERT(isolate == Isolate::Current());                       \
+    args.Verify();                                               \
+    return Builtin_Impl_##name(args, isolate);                   \
+  }                                                              \
+  MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name(       \
       name##ArgumentsType args, Isolate* isolate)
 
 #else  // For release mode.
 
-#define BUILTIN(name)                                      \
-  static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
-
+#define BUILTIN(name)                                            \
+  static MaybeObject* Builtin_impl##name(                        \
+      name##ArgumentsType args, Isolate* isolate);               \
+  static MaybeObject* Builtin_##name(                            \
+      int args_length, Object** args_object, Isolate* isolate) { \
+    name##ArgumentsType args(args_length, args_object);          \
+    return Builtin_impl##name(args, isolate);                    \
+  }                                                              \
+  static MaybeObject* Builtin_impl##name(                        \
+      name##ArgumentsType args, Isolate* isolate)
 #endif
 
 
@@ -323,9 +331,9 @@ static void MoveDoubleElements(FixedDoubleArray* dst,
                                int src_index,
                                int len) {
   if (len == 0) return;
-  memmove(dst->data_start() + dst_index,
-          src->data_start() + src_index,
-          len * kDoubleSize);
+  OS::MemMove(dst->data_start() + dst_index,
+              src->data_start() + src_index,
+              len * kDoubleSize);
 }
 
 
index 12ed56a..ee607ad 100644 (file)
@@ -274,8 +274,6 @@ enum BuiltinExtraArguments {
   V(APPLY_PREPARE, 1)                    \
   V(APPLY_OVERFLOW, 1)
 
-MaybeObject* ArrayConstructor_StubFailure(Arguments args, Isolate* isolate);
-
 class BuiltinFunctionTable;
 class ObjectVisitor;
 
index ee903ae..02c0091 100644 (file)
@@ -147,6 +147,8 @@ bool CodeStubGraphBuilderBase::BuildGraph() {
 
   AddSimulate(BailoutId::StubEntry());
 
+  NoObservableSideEffectsScope no_effects(this);
+
   HValue* return_value = BuildCodeStub();
 
   // We might have extra expressions to pop from the stack in addition to the
@@ -189,6 +191,70 @@ static Handle<Code> DoGenerateCode(Stub* stub) {
 
 
 template <>
+HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
+  Zone* zone = this->zone();
+  Factory* factory = isolate()->factory();
+  AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode();
+  FastCloneShallowArrayStub::Mode mode = casted_stub()->mode();
+  int length = casted_stub()->length();
+
+  HInstruction* boilerplate =
+      AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
+                                          GetParameter(1),
+                                          NULL,
+                                          FAST_ELEMENTS));
+
+  CheckBuilder builder(this);
+  builder.CheckNotUndefined(boilerplate);
+
+  if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
+    HValue* elements =
+        AddInstruction(new(zone) HLoadElements(boilerplate, NULL));
+
+    IfBuilder if_fixed_cow(this);
+    if_fixed_cow.BeginIfMapEquals(elements, factory->fixed_cow_array_map());
+    environment()->Push(BuildCloneShallowArray(context(),
+                                               boilerplate,
+                                               alloc_site_mode,
+                                               FAST_ELEMENTS,
+                                               0/*copy-on-write*/));
+    if_fixed_cow.BeginElse();
+
+    IfBuilder if_fixed(this);
+    if_fixed.BeginIfMapEquals(elements, factory->fixed_array_map());
+    environment()->Push(BuildCloneShallowArray(context(),
+                                               boilerplate,
+                                               alloc_site_mode,
+                                               FAST_ELEMENTS,
+                                               length));
+    if_fixed.BeginElse();
+
+    environment()->Push(BuildCloneShallowArray(context(),
+                                               boilerplate,
+                                               alloc_site_mode,
+                                               FAST_DOUBLE_ELEMENTS,
+                                               length));
+  } else {
+    ElementsKind elements_kind = casted_stub()->ComputeElementsKind();
+    environment()->Push(BuildCloneShallowArray(context(),
+                                               boilerplate,
+                                               alloc_site_mode,
+                                               elements_kind,
+                                               length));
+  }
+
+  return environment()->Pop();
+}
+
+
+Handle<Code> FastCloneShallowArrayStub::GenerateCode() {
+  CodeStubGraphBuilder<FastCloneShallowArrayStub> builder(this);
+  LChunk* chunk = OptimizeGraph(builder.CreateGraph());
+  return chunk->Codegen(Code::COMPILED_STUB);
+}
+
+
+template <>
 HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
   Zone* zone = this->zone();
   Factory* factory = isolate()->factory();
@@ -230,7 +296,6 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
                                               factory->empty_string(),
                                               value,
                                               true, i));
-    AddSimulate(BailoutId::StubEntry());
   }
 
   builder.End();
@@ -264,7 +329,6 @@ HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() {
       GetParameter(0), GetParameter(1), GetParameter(2), NULL,
       casted_stub()->is_js_array(), casted_stub()->elements_kind(),
       true, casted_stub()->store_mode(), Representation::Tagged());
-  AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE);
 
   return GetParameter(2);
 }
@@ -308,7 +372,7 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
       AddInstruction(new(zone) HFixedArrayBaseLength(elements));
 
   HValue* new_elements =
-      BuildAllocateElements(context(), to_kind, elements_length);
+      BuildAllocateAndInitializeElements(context(), to_kind, elements_length);
 
   BuildCopyElements(context(), elements,
                     casted_stub()->from_kind(), new_elements,
@@ -320,13 +384,11 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
                                             factory->elements_field_string(),
                                             new_elements, true,
                                             JSArray::kElementsOffset));
-  AddSimulate(BailoutId::StubEntry());
 
   if_builder.End();
 
   AddInstruction(new(zone) HStoreNamedField(js_array, factory->length_string(),
                                             map, true, JSArray::kMapOffset));
-  AddSimulate(BailoutId::StubEntry());
   return js_array;
 }
 
index eff0f7f..ad418d6 100644 (file)
@@ -619,8 +619,10 @@ void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
 
 
 void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
-  StubFailureTrampolineStub(NOT_JS_FUNCTION_STUB_MODE).GetCode(isolate);
-  StubFailureTrampolineStub(JS_FUNCTION_STUB_MODE).GetCode(isolate);
+  StubFailureTrampolineStub stub1(NOT_JS_FUNCTION_STUB_MODE);
+  StubFailureTrampolineStub stub2(JS_FUNCTION_STUB_MODE);
+  stub1.GetCode(isolate)->set_is_pregenerated(true);
+  stub2.GetCode(isolate)->set_is_pregenerated(true);
 }
 
 
index 99ff515..60c4fb9 100644 (file)
@@ -393,17 +393,24 @@ class ToNumberStub: public PlatformCodeStub {
 
 class FastNewClosureStub : public PlatformCodeStub {
  public:
-  explicit FastNewClosureStub(LanguageMode language_mode)
-    : language_mode_(language_mode) { }
+  explicit FastNewClosureStub(LanguageMode language_mode, bool is_generator)
+    : language_mode_(language_mode),
+      is_generator_(is_generator) { }
 
   void Generate(MacroAssembler* masm);
 
  private:
+  class StrictModeBits: public BitField<bool, 0, 1> {};
+  class IsGeneratorBits: public BitField<bool, 1, 1> {};
+
   Major MajorKey() { return FastNewClosure; }
-  int MinorKey() { return language_mode_ == CLASSIC_MODE
-        ? kNonStrictMode : kStrictMode; }
+  int MinorKey() {
+    return StrictModeBits::encode(language_mode_ != CLASSIC_MODE) |
+      IsGeneratorBits::encode(is_generator_);
+  }
 
   LanguageMode language_mode_;
+  bool is_generator_;
 };
 
 
@@ -443,7 +450,7 @@ class FastNewBlockContextStub : public PlatformCodeStub {
 };
 
 
-class FastCloneShallowArrayStub : public PlatformCodeStub {
+class FastCloneShallowArrayStub : public HydrogenCodeStub {
  public:
   // Maximum length of copied elements array.
   static const int kMaximumClonedLength = 8;
@@ -467,7 +474,31 @@ class FastCloneShallowArrayStub : public PlatformCodeStub {
     ASSERT_LE(length_, kMaximumClonedLength);
   }
 
-  void Generate(MacroAssembler* masm);
+  Mode mode() const { return mode_; }
+  int length() const { return length_; }
+  AllocationSiteMode allocation_site_mode() const {
+    return allocation_site_mode_;
+  }
+
+  ElementsKind ComputeElementsKind() const {
+    switch (mode()) {
+      case CLONE_ELEMENTS:
+      case COPY_ON_WRITE_ELEMENTS:
+        return FAST_ELEMENTS;
+      case CLONE_DOUBLE_ELEMENTS:
+        return FAST_DOUBLE_ELEMENTS;
+      case CLONE_ANY_ELEMENTS:
+        /*fall-through*/;
+    }
+    UNREACHABLE();
+    return LAST_ELEMENTS_KIND;
+  }
+
+  virtual Handle<Code> GenerateCode();
+
+  virtual void InitializeInterfaceDescriptor(
+      Isolate* isolate,
+      CodeStubInterfaceDescriptor* descriptor);
 
  private:
   Mode mode_;
@@ -746,7 +777,7 @@ class BinaryOpStub: public PlatformCodeStub {
  private:
   Token::Value op_;
   OverwriteMode mode_;
-  bool platform_specific_bit_;  // Indicates SSE3 on IA32, VFP2 on ARM.
+  bool platform_specific_bit_;  // Indicates SSE3 on IA32.
 
   // Operand type information determined at runtime.
   BinaryOpIC::TypeInfo left_type_;
@@ -1604,18 +1635,25 @@ class StoreArrayLiteralElementStub : public PlatformCodeStub {
 class StubFailureTrampolineStub : public PlatformCodeStub {
  public:
   explicit StubFailureTrampolineStub(StubFunctionMode function_mode)
-      : function_mode_(function_mode) {}
+      : fp_registers_(CanUseFPRegisters()), function_mode_(function_mode) {}
 
   virtual bool IsPregenerated() { return true; }
 
   static void GenerateAheadOfTime(Isolate* isolate);
 
  private:
+  class FPRegisters:       public BitField<bool,                0, 1> {};
+  class FunctionModeField: public BitField<StubFunctionMode,    1, 1> {};
+
   Major MajorKey() { return StubFailureTrampoline; }
-  int MinorKey() { return static_cast<int>(function_mode_); }
+  int MinorKey() {
+    return FPRegisters::encode(fp_registers_) |
+        FunctionModeField::encode(function_mode_);
+  }
 
   void Generate(MacroAssembler* masm);
 
+  bool fp_registers_;
   StubFunctionMode function_mode_;
 
   DISALLOW_COPY_AND_ASSIGN(StubFailureTrampolineStub);
index c872efb..950c7e7 100644 (file)
 
 "use strict";
 
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
 var $Set = global.Set;
 var $Map = global.Map;
 var $WeakMap = global.WeakMap;
 
-//-------------------------------------------------------------------
-
 // Global sentinel to be used instead of undefined keys, which are not
 // supported internally but required for Harmony sets and maps.
 var undefined_sentinel = {};
 
+// -------------------------------------------------------------------
+// Harmony Set
 
 function SetConstructor() {
   if (%_IsConstructCall()) {
@@ -107,6 +111,31 @@ function SetClear() {
 }
 
 
+// -------------------------------------------------------------------
+
+function SetUpSet() {
+  %CheckIsBootstrapping();
+
+  %SetCode($Set, SetConstructor);
+  %FunctionSetPrototype($Set, new $Object());
+  %SetProperty($Set.prototype, "constructor", $Set, 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,
+    "clear", SetClear
+  ));
+}
+
+SetUpSet();
+
+
+// -------------------------------------------------------------------
+// Harmony Map
+
 function MapConstructor() {
   if (%_IsConstructCall()) {
     %MapInitialize(this);
@@ -183,6 +212,32 @@ function MapClear() {
 }
 
 
+// -------------------------------------------------------------------
+
+function SetUpMap() {
+  %CheckIsBootstrapping();
+
+  %SetCode($Map, MapConstructor);
+  %FunctionSetPrototype($Map, new $Object());
+  %SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
+
+  // 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,
+    "clear", MapClear
+  ));
+}
+
+SetUpMap();
+
+
+// -------------------------------------------------------------------
+// Harmony WeakMap
+
 function WeakMapConstructor() {
   if (%_IsConstructCall()) {
     %WeakMapInitialize(this);
@@ -239,42 +294,14 @@ function WeakMapDelete(key) {
   return %WeakMapDelete(this, key);
 }
 
+
 // -------------------------------------------------------------------
 
-(function () {
+function SetUpWeakMap() {
   %CheckIsBootstrapping();
 
-  // Set up the Set and Map constructor function.
-  %SetCode($Set, SetConstructor);
-  %SetCode($Map, MapConstructor);
-
-  // Set up the constructor property on the Set and Map prototype object.
-  %SetProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
-  %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,
-    "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,
-    "clear", MapClear
-  ));
-
-  // Set up the WeakMap constructor function.
   %SetCode($WeakMap, WeakMapConstructor);
-
-  // Set up the constructor property on the WeakMap prototype object.
+  %FunctionSetPrototype($WeakMap, new $Object());
   %SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);
 
   // Set up the non-enumerable functions on the WeakMap prototype object.
@@ -284,4 +311,6 @@ function WeakMapDelete(key) {
     "has", WeakMapHas,
     "delete", WeakMapDelete
   ));
-})();
+}
+
+SetUpWeakMap();
index 6f9b901..184429b 100644 (file)
@@ -520,14 +520,15 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
 
   // Only allow non-global compiles for eval.
   ASSERT(info->is_eval() || info->is_global());
-  ParsingFlags flags = kNoParsingFlags;
-  if ((info->pre_parse_data() != NULL ||
-       String::cast(script->source())->length() > FLAG_min_preparse_length) &&
-      !DebuggerWantsEagerCompilation(info)) {
-    flags = kAllowLazy;
-  }
-  if (!ParserApi::Parse(info, flags)) {
-    return Handle<SharedFunctionInfo>::null();
+  {
+    Parser parser(info);
+    if ((info->pre_parse_data() != NULL ||
+         String::cast(script->source())->length() > FLAG_min_preparse_length) &&
+        !DebuggerWantsEagerCompilation(info))
+      parser.set_allow_lazy(true);
+    if (!parser.Parse()) {
+      return Handle<SharedFunctionInfo>::null();
+    }
   }
 
   // Measure how long it takes to do the compilation; only take the
@@ -864,7 +865,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
   if (InstallCodeFromOptimizedCodeMap(info)) return true;
 
   // Generate the AST for the lazily compiled function.
-  if (ParserApi::Parse(info, kNoParsingFlags)) {
+  if (Parser::Parse(info)) {
     // Measure how long it takes to do the lazy compilation; only take the
     // rest of the function into account to avoid overlap with the lazy
     // parsing statistics.
@@ -932,7 +933,7 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) {
       return;
     }
 
-    if (ParserApi::Parse(*info, kNoParsingFlags)) {
+    if (Parser::Parse(*info)) {
       LanguageMode language_mode = info->function()->language_mode();
       info->SetLanguageMode(language_mode);
       shared->set_language_mode(language_mode);
@@ -957,18 +958,18 @@ void Compiler::RecompileParallel(Handle<JSFunction> closure) {
     }
   }
 
-  if (shared->code()->stack_check_patched_for_osr()) {
+  if (shared->code()->back_edges_patched_for_osr()) {
     // At this point we either put the function on recompilation queue or
     // aborted optimization.  In either case we want to continue executing
     // the unoptimized code without running into OSR.  If the unoptimized
     // code has been patched for OSR, unpatch it.
     InterruptStub interrupt_stub;
-    Handle<Code> check_code = interrupt_stub.GetCode(isolate);
+    Handle<Code> interrupt_code = interrupt_stub.GetCode(isolate);
     Handle<Code> replacement_code =
         isolate->builtins()->OnStackReplacement();
-    Deoptimizer::RevertStackCheckCode(shared->code(),
-                                      *check_code,
-                                      *replacement_code);
+    Deoptimizer::RevertInterruptCode(shared->code(),
+                                     *interrupt_code,
+                                     *replacement_code);
   }
 
   if (isolate->has_pending_exception()) isolate->clear_pending_exception();
index a0ba2f7..abeb812 100644 (file)
@@ -165,6 +165,11 @@ enum BindingFlags {
   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(GENERATOR_FUNCTION_MAP_INDEX, Map, generator_function_map) \
+  V(STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX, Map, \
+    strict_mode_generator_function_map) \
+  V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, \
+    generator_object_prototype_map) \
   V(RANDOM_SEED_INDEX, ByteArray, random_seed)
 
 // JSFunctions are pairs (context, function code), sometimes also called
@@ -295,6 +300,9 @@ class Context: public FixedArray {
     PROXY_ENUMERATE_INDEX,
     OBSERVERS_NOTIFY_CHANGE_INDEX,
     OBSERVERS_DELIVER_CHANGES_INDEX,
+    GENERATOR_FUNCTION_MAP_INDEX,
+    STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX,
+    GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
     RANDOM_SEED_INDEX,
 
     // Properties from here are treated as weak references by the full GC.
@@ -439,6 +447,16 @@ class Context: public FixedArray {
     return kHeaderSize + index * kPointerSize - kHeapObjectTag;
   }
 
+  static int FunctionMapIndex(LanguageMode language_mode, bool is_generator) {
+    return is_generator
+      ? (language_mode == CLASSIC_MODE
+         ? GENERATOR_FUNCTION_MAP_INDEX
+         : STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX)
+      : (language_mode == CLASSIC_MODE
+         ? FUNCTION_MAP_INDEX
+         : STRICT_MODE_FUNCTION_MAP_INDEX);
+  }
+
   static const int kSize = kHeaderSize + NATIVE_CONTEXT_SLOTS * kPointerSize;
 
   // GC support.
index 7edaf22..eb718d6 100644 (file)
@@ -77,7 +77,7 @@ inline unsigned int FastD2UI(double x) {
     uint32_t result;
     Address mantissa_ptr = reinterpret_cast<Address>(&x);
     // Copy least significant 32 bits of mantissa.
-    memcpy(&result, mantissa_ptr, sizeof(result));
+    OS::MemCopy(&result, mantissa_ptr, sizeof(result));
     return negative ? ~result + 1 : result;
   }
   // Large number (outside uint32 range), Infinity or NaN.
index 7979eb4..47c2a94 100644 (file)
@@ -445,7 +445,7 @@ void CpuProfiler::StartProcessorIfNotStarted() {
     generator_ = new ProfileGenerator(profiles_);
     processor_ = new ProfilerEventsProcessor(generator_);
     is_profiling_ = true;
-    processor_->Start();
+    processor_->StartSynchronously();
     // Enumerate stuff we already have in the heap.
     if (isolate_->heap()->HasBeenSetUp()) {
       if (!FLAG_prof_browser_mode) {
@@ -459,11 +459,11 @@ void CpuProfiler::StartProcessorIfNotStarted() {
     }
     // Enable stack sampling.
     Sampler* sampler = reinterpret_cast<Sampler*>(isolate_->logger()->ticker_);
+    sampler->IncreaseProfilingDepth();
     if (!sampler->IsActive()) {
       sampler->Start();
       need_to_stop_sampler_ = true;
     }
-    sampler->IncreaseProfilingDepth();
   }
 }
 
index 89d9c81..6e2b0e0 100644 (file)
@@ -31,6 +31,7 @@
 #include "allocation.h"
 #include "atomicops.h"
 #include "circular-queue.h"
+#include "sampler.h"
 #include "unbound-queue.h"
 
 namespace v8 {
index b57e390..8f6e384 100644 (file)
 #include "../include/v8-testing.h"
 #endif  // V8_SHARED
 
+#ifdef ENABLE_VTUNE_JIT_INTERFACE
+#include "third_party/vtune/v8-vtune.h"
+#endif
+
 #include "d8.h"
 
 #ifndef V8_SHARED
@@ -144,6 +148,11 @@ class DumbLineEditor: public LineEditor {
 
 Handle<String> DumbLineEditor::Prompt(const char* prompt) {
   printf("%s", prompt);
+#if defined(__native_client__)
+  // Native Client libc is used to being embedded in Chrome and
+  // has trouble recognizing when to flush.
+  fflush(stdout);
+#endif
   return Shell::ReadFromStdin(isolate_);
 }
 
@@ -1921,6 +1930,9 @@ int Shell::Main(int argc, char* argv[]) {
   DumbLineEditor dumb_line_editor(isolate);
   {
     Initialize(isolate);
+#ifdef ENABLE_VTUNE_JIT_INTERFACE
+    vTune::InitilizeVtuneForV8();
+#endif
     Symbols symbols(isolate);
     InitializeDebugger(isolate);
 
index cce8f2a..ea043dc 100644 (file)
@@ -29,6 +29,8 @@
   'includes': ['../build/common.gypi'],
   'variables': {
     'console%': '',
+    # Enable support for Intel VTune. Supported on ia32/x64 only
+    'v8_enable_vtunejit%': 0,
   },
   'targets': [
     {
             }],
           ],
         }],
+        ['v8_enable_vtunejit==1', {
+          'dependencies': [
+            '../src/third_party/vtune/v8vtune.gyp:v8_vtune',
+          ],
+        }],
       ],
     },
     {
index c75d12c..62999e9 100644 (file)
 // (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 relies on the fact that the following declarations have been made
 // in v8natives.js:
 // var $isFinite = GlobalIsFinite;
 
+var $Date = global.Date;
+
 // -------------------------------------------------------------------
 
 // This file contains date support implemented in JavaScript.
 
-// Keep reference to original values of some global properties.  This
-// has the added benefit that the code in this file is isolated from
-// changes to these properties.
-var $Date = global.Date;
-
 // Helper function to throw error.
 function ThrowDateTypeError() {
   throw new $TypeError('this is not a Date object.');
@@ -142,7 +138,7 @@ var Date_cache = {
 };
 
 
-%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
+function DateConstructor(year, month, date, hours, minutes, seconds, ms) {
   if (!%_IsConstructCall()) {
     // ECMA 262 - 15.9.2
     return (new $Date()).toString();
@@ -199,10 +195,7 @@ var Date_cache = {
     value = MakeDate(day, time);
     SET_LOCAL_DATE_VALUE(this, value);
   }
-});
-
-
-%FunctionSetPrototype($Date, new $Date($NaN));
+}
 
 
 var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
@@ -767,6 +760,10 @@ function ResetDateCache() {
 
 function SetUpDate() {
   %CheckIsBootstrapping();
+
+  %SetCode($Date, DateConstructor);
+  %FunctionSetPrototype($Date, new $Date($NaN));
+
   // Set up non-enumerable properties of the Date object itself.
   InstallFunctions($Date, DONT_ENUM, $Array(
     "UTC", DateUTC,
index 91af9cc..4af2194 100644 (file)
@@ -551,9 +551,9 @@ void Debug::ThreadInit() {
 
 char* Debug::ArchiveDebug(char* storage) {
   char* to = storage;
-  memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
+  OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
   to += sizeof(ThreadLocal);
-  memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
+  OS::MemCopy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
   ThreadInit();
   ASSERT(to <= storage + ArchiveSpacePerThread());
   return storage + ArchiveSpacePerThread();
@@ -562,9 +562,10 @@ char* Debug::ArchiveDebug(char* storage) {
 
 char* Debug::RestoreDebug(char* storage) {
   char* from = storage;
-  memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
+  OS::MemCopy(
+      reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
   from += sizeof(ThreadLocal);
-  memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
+  OS::MemCopy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
   ASSERT(from <= storage + ArchiveSpacePerThread());
   return storage + ArchiveSpacePerThread();
 }
@@ -874,8 +875,9 @@ bool Debug::Load() {
   // Check for caught exceptions.
   if (caught_exception) return false;
 
-  // Debugger loaded.
-  debug_context_ = context;
+  // Debugger loaded, create debugger context global handle.
+  debug_context_ = Handle<Context>::cast(
+      isolate_->global_handles()->Create(*context));
 
   return true;
 }
@@ -891,7 +893,7 @@ void Debug::Unload() {
   DestroyScriptCache();
 
   // Clear debugger context global handle.
-  Isolate::Current()->global_handles()->Destroy(
+  isolate_->global_handles()->Destroy(
       reinterpret_cast<Object**>(debug_context_.location()));
   debug_context_ = Handle<Context>();
 }
index 601faf7..1af7365 100644 (file)
@@ -1204,6 +1204,7 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
   // and the standard stack frame slots.  Include space for an argument
   // object to the callee and optionally the space to pass the argument
   // object to the stub failure handler.
+  ASSERT(descriptor->register_param_count_ >= 0);
   int height_in_bytes = kPointerSize * descriptor->register_param_count_ +
       sizeof(Arguments) + kPointerSize;
   int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
@@ -2029,52 +2030,96 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
 }
 
 
-void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code,
-                                      Code* check_code,
-                                      Code* replacement_code) {
-  // Iterate over the stack check table and patch every stack check
+void Deoptimizer::PatchInterruptCode(Code* unoptimized_code,
+                                     Code* interrupt_code,
+                                     Code* replacement_code) {
+  // Iterate over the back edge table and patch every interrupt
   // call to an unconditional call to the replacement code.
   ASSERT(unoptimized_code->kind() == Code::FUNCTION);
-  ASSERT(!unoptimized_code->stack_check_patched_for_osr());
-  Address stack_check_cursor = unoptimized_code->instruction_start() +
-      unoptimized_code->stack_check_table_offset();
-  uint32_t table_length = Memory::uint32_at(stack_check_cursor);
-  stack_check_cursor += kIntSize;
+  int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
+  Address back_edge_cursor = unoptimized_code->instruction_start() +
+      unoptimized_code->back_edge_table_offset();
+  uint32_t table_length = Memory::uint32_at(back_edge_cursor);
+  back_edge_cursor += kIntSize;
   for (uint32_t i = 0; i < table_length; ++i) {
-    uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
-    Address pc_after = unoptimized_code->instruction_start() + pc_offset;
-    PatchStackCheckCodeAt(unoptimized_code,
-                          pc_after,
-                          check_code,
-                          replacement_code);
-    stack_check_cursor += 2 * kIntSize;
+    uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
+    if (loop_depth == loop_nesting_level) {
+      // Loop back edge has the loop depth that we want to patch.
+      uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
+      Address pc_after = unoptimized_code->instruction_start() + pc_offset;
+      PatchInterruptCodeAt(unoptimized_code,
+                           pc_after,
+                           interrupt_code,
+                           replacement_code);
+    }
+    back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
   }
-  unoptimized_code->set_stack_check_patched_for_osr(true);
+  unoptimized_code->set_back_edges_patched_for_osr(true);
+#ifdef DEBUG
+  Deoptimizer::VerifyInterruptCode(
+      unoptimized_code, interrupt_code, replacement_code, loop_nesting_level);
+#endif  // DEBUG
 }
 
 
-void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code,
-                                       Code* check_code,
-                                       Code* replacement_code) {
-  // Iterate over the stack check table and revert the patched
-  // stack check calls.
+void Deoptimizer::RevertInterruptCode(Code* unoptimized_code,
+                                      Code* interrupt_code,
+                                      Code* replacement_code) {
+  // Iterate over the back edge table and revert the patched interrupt calls.
   ASSERT(unoptimized_code->kind() == Code::FUNCTION);
-  ASSERT(unoptimized_code->stack_check_patched_for_osr());
-  Address stack_check_cursor = unoptimized_code->instruction_start() +
-      unoptimized_code->stack_check_table_offset();
-  uint32_t table_length = Memory::uint32_at(stack_check_cursor);
-  stack_check_cursor += kIntSize;
+  ASSERT(unoptimized_code->back_edges_patched_for_osr());
+  int loop_nesting_level = unoptimized_code->allow_osr_at_loop_nesting_level();
+  Address back_edge_cursor = unoptimized_code->instruction_start() +
+      unoptimized_code->back_edge_table_offset();
+  uint32_t table_length = Memory::uint32_at(back_edge_cursor);
+  back_edge_cursor += kIntSize;
   for (uint32_t i = 0; i < table_length; ++i) {
-    uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize);
+    uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
+    if (loop_depth <= loop_nesting_level) {
+      uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
+      Address pc_after = unoptimized_code->instruction_start() + pc_offset;
+      RevertInterruptCodeAt(unoptimized_code,
+                            pc_after,
+                            interrupt_code,
+                            replacement_code);
+    }
+    back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
+  }
+  unoptimized_code->set_back_edges_patched_for_osr(false);
+#ifdef DEBUG
+  // Assert that none of the back edges are patched anymore.
+  Deoptimizer::VerifyInterruptCode(
+      unoptimized_code, interrupt_code, replacement_code, -1);
+#endif  // DEBUG
+}
+
+
+#ifdef DEBUG
+void Deoptimizer::VerifyInterruptCode(Code* unoptimized_code,
+                                      Code* interrupt_code,
+                                      Code* replacement_code,
+                                      int loop_nesting_level) {
+  CHECK(unoptimized_code->kind() == Code::FUNCTION);
+  Address back_edge_cursor = unoptimized_code->instruction_start() +
+      unoptimized_code->back_edge_table_offset();
+  uint32_t table_length = Memory::uint32_at(back_edge_cursor);
+  back_edge_cursor += kIntSize;
+  for (uint32_t i = 0; i < table_length; ++i) {
+    uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
+    CHECK_LE(loop_depth, Code::kMaxLoopNestingMarker);
+    // Assert that all back edges for shallower loops (and only those)
+    // have already been patched.
+    uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
     Address pc_after = unoptimized_code->instruction_start() + pc_offset;
-    RevertStackCheckCodeAt(unoptimized_code,
-                           pc_after,
-                           check_code,
-                           replacement_code);
-    stack_check_cursor += 2 * kIntSize;
+    CHECK_EQ((loop_depth <= loop_nesting_level),
+             InterruptCodeIsPatched(unoptimized_code,
+                                    pc_after,
+                                    interrupt_code,
+                                    replacement_code));
+    back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
   }
-  unoptimized_code->set_stack_check_patched_for_osr(false);
 }
+#endif  // DEBUG
 
 
 unsigned Deoptimizer::ComputeInputFrameSize() const {
@@ -2327,7 +2372,8 @@ int32_t TranslationIterator::Next() {
 Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) {
   int length = contents_.length();
   Handle<ByteArray> result = factory->NewByteArray(length, TENURED);
-  memcpy(result->GetDataStartAddress(), contents_.ToVector().start(), length);
+  OS::MemCopy(
+      result->GetDataStartAddress(), contents_.ToVector().start(), length);
   return result;
 }
 
index 895ed66..97b2206 100644 (file)
@@ -210,32 +210,45 @@ class Deoptimizer : public Malloced {
   // The size in bytes of the code required at a lazy deopt patch site.
   static int patch_size();
 
-  // Patch all stack guard checks in the unoptimized code to
+  // Patch all interrupts with allowed loop depth in the unoptimized code to
   // unconditionally call replacement_code.
-  static void PatchStackCheckCode(Code* unoptimized_code,
-                                  Code* check_code,
-                                  Code* replacement_code);
+  static void PatchInterruptCode(Code* unoptimized_code,
+                                 Code* interrupt_code,
+                                 Code* replacement_code);
 
-  // Patch stack guard check at instruction before pc_after in
+  // Patch the interrupt at the instruction before pc_after in
   // the unoptimized code to unconditionally call replacement_code.
-  static void PatchStackCheckCodeAt(Code* unoptimized_code,
+  static void PatchInterruptCodeAt(Code* unoptimized_code,
+                                   Address pc_after,
+                                   Code* interrupt_code,
+                                   Code* replacement_code);
+
+  // Change all patched interrupts patched in the unoptimized code
+  // back to normal interrupts.
+  static void RevertInterruptCode(Code* unoptimized_code,
+                                  Code* interrupt_code,
+                                  Code* replacement_code);
+
+  // Change patched interrupt in the unoptimized code
+  // back to a normal interrupt.
+  static void RevertInterruptCodeAt(Code* unoptimized_code,
                                     Address pc_after,
-                                    Code* check_code,
+                                    Code* interrupt_code,
                                     Code* replacement_code);
 
-  // Change all patched stack guard checks in the unoptimized code
-  // back to a normal stack guard check.
-  static void RevertStackCheckCode(Code* unoptimized_code,
-                                   Code* check_code,
-                                   Code* replacement_code);
-
-  // Change all patched stack guard checks in the unoptimized code
-  // back to a normal stack guard check.
-  static void RevertStackCheckCodeAt(Code* unoptimized_code,
+#ifdef DEBUG
+  static bool InterruptCodeIsPatched(Code* unoptimized_code,
                                      Address pc_after,
-                                     Code* check_code,
+                                     Code* interrupt_code,
                                      Code* replacement_code);
 
+  // Verify that all back edges of a certain loop depth are patched.
+  static void VerifyInterruptCode(Code* unoptimized_code,
+                                  Code* interrupt_code,
+                                  Code* replacement_code,
+                                  int loop_nesting_level);
+#endif  // DEBUG
+
   ~Deoptimizer();
 
   void MaterializeHeapObjects(JavaScriptFrameIterator* it);
index f168f84..b01b443 100644 (file)
@@ -50,8 +50,8 @@ void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
              pc - begin,
              *pc);
     } else {
-      fprintf(f, "%" V8PRIxPTR "  %4" V8PRIdPTR "  %02x\n",
-              reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
+      PrintF(f, "%" V8PRIxPTR "  %4" V8PRIdPTR "  %02x\n",
+             reinterpret_cast<uintptr_t>(pc), pc - begin, *pc);
     }
   }
 }
@@ -101,13 +101,12 @@ static void DumpBuffer(FILE* f, StringBuilder* out) {
   if (f == NULL) {
     PrintF("%s\n", out->Finalize());
   } else {
-    fprintf(f, "%s\n", out->Finalize());
+    PrintF(f, "%s\n", out->Finalize());
   }
   out->Reset();
 }
 
 
-
 static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
 static const int kRelocInfoPosition = 57;
 
@@ -337,10 +336,10 @@ void Disassembler::Decode(FILE* f, Code* code) {
                      code->kind() == Code::COMPILED_STUB)
       ? static_cast<int>(code->safepoint_table_offset())
       : code->instruction_size();
-  // If there might be a stack check table, stop before reaching it.
+  // If there might be a back edge table, stop before reaching it.
   if (code->kind() == Code::FUNCTION) {
     decode_size =
-        Min(decode_size, static_cast<int>(code->stack_check_table_offset()));
+        Min(decode_size, static_cast<int>(code->back_edge_table_offset()));
   }
 
   byte* begin = code->instruction_start();
index 9deef60..7c2b568 100644 (file)
@@ -183,7 +183,7 @@ static void CopyObjectToObjectElements(FixedArrayBase* from_base,
   Address from_address = from->address() + FixedArray::kHeaderSize;
   CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
             reinterpret_cast<Object**>(from_address) + from_start,
-            copy_size);
+            static_cast<size_t>(copy_size));
   if (IsFastObjectElementsKind(from_kind) &&
       IsFastObjectElementsKind(to_kind)) {
     Heap* heap = from->GetHeap();
@@ -339,7 +339,7 @@ static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
   int words_per_double = (kDoubleSize / kPointerSize);
   CopyWords(reinterpret_cast<Object**>(to_address),
             reinterpret_cast<Object**>(from_address),
-            words_per_double * copy_size);
+            static_cast<size_t>(words_per_double * copy_size));
 }
 
 
index dee3112..025a256 100644 (file)
@@ -33,6 +33,7 @@
 #include "bootstrapper.h"
 #include "codegen.h"
 #include "debug.h"
+#include "deoptimizer.h"
 #include "isolate-inl.h"
 #include "runtime-profiler.h"
 #include "simulator.h"
@@ -448,6 +449,19 @@ void StackGuard::RequestGC() {
 }
 
 
+bool StackGuard::IsFullDeopt() {
+  ExecutionAccess access(isolate_);
+  return (thread_local_.interrupt_flags_ & FULL_DEOPT) != 0;
+}
+
+
+void StackGuard::FullDeopt() {
+  ExecutionAccess access(isolate_);
+  thread_local_.interrupt_flags_ |= FULL_DEOPT;
+  set_interrupt_limits(access);
+}
+
+
 #ifdef ENABLE_DEBUGGER_SUPPORT
 bool StackGuard::IsDebugBreak() {
   ExecutionAccess access(isolate_);
@@ -488,7 +502,7 @@ void StackGuard::Continue(InterruptFlag after_what) {
 
 char* StackGuard::ArchiveStackGuard(char* to) {
   ExecutionAccess access(isolate_);
-  memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
+  OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
   ThreadLocal blank;
 
   // Set the stack limits using the old thread_local_.
@@ -505,7 +519,8 @@ char* StackGuard::ArchiveStackGuard(char* to) {
 
 char* StackGuard::RestoreStackGuard(char* from) {
   ExecutionAccess access(isolate_);
-  memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
+  OS::MemCopy(
+      reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
   isolate_->heap()->SetStackLimits();
   return from + sizeof(ThreadLocal);
 }
@@ -880,7 +895,6 @@ MaybeObject* Execution::HandleStackGuardInterrupt(Isolate* isolate) {
     stack_guard->Continue(GC_REQUEST);
   }
 
-
   isolate->counters()->stack_interrupts()->Increment();
   isolate->counters()->runtime_profiler_ticks()->Increment();
   isolate->runtime_profiler()->OptimizeNow();
@@ -898,6 +912,10 @@ MaybeObject* Execution::HandleStackGuardInterrupt(Isolate* isolate) {
     stack_guard->Continue(INTERRUPT);
     return isolate->StackOverflow();
   }
+  if (stack_guard->IsFullDeopt()) {
+    stack_guard->Continue(FULL_DEOPT);
+    Deoptimizer::DeoptimizeAll(isolate);
+  }
   return isolate->heap()->undefined_value();
 }
 
index b104180..9cf8ac6 100644 (file)
@@ -41,7 +41,8 @@ enum InterruptFlag {
   DEBUGCOMMAND = 1 << 2,
   PREEMPT = 1 << 3,
   TERMINATE = 1 << 4,
-  GC_REQUEST = 1 << 5
+  GC_REQUEST = 1 << 5,
+  FULL_DEOPT = 1 << 6
 };
 
 
@@ -197,6 +198,8 @@ class StackGuard {
 #endif
   bool IsGCRequest();
   void RequestGC();
+  bool IsFullDeopt();
+  void FullDeopt();
   void Continue(InterruptFlag after_what);
 
   // This provides an asynchronous read of the stack limits for the current
index fece9a0..5e2a2b1 100644 (file)
@@ -578,15 +578,22 @@ Handle<JSFunction> Factory::BaseNewFunctionFromSharedFunctionInfo(
 }
 
 
+static Handle<Map> MapForNewFunction(Isolate *isolate,
+                                     Handle<SharedFunctionInfo> function_info) {
+  Context *context = isolate->context()->native_context();
+  int map_index = Context::FunctionMapIndex(function_info->language_mode(),
+                                            function_info->is_generator());
+  return Handle<Map>(Map::cast(context->get(map_index)));
+}
+
+
 Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
     Handle<SharedFunctionInfo> function_info,
     Handle<Context> context,
     PretenureFlag pretenure) {
   Handle<JSFunction> result = BaseNewFunctionFromSharedFunctionInfo(
       function_info,
-      function_info->is_classic_mode()
-          ? isolate()->function_map()
-          : isolate()->strict_mode_function_map(),
+      MapForNewFunction(isolate(), function_info),
       pretenure);
 
   if (function_info->ic_age() != isolate()->heap()->global_ic_age()) {
@@ -874,14 +881,7 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
     initial_map->set_constructor(*function);
   }
 
-  // Set function.prototype and give the prototype a constructor
-  // property that refers to the function.
   SetPrototypeProperty(function, prototype);
-  // Currently safe because it is only invoked from Genesis.
-  CHECK_NOT_EMPTY_HANDLE(isolate(),
-                         JSObject::SetLocalPropertyIgnoreAttributes(
-                             prototype, constructor_string(),
-                             function, DONT_ENUM));
   return function;
 }
 
index ea72168..9c9362b 100644 (file)
@@ -119,6 +119,22 @@ public:
 };
 #endif
 
+#if (defined CAN_USE_VFP3_INSTRUCTIONS) || !(defined ARM_TEST)
+# define ENABLE_VFP3_DEFAULT true
+#else
+# define ENABLE_VFP3_DEFAULT false
+#endif
+#if (defined CAN_USE_ARMV7_INSTRUCTIONS) || !(defined ARM_TEST)
+# define ENABLE_ARMV7_DEFAULT true
+#else
+# define ENABLE_ARMV7_DEFAULT false
+#endif
+#if (defined CAN_USE_VFP32DREGS) || !(defined ARM_TEST)
+# define ENABLE_32DREGS_DEFAULT true
+#else
+# define ENABLE_32DREGS_DEFAULT false
+#endif
+
 #define DEFINE_bool(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt)
 #define DEFINE_int(nam, def, cmt) FLAG(INT, int, nam, def, cmt)
 #define DEFINE_float(nam, def, cmt) FLAG(FLOAT, double, nam, def, cmt)
@@ -168,12 +184,12 @@ DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
 DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
 DEFINE_bool(compiled_transitions, false, "use optimizing compiler to "
             "generate array elements transition stubs")
-DEFINE_bool(compiled_keyed_stores, false, "use optimizing compiler to "
+DEFINE_bool(compiled_keyed_stores, true, "use optimizing compiler to "
             "generate keyed store stubs")
 DEFINE_bool(clever_optimizations,
             true,
             "Optimize object size, Array shift, DOM strings and string +")
-DEFINE_bool(pretenure_literals, false, "allocate literals in old space")
+DEFINE_bool(pretenure_literals, true, "allocate literals in old space")
 
 // Flags for data representation optimizations
 DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
@@ -308,12 +324,9 @@ DEFINE_bool(enable_rdtsc, true,
             "enable use of RDTSC instruction if available")
 DEFINE_bool(enable_sahf, true,
             "enable use of SAHF instruction if available (X64 only)")
-DEFINE_bool(enable_vfp3, true,
-            "enable use of VFP3 instructions if available - this implies "
-            "enabling ARMv7 and VFP2 instructions (ARM only)")
-DEFINE_bool(enable_vfp2, true,
-            "enable use of VFP2 instructions if available")
-DEFINE_bool(enable_armv7, true,
+DEFINE_bool(enable_vfp3, ENABLE_VFP3_DEFAULT,
+            "enable use of VFP3 instructions if available")
+DEFINE_bool(enable_armv7, ENABLE_ARMV7_DEFAULT,
             "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)")
@@ -322,10 +335,8 @@ DEFINE_bool(enable_movw_movt, false,
             "instruction pairs (ARM only)")
 DEFINE_bool(enable_unaligned_accesses, true,
             "enable unaligned accesses for ARMv7 (ARM only)")
-DEFINE_bool(enable_32dregs, true,
+DEFINE_bool(enable_32dregs, ENABLE_32DREGS_DEFAULT,
             "enable use of d16-d31 registers on ARM - this requires VFP3")
-DEFINE_bool(enable_fpu, true,
-            "enable use of MIPS FPU instructions if available (MIPS only)")
 DEFINE_bool(enable_vldr_imm, false,
             "enable use of constant pools for double immediate (ARM only)")
 
@@ -502,6 +513,8 @@ DEFINE_int(sim_stack_alignment, 8,
            "Stack alingment in bytes in simulator (4 or 8, 8 is default)")
 
 // isolate.cc
+DEFINE_bool(abort_on_uncaught_exception, false,
+            "abort program (dump core) when an uncaught exception is thrown")
 DEFINE_bool(trace_exception, false,
             "print stack trace when throwing exceptions")
 DEFINE_bool(preallocate_message_memory, false,
index ff725ad..282bf20 100644 (file)
@@ -34,6 +34,9 @@
 #include "smart-pointers.h"
 #include "string-stream.h"
 
+#ifdef V8_TARGET_ARCH_ARM
+#include "arm/assembler-arm-inl.h"
+#endif
 
 namespace v8 {
 namespace internal {
@@ -305,7 +308,7 @@ static void SplitArgument(const char* arg,
       // make a copy so we can NUL-terminate flag name
       size_t n = arg - *name;
       CHECK(n < static_cast<size_t>(buffer_size));  // buffer is too small
-      memcpy(buffer, *name, n);
+      OS::MemCopy(buffer, *name, n);
       buffer[n] = '\0';
       *name = buffer;
       // get the value
@@ -367,8 +370,8 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
           // sense there.
           continue;
         } else {
-          fprintf(stderr, "Error: unrecognized flag %s\n"
-                  "Try --help for options\n", arg);
+          PrintF(stderr, "Error: unrecognized flag %s\n"
+                 "Try --help for options\n", arg);
           return_code = j;
           break;
         }
@@ -381,9 +384,9 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
         if (i < *argc) {
           value = argv[i++];
         } else {
-          fprintf(stderr, "Error: missing value for flag %s of type %s\n"
-                  "Try --help for options\n",
-                  arg, Type2String(flag->type()));
+          PrintF(stderr, "Error: missing value for flag %s of type %s\n"
+                 "Try --help for options\n",
+                 arg, Type2String(flag->type()));
           return_code = j;
           break;
         }
@@ -424,9 +427,9 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
       if ((flag->type() == Flag::TYPE_BOOL && value != NULL) ||
           (flag->type() != Flag::TYPE_BOOL && is_bool) ||
           *endp != '\0') {
-        fprintf(stderr, "Error: illegal value for flag %s of type %s\n"
-                "Try --help for options\n",
-                arg, Type2String(flag->type()));
+        PrintF(stderr, "Error: illegal value for flag %s of type %s\n"
+               "Try --help for options\n",
+               arg, Type2String(flag->type()));
         return_code = j;
         break;
       }
@@ -475,7 +478,7 @@ static char* SkipBlackSpace(char* p) {
 int FlagList::SetFlagsFromString(const char* str, int len) {
   // make a 0-terminated copy of str
   ScopedVector<char> copy0(len + 1);
-  memcpy(copy0.start(), str, len);
+  OS::MemCopy(copy0.start(), str, len);
   copy0[len] = '\0';
 
   // strip leading white space
@@ -517,6 +520,12 @@ void FlagList::ResetAllFlags() {
 
 // static
 void FlagList::PrintHelp() {
+#ifdef V8_TARGET_ARCH_ARM
+  CpuFeatures::PrintTarget();
+  CpuFeatures::Probe();
+  CpuFeatures::PrintFeatures();
+#endif  // V8_TARGET_ARCH_ARM
+
   printf("Usage:\n");
   printf("  shell [options] -e string\n");
   printf("    execute string in V8\n");
index ca0d5be..11e8d28 100644 (file)
@@ -84,6 +84,18 @@ class InnerPointerToCodeCache {
 };
 
 
+class StackHandlerConstants : public AllStatic {
+ public:
+  static const int kNextOffset     = 0 * kPointerSize;
+  static const int kCodeOffset     = 1 * kPointerSize;
+  static const int kStateOffset    = 2 * kPointerSize;
+  static const int kContextOffset  = 3 * kPointerSize;
+  static const int kFPOffset       = 4 * kPointerSize;
+
+  static const int kSize = kFPOffset + kPointerSize;
+};
+
+
 class StackHandler BASE_EMBEDDED {
  public:
   enum Kind {
@@ -581,7 +593,6 @@ class JavaScriptFrame: public StandardFrame {
   inline Object* function_slot_object() const;
 
   friend class StackFrameIterator;
-  friend class StackTracer;
 };
 
 
index 1c6a0b9..72d0835 100644 (file)
@@ -322,7 +322,7 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
     ASSERT(!isolate->has_pending_exception());
     return false;
   }
-  unsigned table_offset = cgen.EmitStackCheckTable();
+  unsigned table_offset = cgen.EmitBackEdgeTable();
 
   Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
   Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
@@ -341,8 +341,8 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
 #endif  // ENABLE_DEBUGGER_SUPPORT
   code->set_allow_osr_at_loop_nesting_level(0);
   code->set_profiler_ticks(0);
-  code->set_stack_check_table_offset(table_offset);
-  code->set_stack_check_patched_for_osr(false);
+  code->set_back_edge_table_offset(table_offset);
+  code->set_back_edges_patched_for_osr(false);
   CodeGenerator::PrintCode(code, info);
   info->SetCode(code);  // May be an empty handle.
 #ifdef ENABLE_GDB_JIT_INTERFACE
@@ -362,17 +362,18 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
 }
 
 
-unsigned FullCodeGenerator::EmitStackCheckTable() {
-  // The stack check table consists of a length (in number of entries)
+unsigned FullCodeGenerator::EmitBackEdgeTable() {
+  // The back edge table consists of a length (in number of entries)
   // field, and then a sequence of entries.  Each entry is a pair of AST id
   // and code-relative pc offset.
   masm()->Align(kIntSize);
   unsigned offset = masm()->pc_offset();
-  unsigned length = stack_checks_.length();
+  unsigned length = back_edges_.length();
   __ dd(length);
   for (unsigned i = 0; i < length; ++i) {
-    __ dd(stack_checks_[i].id.ToInt());
-    __ dd(stack_checks_[i].pc_and_state);
+    __ dd(back_edges_[i].id.ToInt());
+    __ dd(back_edges_[i].pc);
+    __ db(back_edges_[i].loop_depth);
   }
   return offset;
 }
@@ -478,8 +479,11 @@ void FullCodeGenerator::RecordTypeFeedbackCell(
 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());
+  ASSERT(loop_depth() > 0);
+  uint8_t depth = Min(loop_depth(), Code::kMaxLoopNestingMarker);
+  BackEdgeEntry entry =
+      { ast_id, static_cast<unsigned>(masm_->pc_offset()), depth };
+  back_edges_.Add(entry, zone());
 }
 
 
@@ -1251,7 +1255,7 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
   Comment cmnt(masm_, "[ DoWhileStatement");
   SetStatementPosition(stmt);
-  Label body, stack_check;
+  Label body, book_keeping;
 
   Iteration loop_statement(this, stmt);
   increment_loop_depth();
@@ -1265,13 +1269,13 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
   PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
   SetExpressionPosition(stmt->cond(), stmt->condition_position());
   VisitForControl(stmt->cond(),
-                  &stack_check,
+                  &book_keeping,
                   loop_statement.break_label(),
-                  &stack_check);
+                  &book_keeping);
 
   // Check stack before looping.
   PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
-  __ bind(&stack_check);
+  __ bind(&book_keeping);
   EmitBackEdgeBookkeeping(stmt, &body);
   __ jmp(&body);
 
@@ -1549,6 +1553,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
     UNIMPLEMENTED();
 
   Comment cmnt(masm_, "[ Yield");
+  // TODO(wingo): Actually update the iterator state.
+  VisitForEffect(expr->generator_object());
   VisitForAccumulatorValue(expr->expression());
   // TODO(wingo): Assert that the operand stack depth is 0, at least while
   // general yield expressions are unimplemented.
index c4f3fcc..b9647c2 100644 (file)
@@ -92,7 +92,7 @@ class FullCodeGenerator: public AstVisitor {
         bailout_entries_(info->HasDeoptimizationSupport()
                          ? info->function()->ast_node_count() : 0,
                          info->zone()),
-        stack_checks_(2, info->zone()),  // There's always at least one.
+        back_edges_(2, info->zone()),
         type_feedback_cells_(info->HasDeoptimizationSupport()
                              ? info->function()->ast_node_count() : 0,
                              info->zone()),
@@ -135,6 +135,7 @@ class FullCodeGenerator: public AstVisitor {
 #error Unsupported target architecture.
 #endif
 
+  static const int kBackEdgeEntrySize = 2 * kIntSize + kOneByteSize;
 
  private:
   class Breakable;
@@ -459,9 +460,9 @@ class FullCodeGenerator: public AstVisitor {
                                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();
+  // Emit a table of back edge ids, pcs and loop depths into the code stream.
+  // Return the offset of the start of the table.
+  unsigned EmitBackEdgeTable();
 
   void EmitProfilingCounterDecrement(int delta);
   void EmitProfilingCounterReset();
@@ -624,6 +625,12 @@ class FullCodeGenerator: public AstVisitor {
     unsigned pc_and_state;
   };
 
+  struct BackEdgeEntry {
+    BailoutId id;
+    unsigned pc;
+    uint8_t loop_depth;
+  };
+
   struct TypeFeedbackCellEntry {
     TypeFeedbackId ast_id;
     Handle<JSGlobalPropertyCell> cell;
@@ -818,9 +825,7 @@ class FullCodeGenerator: public AstVisitor {
   const ExpressionContext* context_;
   ZoneList<BailoutEntry> bailout_entries_;
   GrowableBitVector prepared_bailout_ids_;
-  // TODO(svenpanne) Rename this to something like back_edges_ and rename
-  // related functions accordingly.
-  ZoneList<BailoutEntry> stack_checks_;
+  ZoneList<BackEdgeEntry> back_edges_;
   ZoneList<TypeFeedbackCellEntry> type_feedback_cells_;
   int ic_total_count_;
   Handle<FixedArray> handler_table_;
index cf8ca2d..d08f2fe 100644 (file)
@@ -629,7 +629,7 @@ class MachO BASE_EMBEDDED {
 #if defined(__ELF)
 class ELF BASE_EMBEDDED {
  public:
-  ELF(Zone* zone) : sections_(6, zone) {
+  explicit ELF(Zone* zone) : sections_(6, zone) {
     sections_.Add(new(zone) ELFSection("", ELFSection::TYPE_NULL, 0), zone);
     sections_.Add(new(zone) ELFStringTable(".shstrtab"), zone);
   }
@@ -681,7 +681,7 @@ class ELF BASE_EMBEDDED {
 #else
 #error Unsupported target architecture.
 #endif
-    memcpy(header->ident, ident, 16);
+    OS::MemCopy(header->ident, ident, 16);
     header->type = 1;
 #if defined(V8_TARGET_ARCH_IA32)
     header->machine = 3;
@@ -1019,9 +1019,9 @@ class CodeDescription BASE_EMBEDDED {
 
 #if defined(__ELF)
 static void CreateSymbolsTable(CodeDescription* desc,
+                               Zone* zone,
                                ELF* elf,
                                int text_section_index) {
-  Zone* zone = desc->info()->zone();
   ELFSymbolTable* symtab = new(zone) ELFSymbolTable(".symtab", zone);
   ELFStringTable* strtab = new(zone) ELFStringTable(".strtab");
 
@@ -1213,8 +1213,11 @@ class DebugInfoSection : public DebugSection {
         w->WriteSLEB128(StandardFrameConstants::kContextOffset);
         block_size.set(static_cast<uint32_t>(w->position() - block_start));
       }
+
+      w->WriteULEB128(0);  // Terminate the sub program.
     }
 
+    w->WriteULEB128(0);  // Terminate the compile unit.
     size.set(static_cast<uint32_t>(w->position() - start));
     return true;
   }
@@ -1324,15 +1327,14 @@ class DebugAbbrevSection : public DebugSection {
       // The real slot ID is internal_slots + context_slot_id.
       int internal_slots = Context::MIN_CONTEXT_SLOTS;
       int locals = scope->StackLocalCount();
-      int total_children =
-          params + slots + context_slots + internal_slots + locals + 2;
+      // Total children is params + slots + context_slots + internal_slots +
+      // locals + 2 (__function and __context).
 
       // The extra duplication below seems to be necessary to keep
       // gdb from getting upset on OSX.
       w->WriteULEB128(current_abbreviation++);  // Abbreviation code.
       w->WriteULEB128(DW_TAG_SUBPROGRAM);
-      w->Write<uint8_t>(
-          total_children != 0 ? DW_CHILDREN_YES : DW_CHILDREN_NO);
+      w->Write<uint8_t>(DW_CHILDREN_YES);
       w->WriteULEB128(DW_AT_NAME);
       w->WriteULEB128(DW_FORM_STRING);
       w->WriteULEB128(DW_AT_LOW_PC);
@@ -1384,9 +1386,7 @@ class DebugAbbrevSection : public DebugSection {
       // The context.
       WriteVariableAbbreviation(w, current_abbreviation++, true, false);
 
-      if (total_children != 0) {
-        w->WriteULEB128(0);  // Terminate the sibling list.
-      }
+      w->WriteULEB128(0);  // Terminate the sibling list.
     }
 
     w->WriteULEB128(0);  // Terminate the table.
@@ -1789,8 +1789,9 @@ bool UnwindInfoSection::WriteBodyInternal(Writer* w) {
 
 #endif  // V8_TARGET_ARCH_X64
 
-static void CreateDWARFSections(CodeDescription* desc, DebugObject* obj) {
-  Zone* zone = desc->info()->zone();
+static void CreateDWARFSections(CodeDescription* desc,
+                                Zone* zone,
+                                DebugObject* obj) {
   if (desc->IsLineInfoAvailable()) {
     obj->AddSection(new(zone) DebugInfoSection(desc), zone);
     obj->AddSection(new(zone) DebugAbbrevSection(desc), zone);
@@ -1841,7 +1842,7 @@ extern "C" {
 #ifdef OBJECT_PRINT
   void __gdb_print_v8_object(MaybeObject* object) {
     object->Print();
-    fprintf(stdout, "\n");
+    PrintF(stdout, "\n");
   }
 #endif
 }
@@ -1854,7 +1855,7 @@ static JITCodeEntry* CreateCodeEntry(Address symfile_addr,
 
   entry->symfile_addr_ = reinterpret_cast<Address>(entry + 1);
   entry->symfile_size_ = symfile_size;
-  memcpy(entry->symfile_addr_, symfile_addr, symfile_size);
+  OS::MemCopy(entry->symfile_addr_, symfile_addr, symfile_size);
 
   entry->prev_ = entry->next_ = NULL;
 
@@ -1915,8 +1916,7 @@ static void UnregisterCodeEntry(JITCodeEntry* entry) {
 }
 
 
-static JITCodeEntry* CreateELFObject(CodeDescription* desc) {
-  Zone* zone = desc->info()->zone();
+static JITCodeEntry* CreateELFObject(CodeDescription* desc, Zone* zone) {
   ZoneScope zone_scope(zone, DELETE_ON_EXIT);
 #ifdef __MACH_O
   MachO mach_o;
@@ -1944,9 +1944,9 @@ static JITCodeEntry* CreateELFObject(CodeDescription* desc) {
           ELFSection::FLAG_ALLOC | ELFSection::FLAG_EXEC),
       zone);
 
-  CreateSymbolsTable(desc, &elf, text_section_index);
+  CreateSymbolsTable(desc, zone, &elf, text_section_index);
 
-  CreateDWARFSections(desc, &elf);
+  CreateDWARFSections(desc, zone, &elf);
 
   elf.Write(&w);
 #endif
@@ -2083,7 +2083,8 @@ void GDBJITInterface::AddCode(const char* name,
   }
 
   AddUnwindInfo(&code_desc);
-  JITCodeEntry* entry = CreateELFObject(&code_desc);
+  Zone* zone = code->GetIsolate()->runtime_zone();
+  JITCodeEntry* entry = CreateELFObject(&code_desc, zone);
   ASSERT(!IsLineInfoTagged(entry));
 
   delete lineinfo;
diff --git a/deps/v8/src/generator.js b/deps/v8/src/generator.js
new file mode 100644 (file)
index 0000000..d579928
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2013 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";
+
+// This file relies on the fact that the following declarations have been made
+// in runtime.js:
+// var $Function = global.Function;
+
+// ----------------------------------------------------------------------------
+
+
+// TODO(wingo): Give link to specification. For now, the following diagram is
+// the spec:
+// http://wiki.ecmascript.org/lib/exe/fetch.php?cache=cache&media=harmony:es6_generator_object_model_3-29-13.png
+
+function GeneratorObjectNext() {
+  // TODO(wingo): Implement.
+}
+
+function GeneratorObjectSend(value) {
+  // TODO(wingo): Implement.
+}
+
+function GeneratorObjectThrow(exn) {
+  // TODO(wingo): Implement.
+}
+
+function GeneratorObjectClose() {
+  // TODO(wingo): Implement.
+}
+
+function SetUpGenerators() {
+  %CheckIsBootstrapping();
+  var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
+  InstallFunctions(GeneratorObjectPrototype,
+                   DONT_ENUM | DONT_DELETE | READ_ONLY,
+                   ["next", GeneratorObjectNext,
+                    "send", GeneratorObjectSend,
+                    "throw", GeneratorObjectThrow,
+                    "close", GeneratorObjectClose]);
+  %SetProperty(GeneratorObjectPrototype, "constructor",
+               GeneratorFunctionPrototype, DONT_ENUM | DONT_DELETE | READ_ONLY);
+  %SetPrototype(GeneratorFunctionPrototype, $Function.prototype);
+  %SetProperty(GeneratorFunctionPrototype, "constructor",
+               GeneratorFunction, DONT_ENUM | DONT_DELETE | READ_ONLY);
+  %SetPrototype(GeneratorFunction, $Function);
+}
+
+SetUpGenerators();
index 9900144..90707b0 100644 (file)
 #include "../include/v8-profiler.h"
 
 #include "list.h"
+#include "v8utils.h"
 
 namespace v8 {
 namespace internal {
 
+class GCTracer;
+class HeapStats;
+class ObjectVisitor;
+
 // Structure for tracking global handles.
 // A single list keeps all the allocated global handles.
 // Destroyed handles stay in the list but is added to the free list.
@@ -88,7 +93,7 @@ class ImplicitRefGroup {
         malloc(OFFSET_OF(ImplicitRefGroup, children_[length])));
     group->parent_ = parent;
     group->length_ = length;
-    CopyWords(group->children_, children, static_cast<int>(length));
+    CopyWords(group->children_, children, length);
     return group;
   }
 
index 1606996..59931bf 100644 (file)
@@ -67,9 +67,21 @@ namespace internal {
 //   http://www.agner.org/optimize/calling_conventions.pdf
 //   or with gcc, run: "echo | gcc -E -dM -"
 #if defined(_M_X64) || defined(__x86_64__)
+#if defined(__native_client__)
+// For Native Client builds of V8, use V8_TARGET_ARCH_ARM, so that V8
+// generates ARM machine code, together with a portable ARM simulator
+// compiled for the host architecture in question.
+//
+// Since Native Client is ILP-32 on all architectures we use
+// V8_HOST_ARCH_IA32 on both 32- and 64-bit x86.
+#define V8_HOST_ARCH_IA32 1
+#define V8_HOST_ARCH_32_BIT 1
+#define V8_HOST_CAN_READ_UNALIGNED 1
+#else
 #define V8_HOST_ARCH_X64 1
 #define V8_HOST_ARCH_64_BIT 1
 #define V8_HOST_CAN_READ_UNALIGNED 1
+#endif  // __native_client__
 #elif defined(_M_IX86) || defined(__i386__)
 #define V8_HOST_ARCH_IA32 1
 #define V8_HOST_ARCH_32_BIT 1
index b763c86..bb11311 100644 (file)
@@ -59,7 +59,6 @@ inline bool Handle<T>::is_identical_to(const Handle<T> other) const {
   if (FLAG_enable_slow_asserts) {
     Isolate* isolate = Isolate::Current();
     CHECK(isolate->AllowHandleDereference() ||
-          Heap::RelocationLock::IsLocked(isolate->heap()) ||
           !isolate->optimizing_compiler_thread()->IsOptimizerThread());
   }
 #endif  // DEBUG
index b24a4cd..059ff24 100644 (file)
@@ -252,15 +252,32 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object,
 }
 
 
+Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key) {
+  Isolate* isolate = object->GetIsolate();
+  CALL_HEAP_FUNCTION(isolate,
+                     Runtime::DeleteObjectProperty(
+                         isolate, object, key, JSReceiver::NORMAL_DELETION),
+                     Object);
+}
+
+
 Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
                                    Handle<Object> key) {
   Isolate* isolate = object->GetIsolate();
   CALL_HEAP_FUNCTION(isolate,
-                     Runtime::ForceDeleteObjectProperty(isolate, object, key),
+                     Runtime::DeleteObjectProperty(
+                         isolate, object, key, JSReceiver::FORCE_DELETION),
                      Object);
 }
 
 
+Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key) {
+  Isolate* isolate = obj->GetIsolate();
+  CALL_HEAP_FUNCTION(isolate,
+                     Runtime::HasObjectProperty(isolate, obj, key), Object);
+}
+
+
 Handle<Object> GetProperty(Handle<JSReceiver> obj,
                            const char* name) {
   Isolate* isolate = obj->GetIsolate();
@@ -308,6 +325,14 @@ Handle<JSObject> Copy(Handle<JSObject> obj) {
 }
 
 
+Handle<JSObject> DeepCopy(Handle<JSObject> obj) {
+  Isolate* isolate = obj->GetIsolate();
+  CALL_HEAP_FUNCTION(isolate,
+                     obj->DeepCopy(isolate),
+                     JSObject);
+}
+
+
 Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) {
   CALL_HEAP_FUNCTION(obj->GetIsolate(), obj->DefineAccessor(*info), Object);
 }
index c69713e..8e9404c 100644 (file)
@@ -223,11 +223,13 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object,
                                 Handle<Object> value,
                                 PropertyAttributes attributes);
 
-Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
-                                   Handle<Object> key);
+Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key);
 
-Handle<Object> GetProperty(Handle<JSReceiver> obj,
-                           const char* name);
+Handle<Object> ForceDeleteProperty(Handle<JSObject> object, Handle<Object> key);
+
+Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key);
+
+Handle<Object> GetProperty(Handle<JSReceiver> obj, const char* name);
 
 Handle<Object> GetProperty(Isolate* isolate,
                            Handle<Object> obj,
@@ -240,6 +242,8 @@ Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate,
 
 Handle<JSObject> Copy(Handle<JSObject> obj);
 
+Handle<JSObject> DeepCopy(Handle<JSObject> obj);
+
 Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info);
 
 Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray>,
index a15b8ef..28e50aa 100644 (file)
@@ -159,8 +159,8 @@ MaybeObject* Heap::AllocateOneByteInternalizedString(Vector<const uint8_t> str,
   ASSERT_EQ(size, answer->Size());
 
   // Fill in the characters.
-  memcpy(answer->address() + SeqOneByteString::kHeaderSize,
-         str.start(), str.length());
+  OS::MemCopy(answer->address() + SeqOneByteString::kHeaderSize,
+              str.start(), str.length());
 
   return answer;
 }
@@ -192,8 +192,8 @@ MaybeObject* Heap::AllocateTwoByteInternalizedString(Vector<const uc16> str,
   ASSERT_EQ(size, answer->Size());
 
   // Fill in the characters.
-  memcpy(answer->address() + SeqTwoByteString::kHeaderSize,
-         str.start(), str.length() * kUC16Size);
+  OS::MemCopy(answer->address() + SeqTwoByteString::kHeaderSize,
+              str.start(), str.length() * kUC16Size);
 
   return answer;
 }
@@ -345,6 +345,16 @@ bool Heap::InOldPointerSpace(Object* object) {
 }
 
 
+bool Heap::InOldDataSpace(Address address) {
+  return old_data_space_->Contains(address);
+}
+
+
+bool Heap::InOldDataSpace(Object* object) {
+  return InOldDataSpace(reinterpret_cast<Address>(object));
+}
+
+
 bool Heap::OldGenerationAllocationLimitReached() {
   if (!incremental_marking()->IsStopped()) return false;
   return OldGenerationSpaceAvailable() < 0;
@@ -417,7 +427,7 @@ AllocationSpace Heap::TargetSpaceId(InstanceType type) {
 void Heap::CopyBlock(Address dst, Address src, int byte_size) {
   CopyWords(reinterpret_cast<Object**>(dst),
             reinterpret_cast<Object**>(src),
-            byte_size / kPointerSize);
+            static_cast<size_t>(byte_size / kPointerSize));
 }
 
 
@@ -435,7 +445,7 @@ void Heap::MoveBlock(Address dst, Address src, int byte_size) {
       *dst_slot++ = *src_slot++;
     }
   } else {
-    memmove(dst, src, byte_size);
+    OS::MemMove(dst, src, static_cast<size_t>(byte_size));
   }
 }
 
index fb239aa..d22239f 100644 (file)
@@ -2319,7 +2319,7 @@ class OutputStreamWriter {
       int s_chunk_size = Min(
           chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
       ASSERT(s_chunk_size > 0);
-      memcpy(chunk_.start() + chunk_pos_, s, s_chunk_size);
+      OS::MemCopy(chunk_.start() + chunk_pos_, s, s_chunk_size);
       s += s_chunk_size;
       chunk_pos_ += s_chunk_size;
       MaybeWriteChunk();
index fafcb64..453d985 100644 (file)
@@ -162,8 +162,7 @@ Heap::Heap()
 #endif
       promotion_queue_(this),
       configured_(false),
-      chunks_queued_for_free_(NULL),
-      relocation_mutex_(NULL) {
+      chunks_queued_for_free_(NULL) {
   // Allow build-time customization of the max semispace size. Building
   // V8 with snapshots and a non-default max semispace size is much
   // easier if you can define it as part of the build environment.
@@ -688,9 +687,9 @@ void Heap::MoveElements(FixedArray* array,
 
   ASSERT(array->map() != HEAP->fixed_cow_array_map());
   Object** dst_objects = array->data_start() + dst_index;
-  memmove(dst_objects,
-          array->data_start() + src_index,
-          len * kPointerSize);
+  OS::MemMove(dst_objects,
+              array->data_start() + src_index,
+              len * kPointerSize);
   if (!InNewSpace(array)) {
     for (int i = 0; i < len; i++) {
       // TODO(hpayer): check store buffer for entries
@@ -952,6 +951,13 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
       PrintPID("Limited new space size due to high promotion rate: %d MB\n",
                new_space_.InitialCapacity() / MB);
     }
+    // Support for global pre-tenuring uses the high promotion mode as a
+    // heuristic indicator of whether to pretenure or not, we trigger
+    // deoptimization here to take advantage of pre-tenuring as soon as
+    // possible.
+    if (FLAG_pretenure_literals) {
+      isolate_->stack_guard()->FullDeopt();
+    }
   } else if (new_space_high_promotion_mode_active_ &&
       IsStableOrDecreasingSurvivalTrend() &&
       IsLowSurvivalRate()) {
@@ -963,6 +969,11 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
       PrintPID("Unlimited new space size due to low promotion rate: %d MB\n",
                new_space_.MaximumCapacity() / MB);
     }
+    // Trigger deoptimization here to turn off pre-tenuring as soon as
+    // possible.
+    if (FLAG_pretenure_literals) {
+      isolate_->stack_guard()->FullDeopt();
+    }
   }
 
   if (new_space_high_promotion_mode_active_ &&
@@ -1282,8 +1293,6 @@ class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
 
 
 void Heap::Scavenge() {
-  RelocationLock relocation_lock(this);
-
 #ifdef VERIFY_HEAP
   if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
 #endif
@@ -2836,13 +2845,6 @@ bool Heap::CreateInitialObjects() {
   }
   hidden_string_ = String::cast(obj);
 
-  // Allocate the foreign for __proto__.
-  { MaybeObject* maybe_obj =
-        AllocateForeign((Address) &Accessors::ObjectPrototype);
-    if (!maybe_obj->ToObject(&obj)) return false;
-  }
-  set_prototype_accessors(Foreign::cast(obj));
-
   // Allocate the code_stubs dictionary. The initial size is set to avoid
   // expanding the dictionary during bootstrapping.
   { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(this, 128);
@@ -3963,30 +3965,36 @@ void Heap::InitializeFunction(JSFunction* function,
 
 
 MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
-  // Allocate the prototype.  Make sure to use the object function
-  // from the function's context, since the function can be from a
-  // different context.
-  JSFunction* object_function =
-      function->context()->native_context()->object_function();
-
-  // Each function prototype gets a copy of the object function map.
-  // This avoid unwanted sharing of maps between prototypes of different
-  // constructors.
+  // Make sure to use globals from the function's context, since the function
+  // can be from a different context.
+  Context* native_context = function->context()->native_context();
+  bool needs_constructor_property;
   Map* new_map;
-  ASSERT(object_function->has_initial_map());
-  MaybeObject* maybe_map = object_function->initial_map()->Copy();
-  if (!maybe_map->To(&new_map)) return maybe_map;
+  if (function->shared()->is_generator()) {
+    // Generator prototypes can share maps since they don't have "constructor"
+    // properties.
+    new_map = native_context->generator_object_prototype_map();
+    needs_constructor_property = false;
+  } else {
+    // Each function prototype gets a fresh map to avoid unwanted sharing of
+    // maps between prototypes of different constructors.
+    JSFunction* object_function = native_context->object_function();
+    ASSERT(object_function->has_initial_map());
+    MaybeObject* maybe_map = object_function->initial_map()->Copy();
+    if (!maybe_map->To(&new_map)) return maybe_map;
+    needs_constructor_property = true;
+  }
 
   Object* prototype;
   MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
   if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
 
-  // When creating the prototype for the function we must set its
-  // constructor to the function.
-  MaybeObject* maybe_failure =
-      JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
-          constructor_string(), function, DONT_ENUM);
-  if (maybe_failure->IsFailure()) return maybe_failure;
+  if (needs_constructor_property) {
+    MaybeObject* maybe_failure =
+        JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
+            constructor_string(), function, DONT_ENUM);
+    if (maybe_failure->IsFailure()) return maybe_failure;
+  }
 
   return prototype;
 }
@@ -4086,10 +4094,20 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
 
   // First create a new map with the size and number of in-object properties
   // suggested by the function.
-  int instance_size = fun->shared()->CalculateInstanceSize();
-  int in_object_properties = fun->shared()->CalculateInObjectProperties();
+  InstanceType instance_type;
+  int instance_size;
+  int in_object_properties;
+  if (fun->shared()->is_generator()) {
+    instance_type = JS_GENERATOR_OBJECT_TYPE;
+    instance_size = JSGeneratorObject::kSize;
+    in_object_properties = 0;
+  } else {
+    instance_type = JS_OBJECT_TYPE;
+    instance_size = fun->shared()->CalculateInstanceSize();
+    in_object_properties = fun->shared()->CalculateInObjectProperties();
+  }
   Map* map;
-  MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
+  MaybeObject* maybe_map = AllocateMap(instance_type, instance_size);
   if (!maybe_map->To(&map)) return maybe_map;
 
   // Fetch or allocate prototype.
@@ -4111,7 +4129,8 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
   // the inline_new flag so we only change the map if we generate a
   // specialized construct stub.
   ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
-  if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
+  if (instance_type == JS_OBJECT_TYPE &&
+      fun->shared()->CanGenerateInlineConstructor(prototype)) {
     int count = fun->shared()->this_property_assignments_count();
     if (count > in_object_properties) {
       // Inline constructor can only handle inobject properties.
@@ -4144,7 +4163,9 @@ MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
     }
   }
 
-  fun->shared()->StartInobjectSlackTracking(map);
+  if (instance_type == JS_OBJECT_TYPE) {
+    fun->shared()->StartInobjectSlackTracking(map);
+  }
 
   return map;
 }
@@ -4327,6 +4348,22 @@ MaybeObject* Heap::AllocateJSObjectWithAllocationSite(JSFunction* constructor,
 }
 
 
+MaybeObject* Heap::AllocateJSGeneratorObject(JSFunction *function) {
+  ASSERT(function->shared()->is_generator());
+  Map *map;
+  if (function->has_initial_map()) {
+    map = function->initial_map();
+  } else {
+    // Allocate the initial map if absent.
+    MaybeObject* maybe_map = AllocateInitialMap(function);
+    if (!maybe_map->To(&map)) return maybe_map;
+    function->set_initial_map(map);
+  }
+  ASSERT(map->instance_type() == JS_GENERATOR_OBJECT_TYPE);
+  return AllocateJSObjectFromMap(map);
+}
+
+
 MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
   // Allocate a fresh map. Modules do not have a prototype.
   Map* map;
@@ -4945,7 +4982,7 @@ static inline void WriteOneByteData(Vector<const char> vector,
                                     int len) {
   // Only works for ascii.
   ASSERT(vector.length() == len);
-  memcpy(chars, vector.start(), len);
+  OS::MemCopy(chars, vector.start(), len);
 }
 
 static inline void WriteTwoByteData(Vector<const char> vector,
@@ -6588,11 +6625,6 @@ bool Heap::SetUp() {
 
   store_buffer()->SetUp();
 
-  if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
-#ifdef DEBUG
-  relocation_mutex_locked_ = false;
-#endif  // DEBUG
-
   return true;
 }
 
@@ -6695,8 +6727,6 @@ void Heap::TearDown() {
   incremental_marking()->TearDown();
 
   isolate_->memory_allocator()->TearDown();
-
-  delete relocation_mutex_;
 }
 
 
@@ -7821,8 +7851,8 @@ void Heap::CheckpointObjectStats() {
   FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
 #undef ADJUST_LAST_TIME_OBJECT_COUNT
 
-  memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
-  memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
+  OS::MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
+  OS::MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
   ClearObjectStats();
 }
 
index 8992e31..7b4b70d 100644 (file)
@@ -150,7 +150,6 @@ namespace internal {
   V(HeapNumber, minus_zero_value, MinusZeroValue)                              \
   V(Map, neander_map, NeanderMap)                                              \
   V(JSObject, message_listeners, MessageListeners)                             \
-  V(Foreign, prototype_accessors, PrototypeAccessors)                          \
   V(UnseededNumberDictionary, code_stubs, CodeStubs)                           \
   V(UnseededNumberDictionary, non_monomorphic_cache, NonMonomorphicCache)      \
   V(PolymorphicCodeCache, polymorphic_code_cache, PolymorphicCodeCache)        \
@@ -210,9 +209,11 @@ namespace internal {
   V(index_string, "index")                                               \
   V(last_index_string, "lastIndex")                                      \
   V(object_string, "object")                                             \
+  V(payload_string, "payload")                                           \
   V(prototype_string, "prototype")                                       \
   V(string_string, "string")                                             \
   V(String_string, "String")                                             \
+  V(unknown_field_string, "unknownField")                                \
   V(symbol_string, "symbol")                                             \
   V(Symbol_string, "Symbol")                                             \
   V(Date_string, "Date")                                                 \
@@ -601,6 +602,13 @@ class Heap {
     return old_pointer_space_->allocation_limit_address();
   }
 
+  Address* OldDataSpaceAllocationTopAddress() {
+    return old_data_space_->allocation_top_address();
+  }
+  Address* OldDataSpaceAllocationLimitAddress() {
+    return old_data_space_->allocation_limit_address();
+  }
+
   // Uncommit unused semi space.
   bool UncommitFromSpace() { return new_space_.UncommitFromSpace(); }
 
@@ -617,6 +625,9 @@ class Heap {
       JSFunction* constructor,
       Handle<Object> allocation_site_info_payload);
 
+  MUST_USE_RESULT MaybeObject* AllocateJSGeneratorObject(
+      JSFunction* function);
+
   MUST_USE_RESULT MaybeObject* AllocateJSModule(Context* context,
                                                 ScopeInfo* scope_info);
 
@@ -1329,6 +1340,10 @@ class Heap {
   inline bool InOldPointerSpace(Address address);
   inline bool InOldPointerSpace(Object* object);
 
+  // Returns whether the object resides in old data space.
+  inline bool InOldDataSpace(Address address);
+  inline bool InOldDataSpace(Object* object);
+
   // Checks whether an address/object in the heap (including auxiliary
   // area and unused area).
   bool Contains(Address addr);
@@ -1497,6 +1512,12 @@ class Heap {
   MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int length,
                                                      PretenureFlag pretenure);
 
+  // Predicate that governs global pre-tenuring decisions based on observed
+  // promotion rates of previous collections.
+  inline bool ShouldGloballyPretenure() {
+    return new_space_high_promotion_mode_active_;
+  }
+
   inline intptr_t PromotedTotalSize() {
     return PromotedSpaceSizeOfObjects() + PromotedExternalMemorySize();
   }
@@ -1825,38 +1846,6 @@ class Heap {
 
   void CheckpointObjectStats();
 
-  // We don't use a ScopedLock here since we want to lock the heap
-  // only when FLAG_parallel_recompilation is true.
-  class RelocationLock {
-   public:
-    explicit RelocationLock(Heap* heap) : heap_(heap) {
-      if (FLAG_parallel_recompilation) {
-        heap_->relocation_mutex_->Lock();
-#ifdef DEBUG
-        heap_->relocation_mutex_locked_ = true;
-#endif  // DEBUG
-      }
-    }
-
-    ~RelocationLock() {
-      if (FLAG_parallel_recompilation) {
-#ifdef DEBUG
-        heap_->relocation_mutex_locked_ = false;
-#endif  // DEBUG
-        heap_->relocation_mutex_->Unlock();
-      }
-    }
-
-#ifdef DEBUG
-    static bool IsLocked(Heap* heap) {
-      return heap->relocation_mutex_locked_;
-    }
-#endif  // DEBUG
-
-   private:
-    Heap* heap_;
-  };
-
  private:
   Heap();
 
@@ -2326,11 +2315,6 @@ class Heap {
 
   MemoryChunk* chunks_queued_for_free_;
 
-  Mutex* relocation_mutex_;
-#ifdef DEBUG
-  bool relocation_mutex_locked_;
-#endif  // DEBUG;
-
   friend class Factory;
   friend class GCTracer;
   friend class DisallowAllocationFailure;
index edbffc2..60a6912 100644 (file)
@@ -685,7 +685,7 @@ void HValue::Kill() {
     HValue* operand = OperandAt(i);
     if (operand == NULL) continue;
     HUseListNode* first = operand->use_list_;
-    if (first != NULL && first->value() == this && first->index() == i) {
+    if (first != NULL && first->value()->CheckFlag(kIsDead)) {
       operand->use_list_ = first->tail();
     }
   }
@@ -806,6 +806,9 @@ void HInstruction::PrintTo(StringStream* stream) {
   PrintRangeTo(stream);
   PrintChangesTo(stream);
   PrintTypeTo(stream);
+  if (CheckFlag(HValue::kHasNoObservableSideEffects)) {
+    stream->Add(" [noOSE]");
+  }
 }
 
 
@@ -1581,10 +1584,10 @@ void HCheckMaps::SetSideEffectDominator(GVNFlag side_effect,
   // for which the map is known.
   if (HasNoUses() && dominator->IsStoreNamedField()) {
     HStoreNamedField* store = HStoreNamedField::cast(dominator);
-    Handle<Map> map = store->transition();
-    if (map.is_null() || store->object() != value()) return;
+    UniqueValueId map_unique_id = store->transition_unique_id();
+    if (!map_unique_id.IsInitialized() || store->object() != value()) return;
     for (int i = 0; i < map_set()->length(); i++) {
-      if (map.is_identical_to(map_set()->at(i))) {
+      if (map_unique_id == map_unique_ids_.at(i)) {
         DeleteAndReplaceWith(NULL);
         return;
       }
@@ -1980,20 +1983,25 @@ void HPhi::AddIndirectUsesTo(int* dest) {
 }
 
 
-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_--;
+void HSimulate::MergeWith(ZoneList<HSimulate*>* list) {
+  while (!list->is_empty()) {
+    HSimulate* from = list->RemoveLast();
+    ZoneList<HValue*>* from_values = &from->values_;
+    for (int i = 0; i < from_values->length(); ++i) {
+      if (from->HasAssignedIndexAt(i)) {
+        AddAssignedValue(from->GetAssignedIndexAt(i),
+                         from_values->at(i));
       } else {
-        other->AddPushedValue(value);
+        if (pop_count_ > 0) {
+          pop_count_--;
+        } else {
+          AddPushedValue(from_values->at(i));
+        }
       }
     }
+    pop_count_ += from->pop_count_;
+    from->DeleteAndReplaceWith(NULL);
   }
-  other->pop_count_ += pop_count();
 }
 
 
@@ -2039,6 +2047,7 @@ static bool IsInteger32(double value) {
 
 HConstant::HConstant(Handle<Object> handle, Representation r)
   : handle_(handle),
+    unique_id_(),
     has_int32_value_(false),
     has_double_value_(false),
     is_internalized_string_(false),
@@ -2067,11 +2076,13 @@ HConstant::HConstant(Handle<Object> handle, Representation r)
 
 
 HConstant::HConstant(Handle<Object> handle,
+                     UniqueValueId unique_id,
                      Representation r,
                      HType type,
                      bool is_internalize_string,
                      bool boolean_value)
     : handle_(handle),
+      unique_id_(unique_id),
       has_int32_value_(false),
       has_double_value_(false),
       is_internalized_string_(is_internalize_string),
@@ -2087,7 +2098,9 @@ HConstant::HConstant(Handle<Object> handle,
 HConstant::HConstant(int32_t integer_value,
                      Representation r,
                      Handle<Object> optional_handle)
-    : has_int32_value_(true),
+    : handle_(optional_handle),
+      unique_id_(),
+      has_int32_value_(true),
       has_double_value_(true),
       is_internalized_string_(false),
       boolean_value_(integer_value != 0),
@@ -2100,7 +2113,9 @@ HConstant::HConstant(int32_t integer_value,
 HConstant::HConstant(double double_value,
                      Representation r,
                      Handle<Object> optional_handle)
-    : has_int32_value_(IsInteger32(double_value)),
+    : handle_(optional_handle),
+      unique_id_(),
+      has_int32_value_(IsInteger32(double_value)),
       has_double_value_(true),
       is_internalized_string_(false),
       boolean_value_(double_value != 0 && !isnan(double_value)),
@@ -2125,8 +2140,12 @@ HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const {
   if (has_int32_value_) return new(zone) HConstant(int32_value_, r, handle_);
   if (has_double_value_) return new(zone) HConstant(double_value_, r, handle_);
   ASSERT(!handle_.is_null());
-  return new(zone) HConstant(
-      handle_, r, type_from_value_, is_internalized_string_, boolean_value_);
+  return new(zone) HConstant(handle_,
+                             unique_id_,
+                             r,
+                             type_from_value_,
+                             is_internalized_string_,
+                             boolean_value_);
 }
 
 
@@ -2451,6 +2470,8 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
                                                        Zone* zone)
     : types_(Min(types->length(), kMaxLoadPolymorphism), zone),
       name_(name),
+      types_unique_ids_(0, zone),
+      name_unique_id_(),
       need_generic_(false) {
   SetOperandAt(0, context);
   SetOperandAt(1, object);
@@ -2517,15 +2538,39 @@ HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
 }
 
 
+void HCheckMaps::FinalizeUniqueValueId() {
+  if (!map_unique_ids_.is_empty()) return;
+  Zone* zone = block()->zone();
+  map_unique_ids_.Initialize(map_set_.length(), zone);
+  for (int i = 0; i < map_set_.length(); i++) {
+    map_unique_ids_.Add(UniqueValueId(map_set_.at(i)), zone);
+  }
+}
+
+
+void HLoadNamedFieldPolymorphic::FinalizeUniqueValueId() {
+  if (!types_unique_ids_.is_empty()) return;
+  Zone* zone = block()->zone();
+  types_unique_ids_.Initialize(types_.length(), zone);
+  for (int i = 0; i < types_.length(); i++) {
+    types_unique_ids_.Add(UniqueValueId(types_.at(i)), zone);
+  }
+  name_unique_id_ = UniqueValueId(name_);
+}
+
+
 bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
+  ASSERT_EQ(types_.length(), types_unique_ids_.length());
   HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
-  if (types_.length() != other->types()->length()) return false;
-  if (!name_.is_identical_to(other->name())) return false;
+  if (name_unique_id_ != other->name_unique_id_) return false;
+  if (types_unique_ids_.length() != other->types_unique_ids_.length()) {
+    return false;
+  }
   if (need_generic_ != other->need_generic_) return false;
-  for (int i = 0; i < types_.length(); i++) {
+  for (int i = 0; i < types_unique_ids_.length(); i++) {
     bool found = false;
-    for (int j = 0; j < types_.length(); j++) {
-      if (types_.at(j).is_identical_to(other->types()->at(i))) {
+    for (int j = 0; j < types_unique_ids_.length(); j++) {
+      if (types_unique_ids_.at(j) == other->types_unique_ids_.at(i)) {
         found = true;
         break;
       }
@@ -2916,12 +2961,6 @@ void HAllocate::PrintDataTo(StringStream* stream) {
 }
 
 
-HType HFastLiteral::CalculateInferredType() {
-  // TODO(mstarzinger): Be smarter, could also be JSArray here.
-  return HType::JSObject();
-}
-
-
 HType HArrayLiteral::CalculateInferredType() {
   return HType::JSArray();
 }
index ad03687..6853dfe 100644 (file)
@@ -111,7 +111,6 @@ class LChunkBuilder;
   V(DummyUse)                                  \
   V(ElementsKind)                              \
   V(EnterInlined)                              \
-  V(FastLiteral)                               \
   V(FixedArrayBaseLength)                      \
   V(ForceRepresentation)                       \
   V(FunctionLiteral)                           \
@@ -235,14 +234,6 @@ class LChunkBuilder;
   virtual Opcode opcode() const { return HValue::k##type; }
 
 
-#ifdef DEBUG
-#define ASSERT_ALLOCATION_DISABLED                                       \
-  ASSERT(isolate()->optimizing_compiler_thread()->IsOptimizerThread() || \
-         !isolate()->heap()->IsAllocationAllowed())
-#else
-#define ASSERT_ALLOCATION_DISABLED do {} while (0)
-#endif
-
 class Range: public ZoneObject {
  public:
   Range()
@@ -365,6 +356,48 @@ class Representation {
 };
 
 
+class UniqueValueId {
+ public:
+  UniqueValueId() : raw_address_(NULL) { }
+
+  explicit UniqueValueId(Object* object) {
+    raw_address_ = reinterpret_cast<Address>(object);
+    ASSERT(IsInitialized());
+  }
+
+  explicit UniqueValueId(Handle<Object> handle) {
+    static const Address kEmptyHandleSentinel = reinterpret_cast<Address>(1);
+    if (handle.is_null()) {
+      raw_address_ = kEmptyHandleSentinel;
+    } else {
+      raw_address_ = reinterpret_cast<Address>(*handle);
+      ASSERT_NE(kEmptyHandleSentinel, raw_address_);
+    }
+    ASSERT(IsInitialized());
+  }
+
+  bool IsInitialized() const { return raw_address_ != NULL; }
+
+  bool operator==(const UniqueValueId& other) const {
+    ASSERT(IsInitialized() && other.IsInitialized());
+    return raw_address_ == other.raw_address_;
+  }
+
+  bool operator!=(const UniqueValueId& other) const {
+    ASSERT(IsInitialized() && other.IsInitialized());
+    return raw_address_ != other.raw_address_;
+  }
+
+  intptr_t Hashcode() const {
+    ASSERT(IsInitialized());
+    return reinterpret_cast<intptr_t>(raw_address_);
+  }
+
+ private:
+  Address raw_address_;
+};
+
+
 class HType {
  public:
   HType() : type_(kUninitialized) { }
@@ -829,6 +862,7 @@ class HValue: public ZoneObject {
     // This flag is set to true after the SetupInformativeDefinitions() pass
     // has processed this instruction.
     kIDefsProcessingDone,
+    kHasNoObservableSideEffects,
     kLastFlag = kIDefsProcessingDone
   };
 
@@ -1006,7 +1040,8 @@ class HValue: public ZoneObject {
     return gvn_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
   }
   bool HasObservableSideEffects() const {
-    return gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
+    return !CheckFlag(kHasNoObservableSideEffects) &&
+        gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
   }
 
   GVNFlagSet DependsOnFlags() const {
@@ -1056,6 +1091,9 @@ class HValue: public ZoneObject {
   bool Equals(HValue* other);
   virtual intptr_t Hashcode();
 
+  // Compute unique ids upfront that is safe wrt GC and parallel recompilation.
+  virtual void FinalizeUniqueValueId() { }
+
   // Printing support.
   virtual void PrintTo(StringStream* stream) = 0;
   void PrintNameTo(StringStream* stream);
@@ -1830,7 +1868,7 @@ class HSimulate: public HInstruction {
     return Representation::None();
   }
 
-  void MergeInto(HSimulate* other);
+  void MergeWith(ZoneList<HSimulate*>* list);
   bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
 
   DECLARE_CONCRETE_INSTRUCTION(Simulate)
@@ -2642,7 +2680,8 @@ class HLoadExternalArrayPointer: public HUnaryOperation {
 class HCheckMaps: public HTemplateInstruction<2> {
  public:
   HCheckMaps(HValue* value, Handle<Map> map, Zone* zone,
-             HValue* typecheck = NULL) {
+             HValue* typecheck = NULL)
+      : map_unique_ids_(0, zone) {
     SetOperandAt(0, value);
     // If callers don't depend on a typecheck, they can pass in NULL. In that
     // case we use a copy of the |value| argument as a dummy value.
@@ -2654,7 +2693,8 @@ class HCheckMaps: public HTemplateInstruction<2> {
     SetGVNFlag(kDependsOnElementsKind);
     map_set()->Add(map, zone);
   }
-  HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone) {
+  HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone)
+      : map_unique_ids_(0, zone) {
     SetOperandAt(0, value);
     SetOperandAt(1, value);
     set_representation(Representation::Tagged());
@@ -2701,28 +2741,36 @@ class HCheckMaps: public HTemplateInstruction<2> {
   HValue* value() { return OperandAt(0); }
   SmallMapList* map_set() { return &map_set_; }
 
+  virtual void FinalizeUniqueValueId();
+
   DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
 
  protected:
   virtual bool DataEquals(HValue* other) {
+    ASSERT_EQ(map_set_.length(), map_unique_ids_.length());
     HCheckMaps* b = HCheckMaps::cast(other);
     // Relies on the fact that map_set has been sorted before.
-    if (map_set()->length() != b->map_set()->length()) return false;
-    for (int i = 0; i < map_set()->length(); i++) {
-      if (!map_set()->at(i).is_identical_to(b->map_set()->at(i))) return false;
+    if (map_unique_ids_.length() != b->map_unique_ids_.length()) {
+      return false;
+    }
+    for (int i = 0; i < map_unique_ids_.length(); i++) {
+      if (map_unique_ids_.at(i) != b->map_unique_ids_.at(i)) {
+        return false;
+      }
     }
     return true;
   }
 
  private:
   SmallMapList map_set_;
+  ZoneList<UniqueValueId> map_unique_ids_;
 };
 
 
 class HCheckFunction: public HUnaryOperation {
  public:
   HCheckFunction(HValue* value, Handle<JSFunction> function)
-      : HUnaryOperation(value), target_(function) {
+      : HUnaryOperation(value), target_(function), target_unique_id_() {
     set_representation(Representation::Tagged());
     SetFlag(kUseGVN);
     target_in_new_space_ = Isolate::Current()->heap()->InNewSpace(*function);
@@ -2738,6 +2786,10 @@ class HCheckFunction: public HUnaryOperation {
   virtual void Verify();
 #endif
 
+  virtual void FinalizeUniqueValueId() {
+    target_unique_id_ = UniqueValueId(target_);
+  }
+
   Handle<JSFunction> target() const { return target_; }
   bool target_in_new_space() const { return target_in_new_space_; }
 
@@ -2746,11 +2798,12 @@ class HCheckFunction: public HUnaryOperation {
  protected:
   virtual bool DataEquals(HValue* other) {
     HCheckFunction* b = HCheckFunction::cast(other);
-    return target_.is_identical_to(b->target());
+    return target_unique_id_ == b->target_unique_id_;
   }
 
  private:
   Handle<JSFunction> target_;
+  UniqueValueId target_unique_id_;
   bool target_in_new_space_;
 };
 
@@ -2855,7 +2908,11 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
  public:
   HCheckPrototypeMaps(Handle<JSObject> prototype,
                       Handle<JSObject> holder,
-                      Zone* zone) : prototypes_(2, zone), maps_(2, zone) {
+                      Zone* zone)
+      : prototypes_(2, zone),
+        maps_(2, zone),
+        first_prototype_unique_id_(),
+        last_prototype_unique_id_() {
     SetFlag(kUseGVN);
     SetGVNFlag(kDependsOnMaps);
     // Keep a list of all objects on the prototype chain up to the holder
@@ -2881,18 +2938,13 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
   virtual void PrintDataTo(StringStream* stream);
 
   virtual intptr_t Hashcode() {
-    ASSERT_ALLOCATION_DISABLED;
-    // Dereferencing to use the object's raw address for hashing is safe.
-    HandleDereferenceGuard allow_handle_deref(isolate(),
-                                              HandleDereferenceGuard::ALLOW);
-    SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) ||
-                !isolate()->optimizing_compiler_thread()->IsOptimizerThread());
-    intptr_t hash = 0;
-    for (int i = 0; i < prototypes_.length(); i++) {
-      hash = 17 * hash + reinterpret_cast<intptr_t>(*prototypes_[i]);
-      hash = 17 * hash + reinterpret_cast<intptr_t>(*maps_[i]);
-    }
-    return hash;
+    return first_prototype_unique_id_.Hashcode() * 17 +
+           last_prototype_unique_id_.Hashcode();
+  }
+
+  virtual void FinalizeUniqueValueId() {
+    first_prototype_unique_id_ = UniqueValueId(prototypes_.first());
+    last_prototype_unique_id_ = UniqueValueId(prototypes_.last());
   }
 
   bool CanOmitPrototypeChecks() {
@@ -2905,22 +2957,15 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
  protected:
   virtual bool DataEquals(HValue* other) {
     HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other);
-#ifdef DEBUG
-    if (prototypes_.length() != b->prototypes()->length()) return false;
-    for (int i = 0; i < prototypes_.length(); i++) {
-      if (!prototypes_[i].is_identical_to(b->prototypes()->at(i))) return false;
-      if (!maps_[i].is_identical_to(b->maps()->at(i))) return false;
-    }
-    return true;
-#else
-    return prototypes_.first().is_identical_to(b->prototypes()->first()) &&
-           prototypes_.last().is_identical_to(b->prototypes()->last());
-#endif  // DEBUG
+    return first_prototype_unique_id_ == b->first_prototype_unique_id_ &&
+           last_prototype_unique_id_ == b->last_prototype_unique_id_;
   }
 
  private:
   ZoneList<Handle<JSObject> > prototypes_;
   ZoneList<Handle<Map> > maps_;
+  UniqueValueId first_prototype_unique_id_;
+  UniqueValueId last_prototype_unique_id_;
 };
 
 
@@ -3175,6 +3220,7 @@ class HConstant: public HTemplateInstruction<0> {
             Representation r,
             Handle<Object> optional_handle = Handle<Object>::null());
   HConstant(Handle<Object> handle,
+            UniqueValueId unique_id,
             Representation r,
             HType type,
             bool is_internalized_string,
@@ -3188,35 +3234,36 @@ class HConstant: public HTemplateInstruction<0> {
     return handle_;
   }
 
-  bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); }
+  bool IsSpecialDouble() const {
+    return has_double_value_ &&
+        (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
+         FixedDoubleArray::is_the_hole_nan(double_value_) ||
+         isnan(double_value_));
+  }
 
   bool ImmortalImmovable() const {
     if (has_int32_value_) {
       return false;
     }
     if (has_double_value_) {
-      if (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
-          isnan(double_value_)) {
+      if (IsSpecialDouble()) {
         return true;
       }
       return false;
     }
 
     ASSERT(!handle_.is_null());
+    HandleDereferenceGuard allow_dereference_for_immovable_check(
+        isolate(), HandleDereferenceGuard::ALLOW);
     Heap* heap = isolate()->heap();
-    // We should have handled minus_zero_value and nan_value in the
-    // has_double_value_ clause above.
-    // Dereferencing is safe to compare against immovable singletons.
-    HandleDereferenceGuard allow_handle_deref(isolate(),
-                                              HandleDereferenceGuard::ALLOW);
-    ASSERT(*handle_ != heap->minus_zero_value());
-    ASSERT(*handle_ != heap->nan_value());
-    return *handle_ == heap->undefined_value() ||
-           *handle_ == heap->null_value() ||
-           *handle_ == heap->true_value() ||
-           *handle_ == heap->false_value() ||
-           *handle_ == heap->the_hole_value() ||
-           *handle_ == heap->empty_string();
+    ASSERT(unique_id_ != UniqueValueId(heap->minus_zero_value()));
+    ASSERT(unique_id_ != UniqueValueId(heap->nan_value()));
+    return unique_id_ == UniqueValueId(heap->undefined_value()) ||
+           unique_id_ == UniqueValueId(heap->null_value()) ||
+           unique_id_ == UniqueValueId(heap->true_value()) ||
+           unique_id_ == UniqueValueId(heap->false_value()) ||
+           unique_id_ == UniqueValueId(heap->the_hole_value()) ||
+           unique_id_ == UniqueValueId(heap->empty_string());
   }
 
   virtual Representation RequiredInputRepresentation(int index) {
@@ -3227,7 +3274,9 @@ class HConstant: public HTemplateInstruction<0> {
     return has_int32_value_;
   }
 
-  virtual bool EmitAtUses() { return !representation().IsDouble(); }
+  virtual bool EmitAtUses() {
+    return !representation().IsDouble() || IsSpecialDouble();
+  }
   virtual void PrintDataTo(StringStream* stream);
   virtual HType CalculateInferredType();
   bool IsInteger() { return handle()->IsSmi(); }
@@ -3246,6 +3295,16 @@ class HConstant: public HTemplateInstruction<0> {
     ASSERT(HasDoubleValue());
     return double_value_;
   }
+  bool IsTheHole() const {
+    if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) {
+      return true;
+    }
+    Heap* heap = isolate()->heap();
+    if (!handle_.is_null() && *handle_ == heap->the_hole_value()) {
+      return true;
+    }
+    return false;
+  }
   bool HasNumberValue() const { return has_double_value_; }
   int32_t NumberValueAsInteger32() const {
     ASSERT(HasNumberValue());
@@ -3274,24 +3333,21 @@ class HConstant: public HTemplateInstruction<0> {
   }
 
   virtual intptr_t Hashcode() {
-    ASSERT_ALLOCATION_DISABLED;
-    intptr_t hash;
-
     if (has_int32_value_) {
-      hash = static_cast<intptr_t>(int32_value_);
+      return static_cast<intptr_t>(int32_value_);
     } else if (has_double_value_) {
-      hash = static_cast<intptr_t>(BitCast<int64_t>(double_value_));
+      return static_cast<intptr_t>(BitCast<int64_t>(double_value_));
     } else {
       ASSERT(!handle_.is_null());
-      // Dereferencing to use the object's raw address for hashing is safe.
-      HandleDereferenceGuard allow_handle_deref(isolate(),
-                                                HandleDereferenceGuard::ALLOW);
-      SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) ||
-                 !isolate()->optimizing_compiler_thread()->IsOptimizerThread());
-      hash = reinterpret_cast<intptr_t>(*handle_);
+      return unique_id_.Hashcode();
     }
+  }
 
-    return hash;
+  virtual void FinalizeUniqueValueId() {
+    if (!has_double_value_) {
+      ASSERT(!handle_.is_null());
+      unique_id_ = UniqueValueId(handle_);
+    }
   }
 
 #ifdef DEBUG
@@ -3315,7 +3371,7 @@ class HConstant: public HTemplateInstruction<0> {
     } else {
       ASSERT(!handle_.is_null());
       return !other_constant->handle_.is_null() &&
-          handle_.is_identical_to(other_constant->handle_);
+             unique_id_ == other_constant->unique_id_;
     }
   }
 
@@ -3329,6 +3385,7 @@ class HConstant: public HTemplateInstruction<0> {
   // constant is non-numeric, handle_ always points to a valid
   // constant HeapObject.
   Handle<Object> handle_;
+  UniqueValueId unique_id_;
 
   // We store the HConstant in the most specific form safely possible.
   // The two flags, has_int32_value_ and has_double_value_ tell us if
@@ -4740,7 +4797,7 @@ class HUnknownOSRValue: public HTemplateInstruction<0> {
 class HLoadGlobalCell: public HTemplateInstruction<0> {
  public:
   HLoadGlobalCell(Handle<JSGlobalPropertyCell> cell, PropertyDetails details)
-      : cell_(cell), details_(details) {
+      : cell_(cell), details_(details), unique_id_() {
     set_representation(Representation::Tagged());
     SetFlag(kUseGVN);
     SetGVNFlag(kDependsOnGlobalVars);
@@ -4752,13 +4809,11 @@ class HLoadGlobalCell: public HTemplateInstruction<0> {
   virtual void PrintDataTo(StringStream* stream);
 
   virtual intptr_t Hashcode() {
-    ASSERT_ALLOCATION_DISABLED;
-    // Dereferencing to use the object's raw address for hashing is safe.
-    HandleDereferenceGuard allow_handle_deref(isolate(),
-                                              HandleDereferenceGuard::ALLOW);
-    SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) ||
-               !isolate()->optimizing_compiler_thread()->IsOptimizerThread());
-    return reinterpret_cast<intptr_t>(*cell_);
+    return unique_id_.Hashcode();
+  }
+
+  virtual void FinalizeUniqueValueId() {
+    unique_id_ = UniqueValueId(cell_);
   }
 
   virtual Representation RequiredInputRepresentation(int index) {
@@ -4770,7 +4825,7 @@ class HLoadGlobalCell: public HTemplateInstruction<0> {
  protected:
   virtual bool DataEquals(HValue* other) {
     HLoadGlobalCell* b = HLoadGlobalCell::cast(other);
-    return cell_.is_identical_to(b->cell());
+    return unique_id_ == b->unique_id_;
   }
 
  private:
@@ -4778,6 +4833,7 @@ class HLoadGlobalCell: public HTemplateInstruction<0> {
 
   Handle<JSGlobalPropertyCell> cell_;
   PropertyDetails details_;
+  UniqueValueId unique_id_;
 };
 
 
@@ -4860,7 +4916,6 @@ class HAllocate: public HTemplateInstruction<2> {
   HAllocate(HValue* context, HValue* size, HType type, Flags flags)
       : type_(type),
         flags_(flags) {
-    ASSERT((flags & CAN_ALLOCATE_IN_OLD_DATA_SPACE) == 0);  // unimplemented
     SetOperandAt(0, context);
     SetOperandAt(1, size);
     set_representation(Representation::Tagged());
@@ -4955,7 +5010,6 @@ inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
         new_space_dominator);
   }
   if (object != new_space_dominator) return true;
-  if (object->IsFastLiteral()) return false;
   if (object->IsAllocateObject()) return false;
   if (object->IsAllocate()) {
     return !HAllocate::cast(object)->GuaranteedInNewSpace();
@@ -5238,12 +5292,16 @@ class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> {
 
   static const int kMaxLoadPolymorphism = 4;
 
+  virtual void FinalizeUniqueValueId();
+
  protected:
   virtual bool DataEquals(HValue* value);
 
  private:
   SmallMapList types_;
   Handle<String> name_;
+  ZoneList<UniqueValueId> types_unique_ids_;
+  UniqueValueId name_unique_id_;
   bool need_generic_;
 };
 
@@ -5507,6 +5565,7 @@ class HStoreNamedField: public HTemplateInstruction<2> {
       : name_(name),
         is_in_object_(in_object),
         offset_(offset),
+        transition_unique_id_(),
         new_space_dominator_(NULL) {
     SetOperandAt(0, obj);
     SetOperandAt(1, val);
@@ -5537,6 +5596,7 @@ class HStoreNamedField: public HTemplateInstruction<2> {
   bool is_in_object() const { return is_in_object_; }
   int offset() const { return offset_; }
   Handle<Map> transition() const { return transition_; }
+  UniqueValueId transition_unique_id() const { return transition_unique_id_; }
   void set_transition(Handle<Map> map) { transition_ = map; }
   HValue* new_space_dominator() const { return new_space_dominator_; }
 
@@ -5549,11 +5609,16 @@ class HStoreNamedField: public HTemplateInstruction<2> {
     return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
   }
 
+  virtual void FinalizeUniqueValueId() {
+    transition_unique_id_ = UniqueValueId(transition_);
+  }
+
  private:
   Handle<String> name_;
   bool is_in_object_;
   int offset_;
   Handle<Map> transition_;
+  UniqueValueId transition_unique_id_;
   HValue* new_space_dominator_;
 };
 
@@ -5677,6 +5742,10 @@ class HStoreKeyed
   bool IsDehoisted() { return is_dehoisted_; }
   void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
 
+  bool IsConstantHoleStore() {
+    return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
+  }
+
   virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
     ASSERT(side_effect == kChangesNewSpacePromotion);
     new_space_dominator_ = dominator;
@@ -5750,6 +5819,8 @@ class HTransitionElementsKind: public HTemplateInstruction<2> {
                           Handle<Map> transitioned_map)
       : original_map_(original_map),
         transitioned_map_(transitioned_map),
+        original_map_unique_id_(),
+        transitioned_map_unique_id_(),
         from_kind_(original_map->elements_kind()),
         to_kind_(transitioned_map->elements_kind()) {
     SetOperandAt(0, object);
@@ -5780,18 +5851,25 @@ class HTransitionElementsKind: public HTemplateInstruction<2> {
 
   virtual void PrintDataTo(StringStream* stream);
 
+  virtual void FinalizeUniqueValueId() {
+    original_map_unique_id_ = UniqueValueId(original_map_);
+    transitioned_map_unique_id_ = UniqueValueId(transitioned_map_);
+  }
+
   DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
 
  protected:
   virtual bool DataEquals(HValue* other) {
     HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
-    return original_map_.is_identical_to(instr->original_map()) &&
-        transitioned_map_.is_identical_to(instr->transitioned_map());
+    return original_map_unique_id_ == instr->original_map_unique_id_ &&
+           transitioned_map_unique_id_ == instr->transitioned_map_unique_id_;
   }
 
  private:
   Handle<Map> original_map_;
   Handle<Map> transitioned_map_;
+  UniqueValueId original_map_unique_id_;
+  UniqueValueId transitioned_map_unique_id_;
   ElementsKind from_kind_;
   ElementsKind to_kind_;
 };
@@ -5966,45 +6044,6 @@ class HMaterializedLiteral: public HTemplateInstruction<V> {
 };
 
 
-class HFastLiteral: public HMaterializedLiteral<1> {
- public:
-  HFastLiteral(HValue* context,
-               Handle<JSObject> boilerplate,
-               int total_size,
-               int literal_index,
-               int depth,
-               AllocationSiteMode mode)
-      : HMaterializedLiteral<1>(literal_index, depth, mode),
-        boilerplate_(boilerplate),
-        total_size_(total_size) {
-    SetOperandAt(0, context);
-    SetGVNFlag(kChangesNewSpacePromotion);
-  }
-
-  // Maximum depth and total number of elements and properties for literal
-  // graphs to be considered for fast deep-copying.
-  static const int kMaxLiteralDepth = 3;
-  static const int kMaxLiteralProperties = 8;
-
-  HValue* context() { return OperandAt(0); }
-  Handle<JSObject> boilerplate() const { return boilerplate_; }
-  int total_size() const { return total_size_; }
-  virtual Representation RequiredInputRepresentation(int index) {
-    return Representation::Tagged();
-  }
-  virtual Handle<Map> GetMonomorphicJSObjectMap() {
-    return Handle<Map>(boilerplate()->map());
-  }
-  virtual HType CalculateInferredType();
-
-  DECLARE_CONCRETE_INSTRUCTION(FastLiteral)
-
- private:
-  Handle<JSObject> boilerplate_;
-  int total_size_;
-};
-
-
 class HArrayLiteral: public HMaterializedLiteral<1> {
  public:
   HArrayLiteral(HValue* context,
@@ -6192,7 +6231,7 @@ class HToFastProperties: public HUnaryOperation {
     // This instruction is not marked as having side effects, but
     // changes the map of the input operand. Use it only when creating
     // object literals.
-    ASSERT(value->IsObjectLiteral() || value->IsFastLiteral());
+    ASSERT(value->IsObjectLiteral());
     set_representation(Representation::Tagged());
   }
 
index abff7b7..127d7a9 100644 (file)
@@ -517,7 +517,6 @@ class ReachabilityAnalyzer BASE_EMBEDDED {
 
 void HGraph::Verify(bool do_full_verify) const {
   // Allow dereferencing for debug mode verification.
-  Heap::RelocationLock(isolate()->heap());
   HandleDereferenceGuard allow_handle_deref(isolate(),
                                             HandleDereferenceGuard::ALLOW);
   for (int i = 0; i < blocks_.length(); i++) {
@@ -619,6 +618,7 @@ HConstant* HGraph::GetConstant##Name() {                                       \
   if (!constant_##name##_.is_set()) {                                          \
     HConstant* constant = new(zone()) HConstant(                               \
         isolate()->factory()->name##_value(),                                  \
+        UniqueValueId(isolate()->heap()->name##_value()),                      \
         Representation::Tagged(),                                              \
         htype,                                                                 \
         false,                                                                 \
@@ -880,6 +880,7 @@ HGraph* HGraphBuilder::CreateGraph() {
   HPhase phase("H_Block building", isolate());
   set_current_block(graph()->entry_block());
   if (!BuildGraph()) return NULL;
+  graph()->FinalizeUniqueValueIds();
   return graph_;
 }
 
@@ -887,6 +888,9 @@ HGraph* HGraphBuilder::CreateGraph() {
 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
   ASSERT(current_block() != NULL);
   current_block()->AddInstruction(instr);
+  if (no_side_effects_scope_count_ > 0) {
+    instr->SetFlag(HValue::kHasNoObservableSideEffects);
+  }
   return instr;
 }
 
@@ -894,6 +898,7 @@ HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
 void HGraphBuilder::AddSimulate(BailoutId id,
                                 RemovableSimulate removable) {
   ASSERT(current_block() != NULL);
+  ASSERT(no_side_effects_scope_count_ == 0);
   current_block()->AddSimulate(id, removable);
   environment()->set_previous_ast_id(id);
 }
@@ -1041,7 +1046,6 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
                                                  HValue* length,
                                                  HValue* key,
                                                  bool is_js_array) {
-  BailoutId ast_id = environment()->previous_ast_id();
   Zone* zone = this->zone();
   IfBuilder length_checker(this);
 
@@ -1074,7 +1078,6 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
         HAdd::New(zone, context, length, graph_->GetConstant1()));
     new_length->ChangeRepresentation(Representation::Integer32());
     new_length->ClearFlag(HValue::kCanOverflow);
-    AddSimulate(ast_id, REMOVABLE_SIMULATE);
 
     Factory* factory = isolate()->factory();
     HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField(
@@ -1083,7 +1086,6 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
         new_length, true,
         JSArray::kLengthOffset));
     length_store->SetGVNFlag(kChangesArrayLengths);
-    AddSimulate(ast_id, REMOVABLE_SIMULATE);
   }
 
   length_checker.BeginElse();
@@ -1210,6 +1212,8 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
   }
 
   if (IsGrowStoreMode(store_mode)) {
+    NoObservableSideEffectsScope no_effects(this);
+
     elements = BuildCheckForCapacityGrow(object, elements, elements_kind,
                                          length, key, is_js_array);
     checked_key = key;
@@ -1219,6 +1223,8 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
 
     if (is_store && (fast_elements || fast_smi_only_elements)) {
       if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
+        NoObservableSideEffectsScope no_effects(this);
+
         elements = BuildCopyElementsOnWrite(object, elements, elements_kind,
                                             length);
       } else {
@@ -1238,7 +1244,6 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
 HValue* HGraphBuilder::BuildAllocateElements(HValue* context,
                                              ElementsKind kind,
                                              HValue* capacity) {
-  BailoutId ast_id = current_block()->last_environment()->previous_ast_id();
   Zone* zone = this->zone();
 
   int elements_size = IsFastDoubleElementsKind(kind)
@@ -1260,10 +1265,14 @@ HValue* HGraphBuilder::BuildAllocateElements(HValue* context,
   total_size->ClearFlag(HValue::kCanOverflow);
 
   HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
-  // TODO(hpayer): add support for old data space
-  if (FLAG_pretenure_literals && !IsFastDoubleElementsKind(kind)) {
-    flags = static_cast<HAllocate::Flags>(
-        flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
+  if (FLAG_pretenure_literals) {
+    if (IsFastDoubleElementsKind(kind)) {
+      flags = static_cast<HAllocate::Flags>(
+          flags | HAllocate::CAN_ALLOCATE_IN_OLD_DATA_SPACE);
+    } else {
+      flags = static_cast<HAllocate::Flags>(
+          flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
+    }
   }
   if (IsFastDoubleElementsKind(kind)) {
     flags = static_cast<HAllocate::Flags>(
@@ -1273,27 +1282,40 @@ HValue* HGraphBuilder::BuildAllocateElements(HValue* context,
   HValue* elements =
       AddInstruction(new(zone) HAllocate(context, total_size,
                                          HType::JSArray(), flags));
+  return elements;
+}
+
 
+void HGraphBuilder::BuildInitializeElements(HValue* elements,
+                                            ElementsKind kind,
+                                            HValue* capacity) {
+  Zone* zone = this->zone();
   Factory* factory = isolate()->factory();
   Handle<Map> map = IsFastDoubleElementsKind(kind)
       ? factory->fixed_double_array_map()
       : factory->fixed_array_map();
-  BuildStoreMap(elements, map, ast_id);
+  BuildStoreMap(elements, map);
 
   Handle<String> fixed_array_length_field_name = factory->length_field_string();
   HInstruction* store_length =
       new(zone) HStoreNamedField(elements, fixed_array_length_field_name,
                                  capacity, true, FixedArray::kLengthOffset);
   AddInstruction(store_length);
-  AddSimulate(ast_id, REMOVABLE_SIMULATE);
+}
 
-  return elements;
+
+HValue* HGraphBuilder::BuildAllocateAndInitializeElements(HValue* context,
+                                                          ElementsKind kind,
+                                                          HValue* capacity) {
+  HValue* new_elements =
+      BuildAllocateElements(context, kind, capacity);
+  BuildInitializeElements(new_elements, kind, capacity);
+  return new_elements;
 }
 
 
 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
-                                           HValue* map,
-                                           BailoutId id) {
+                                           HValue* map) {
   Zone* zone = this->zone();
   Factory* factory = isolate()->factory();
   Handle<String> map_field_name = factory->map_field_string();
@@ -1302,18 +1324,16 @@ HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
                                  true, JSObject::kMapOffset);
   store_map->SetGVNFlag(kChangesMaps);
   AddInstruction(store_map);
-  AddSimulate(id, REMOVABLE_SIMULATE);
   return store_map;
 }
 
 
 HInstruction* HGraphBuilder::BuildStoreMap(HValue* object,
-                                           Handle<Map> map,
-                                           BailoutId id) {
+                                           Handle<Map> map) {
   Zone* zone = this->zone();
   HValue* map_constant =
       AddInstruction(new(zone) HConstant(map, Representation::Tagged()));
-  return BuildStoreMap(object, map_constant, id);
+  return BuildStoreMap(object, map_constant);
 }
 
 
@@ -1372,7 +1392,7 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
   BuildNewSpaceArrayCheck(new_capacity, kind);
 
   HValue* new_elements =
-      BuildAllocateElements(context, kind, new_capacity);
+      BuildAllocateAndInitializeElements(context, kind, new_capacity);
 
   BuildCopyElements(context, elements, kind,
                     new_elements, kind,
@@ -1395,7 +1415,6 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* context,
                                               ElementsKind elements_kind,
                                               HValue* from,
                                               HValue* to) {
-  BailoutId ast_id = current_block()->last_environment()->previous_ast_id();
   // Fast elements kinds need to be initialized in case statements below cause
   // a garbage collection.
   Factory* factory = isolate()->factory();
@@ -1413,7 +1432,6 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* context,
   HValue* key = builder.BeginBody(from, to, Token::LT);
 
   AddInstruction(new(zone) HStoreKeyed(elements, key, hole, elements_kind));
-  AddSimulate(ast_id, REMOVABLE_SIMULATE);
 
   builder.EndBody();
 }
@@ -1426,7 +1444,6 @@ void HGraphBuilder::BuildCopyElements(HValue* context,
                                       ElementsKind to_elements_kind,
                                       HValue* length,
                                       HValue* capacity) {
-  BailoutId ast_id = environment()->previous_ast_id();
   bool pre_fill_with_holes =
       IsFastDoubleElementsKind(from_elements_kind) &&
       IsFastObjectElementsKind(to_elements_kind);
@@ -1450,7 +1467,6 @@ void HGraphBuilder::BuildCopyElements(HValue* context,
 
   AddInstruction(new(zone()) HStoreKeyed(to_elements, key, element,
                                          to_elements_kind));
-  AddSimulate(ast_id, REMOVABLE_SIMULATE);
 
   builder.EndBody();
 
@@ -1462,6 +1478,119 @@ void HGraphBuilder::BuildCopyElements(HValue* context,
 }
 
 
+HValue* HGraphBuilder::BuildCloneShallowArray(HContext* context,
+                                              HValue* boilerplate,
+                                              AllocationSiteMode mode,
+                                              ElementsKind kind,
+                                              int length) {
+  Zone* zone = this->zone();
+  Factory* factory = isolate()->factory();
+
+  NoObservableSideEffectsScope no_effects(this);
+
+  // All sizes here are multiples of kPointerSize.
+  int size = JSArray::kSize;
+  if (mode == TRACK_ALLOCATION_SITE) {
+    size += AllocationSiteInfo::kSize;
+  }
+  int elems_offset = size;
+  if (length > 0) {
+    size += IsFastDoubleElementsKind(kind)
+        ? FixedDoubleArray::SizeFor(length)
+        : FixedArray::SizeFor(length);
+  }
+
+  HAllocate::Flags allocate_flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
+  if (IsFastDoubleElementsKind(kind)) {
+    allocate_flags = static_cast<HAllocate::Flags>(
+        allocate_flags | HAllocate::ALLOCATE_DOUBLE_ALIGNED);
+  }
+
+  // Allocate both the JS array and the elements array in one big
+  // allocation. This avoids multiple limit checks.
+  HValue* size_in_bytes =
+      AddInstruction(new(zone) HConstant(size, Representation::Integer32()));
+  HInstruction* object =
+      AddInstruction(new(zone) HAllocate(context,
+                                         size_in_bytes,
+                                         HType::JSObject(),
+                                         allocate_flags));
+
+  // Copy the JS array part.
+  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
+    if ((i != JSArray::kElementsOffset) || (length == 0)) {
+      HInstruction* value =
+          AddInstruction(new(zone) HLoadNamedField(boilerplate, true, i));
+      if (i != JSArray::kMapOffset) {
+        AddInstruction(new(zone) HStoreNamedField(object,
+                                                  factory->empty_string(),
+                                                  value,
+                                                  true, i));
+      } else {
+        BuildStoreMap(object, value);
+      }
+    }
+  }
+
+  // Create an allocation site info if requested.
+  if (mode == TRACK_ALLOCATION_SITE) {
+    HValue* alloc_site =
+        AddInstruction(new(zone) HInnerAllocatedObject(object, JSArray::kSize));
+    Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map());
+    BuildStoreMap(alloc_site, alloc_site_map);
+    int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset;
+    AddInstruction(new(zone) HStoreNamedField(alloc_site,
+                                              factory->empty_string(),
+                                              boilerplate,
+                                              true, alloc_payload_offset));
+  }
+
+  if (length > 0) {
+    // Get hold of the elements array of the boilerplate and setup the
+    // elements pointer in the resulting object.
+    HValue* boilerplate_elements =
+        AddInstruction(new(zone) HLoadElements(boilerplate, NULL));
+    HValue* object_elements =
+        AddInstruction(new(zone) HInnerAllocatedObject(object, elems_offset));
+    AddInstruction(new(zone) HStoreNamedField(object,
+                                              factory->elements_field_string(),
+                                              object_elements,
+                                              true, JSObject::kElementsOffset));
+
+    // Copy the elements array header.
+    for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
+      HInstruction* value =
+          AddInstruction(new(zone) HLoadNamedField(boilerplate_elements,
+                                                   true, i));
+      AddInstruction(new(zone) HStoreNamedField(object_elements,
+                                                factory->empty_string(),
+                                                value,
+                                                true, i));
+    }
+
+    // Copy the elements array contents.
+    // TODO(mstarzinger): Teach HGraphBuilder::BuildCopyElements to unfold
+    // copying loops with constant length up to a given boundary and use this
+    // helper here instead.
+    for (int i = 0; i < length; i++) {
+      HValue* key_constant =
+          AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
+      HInstruction* value =
+          AddInstruction(new(zone) HLoadKeyed(boilerplate_elements,
+                                              key_constant,
+                                              NULL,
+                                              kind));
+      AddInstruction(new(zone) HStoreKeyed(object_elements,
+                                           key_constant,
+                                           value,
+                                           kind));
+    }
+  }
+
+  return object;
+}
+
+
 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info,
                                                TypeFeedbackOracle* oracle)
     : HGraphBuilder(info),
@@ -1568,6 +1697,19 @@ HBasicBlock* HGraph::CreateBasicBlock() {
 }
 
 
+void HGraph::FinalizeUniqueValueIds() {
+  AssertNoAllocation no_gc;
+  ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread());
+  for (int i = 0; i < blocks()->length(); ++i) {
+    for (HInstruction* instr = blocks()->at(i)->first();
+        instr != NULL;
+        instr = instr->next()) {
+      instr->FinalizeUniqueValueId();
+    }
+  }
+}
+
+
 void HGraph::Canonicalize() {
   if (!FLAG_use_canonicalizing) return;
   HPhase phase("H_Canonicalize", this);
@@ -2358,8 +2500,10 @@ HValueMap::HValueMap(Zone* zone, const HValueMap* other)
       array_(zone->NewArray<HValueMapListElement>(other->array_size_)),
       lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)),
       free_list_head_(other->free_list_head_) {
-  memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement));
-  memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
+  OS::MemCopy(
+      array_, other->array_, array_size_ * sizeof(HValueMapListElement));
+  OS::MemCopy(
+      lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
 }
 
 
@@ -2485,7 +2629,7 @@ void HValueMap::ResizeLists(int new_size, Zone* zone) {
   lists_ = new_lists;
 
   if (old_lists != NULL) {
-    memcpy(lists_, old_lists, old_size * sizeof(HValueMapListElement));
+    OS::MemCopy(lists_, old_lists, old_size * sizeof(HValueMapListElement));
   }
   for (int i = old_size; i < lists_size_; ++i) {
     lists_[i].next = free_list_head_;
@@ -2531,7 +2675,7 @@ HSideEffectMap::HSideEffectMap(HSideEffectMap* other) : count_(other->count_) {
 
 HSideEffectMap& HSideEffectMap::operator= (const HSideEffectMap& other) {
   if (this != &other) {
-    memcpy(data_, other.data_, kNumberOfTrackedSideEffects * kPointerSize);
+    OS::MemCopy(data_, other.data_, kNumberOfTrackedSideEffects * kPointerSize);
   }
   return *this;
 }
@@ -2829,7 +2973,7 @@ GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
   size_t string_len = strlen(underlying_buffer) + 1;
   ASSERT(string_len <= sizeof(underlying_buffer));
   char* result = new char[strlen(underlying_buffer) + 1];
-  memcpy(result, underlying_buffer, string_len);
+  OS::MemCopy(result, underlying_buffer, string_len);
   return SmartArrayPointer<char>(result);
 }
 
@@ -3295,10 +3439,11 @@ void HInferRepresentation::Analyze() {
 
 
 void HGraph::MergeRemovableSimulates() {
+  ZoneList<HSimulate*> mergelist(2, zone());
   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;
+    // Make sure the merge list is empty at the start of a block.
+    ASSERT(mergelist.is_empty());
     // 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;
@@ -3309,33 +3454,38 @@ void HGraph::MergeRemovableSimulates() {
         // 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);
+        // Simply remove all accumulated simulates without merging.  This
+        // is safe because simulates after instructions with side effects
+        // are never added to the merge list.
+        while (!mergelist.is_empty()) {
+          mergelist.RemoveLast()->DeleteAndReplaceWith(NULL);
         }
-        folding_candidate = NULL;
         continue;
       }
-      // If we have an HSimulate and a candidate, perform the folding.
+      // Skip the non-simulates and the first simulate.
       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()) {
+      if ((current_simulate->previous()->HasObservableSideEffects() &&
+           !current_simulate->next()->IsSimulate()) ||
+          !current_simulate->is_candidate_for_removal()) {
+        // This simulate is not suitable for folding.
+        // Fold the ones accumulated so far.
+        current_simulate->MergeWith(&mergelist);
         continue;
+      } else {
+        // Accumulate this simulate for folding later on.
+        mergelist.Add(current_simulate, zone());
       }
-      folding_candidate = current_simulate;
+    }
+
+    if (!mergelist.is_empty()) {
+      // Merge the accumulated simulates at the end of the block.
+      HSimulate* last = mergelist.RemoveLast();
+      last->MergeWith(&mergelist);
     }
   }
 }
@@ -4193,8 +4343,6 @@ bool HOptimizedGraphBuilder::BuildGraph() {
 void HGraph::GlobalValueNumbering() {
   // Perform common subexpression elimination and loop-invariant code motion.
   if (FLAG_use_gvn) {
-    // We use objects' raw addresses for identification, so they must not move.
-    Heap::RelocationLock relocation_lock(isolate()->heap());
     HPhase phase("H_Global value numbering", this);
     HGlobalValueNumberer gvn(this, info());
     bool removed_side_effects = gvn.Analyze();
@@ -5977,7 +6125,8 @@ static bool LookupSetter(Handle<Map> map,
 static bool IsFastLiteral(Handle<JSObject> boilerplate,
                           int max_depth,
                           int* max_properties,
-                          int* total_size) {
+                          int* data_size,
+                          int* pointer_size) {
   ASSERT(max_depth >= 0 && *max_properties >= 0);
   if (max_depth == 0) return false;
 
@@ -5986,7 +6135,7 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate,
   if (elements->length() > 0 &&
       elements->map() != isolate->heap()->fixed_cow_array_map()) {
     if (boilerplate->HasFastDoubleElements()) {
-      *total_size += FixedDoubleArray::SizeFor(elements->length());
+      *data_size += FixedDoubleArray::SizeFor(elements->length());
     } else if (boilerplate->HasFastObjectElements()) {
       Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
       int length = elements->length();
@@ -5998,12 +6147,13 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate,
           if (!IsFastLiteral(value_object,
                              max_depth - 1,
                              max_properties,
-                             total_size)) {
+                             data_size,
+                             pointer_size)) {
             return false;
           }
         }
       }
-      *total_size += FixedArray::SizeFor(length);
+      *pointer_size += FixedArray::SizeFor(length);
     } else {
       return false;
     }
@@ -6022,14 +6172,15 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate,
         if (!IsFastLiteral(value_object,
                            max_depth - 1,
                            max_properties,
-                           total_size)) {
+                           data_size,
+                           pointer_size)) {
           return false;
         }
       }
     }
   }
 
-  *total_size += boilerplate->map()->instance_size();
+  *pointer_size += boilerplate->map()->instance_size();
   return true;
 }
 
@@ -6043,34 +6194,41 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
   HInstruction* literal;
 
   // Check whether to use fast or slow deep-copying for boilerplate.
-  int total_size = 0;
-  int max_properties = HFastLiteral::kMaxLiteralProperties;
-  Handle<Object> boilerplate(closure->literals()->get(expr->literal_index()),
-                             isolate());
-  if (boilerplate->IsJSObject() &&
-      IsFastLiteral(Handle<JSObject>::cast(boilerplate),
-                    HFastLiteral::kMaxLiteralDepth,
+  int data_size = 0;
+  int pointer_size = 0;
+  int max_properties = kMaxFastLiteralProperties;
+  Handle<Object> original_boilerplate(closure->literals()->get(
+      expr->literal_index()), isolate());
+  if (original_boilerplate->IsJSObject() &&
+      IsFastLiteral(Handle<JSObject>::cast(original_boilerplate),
+                    kMaxFastLiteralDepth,
                     &max_properties,
-                    &total_size)) {
-    Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate);
-    literal = new(zone()) HFastLiteral(context,
-                                       boilerplate_object,
-                                       total_size,
-                                       expr->literal_index(),
-                                       expr->depth(),
-                                       DONT_TRACK_ALLOCATION_SITE);
+                    &data_size,
+                    &pointer_size)) {
+    Handle<JSObject> original_boilerplate_object =
+        Handle<JSObject>::cast(original_boilerplate);
+    Handle<JSObject> boilerplate_object =
+        DeepCopy(original_boilerplate_object);
+
+    literal = BuildFastLiteral(context,
+                               boilerplate_object,
+                               original_boilerplate_object,
+                               data_size,
+                               pointer_size,
+                               DONT_TRACK_ALLOCATION_SITE);
   } else {
-    literal = new(zone()) HObjectLiteral(context,
-                                         expr->constant_properties(),
-                                         expr->fast_elements(),
-                                         expr->literal_index(),
-                                         expr->depth(),
-                                         expr->has_function());
+    literal = AddInstruction(
+        new(zone()) HObjectLiteral(context,
+                                   expr->constant_properties(),
+                                   expr->fast_elements(),
+                                   expr->literal_index(),
+                                   expr->depth(),
+                                   expr->has_function()));
   }
 
   // The object is expected in the bailout environment during computation
   // of the property values and is the value of the entire expression.
-  PushAndAdd(literal);
+  Push(literal);
 
   expr->CalculateEmitStore(zone());
 
@@ -6167,9 +6325,10 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
     }
   }
 
-  Handle<JSObject> boilerplate = Handle<JSObject>::cast(raw_boilerplate);
+  Handle<JSObject> original_boilerplate_object =
+      Handle<JSObject>::cast(raw_boilerplate);
   ElementsKind boilerplate_elements_kind =
-      Handle<JSObject>::cast(boilerplate)->GetElementsKind();
+      Handle<JSObject>::cast(original_boilerplate_object)->GetElementsKind();
 
   // TODO(mvstanton): This heuristic is only a temporary solution.  In the
   // end, we want to quit creating allocation site info after a certain number
@@ -6178,33 +6337,38 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
       boilerplate_elements_kind);
 
   // Check whether to use fast or slow deep-copying for boilerplate.
-  int total_size = 0;
-  int max_properties = HFastLiteral::kMaxLiteralProperties;
-  if (IsFastLiteral(boilerplate,
-                    HFastLiteral::kMaxLiteralDepth,
+  int data_size = 0;
+  int pointer_size = 0;
+  int max_properties = kMaxFastLiteralProperties;
+  if (IsFastLiteral(original_boilerplate_object,
+                    kMaxFastLiteralDepth,
                     &max_properties,
-                    &total_size)) {
+                    &data_size,
+                    &pointer_size)) {
     if (mode == TRACK_ALLOCATION_SITE) {
-      total_size += AllocationSiteInfo::kSize;
-    }
-    literal = new(zone()) HFastLiteral(context,
-                                       boilerplate,
-                                       total_size,
-                                       expr->literal_index(),
-                                       expr->depth(),
-                                       mode);
+      pointer_size += AllocationSiteInfo::kSize;
+    }
+
+    Handle<JSObject> boilerplate_object = DeepCopy(original_boilerplate_object);
+    literal = BuildFastLiteral(context,
+                               boilerplate_object,
+                               original_boilerplate_object,
+                               data_size,
+                               pointer_size,
+                               mode);
   } else {
-    literal = new(zone()) HArrayLiteral(context,
-                                        boilerplate,
-                                        length,
-                                        expr->literal_index(),
-                                        expr->depth(),
-                                        mode);
+    literal = AddInstruction(
+                  new(zone()) HArrayLiteral(context,
+                                            original_boilerplate_object,
+                                            length,
+                                            expr->literal_index(),
+                                            expr->depth(),
+                                            mode));
   }
 
   // The array is expected in the bailout environment during computation
   // of the property values and is the value of the entire expression.
-  PushAndAdd(literal);
+  Push(literal);
 
   HLoadElements* elements = NULL;
 
@@ -6420,8 +6584,9 @@ bool HOptimizedGraphBuilder::HandlePolymorphicArrayLengthLoad(
   }
 
   AddInstruction(new(zone()) HCheckNonSmi(object));
+
   HInstruction* typecheck =
-    AddInstruction(HCheckInstanceType::NewIsJSArray(object, zone()));
+    AddInstruction(new(zone()) HCheckMaps(object, types, zone()));
   HInstruction* instr =
     HLoadNamedField::NewArrayLength(zone(), object, typecheck);
   instr->set_position(expr->position());
@@ -7113,8 +7278,10 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
     Handle<JSObject> holder(lookup.holder());
     Handle<Map> holder_map(holder->map());
     AddCheckMap(object, map);
-    HInstruction* holder_value = AddInstruction(
+    AddInstruction(
         new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
+    HValue* holder_value = AddInstruction(
+            new(zone()) HConstant(holder, Representation::Tagged()));
     return BuildLoadNamedField(holder_value, holder_map, &lookup);
   }
 
@@ -7990,8 +8157,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
   // Parse and allocate variables.
   CompilationInfo target_info(target, zone());
   Handle<SharedFunctionInfo> target_shared(target->shared());
-  if (!ParserApi::Parse(&target_info, kNoParsingFlags) ||
-      !Scope::Analyze(&target_info)) {
+  if (!Parser::Parse(&target_info) || !Scope::Analyze(&target_info)) {
     if (target_info.isolate()->has_pending_exception()) {
       // Parse or scope error, never optimize this function.
       SetStackOverflow();
@@ -9942,6 +10108,241 @@ HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
 }
 
 
+HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
+    HValue* context,
+    Handle<JSObject> boilerplate_object,
+    Handle<JSObject> original_boilerplate_object,
+    int data_size,
+    int pointer_size,
+    AllocationSiteMode mode) {
+  Zone* zone = this->zone();
+  int total_size = data_size + pointer_size;
+
+  NoObservableSideEffectsScope no_effects(this);
+
+  HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
+  // TODO(hpayer): add support for old data space
+  if (FLAG_pretenure_literals &&
+      isolate()->heap()->ShouldGloballyPretenure() &&
+      data_size == 0) {
+    flags = static_cast<HAllocate::Flags>(
+        flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
+  }
+
+  HValue* size_in_bytes =
+      AddInstruction(new(zone) HConstant(total_size,
+          Representation::Integer32()));
+  HInstruction* result =
+      AddInstruction(new(zone) HAllocate(context,
+                                         size_in_bytes,
+                                         HType::JSObject(),
+                                         flags));
+  int offset = 0;
+  BuildEmitDeepCopy(boilerplate_object, original_boilerplate_object, result,
+                    &offset, mode);
+  return result;
+}
+
+
+void HOptimizedGraphBuilder::BuildEmitDeepCopy(
+    Handle<JSObject> boilerplate_object,
+    Handle<JSObject> original_boilerplate_object,
+    HInstruction* target,
+    int* offset,
+    AllocationSiteMode mode) {
+  Zone* zone = this->zone();
+  Factory* factory = isolate()->factory();
+
+  HInstruction* original_boilerplate = AddInstruction(new(zone) HConstant(
+      original_boilerplate_object, Representation::Tagged()));
+
+  bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
+      boilerplate_object->map()->CanTrackAllocationSite();
+
+  // Only elements backing stores for non-COW arrays need to be copied.
+  Handle<FixedArrayBase> elements(boilerplate_object->elements());
+  Handle<FixedArrayBase> original_elements(
+      original_boilerplate_object->elements());
+  ElementsKind kind = boilerplate_object->map()->elements_kind();
+
+  // Increase the offset so that subsequent objects end up right after
+  // this object and its backing store.
+  int object_offset = *offset;
+  int object_size = boilerplate_object->map()->instance_size();
+  int elements_size = (elements->length() > 0 &&
+      elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
+          elements->Size() : 0;
+  int elements_offset = *offset + object_size;
+  int inobject_properties = boilerplate_object->map()->inobject_properties();
+  if (create_allocation_site_info) {
+    elements_offset += AllocationSiteInfo::kSize;
+    *offset += AllocationSiteInfo::kSize;
+  }
+
+  *offset += object_size + elements_size;
+
+  HValue* object_elements = BuildCopyObjectHeader(boilerplate_object, target,
+      object_offset, elements_offset, elements_size);
+
+  // Copy in-object properties.
+  HValue* object_properties =
+      AddInstruction(new(zone) HInnerAllocatedObject(target, object_offset));
+  for (int i = 0; i < inobject_properties; i++) {
+    Handle<Object> value =
+        Handle<Object>(boilerplate_object->InObjectPropertyAt(i),
+        isolate());
+    if (value->IsJSObject()) {
+      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
+      Handle<JSObject> original_value_object = Handle<JSObject>::cast(
+          Handle<Object>(original_boilerplate_object->InObjectPropertyAt(i),
+              isolate()));
+      HInstruction* value_instruction =
+          AddInstruction(new(zone) HInnerAllocatedObject(target, *offset));
+      AddInstruction(new(zone) HStoreNamedField(
+          object_properties, factory->unknown_field_string(), value_instruction,
+          true, boilerplate_object->GetInObjectPropertyOffset(i)));
+      BuildEmitDeepCopy(value_object, original_value_object, target,
+                        offset, DONT_TRACK_ALLOCATION_SITE);
+    } else {
+      HInstruction* value_instruction = AddInstruction(new(zone) HConstant(
+          value, Representation::Tagged()));
+      AddInstruction(new(zone) HStoreNamedField(
+          object_properties, factory->unknown_field_string(), value_instruction,
+          true, boilerplate_object->GetInObjectPropertyOffset(i)));
+    }
+  }
+
+  // Build Allocation Site Info if desired
+  if (create_allocation_site_info) {
+    HValue* alloc_site =
+        AddInstruction(new(zone) HInnerAllocatedObject(target, JSArray::kSize));
+    Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map());
+    BuildStoreMap(alloc_site, alloc_site_map);
+    int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset;
+    AddInstruction(new(zone) HStoreNamedField(alloc_site,
+                                              factory->payload_string(),
+                                              original_boilerplate,
+                                              true, alloc_payload_offset));
+  }
+
+  if (object_elements != NULL) {
+    HInstruction* boilerplate_elements = AddInstruction(new(zone) HConstant(
+        elements, Representation::Tagged()));
+
+    int elements_length = elements->length();
+    HValue* object_elements_length =
+        AddInstruction(new(zone) HConstant(
+            elements_length, Representation::Integer32()));
+
+    BuildInitializeElements(object_elements, kind, object_elements_length);
+
+    // Copy elements backing store content.
+    if (elements->IsFixedDoubleArray()) {
+      for (int i = 0; i < elements_length; i++) {
+        HValue* key_constant =
+            AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
+        HInstruction* value_instruction =
+            AddInstruction(new(zone) HLoadKeyed(
+                boilerplate_elements, key_constant, NULL, kind));
+        AddInstruction(new(zone) HStoreKeyed(
+                object_elements, key_constant, value_instruction, kind));
+      }
+    } else if (elements->IsFixedArray()) {
+      Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
+      Handle<FixedArray> original_fast_elements =
+          Handle<FixedArray>::cast(original_elements);
+      for (int i = 0; i < elements_length; i++) {
+        Handle<Object> value(fast_elements->get(i), isolate());
+        HValue* key_constant =
+            AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
+        if (value->IsJSObject()) {
+          Handle<JSObject> value_object = Handle<JSObject>::cast(value);
+          Handle<JSObject> original_value_object = Handle<JSObject>::cast(
+              Handle<Object>(original_fast_elements->get(i), isolate()));
+          HInstruction* value_instruction =
+              AddInstruction(new(zone) HInnerAllocatedObject(target, *offset));
+          AddInstruction(new(zone) HStoreKeyed(
+              object_elements, key_constant, value_instruction, kind));
+          BuildEmitDeepCopy(value_object, original_value_object, target,
+              offset, DONT_TRACK_ALLOCATION_SITE);
+        } else {
+          HInstruction* value_instruction =
+              AddInstruction(new(zone) HLoadKeyed(
+                  boilerplate_elements, key_constant, NULL, kind));
+          AddInstruction(new(zone) HStoreKeyed(
+              object_elements, key_constant, value_instruction, kind));
+        }
+      }
+    } else {
+      UNREACHABLE();
+    }
+  }
+}
+
+
+HValue* HOptimizedGraphBuilder::BuildCopyObjectHeader(
+    Handle<JSObject> boilerplate_object,
+    HInstruction* target,
+    int object_offset,
+    int elements_offset,
+    int elements_size) {
+  ASSERT(boilerplate_object->properties()->length() == 0);
+  Zone* zone = this->zone();
+  Factory* factory = isolate()->factory();
+  HValue* result = NULL;
+
+  HValue* object_header =
+      AddInstruction(new(zone) HInnerAllocatedObject(target, object_offset));
+  Handle<Map> boilerplate_object_map(boilerplate_object->map());
+  BuildStoreMap(object_header, boilerplate_object_map);
+
+  HInstruction* elements;
+  if (elements_size == 0) {
+    Handle<Object> elements_field =
+        Handle<Object>(boilerplate_object->elements(), isolate());
+    elements = AddInstruction(new(zone) HConstant(
+        elements_field, Representation::Tagged()));
+  } else {
+    elements = AddInstruction(new(zone) HInnerAllocatedObject(
+        target, elements_offset));
+    result = elements;
+  }
+  HInstruction* elements_store = AddInstruction(new(zone) HStoreNamedField(
+      object_header,
+      factory->elements_field_string(),
+      elements,
+      true, JSObject::kElementsOffset));
+  elements_store->SetGVNFlag(kChangesElementsPointer);
+
+  Handle<Object> properties_field =
+      Handle<Object>(boilerplate_object->properties(), isolate());
+  ASSERT(*properties_field == isolate()->heap()->empty_fixed_array());
+  HInstruction* properties = AddInstruction(new(zone) HConstant(
+      properties_field, Representation::None()));
+  AddInstruction(new(zone) HStoreNamedField(object_header,
+                                            factory->empty_string(),
+                                            properties,
+                                            true, JSObject::kPropertiesOffset));
+
+  if (boilerplate_object->IsJSArray()) {
+    Handle<JSArray> boilerplate_array =
+        Handle<JSArray>::cast(boilerplate_object);
+    Handle<Object> length_field =
+        Handle<Object>(boilerplate_array->length(), isolate());
+    HInstruction* length = AddInstruction(new(zone) HConstant(
+        length_field, Representation::None()));
+    HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField(
+        object_header,
+        factory->length_field_string(),
+        length,
+        true, JSArray::kLengthOffset));
+    length_store->SetGVNFlag(kChangesArrayLengths);
+  }
+
+  return result;
+}
+
+
 void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
   ASSERT(!HasStackOverflow());
   ASSERT(current_block() != NULL);
@@ -10583,7 +10984,13 @@ void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) {
 
 
 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
-  return Bailout("inlined runtime function: MathSqrt");
+  ASSERT(call->arguments()->length() == 1);
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* value = Pop();
+  HValue* context = environment()->LookupContext();
+  HInstruction* result =
+      HUnaryMathOperation::New(zone(), context, value, kMathSqrt);
+  return ast_context()->ReturnInstruction(result, call->id());
 }
 
 
index ef3679e..3dbca3c 100644 (file)
@@ -260,6 +260,7 @@ class HGraph: public ZoneObject {
   HBasicBlock* entry_block() const { return entry_block_; }
   HEnvironment* start_environment() const { return start_environment_; }
 
+  void FinalizeUniqueValueIds();
   void InitializeInferredTypes();
   void InsertTypeConversions();
   void MergeRemovableSimulates();
@@ -865,7 +866,10 @@ class FunctionState {
 class HGraphBuilder {
  public:
   explicit HGraphBuilder(CompilationInfo* info)
-      : info_(info), graph_(NULL), current_block_(NULL) {}
+      : info_(info),
+        graph_(NULL),
+        current_block_(NULL),
+        no_side_effects_scope_count_(0) {}
   virtual ~HGraphBuilder() {}
 
   HBasicBlock* current_block() const { return current_block_; }
@@ -891,6 +895,14 @@ class HGraphBuilder {
 
   HReturn* AddReturn(HValue* value);
 
+  void IncrementInNoSideEffectsScope() {
+    no_side_effects_scope_count_++;
+  }
+
+  void DecrementInNoSideEffectsScope() {
+    no_side_effects_scope_count_--;
+  }
+
  protected:
   virtual bool BuildGraph() = 0;
 
@@ -939,8 +951,8 @@ class HGraphBuilder {
       KeyedAccessStoreMode store_mode,
       Representation checked_index_representation = Representation::None());
 
-  HInstruction* BuildStoreMap(HValue* object, HValue* map, BailoutId id);
-  HInstruction* BuildStoreMap(HValue* object, Handle<Map> map, BailoutId id);
+  HInstruction* BuildStoreMap(HValue* object, HValue* map);
+  HInstruction* BuildStoreMap(HValue* object, Handle<Map> map);
 
   class CheckBuilder {
    public:
@@ -1032,6 +1044,20 @@ class HGraphBuilder {
     bool finished_;
   };
 
+  class NoObservableSideEffectsScope {
+   public:
+    explicit NoObservableSideEffectsScope(HGraphBuilder* builder) :
+        builder_(builder) {
+      builder_->IncrementInNoSideEffectsScope();
+    }
+    ~NoObservableSideEffectsScope() {
+      builder_->DecrementInNoSideEffectsScope();
+    }
+
+   private:
+    HGraphBuilder* builder_;
+  };
+
   HValue* BuildNewElementsCapacity(HValue* context,
                                    HValue* old_capacity);
 
@@ -1042,6 +1068,14 @@ class HGraphBuilder {
                                 ElementsKind kind,
                                 HValue* capacity);
 
+  void BuildInitializeElements(HValue* elements,
+                               ElementsKind kind,
+                               HValue* capacity);
+
+  HValue* BuildAllocateAndInitializeElements(HValue* context,
+                                             ElementsKind kind,
+                                             HValue* capacity);
+
   HValue* BuildGrowElementsCapacity(HValue* object,
                                     HValue* elements,
                                     ElementsKind kind,
@@ -1062,11 +1096,18 @@ class HGraphBuilder {
                          HValue* length,
                          HValue* capacity);
 
+  HValue* BuildCloneShallowArray(HContext* context,
+                                 HValue* boilerplate,
+                                 AllocationSiteMode mode,
+                                 ElementsKind kind,
+                                 int length);
+
  private:
   HGraphBuilder();
   CompilationInfo* info_;
   HGraph* graph_;
   HBasicBlock* current_block_;
+  int no_side_effects_scope_count_;
 };
 
 
@@ -1183,6 +1224,11 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
   static const int kUnlimitedMaxInlinedNodes = 10000;
   static const int kUnlimitedMaxInlinedNodesCumulative = 10000;
 
+  // Maximum depth and total number of elements and properties for literal
+  // graphs to be considered for fast deep-copying.
+  static const int kMaxFastLiteralDepth = 3;
+  static const int kMaxFastLiteralProperties = 8;
+
   // Simple accessors.
   void set_function_state(FunctionState* state) { function_state_ = state; }
 
@@ -1459,6 +1505,26 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
 
   HInstruction* BuildThisFunction();
 
+  HInstruction* BuildFastLiteral(HValue* context,
+                                 Handle<JSObject> boilerplate_object,
+                                 Handle<JSObject> original_boilerplate_object,
+                                 int data_size,
+                                 int pointer_size,
+                                 AllocationSiteMode mode);
+
+  void BuildEmitDeepCopy(Handle<JSObject> boilerplat_object,
+                         Handle<JSObject> object,
+                         HInstruction* result,
+                         int* offset,
+                         AllocationSiteMode mode);
+
+  MUST_USE_RESULT HValue* BuildCopyObjectHeader(
+      Handle<JSObject> boilerplat_object,
+      HInstruction* target,
+      int object_offset,
+      int elements_offset,
+      int elements_size);
+
   void AddCheckPrototypeMaps(Handle<JSObject> holder,
                              Handle<Map> receiver_map);
 
index b48906e..32fe6a9 100644 (file)
@@ -2556,9 +2556,9 @@ void Assembler::GrowBuffer() {
   // Copy the data.
   int pc_delta = desc.buffer - buffer_;
   int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
-  memmove(desc.buffer, buffer_, desc.instr_size);
-  memmove(rc_delta + reloc_info_writer.pos(),
-          reloc_info_writer.pos(), desc.reloc_size);
+  OS::MemMove(desc.buffer, buffer_, desc.instr_size);
+  OS::MemMove(rc_delta + reloc_info_writer.pos(),
+              reloc_info_writer.pos(), desc.reloc_size);
 
   // Switch buffers.
   if (isolate()->assembler_spare_buffer() == NULL &&
index a3da9af..d1c1fbf 100644 (file)
@@ -1026,6 +1026,13 @@ class Assembler : public AssemblerBase {
   void movdqa(const Operand& dst, XMMRegister src);
   void movdqu(XMMRegister dst, const Operand& src);
   void movdqu(const Operand& dst, XMMRegister src);
+  void movdq(bool aligned, XMMRegister dst, const Operand& src) {
+    if (aligned) {
+      movdqa(dst, src);
+    } else {
+      movdqu(dst, src);
+    }
+  }
 
   // Use either movsd or movlpd.
   void movdbl(XMMRegister dst, const Operand& src);
index e861db3..08bc227 100644 (file)
@@ -1810,25 +1810,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
 
 
 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
-  // Get the loop depth of the stack guard check. This is recorded in
-  // a test(eax, depth) instruction right after the call.
-  Label stack_check;
-  __ mov(ebx, Operand(esp, 0));  // return address
-  if (FLAG_debug_code) {
-    __ cmpb(Operand(ebx, 0), Assembler::kTestAlByte);
-    __ Assert(equal, "test eax instruction not found after loop stack check");
-  }
-  __ movzx_b(ebx, Operand(ebx, 1));  // depth
-
-  // Get the loop nesting level at which we allow OSR from the
-  // unoptimized code and check if we want to do OSR yet. If not we
-  // should perform a stack guard check so we can get interrupts while
-  // waiting for on-stack replacement.
   __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
-  __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
-  __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset));
-  __ cmpb(ebx, FieldOperand(ecx, Code::kAllowOSRAtLoopNestingLevelOffset));
-  __ j(greater, &stack_check);
 
   // Pass the function to optimize as the argument to the on-stack
   // replacement runtime function.
@@ -1845,23 +1827,6 @@ void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
   __ j(not_equal, &skip, Label::kNear);
   __ ret(0);
 
-  // Insert a stack guard check so that if we decide not to perform
-  // on-stack replacement right away, the function calling this stub can
-  // still be interrupted.
-  __ bind(&stack_check);
-  Label ok;
-  ExternalReference stack_limit =
-      ExternalReference::address_of_stack_limit(masm->isolate());
-  __ cmp(esp, Operand::StaticVariable(stack_limit));
-  __ j(above_equal, &ok, Label::kNear);
-  StackCheckStub stub;
-  __ TailCallStub(&stub);
-  if (FLAG_debug_code) {
-    __ Abort("Unreachable code: returned from tail call.");
-  }
-  __ bind(&ok);
-  __ ret(0);
-
   __ bind(&skip);
   // Untag the AST id and push it on the stack.
   __ SmiUntag(eax);
index 9b77c50..05dceb7 100644 (file)
@@ -30,6 +30,7 @@
 #if defined(V8_TARGET_ARCH_IA32)
 
 #include "bootstrapper.h"
+#include "builtins-decls.h"
 #include "code-stubs.h"
 #include "isolate.h"
 #include "jsregexp.h"
@@ -43,6 +44,18 @@ namespace v8 {
 namespace internal {
 
 
+void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { eax, ebx, ecx };
+  descriptor->register_param_count_ = 3;
+  descriptor->register_params_ = registers;
+  descriptor->stack_parameter_count_ = NULL;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
+}
+
+
 void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
@@ -163,9 +176,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
   // Get the function info from the stack.
   __ mov(edx, Operand(esp, 1 * kPointerSize));
 
-  int map_index = (language_mode_ == CLASSIC_MODE)
-      ? Context::FUNCTION_MAP_INDEX
-      : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
+  int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
 
   // Compute the function map in the current native context and set that
   // as the map of the allocated object.
@@ -393,168 +404,6 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
 }
 
 
-static void GenerateFastCloneShallowArrayCommon(
-    MacroAssembler* masm,
-    int length,
-    FastCloneShallowArrayStub::Mode mode,
-    AllocationSiteMode allocation_site_mode,
-    Label* fail) {
-  // Registers on entry:
-  //
-  // ecx: boilerplate literal array.
-  ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
-
-  // All sizes here are multiples of kPointerSize.
-  int elements_size = 0;
-  if (length > 0) {
-    elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
-        ? FixedDoubleArray::SizeFor(length)
-        : FixedArray::SizeFor(length);
-  }
-  int size = JSArray::kSize;
-  int allocation_info_start = size;
-  if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-    size += AllocationSiteInfo::kSize;
-  }
-  size += elements_size;
-
-  // Allocate both the JS array and the elements array in one big
-  // allocation. This avoids multiple limit checks.
-  AllocationFlags flags = TAG_OBJECT;
-  if (mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS) {
-    flags = static_cast<AllocationFlags>(DOUBLE_ALIGNMENT | flags);
-  }
-  __ Allocate(size, eax, ebx, edx, fail, flags);
-
-  if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-    __ mov(FieldOperand(eax, allocation_info_start),
-           Immediate(Handle<Map>(masm->isolate()->heap()->
-                                 allocation_site_info_map())));
-    __ mov(FieldOperand(eax, allocation_info_start + kPointerSize), ecx);
-  }
-
-  // Copy the JS array part.
-  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
-    if ((i != JSArray::kElementsOffset) || (length == 0)) {
-      __ mov(ebx, FieldOperand(ecx, i));
-      __ mov(FieldOperand(eax, i), ebx);
-    }
-  }
-
-  if (length > 0) {
-    // Get hold of the elements array of the boilerplate and setup the
-    // elements pointer in the resulting object.
-    __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
-    if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-      __ lea(edx, Operand(eax, JSArray::kSize + AllocationSiteInfo::kSize));
-    } else {
-      __ lea(edx, Operand(eax, JSArray::kSize));
-    }
-    __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
-
-    // Copy the elements array.
-    if (mode == FastCloneShallowArrayStub::CLONE_ELEMENTS) {
-      for (int i = 0; i < elements_size; i += kPointerSize) {
-        __ mov(ebx, FieldOperand(ecx, i));
-        __ mov(FieldOperand(edx, i), ebx);
-      }
-    } else {
-      ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS);
-      int i;
-      for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
-        __ mov(ebx, FieldOperand(ecx, i));
-        __ mov(FieldOperand(edx, i), ebx);
-      }
-      while (i < elements_size) {
-        __ fld_d(FieldOperand(ecx, i));
-        __ fstp_d(FieldOperand(edx, i));
-        i += kDoubleSize;
-      }
-      ASSERT(i == elements_size);
-    }
-  }
-}
-
-
-void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
-  // Stack layout on entry:
-  //
-  // [esp + kPointerSize]: constant elements.
-  // [esp + (2 * kPointerSize)]: literal index.
-  // [esp + (3 * kPointerSize)]: literals array.
-
-  // Load boilerplate object into ecx and check if we need to create a
-  // boilerplate.
-  __ mov(ecx, Operand(esp, 3 * kPointerSize));
-  __ mov(eax, Operand(esp, 2 * kPointerSize));
-  STATIC_ASSERT(kPointerSize == 4);
-  STATIC_ASSERT(kSmiTagSize == 1);
-  STATIC_ASSERT(kSmiTag == 0);
-  __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size,
-                           FixedArray::kHeaderSize));
-  Factory* factory = masm->isolate()->factory();
-  __ cmp(ecx, factory->undefined_value());
-  Label slow_case;
-  __ j(equal, &slow_case);
-
-  FastCloneShallowArrayStub::Mode mode = mode_;
-  // ecx is boilerplate object.
-  if (mode == CLONE_ANY_ELEMENTS) {
-    Label double_elements, check_fast_elements;
-    __ mov(ebx, FieldOperand(ecx, JSArray::kElementsOffset));
-    __ CheckMap(ebx, factory->fixed_cow_array_map(),
-                &check_fast_elements, DONT_DO_SMI_CHECK);
-    GenerateFastCloneShallowArrayCommon(masm, 0, COPY_ON_WRITE_ELEMENTS,
-                                        allocation_site_mode_,
-                                        &slow_case);
-    __ ret(3 * kPointerSize);
-
-    __ bind(&check_fast_elements);
-    __ CheckMap(ebx, factory->fixed_array_map(),
-                &double_elements, DONT_DO_SMI_CHECK);
-    GenerateFastCloneShallowArrayCommon(masm, length_, CLONE_ELEMENTS,
-                                        allocation_site_mode_,
-                                        &slow_case);
-    __ ret(3 * kPointerSize);
-
-    __ bind(&double_elements);
-    mode = CLONE_DOUBLE_ELEMENTS;
-    // Fall through to generate the code to handle double elements.
-  }
-
-  if (FLAG_debug_code) {
-    const char* message;
-    Handle<Map> expected_map;
-    if (mode == CLONE_ELEMENTS) {
-      message = "Expected (writable) fixed array";
-      expected_map = factory->fixed_array_map();
-    } else if (mode == CLONE_DOUBLE_ELEMENTS) {
-      message = "Expected (writable) fixed double array";
-      expected_map = factory->fixed_double_array_map();
-    } else {
-      ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
-      message = "Expected copy-on-write fixed array";
-      expected_map = factory->fixed_cow_array_map();
-    }
-    __ push(ecx);
-    __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
-    __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map);
-    __ Assert(equal, message);
-    __ pop(ecx);
-  }
-
-  GenerateFastCloneShallowArrayCommon(masm, length_, mode,
-                                      allocation_site_mode_,
-                                      &slow_case);
-
-  // Return and remove the on-stack parameters.
-  __ ret(3 * kPointerSize);
-
-  __ bind(&slow_case);
-  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
-}
-
-
 // The stub expects its argument on the stack and returns its result in tos_:
 // zero for false, and a non-zero value for true.
 void ToBooleanStub::Generate(MacroAssembler* masm) {
@@ -5076,6 +4925,7 @@ bool CEntryStub::IsPregenerated() {
 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   CEntryStub::GenerateAheadOfTime(isolate);
   StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+  StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   // It is important that the store buffer overflow stubs are generated first.
   RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
 }
@@ -5215,8 +5065,13 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   // Special handling of out of memory exceptions.
   JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
 
-  // Retrieve the pending exception and clear the variable.
+  // Retrieve the pending exception.
   __ mov(eax, Operand::StaticVariable(pending_exception_address));
+
+  // See if we just retrieved an OOM exception.
+  JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
+
+  // Clear the pending exception.
   __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
   __ mov(Operand::StaticVariable(pending_exception_address), edx);
 
@@ -7786,9 +7641,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
 
 
 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
-  ASSERT(!Serializer::enabled());
-  bool save_fp_regs = CpuFeatures::IsSupported(SSE2);
-  CEntryStub ces(1, save_fp_regs ? kSaveFPRegs : kDontSaveFPRegs);
+  CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
   __ call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
   int parameter_count_offset =
       StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
index 550c83d..caf808b 100644 (file)
@@ -173,21 +173,94 @@ UnaryMathFunction CreateSqrtFunction() {
 }
 
 
-static void MemCopyWrapper(void* dest, const void* src, size_t size) {
-  memcpy(dest, src, size);
+// Helper functions for CreateMemMoveFunction.
+#undef __
+#define __ ACCESS_MASM(masm)
+
+// Keep around global pointers to these objects so that Valgrind won't complain.
+static size_t* medium_handlers = NULL;
+static size_t* small_handlers = NULL;
+
+
+enum Direction { FORWARD, BACKWARD };
+enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
+
+// Expects registers:
+// esi - source, aligned if alignment == ALIGNED
+// edi - destination, always aligned
+// ecx - count (copy size in bytes)
+// edx - loop count (number of 64 byte chunks)
+void MemMoveEmitMainLoop(MacroAssembler* masm,
+                         Label* move_last_15,
+                         Direction direction,
+                         Alignment alignment) {
+  Register src = esi;
+  Register dst = edi;
+  Register count = ecx;
+  Register loop_count = edx;
+  Label loop, move_last_31, move_last_63;
+  __ cmp(loop_count, 0);
+  __ j(equal, &move_last_63);
+  __ bind(&loop);
+  // Main loop. Copy in 64 byte chunks.
+  if (direction == BACKWARD) __ sub(src, Immediate(0x40));
+  __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
+  __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
+  __ movdq(alignment == MOVE_ALIGNED, xmm2, Operand(src, 0x20));
+  __ movdq(alignment == MOVE_ALIGNED, xmm3, Operand(src, 0x30));
+  if (direction == FORWARD) __ add(src, Immediate(0x40));
+  if (direction == BACKWARD) __ sub(dst, Immediate(0x40));
+  __ movdqa(Operand(dst, 0x00), xmm0);
+  __ movdqa(Operand(dst, 0x10), xmm1);
+  __ movdqa(Operand(dst, 0x20), xmm2);
+  __ movdqa(Operand(dst, 0x30), xmm3);
+  if (direction == FORWARD) __ add(dst, Immediate(0x40));
+  __ dec(loop_count);
+  __ j(not_zero, &loop);
+  // At most 63 bytes left to copy.
+  __ bind(&move_last_63);
+  __ test(count, Immediate(0x20));
+  __ j(zero, &move_last_31);
+  if (direction == BACKWARD) __ sub(src, Immediate(0x20));
+  __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
+  __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
+  if (direction == FORWARD) __ add(src, Immediate(0x20));
+  if (direction == BACKWARD) __ sub(dst, Immediate(0x20));
+  __ movdqa(Operand(dst, 0x00), xmm0);
+  __ movdqa(Operand(dst, 0x10), xmm1);
+  if (direction == FORWARD) __ add(dst, Immediate(0x20));
+  // At most 31 bytes left to copy.
+  __ bind(&move_last_31);
+  __ test(count, Immediate(0x10));
+  __ j(zero, move_last_15);
+  if (direction == BACKWARD) __ sub(src, Immediate(0x10));
+  __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0));
+  if (direction == FORWARD) __ add(src, Immediate(0x10));
+  if (direction == BACKWARD) __ sub(dst, Immediate(0x10));
+  __ movdqa(Operand(dst, 0), xmm0);
+  if (direction == FORWARD) __ add(dst, Immediate(0x10));
+}
+
+
+void MemMoveEmitPopAndReturn(MacroAssembler* masm) {
+  __ pop(esi);
+  __ pop(edi);
+  __ ret(0);
 }
 
 
-OS::MemCopyFunction CreateMemCopyFunction() {
+#undef __
+#define __ masm.
+
+
+OS::MemMoveFunction CreateMemMoveFunction() {
   size_t actual_size;
   // Allocate buffer in executable space.
-  byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
-                                                 &actual_size,
-                                                 true));
-  if (buffer == NULL) return &MemCopyWrapper;
+  byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
+  if (buffer == NULL) return NULL;
   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
 
-  // Generated code is put into a fixed, unmovable, buffer, and not into
+  // Generated code is put into a fixed, unmovable buffer, and not into
   // the V8 heap. We can't, and don't, refer to any relocatable addresses
   // (e.g. the JavaScript nan-object).
 
@@ -203,185 +276,369 @@ OS::MemCopyFunction CreateMemCopyFunction() {
   const int kSourceOffset = 2 * kPointerSize;
   const int kSizeOffset = 3 * kPointerSize;
 
+  // When copying up to this many bytes, use special "small" handlers.
+  const size_t kSmallCopySize = 8;
+  // When copying up to this many bytes, use special "medium" handlers.
+  const size_t kMediumCopySize = 63;
+  // When non-overlapping region of src and dst is less than this,
+  // use a more careful implementation (slightly slower).
+  const size_t kMinMoveDistance = 16;
+  // Note that these values are dictated by the implementation below,
+  // do not just change them and hope things will work!
+
   int stack_offset = 0;  // Update if we change the stack height.
 
-  if (FLAG_debug_code) {
-    __ cmp(Operand(esp, kSizeOffset + stack_offset),
-           Immediate(OS::kMinComplexMemCopy));
-    Label ok;
-    __ j(greater_equal, &ok);
-    __ int3();
-    __ bind(&ok);
-  }
+  Label backward, backward_much_overlap;
+  Label forward_much_overlap, small_size, medium_size, pop_and_return;
+  __ push(edi);
+  __ push(esi);
+  stack_offset += 2 * kPointerSize;
+  Register dst = edi;
+  Register src = esi;
+  Register count = ecx;
+  Register loop_count = edx;
+  __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
+  __ mov(src, Operand(esp, stack_offset + kSourceOffset));
+  __ mov(count, Operand(esp, stack_offset + kSizeOffset));
+
+  __ cmp(dst, src);
+  __ j(equal, &pop_and_return);
+
   if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope enable(&masm, SSE2);
-    __ push(edi);
-    __ push(esi);
-    stack_offset += 2 * kPointerSize;
-    Register dst = edi;
-    Register src = esi;
-    Register count = ecx;
-    __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
-    __ mov(src, Operand(esp, stack_offset + kSourceOffset));
-    __ mov(count, Operand(esp, stack_offset + kSizeOffset));
-
-
-    __ movdqu(xmm0, Operand(src, 0));
-    __ movdqu(Operand(dst, 0), xmm0);
-    __ mov(edx, dst);
-    __ and_(edx, 0xF);
-    __ neg(edx);
-    __ add(edx, Immediate(16));
-    __ add(dst, edx);
-    __ add(src, edx);
-    __ sub(count, edx);
-
-    // edi is now aligned. Check if esi is also aligned.
-    Label unaligned_source;
-    __ test(src, Immediate(0x0F));
-    __ j(not_zero, &unaligned_source);
+    CpuFeatureScope sse2_scope(&masm, SSE2);
+    __ prefetch(Operand(src, 0), 1);
+    __ cmp(count, kSmallCopySize);
+    __ j(below_equal, &small_size);
+    __ cmp(count, kMediumCopySize);
+    __ j(below_equal, &medium_size);
+    __ cmp(dst, src);
+    __ j(above, &backward);
+
     {
+      // |dst| is a lower address than |src|. Copy front-to-back.
+      Label unaligned_source, move_last_15, skip_last_move;
+      __ mov(eax, src);
+      __ sub(eax, dst);
+      __ cmp(eax, kMinMoveDistance);
+      __ j(below, &forward_much_overlap);
+      // Copy first 16 bytes.
+      __ movdqu(xmm0, Operand(src, 0));
+      __ movdqu(Operand(dst, 0), xmm0);
+      // Determine distance to alignment: 16 - (dst & 0xF).
+      __ mov(edx, dst);
+      __ and_(edx, 0xF);
+      __ neg(edx);
+      __ add(edx, Immediate(16));
+      __ add(dst, edx);
+      __ add(src, edx);
+      __ sub(count, edx);
+      // dst is now aligned. Main copy loop.
+      __ mov(loop_count, count);
+      __ shr(loop_count, 6);
+      // Check if src is also aligned.
+      __ test(src, Immediate(0xF));
+      __ j(not_zero, &unaligned_source);
       // Copy loop for aligned source and destination.
-      __ mov(edx, count);
-      Register loop_count = ecx;
-      Register count = edx;
-      __ shr(loop_count, 5);
-      {
-        // Main copy loop.
-        Label loop;
-        __ bind(&loop);
-        __ prefetch(Operand(src, 0x20), 1);
-        __ movdqa(xmm0, Operand(src, 0x00));
-        __ movdqa(xmm1, Operand(src, 0x10));
-        __ add(src, Immediate(0x20));
-
-        __ movdqa(Operand(dst, 0x00), xmm0);
-        __ movdqa(Operand(dst, 0x10), xmm1);
-        __ add(dst, Immediate(0x20));
-
-        __ dec(loop_count);
-        __ j(not_zero, &loop);
-      }
-
-      // At most 31 bytes to copy.
-      Label move_less_16;
-      __ test(count, Immediate(0x10));
-      __ j(zero, &move_less_16);
-      __ movdqa(xmm0, Operand(src, 0));
-      __ add(src, Immediate(0x10));
-      __ movdqa(Operand(dst, 0), xmm0);
-      __ add(dst, Immediate(0x10));
-      __ bind(&move_less_16);
-
+      MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
       // At most 15 bytes to copy. Copy 16 bytes at end of string.
+      __ bind(&move_last_15);
       __ and_(count, 0xF);
+      __ j(zero, &skip_last_move, Label::kNear);
       __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
       __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
+      __ bind(&skip_last_move);
+      MemMoveEmitPopAndReturn(&masm);
 
-      __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
-      __ pop(esi);
-      __ pop(edi);
-      __ ret(0);
-    }
-    __ Align(16);
-    {
       // Copy loop for unaligned source and aligned destination.
-      // If source is not aligned, we can't read it as efficiently.
       __ bind(&unaligned_source);
-      __ mov(edx, ecx);
-      Register loop_count = ecx;
-      Register count = edx;
-      __ shr(loop_count, 5);
-      {
-        // Main copy loop
-        Label loop;
-        __ bind(&loop);
-        __ prefetch(Operand(src, 0x20), 1);
-        __ movdqu(xmm0, Operand(src, 0x00));
-        __ movdqu(xmm1, Operand(src, 0x10));
-        __ add(src, Immediate(0x20));
-
-        __ movdqa(Operand(dst, 0x00), xmm0);
-        __ movdqa(Operand(dst, 0x10), xmm1);
-        __ add(dst, Immediate(0x20));
-
-        __ dec(loop_count);
-        __ j(not_zero, &loop);
-      }
+      MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
+      __ jmp(&move_last_15);
+
+      // Less than kMinMoveDistance offset between dst and src.
+      Label loop_until_aligned, last_15_much_overlap;
+      __ bind(&loop_until_aligned);
+      __ mov_b(eax, Operand(src, 0));
+      __ inc(src);
+      __ mov_b(Operand(dst, 0), eax);
+      __ inc(dst);
+      __ dec(count);
+      __ bind(&forward_much_overlap);  // Entry point into this block.
+      __ test(dst, Immediate(0xF));
+      __ j(not_zero, &loop_until_aligned);
+      // dst is now aligned, src can't be. Main copy loop.
+      __ mov(loop_count, count);
+      __ shr(loop_count, 6);
+      MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
+                          FORWARD, MOVE_UNALIGNED);
+      __ bind(&last_15_much_overlap);
+      __ and_(count, 0xF);
+      __ j(zero, &pop_and_return);
+      __ cmp(count, kSmallCopySize);
+      __ j(below_equal, &small_size);
+      __ jmp(&medium_size);
+    }
 
-      // At most 31 bytes to copy.
-      Label move_less_16;
-      __ test(count, Immediate(0x10));
-      __ j(zero, &move_less_16);
+    {
+      // |dst| is a higher address than |src|. Copy backwards.
+      Label unaligned_source, move_first_15, skip_last_move;
+      __ bind(&backward);
+      // |dst| and |src| always point to the end of what's left to copy.
+      __ add(dst, count);
+      __ add(src, count);
+      __ mov(eax, dst);
+      __ sub(eax, src);
+      __ cmp(eax, kMinMoveDistance);
+      __ j(below, &backward_much_overlap);
+      // Copy last 16 bytes.
+      __ movdqu(xmm0, Operand(src, -0x10));
+      __ movdqu(Operand(dst, -0x10), xmm0);
+      // Find distance to alignment: dst & 0xF
+      __ mov(edx, dst);
+      __ and_(edx, 0xF);
+      __ sub(dst, edx);
+      __ sub(src, edx);
+      __ sub(count, edx);
+      // dst is now aligned. Main copy loop.
+      __ mov(loop_count, count);
+      __ shr(loop_count, 6);
+      // Check if src is also aligned.
+      __ test(src, Immediate(0xF));
+      __ j(not_zero, &unaligned_source);
+      // Copy loop for aligned source and destination.
+      MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
+      // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
+      __ bind(&move_first_15);
+      __ and_(count, 0xF);
+      __ j(zero, &skip_last_move, Label::kNear);
+      __ sub(src, count);
+      __ sub(dst, count);
       __ movdqu(xmm0, Operand(src, 0));
-      __ add(src, Immediate(0x10));
-      __ movdqa(Operand(dst, 0), xmm0);
-      __ add(dst, Immediate(0x10));
-      __ bind(&move_less_16);
-
-      // At most 15 bytes to copy. Copy 16 bytes at end of string.
-      __ and_(count, 0x0F);
-      __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
-      __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
+      __ movdqu(Operand(dst, 0), xmm0);
+      __ bind(&skip_last_move);
+      MemMoveEmitPopAndReturn(&masm);
 
-      __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
-      __ pop(esi);
-      __ pop(edi);
-      __ ret(0);
+      // Copy loop for unaligned source and aligned destination.
+      __ bind(&unaligned_source);
+      MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED);
+      __ jmp(&move_first_15);
+
+      // Less than kMinMoveDistance offset between dst and src.
+      Label loop_until_aligned, first_15_much_overlap;
+      __ bind(&loop_until_aligned);
+      __ dec(src);
+      __ dec(dst);
+      __ mov_b(eax, Operand(src, 0));
+      __ mov_b(Operand(dst, 0), eax);
+      __ dec(count);
+      __ bind(&backward_much_overlap);  // Entry point into this block.
+      __ test(dst, Immediate(0xF));
+      __ j(not_zero, &loop_until_aligned);
+      // dst is now aligned, src can't be. Main copy loop.
+      __ mov(loop_count, count);
+      __ shr(loop_count, 6);
+      MemMoveEmitMainLoop(&masm, &first_15_much_overlap,
+                          BACKWARD, MOVE_UNALIGNED);
+      __ bind(&first_15_much_overlap);
+      __ and_(count, 0xF);
+      __ j(zero, &pop_and_return);
+      // Small/medium handlers expect dst/src to point to the beginning.
+      __ sub(dst, count);
+      __ sub(src, count);
+      __ cmp(count, kSmallCopySize);
+      __ j(below_equal, &small_size);
+      __ jmp(&medium_size);
+    }
+    {
+      // Special handlers for 9 <= copy_size < 64. No assumptions about
+      // alignment or move distance, so all reads must be unaligned and
+      // must happen before any writes.
+      Label f9_16, f17_32, f33_48, f49_63;
+
+      __ bind(&f9_16);
+      __ movdbl(xmm0, Operand(src, 0));
+      __ movdbl(xmm1, Operand(src, count, times_1, -8));
+      __ movdbl(Operand(dst, 0), xmm0);
+      __ movdbl(Operand(dst, count, times_1, -8), xmm1);
+      MemMoveEmitPopAndReturn(&masm);
+
+      __ bind(&f17_32);
+      __ movdqu(xmm0, Operand(src, 0));
+      __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
+      __ movdqu(Operand(dst, 0x00), xmm0);
+      __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
+      MemMoveEmitPopAndReturn(&masm);
+
+      __ bind(&f33_48);
+      __ movdqu(xmm0, Operand(src, 0x00));
+      __ movdqu(xmm1, Operand(src, 0x10));
+      __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
+      __ movdqu(Operand(dst, 0x00), xmm0);
+      __ movdqu(Operand(dst, 0x10), xmm1);
+      __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
+      MemMoveEmitPopAndReturn(&masm);
+
+      __ bind(&f49_63);
+      __ movdqu(xmm0, Operand(src, 0x00));
+      __ movdqu(xmm1, Operand(src, 0x10));
+      __ movdqu(xmm2, Operand(src, 0x20));
+      __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
+      __ movdqu(Operand(dst, 0x00), xmm0);
+      __ movdqu(Operand(dst, 0x10), xmm1);
+      __ movdqu(Operand(dst, 0x20), xmm2);
+      __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
+      MemMoveEmitPopAndReturn(&masm);
+
+      medium_handlers = new size_t[4];
+      medium_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f9_16.pos();
+      medium_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f17_32.pos();
+      medium_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f33_48.pos();
+      medium_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f49_63.pos();
+
+      __ bind(&medium_size);  // Entry point into this block.
+      __ mov(eax, count);
+      __ dec(eax);
+      __ shr(eax, 4);
+      if (FLAG_debug_code) {
+        Label ok;
+        __ cmp(eax, 3);
+        __ j(below_equal, &ok);
+        __ int3();
+        __ bind(&ok);
+      }
+      __ mov(eax, Operand(eax, times_4,
+                          reinterpret_cast<intptr_t>(medium_handlers)));
+      __ jmp(eax);
+    }
+    {
+      // Specialized copiers for copy_size <= 8 bytes.
+      Label f0, f1, f2, f3, f4, f5_8;
+      __ bind(&f0);
+      MemMoveEmitPopAndReturn(&masm);
+
+      __ bind(&f1);
+      __ mov_b(eax, Operand(src, 0));
+      __ mov_b(Operand(dst, 0), eax);
+      MemMoveEmitPopAndReturn(&masm);
+
+      __ bind(&f2);
+      __ mov_w(eax, Operand(src, 0));
+      __ mov_w(Operand(dst, 0), eax);
+      MemMoveEmitPopAndReturn(&masm);
+
+      __ bind(&f3);
+      __ mov_w(eax, Operand(src, 0));
+      __ mov_b(edx, Operand(src, 2));
+      __ mov_w(Operand(dst, 0), eax);
+      __ mov_b(Operand(dst, 2), edx);
+      MemMoveEmitPopAndReturn(&masm);
+
+      __ bind(&f4);
+      __ mov(eax, Operand(src, 0));
+      __ mov(Operand(dst, 0), eax);
+      MemMoveEmitPopAndReturn(&masm);
+
+      __ bind(&f5_8);
+      __ mov(eax, Operand(src, 0));
+      __ mov(edx, Operand(src, count, times_1, -4));
+      __ mov(Operand(dst, 0), eax);
+      __ mov(Operand(dst, count, times_1, -4), edx);
+      MemMoveEmitPopAndReturn(&masm);
+
+      small_handlers = new size_t[9];
+      small_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f0.pos();
+      small_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f1.pos();
+      small_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f2.pos();
+      small_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f3.pos();
+      small_handlers[4] = reinterpret_cast<intptr_t>(buffer) + f4.pos();
+      small_handlers[5] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
+      small_handlers[6] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
+      small_handlers[7] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
+      small_handlers[8] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
+
+      __ bind(&small_size);  // Entry point into this block.
+      if (FLAG_debug_code) {
+        Label ok;
+        __ cmp(count, 8);
+        __ j(below_equal, &ok);
+        __ int3();
+        __ bind(&ok);
+      }
+      __ mov(eax, Operand(count, times_4,
+                          reinterpret_cast<intptr_t>(small_handlers)));
+      __ jmp(eax);
     }
-
   } else {
-    // SSE2 not supported. Unlikely to happen in practice.
-    __ push(edi);
-    __ push(esi);
-    stack_offset += 2 * kPointerSize;
-    __ cld();
-    Register dst = edi;
-    Register src = esi;
-    Register count = ecx;
-    __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
-    __ mov(src, Operand(esp, stack_offset + kSourceOffset));
-    __ mov(count, Operand(esp, stack_offset + kSizeOffset));
-
-    // Copy the first word.
-    __ mov(eax, Operand(src, 0));
-    __ mov(Operand(dst, 0), eax);
-
-    // Increment src,dstso that dst is aligned.
-    __ mov(edx, dst);
-    __ and_(edx, 0x03);
-    __ neg(edx);
-    __ add(edx, Immediate(4));  // edx = 4 - (dst & 3)
-    __ add(dst, edx);
-    __ add(src, edx);
-    __ sub(count, edx);
-    // edi is now aligned, ecx holds number of remaning bytes to copy.
-
-    __ mov(edx, count);
-    count = edx;
-    __ shr(ecx, 2);  // Make word count instead of byte count.
-    __ rep_movs();
-
-    // At most 3 bytes left to copy. Copy 4 bytes at end of string.
-    __ and_(count, 3);
-    __ mov(eax, Operand(src, count, times_1, -4));
-    __ mov(Operand(dst, count, times_1, -4), eax);
-
-    __ mov(eax, Operand(esp, stack_offset + kDestinationOffset));
-    __ pop(esi);
-    __ pop(edi);
-    __ ret(0);
+    // No SSE2.
+    Label forward;
+    __ cmp(count, 0);
+    __ j(equal, &pop_and_return);
+    __ cmp(dst, src);
+    __ j(above, &backward);
+    __ jmp(&forward);
+    {
+      // Simple forward copier.
+      Label forward_loop_1byte, forward_loop_4byte;
+      __ bind(&forward_loop_4byte);
+      __ mov(eax, Operand(src, 0));
+      __ sub(count, Immediate(4));
+      __ add(src, Immediate(4));
+      __ mov(Operand(dst, 0), eax);
+      __ add(dst, Immediate(4));
+      __ bind(&forward);  // Entry point.
+      __ cmp(count, 3);
+      __ j(above, &forward_loop_4byte);
+      __ bind(&forward_loop_1byte);
+      __ cmp(count, 0);
+      __ j(below_equal, &pop_and_return);
+      __ mov_b(eax, Operand(src, 0));
+      __ dec(count);
+      __ inc(src);
+      __ mov_b(Operand(dst, 0), eax);
+      __ inc(dst);
+      __ jmp(&forward_loop_1byte);
+    }
+    {
+      // Simple backward copier.
+      Label backward_loop_1byte, backward_loop_4byte, entry_shortcut;
+      __ bind(&backward);
+      __ add(src, count);
+      __ add(dst, count);
+      __ cmp(count, 3);
+      __ j(below_equal, &entry_shortcut);
+
+      __ bind(&backward_loop_4byte);
+      __ sub(src, Immediate(4));
+      __ sub(count, Immediate(4));
+      __ mov(eax, Operand(src, 0));
+      __ sub(dst, Immediate(4));
+      __ mov(Operand(dst, 0), eax);
+      __ cmp(count, 3);
+      __ j(above, &backward_loop_4byte);
+      __ bind(&backward_loop_1byte);
+      __ cmp(count, 0);
+      __ j(below_equal, &pop_and_return);
+      __ bind(&entry_shortcut);
+      __ dec(src);
+      __ dec(count);
+      __ mov_b(eax, Operand(src, 0));
+      __ dec(dst);
+      __ mov_b(Operand(dst, 0), eax);
+      __ jmp(&backward_loop_1byte);
+    }
   }
 
+  __ bind(&pop_and_return);
+  MemMoveEmitPopAndReturn(&masm);
+
   CodeDesc desc;
   masm.GetCode(&desc);
   ASSERT(!RelocInfo::RequiresRelocation(desc));
-
   CPU::FlushICache(buffer, actual_size);
   OS::ProtectCode(buffer, actual_size);
-  return FUNCTION_CAST<OS::MemCopyFunction>(buffer);
+  return FUNCTION_CAST<OS::MemMoveFunction>(buffer);
 }
 
+
 #undef __
 
 // -------------------------------------------------------------------------
index 9eabb2a..2d83cab 100644 (file)
@@ -79,6 +79,8 @@ void CPU::DebugBreak() {
   // instead
   // __asm { int 3 }
   __debugbreak();
+#elif defined(__native_client__)
+  asm("hlt");
 #else
   asm("int $3");
 #endif
index 8cdcf99..f043622 100644 (file)
@@ -90,9 +90,9 @@ void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
     Factory* factory = isolate->factory();
     Handle<ByteArray> new_reloc =
         factory->NewByteArray(reloc_length + padding, TENURED);
-    memcpy(new_reloc->GetDataStartAddress() + padding,
-           code->relocation_info()->GetDataStartAddress(),
-           reloc_length);
+    OS::MemCopy(new_reloc->GetDataStartAddress() + padding,
+                code->relocation_info()->GetDataStartAddress(),
+                reloc_length);
     // Create a relocation writer to write the comments in the padding
     // space. Use position 0 for everything to ensure short encoding.
     RelocInfoWriter reloc_info_writer(
@@ -177,7 +177,8 @@ void Deoptimizer::DeoptimizeFunctionWithPreparedFunctionList(
 
   // Move the relocation info to the beginning of the byte array.
   int new_reloc_size = reloc_end_address - reloc_info_writer.pos();
-  memmove(code->relocation_start(), reloc_info_writer.pos(), new_reloc_size);
+  OS::MemMove(
+      code->relocation_start(), reloc_info_writer.pos(), new_reloc_size);
 
   // The relocation info is in place, update the size.
   reloc_info->set_length(new_reloc_size);
@@ -211,41 +212,39 @@ void Deoptimizer::DeoptimizeFunctionWithPreparedFunctionList(
 
 
 static const byte kJnsInstruction = 0x79;
-static const byte kJnsOffset = 0x13;
+static const byte kJnsOffset = 0x11;
 static const byte kCallInstruction = 0xe8;
 static const byte kNopByteOne = 0x66;
 static const byte kNopByteTwo = 0x90;
 
-
-void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
-                                        Address pc_after,
-                                        Code* check_code,
-                                        Code* replacement_code) {
+// The back edge bookkeeping code matches the pattern:
+//
+//     sub <profiling_counter>, <delta>
+//     jns ok
+//     call <interrupt stub>
+//   ok:
+//
+// The patched back edge looks like this:
+//
+//     sub <profiling_counter>, <delta>  ;; Not changed
+//     nop
+//     nop
+//     call <on-stack replacment>
+//   ok:
+
+void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
+                                       Address pc_after,
+                                       Code* interrupt_code,
+                                       Code* replacement_code) {
+  ASSERT(!InterruptCodeIsPatched(unoptimized_code,
+                                 pc_after,
+                                 interrupt_code,
+                                 replacement_code));
+  // Turn the jump into nops.
   Address call_target_address = pc_after - kIntSize;
-  ASSERT_EQ(check_code->entry(),
-            Assembler::target_address_at(call_target_address));
-  // The back edge bookkeeping code matches the pattern:
-  //
-  //     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:
-  //
-  //     sub <profiling_counter>, <delta>  ;; Not changed
-  //     nop
-  //     nop
-  //     call <on-stack replacment>
-  //     test eax, <loop nesting depth>
-  // ok:
-
-  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;
+  // Replace the call address.
   Assembler::set_target_address_at(call_target_address,
                                    replacement_code->entry());
 
@@ -254,27 +253,48 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
 }
 
 
-void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
-                                         Address pc_after,
-                                         Code* check_code,
-                                         Code* replacement_code) {
+void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
+                                        Address pc_after,
+                                        Code* interrupt_code,
+                                        Code* replacement_code) {
+  ASSERT(InterruptCodeIsPatched(unoptimized_code,
+                                pc_after,
+                                interrupt_code,
+                                replacement_code));
+  // Restore the original jump.
   Address call_target_address = pc_after - kIntSize;
-  ASSERT_EQ(replacement_code->entry(),
-            Assembler::target_address_at(call_target_address));
-
-  // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to
-  // restore the conditional branch.
-  ASSERT_EQ(kNopByteOne,      *(call_target_address - 3));
-  ASSERT_EQ(kNopByteTwo,      *(call_target_address - 2));
-  ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
   *(call_target_address - 3) = kJnsInstruction;
   *(call_target_address - 2) = kJnsOffset;
+  // Restore the original call address.
   Assembler::set_target_address_at(call_target_address,
-                                   check_code->entry());
+                                   interrupt_code->entry());
 
-  check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
-      unoptimized_code, call_target_address, check_code);
+  interrupt_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+      unoptimized_code, call_target_address, interrupt_code);
+}
+
+
+#ifdef DEBUG
+bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
+                                         Address pc_after,
+                                         Code* interrupt_code,
+                                         Code* replacement_code) {
+  Address call_target_address = pc_after - kIntSize;
+  ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
+  if (*(call_target_address - 3) == kNopByteOne) {
+    ASSERT_EQ(replacement_code->entry(),
+             Assembler::target_address_at(call_target_address));
+    ASSERT_EQ(kNopByteTwo,      *(call_target_address - 2));
+    return true;
+  } else {
+    ASSERT_EQ(interrupt_code->entry(),
+              Assembler::target_address_at(call_target_address));
+    ASSERT_EQ(kJnsInstruction,  *(call_target_address - 3));
+    ASSERT_EQ(kJnsOffset,       *(call_target_address - 2));
+    return false;
+  }
 }
+#endif  // DEBUG
 
 
 static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
index c59b166..6223748 100644 (file)
@@ -60,18 +60,6 @@ const int kAlignmentZapValue = 0x12345678;  // Not heap object tagged.
 // ----------------------------------------------------
 
 
-class StackHandlerConstants : public AllStatic {
- public:
-  static const int kNextOffset     = 0 * kPointerSize;
-  static const int kCodeOffset     = 1 * kPointerSize;
-  static const int kStateOffset    = 2 * kPointerSize;
-  static const int kContextOffset  = 3 * kPointerSize;
-  static const int kFPOffset       = 4 * kPointerSize;
-
-  static const int kSize = kFPOffset + kPointerSize;
-};
-
-
 class EntryFrameConstants : public AllStatic {
  public:
   static const int kCallerFPOffset      = -6 * kPointerSize;
index efbdf13..19989b1 100644 (file)
@@ -164,6 +164,8 @@ void FullCodeGenerator::Generate() {
 
   { Comment cmnt(masm_, "[ Allocate locals");
     int locals_count = info->scope()->num_stack_slots();
+    // Generators allocate locals, if any, in context slots.
+    ASSERT(!info->function()->is_generator() || locals_count == 0);
     if (locals_count == 1) {
       __ push(Immediate(isolate()->factory()->undefined_value()));
     } else if (locals_count > 1) {
@@ -351,13 +353,6 @@ void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
   // the deoptimization input data found in the optimized code.
   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
-  // in a test instruction after the call so we can extract it from the OSR
-  // builtin.
-  ASSERT(loop_depth() > 0);
-  __ test(eax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
-
   EmitProfilingCounterReset();
 
   __ bind(&ok);
@@ -1214,7 +1209,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
       !pretenure &&
       scope()->is_function_scope() &&
       info->num_literals() == 0) {
-    FastNewClosureStub stub(info->language_mode());
+    FastNewClosureStub stub(info->language_mode(), info->is_generator());
     __ push(Immediate(info));
     __ CallStub(&stub);
   } else {
@@ -1670,24 +1665,33 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
   Handle<FixedArrayBase> constant_elements_values(
       FixedArrayBase::cast(constant_elements->get(1)));
 
-  __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
-  __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
-  __ push(Immediate(Smi::FromInt(expr->literal_index())));
-  __ push(Immediate(constant_elements));
   Heap* heap = isolate()->heap();
   if (has_constant_fast_elements &&
       constant_elements_values->map() == heap->fixed_cow_array_map()) {
     // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
     // change, so it's possible to specialize the stub in advance.
     __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
+    __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+    __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
+    __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
+    __ mov(ecx, Immediate(constant_elements));
     FastCloneShallowArrayStub stub(
         FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
         DONT_TRACK_ALLOCATION_SITE,
         length);
     __ CallStub(&stub);
   } else if (expr->depth() > 1) {
+    __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+    __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
+    __ push(Immediate(Smi::FromInt(expr->literal_index())));
+    __ push(Immediate(constant_elements));
     __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
-  } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+  } else if (Serializer::enabled() ||
+      length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+    __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+    __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
+    __ push(Immediate(Smi::FromInt(expr->literal_index())));
+    __ push(Immediate(constant_elements));
     __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
   } else {
     ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
@@ -1704,6 +1708,10 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
       allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
     }
 
+    __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
+    __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
+    __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
+    __ mov(ecx, Immediate(constant_elements));
     FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
     __ CallStub(&stub);
   }
index 4d23aef..1dcad04 100644 (file)
@@ -135,7 +135,7 @@ void LCodeGen::Comment(const char* format, ...) {
   // issues when the stack allocated buffer goes out of scope.
   size_t length = builder.position();
   Vector<char> copy = Vector<char>::New(length + 1);
-  memcpy(copy.start(), builder.Finalize(), copy.length());
+  OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
   masm()->RecordComment(copy.start());
 }
 
@@ -366,7 +366,20 @@ bool LCodeGen::GenerateBody() {
           Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
         }
       }
+
+      if (!CpuFeatures::IsSupported(SSE2)) {
+        FlushX87StackIfNecessary(instr);
+      }
+
       instr->CompileToNative(this);
+
+      if (!CpuFeatures::IsSupported(SSE2)) {
+        ASSERT(!instr->HasDoubleRegisterResult() || x87_stack_depth_ == 1);
+
+        if (FLAG_debug_code && FLAG_enable_slow_asserts) {
+          __ VerifyX87StackDepth(x87_stack_depth_);
+        }
+      }
     }
   }
   EnsureSpaceForLazyDeopt();
@@ -521,6 +534,52 @@ bool LCodeGen::IsX87TopOfStack(LOperand* op) const {
 }
 
 
+void LCodeGen::ReadX87Operand(Operand dst) {
+  ASSERT(x87_stack_depth_ == 1);
+  __ fst_d(dst);
+}
+
+
+void LCodeGen::PushX87DoubleOperand(Operand src) {
+  ASSERT(x87_stack_depth_ == 0);
+  x87_stack_depth_++;
+  __ fld_d(src);
+}
+
+
+void LCodeGen::PushX87FloatOperand(Operand src) {
+  ASSERT(x87_stack_depth_ == 0);
+  x87_stack_depth_++;
+  __ fld_s(src);
+}
+
+
+void LCodeGen::PopX87() {
+  ASSERT(x87_stack_depth_ == 1);
+  x87_stack_depth_--;
+  __ fstp(0);
+}
+
+
+void LCodeGen::CurrentInstructionReturnsX87Result() {
+  ASSERT(x87_stack_depth_ <= 1);
+  if (x87_stack_depth_ == 0) {
+    x87_stack_depth_ = 1;
+  }
+}
+
+
+void LCodeGen::FlushX87StackIfNecessary(LInstruction* instr) {
+  if (x87_stack_depth_ > 0) {
+    if ((instr->ClobbersDoubleRegisters() ||
+         instr->HasDoubleRegisterResult()) &&
+        !instr->HasDoubleRegisterInput()) {
+      PopX87();
+    }
+  }
+}
+
+
 Register LCodeGen::ToRegister(LOperand* op) const {
   ASSERT(op->IsRegister());
   return ToRegister(op->index());
@@ -846,6 +905,8 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(
 void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
   RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
   ASSERT(environment->HasBeenRegistered());
+  // It's an error to deoptimize with the x87 fp stack in use.
+  ASSERT(x87_stack_depth_ == 0);
   int id = environment->deoptimization_index();
   ASSERT(info()->IsOptimizing() || info()->IsStub());
   Deoptimizer::BailoutType bailout_type = info()->IsStub()
@@ -858,8 +919,8 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
     return;
   }
 
-  if (FLAG_deopt_every_n_times != 0) {
-    Handle<SharedFunctionInfo> shared(info_->shared_info());
+  if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
+    Handle<SharedFunctionInfo> shared(info()->shared_info());
     Label no_deopt;
     __ pushfd();
     __ push(eax);
@@ -1689,40 +1750,46 @@ void LCodeGen::DoConstantI(LConstantI* instr) {
 
 
 void LCodeGen::DoConstantD(LConstantD* instr) {
-  ASSERT(instr->result()->IsDoubleRegister());
-  XMMRegister res = ToDoubleRegister(instr->result());
   double v = instr->value();
-  // Use xor to produce +0.0 in a fast and compact way, but avoid to
-  // do so if the constant is -0.0.
-  if (BitCast<uint64_t, double>(v) == 0) {
-    __ xorps(res, res);
+  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));
+
+  if (!CpuFeatures::IsSafeForSnapshot(SSE2)) {
+    __ push(Immediate(lower));
+    __ push(Immediate(upper));
+    PushX87DoubleOperand(Operand(esp, 0));
+    __ add(Operand(esp), Immediate(kDoubleSize));
+    CurrentInstructionReturnsX87Result();
   } else {
-    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));
-    if (CpuFeatures::IsSupported(SSE4_1)) {
-      CpuFeatureScope scope1(masm(), SSE2);
-      CpuFeatureScope scope2(masm(), SSE4_1);
-      if (lower != 0) {
-        __ Set(temp, Immediate(lower));
-        __ movd(res, Operand(temp));
-        __ Set(temp, Immediate(upper));
-        __ pinsrd(res, Operand(temp), 1);
+    CpuFeatureScope scope1(masm(), SSE2);
+    ASSERT(instr->result()->IsDoubleRegister());
+    XMMRegister res = ToDoubleRegister(instr->result());
+    if (int_val == 0) {
+      __ xorps(res, res);
+    } else {
+      Register temp = ToRegister(instr->temp());
+      if (CpuFeatures::IsSupported(SSE4_1)) {
+        CpuFeatureScope scope2(masm(), SSE4_1);
+        if (lower != 0) {
+          __ Set(temp, Immediate(lower));
+          __ movd(res, Operand(temp));
+          __ Set(temp, Immediate(upper));
+          __ pinsrd(res, Operand(temp), 1);
+        } else {
+          __ xorps(res, res);
+          __ Set(temp, Immediate(upper));
+          __ pinsrd(res, Operand(temp), 1);
+        }
       } else {
-        __ xorps(res, res);
         __ Set(temp, Immediate(upper));
-        __ pinsrd(res, Operand(temp), 1);
-      }
-    } else {
-      CpuFeatureScope scope(masm(), SSE2);
-      __ Set(temp, Immediate(upper));
-      __ movd(res, Operand(temp));
-      __ psllq(res, 32);
-      if (lower != 0) {
-        __ Set(temp, Immediate(lower));
-        __ movd(xmm0, Operand(temp));
-        __ por(res, xmm0);
+        __ movd(res, Operand(temp));
+        __ psllq(res, 32);
+        if (lower != 0) {
+          __ Set(temp, Immediate(lower));
+          __ movd(xmm0, Operand(temp));
+          __ por(res, xmm0);
+        }
       }
     }
   }
@@ -1951,6 +2018,9 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
       break;
     case Token::DIV:
       __ divsd(left, right);
+      // Don't delete this mov. It may improve performance on some CPUs,
+      // when there is a mulsd depending on the result
+      __ movaps(left, left);
       break;
     case Token::MOD: {
       // Pass two doubles as arguments on the stack.
@@ -3158,16 +3228,16 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
       __ movss(result, operand);
       __ cvtss2sd(result, result);
     } else {
-      __ fld_s(operand);
-      HandleX87FPReturnValue(instr);
+      PushX87FloatOperand(operand);
+      CurrentInstructionReturnsX87Result();
     }
   } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
     if (CpuFeatures::IsSupported(SSE2)) {
       CpuFeatureScope scope(masm(), SSE2);
       __ movdbl(ToDoubleRegister(instr->result()), operand);
     } else {
-      __ fld_d(operand);
-      HandleX87FPReturnValue(instr);
+      PushX87DoubleOperand(operand);
+      CurrentInstructionReturnsX87Result();
     }
   } else {
     Register result(ToRegister(instr->result()));
@@ -3212,29 +3282,6 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
 }
 
 
-void LCodeGen::HandleX87FPReturnValue(LInstruction* instr) {
-  if (IsX87TopOfStack(instr->result())) {
-    // Return value is already on stack. If the value has no uses, then
-    // pop it off the FP stack. Otherwise, make sure that there are enough
-    // copies of the value on the stack to feed all of the usages, e.g.
-    // when the following instruction uses the return value in multiple
-    // inputs.
-    int count = instr->hydrogen_value()->UseCount();
-    if (count == 0) {
-      __ fstp(0);
-    } else {
-      count--;
-      ASSERT(count <= 7);
-      while (count-- > 0) {
-        __ fld(0);
-      }
-    }
-  } else {
-    __ fstp_d(ToOperand(instr->result()));
-  }
-}
-
-
 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
   if (instr->hydrogen()->RequiresHoleCheck()) {
     int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
@@ -3261,8 +3308,8 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
     XMMRegister result = ToDoubleRegister(instr->result());
     __ movdbl(result, double_load_operand);
   } else {
-    __ fld_d(double_load_operand);
-    HandleX87FPReturnValue(instr);
+    PushX87DoubleOperand(double_load_operand);
+    CurrentInstructionReturnsX87Result();
   }
 }
 
@@ -3598,7 +3645,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
 }
 
 
-void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
+void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
   Register input_reg = ToRegister(instr->value());
   __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
          factory()->heap_number_map());
@@ -3651,7 +3698,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
   Register input_reg = ToRegister(instr->value());
   __ test(input_reg, Operand(input_reg));
   Label is_positive;
@@ -3663,19 +3710,18 @@ void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
   // Class for deferred case.
   class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
    public:
-    DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
-                                    LUnaryMathOperation* instr)
+    DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
         : LDeferredCode(codegen), instr_(instr) { }
     virtual void Generate() {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
     virtual LInstruction* instr() { return instr_; }
    private:
-    LUnaryMathOperation* instr_;
+    LMathAbs* instr_;
   };
 
   ASSERT(instr->value()->Equals(instr->result()));
@@ -3702,7 +3748,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathFloor(LMathFloor* instr) {
   CpuFeatureScope scope(masm(), SSE2);
   XMMRegister xmm_scratch = xmm0;
   Register output_reg = ToRegister(instr->result());
@@ -3828,7 +3874,7 @@ void LCodeGen::DoMathRound(LMathRound* instr) {
 }
 
 
-void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
   CpuFeatureScope scope(masm(), SSE2);
   XMMRegister input_reg = ToDoubleRegister(instr->value());
   ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
@@ -3981,7 +4027,7 @@ void LCodeGen::DoDeferredRandom(LRandom* instr) {
 }
 
 
-void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathLog(LMathLog* instr) {
   CpuFeatureScope scope(masm(), SSE2);
   ASSERT(instr->value()->Equals(instr->result()));
   XMMRegister input_reg = ToDoubleRegister(instr->value());
@@ -4024,7 +4070,7 @@ void LCodeGen::DoMathExp(LMathExp* instr) {
 }
 
 
-void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathTan(LMathTan* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
   TranscendentalCacheStub stub(TranscendentalCache::TAN,
                                TranscendentalCacheStub::UNTAGGED);
@@ -4032,7 +4078,7 @@ void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathCos(LMathCos* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
   TranscendentalCacheStub stub(TranscendentalCache::COS,
                                TranscendentalCacheStub::UNTAGGED);
@@ -4040,7 +4086,7 @@ void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSin(LMathSin* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
   TranscendentalCacheStub stub(TranscendentalCache::SIN,
                                TranscendentalCacheStub::UNTAGGED);
@@ -4048,36 +4094,6 @@ void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
-  switch (instr->op()) {
-    case kMathAbs:
-      DoMathAbs(instr);
-      break;
-    case kMathFloor:
-      DoMathFloor(instr);
-      break;
-    case kMathSqrt:
-      DoMathSqrt(instr);
-      break;
-    case kMathCos:
-      DoMathCos(instr);
-      break;
-    case kMathSin:
-      DoMathSin(instr);
-      break;
-    case kMathTan:
-      DoMathTan(instr);
-      break;
-    case kMathLog:
-      DoMathLog(instr);
-      break;
-
-    default:
-      UNREACHABLE();
-  }
-}
-
-
 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   ASSERT(ToRegister(instr->context()).is(esi));
   ASSERT(ToRegister(instr->function()).is(edi));
@@ -4311,12 +4327,21 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
       0,
       instr->additional_index()));
   if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
-    CpuFeatureScope scope(masm(), SSE2);
-    __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
-    __ movss(operand, xmm0);
+    if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+      CpuFeatureScope scope(masm(), SSE2);
+      __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
+      __ movss(operand, xmm0);
+    } else {
+      __ fld(0);
+      __ fstp_s(operand);
+    }
   } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
-    CpuFeatureScope scope(masm(), SSE2);
-    __ movdbl(operand, ToDoubleRegister(instr->value()));
+    if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+      CpuFeatureScope scope(masm(), SSE2);
+      __ movdbl(operand, ToDoubleRegister(instr->value()));
+    } else {
+      __ fst_d(operand);
+    }
   } else {
     Register value = ToRegister(instr->value());
     switch (elements_kind) {
@@ -4351,21 +4376,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
 
 
 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
-  CpuFeatureScope scope(masm(), SSE2);
-  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);
-  }
-
+  ExternalReference canonical_nan_reference =
+      ExternalReference::address_of_canonical_non_hole_nan();
   Operand double_store_operand = BuildFastArrayOperand(
       instr->elements(),
       instr->key(),
@@ -4373,7 +4385,68 @@ void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
       FAST_DOUBLE_ELEMENTS,
       FixedDoubleArray::kHeaderSize - kHeapObjectTag,
       instr->additional_index());
-  __ movdbl(double_store_operand, value);
+
+  if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+    CpuFeatureScope scope(masm(), SSE2);
+    XMMRegister value = ToDoubleRegister(instr->value());
+
+    if (instr->NeedsCanonicalization()) {
+      Label have_value;
+
+      __ ucomisd(value, value);
+      __ j(parity_odd, &have_value);  // NaN.
+
+      __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
+      __ bind(&have_value);
+    }
+
+    __ movdbl(double_store_operand, value);
+  } else {
+    // Can't use SSE2 in the serializer
+    if (instr->hydrogen()->IsConstantHoleStore()) {
+      // This means we should store the (double) hole. No floating point
+      // registers required.
+      double nan_double = FixedDoubleArray::hole_nan_as_double();
+      uint64_t int_val = BitCast<uint64_t, double>(nan_double);
+      int32_t lower = static_cast<int32_t>(int_val);
+      int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
+
+      __ mov(double_store_operand, Immediate(lower));
+      Operand double_store_operand2 = BuildFastArrayOperand(
+          instr->elements(),
+          instr->key(),
+          instr->hydrogen()->key()->representation(),
+          FAST_DOUBLE_ELEMENTS,
+          FixedDoubleArray::kHeaderSize - kHeapObjectTag + kPointerSize,
+          instr->additional_index());
+      __ mov(double_store_operand2, Immediate(upper));
+    } else {
+      Label no_special_nan_handling;
+      ASSERT(x87_stack_depth_ > 0);
+
+      if (instr->NeedsCanonicalization()) {
+        __ fld(0);
+        __ fld(0);
+        __ FCmp();
+
+        __ j(parity_odd, &no_special_nan_handling);
+        __ sub(esp, Immediate(kDoubleSize));
+        __ fst_d(MemOperand(esp, 0));
+        __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
+               Immediate(kHoleNanUpper32));
+        __ add(esp, Immediate(kDoubleSize));
+        Label canonicalize;
+        __ j(not_equal, &canonicalize);
+        __ jmp(&no_special_nan_handling);
+        __ bind(&canonicalize);
+        __ fstp(0);
+        __ fld_d(Operand::StaticVariable(canonical_nan_reference));
+      }
+
+      __ bind(&no_special_nan_handling);
+      __ fst_d(double_store_operand);
+    }
+  }
 }
 
 
@@ -4805,9 +4878,6 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
       XMMRegister input_reg = ToDoubleRegister(instr->value());
       __ ucomisd(input_reg, input_reg);
     } else {
-      if (!IsX87TopOfStack(instr->value())) {
-        __ fld_d(ToOperand(instr->value()));
-      }
       __ fld(0);
       __ fld(0);
       __ FCmp();
@@ -4829,6 +4899,9 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
     __ j(not_equal, &canonicalize);
     __ add(esp, Immediate(kDoubleSize));
     __ mov(reg, factory()->the_hole_value());
+    if (!use_sse2) {
+      __ fstp(0);
+    }
     __ jmp(&done);
     __ bind(&canonicalize);
     __ add(esp, Immediate(kDoubleSize));
@@ -4858,10 +4931,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
     XMMRegister input_reg = ToDoubleRegister(instr->value());
     __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
   } else {
-    if (!IsX87TopOfStack(instr->value())) {
-    __ fld_d(ToOperand(instr->value()));
-    }
-    __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
+    __ fst_d(FieldOperand(reg, HeapNumber::kValueOffset));
   }
   __ bind(&done);
 }
@@ -4909,6 +4979,79 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
 }
 
 
+void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg,
+                                      Register temp_reg,
+                                      bool deoptimize_on_undefined,
+                                      bool deoptimize_on_minus_zero,
+                                      LEnvironment* env,
+                                      NumberUntagDMode mode) {
+  Label load_smi, done;
+
+  if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
+    // Smi check.
+    __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
+
+    // Heap number map check.
+    __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+           factory()->heap_number_map());
+    if (deoptimize_on_undefined) {
+      DeoptimizeIf(not_equal, env);
+    } else {
+      Label heap_number;
+      __ j(equal, &heap_number, Label::kNear);
+
+      __ cmp(input_reg, factory()->undefined_value());
+      DeoptimizeIf(not_equal, env);
+
+      // Convert undefined to NaN.
+      ExternalReference nan =
+          ExternalReference::address_of_canonical_non_hole_nan();
+      __ fld_d(Operand::StaticVariable(nan));
+      __ jmp(&done, Label::kNear);
+      __ bind(&heap_number);
+    }
+    // Heap number to x87 conversion.
+    __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
+    if (deoptimize_on_minus_zero) {
+      __ fldz();
+      __ FCmp();
+      __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
+      __ j(not_zero, &done, Label::kNear);
+
+      // Use general purpose registers to check if we have -0.0
+      __ mov(temp_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
+      __ test(temp_reg, Immediate(HeapNumber::kSignMask));
+      __ j(zero, &done, Label::kNear);
+
+      // Pop FPU stack before deoptimizing.
+      __ fstp(0);
+      DeoptimizeIf(not_zero, env);
+    }
+    __ jmp(&done, Label::kNear);
+  } else if (mode == NUMBER_CANDIDATE_IS_SMI_OR_HOLE) {
+    __ test(input_reg, Immediate(kSmiTagMask));
+    DeoptimizeIf(not_equal, env);
+  } else if (mode == NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE) {
+    __ test(input_reg, Immediate(kSmiTagMask));
+    __ j(zero, &load_smi);
+    ExternalReference hole_nan_reference =
+        ExternalReference::address_of_the_hole_nan();
+    __ fld_d(Operand::StaticVariable(hole_nan_reference));
+    __ jmp(&done, Label::kNear);
+  } else {
+    ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
+  }
+
+  __ bind(&load_smi);
+  __ SmiUntag(input_reg);  // Untag smi before converting to float.
+  __ push(input_reg);
+  __ fild_s(Operand(esp, 0));
+  __ pop(input_reg);
+  __ SmiTag(input_reg);  // Retag smi.
+  __ bind(&done);
+}
+
+
 void LCodeGen::EmitNumberUntagD(Register input_reg,
                                 Register temp_reg,
                                 XMMRegister result_reg,
@@ -5021,7 +5164,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
       __ fisttp_d(Operand(esp, 0));
       __ mov(input_reg, Operand(esp, 0));  // Low word of answer is the result.
       __ add(Operand(esp), Immediate(kDoubleSize));
-    } else {
+    } else if (CpuFeatures::IsSupported(SSE2)) {
       CpuFeatureScope scope(masm(), SSE2);
       XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
       __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
@@ -5035,6 +5178,8 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
       __ ucomisd(xmm_temp, xmm0);
       DeoptimizeIf(not_equal, instr->environment());
       DeoptimizeIf(parity_even, instr->environment());  // NaN.
+    } else {
+      UNREACHABLE();
     }
   } else if (CpuFeatures::IsSupported(SSE2)) {
     CpuFeatureScope scope(masm(), SSE2);
@@ -5079,18 +5224,169 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
 
   LOperand* input = instr->value();
   ASSERT(input->IsRegister());
-  ASSERT(input->Equals(instr->result()));
-
   Register input_reg = ToRegister(input);
+  ASSERT(input_reg.is(ToRegister(instr->result())));
 
   DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
 
-  // Smi check.
   __ JumpIfNotSmi(input_reg, deferred->entry());
+  __ SmiUntag(input_reg);
+  __ bind(deferred->exit());
+}
 
-  // Smi to int32 conversion
-  __ SmiUntag(input_reg);  // Untag smi.
 
+void LCodeGen::DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
+  Label done, heap_number;
+  Register result_reg = ToRegister(instr->result());
+  Register input_reg = ToRegister(instr->value());
+
+  // Heap number map check.
+  __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+         factory()->heap_number_map());
+  __ j(equal, &heap_number, Label::kNear);
+  // 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());
+  __ xor_(result_reg, result_reg);
+  __ jmp(&done, Label::kFar);
+  __ bind(&heap_number);
+
+  // Surprisingly, all of this crazy bit manipulation is considerably
+  // faster than using the built-in x86 CPU conversion functions (about 6x).
+  Label right_exponent, adjust_bias, zero_result;
+  Register scratch = ToRegister(instr->scratch());
+  Register scratch2 = ToRegister(instr->scratch2());
+  // Get exponent word.
+  __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
+  // Get exponent alone in scratch2.
+  __ mov(scratch2, scratch);
+  __ and_(scratch2, HeapNumber::kExponentMask);
+  __ shr(scratch2, HeapNumber::kExponentShift);
+  if (instr->truncating()) {
+    __ j(zero, &zero_result);
+  } else {
+    __ j(not_zero, &adjust_bias);
+    __ test(scratch, Immediate(HeapNumber::kMantissaMask));
+    DeoptimizeIf(not_zero, instr->environment());
+    __ cmp(FieldOperand(input_reg, HeapNumber::kMantissaOffset), Immediate(0));
+    DeoptimizeIf(not_equal, instr->environment());
+    __ bind(&adjust_bias);
+  }
+  __ sub(scratch2, Immediate(HeapNumber::kExponentBias));
+  if (!instr->truncating()) {
+    DeoptimizeIf(negative, instr->environment());
+  } else {
+    __ j(negative, &zero_result);
+  }
+
+  // Get the second half of the double. For some exponents we don't
+  // actually need this because the bits get shifted out again, but
+  // it's probably slower to test than just to do it.
+  Register scratch3 = ToRegister(instr->scratch3());
+  __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
+  __ xor_(result_reg, result_reg);
+
+  const uint32_t non_int32_exponent = 31;
+  __ cmp(scratch2, Immediate(non_int32_exponent));
+  // If we have a match of the int32 exponent then skip some logic.
+  __ j(equal, &right_exponent, Label::kNear);
+  // If the number doesn't find in an int32, deopt.
+  DeoptimizeIf(greater, instr->environment());
+
+  // Exponent word in scratch, exponent in scratch2.  We know that 0 <= exponent
+  // < 31.
+  __ mov(result_reg, Immediate(31));
+  __ sub(result_reg, scratch2);
+
+  __ bind(&right_exponent);
+
+  // Save off exponent for negative check later.
+  __ mov(scratch2, scratch);
+
+  // Here result_reg is the shift, scratch is the exponent word.
+  // Get the top bits of the mantissa.
+  __ and_(scratch, HeapNumber::kMantissaMask);
+  // Put back the implicit 1.
+  __ or_(scratch, 1 << HeapNumber::kExponentShift);
+  // Shift up the mantissa bits to take up the space the exponent used to
+  // take. We have kExponentShift + 1 significant bits int he low end of the
+  // word.  Shift them to the top bits.
+  const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
+  __ shl(scratch, shift_distance);
+  if (!instr->truncating()) {
+    // If not truncating, a non-zero value in the bottom 22 bits means a
+    // non-integral value --> trigger a deopt.
+    __ test(scratch3, Immediate((1 << (32 - shift_distance)) - 1));
+    DeoptimizeIf(not_equal, instr->environment());
+  }
+  // Shift down 22 bits to get the most significant 10 bits or the low
+  // mantissa word.
+  __ shr(scratch3, 32 - shift_distance);
+  __ or_(scratch3, scratch);
+  if (!instr->truncating()) {
+    // If truncating, a non-zero value in the bits that will be shifted away
+    // when adjusting the exponent means rounding --> deopt.
+    __ mov(scratch, 0x1);
+    ASSERT(result_reg.is(ecx));
+    __ shl_cl(scratch);
+    __ dec(scratch);
+    __ test(scratch3, scratch);
+    DeoptimizeIf(not_equal, instr->environment());
+  }
+  // Move down according to the exponent.
+  ASSERT(result_reg.is(ecx));
+  __ shr_cl(scratch3);
+  // Now the unsigned 32-bit answer is in scratch3.  We need to move it to
+  // result_reg and we may need to fix the sign.
+  Label negative_result;
+  __ xor_(result_reg, result_reg);
+  __ cmp(scratch2, result_reg);
+  __ j(less, &negative_result, Label::kNear);
+  __ cmp(scratch3, result_reg);
+  __ mov(result_reg, scratch3);
+  // If the result is > MAX_INT, result doesn't fit in signed 32-bit --> deopt.
+  DeoptimizeIf(less, instr->environment());
+  __ jmp(&done, Label::kNear);
+  __ bind(&zero_result);
+  __ xor_(result_reg, result_reg);
+  __ jmp(&done, Label::kNear);
+  __ bind(&negative_result);
+  __ sub(result_reg, scratch3);
+  if (!instr->truncating()) {
+    // -0.0 triggers a deopt.
+    DeoptimizeIf(zero, instr->environment());
+  }
+  // If the negative subtraction overflows into a positive number, there was an
+  // overflow --> deopt.
+  DeoptimizeIf(positive, instr->environment());
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
+  class DeferredTaggedToINoSSE2: public LDeferredCode {
+   public:
+    DeferredTaggedToINoSSE2(LCodeGen* codegen, LTaggedToINoSSE2* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() { codegen()->DoDeferredTaggedToINoSSE2(instr_); }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LTaggedToINoSSE2* instr_;
+  };
+
+  LOperand* input = instr->value();
+  ASSERT(input->IsRegister());
+  Register input_reg = ToRegister(input);
+  ASSERT(input_reg.is(ToRegister(instr->result())));
+
+  DeferredTaggedToINoSSE2* deferred =
+      new(zone()) DeferredTaggedToINoSSE2(this, instr);
+
+  // Smi check.
+  __ JumpIfNotSmi(input_reg, deferred->entry());
+  __ SmiUntag(input_reg);  // Untag smi.
   __ bind(deferred->exit());
 }
 
@@ -5103,32 +5399,31 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
   LOperand* result = instr->result();
   ASSERT(result->IsDoubleRegister());
 
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope scope(masm(), SSE2);
-    Register input_reg = ToRegister(input);
-    XMMRegister result_reg = ToDoubleRegister(result);
-
-    bool deoptimize_on_minus_zero =
-        instr->hydrogen()->deoptimize_on_minus_zero();
-    Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
-
-    NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
-    HValue* value = instr->hydrogen()->value();
-    if (value->type().IsSmi()) {
-      if (value->IsLoadKeyed()) {
-        HLoadKeyed* load = HLoadKeyed::cast(value);
-        if (load->UsesMustHandleHole()) {
-          if (load->hole_mode() == ALLOW_RETURN_HOLE) {
-            mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
-          } else {
-            mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
-          }
+  Register input_reg = ToRegister(input);
+  bool deoptimize_on_minus_zero =
+      instr->hydrogen()->deoptimize_on_minus_zero();
+  Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
+
+  NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
+  HValue* value = instr->hydrogen()->value();
+  if (value->type().IsSmi()) {
+    if (value->IsLoadKeyed()) {
+      HLoadKeyed* load = HLoadKeyed::cast(value);
+      if (load->UsesMustHandleHole()) {
+        if (load->hole_mode() == ALLOW_RETURN_HOLE) {
+          mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE;
         } else {
-          mode = NUMBER_CANDIDATE_IS_SMI;
+          mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE;
         }
+      } else {
+        mode = NUMBER_CANDIDATE_IS_SMI;
       }
     }
+  }
 
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatureScope scope(masm(), SSE2);
+    XMMRegister result_reg = ToDoubleRegister(result);
     EmitNumberUntagD(input_reg,
                      temp_reg,
                      result_reg,
@@ -5137,7 +5432,13 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
                      instr->environment(),
                      mode);
   } else {
-    UNIMPLEMENTED();
+    EmitNumberUntagDNoSSE2(input_reg,
+                           temp_reg,
+                           instr->hydrogen()->deoptimize_on_undefined(),
+                           deoptimize_on_minus_zero,
+                           instr->environment(),
+                           mode);
+    CurrentInstructionReturnsX87Result();
   }
 }
 
@@ -5409,13 +5710,133 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
   __ bind(&is_smi);
   __ SmiUntag(input_reg);
   __ ClampUint8(input_reg);
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) {
+  Register input_reg = ToRegister(instr->unclamped());
+  Register result_reg = ToRegister(instr->result());
+  Register scratch = ToRegister(instr->scratch());
+  Register scratch2 = ToRegister(instr->scratch2());
+  Register scratch3 = ToRegister(instr->scratch3());
+  Label is_smi, done, heap_number, valid_exponent,
+      largest_value, zero_result, maybe_nan_or_infinity;
 
+  __ JumpIfSmi(input_reg, &is_smi);
+
+  // Check for heap number
+  __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+         factory()->heap_number_map());
+  __ j(equal, &heap_number, Label::kFar);
+
+  // Check for undefined. Undefined is converted to zero for clamping
+  // conversions.
+  __ cmp(input_reg, factory()->undefined_value());
+  DeoptimizeIf(not_equal, instr->environment());
+  __ jmp(&zero_result);
+
+  // Heap number
+  __ bind(&heap_number);
+
+  // Surprisingly, all of the hand-crafted bit-manipulations below are much
+  // faster than the x86 FPU built-in instruction, especially since "banker's
+  // rounding" would be additionally very expensive
+
+  // Get exponent word.
+  __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
+  __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
+
+  // Test for negative values --> clamp to zero
+  __ test(scratch, scratch);
+  __ j(negative, &zero_result);
+
+  // Get exponent alone in scratch2.
+  __ mov(scratch2, scratch);
+  __ and_(scratch2, HeapNumber::kExponentMask);
+  __ shr(scratch2, HeapNumber::kExponentShift);
+  __ j(zero, &zero_result);
+  __ sub(scratch2, Immediate(HeapNumber::kExponentBias - 1));
+  __ j(negative, &zero_result);
+
+  const uint32_t non_int8_exponent = 7;
+  __ cmp(scratch2, Immediate(non_int8_exponent + 1));
+  // If the exponent is too big, check for special values.
+  __ j(greater, &maybe_nan_or_infinity, Label::kNear);
+
+  __ bind(&valid_exponent);
+  // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent
+  // < 7. The shift bias is the number of bits to shift the mantissa such that
+  // with an exponent of 7 such the that top-most one is in bit 30, allowing
+  // detection the rounding overflow of a 255.5 to 256 (bit 31 goes from 0 to
+  // 1).
+  int shift_bias = (30 - HeapNumber::kExponentShift) - 7 - 1;
+  __ lea(result_reg, MemOperand(scratch2, shift_bias));
+  // Here result_reg (ecx) is the shift, scratch is the exponent word.  Get the
+  // top bits of the mantissa.
+  __ and_(scratch, HeapNumber::kMantissaMask);
+  // Put back the implicit 1 of the mantissa
+  __ or_(scratch, 1 << HeapNumber::kExponentShift);
+  // Shift up to round
+  __ shl_cl(scratch);
+  // Use "banker's rounding" to spec: If fractional part of number is 0.5, then
+  // use the bit in the "ones" place and add it to the "halves" place, which has
+  // the effect of rounding to even.
+  __ mov(scratch2, scratch);
+  const uint32_t one_half_bit_shift = 30 - sizeof(uint8_t) * 8;
+  const uint32_t one_bit_shift = one_half_bit_shift + 1;
+  __ and_(scratch2, Immediate((1 << one_bit_shift) - 1));
+  __ cmp(scratch2, Immediate(1 << one_half_bit_shift));
+  Label no_round;
+  __ j(less, &no_round);
+  Label round_up;
+  __ mov(scratch2, Immediate(1 << one_half_bit_shift));
+  __ j(greater, &round_up);
+  __ test(scratch3, scratch3);
+  __ j(not_zero, &round_up);
+  __ mov(scratch2, scratch);
+  __ and_(scratch2, Immediate(1 << one_bit_shift));
+  __ shr(scratch2, 1);
+  __ bind(&round_up);
+  __ add(scratch, scratch2);
+  __ j(overflow, &largest_value);
+  __ bind(&no_round);
+  __ shr(scratch, 23);
+  __ mov(result_reg, scratch);
+  __ jmp(&done, Label::kNear);
+
+  __ bind(&maybe_nan_or_infinity);
+  // Check for NaN/Infinity, all other values map to 255
+  __ cmp(scratch2, Immediate(HeapNumber::kInfinityOrNanExponent + 1));
+  __ j(not_equal, &largest_value, Label::kNear);
+
+  // Check for NaN, which differs from Infinity in that at least one mantissa
+  // bit is set.
+  __ and_(scratch, HeapNumber::kMantissaMask);
+  __ or_(scratch, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
+  __ j(not_zero, &zero_result);  // M!=0 --> NaN
+  // Infinity -> Fall through to map to 255.
+
+  __ bind(&largest_value);
+  __ mov(result_reg, Immediate(255));
+  __ jmp(&done, Label::kNear);
+
+  __ bind(&zero_result);
+  __ xor_(result_reg, result_reg);
+  __ jmp(&done);
+
+  // smi
+  __ bind(&is_smi);
+  if (!input_reg.is(result_reg)) {
+    __ mov(result_reg, input_reg);
+  }
+  __ SmiUntag(result_reg);
+  __ ClampUint8(result_reg);
   __ bind(&done);
 }
 
 
 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
-  ASSERT(instr->temp()->Equals(instr->result()));
   Register reg = ToRegister(instr->temp());
 
   ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
@@ -5423,15 +5844,10 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
 
   ASSERT(prototypes->length() == maps->length());
 
-  // TODO(ulan): Move this check to hydrogen and split HCheckPrototypeMaps
-  // into two instruction: one that checks the prototypes and another that
-  // loads the holder (HConstant). Find a way to do it without breaking
-  // parallel recompilation.
   if (instr->hydrogen()->CanOmitPrototypeChecks()) {
     for (int i = 0; i < maps->length(); i++) {
       prototype_maps_.Add(maps->at(i), info()->zone());
     }
-    __ LoadHeapObject(reg, prototypes->at(prototypes->length() - 1));
   } else {
     for (int i = 0; i < prototypes->length(); i++) {
       __ LoadHeapObject(reg, prototypes->at(i));
@@ -5557,11 +5973,11 @@ void LCodeGen::DoAllocate(LAllocate* instr) {
   if (instr->hydrogen()->MustAllocateDoubleAligned()) {
     flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
   }
+  if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+    flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+  }
   if (instr->size()->IsConstantOperand()) {
     int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
-    if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
-      flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
-    }
     __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
   } else {
     Register size = ToRegister(instr->size());
@@ -5585,8 +6001,13 @@ void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
     __ StoreToSafepointRegisterSlot(result, size);
   }
   __ push(size);
-  CallRuntimeFromDeferred(
-      Runtime::kAllocateInNewSpace, 1, instr, instr->context());
+  if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+    CallRuntimeFromDeferred(
+        Runtime::kAllocateInOldPointerSpace, 1, instr, instr->context());
+  } else {
+    CallRuntimeFromDeferred(
+        Runtime::kAllocateInNewSpace, 1, instr, instr->context());
+  }
   __ StoreToSafepointRegisterSlot(result, eax);
 }
 
@@ -5615,26 +6036,33 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
     DeoptimizeIf(not_equal, instr->environment());
   }
 
-  // Set up the parameters to the stub/runtime call.
-  __ PushHeapObject(literals);
-  __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
-  // Boilerplate already exists, constant elements are never accessed.
-  // Pass an empty fixed array.
-  __ push(Immediate(isolate()->factory()->empty_fixed_array()));
-
-  // Pick the right runtime function or stub to call.
+  // Set up the parameters to the stub/runtime call and pick the right
+  // runtime function or stub to call. Boilerplate already exists,
+  // constant elements are never accessed, pass an empty fixed array.
   int length = instr->hydrogen()->length();
   if (instr->hydrogen()->IsCopyOnWrite()) {
     ASSERT(instr->hydrogen()->depth() == 1);
+    __ LoadHeapObject(eax, literals);
+    __ mov(ebx, Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
+    __ mov(ecx, Immediate(isolate()->factory()->empty_fixed_array()));
     FastCloneShallowArrayStub::Mode mode =
         FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
     FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
     CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
   } else if (instr->hydrogen()->depth() > 1) {
+    __ PushHeapObject(literals);
+    __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
+    __ push(Immediate(isolate()->factory()->empty_fixed_array()));
     CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
   } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+    __ PushHeapObject(literals);
+    __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
+    __ push(Immediate(isolate()->factory()->empty_fixed_array()));
     CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
   } else {
+    __ LoadHeapObject(eax, literals);
+    __ mov(ebx, Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
+    __ mov(ecx, Immediate(isolate()->factory()->empty_fixed_array()));
     FastCloneShallowArrayStub::Mode mode =
         boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
         ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
@@ -5645,178 +6073,6 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
 }
 
 
-void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
-                            Register result,
-                            Register source,
-                            int* offset,
-                            AllocationSiteMode mode) {
-  ASSERT(!source.is(ecx));
-  ASSERT(!result.is(ecx));
-
-  bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
-      object->map()->CanTrackAllocationSite();
-
-  if (FLAG_debug_code) {
-    __ LoadHeapObject(ecx, object);
-    __ cmp(source, ecx);
-    __ Assert(equal, "Unexpected object literal boilerplate");
-    __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
-    __ cmp(ecx, Handle<Map>(object->map()));
-    __ Assert(equal, "Unexpected boilerplate map");
-    __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
-    __ and_(ecx, Map::kElementsKindMask);
-    __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
-    __ Assert(equal, "Unexpected boilerplate elements kind");
-  }
-
-  // Only elements backing stores for non-COW arrays need to be copied.
-  Handle<FixedArrayBase> elements(object->elements());
-  bool has_elements = elements->length() > 0 &&
-      elements->map() != isolate()->heap()->fixed_cow_array_map();
-
-  // Increase the offset so that subsequent objects end up right after
-  // this object and its backing store.
-  int object_offset = *offset;
-  int object_size = object->map()->instance_size();
-  int elements_size = has_elements ? elements->Size() : 0;
-  int elements_offset = *offset + object_size;
-  if (create_allocation_site_info) {
-    elements_offset += AllocationSiteInfo::kSize;
-    *offset += AllocationSiteInfo::kSize;
-  }
-
-  *offset += object_size + elements_size;
-
-  // Copy object header.
-  ASSERT(object->properties()->length() == 0);
-  int inobject_properties = object->map()->inobject_properties();
-  int header_size = object_size - inobject_properties * kPointerSize;
-  for (int i = 0; i < header_size; i += kPointerSize) {
-    if (has_elements && i == JSObject::kElementsOffset) {
-      __ lea(ecx, Operand(result, elements_offset));
-    } else {
-      __ mov(ecx, FieldOperand(source, i));
-    }
-    __ mov(FieldOperand(result, object_offset + i), ecx);
-  }
-
-  // Copy in-object properties.
-  for (int i = 0; i < inobject_properties; i++) {
-    int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
-    Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
-                                          isolate());
-    if (value->IsJSObject()) {
-      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
-      __ lea(ecx, Operand(result, *offset));
-      __ mov(FieldOperand(result, total_offset), ecx);
-      __ LoadHeapObject(source, value_object);
-      EmitDeepCopy(value_object, result, source, offset,
-                   DONT_TRACK_ALLOCATION_SITE);
-    } else if (value->IsHeapObject()) {
-      __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
-      __ mov(FieldOperand(result, total_offset), ecx);
-    } else {
-      __ mov(FieldOperand(result, total_offset), Immediate(value));
-    }
-  }
-
-  // Build Allocation Site Info if desired
-  if (create_allocation_site_info) {
-    __ mov(FieldOperand(result, object_size),
-           Immediate(Handle<Map>(isolate()->heap()->
-                                 allocation_site_info_map())));
-    __ mov(FieldOperand(result, object_size + kPointerSize), source);
-  }
-
-  if (has_elements) {
-    // Copy elements backing store header.
-    __ LoadHeapObject(source, elements);
-    for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
-      __ mov(ecx, FieldOperand(source, i));
-      __ mov(FieldOperand(result, elements_offset + i), ecx);
-    }
-
-    // Copy elements backing store content.
-    int elements_length = elements->length();
-    if (elements->IsFixedDoubleArray()) {
-      Handle<FixedDoubleArray> double_array =
-          Handle<FixedDoubleArray>::cast(elements);
-      for (int i = 0; i < elements_length; i++) {
-        int64_t value = double_array->get_representation(i);
-        int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
-        int32_t value_high = static_cast<int32_t>(value >> 32);
-        int total_offset =
-            elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
-        __ mov(FieldOperand(result, total_offset), Immediate(value_low));
-        __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
-      }
-    } else if (elements->IsFixedArray()) {
-      Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
-      for (int i = 0; i < elements_length; i++) {
-        int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
-        Handle<Object> value(fast_elements->get(i), isolate());
-        if (value->IsJSObject()) {
-          Handle<JSObject> value_object = Handle<JSObject>::cast(value);
-          __ lea(ecx, Operand(result, *offset));
-          __ mov(FieldOperand(result, total_offset), ecx);
-          __ LoadHeapObject(source, value_object);
-          EmitDeepCopy(value_object, result, source, offset,
-                       DONT_TRACK_ALLOCATION_SITE);
-        } else if (value->IsHeapObject()) {
-          __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
-          __ mov(FieldOperand(result, total_offset), ecx);
-        } else {
-          __ mov(FieldOperand(result, total_offset), Immediate(value));
-        }
-      }
-    } else {
-      UNREACHABLE();
-    }
-  }
-}
-
-
-void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
-  ASSERT(ToRegister(instr->context()).is(esi));
-  int size = instr->hydrogen()->total_size();
-  ElementsKind boilerplate_elements_kind =
-      instr->hydrogen()->boilerplate()->GetElementsKind();
-
-  // Deopt if the literal boilerplate ElementsKind is of a type different than
-  // the expected one. The check isn't necessary if the boilerplate has already
-  // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
-  if (CanTransitionToMoreGeneralFastElementsKind(
-          boilerplate_elements_kind, true)) {
-    __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
-    __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
-    // Load the map's "bit field 2". We only need the first byte,
-    // but the following masking takes care of that anyway.
-    __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
-    // Retrieve elements_kind from bit field 2.
-    __ and_(ecx, Map::kElementsKindMask);
-    __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
-    DeoptimizeIf(not_equal, instr->environment());
-  }
-
-  // Allocate all objects that are part of the literal in one big
-  // allocation. This avoids multiple limit checks.
-  Label allocated, runtime_allocate;
-  __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
-  __ jmp(&allocated);
-
-  __ bind(&runtime_allocate);
-  __ push(Immediate(Smi::FromInt(size)));
-  CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
-
-  __ bind(&allocated);
-  int offset = 0;
-  __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
-  EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset,
-               instr->hydrogen()->allocation_site_mode());
-  ASSERT_EQ(size, offset);
-}
-
-
 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
   ASSERT(ToRegister(instr->context()).is(esi));
   Handle<FixedArray> literals(instr->environment()->closure()->literals());
@@ -5923,7 +6179,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
   Handle<SharedFunctionInfo> shared_info = instr->shared_info();
   bool pretenure = instr->hydrogen()->pretenure();
   if (!pretenure && shared_info->num_literals() == 0) {
-    FastNewClosureStub stub(shared_info->language_mode());
+    FastNewClosureStub stub(shared_info->language_mode(),
+                            shared_info->is_generator());
     __ push(Immediate(shared_info));
     CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
   } else {
index 3a38e32..362f091 100644 (file)
@@ -68,6 +68,7 @@ class LCodeGen BASE_EMBEDDED {
         osr_pc_offset_(-1),
         last_lazy_deopt_pc_(0),
         frame_is_built_(false),
+        x87_stack_depth_(0),
         safepoints_(info->zone()),
         resolver_(this),
         expected_safepoint_kind_(Safepoint::kSimple) {
@@ -102,10 +103,17 @@ class LCodeGen BASE_EMBEDDED {
     return Immediate(ToInteger32(LConstantOperand::cast(op)));
   }
 
-  Handle<Object> ToHandle(LConstantOperand* op) const;
+  // Support for non-sse2 (x87) floating point stack handling.
+  // These functions maintain the depth of the stack (either 0 or 1)
+  void PushX87DoubleOperand(Operand src);
+  void PushX87FloatOperand(Operand src);
+  void ReadX87Operand(Operand dst);
+  bool X87StackNonEmpty() const { return x87_stack_depth_ > 0; }
+  void PopX87();
+  void CurrentInstructionReturnsX87Result();
+  void FlushX87StackIfNecessary(LInstruction* instr);
 
-  // A utility for instructions that return floating point values on X87.
-  void HandleX87FPReturnValue(LInstruction* instr);
+  Handle<Object> ToHandle(LConstantOperand* op) const;
 
   // The operand denoting the second word (the one with a higher address) of
   // a double stack slot.
@@ -129,7 +137,8 @@ class LCodeGen BASE_EMBEDDED {
                             IntegerSignedness signedness);
 
   void DoDeferredTaggedToI(LTaggedToI* instr);
-  void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
+  void DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr);
+  void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
   void DoDeferredStackCheck(LStackCheck* instr);
   void DoDeferredRandom(LRandom* instr);
   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
@@ -281,15 +290,7 @@ class LCodeGen BASE_EMBEDDED {
                                 uint32_t offset,
                                 uint32_t additional_index = 0);
 
-  // Specific math operations - used from DoUnaryMathOperation.
-  void EmitIntegerMathAbs(LUnaryMathOperation* instr);
-  void DoMathAbs(LUnaryMathOperation* instr);
-  void DoMathFloor(LUnaryMathOperation* instr);
-  void DoMathSqrt(LUnaryMathOperation* instr);
-  void DoMathLog(LUnaryMathOperation* instr);
-  void DoMathTan(LUnaryMathOperation* instr);
-  void DoMathCos(LUnaryMathOperation* instr);
-  void DoMathSin(LUnaryMathOperation* instr);
+  void EmitIntegerMathAbs(LMathAbs* instr);
 
   // Support for recording safepoint and position information.
   void RecordSafepoint(LPointerMap* pointers,
@@ -315,6 +316,14 @@ class LCodeGen BASE_EMBEDDED {
       LEnvironment* env,
       NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED);
 
+  void EmitNumberUntagDNoSSE2(
+      Register input,
+      Register temp,
+      bool deoptimize_on_undefined,
+      bool deoptimize_on_minus_zero,
+      LEnvironment* env,
+      NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED);
+
   // Emits optimized code for typeof x == "y".  Modifies input register.
   // Returns the condition on which a final split to
   // true and false label should be made, to optimize fallthrough.
@@ -404,6 +413,7 @@ class LCodeGen BASE_EMBEDDED {
   int osr_pc_offset_;
   int last_lazy_deopt_pc_;
   bool frame_is_built_;
+  int x87_stack_depth_;
 
   // Builder that keeps track of safepoints in the code. The table
   // itself is emitted at the end of the generated code.
index b062ba5..6c7e375 100644 (file)
@@ -324,29 +324,61 @@ void LGapResolver::EmitMove(int index) {
     }
 
   } else if (source->IsDoubleRegister()) {
-    CpuFeatureScope scope(cgen_->masm(), SSE2);
-    XMMRegister src = cgen_->ToDoubleRegister(source);
-    if (destination->IsDoubleRegister()) {
-      XMMRegister dst = cgen_->ToDoubleRegister(destination);
-      __ movaps(dst, src);
+    if (CpuFeatures::IsSupported(SSE2)) {
+      CpuFeatureScope scope(cgen_->masm(), SSE2);
+      XMMRegister src = cgen_->ToDoubleRegister(source);
+      if (destination->IsDoubleRegister()) {
+        XMMRegister dst = cgen_->ToDoubleRegister(destination);
+        __ movaps(dst, src);
+      } else {
+        ASSERT(destination->IsDoubleStackSlot());
+        Operand dst = cgen_->ToOperand(destination);
+        __ movdbl(dst, src);
+      }
     } else {
+      // load from the register onto the stack, store in destination, which must
+      // be a double stack slot in the non-SSE2 case.
+      ASSERT(source->index() == 0);  // source is on top of the stack
       ASSERT(destination->IsDoubleStackSlot());
       Operand dst = cgen_->ToOperand(destination);
-      __ movdbl(dst, src);
+      cgen_->ReadX87Operand(dst);
     }
   } else if (source->IsDoubleStackSlot()) {
-    CpuFeatureScope scope(cgen_->masm(), SSE2);
-    ASSERT(destination->IsDoubleRegister() ||
-           destination->IsDoubleStackSlot());
-    Operand src = cgen_->ToOperand(source);
-    if (destination->IsDoubleRegister()) {
-      XMMRegister dst = cgen_->ToDoubleRegister(destination);
-      __ movdbl(dst, src);
+    if (CpuFeatures::IsSupported(SSE2)) {
+      CpuFeatureScope scope(cgen_->masm(), SSE2);
+      ASSERT(destination->IsDoubleRegister() ||
+             destination->IsDoubleStackSlot());
+      Operand src = cgen_->ToOperand(source);
+      if (destination->IsDoubleRegister()) {
+        XMMRegister dst = cgen_->ToDoubleRegister(destination);
+        __ movdbl(dst, src);
+      } else {
+        // We rely on having xmm0 available as a fixed scratch register.
+        Operand dst = cgen_->ToOperand(destination);
+        __ movdbl(xmm0, src);
+        __ movdbl(dst, xmm0);
+      }
     } else {
-      // We rely on having xmm0 available as a fixed scratch register.
-      Operand dst = cgen_->ToOperand(destination);
-      __ movdbl(xmm0, src);
-      __ movdbl(dst, xmm0);
+      // load from the stack slot on top of the floating point stack, and then
+      // store in destination. If destination is a double register, then it
+      // represents the top of the stack and nothing needs to be done.
+      if (destination->IsDoubleStackSlot()) {
+        Register tmp = EnsureTempRegister();
+        Operand src0 = cgen_->ToOperand(source);
+        Operand src1 = cgen_->HighOperand(source);
+        Operand dst0 = cgen_->ToOperand(destination);
+        Operand dst1 = cgen_->HighOperand(destination);
+        __ mov(tmp, src0);  // Then use tmp to copy source to destination.
+        __ mov(dst0, tmp);
+        __ mov(tmp, src1);
+        __ mov(dst1, tmp);
+      } else {
+        Operand src = cgen_->ToOperand(source);
+        if (cgen_->X87StackNonEmpty()) {
+          cgen_->PopX87();
+        }
+        cgen_->PushX87DoubleOperand(src);
+      }
     }
   } else {
     UNREACHABLE();
@@ -419,21 +451,19 @@ void LGapResolver::EmitSwap(int index) {
     __ movaps(xmm0, src);
     __ movaps(src, dst);
     __ movaps(dst, xmm0);
-
   } else if (source->IsDoubleRegister() || destination->IsDoubleRegister()) {
     CpuFeatureScope scope(cgen_->masm(), SSE2);
     // XMM register-memory swap.  We rely on having xmm0
     // available as a fixed scratch register.
     ASSERT(source->IsDoubleStackSlot() || destination->IsDoubleStackSlot());
     XMMRegister reg = cgen_->ToDoubleRegister(source->IsDoubleRegister()
-                                                  ? source
-                                                  : destination);
+                                              ? source
+                                              : destination);
     Operand other =
         cgen_->ToOperand(source->IsDoubleRegister() ? destination : source);
     __ movdbl(xmm0, other);
     __ movdbl(other, reg);
     __ movdbl(reg, Operand(xmm0));
-
   } else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) {
     CpuFeatureScope scope(cgen_->masm(), SSE2);
     // Double-width memory-to-memory.  Spill on demand to use a general
index 102515a..a7bb2d9 100644 (file)
@@ -91,6 +91,22 @@ void LInstruction::VerifyCall() {
 #endif
 
 
+bool LInstruction::HasDoubleRegisterResult() {
+  return HasResult() && result()->IsDoubleRegister();
+}
+
+
+bool LInstruction::HasDoubleRegisterInput() {
+  for (int i = 0; i < InputCount(); i++) {
+    LOperand* op = InputAt(i);
+    if (op->IsDoubleRegister()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
 void LInstruction::PrintTo(StringStream* stream) {
   stream->Add("%s ", this->Mnemonic());
 
@@ -304,29 +320,6 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
 }
 
 
-void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
-  stream->Add("/%s ", hydrogen()->OpName());
-  value()->PrintTo(stream);
-}
-
-
-void LMathExp::PrintDataTo(StringStream* stream) {
-  value()->PrintTo(stream);
-}
-
-
-void LMathPowHalf::PrintDataTo(StringStream* stream) {
-  stream->Add("/pow_half ");
-  value()->PrintTo(stream);
-}
-
-
-void LMathRound::PrintDataTo(StringStream* stream) {
-  stream->Add("/round ");
-  value()->PrintTo(stream);
-}
-
-
 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
   context()->PrintTo(stream);
   stream->Add("[%d]", slot_index());
@@ -542,6 +535,11 @@ LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
 }
 
 
+LOperand* LChunkBuilder::UseX87TopOfStack(HValue* value) {
+  return Use(value, ToUnallocated(x87tos));
+}
+
+
 LOperand* LChunkBuilder::UseRegister(HValue* value) {
   return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
 }
@@ -1187,62 +1185,105 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
 
 
 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
-  BuiltinFunctionId op = instr->op();
-  if (op == kMathLog) {
-    ASSERT(instr->representation().IsDouble());
-    ASSERT(instr->value()->representation().IsDouble());
-    LOperand* context = UseAny(instr->context());  // Not actually used.
-    LOperand* input = UseRegisterAtStart(instr->value());
-    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);
-    LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
-                                                                  input);
-    return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
-  } else {
-    LOperand* context = UseAny(instr->context());  // Deferred use by MathAbs.
-    LOperand* input = NULL;
-    if (op == kMathPowHalf) {
-      input = UseRegisterAtStart(instr->value());
-      LOperand* temp = TempRegister();
-      LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp);
-      return DefineSameAsFirst(result);
-    } else if (op == kMathRound) {
-      input = UseRegister(instr->value());
-      LOperand* temp = FixedTemp(xmm4);
-      LMathRound* result = new(zone()) LMathRound(context, input, temp);
-      return AssignEnvironment(DefineAsRegister(result));
-    } else {
-      input = UseRegisterAtStart(instr->value());
-    }
-    LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
-                                                                  input);
-    switch (op) {
-      case kMathAbs:
-        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
-      case kMathFloor:
-        return AssignEnvironment(DefineAsRegister(result));
-      case kMathSqrt:
-        return DefineSameAsFirst(result);
-      default:
-        UNREACHABLE();
-        return NULL;
-    }
+  switch (instr->op()) {
+    case kMathFloor: return DoMathFloor(instr);
+    case kMathRound: return DoMathRound(instr);
+    case kMathAbs: return DoMathAbs(instr);
+    case kMathLog: return DoMathLog(instr);
+    case kMathSin: return DoMathSin(instr);
+    case kMathCos: return DoMathCos(instr);
+    case kMathTan: return DoMathTan(instr);
+    case kMathExp: return DoMathExp(instr);
+    case kMathSqrt: return DoMathSqrt(instr);
+    case kMathPowHalf: return DoMathPowHalf(instr);
+    default:
+      UNREACHABLE();
+      return NULL;
   }
 }
 
 
+LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathFloor* result = new(zone()) LMathFloor(input);
+  return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
+  LOperand* context = UseAny(instr->context());
+  LOperand* input = UseRegister(instr->value());
+  LOperand* temp = FixedTemp(xmm4);
+  LMathRound* result = new(zone()) LMathRound(context, input, temp);
+  return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+  LOperand* context = UseAny(instr->context());  // Deferred use.
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathAbs* result = new(zone()) LMathAbs(context, input);
+  return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
+  ASSERT(instr->representation().IsDouble());
+  ASSERT(instr->value()->representation().IsDouble());
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathLog* result = new(zone()) LMathLog(input);
+  return DefineSameAsFirst(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), xmm1);
+  LMathSin* result = new(zone()) LMathSin(input);
+  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), xmm1);
+  LMathCos* result = new(zone()) LMathCos(input);
+  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), xmm1);
+  LMathTan* result = new(zone()) LMathTan(input);
+  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
+  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);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathSqrt* result = new(zone()) LMathSqrt(input);
+  return DefineSameAsFirst(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
+  LOperand* context = UseAny(instr->context());
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LOperand* temp = TempRegister();
+  LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp);
+  return DefineSameAsFirst(result);
+}
+
+
 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
   ASSERT(instr->key()->representation().IsTagged());
   LOperand* context = UseFixed(instr->context(), esi);
@@ -1861,20 +1902,33 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
                        ? TempRegister()
                        : NULL;
       LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
-      return AssignEnvironment(DefineAsRegister(res));
+      if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+        return AssignEnvironment(DefineAsRegister(res));
+      } else {
+        return AssignEnvironment(DefineX87TOS(res));
+      }
     } else {
       ASSERT(to.IsInteger32());
-      LOperand* value = UseRegister(instr->value());
       if (instr->value()->type().IsSmi()) {
+        LOperand* value = UseRegister(instr->value());
         return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
       } else {
         bool truncating = instr->CanTruncateToInt32();
-        LOperand* xmm_temp =
-            (truncating && CpuFeatures::IsSupported(SSE3))
-            ? NULL
-            : FixedTemp(xmm1);
-        LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
-        return AssignEnvironment(DefineSameAsFirst(res));
+        if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+          LOperand* value = UseRegister(instr->value());
+          LOperand* xmm_temp =
+              (truncating && CpuFeatures::IsSupported(SSE3))
+              ? NULL
+              : FixedTemp(xmm1);
+          LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
+          return AssignEnvironment(DefineSameAsFirst(res));
+        } else {
+          LOperand* value = UseFixed(instr->value(), ecx);
+          LTaggedToINoSSE2* res =
+              new(zone()) LTaggedToINoSSE2(value, TempRegister(),
+                                           TempRegister(), TempRegister());
+          return AssignEnvironment(DefineFixed(res, ecx));
+        }
       }
     }
   } else if (from.IsDouble()) {
@@ -1947,7 +2001,7 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
 LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
   LUnallocated* temp = TempRegister();
   LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
-  return AssignEnvironment(Define(result, temp));
+  return AssignEnvironment(result);
 }
 
 
@@ -1992,12 +2046,20 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
     return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
   } else {
     ASSERT(input_rep.IsTagged());
-    LOperand* reg = UseFixed(value, eax);
-    // Register allocator doesn't (yet) support allocation of double
-    // temps. Reserve xmm1 explicitly.
-    LOperand* temp = FixedTemp(xmm1);
-    LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
-    return AssignEnvironment(DefineFixed(result, eax));
+    if (CpuFeatures::IsSupported(SSE2)) {
+      LOperand* reg = UseFixed(value, eax);
+      // Register allocator doesn't (yet) support allocation of double
+      // temps. Reserve xmm1 explicitly.
+      LOperand* temp = FixedTemp(xmm1);
+      LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
+      return AssignEnvironment(DefineFixed(result, eax));
+    } else {
+      LOperand* value = UseRegister(instr->value());
+      LClampTToUint8NoSSE2* res =
+          new(zone()) LClampTToUint8NoSSE2(value, TempRegister(),
+                                           TempRegister(), TempRegister());
+      return AssignEnvironment(DefineFixed(res, ecx));
+    }
   }
 }
 
@@ -2018,10 +2080,13 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
     return DefineAsRegister(new(zone()) LConstantI);
   } else if (r.IsDouble()) {
     double value = instr->DoubleValue();
-    LOperand* temp = (BitCast<uint64_t, double>(value) != 0)
-        ? TempRegister()
-        : NULL;
-    return DefineAsRegister(new(zone()) LConstantD(temp));
+    bool value_is_zero = BitCast<uint64_t, double>(value) == 0;
+    if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+      LOperand* temp = value_is_zero ? NULL : TempRegister();
+      return DefineAsRegister(new(zone()) LConstantD(temp));
+    } else {
+      return DefineX87TOS(new(zone()) LConstantD(NULL));
+    }
   } else if (r.IsTagged()) {
     return DefineAsRegister(new(zone()) LConstantT);
   } else {
@@ -2190,6 +2255,27 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
 }
 
 
+LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) {
+  ElementsKind elements_kind = instr->elements_kind();
+
+  // 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;
+  if (val_is_fixed_register) {
+    return UseFixed(instr->value(), eax);
+  }
+
+  if (!CpuFeatures::IsSafeForSnapshot(SSE2) &&
+      IsDoubleOrFloatElementsKind(elements_kind)) {
+    return UseRegisterAtStart(instr->value());
+  }
+
+  return UseRegister(instr->value());
+}
+
+
 LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
   if (!instr->is_external()) {
     ASSERT(instr->elements()->representation().IsTagged());
@@ -2198,7 +2284,12 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
 
     if (instr->value()->representation().IsDouble()) {
       LOperand* object = UseRegisterAtStart(instr->elements());
-      LOperand* val = UseTempRegister(instr->value());
+      LOperand* val = NULL;
+      if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+        val = UseRegisterAtStart(instr->value());
+      } else if (!instr->IsConstantHoleStore()) {
+        val = UseX87TopOfStack(instr->value());
+      }
       LOperand* key = UseRegisterOrConstantAtStart(instr->key());
 
       return new(zone()) LStoreKeyed(object, key, val);
@@ -2228,15 +2319,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
   ASSERT(instr->elements()->representation().IsExternal());
 
   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;
-
-  LOperand* val = val_is_fixed_register
-      ? UseFixed(instr->value(), eax)
-      : UseRegister(instr->value());
+  LOperand* val = GetStoreKeyedValueOperand(instr);
   bool clobbers_key = ExternalArrayOpRequiresTemp(
       instr->key()->representation(), elements_kind);
   LOperand* key = clobbers_key
@@ -2400,13 +2483,6 @@ LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
-  LOperand* context = UseFixed(instr->context(), esi);
-  return MarkAsCall(
-      DefineFixed(new(zone()) LFastLiteral(context), eax), instr);
-}
-
-
 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
   LOperand* context = UseFixed(instr->context(), esi);
   return MarkAsCall(
index 1c490bb..10272fd 100644 (file)
@@ -74,6 +74,7 @@ class LCodeGen;
   V(ClampDToUint8)                              \
   V(ClampIToUint8)                              \
   V(ClampTToUint8)                              \
+  V(ClampTToUint8NoSSE2)                        \
   V(ClassOfTestAndBranch)                       \
   V(CmpIDAndBranch)                             \
   V(CmpObjectEqAndBranch)                       \
@@ -91,7 +92,6 @@ class LCodeGen;
   V(DoubleToI)                                  \
   V(DummyUse)                                   \
   V(ElementsKind)                               \
-  V(FastLiteral)                                \
   V(FixedArrayBaseLength)                       \
   V(FunctionLiteral)                            \
   V(GetCachedArrayIndex)                        \
@@ -128,11 +128,18 @@ class LCodeGen;
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MapEnumLength)                              \
+  V(MathAbs)                                    \
+  V(MathCos)                                    \
   V(MathExp)                                    \
+  V(MathFloor)                                  \
   V(MathFloorOfDiv)                             \
+  V(MathLog)                                    \
   V(MathMinMax)                                 \
   V(MathPowHalf)                                \
   V(MathRound)                                  \
+  V(MathSin)                                    \
+  V(MathSqrt)                                   \
+  V(MathTan)                                    \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -167,6 +174,7 @@ class LCodeGen;
   V(StringLength)                               \
   V(SubI)                                       \
   V(TaggedToI)                                  \
+  V(TaggedToINoSSE2)                            \
   V(ThisFunction)                               \
   V(Throw)                                      \
   V(ToFastProperties)                           \
@@ -174,7 +182,6 @@ class LCodeGen;
   V(TrapAllocationMemento)                      \
   V(Typeof)                                     \
   V(TypeofIsAndBranch)                          \
-  V(UnaryMathOperation)                         \
   V(UnknownOSRValue)                            \
   V(ValueOf)                                    \
   V(ForInPrepareMap)                            \
@@ -265,6 +272,9 @@ class LInstruction: public ZoneObject {
   virtual bool HasResult() const = 0;
   virtual LOperand* result() = 0;
 
+  bool HasDoubleRegisterResult();
+  bool HasDoubleRegisterInput();
+
   LOperand* FirstInput() { return InputAt(0); }
   LOperand* Output() { return HasResult() ? result() : NULL; }
 
@@ -645,9 +655,39 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
 };
 
 
-class LUnaryMathOperation: public LTemplateInstruction<1, 2, 0> {
+class LMathFloor: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathFloor(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathRound: public LTemplateInstruction<1, 2, 1> {
+ public:
+  LMathRound(LOperand* context, LOperand* value, LOperand* temp) {
+    inputs_[1] = context;
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* context() { return inputs_[1]; }
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathAbs: public LTemplateInstruction<1, 2, 0> {
  public:
-  LUnaryMathOperation(LOperand* context, LOperand* value) {
+  LMathAbs(LOperand* context, LOperand* value) {
     inputs_[1] = context;
     inputs_[0] = value;
   }
@@ -655,11 +695,56 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 2, 0> {
   LOperand* context() { return inputs_[1]; }
   LOperand* value() { return inputs_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
+  DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
   DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
 
-  virtual void PrintDataTo(StringStream* stream);
-  BuiltinFunctionId op() const { return hydrogen()->op(); }
+
+class LMathLog: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathLog(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathSin: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathSin(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathSin, "math-sin")
+};
+
+
+class LMathCos: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathCos(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathCos, "math-cos")
+};
+
+
+class LMathTan: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathTan(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathTan, "math-tan")
 };
 
 
@@ -679,32 +764,24 @@ class LMathExp: public LTemplateInstruction<1, 1, 2> {
   LOperand* temp2() { return temps_[1]; }
 
   DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
-
-  virtual void PrintDataTo(StringStream* stream);
 };
 
 
-class LMathPowHalf: public LTemplateInstruction<1, 2, 1> {
+class LMathSqrt: public LTemplateInstruction<1, 1, 0> {
  public:
-  LMathPowHalf(LOperand* context, LOperand* value, LOperand* temp) {
-    inputs_[1] = context;
+  explicit LMathSqrt(LOperand* value) {
     inputs_[0] = value;
-    temps_[0] = temp;
   }
 
-  LOperand* context() { return inputs_[1]; }
   LOperand* value() { return inputs_[0]; }
-  LOperand* temp() { return temps_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
-
-  virtual void PrintDataTo(StringStream* stream);
+  DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
 };
 
 
-class LMathRound: public LTemplateInstruction<1, 2, 1> {
+class LMathPowHalf: public LTemplateInstruction<1, 2, 1> {
  public:
-  LMathRound(LOperand* context, LOperand* value, LOperand* temp) {
+  LMathPowHalf(LOperand* context, LOperand* value, LOperand* temp) {
     inputs_[1] = context;
     inputs_[0] = value;
     temps_[0] = temp;
@@ -714,10 +791,7 @@ class LMathRound: public LTemplateInstruction<1, 2, 1> {
   LOperand* value() { return inputs_[0]; }
   LOperand* temp() { return temps_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
-  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
-
-  virtual void PrintDataTo(StringStream* stream);
+  DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
 };
 
 
@@ -1088,6 +1162,10 @@ class LConstantD: public LTemplateInstruction<1, 0, 1> {
     temps_[0] = temp;
   }
 
+  virtual bool ClobbersDoubleRegisters() const {
+    return false;
+  }
+
   LOperand* temp() { return temps_[0]; }
 
   DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
@@ -1296,7 +1374,7 @@ class LMathMinMax: public LTemplateInstruction<1, 2, 0> {
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
   DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
 };
 
@@ -2018,6 +2096,31 @@ class LTaggedToI: public LTemplateInstruction<1, 1, 1> {
 };
 
 
+// Truncating conversion from a tagged value to an int32.
+class LTaggedToINoSSE2: public LTemplateInstruction<1, 1, 3> {
+ public:
+  LTaggedToINoSSE2(LOperand* value,
+                   LOperand* temp1,
+                   LOperand* temp2,
+                   LOperand* temp3) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+    temps_[2] = temp3;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* scratch() { return temps_[0]; }
+  LOperand* scratch2() { return temps_[1]; }
+  LOperand* scratch3() { return temps_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TaggedToINoSSE2, "tagged-to-i-nosse2")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+
+  bool truncating() { return hydrogen()->CanTruncateToInt32(); }
+};
+
+
 class LSmiTag: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LSmiTag(LOperand* value) {
@@ -2040,6 +2143,10 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 1> {
   LOperand* value() { return inputs_[0]; }
   LOperand* temp() { return temps_[0]; }
 
+  virtual bool ClobbersDoubleRegisters() const {
+    return false;
+  }
+
   DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
   DECLARE_HYDROGEN_ACCESSOR(Change);
 };
@@ -2313,7 +2420,7 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> {
 };
 
 
-class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> {
+class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> {
  public:
   explicit LCheckPrototypeMaps(LOperand* temp)  {
     temps_[0] = temp;
@@ -2380,6 +2487,30 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> {
 };
 
 
+// Truncating conversion from a tagged value to an int32.
+class LClampTToUint8NoSSE2: public LTemplateInstruction<1, 1, 3> {
+ public:
+  LClampTToUint8NoSSE2(LOperand* unclamped,
+                       LOperand* temp1,
+                       LOperand* temp2,
+                       LOperand* temp3) {
+    inputs_[0] = unclamped;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+    temps_[2] = temp3;
+  }
+
+  LOperand* unclamped() { return inputs_[0]; }
+  LOperand* scratch() { return temps_[0]; }
+  LOperand* scratch2() { return temps_[1]; }
+  LOperand* scratch3() { return temps_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8NoSSE2,
+                               "clamp-t-to-uint8-nosse2")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+};
+
+
 class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
  public:
   explicit LCheckNonSmi(LOperand* value) {
@@ -2424,19 +2555,6 @@ class LAllocate: public LTemplateInstruction<1, 2, 1> {
 };
 
 
-class LFastLiteral: public LTemplateInstruction<1, 1, 0> {
- public:
-  explicit LFastLiteral(LOperand* context) {
-    inputs_[0] = context;
-  }
-
-  LOperand* context() { return inputs_[0]; }
-
-  DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
-  DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
-};
-
-
 class LArrayLiteral: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LArrayLiteral(LOperand* context) {
@@ -2712,6 +2830,17 @@ class LChunkBuilder BASE_EMBEDDED {
   static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
   static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
 
+  LInstruction* DoMathFloor(HUnaryMathOperation* instr);
+  LInstruction* DoMathRound(HUnaryMathOperation* instr);
+  LInstruction* DoMathAbs(HUnaryMathOperation* instr);
+  LInstruction* DoMathLog(HUnaryMathOperation* instr);
+  LInstruction* DoMathSin(HUnaryMathOperation* instr);
+  LInstruction* DoMathCos(HUnaryMathOperation* instr);
+  LInstruction* DoMathTan(HUnaryMathOperation* instr);
+  LInstruction* DoMathExp(HUnaryMathOperation* instr);
+  LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
+  LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
+
  private:
   enum Status {
     UNUSED,
@@ -2742,6 +2871,7 @@ class LChunkBuilder BASE_EMBEDDED {
   MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register);
   MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value,
                                            XMMRegister fixed_register);
+  MUST_USE_RESULT LOperand* UseX87TopOfStack(HValue* value);
 
   // A value that is guaranteed to be allocated to a register.
   // Operand created by UseRegister is guaranteed to be live until the end of
@@ -2827,6 +2957,8 @@ class LChunkBuilder BASE_EMBEDDED {
   LInstruction* DoArithmeticT(Token::Value op,
                               HArithmeticBinaryOperation* instr);
 
+  LOperand* GetStoreKeyedValueOperand(HStoreKeyed* instr);
+
   LPlatformChunk* chunk_;
   CompilationInfo* info_;
   HGraph* const graph_;
index 3d3dabc..3228e83 100644 (file)
@@ -1024,69 +1024,65 @@ void MacroAssembler::ThrowUncatchable(Register value) {
 
 
 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
-                                            Register scratch,
+                                            Register scratch1,
+                                            Register scratch2,
                                             Label* miss) {
   Label same_contexts;
 
-  ASSERT(!holder_reg.is(scratch));
+  ASSERT(!holder_reg.is(scratch1));
+  ASSERT(!holder_reg.is(scratch2));
+  ASSERT(!scratch1.is(scratch2));
 
   // Load current lexical context from the stack frame.
-  mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset));
+  mov(scratch1, Operand(ebp, StandardFrameConstants::kContextOffset));
 
   // When generating debug code, make sure the lexical context is set.
   if (emit_debug_code()) {
-    cmp(scratch, Immediate(0));
+    cmp(scratch1, Immediate(0));
     Check(not_equal, "we should not have an empty lexical context");
   }
   // Load the native context of the current context.
   int offset =
       Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
-  mov(scratch, FieldOperand(scratch, offset));
-  mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
+  mov(scratch1, FieldOperand(scratch1, offset));
+  mov(scratch1, FieldOperand(scratch1, GlobalObject::kNativeContextOffset));
 
   // Check the context is a native context.
   if (emit_debug_code()) {
-    push(scratch);
     // Read the first word and compare to native_context_map.
-    mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
-    cmp(scratch, isolate()->factory()->native_context_map());
+    cmp(FieldOperand(scratch1, HeapObject::kMapOffset),
+        isolate()->factory()->native_context_map());
     Check(equal, "JSGlobalObject::native_context should be a native context.");
-    pop(scratch);
   }
 
   // Check if both contexts are the same.
-  cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
+  cmp(scratch1, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
   j(equal, &same_contexts);
 
   // Compare security tokens, save holder_reg on the stack so we can use it
   // as a temporary register.
   //
-  // TODO(119): avoid push(holder_reg)/pop(holder_reg)
-  push(holder_reg);
   // Check that the security token in the calling global object is
   // compatible with the security token in the receiving global
   // object.
-  mov(holder_reg,
+  mov(scratch2,
       FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
 
   // Check the context is a native context.
   if (emit_debug_code()) {
-    cmp(holder_reg, isolate()->factory()->null_value());
+    cmp(scratch2, isolate()->factory()->null_value());
     Check(not_equal, "JSGlobalProxy::context() should not be null.");
 
-    push(holder_reg);
     // Read the first word and compare to native_context_map(),
-    mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
-    cmp(holder_reg, isolate()->factory()->native_context_map());
+    cmp(FieldOperand(scratch2, HeapObject::kMapOffset),
+        isolate()->factory()->native_context_map());
     Check(equal, "JSGlobalObject::native_context should be a native context.");
-    pop(holder_reg);
   }
 
   int token_offset = Context::kHeaderSize +
                      Context::SECURITY_TOKEN_INDEX * kPointerSize;
-  mov(scratch, FieldOperand(scratch, token_offset));
-  cmp(scratch, FieldOperand(holder_reg, token_offset));
-  pop(holder_reg);
+  mov(scratch1, FieldOperand(scratch1, token_offset));
+  cmp(scratch1, FieldOperand(scratch2, token_offset));
   j(not_equal, miss);
 
   bind(&same_contexts);
@@ -2522,6 +2518,28 @@ void MacroAssembler::Ret(int bytes_dropped, Register scratch) {
 }
 
 
+void MacroAssembler::VerifyX87StackDepth(uint32_t depth) {
+  // Make sure the floating point stack is either empty or has depth items.
+  ASSERT(depth <= 7);
+
+  // The top-of-stack (tos) is 7 if there is one item pushed.
+  int tos = (8 - depth) % 8;
+  const int kTopMask = 0x3800;
+  push(eax);
+  fwait();
+  fnstsw_ax();
+  and_(eax, kTopMask);
+  shr(eax, 11);
+  cmp(eax, Immediate(tos));
+  Label all_ok;
+  j(equal, &all_ok);
+  Check(equal, "Unexpected FPU stack depth after instruction");
+  bind(&all_ok);
+  fnclex();
+  pop(eax);
+}
+
+
 void MacroAssembler::Drop(int stack_elements) {
   if (stack_elements > 0) {
     add(esp, Immediate(stack_elements * kPointerSize));
index b3dae73..159ae6e 100644 (file)
@@ -548,7 +548,8 @@ class MacroAssembler: public Assembler {
   // on access to global objects across environments. The holder register
   // is left untouched, but the scratch register is clobbered.
   void CheckAccessGlobalProxy(Register holder_reg,
-                              Register scratch,
+                              Register scratch1,
+                              Register scratch2,
                               Label* miss);
 
   void GetNumberHash(Register r0, Register scratch);
@@ -806,6 +807,8 @@ class MacroAssembler: public Assembler {
     return code_object_;
   }
 
+  // Insert code to verify that the x87 stack has the specified depth (0-7)
+  void VerifyX87StackDepth(uint32_t depth);
 
   // ---------------------------------------------------------------------------
   // StatsCounter support
index cb4b4a7..cb3c68e 100644 (file)
@@ -726,33 +726,54 @@ void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
 }
 
 
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+static void GenerateCheckPropertyCell(MacroAssembler* masm,
+                                      Handle<GlobalObject> global,
+                                      Handle<Name> name,
+                                      Register scratch,
+                                      Label* miss) {
+  Handle<JSGlobalPropertyCell> cell =
+      GlobalObject::EnsurePropertyCell(global, name);
+  ASSERT(cell->value()->IsTheHole());
+  Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
+  if (Serializer::enabled()) {
+    __ mov(scratch, Immediate(cell));
+    __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+           Immediate(the_hole));
+  } else {
+    __ cmp(Operand::Cell(cell), Immediate(the_hole));
+  }
+  __ j(not_equal, miss);
+}
+
+
 // Both name_reg and receiver_reg are preserved on jumps to miss_label,
 // but may be destroyed if store is successful.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
-                                      Handle<JSObject> object,
-                                      LookupResult* lookup,
-                                      Handle<Map> transition,
-                                      Handle<Name> name,
-                                      Register receiver_reg,
-                                      Register name_reg,
-                                      Register value_reg,
-                                      Register scratch1,
-                                      Register scratch2,
-                                      Label* miss_label,
-                                      Label* miss_restore_name) {
+void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+                                           Handle<JSObject> object,
+                                           LookupResult* lookup,
+                                           Handle<Map> transition,
+                                           Handle<Name> name,
+                                           Register receiver_reg,
+                                           Register name_reg,
+                                           Register value_reg,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           Label* miss_label,
+                                           Label* miss_restore_name) {
   // Check that the map of the object hasn't changed.
-  CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
-                                             : REQUIRE_EXACT_MAP;
   __ CheckMap(receiver_reg, Handle<Map>(object->map()),
-              miss_label, DO_SMI_CHECK, mode);
+              miss_label, DO_SMI_CHECK, REQUIRE_EXACT_MAP);
 
   // Perform global security token check if needed.
   if (object->IsJSGlobalProxy()) {
-    __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
+    __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
   }
 
   // Check that we are allowed to write this.
-  if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
+  if (object->GetPrototype()->IsJSObject()) {
     JSObject* holder;
     // holder == object indicates that no property was found.
     if (lookup->holder() != *object) {
@@ -771,12 +792,18 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     // If no property was found, and the holder (the last object in the
     // prototype chain) is in slow mode, we need to do a negative lookup on the
     // holder.
-    if (lookup->holder() == *object &&
-        !holder->HasFastProperties() &&
-        !holder->IsJSGlobalProxy() &&
-        !holder->IsJSGlobalObject()) {
-      GenerateDictionaryNegativeLookup(
-          masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+    if (lookup->holder() == *object) {
+      if (holder->IsJSGlobalObject()) {
+        GenerateCheckPropertyCell(
+            masm,
+            Handle<GlobalObject>(GlobalObject::cast(holder)),
+            name,
+            scratch1,
+            miss_restore_name);
+      } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+        GenerateDictionaryNegativeLookup(
+            masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+      }
     }
   }
 
@@ -785,7 +812,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
   // Perform map transition for the receiver if necessary.
-  if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
+  if (object->map()->unused_property_fields() == 0) {
     // The properties must be extended before we can store the value.
     // We jump to a runtime call that extends the properties array.
     __ pop(scratch1);  // Return address.
@@ -801,33 +828,29 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     return;
   }
 
-  int index;
-  if (!transition.is_null()) {
-    // Update the map of the object.
-    __ mov(scratch1, Immediate(transition));
-    __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
+  // Update the map of the object.
+  __ mov(scratch1, Immediate(transition));
+  __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
 
-    // Update the write barrier for the map field and pass the now unused
-    // name_reg as scratch register.
-    __ RecordWriteField(receiver_reg,
-                        HeapObject::kMapOffset,
-                        scratch1,
-                        name_reg,
-                        kDontSaveFPRegs,
-                        OMIT_REMEMBERED_SET,
-                        OMIT_SMI_CHECK);
-    index = transition->instance_descriptors()->GetFieldIndex(
-        transition->LastAdded());
-  } else {
-    index = lookup->GetFieldIndex().field_index();
-  }
+  // Update the write barrier for the map field and pass the now unused
+  // name_reg as scratch register.
+  __ RecordWriteField(receiver_reg,
+                      HeapObject::kMapOffset,
+                      scratch1,
+                      name_reg,
+                      kDontSaveFPRegs,
+                      OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
 
+  int index = transition->instance_descriptors()->GetFieldIndex(
+      transition->LastAdded());
 
   // Adjust for the number of properties stored in the object. Even in the
   // face of a transition we can use the old map here because the size of the
   // object and the number of in-object properties is not going to change.
   index -= object->map()->inobject_properties();
 
+  // TODO(verwaest): Share this code as a code stub.
   if (index < 0) {
     // Set the property straight into the object.
     int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -864,26 +887,71 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
 }
 
 
-// Generate code to check that a global property cell is empty. Create
-// the property cell at compilation time if no cell exists for the
-// property.
-static void GenerateCheckPropertyCell(MacroAssembler* masm,
-                                      Handle<GlobalObject> global,
-                                      Handle<Name> name,
-                                      Register scratch,
-                                      Label* miss) {
-  Handle<JSGlobalPropertyCell> cell =
-      GlobalObject::EnsurePropertyCell(global, name);
-  ASSERT(cell->value()->IsTheHole());
-  Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
-  if (Serializer::enabled()) {
-    __ mov(scratch, Immediate(cell));
-    __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
-           Immediate(the_hole));
+// Both name_reg and receiver_reg are preserved on jumps to miss_label,
+// but may be destroyed if store is successful.
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+                                      Handle<JSObject> object,
+                                      LookupResult* lookup,
+                                      Register receiver_reg,
+                                      Register name_reg,
+                                      Register value_reg,
+                                      Register scratch1,
+                                      Register scratch2,
+                                      Label* miss_label) {
+  // Check that the map of the object hasn't changed.
+  __ CheckMap(receiver_reg, Handle<Map>(object->map()),
+              miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+
+  // Perform global security token check if needed.
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+  int index = lookup->GetFieldIndex().field_index();
+
+  // Adjust for the number of properties stored in the object. Even in the
+  // face of a transition we can use the old map here because the size of the
+  // object and the number of in-object properties is not going to change.
+  index -= object->map()->inobject_properties();
+
+  // TODO(verwaest): Share this code as a code stub.
+  if (index < 0) {
+    // Set the property straight into the object.
+    int offset = object->map()->instance_size() + (index * kPointerSize);
+    __ mov(FieldOperand(receiver_reg, offset), value_reg);
+
+    // Update the write barrier for the array address.
+    // Pass the value being stored in the now unused name_reg.
+    __ mov(name_reg, value_reg);
+    __ RecordWriteField(receiver_reg,
+                        offset,
+                        name_reg,
+                        scratch1,
+                        kDontSaveFPRegs);
   } else {
-    __ cmp(Operand::Cell(cell), Immediate(the_hole));
+    // Write to the properties array.
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
+    // Get the properties array (optimistically).
+    __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
+    __ mov(FieldOperand(scratch1, offset), eax);
+
+    // Update the write barrier for the array address.
+    // Pass the value being stored in the now unused name_reg.
+    __ mov(name_reg, value_reg);
+    __ RecordWriteField(scratch1,
+                        offset,
+                        name_reg,
+                        receiver_reg,
+                        kDontSaveFPRegs);
   }
-  __ j(not_equal, miss);
+
+  // Return the value (register eax).
+  ASSERT(value_reg.is(eax));
+  __ ret(0);
 }
 
 
@@ -972,10 +1040,6 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
     } else {
       bool in_new_space = heap()->InNewSpace(*prototype);
       Handle<Map> current_map(current->map());
-      if (in_new_space) {
-        // Save the map in scratch1 for later.
-        __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
-      }
       if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
         __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
                     ALLOW_ELEMENT_TRANSITION_MAPS);
@@ -985,8 +1049,14 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
       // the map check so that we know that the object is actually a global
       // object.
       if (current->IsJSGlobalProxy()) {
-        __ CheckAccessGlobalProxy(reg, scratch2, miss);
+        __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
       }
+
+      if (in_new_space) {
+        // Save the map in scratch1 for later.
+        __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
+      }
+
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
       if (in_new_space) {
@@ -1020,7 +1090,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
   // Perform security check for access to the global object.
   ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
   if (holder->IsJSGlobalProxy()) {
-    __ CheckAccessGlobalProxy(reg, scratch1, miss);
+    __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
   }
 
   // If we've skipped any global objects, it's not enough to verify that
@@ -1111,7 +1181,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     Handle<GlobalObject> global) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
+  HandlerFrontendHeader(object, receiver(), last, name, &miss);
 
   // If the last object in the prototype chain is a global object,
   // check that the global property cell is empty.
@@ -1119,13 +1189,6 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
   }
 
-  if (!last->HasFastProperties()) {
-    __ mov(scratch2(), FieldOperand(reg, HeapObject::kMapOffset));
-    __ mov(scratch2(), FieldOperand(scratch2(), Map::kPrototypeOffset));
-    __ cmp(scratch2(), isolate()->factory()->null_value());
-    __ j(not_equal, &miss);
-  }
-
   HandlerFrontendFooter(success, &miss);
 }
 
@@ -2657,7 +2720,7 @@ Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
 
   // Perform global security token check if needed.
   if (object->IsJSGlobalProxy()) {
-    __ CheckAccessGlobalProxy(edx, ebx, &miss);
+    __ CheckAccessGlobalProxy(receiver(), scratch1(), scratch2(), &miss);
   }
 
   // Stub never generated for non-global objects that require access
index 515c6f7..3c33e4f 100644 (file)
@@ -1586,7 +1586,7 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
   switch (lookup->type()) {
     case FIELD:
       return isolate()->stub_cache()->ComputeStoreField(
-          name, receiver, lookup, Handle<Map>::null(), strict_mode);
+          name, receiver, lookup, strict_mode);
     case NORMAL:
       if (receiver->IsGlobalObject()) {
         // The stub generated for the global object picks the value directly
@@ -1644,7 +1644,7 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
 
       if (details.type() != FIELD || details.attributes() != NONE) break;
 
-      return isolate()->stub_cache()->ComputeStoreField(
+      return isolate()->stub_cache()->ComputeStoreTransition(
           name, receiver, lookup, transition, strict_mode);
     }
     case NONEXISTENT:
@@ -1987,7 +1987,7 @@ Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
   switch (lookup->type()) {
     case FIELD:
       return isolate()->stub_cache()->ComputeKeyedStoreField(
-          name, receiver, lookup, Handle<Map>::null(), strict_mode);
+          name, receiver, lookup, strict_mode);
     case TRANSITION: {
       // Explicitly pass in the receiver map since LookupForWrite may have
       // stored something else than the receiver in the holder.
@@ -1999,7 +1999,7 @@ Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
       PropertyDetails details = target_descriptors->GetDetails(descriptor);
 
       if (details.type() == FIELD && details.attributes() == NONE) {
-        return isolate()->stub_cache()->ComputeKeyedStoreField(
+        return isolate()->stub_cache()->ComputeKeyedStoreTransition(
             name, receiver, lookup, transition, strict_mode);
       }
       // fall through.
@@ -2386,8 +2386,7 @@ RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) {
     ic.patch(*code);
   }
 
-  Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
-      isolate->thread_local_top()->context_->builtins(), isolate);
+  Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
   Object* builtin = NULL;  // Initialization calms down the compiler.
   switch (op) {
     case Token::SUB:
@@ -2524,8 +2523,7 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
     }
   }
 
-  Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
-      isolate->thread_local_top()->context_->builtins(), isolate);
+  Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
   Object* builtin = NULL;  // Initialization calms down the compiler.
   switch (op) {
     case Token::ADD:
index 0415519..ca2c025 100644 (file)
@@ -371,6 +371,12 @@ Isolate::PerIsolateThreadData*
 
 Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThisThread() {
   ThreadId thread_id = ThreadId::Current();
+  return FindPerThreadDataForThread(thread_id);
+}
+
+
+Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThread(
+    ThreadId thread_id) {
   PerIsolateThreadData* per_thread = NULL;
   {
     ScopedLock lock(process_wide_mutex_);
@@ -1140,7 +1146,7 @@ void Isolate::PrintCurrentStackTrace(FILE* out) {
         Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
     if (line->length() > 0) {
       line->PrintOn(out);
-      fprintf(out, "\n");
+      PrintF(out, "\n");
     }
   }
 }
@@ -1213,6 +1219,7 @@ bool Isolate::IsErrorObject(Handle<Object> obj) {
   return false;
 }
 
+static int fatal_exception_depth = 0;
 
 void Isolate::DoThrow(Object* exception, MessageLocation* location) {
   ASSERT(!has_pending_exception());
@@ -1296,6 +1303,21 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) {
         thread_local_top()->pending_message_start_pos_ = location->start_pos();
         thread_local_top()->pending_message_end_pos_ = location->end_pos();
       }
+
+      // If the abort-on-uncaught-exception flag is specified, abort on any
+      // exception not caught by JavaScript, even when an external handler is
+      // present.  This flag is intended for use by JavaScript developers, so
+      // print a user-friendly stack trace (not an internal one).
+      if (fatal_exception_depth == 0 &&
+          FLAG_abort_on_uncaught_exception &&
+          (report_exception || can_be_caught_externally)) {
+        fatal_exception_depth++;
+        PrintF(stderr,
+               "%s\n\nFROM\n",
+               *MessageHandler::GetLocalizedMessage(this, message_obj));
+        PrintCurrentStackTrace(stderr);
+        OS::Abort();
+      }
     } else if (location != NULL && !location->script().is_null()) {
       // We are bootstrapping and caught an error where the location is set
       // and we have a script for the location.
@@ -1508,14 +1530,12 @@ bool Isolate::is_out_of_memory() {
 
 
 Handle<Context> Isolate::native_context() {
-  GlobalObject* global = thread_local_top()->context_->global_object();
-  return Handle<Context>(global->native_context());
+  return Handle<Context>(context()->global_object()->native_context());
 }
 
 
 Handle<Context> Isolate::global_context() {
-  GlobalObject* global = thread_local_top()->context_->global_object();
-  return Handle<Context>(global->global_context());
+  return Handle<Context>(context()->global_object()->global_context());
 }
 
 
@@ -1542,11 +1562,8 @@ Handle<Context> Isolate::GetCallingNativeContext() {
 
 
 char* Isolate::ArchiveThread(char* to) {
-  if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
-    RuntimeProfiler::IsolateExitedJS(this);
-  }
-  memcpy(to, reinterpret_cast<char*>(thread_local_top()),
-         sizeof(ThreadLocalTop));
+  OS::MemCopy(to, reinterpret_cast<char*>(thread_local_top()),
+              sizeof(ThreadLocalTop));
   InitializeThreadLocal();
   clear_pending_exception();
   clear_pending_message();
@@ -1556,8 +1573,8 @@ char* Isolate::ArchiveThread(char* to) {
 
 
 char* Isolate::RestoreThread(char* from) {
-  memcpy(reinterpret_cast<char*>(thread_local_top()), from,
-         sizeof(ThreadLocalTop));
+  OS::MemCopy(reinterpret_cast<char*>(thread_local_top()), from,
+              sizeof(ThreadLocalTop));
   // This might be just paranoia, but it seems to be needed in case a
   // thread_local_top_ is restored on a separate OS thread.
 #ifdef USE_SIMULATOR
@@ -1567,9 +1584,6 @@ char* Isolate::RestoreThread(char* from) {
   thread_local_top()->simulator_ = Simulator::current(this);
 #endif
 #endif
-  if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
-    RuntimeProfiler::IsolateEnteredJS(this);
-  }
   ASSERT(context() == NULL || context()->IsContext());
   return from + sizeof(ThreadLocalTop);
 }
@@ -1810,7 +1824,8 @@ void Isolate::Deinit() {
     if (FLAG_hydrogen_stats) GetHStatistics()->Print();
 
     // We must stop the logger before we tear down other components.
-    logger_->EnsureTickerStopped();
+    Sampler* sampler = logger_->sampler();
+    if (sampler && sampler->IsActive()) sampler->Stop();
 
     delete deoptimizer_data_;
     deoptimizer_data_ = NULL;
@@ -1826,11 +1841,6 @@ void Isolate::Deinit() {
     preallocated_message_space_ = NULL;
     PreallocatedMemoryThreadStop();
 
-    delete heap_profiler_;
-    heap_profiler_ = NULL;
-    delete cpu_profiler_;
-    cpu_profiler_ = NULL;
-
     if (runtime_profiler_ != NULL) {
       runtime_profiler_->TearDown();
       delete runtime_profiler_;
@@ -1839,6 +1849,11 @@ void Isolate::Deinit() {
     heap_.TearDown();
     logger_->TearDown();
 
+    delete heap_profiler_;
+    heap_profiler_ = NULL;
+    delete cpu_profiler_;
+    cpu_profiler_ = NULL;
+
     // The default isolate is re-initializable due to legacy API.
     state_ = UNINITIALIZED;
   }
@@ -2055,13 +2070,12 @@ bool Isolate::Init(Deserializer* des) {
   date_cache_ = new DateCache();
   code_stub_interface_descriptors_ =
       new CodeStubInterfaceDescriptor[CodeStub::NUMBER_OF_IDS];
+  cpu_profiler_ = new CpuProfiler(this);
+  heap_profiler_ = new HeapProfiler(heap());
 
   // Enable logging before setting up the heap
   logger_->SetUp();
 
-  cpu_profiler_ = new CpuProfiler(this);
-  heap_profiler_ = new HeapProfiler(heap());
-
   // Initialize other runtime facilities
 #if defined(USE_SIMULATOR)
 #if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS)
@@ -2177,9 +2191,16 @@ bool Isolate::Init(Deserializer* des) {
     // Ensure that all stubs which need to be generated ahead of time, but
     // cannot be serialized into the snapshot have been generated.
     HandleScope scope(this);
-    StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(this);
     CodeStub::GenerateFPStubs(this);
+    StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(this);
     StubFailureTrampolineStub::GenerateAheadOfTime(this);
+    // TODO(mstarzinger): The following is an ugly hack to make sure the
+    // interface descriptor is initialized even when stubs have been
+    // deserialized out of the snapshot without the graph builder.
+    FastCloneShallowArrayStub stub(FastCloneShallowArrayStub::CLONE_ELEMENTS,
+                                   DONT_TRACK_ALLOCATION_SITE, 0);
+    stub.InitializeInterfaceDescriptor(
+        this, code_stub_interface_descriptor(CodeStub::FastCloneShallowArray));
   }
 
   if (FLAG_parallel_recompilation) optimizing_compiler_thread_.Start();
index f7a81d3..927ad0e 100644 (file)
@@ -497,6 +497,10 @@ class Isolate {
   // If one does not yet exist, return null.
   PerIsolateThreadData* FindPerThreadDataForThisThread();
 
+  // Find the PerThread for given (isolate, thread) combination
+  // If one does not yet exist, return null.
+  PerIsolateThreadData* FindPerThreadDataForThread(ThreadId thread_id);
+
 #ifdef ENABLE_DEBUGGER_SUPPORT
   // Get the debugger from the default isolate. Preinitializes the
   // default isolate if needed.
@@ -645,7 +649,7 @@ class Isolate {
   }
   inline Address* handler_address() { return &thread_local_top_.handler_; }
 
-  // Bottom JS entry (see StackTracer::Trace in log.cc).
+  // Bottom JS entry (see StackTracer::Trace in sampler.cc).
   static Address js_entry_sp(ThreadLocalTop* thread) {
     return thread->js_entry_sp_;
   }
@@ -1027,23 +1031,6 @@ class Isolate {
   }
 
   void SetCurrentVMState(StateTag state) {
-    if (RuntimeProfiler::IsEnabled()) {
-      // Make sure thread local top is initialized.
-      ASSERT(thread_local_top_.isolate_ == this);
-      StateTag current_state = thread_local_top_.current_vm_state_;
-      if (current_state != JS && state == JS) {
-        // Non-JS -> JS transition.
-        RuntimeProfiler::IsolateEnteredJS(this);
-      } else if (current_state == JS && state != JS) {
-        // JS -> non-JS transition.
-        RuntimeProfiler::IsolateExitedJS(this);
-      } else {
-        // Other types of state transitions are not interesting to the
-        // runtime profiler, because they don't affect whether we're
-        // in JS or not.
-        ASSERT((current_state == JS) == (state == JS));
-      }
-    }
     thread_local_top_.current_vm_state_ = state;
   }
 
@@ -1480,7 +1467,6 @@ class PostponeInterruptsScope BASE_EMBEDDED {
 #define HEAP (v8::internal::Isolate::Current()->heap())
 #define FACTORY (v8::internal::Isolate::Current()->factory())
 #define ISOLATE (v8::internal::Isolate::Current())
-#define LOGGER (v8::internal::Isolate::Current()->logger())
 
 
 // Tells whether the native context is marked with out of memory.
index ac34c59..74850ca 100644 (file)
@@ -102,9 +102,37 @@ class JsonParser BASE_EMBEDDED {
   Handle<String> ParseJsonString() {
     return ScanJsonString<false>();
   }
+
+  bool ParseJsonString(Handle<String> expected) {
+    int length = expected->length();
+    if (source_->length() - position_ - 1 > length) {
+      AssertNoAllocation no_gc;
+      String::FlatContent content = expected->GetFlatContent();
+      if (content.IsAscii()) {
+        ASSERT_EQ('"', c0_);
+        const uint8_t* input_chars = seq_source_->GetChars() + position_ + 1;
+        const uint8_t* expected_chars = content.ToOneByteVector().start();
+        for (int i = 0; i < length; i++) {
+          uint8_t c0 = input_chars[i];
+          if (c0 != expected_chars[i] ||
+              c0 == '"' || c0 < 0x20 || c0 == '\\') {
+            return false;
+          }
+        }
+        if (input_chars[length] == '"') {
+          position_ = position_ + length + 1;
+          AdvanceSkipWhitespace();
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   Handle<String> ParseJsonInternalizedString() {
     return ScanJsonString<true>();
   }
+
   template <bool is_internalized>
   Handle<String> ScanJsonString();
   // Creates a new string and copies prefix[start..end] into the beginning
@@ -294,8 +322,13 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() {
   HandleScope scope(isolate());
   Handle<JSObject> json_object =
       factory()->NewJSObject(object_constructor(), pretenure_);
+  Handle<Map> map(json_object->map());
+  ZoneScope zone_scope(zone(), DELETE_ON_EXIT);
+  ZoneList<Handle<Object> > properties(8, zone());
   ASSERT_EQ(c0_, '{');
 
+  bool transitioning = true;
+
   AdvanceSkipWhitespace();
   if (c0_ != '}') {
     do {
@@ -339,24 +372,75 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() {
       c0_ = '"';
 #endif
 
-      Handle<String> key = ParseJsonInternalizedString();
-      if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
+      Handle<String> key;
+      Handle<Object> value;
+
+      // Try to follow existing transitions as long as possible. Once we stop
+      // transitioning, no transition can be found anymore.
+      if (transitioning) {
+        // First check whether there is a single expected transition. If so, try
+        // to parse it first.
+        bool follow_expected = false;
+        if (seq_ascii) {
+          key = JSObject::ExpectedTransitionKey(map);
+          follow_expected = !key.is_null() && ParseJsonString(key);
+        }
+        // If the expected transition hits, follow it.
+        if (follow_expected) {
+          map = JSObject::ExpectedTransitionTarget(map);
+        } else {
+          // If the expected transition failed, parse an internalized string and
+          // try to find a matching transition.
+          key = ParseJsonInternalizedString();
+          if (key.is_null()) return ReportUnexpectedCharacter();
+
+          Handle<Map> target = JSObject::FindTransitionToField(map, key);
+          // If a transition was found, follow it and continue.
+          if (!target.is_null()) {
+            map = target;
+          } else {
+            // If no transition was found, commit the intermediate state to the
+            // object and stop transitioning.
+            JSObject::TransitionToMap(json_object, map);
+            int length = properties.length();
+            for (int i = 0; i < length; i++) {
+              json_object->FastPropertyAtPut(i, *properties[i]);
+            }
+            transitioning = false;
+          }
+        }
+        if (c0_ != ':') return ReportUnexpectedCharacter();
 
-      AdvanceSkipWhitespace();
-      Handle<Object> value = ParseJsonValue();
-      if (value.is_null()) return ReportUnexpectedCharacter();
+        AdvanceSkipWhitespace();
+        value = ParseJsonValue();
+        if (value.is_null()) return ReportUnexpectedCharacter();
 
-      if (JSObject::TryTransitionToField(json_object, key)) {
-        int index = json_object->LastAddedFieldIndex();
-        json_object->FastPropertyAtPut(index, *value);
+        properties.Add(value, zone());
+        if (transitioning) continue;
       } else {
-        JSObject::SetLocalPropertyIgnoreAttributes(
-            json_object, key, value, NONE);
+        key = ParseJsonInternalizedString();
+        if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
+
+        AdvanceSkipWhitespace();
+        value = ParseJsonValue();
+        if (value.is_null()) return ReportUnexpectedCharacter();
       }
+
+      JSObject::SetLocalPropertyIgnoreAttributes(
+          json_object, key, value, NONE);
     } while (MatchSkipWhiteSpace(','));
     if (c0_ != '}') {
       return ReportUnexpectedCharacter();
     }
+
+    // If we transitioned until the very end, transition the map now.
+    if (transitioning) {
+      JSObject::TransitionToMap(json_object, map);
+      int length = properties.length();
+      for (int i = 0; i < length; i++) {
+        json_object->FastPropertyAtPut(i, *properties[i]);
+      }
+    }
   }
   AdvanceSkipWhitespace();
   return scope.CloseAndEscape(json_object);
@@ -644,22 +728,32 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() {
     uint32_t capacity = string_table->Capacity();
     uint32_t entry = StringTable::FirstProbe(hash, capacity);
     uint32_t count = 1;
+    Handle<String> result;
     while (true) {
       Object* element = string_table->KeyAt(entry);
       if (element == isolate()->heap()->undefined_value()) {
         // Lookup failure.
+        result = factory()->InternalizeOneByteString(
+            seq_source_, position_, length);
         break;
       }
       if (element != isolate()->heap()->the_hole_value() &&
           String::cast(element)->IsOneByteEqualTo(string_vector)) {
-        // Lookup success, update the current position.
-        position_ = position;
-        // Advance past the last '"'.
-        AdvanceSkipWhitespace();
-        return Handle<String>(String::cast(element), isolate());
+        result = Handle<String>(String::cast(element), isolate());
+#ifdef DEBUG
+        uint32_t hash_field =
+            (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
+        ASSERT_EQ(static_cast<int>(result->Hash()),
+                  static_cast<int>(hash_field >> String::kHashShift));
+#endif
+        break;
       }
       entry = StringTable::NextProbe(entry, count++, capacity);
     }
+    position_ = position;
+    // Advance past the last '"'.
+    AdvanceSkipWhitespace();
+    return result;
   }
 
   int beg_pos = position_;
@@ -682,14 +776,10 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() {
     }
   } while (c0_ != '"');
   int length = position_ - beg_pos;
-  Handle<String> result;
-  if (seq_ascii && is_internalized) {
-    result = factory()->InternalizeOneByteString(seq_source_, beg_pos, length);
-  } else {
-    result = factory()->NewRawOneByteString(length, pretenure_);
-    uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
-    String::WriteToFlat(*source_, dest, beg_pos, position_);
-  }
+  Handle<String> result = factory()->NewRawOneByteString(length, pretenure_);
+  uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
+  String::WriteToFlat(*source_, dest, beg_pos, position_);
+
   ASSERT_EQ('"', c0_);
   // Advance past the last '"'.
   AdvanceSkipWhitespace();
index bcdd64c..3bab324 100644 (file)
@@ -296,18 +296,23 @@ MaybeObject* BasicJsonStringifier::StringifyString(Isolate* isolate,
   }
 
   FlattenString(object);
-  String::FlatContent flat = object->GetFlatContent();
-  if (flat.IsAscii()) {
+  ASSERT(object->IsFlat());
+  if (object->IsOneByteRepresentationUnderneath()) {
+    Handle<String> result =
+        isolate->factory()->NewRawOneByteString(worst_case_length);
+    AssertNoAllocation no_alloc;
     return StringifyString_<SeqOneByteString>(
         isolate,
-        flat.ToOneByteVector(),
-        isolate->factory()->NewRawOneByteString(worst_case_length));
+        object->GetFlatContent().ToOneByteVector(),
+        result);
   } else {
-    ASSERT(flat.IsTwoByte());
+    Handle<String> result =
+        isolate->factory()->NewRawTwoByteString(worst_case_length);
+    AssertNoAllocation no_alloc;
     return StringifyString_<SeqTwoByteString>(
         isolate,
-        flat.ToUC16Vector(),
-        isolate->factory()->NewRawTwoByteString(worst_case_length));
+        object->GetFlatContent().ToUC16Vector(),
+        result);
   }
 }
 
index e94d3c8..b0e14e1 100644 (file)
 // (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 relies on the fact that the following declarations have been made
+// in runtime.js:
+// var $Array = global.Array;
+// var $String = global.String;
+
 var $JSON = global.JSON;
 
+// -------------------------------------------------------------------
+
 function Revive(holder, name, reviver) {
   var val = holder[name];
   if (IS_OBJECT(val)) {
@@ -207,14 +214,23 @@ function JSONStringify(value, replacer, space) {
 }
 
 
+// -------------------------------------------------------------------
+
 function SetUpJSON() {
   %CheckIsBootstrapping();
+
+  // Set up non-enumerable properties of the JSON object.
   InstallFunctions($JSON, DONT_ENUM, $Array(
     "parse", JSONParse,
     "stringify", JSONStringify
   ));
 }
 
+SetUpJSON();
+
+
+// -------------------------------------------------------------------
+// JSON Builtins
 
 function JSONSerializeAdapter(key, object) {
   var holder = {};
@@ -222,5 +238,3 @@ function JSONSerializeAdapter(key, object) {
   // No need to pass the actual holder since there is no replacer function.
   return JSONSerialize(key, holder, void 0, new InternalArray(), "", "");
 }
-
-SetUpJSON();
index b490521..fd87a80 100644 (file)
@@ -624,7 +624,8 @@ int RegExpImpl::IrregexpExecRaw(Handle<JSRegExp> regexp,
                                                      index);
   if (result == RE_SUCCESS) {
     // Copy capture results to the start of the registers array.
-    memcpy(output, raw_output, number_of_capture_registers * sizeof(int32_t));
+    OS::MemCopy(
+        output, raw_output, number_of_capture_registers * sizeof(int32_t));
   }
   if (result == RE_EXCEPTION) {
     ASSERT(!isolate->has_pending_exception());
index 7a84313..408859e 100644 (file)
@@ -29,6 +29,7 @@
 #define V8_LIST_INL_H_
 
 #include "list.h"
+#include "platform.h"
 
 namespace v8 {
 namespace internal {
@@ -87,7 +88,7 @@ template<typename T, class P>
 void List<T, P>::Resize(int new_capacity, P alloc) {
   ASSERT_LE(length_, new_capacity);
   T* new_data = NewData(new_capacity, alloc);
-  memcpy(new_data, data_, length_ * sizeof(T));
+  OS::MemCopy(new_data, data_, length_ * sizeof(T));
   List<T, P>::DeleteData(data_);
   data_ = new_data;
   capacity_ = new_capacity;
index 7049a58..7bddef7 100644 (file)
@@ -1546,6 +1546,9 @@ void LAllocator::AllocateRegisters() {
     LiveRange* current = unhandled_live_ranges_.RemoveLast();
     ASSERT(UnhandledIsSorted());
     LifetimePosition position = current->Start();
+#ifdef DEBUG
+    allocation_finger_ = position;
+#endif
     TraceAlloc("Processing interval %d start=%d\n",
                current->id(),
                position.Value());
@@ -1670,6 +1673,7 @@ void LAllocator::AddToInactive(LiveRange* range) {
 void LAllocator::AddToUnhandledSorted(LiveRange* range) {
   if (range == NULL || range->IsEmpty()) return;
   ASSERT(!range->HasRegisterAssigned() && !range->IsSpilled());
+  ASSERT(allocation_finger_.Value() <= range->Start().Value());
   for (int i = unhandled_live_ranges_.length() - 1; i >= 0; --i) {
     LiveRange* cur_range = unhandled_live_ranges_.at(i);
     if (range->ShouldBeAllocatedBefore(cur_range)) {
@@ -1788,7 +1792,7 @@ STATIC_ASSERT(DoubleRegister::kMaxNumAllocatableRegisters >=
 bool LAllocator::TryAllocateFreeReg(LiveRange* current) {
   LifetimePosition free_until_pos[DoubleRegister::kMaxNumAllocatableRegisters];
 
-  for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; i++) {
+  for (int i = 0; i < num_registers_; i++) {
     free_until_pos[i] = LifetimePosition::MaxPosition();
   }
 
@@ -1880,7 +1884,7 @@ void LAllocator::AllocateBlockedReg(LiveRange* current) {
   LifetimePosition use_pos[DoubleRegister::kMaxNumAllocatableRegisters];
   LifetimePosition block_pos[DoubleRegister::kMaxNumAllocatableRegisters];
 
-  for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
+  for (int i = 0; i < num_registers_; i++) {
     use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
   }
 
@@ -2000,7 +2004,15 @@ void LAllocator::SplitAndSpillIntersecting(LiveRange* current) {
       if (next_pos == NULL) {
         SpillAfter(range, spill_pos);
       } else {
-        SpillBetween(range, spill_pos, next_pos->pos());
+        // When spilling between spill_pos and next_pos ensure that the range
+        // remains spilled at least until the start of the current live range.
+        // This guarantees that we will not introduce new unhandled ranges that
+        // start before the current range as this violates allocation invariant
+        // and will lead to an inconsistent state of active and inactive
+        // live-ranges: ranges are allocated in order of their start positions,
+        // ranges are retired from active/inactive when the start of the
+        // current live-range is larger than their end.
+        SpillBetweenUntil(range, spill_pos, current->Start(), next_pos->pos());
       }
       if (!AllocationOk()) return;
       ActiveToHandled(range);
@@ -2114,6 +2126,14 @@ void LAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) {
 void LAllocator::SpillBetween(LiveRange* range,
                               LifetimePosition start,
                               LifetimePosition end) {
+  SpillBetweenUntil(range, start, start, end);
+}
+
+
+void LAllocator::SpillBetweenUntil(LiveRange* range,
+                                   LifetimePosition start,
+                                   LifetimePosition until,
+                                   LifetimePosition end) {
   CHECK(start.Value() < end.Value());
   LiveRange* second_part = SplitRangeAt(range, start);
   if (!AllocationOk()) return;
@@ -2124,7 +2144,7 @@ void LAllocator::SpillBetween(LiveRange* range,
     // and put the rest to unhandled.
     LiveRange* third_part = SplitBetween(
         second_part,
-        second_part->Start().InstructionEnd(),
+        Max(second_part->Start().InstructionEnd(), until),
         end.PrevInstruction().InstructionEnd());
     if (!AllocationOk()) return;
 
index 70f3182..8b45531 100644 (file)
@@ -536,11 +536,18 @@ class LAllocator BASE_EMBEDDED {
   // Spill the given life range after position pos.
   void SpillAfter(LiveRange* range, LifetimePosition pos);
 
-  // Spill the given life range after position start and up to position end.
+  // Spill the given life range after position [start] and up to position [end].
   void SpillBetween(LiveRange* range,
                     LifetimePosition start,
                     LifetimePosition end);
 
+  // Spill the given life range after position [start] and up to position [end].
+  // Range is guaranteed to be spilled at least until position [until].
+  void SpillBetweenUntil(LiveRange* range,
+                         LifetimePosition start,
+                         LifetimePosition until,
+                         LifetimePosition end);
+
   void SplitAndSpillIntersecting(LiveRange* range);
 
   // If we are trying to spill a range inside the loop try to
@@ -625,6 +632,10 @@ class LAllocator BASE_EMBEDDED {
   // Indicates success or failure during register allocation.
   bool allocation_ok_;
 
+#ifdef DEBUG
+  LifetimePosition allocation_finger_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(LAllocator);
 };
 
index 58c846a..b28cd3e 100644 (file)
@@ -609,7 +609,7 @@ static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) {
   CompilationInfoWithZone info(script);
   info.MarkAsGlobal();
   // Parse and don't allow skipping lazy functions.
-  if (ParserApi::Parse(&info, kNoParsingFlags)) {
+  if (Parser::Parse(&info)) {
     // Compile the code.
     LiveEditFunctionTracker tracker(info.isolate(), info.function());
     if (Compiler::MakeCodeForLiveEdit(&info)) {
@@ -1435,8 +1435,8 @@ class RelocInfoBuffer {
     // Copy the data.
     int curently_used_size =
         static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
-    memmove(new_buffer + new_buffer_size - curently_used_size,
-            reloc_info_writer_.pos(), curently_used_size);
+    OS::MemMove(new_buffer + new_buffer_size - curently_used_size,
+                reloc_info_writer_.pos(), curently_used_size);
 
     reloc_info_writer_.Reposition(
         new_buffer + new_buffer_size - curently_used_size,
@@ -1488,7 +1488,7 @@ static Handle<Code> PatchPositionsInCode(
 
   if (buffer.length() == code->relocation_size()) {
     // Simply patch relocation area of code.
-    memcpy(code->relocation_start(), buffer.start(), buffer.length());
+    OS::MemCopy(code->relocation_start(), buffer.start(), buffer.length());
     return code;
   } else {
     // Relocation info section now has different size. We cannot simply
@@ -1761,9 +1761,9 @@ static const char* DropFrames(Vector<StackFrame*> frames,
 
       StackFrame* pre_pre_frame = frames[top_frame_index - 2];
 
-      memmove(padding_start + kPointerSize - shortage_bytes,
-          padding_start + kPointerSize,
-          Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
+      OS::MemMove(padding_start + kPointerSize - shortage_bytes,
+                  padding_start + kPointerSize,
+                  Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
 
       pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
       pre_pre_frame->SetCallerFp(pre_top_frame->fp());
index 45ac403..cef7dba 100644 (file)
@@ -167,8 +167,9 @@ void Log::OpenFile(const char* name) {
     // Open the low-level log file.
     size_t len = strlen(name);
     ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLowLevelLogExt)));
-    memcpy(ll_name.start(), name, len);
-    memcpy(ll_name.start() + len, kLowLevelLogExt, sizeof(kLowLevelLogExt));
+    OS::MemCopy(ll_name.start(), name, len);
+    OS::MemCopy(ll_name.start() + len,
+                kLowLevelLogExt, sizeof(kLowLevelLogExt));
     ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
     setvbuf(ll_output_handle_, NULL, _IOFBF, kLowLevelLogBufferSize);
   }
index 9438537..1538894 100644 (file)
@@ -112,45 +112,6 @@ class Profiler: public Thread {
 
 
 //
-// StackTracer implementation
-//
-DISABLE_ASAN void StackTracer::Trace(Isolate* isolate, TickSample* sample) {
-  ASSERT(isolate->IsInitialized());
-
-  // Avoid collecting traces while doing GC.
-  if (sample->state == GC) return;
-
-  const Address js_entry_sp =
-      Isolate::js_entry_sp(isolate->thread_local_top());
-  if (js_entry_sp == 0) {
-    // Not executing JS now.
-    return;
-  }
-
-  const Address callback = isolate->external_callback();
-  if (callback != NULL) {
-    sample->external_callback = callback;
-    sample->has_external_callback = true;
-  } else {
-    // Sample potential return address value for frameless invocation of
-    // stubs (we'll figure out later, if this value makes sense).
-    sample->tos = Memory::Address_at(sample->sp);
-    sample->has_external_callback = false;
-  }
-
-  SafeStackTraceFrameIterator it(isolate,
-                                 sample->fp, sample->sp,
-                                 sample->sp, js_entry_sp);
-  int i = 0;
-  while (!it.done() && i < TickSample::kMaxFramesCount) {
-    sample->stack[i++] = it.frame()->pc();
-    it.Advance();
-  }
-  sample->frames_count = i;
-}
-
-
-//
 // Ticker used to provide ticks to the profiler and the sliding state
 // window.
 //
@@ -179,11 +140,6 @@ class Ticker: public Sampler {
     if (IsActive()) Stop();
   }
 
- protected:
-  virtual void DoSampleStack(TickSample* sample) {
-    StackTracer::Trace(isolate(), sample);
-  }
-
  private:
   Profiler* profiler_;
 };
@@ -216,9 +172,10 @@ void Profiler::Engage() {
   Start();
 
   // Register to get ticks.
-  LOGGER->ticker_->SetProfiler(this);
+  Logger* logger = isolate_->logger();
+  logger->ticker_->SetProfiler(this);
 
-  LOGGER->ProfilerBeginEvent();
+  logger->ProfilerBeginEvent();
 }
 
 
@@ -226,7 +183,7 @@ void Profiler::Disengage() {
   if (!engaged_) return;
 
   // Stop receiving ticks.
-  LOGGER->ticker_->ClearProfiler();
+  isolate_->logger()->ticker_->ClearProfiler();
 
   // Terminate the worker thread by setting running_ to false,
   // inserting a fake element in the queue and then wait for
@@ -406,7 +363,7 @@ class Logger::NameBuffer {
 
   void AppendBytes(const char* bytes, int size) {
     size = Min(size, kUtf8BufferSize - utf8_pos_);
-    memcpy(utf8_buffer_ + utf8_pos_, bytes, size);
+    OS::MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
     utf8_pos_ += size;
   }
 
@@ -778,11 +735,10 @@ void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
 }
 
 
-void Logger::LogRuntime(Isolate* isolate,
-                        Vector<const char> format,
+void Logger::LogRuntime(Vector<const char> format,
                         JSArray* args) {
   if (!log_->IsEnabled() || !FLAG_log_runtime) return;
-  HandleScope scope(isolate);
+  HandleScope scope(isolate_);
   LogMessageBuilder msg(this);
   for (int i = 0; i < format.length(); i++) {
     char c = format[i];
@@ -899,12 +855,12 @@ void Logger::DeleteEvent(const char* name, void* object) {
 
 
 void Logger::NewEventStatic(const char* name, void* object, size_t size) {
-  LOGGER->NewEvent(name, object, size);
+  Isolate::Current()->logger()->NewEvent(name, object, size);
 }
 
 
 void Logger::DeleteEventStatic(const char* name, void* object) {
-  LOGGER->DeleteEvent(name, object);
+  Isolate::Current()->logger()->DeleteEvent(name, object);
 }
 
 void Logger::CallbackEventInternal(const char* prefix, Name* name,
@@ -1492,13 +1448,7 @@ void Logger::TickEvent(TickSample* sample, bool overflow) {
   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);
-  } else {
-    msg.Append(",0,");
-    msg.AppendAddress(sample->tos);
-  }
+  msg.AppendAddress(sample->external_callback);
   msg.Append(",%d", static_cast<int>(sample->state));
   if (overflow) {
     msg.Append(",overflow");
@@ -1560,11 +1510,6 @@ void Logger::LogFailure() {
 }
 
 
-bool Logger::IsProfilerSamplerActive() {
-  return ticker_->IsActive();
-}
-
-
 class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
  public:
   EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
@@ -1937,17 +1882,6 @@ Sampler* Logger::sampler() {
 }
 
 
-void Logger::EnsureTickerStarted() {
-  ASSERT(ticker_ != NULL);
-  if (!ticker_->IsActive()) ticker_->Start();
-}
-
-
-void Logger::EnsureTickerStopped() {
-  if (ticker_ != NULL && ticker_->IsActive()) ticker_->Stop();
-}
-
-
 FILE* Logger::TearDown() {
   if (!is_initialized_) return NULL;
   is_initialized_ = false;
@@ -1965,65 +1899,4 @@ FILE* Logger::TearDown() {
   return log_->Close();
 }
 
-
-// Protects the state below.
-static Mutex* active_samplers_mutex = NULL;
-
-List<Sampler*>* SamplerRegistry::active_samplers_ = NULL;
-
-
-void SamplerRegistry::SetUp() {
-  if (!active_samplers_mutex) {
-    active_samplers_mutex = OS::CreateMutex();
-  }
-}
-
-
-bool SamplerRegistry::IterateActiveSamplers(VisitSampler func, void* param) {
-  ScopedLock lock(active_samplers_mutex);
-  for (int i = 0;
-       ActiveSamplersExist() && i < active_samplers_->length();
-       ++i) {
-    func(active_samplers_->at(i), param);
-  }
-  return ActiveSamplersExist();
-}
-
-
-static void ComputeCpuProfiling(Sampler* sampler, void* flag_ptr) {
-  bool* flag = reinterpret_cast<bool*>(flag_ptr);
-  *flag |= sampler->IsProfiling();
-}
-
-
-SamplerRegistry::State SamplerRegistry::GetState() {
-  bool flag = false;
-  if (!IterateActiveSamplers(&ComputeCpuProfiling, &flag)) {
-    return HAS_NO_SAMPLERS;
-  }
-  return flag ? HAS_CPU_PROFILING_SAMPLERS : HAS_SAMPLERS;
-}
-
-
-void SamplerRegistry::AddActiveSampler(Sampler* sampler) {
-  ASSERT(sampler->IsActive());
-  ScopedLock lock(active_samplers_mutex);
-  if (active_samplers_ == NULL) {
-    active_samplers_ = new List<Sampler*>;
-  } else {
-    ASSERT(!active_samplers_->Contains(sampler));
-  }
-  active_samplers_->Add(sampler);
-}
-
-
-void SamplerRegistry::RemoveActiveSampler(Sampler* sampler) {
-  ASSERT(sampler->IsActive());
-  ScopedLock lock(active_samplers_mutex);
-  ASSERT(active_samplers_ != NULL);
-  bool removed = active_samplers_->RemoveElement(sampler);
-  ASSERT(removed);
-  USE(removed);
-}
-
 } }  // namespace v8::internal
index a5eddc7..2683330 100644 (file)
@@ -74,6 +74,7 @@ namespace internal {
 class LogMessageBuilder;
 class Profiler;
 class Semaphore;
+struct TickSample;
 class Ticker;
 class Isolate;
 class PositionsRecorder;
@@ -168,9 +169,6 @@ class Logger {
   void SetCodeEventHandler(uint32_t options,
                            JitCodeEventHandler event_handler);
 
-  void EnsureTickerStarted();
-  void EnsureTickerStopped();
-
   Sampler* sampler();
 
   // Frees resources acquired in SetUp.
@@ -327,7 +325,7 @@ class Logger {
   void RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache);
 
   // Log an event reported from generated code
-  void LogRuntime(Isolate* isolate, Vector<const char> format, JSArray* args);
+  void LogRuntime(Vector<const char> format, JSArray* args);
 
   bool is_logging() {
     return logging_nesting_ > 0;
@@ -448,9 +446,6 @@ class Logger {
   void UncheckedIntEvent(const char* name, int value);
   void UncheckedIntPtrTEvent(const char* name, intptr_t value);
 
-  // Returns whether profiler's sampler is active.
-  bool IsProfilerSamplerActive();
-
   Isolate* isolate_;
 
   // The sampler used by the profiler and the sliding state window.
@@ -471,7 +466,6 @@ class Logger {
   friend class LogMessageBuilder;
   friend class TimeLog;
   friend class Profiler;
-  friend class StackTracer;
   friend class VMState;
 
   friend class LoggerTestHelper;
@@ -510,46 +504,6 @@ class Logger {
 };
 
 
-// Process wide registry of samplers.
-class SamplerRegistry : public AllStatic {
- public:
-  enum State {
-    HAS_NO_SAMPLERS,
-    HAS_SAMPLERS,
-    HAS_CPU_PROFILING_SAMPLERS
-  };
-
-  static void SetUp();
-
-  typedef void (*VisitSampler)(Sampler*, void*);
-
-  static State GetState();
-
-  // Iterates over all active samplers keeping the internal lock held.
-  // Returns whether there are any active samplers.
-  static bool IterateActiveSamplers(VisitSampler func, void* param);
-
-  // Adds/Removes an active sampler.
-  static void AddActiveSampler(Sampler* sampler);
-  static void RemoveActiveSampler(Sampler* sampler);
-
- private:
-  static bool ActiveSamplersExist() {
-    return active_samplers_ != NULL && !active_samplers_->is_empty();
-  }
-
-  static List<Sampler*>* active_samplers_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(SamplerRegistry);
-};
-
-
-// Class that extracts stack trace, used for profiling.
-class StackTracer : public AllStatic {
- public:
-  static void Trace(Isolate* isolate, TickSample* sample);
-};
-
 } }  // namespace v8::internal
 
 
index 55dccfa..9fdf2ee 100644 (file)
@@ -51,7 +51,9 @@ enum AllocationFlags {
   // Align the allocation to a multiple of kDoubleSize
   DOUBLE_ALIGNMENT = 1 << 3,
   // Directly allocate in old pointer space
-  PRETENURE_OLD_POINTER_SPACE = 1 << 4
+  PRETENURE_OLD_POINTER_SPACE = 1 << 4,
+  // Directly allocate in old data space
+  PRETENURE_OLD_DATA_SPACE = 1 << 5
 };
 
 
@@ -175,17 +177,26 @@ class AllocationUtils {
  public:
   static ExternalReference GetAllocationTopReference(
       Isolate* isolate, AllocationFlags flags) {
-    return ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) ?
-        ExternalReference::old_pointer_space_allocation_top_address(isolate) :
-        ExternalReference::new_space_allocation_top_address(isolate);
+    if ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) {
+      return ExternalReference::old_pointer_space_allocation_top_address(
+          isolate);
+    } else if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
+      return ExternalReference::old_data_space_allocation_top_address(isolate);
+    }
+    return ExternalReference::new_space_allocation_top_address(isolate);
   }
 
 
   static ExternalReference GetAllocationLimitReference(
       Isolate* isolate, AllocationFlags flags) {
-    return ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) ?
-        ExternalReference::old_pointer_space_allocation_limit_address(isolate) :
-        ExternalReference::new_space_allocation_limit_address(isolate);
+    if ((flags & PRETENURE_OLD_POINTER_SPACE) != 0) {
+      return ExternalReference::old_pointer_space_allocation_limit_address(
+          isolate);
+    } else if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
+      return ExternalReference::old_data_space_allocation_limit_address(
+          isolate);
+    }
+    return ExternalReference::new_space_allocation_limit_address(isolate);
   }
 };
 
index 7503f24..f49179f 100644 (file)
@@ -672,8 +672,8 @@ static int FreeListFragmentation(PagedSpace* space, Page* p) {
     return 0;
   }
 
-  FreeList::SizeStats sizes;
-  space->CountFreeListItems(p, &sizes);
+  PagedSpace::SizeStats sizes;
+  space->ObtainFreeListStatistics(p, &sizes);
 
   intptr_t ratio;
   intptr_t ratio_threshold;
@@ -812,8 +812,8 @@ void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) {
       if (!p->WasSwept()) {
         free_bytes = (p->area_size() - p->LiveBytes());
       } else {
-        FreeList::SizeStats sizes;
-        space->CountFreeListItems(p, &sizes);
+        PagedSpace::SizeStats sizes;
+        space->ObtainFreeListStatistics(p, &sizes);
         free_bytes = sizes.Total();
       }
 
@@ -3125,8 +3125,6 @@ void MarkCompactCollector::ProcessInvalidatedCode(ObjectVisitor* visitor) {
 
 
 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
-  Heap::RelocationLock relocation_lock(heap());
-
   bool code_slots_filtering_required;
   { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE);
     code_slots_filtering_required = MarkInvalidatedCode();
index 0e02541..e5ab70c 100644 (file)
@@ -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.
 
+// This file relies on the fact that the following declarations have been made
+// in runtime.js:
+// var $Object = global.Object;
 
 // Keep reference to original values of some global properties.  This
 // has the added benefit that the code in this file is isolated from
@@ -35,10 +38,9 @@ var $abs = MathAbs;
 // Instance class name can only be set on functions. That is the only
 // purpose for MathConstructor.
 function MathConstructor() {}
-%FunctionSetInstanceClassName(MathConstructor, 'Math');
 var $Math = new MathConstructor();
-%SetPrototype($Math, $Object.prototype);
-%SetProperty(global, "Math", $Math, DONT_ENUM);
+
+// -------------------------------------------------------------------
 
 // ECMA 262 - 15.8.2.1
 function MathAbs(x) {
@@ -216,6 +218,11 @@ function MathTan(x) {
 
 function SetUpMath() {
   %CheckIsBootstrapping();
+
+  %SetPrototype($Math, $Object.prototype);
+  %SetProperty(global, "Math", $Math, DONT_ENUM);
+  %FunctionSetInstanceClassName(MathConstructor, 'Math');
+
   // Set up math constants.
   // ECMA-262, section 15.8.1.1.
   %OptimizeObjectForAddingMultipleProperties($Math, 8);
index d51d384..67fe3cc 100644 (file)
@@ -98,9 +98,13 @@ var kMessages = {
   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"],
+  proto_poison_pill:             ["Generic use of __proto__ accessor not allowed"],
   // RangeError
   invalid_array_length:          ["Invalid array length"],
   invalid_array_buffer_length:   ["Invalid array buffer length"],
+  invalid_typed_array_offset:    ["Start offset is too large"],
+  invalid_typed_array_length:    ["Length is too large"],
+  invalid_typed_array_alignment: ["%0", "of", "%1", "should be a multiple of", "%3"],
   stack_overflow:                ["Maximum call stack size exceeded"],
   invalid_time_value:            ["Invalid time value"],
   // SyntaxError
index 9c9f611..d922bfa 100644 (file)
@@ -81,29 +81,17 @@ bool Operand::is_reg() const {
 
 
 int Register::NumAllocatableRegisters() {
-  if (CpuFeatures::IsSupported(FPU)) {
     return kMaxNumAllocatableRegisters;
-  } else {
-    return kMaxNumAllocatableRegisters - kGPRsPerNonFPUDouble;
-  }
 }
 
 
 int DoubleRegister::NumRegisters() {
-  if (CpuFeatures::IsSupported(FPU)) {
     return FPURegister::kMaxNumRegisters;
-  } else {
-    return 1;
-  }
 }
 
 
 int DoubleRegister::NumAllocatableRegisters() {
-  if (CpuFeatures::IsSupported(FPU)) {
     return FPURegister::kMaxNumAllocatableRegisters;
-  } else {
-    return 1;
-  }
 }
 
 
index c255d0f..e36b97f 100644 (file)
@@ -80,29 +80,24 @@ static uint64_t CpuFeaturesImpliedByCompiler() {
 
 
 const char* DoubleRegister::AllocationIndexToString(int index) {
-  if (CpuFeatures::IsSupported(FPU)) {
-    ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
-    const char* const names[] = {
-      "f0",
-      "f2",
-      "f4",
-      "f6",
-      "f8",
-      "f10",
-      "f12",
-      "f14",
-      "f16",
-      "f18",
-      "f20",
-      "f22",
-      "f24",
-      "f26"
-    };
-    return names[index];
-  } else {
-    ASSERT(index == 0);
-    return "sfpd0";
-  }
+  ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
+  const char* const names[] = {
+    "f0",
+    "f2",
+    "f4",
+    "f6",
+    "f8",
+    "f10",
+    "f12",
+    "f14",
+    "f16",
+    "f18",
+    "f20",
+    "f22",
+    "f24",
+    "f26"
+  };
+  return names[index];
 }
 
 
@@ -127,10 +122,8 @@ void CpuFeatures::Probe() {
   // If the compiler is allowed to use fpu then we can use fpu too in our
   // code generation.
 #if !defined(__mips__)
-  // For the simulator=mips build, use FPU when FLAG_enable_fpu is enabled.
-  if (FLAG_enable_fpu) {
-      supported_ |= static_cast<uint64_t>(1) << FPU;
-  }
+  // For the simulator build, use FPU.
+  supported_ |= static_cast<uint64_t>(1) << FPU;
 #else
   // Probe for additional features not already known to be available.
   if (OS::MipsCpuHasFeature(FPU)) {
@@ -876,7 +869,6 @@ void Assembler::GenInstrRegister(Opcode opcode,
                                  FPURegister fd,
                                  SecondaryField func) {
   ASSERT(fd.is_valid() && fs.is_valid() && ft.is_valid());
-  ASSERT(IsEnabled(FPU));
   Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
       | (fd.code() << kFdShift) | func;
   emit(instr);
@@ -890,7 +882,6 @@ void Assembler::GenInstrRegister(Opcode opcode,
                                  FPURegister fd,
                                  SecondaryField func) {
   ASSERT(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
-  ASSERT(IsEnabled(FPU));
   Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
       | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
   emit(instr);
@@ -904,7 +895,6 @@ void Assembler::GenInstrRegister(Opcode opcode,
                                  FPURegister fd,
                                  SecondaryField func) {
   ASSERT(fd.is_valid() && fs.is_valid() && rt.is_valid());
-  ASSERT(IsEnabled(FPU));
   Instr instr = opcode | fmt | (rt.code() << kRtShift)
       | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
   emit(instr);
@@ -917,7 +907,6 @@ void Assembler::GenInstrRegister(Opcode opcode,
                                  FPUControlRegister fs,
                                  SecondaryField func) {
   ASSERT(fs.is_valid() && rt.is_valid());
-  ASSERT(IsEnabled(FPU));
   Instr instr =
       opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
   emit(instr);
@@ -952,7 +941,6 @@ void Assembler::GenInstrImmediate(Opcode opcode,
                                   FPURegister ft,
                                   int32_t j) {
   ASSERT(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
-  ASSERT(IsEnabled(FPU));
   Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
       | (j & kImm16Mask);
   emit(instr);
@@ -1679,7 +1667,7 @@ void Assembler::cfc1(Register rt, FPUControlRegister fs) {
 
 void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
   uint64_t i;
-  memcpy(&i, &d, 8);
+  OS::MemCopy(&i, &d, 8);
 
   *lo = i & 0xffffffff;
   *hi = i >> 32;
@@ -1874,7 +1862,6 @@ void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
 // Conditions.
 void Assembler::c(FPUCondition cond, SecondaryField fmt,
     FPURegister fs, FPURegister ft, uint16_t cc) {
-  ASSERT(IsEnabled(FPU));
   ASSERT(is_uint3(cc));
   ASSERT((fmt & ~(31 << kRsShift)) == 0);
   Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
@@ -1885,7 +1872,6 @@ void Assembler::c(FPUCondition cond, SecondaryField fmt,
 
 void Assembler::fcmp(FPURegister src1, const double src2,
       FPUCondition cond) {
-  ASSERT(IsEnabled(FPU));
   ASSERT(src2 == 0.0);
   mtc1(zero_reg, f14);
   cvt_d_w(f14, f14);
@@ -1894,7 +1880,6 @@ void Assembler::fcmp(FPURegister src1, const double src2,
 
 
 void Assembler::bc1f(int16_t offset, uint16_t cc) {
-  ASSERT(IsEnabled(FPU));
   ASSERT(is_uint3(cc));
   Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
   emit(instr);
@@ -1902,7 +1887,6 @@ void Assembler::bc1f(int16_t offset, uint16_t cc) {
 
 
 void Assembler::bc1t(int16_t offset, uint16_t cc) {
-  ASSERT(IsEnabled(FPU));
   ASSERT(is_uint3(cc));
   Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
   emit(instr);
@@ -1997,9 +1981,9 @@ void Assembler::GrowBuffer() {
   // Copy the data.
   int pc_delta = desc.buffer - buffer_;
   int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
-  memmove(desc.buffer, buffer_, desc.instr_size);
-  memmove(reloc_info_writer.pos() + rc_delta,
-          reloc_info_writer.pos(), desc.reloc_size);
+  OS::MemMove(desc.buffer, buffer_, desc.instr_size);
+  OS::MemMove(reloc_info_writer.pos() + rc_delta,
+              reloc_info_writer.pos(), desc.reloc_size);
 
   // Switch buffers.
   DeleteArray(buffer_);
index 9d3d39b..d12c0da 100644 (file)
@@ -74,7 +74,6 @@ struct Register {
   static const int kNumRegisters = v8::internal::kNumRegisters;
   static const int kMaxNumAllocatableRegisters = 14;  // v0 through t7.
   static const int kSizeInBytes = 4;
-  static const int kGPRsPerNonFPUDouble = 2;
 
   inline static int NumAllocatableRegisters();
 
@@ -300,9 +299,6 @@ const FPURegister f29 = { 29 };
 const FPURegister f30 = { 30 };
 const FPURegister f31 = { 31 };
 
-const Register sfpd_lo  = { kRegister_t6_Code };
-const Register sfpd_hi  = { kRegister_t7_Code };
-
 // Register aliases.
 // cp is assumed to be a callee saved register.
 // Defined using #define instead of "static const Register&" because Clang
@@ -403,7 +399,6 @@ class CpuFeatures : public AllStatic {
   // Check whether a feature is supported by the target CPU.
   static bool IsSupported(CpuFeature f) {
     ASSERT(initialized_);
-    if (f == FPU && !FLAG_enable_fpu) return false;
     return (supported_ & (1u << f)) != 0;
   }
 
index 37d7720..cbe2048 100644 (file)
@@ -30,6 +30,7 @@
 #if defined(V8_TARGET_ARCH_MIPS)
 
 #include "bootstrapper.h"
+#include "builtins-decls.h"
 #include "code-stubs.h"
 #include "codegen.h"
 #include "regexp-macro-assembler.h"
@@ -39,6 +40,18 @@ namespace v8 {
 namespace internal {
 
 
+void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { a3, a2, a1 };
+  descriptor->register_param_count_ = 3;
+  descriptor->register_params_ = registers;
+  descriptor->stack_parameter_count_ = NULL;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
+}
+
+
 void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
@@ -134,7 +147,6 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
                                     Label* rhs_not_nan,
                                     Label* slow,
                                     bool strict);
-static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc);
 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
                                            Register lhs,
                                            Register rhs);
@@ -183,9 +195,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
 
   __ IncrementCounter(counters->fast_new_closure_total(), 1, t2, t3);
 
-  int map_index = (language_mode_ == CLASSIC_MODE)
-      ? Context::FUNCTION_MAP_INDEX
-      : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
+  int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
 
   // Compute the function map in the current native context and set that
   // as the map of the allocated object.
@@ -402,147 +412,6 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
 }
 
 
-static void GenerateFastCloneShallowArrayCommon(
-    MacroAssembler* masm,
-    int length,
-    FastCloneShallowArrayStub::Mode mode,
-    AllocationSiteMode allocation_site_mode,
-    Label* fail) {
-  // Registers on entry:
-  // a3: boilerplate literal array.
-  ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
-
-  // All sizes here are multiples of kPointerSize.
-  int elements_size = 0;
-  if (length > 0) {
-    elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
-        ? FixedDoubleArray::SizeFor(length)
-        : FixedArray::SizeFor(length);
-  }
-
-  int size = JSArray::kSize;
-  int allocation_info_start = size;
-  if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-    size += AllocationSiteInfo::kSize;
-  }
-  size += elements_size;
-
-  // Allocate both the JS array and the elements array in one big
-  // allocation. This avoids multiple limit checks.
-  __ Allocate(size, v0, a1, a2, fail, TAG_OBJECT);
-
-  if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-    __ li(a2, Operand(Handle<Map>(masm->isolate()->heap()->
-                                   allocation_site_info_map())));
-    __ sw(a2, FieldMemOperand(v0, allocation_info_start));
-    __ sw(a3, FieldMemOperand(v0, allocation_info_start + kPointerSize));
-  }
-
-  // Copy the JS array part.
-  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
-    if ((i != JSArray::kElementsOffset) || (length == 0)) {
-      __ lw(a1, FieldMemOperand(a3, i));
-      __ sw(a1, FieldMemOperand(v0, i));
-    }
-  }
-
-  if (length > 0) {
-    // Get hold of the elements array of the boilerplate and setup the
-    // elements pointer in the resulting object.
-    __ lw(a3, FieldMemOperand(a3, JSArray::kElementsOffset));
-    if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-      __ Addu(a2, v0, Operand(JSArray::kSize + AllocationSiteInfo::kSize));
-    } else {
-      __ Addu(a2, v0, Operand(JSArray::kSize));
-    }
-    __ sw(a2, FieldMemOperand(v0, JSArray::kElementsOffset));
-
-    // Copy the elements array.
-    ASSERT((elements_size % kPointerSize) == 0);
-    __ CopyFields(a2, a3, a1.bit(), elements_size / kPointerSize);
-  }
-}
-
-void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
-  // Stack layout on entry:
-  //
-  // [sp]: constant elements.
-  // [sp + kPointerSize]: literal index.
-  // [sp + (2 * kPointerSize)]: literals array.
-
-  // Load boilerplate object into r3 and check if we need to create a
-  // boilerplate.
-  Label slow_case;
-  __ lw(a3, MemOperand(sp, 2 * kPointerSize));
-  __ lw(a0, MemOperand(sp, 1 * kPointerSize));
-  __ Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
-  __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
-  __ Addu(t0, a3, t0);
-  __ lw(a3, MemOperand(t0));
-  __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
-  __ Branch(&slow_case, eq, a3, Operand(t1));
-
-  FastCloneShallowArrayStub::Mode mode = mode_;
-  if (mode == CLONE_ANY_ELEMENTS) {
-    Label double_elements, check_fast_elements;
-    __ lw(v0, FieldMemOperand(a3, JSArray::kElementsOffset));
-    __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
-    __ LoadRoot(t1, Heap::kFixedCOWArrayMapRootIndex);
-    __ Branch(&check_fast_elements, ne, v0, Operand(t1));
-    GenerateFastCloneShallowArrayCommon(masm, 0, COPY_ON_WRITE_ELEMENTS,
-                                        allocation_site_mode_,
-                                        &slow_case);
-    // Return and remove the on-stack parameters.
-    __ DropAndRet(3);
-
-    __ bind(&check_fast_elements);
-    __ LoadRoot(t1, Heap::kFixedArrayMapRootIndex);
-    __ Branch(&double_elements, ne, v0, Operand(t1));
-    GenerateFastCloneShallowArrayCommon(masm, length_, CLONE_ELEMENTS,
-                                        allocation_site_mode_,
-                                        &slow_case);
-    // Return and remove the on-stack parameters.
-    __ DropAndRet(3);
-
-    __ bind(&double_elements);
-    mode = CLONE_DOUBLE_ELEMENTS;
-    // Fall through to generate the code to handle double elements.
-  }
-
-  if (FLAG_debug_code) {
-    const char* message;
-    Heap::RootListIndex expected_map_index;
-    if (mode == CLONE_ELEMENTS) {
-      message = "Expected (writable) fixed array";
-      expected_map_index = Heap::kFixedArrayMapRootIndex;
-    } else if (mode == CLONE_DOUBLE_ELEMENTS) {
-      message = "Expected (writable) fixed double array";
-      expected_map_index = Heap::kFixedDoubleArrayMapRootIndex;
-    } else {
-      ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
-      message = "Expected copy-on-write fixed array";
-      expected_map_index = Heap::kFixedCOWArrayMapRootIndex;
-    }
-    __ push(a3);
-    __ lw(a3, FieldMemOperand(a3, JSArray::kElementsOffset));
-    __ lw(a3, FieldMemOperand(a3, HeapObject::kMapOffset));
-    __ LoadRoot(at, expected_map_index);
-    __ Assert(eq, message, a3, Operand(at));
-    __ pop(a3);
-  }
-
-  GenerateFastCloneShallowArrayCommon(masm, length_, mode,
-                                      allocation_site_mode_,
-                                      &slow_case);
-
-  // Return and remove the on-stack parameters.
-  __ DropAndRet(3);
-
-  __ bind(&slow_case);
-  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
-}
-
-
 // Takes a Smi and converts to an IEEE 64 bit floating point value in two
 // registers.  The format is 1 sign bit, 11 exponent bits (biased 1023) and
 // 52 fraction bits (20 in the first word, 32 in the second).  Zeros is a
@@ -646,30 +515,15 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
                                    FloatingPointHelper::Destination destination,
                                    Register scratch1,
                                    Register scratch2) {
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    __ sra(scratch1, a0, kSmiTagSize);
-    __ mtc1(scratch1, f14);
-    __ cvt_d_w(f14, f14);
-    __ sra(scratch1, a1, kSmiTagSize);
-    __ mtc1(scratch1, f12);
-    __ cvt_d_w(f12, f12);
-    if (destination == kCoreRegisters) {
-      __ Move(a2, a3, f14);
-      __ Move(a0, a1, f12);
-    }
-  } else {
-    ASSERT(destination == kCoreRegisters);
-    // Write Smi from a0 to a3 and a2 in double format.
-    __ mov(scratch1, a0);
-    ConvertToDoubleStub stub1(a3, a2, scratch1, scratch2);
-    __ push(ra);
-    __ Call(stub1.GetCode(masm->isolate()));
-    // Write Smi from a1 to a1 and a0 in double format.
-    __ mov(scratch1, a1);
-    ConvertToDoubleStub stub2(a1, a0, scratch1, scratch2);
-    __ Call(stub2.GetCode(masm->isolate()));
-    __ pop(ra);
+  __ sra(scratch1, a0, kSmiTagSize);
+  __ mtc1(scratch1, f14);
+  __ cvt_d_w(f14, f14);
+  __ sra(scratch1, a1, kSmiTagSize);
+  __ mtc1(scratch1, f12);
+  __ cvt_d_w(f12, f12);
+  if (destination == kCoreRegisters) {
+    __ Move(a2, a3, f14);
+    __ Move(a0, a1, f12);
   }
 }
 
@@ -684,8 +538,6 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
                                      Register scratch1,
                                      Register scratch2,
                                      Label* not_number) {
-  ASSERT(!object.is(dst1) && !object.is(dst2));
-
   __ AssertRootValue(heap_number_map,
                      Heap::kHeapNumberMapRootIndex,
                      "HeapNumberMap register clobbered.");
@@ -698,9 +550,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
   __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
 
   // Handle loading a double from a heap number.
-  if (CpuFeatures::IsSupported(FPU) &&
-      destination == kFPURegisters) {
-    CpuFeatureScope scope(masm, FPU);
+  if (destination == kFPURegisters) {
     // Load the double from tagged HeapNumber to double register.
 
     // ARM uses a workaround here because of the unaligned HeapNumber
@@ -718,25 +568,13 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
 
   // Handle loading a double from a smi.
   __ bind(&is_smi);
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    // Convert smi to double using FPU instructions.
-    __ mtc1(scratch1, dst);
-    __ cvt_d_w(dst, dst);
-    if (destination == kCoreRegisters) {
-      // Load the converted smi to dst1 and dst2 in double format.
-      __ Move(dst1, dst2, dst);
-    }
-  } else {
-    ASSERT(destination == kCoreRegisters);
-    // Write smi to dst1 and dst2 double format.
-    __ mov(scratch1, object);
-    ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
-    __ push(ra);
-    __ Call(stub.GetCode(masm->isolate()));
-    __ pop(ra);
+  // Convert smi to double using FPU instructions.
+  __ mtc1(scratch1, dst);
+  __ cvt_d_w(dst, dst);
+  if (destination == kCoreRegisters) {
+    // Load the converted smi to dst1 and dst2 in double format.
+    __ Move(dst1, dst2, dst);
   }
-
   __ bind(&done);
 }
 
@@ -792,74 +630,11 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm,
   ASSERT(!int_scratch.is(dst_mantissa));
   ASSERT(!int_scratch.is(dst_exponent));
 
-  Label done;
-
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    __ mtc1(int_scratch, single_scratch);
-    __ cvt_d_w(double_dst, single_scratch);
-    if (destination == kCoreRegisters) {
-      __ Move(dst_mantissa, dst_exponent, double_dst);
-    }
-  } else {
-    Label fewer_than_20_useful_bits;
-    // Expected output:
-    // |       dst_exponent      |       dst_mantissa      |
-    // | s |   exp   |              mantissa               |
-
-    // Check for zero.
-    __ 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(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, 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(dst_mantissa, int_scratch);
-    __ li(scratch2, 31);
-    __ Subu(dst_mantissa, scratch2, dst_mantissa);
-
-    // Set the exponent.
-    __ 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, 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, 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_(dst_exponent, dst_exponent, at);
-    __ li(at, 32);
-    __ subu(scratch2, at, scratch2);
-    __ sllv(dst_mantissa, int_scratch, scratch2);
-    __ Branch(&done);
-
-    __ bind(&fewer_than_20_useful_bits);
-    __ li(at, HeapNumber::kMantissaBitsInTopWord);
-    __ subu(scratch2, at, dst_mantissa);
-    __ sllv(scratch2, int_scratch, scratch2);
-    __ Or(dst_exponent, dst_exponent, scratch2);
-    // Set dst_mantissa to 0.
-    __ mov(dst_mantissa, zero_reg);
+  __ mtc1(int_scratch, single_scratch);
+  __ cvt_d_w(double_dst, single_scratch);
+  if (destination == kCoreRegisters) {
+    __ Move(dst_mantissa, dst_exponent, double_dst);
   }
-  __ bind(&done);
 }
 
 
@@ -880,10 +655,6 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
   ASSERT(!heap_number_map.is(object) &&
          !heap_number_map.is(scratch1) &&
          !heap_number_map.is(scratch2));
-  // ARM uses pop/push and Ldlr to save dst_* and probably object registers in
-  // softfloat path. On MIPS there is no ldlr, 1st lw instruction may overwrite
-  // object register making the 2nd lw invalid.
-  ASSERT(!object.is(dst_mantissa) && !object.is(dst_exponent));
 
   Label done, obj_is_not_smi;
 
@@ -900,46 +671,23 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
   __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
 
   // Load the number.
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    // Load the double value.
-    __ ldc1(double_dst, FieldMemOperand(object, HeapNumber::kValueOffset));
-
-    Register except_flag = scratch2;
-    __ EmitFPUTruncate(kRoundToZero,
-                       scratch1,
-                       double_dst,
-                       at,
-                       double_scratch,
-                       except_flag,
-                       kCheckForInexactConversion);
-
-    // Jump to not_int32 if the operation did not succeed.
-    __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
-
-    if (destination == kCoreRegisters) {
-      __ Move(dst_mantissa, dst_exponent, double_dst);
-    }
-  } else {
-    // Load the double value in the destination registers.
-    __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
-    __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
-
-    // Check for 0 and -0.
-    __ And(scratch1, dst_exponent, Operand(~HeapNumber::kSignMask));
-    __ Or(scratch1, scratch1, Operand(dst_mantissa));
-    __ Branch(&done, 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, dst_exponent, dst_mantissa, scratch1, scratch2,
-                         not_int32);
-
-    // dst_* were trashed. Reload the double value.
-    __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
-    __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+  // Load the double value.
+  __ ldc1(double_dst, FieldMemOperand(object, HeapNumber::kValueOffset));
+
+  Register except_flag = scratch2;
+  __ EmitFPUTruncate(kRoundToZero,
+                     scratch1,
+                     double_dst,
+                     at,
+                     double_scratch,
+                     except_flag,
+                     kCheckForInexactConversion);
+
+  // Jump to not_int32 if the operation did not succeed.
+  __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
+  if (destination == kCoreRegisters) {
+    __ Move(dst_mantissa, dst_exponent, double_dst);
   }
-
   __ bind(&done);
 }
 
@@ -972,53 +720,20 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
 
   // Object is a heap number.
   // Convert the floating point value to a 32-bit integer.
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    // Load the double value.
-    __ ldc1(double_scratch0, FieldMemOperand(object, HeapNumber::kValueOffset));
-
-    Register except_flag = scratch2;
-    __ EmitFPUTruncate(kRoundToZero,
-                       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));
-  } else {
-    // Load the double value in the destination registers.
-    __ lw(scratch2, FieldMemOperand(object, HeapNumber::kExponentOffset));
-    __ lw(scratch1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
-
-    // Check for 0 and -0.
-    __ And(dst, scratch1, Operand(~HeapNumber::kSignMask));
-    __ Or(dst, scratch2, Operand(dst));
-    __ Branch(&done, eq, dst, Operand(zero_reg));
-
-    DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32);
-
-    // Registers state after DoubleIs32BitInteger.
-    // dst: mantissa[51:20].
-    // scratch2: 1
-
-    // Shift back the higher bits of the mantissa.
-    __ srlv(dst, dst, scratch3);
-    // Set the implicit first bit.
-    __ li(at, 32);
-    __ subu(scratch3, at, scratch3);
-    __ sllv(scratch2, scratch2, scratch3);
-    __ Or(dst, dst, scratch2);
-    // Set the sign.
-    __ lw(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
-    __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
-    Label skip_sub;
-    __ Branch(&skip_sub, ge, scratch1, Operand(zero_reg));
-    __ Subu(dst, zero_reg, dst);
-    __ bind(&skip_sub);
-  }
+  // Load the double value.
+  __ ldc1(double_scratch0, FieldMemOperand(object, HeapNumber::kValueOffset));
+
+  Register except_flag = scratch2;
+  __ EmitFPUTruncate(kRoundToZero,
+                     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));
   __ Branch(&done);
 
   __ bind(&maybe_undefined);
@@ -1032,66 +747,6 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
 }
 
 
-void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm,
-                                               Register src_exponent,
-                                               Register src_mantissa,
-                                               Register dst,
-                                               Register scratch,
-                                               Label* not_int32) {
-  // Get exponent alone in scratch.
-  __ Ext(scratch,
-         src_exponent,
-         HeapNumber::kExponentShift,
-         HeapNumber::kExponentBits);
-
-  // Substract the bias from the exponent.
-  __ Subu(scratch, scratch, Operand(HeapNumber::kExponentBias));
-
-  // src1: higher (exponent) part of the double value.
-  // src2: lower (mantissa) part of the double value.
-  // scratch: unbiased exponent.
-
-  // Fast cases. Check for obvious non 32-bit integer values.
-  // Negative exponent cannot yield 32-bit integers.
-  __ Branch(not_int32, lt, scratch, Operand(zero_reg));
-  // Exponent greater than 31 cannot yield 32-bit integers.
-  // Also, a positive value with an exponent equal to 31 is outside of the
-  // signed 32-bit integer range.
-  // 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, 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, src_mantissa, 0x3fffff);
-  __ Branch(not_int32, ne, tmp, Operand(zero_reg));
-
-  // Otherwise the exponent needs to be big enough to shift left all the
-  // non zero bits left. So we need the (30 - exponent) last bits of the
-  // 31 higher bits of the mantissa to be null.
-  // Because bits [21:0] are null, we can check instead that the
-  // (32 - exponent) last bits of the 32 higher bits of the mantissa are null.
-
-  // Get the 32 higher bits of the mantissa in dst.
-  __ Ext(dst,
-         src_mantissa,
-         HeapNumber::kMantissaBitsInTopWord,
-         32 - HeapNumber::kMantissaBitsInTopWord);
-  __ 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(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));
-}
-
-
 void FloatingPointHelper::CallCCodeForDoubleOperation(
     MacroAssembler* masm,
     Token::Value op,
@@ -1111,7 +766,6 @@ void FloatingPointHelper::CallCCodeForDoubleOperation(
   __ push(ra);
   __ PrepareCallCFunction(4, scratch);  // Two doubles are 4 arguments.
   if (!IsMipsSoftFloatABI) {
-    CpuFeatureScope scope(masm, FPU);
     // We are not using MIPS FPU instructions, and parameters for the runtime
     // function call are prepaired in a0-a3 registers, but function we are
     // calling is compiled with hard-float flag and expecting hard float ABI
@@ -1127,7 +781,6 @@ void FloatingPointHelper::CallCCodeForDoubleOperation(
   }
   // Store answer in the overwritable heap number.
   if (!IsMipsSoftFloatABI) {
-    CpuFeatureScope scope(masm, FPU);
     // Double returned in register f0.
     __ sdc1(f0, FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
   } else {
@@ -1350,25 +1003,10 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
 
   // Rhs is a smi, lhs is a number.
   // Convert smi rhs to double.
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    __ sra(at, rhs, kSmiTagSize);
-    __ mtc1(at, f14);
-    __ cvt_d_w(f14, f14);
-    __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
-  } else {
-    // Load lhs to a double in a2, a3.
-    __ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4));
-    __ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset));
-
-    // Write Smi from rhs to a1 and a0 in double format. t5 is scratch.
-    __ mov(t6, rhs);
-    ConvertToDoubleStub stub1(a1, a0, t6, t5);
-    __ push(ra);
-    __ Call(stub1.GetCode(masm->isolate()));
-
-    __ pop(ra);
-  }
+  __ sra(at, rhs, kSmiTagSize);
+  __ mtc1(at, f14);
+  __ cvt_d_w(f14, f14);
+  __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
 
   // We now have both loaded as doubles.
   __ jmp(both_loaded_as_doubles);
@@ -1389,179 +1027,14 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
 
   // Lhs is a smi, rhs is a number.
   // Convert smi lhs to double.
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    __ sra(at, lhs, kSmiTagSize);
-    __ mtc1(at, f12);
-    __ cvt_d_w(f12, f12);
-    __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
-  } else {
-    // Convert lhs to a double format. t5 is scratch.
-    __ mov(t6, lhs);
-    ConvertToDoubleStub stub2(a3, a2, t6, t5);
-    __ push(ra);
-    __ Call(stub2.GetCode(masm->isolate()));
-    __ pop(ra);
-    // Load rhs to a double in a1, a0.
-    if (rhs.is(a0)) {
-      __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
-      __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
-    } else {
-      __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
-      __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
-    }
-  }
+  __ sra(at, lhs, kSmiTagSize);
+  __ mtc1(at, f12);
+  __ cvt_d_w(f12, f12);
+  __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
   // Fall through to both_loaded_as_doubles.
 }
 
 
-void EmitNanCheck(MacroAssembler* masm, Condition cc) {
-  bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    // Lhs and rhs are already loaded to f12 and f14 register pairs.
-    __ Move(t0, t1, f14);
-    __ Move(t2, t3, f12);
-  } else {
-    // Lhs and rhs are already loaded to GP registers.
-    __ mov(t0, a0);  // a0 has LS 32 bits of rhs.
-    __ mov(t1, a1);  // a1 has MS 32 bits of rhs.
-    __ mov(t2, a2);  // a2 has LS 32 bits of lhs.
-    __ mov(t3, a3);  // a3 has MS 32 bits of lhs.
-  }
-  Register rhs_exponent = exp_first ? t0 : t1;
-  Register lhs_exponent = exp_first ? t2 : t3;
-  Register rhs_mantissa = exp_first ? t1 : t0;
-  Register lhs_mantissa = exp_first ? t3 : t2;
-  Label one_is_nan, neither_is_nan;
-  Label lhs_not_nan_exp_mask_is_loaded;
-
-  Register exp_mask_reg = t4;
-  __ li(exp_mask_reg, HeapNumber::kExponentMask);
-  __ and_(t5, lhs_exponent, exp_mask_reg);
-  __ Branch(&lhs_not_nan_exp_mask_is_loaded, ne, t5, Operand(exp_mask_reg));
-
-  __ sll(t5, lhs_exponent, HeapNumber::kNonMantissaBitsInTopWord);
-  __ Branch(&one_is_nan, ne, t5, Operand(zero_reg));
-
-  __ Branch(&one_is_nan, ne, lhs_mantissa, Operand(zero_reg));
-
-  __ li(exp_mask_reg, HeapNumber::kExponentMask);
-  __ bind(&lhs_not_nan_exp_mask_is_loaded);
-  __ and_(t5, rhs_exponent, exp_mask_reg);
-
-  __ Branch(&neither_is_nan, ne, t5, Operand(exp_mask_reg));
-
-  __ sll(t5, rhs_exponent, HeapNumber::kNonMantissaBitsInTopWord);
-  __ Branch(&one_is_nan, ne, t5, Operand(zero_reg));
-
-  __ Branch(&neither_is_nan, eq, rhs_mantissa, Operand(zero_reg));
-
-  __ bind(&one_is_nan);
-  // NaN comparisons always fail.
-  // Load whatever we need in v0 to make the comparison fail.
-
-  if (cc == lt || cc == le) {
-    __ li(v0, Operand(GREATER));
-  } else {
-    __ li(v0, Operand(LESS));
-  }
-  __ Ret();
-
-  __ bind(&neither_is_nan);
-}
-
-
-static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) {
-  // f12 and f14 have the two doubles.  Neither is a NaN.
-  // Call a native function to do a comparison between two non-NaNs.
-  // Call C routine that may not cause GC or other trouble.
-  // We use a call_was and return manually because we need arguments slots to
-  // be freed.
-
-  Label return_result_not_equal, return_result_equal;
-  if (cc == eq) {
-    // Doubles are not equal unless they have the same bit pattern.
-    // Exception: 0 and -0.
-    bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
-    if (CpuFeatures::IsSupported(FPU)) {
-      CpuFeatureScope scope(masm, FPU);
-      // Lhs and rhs are already loaded to f12 and f14 register pairs.
-      __ Move(t0, t1, f14);
-      __ Move(t2, t3, f12);
-    } else {
-      // Lhs and rhs are already loaded to GP registers.
-      __ mov(t0, a0);  // a0 has LS 32 bits of rhs.
-      __ mov(t1, a1);  // a1 has MS 32 bits of rhs.
-      __ mov(t2, a2);  // a2 has LS 32 bits of lhs.
-      __ mov(t3, a3);  // a3 has MS 32 bits of lhs.
-    }
-    Register rhs_exponent = exp_first ? t0 : t1;
-    Register lhs_exponent = exp_first ? t2 : t3;
-    Register rhs_mantissa = exp_first ? t1 : t0;
-    Register lhs_mantissa = exp_first ? t3 : t2;
-
-    __ xor_(v0, rhs_mantissa, lhs_mantissa);
-    __ Branch(&return_result_not_equal, ne, v0, Operand(zero_reg));
-
-    __ subu(v0, rhs_exponent, lhs_exponent);
-    __ Branch(&return_result_equal, eq, v0, Operand(zero_reg));
-    // 0, -0 case.
-    __ sll(rhs_exponent, rhs_exponent, kSmiTagSize);
-    __ sll(lhs_exponent, lhs_exponent, kSmiTagSize);
-    __ or_(t4, rhs_exponent, lhs_exponent);
-    __ or_(t4, t4, rhs_mantissa);
-
-    __ Branch(&return_result_not_equal, ne, t4, Operand(zero_reg));
-
-    __ bind(&return_result_equal);
-
-    __ li(v0, Operand(EQUAL));
-    __ Ret();
-  }
-
-  __ bind(&return_result_not_equal);
-
-  if (!CpuFeatures::IsSupported(FPU)) {
-    __ push(ra);
-    __ PrepareCallCFunction(0, 2, t4);
-    if (!IsMipsSoftFloatABI) {
-      // We are not using MIPS FPU instructions, and parameters for the runtime
-      // function call are prepaired in a0-a3 registers, but function we are
-      // calling is compiled with hard-float flag and expecting hard float ABI
-      // (parameters in f12/f14 registers). We need to copy parameters from
-      // a0-a3 registers to f12/f14 register pairs.
-      __ Move(f12, a0, a1);
-      __ Move(f14, a2, a3);
-    }
-
-    AllowExternalCallThatCantCauseGC scope(masm);
-    __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()),
-       0, 2);
-    __ pop(ra);  // Because this function returns int, result is in v0.
-    __ Ret();
-  } else {
-    CpuFeatureScope scope(masm, FPU);
-    Label equal, less_than;
-    __ BranchF(&equal, NULL, eq, f12, f14);
-    __ BranchF(&less_than, NULL, lt, f12, f14);
-
-    // Not equal, not less, not NaN, must be greater.
-
-    __ li(v0, Operand(GREATER));
-    __ Ret();
-
-    __ bind(&equal);
-    __ li(v0, Operand(EQUAL));
-    __ Ret();
-
-    __ bind(&less_than);
-    __ li(v0, Operand(LESS));
-    __ Ret();
-  }
-}
-
-
 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
                                            Register lhs,
                                            Register rhs) {
@@ -1616,21 +1089,9 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
 
   // Both are heap numbers. Load them up then jump to the code we have
   // for that.
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
-    __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
-  } else {
-    __ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset));
-    __ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4));
-    if (rhs.is(a0)) {
-      __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
-      __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
-    } else {
-      __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset));
-      __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4));
-    }
-  }
+  __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset));
+  __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset));
+
   __ jmp(both_loaded_as_doubles);
 }
 
@@ -1711,42 +1172,34 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
   Label load_result_from_cache;
   if (!object_is_smi) {
     __ JumpIfSmi(object, &is_smi);
-    if (CpuFeatures::IsSupported(FPU)) {
-      CpuFeatureScope scope(masm, FPU);
-      __ CheckMap(object,
-                  scratch1,
-                  Heap::kHeapNumberMapRootIndex,
-                  not_found,
-                  DONT_DO_SMI_CHECK);
-
-      STATIC_ASSERT(8 == kDoubleSize);
-      __ Addu(scratch1,
-              object,
-              Operand(HeapNumber::kValueOffset - kHeapObjectTag));
-      __ lw(scratch2, MemOperand(scratch1, kPointerSize));
-      __ lw(scratch1, MemOperand(scratch1, 0));
-      __ Xor(scratch1, scratch1, Operand(scratch2));
-      __ And(scratch1, scratch1, Operand(mask));
-
-      // Calculate address of entry in string cache: each entry consists
-      // of two pointer sized fields.
-      __ sll(scratch1, scratch1, kPointerSizeLog2 + 1);
-      __ Addu(scratch1, number_string_cache, scratch1);
-
-      Register probe = mask;
-      __ lw(probe,
-             FieldMemOperand(scratch1, FixedArray::kHeaderSize));
-      __ JumpIfSmi(probe, not_found);
-      __ ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset));
-      __ ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset));
-      __ BranchF(&load_result_from_cache, NULL, eq, f12, f14);
-      __ Branch(not_found);
-    } else {
-      // Note that there is no cache check for non-FPU case, even though
-      // it seems there could be. May be a tiny opimization for non-FPU
-      // cores.
-      __ Branch(not_found);
-    }
+    __ CheckMap(object,
+                scratch1,
+                Heap::kHeapNumberMapRootIndex,
+                not_found,
+                DONT_DO_SMI_CHECK);
+
+    STATIC_ASSERT(8 == kDoubleSize);
+    __ Addu(scratch1,
+            object,
+            Operand(HeapNumber::kValueOffset - kHeapObjectTag));
+    __ lw(scratch2, MemOperand(scratch1, kPointerSize));
+    __ lw(scratch1, MemOperand(scratch1, 0));
+    __ Xor(scratch1, scratch1, Operand(scratch2));
+    __ And(scratch1, scratch1, Operand(mask));
+
+    // Calculate address of entry in string cache: each entry consists
+    // of two pointer sized fields.
+    __ sll(scratch1, scratch1, kPointerSizeLog2 + 1);
+    __ Addu(scratch1, number_string_cache, scratch1);
+
+    Register probe = mask;
+    __ lw(probe,
+           FieldMemOperand(scratch1, FixedArray::kHeaderSize));
+    __ JumpIfSmi(probe, not_found);
+    __ ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset));
+    __ ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset));
+    __ BranchF(&load_result_from_cache, NULL, eq, f12, f14);
+    __ Branch(not_found);
   }
 
   __ bind(&is_smi);
@@ -1864,49 +1317,38 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
   // left hand side and a0, a1 represent right hand side.
 
   Isolate* isolate = masm->isolate();
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    Label nan;
-    __ li(t0, Operand(LESS));
-    __ li(t1, Operand(GREATER));
-    __ li(t2, Operand(EQUAL));
-
-    // Check if either rhs or lhs is NaN.
-    __ BranchF(NULL, &nan, eq, f12, f14);
-
-    // Check if LESS condition is satisfied. If true, move conditionally
-    // result to v0.
-    __ c(OLT, D, f12, f14);
-    __ Movt(v0, t0);
-    // Use previous check to store conditionally to v0 oposite condition
-    // (GREATER). If rhs is equal to lhs, this will be corrected in next
-    // check.
-    __ Movf(v0, t1);
-    // Check if EQUAL condition is satisfied. If true, move conditionally
-    // result to v0.
-    __ c(EQ, D, f12, f14);
-    __ Movt(v0, t2);
+  Label nan;
+  __ li(t0, Operand(LESS));
+  __ li(t1, Operand(GREATER));
+  __ li(t2, Operand(EQUAL));
+
+  // Check if either rhs or lhs is NaN.
+  __ BranchF(NULL, &nan, eq, f12, f14);
+
+  // Check if LESS condition is satisfied. If true, move conditionally
+  // result to v0.
+  __ c(OLT, D, f12, f14);
+  __ Movt(v0, t0);
+  // Use previous check to store conditionally to v0 oposite condition
+  // (GREATER). If rhs is equal to lhs, this will be corrected in next
+  // check.
+  __ Movf(v0, t1);
+  // Check if EQUAL condition is satisfied. If true, move conditionally
+  // result to v0.
+  __ c(EQ, D, f12, f14);
+  __ Movt(v0, t2);
 
-    __ Ret();
+  __ Ret();
 
-    __ bind(&nan);
-    // NaN comparisons always fail.
-    // Load whatever we need in v0 to make the comparison fail.
-    if (cc == lt || cc == le) {
-      __ li(v0, Operand(GREATER));
-    } else {
-      __ li(v0, Operand(LESS));
-    }
-    __ Ret();
+  __ bind(&nan);
+  // NaN comparisons always fail.
+  // Load whatever we need in v0 to make the comparison fail.
+  if (cc == lt || cc == le) {
+    __ li(v0, Operand(GREATER));
   } 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);
-
-    // Compares two doubles that are not NaNs. Returns the answer.
-    // Never falls through.
-    EmitTwoNonNanDoubleComparison(masm, cc);
+    __ li(v0, Operand(LESS));
   }
+  __ Ret();
 
   __ bind(&not_smis);
   // At this point we know we are dealing with two different objects,
@@ -1999,9 +1441,6 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
 // The stub expects its argument in the tos_ register and returns its result in
 // it, too: zero for false, and a non-zero value for true.
 void ToBooleanStub::Generate(MacroAssembler* masm) {
-  // This stub uses FPU instructions.
-  CpuFeatureScope scope(masm, FPU);
-
   Label patch;
   const Register map = t5.is(tos_) ? t3 : t5;
 
@@ -2115,7 +1554,6 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
   // restore them.
   __ MultiPush(kJSCallerSaved | ra.bit());
   if (save_doubles_ == kSaveFPRegs) {
-    CpuFeatureScope scope(masm, FPU);
     __ MultiPushFPU(kCallerSavedFPU);
   }
   const int argument_count = 1;
@@ -2129,7 +1567,6 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
       ExternalReference::store_buffer_overflow_function(masm->isolate()),
       argument_count);
   if (save_doubles_ == kSaveFPRegs) {
-    CpuFeatureScope scope(masm, FPU);
     __ MultiPopFPU(kCallerSavedFPU);
   }
 
@@ -2360,19 +1797,11 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(
     __ mov(v0, a2);  // Move newly allocated heap number to v0.
   }
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    // Convert the int32 in a1 to the heap number in v0. a2 is corrupted.
-    CpuFeatureScope scope(masm, FPU);
-    __ mtc1(a1, f0);
-    __ cvt_d_w(f0, f0);
-    __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
-    __ Ret();
-  } else {
-    // WriteInt32ToHeapNumberStub does not trigger GC, so we do not
-    // have to set up a frame.
-    WriteInt32ToHeapNumberStub stub(a1, v0, a2, a3);
-    __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
-  }
+  // Convert the int32 in a1 to the heap number in v0. a2 is corrupted.
+  __ mtc1(a1, f0);
+  __ cvt_d_w(f0, f0);
+  __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+  __ Ret();
 
   __ bind(&impossible);
   if (FLAG_debug_code) {
@@ -2434,7 +1863,7 @@ void UnaryOpStub::GenerateGenericCodeFallback(
 
 
 void BinaryOpStub::Initialize() {
-  platform_specific_bit_ = CpuFeatures::IsSupported(FPU);
+  platform_specific_bit_ = true;  // FPU is a base requirement for V8.
 }
 
 
@@ -2661,9 +2090,8 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
     case Token::DIV:
     case Token::MOD: {
       // Load left and right operands into f12 and f14 or a0/a1 and a2/a3
-      // depending on whether FPU is available or not.
+      // depending on operation.
       FloatingPointHelper::Destination destination =
-          CpuFeatures::IsSupported(FPU) &&
           op != Token::MOD ?
               FloatingPointHelper::kFPURegisters :
               FloatingPointHelper::kCoreRegisters;
@@ -2688,20 +2116,16 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
               masm, destination, right, f14, a2, a3, heap_number_map,
               scratch1, scratch2, fail);
         }
-        // Use scratch3 as left in LoadNumber functions to avoid overwriting of
-        // left (a0) register.
-        __ mov(scratch3, left);
-
         // 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, scratch3, destination, f12, f16, a0, a1, heap_number_map,
+              masm, left, destination, f12, f16, a0, a1, heap_number_map,
               scratch1, scratch2, f2, miss);
         } else {
           Label* fail = (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
           FloatingPointHelper::LoadNumber(
-              masm, destination, scratch3, f12, a0, a1, heap_number_map,
+              masm, destination, left, f12, a0, a1, heap_number_map,
               scratch1, scratch2, fail);
         }
       }
@@ -2711,7 +2135,6 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
         // Using FPU registers:
         // f12: Left value.
         // f14: Right value.
-        CpuFeatureScope scope(masm, FPU);
         switch (op) {
         case Token::ADD:
           __ add_d(f10, f12, f14);
@@ -2801,11 +2224,7 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
           // The code below for writing into heap numbers isn't capable of
           // writing the register as an unsigned int so we go to slow case if we
           // hit this case.
-          if (CpuFeatures::IsSupported(FPU)) {
-            __ Branch(&result_not_a_smi, lt, a2, Operand(zero_reg));
-          } else {
-            __ Branch(not_numbers, lt, a2, Operand(zero_reg));
-          }
+          __ Branch(&result_not_a_smi, lt, a2, Operand(zero_reg));
           break;
         case Token::SHL:
           // Use only the 5 least significant bits of the shift count.
@@ -2839,28 +2258,19 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
       // Nothing can go wrong now, so move the heap number to v0, which is the
       // result.
       __ mov(v0, t1);
-
-      if (CpuFeatures::IsSupported(FPU)) {
-        // Convert the int32 in a2 to the heap number in a0. As
-        // mentioned above SHR needs to always produce a positive result.
-        CpuFeatureScope scope(masm, FPU);
-        __ mtc1(a2, f0);
-        if (op == Token::SHR) {
-          __ Cvt_d_uw(f0, f0, f22);
-        } else {
-          __ cvt_d_w(f0, f0);
-        }
-        // ARM uses a workaround here because of the unaligned HeapNumber
-        // kValueOffset. On MIPS this workaround is built into sdc1 so
-        // there's no point in generating even more instructions.
-        __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
-        __ Ret();
+      // Convert the int32 in a2 to the heap number in a0. As
+      // mentioned above SHR needs to always produce a positive result.
+      __ mtc1(a2, f0);
+      if (op == Token::SHR) {
+        __ Cvt_d_uw(f0, f0, f22);
       } else {
-        // Tail call that writes the int32 in a2 to the heap number in v0, using
-        // a3 and a0 as scratch. v0 is preserved and returned.
-        WriteInt32ToHeapNumberStub stub(a2, v0, a3, a0);
-        __ TailCallStub(&stub);
+        __ cvt_d_w(f0, f0);
       }
+      // ARM uses a workaround here because of the unaligned HeapNumber
+      // kValueOffset. On MIPS this workaround is built into sdc1 so
+      // there's no point in generating even more instructions.
+      __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+      __ Ret();
       break;
     }
     default:
@@ -3007,8 +2417,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
       // 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.
-      FloatingPointHelper::Destination destination =
-          (CpuFeatures::IsSupported(FPU) && op_ != Token::MOD)
+      FloatingPointHelper::Destination destination = (op_ != Token::MOD)
               ? FloatingPointHelper::kFPURegisters
               : FloatingPointHelper::kCoreRegisters;
 
@@ -3038,7 +2447,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
                                                    &transition);
 
       if (destination == FloatingPointHelper::kFPURegisters) {
-        CpuFeatureScope scope(masm, FPU);
         Label return_heap_number;
         switch (op_) {
           case Token::ADD:
@@ -3207,23 +2615,12 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
           // We only get a negative result if the shift value (a2) is 0.
           // This result cannot be respresented as a signed 32-bit integer, try
           // to return a heap number if we can.
-          // The non FPU code does not support this special case, so jump to
-          // runtime if we don't support it.
-          if (CpuFeatures::IsSupported(FPU)) {
-            __ Branch((result_type_ <= BinaryOpIC::INT32)
-                        ? &transition
-                        : &return_heap_number,
-                       lt,
-                       a2,
-                       Operand(zero_reg));
-          } else {
-            __ Branch((result_type_ <= BinaryOpIC::INT32)
-                        ? &transition
-                        : &call_runtime,
-                       lt,
-                       a2,
-                       Operand(zero_reg));
-          }
+          __ Branch((result_type_ <= BinaryOpIC::INT32)
+                      ? &transition
+                      : &return_heap_number,
+                     lt,
+                     a2,
+                     Operand(zero_reg));
           break;
         case Token::SHL:
           __ And(a2, a2, Operand(0x1f));
@@ -3251,31 +2648,21 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
                                                 &call_runtime,
                                                 mode_);
 
-      if (CpuFeatures::IsSupported(FPU)) {
-        CpuFeatureScope scope(masm, FPU);
-
-        if (op_ != Token::SHR) {
-          // Convert the result to a floating point value.
-          __ mtc1(a2, double_scratch);
-          __ cvt_d_w(double_scratch, double_scratch);
-        } else {
-          // The result must be interpreted as an unsigned 32-bit integer.
-          __ mtc1(a2, double_scratch);
-          __ Cvt_d_uw(double_scratch, double_scratch, single_scratch);
-        }
-
-        // Store the result.
-        __ mov(v0, heap_number_result);
-        __ sdc1(double_scratch, FieldMemOperand(v0, HeapNumber::kValueOffset));
-        __ Ret();
+      if (op_ != Token::SHR) {
+        // Convert the result to a floating point value.
+        __ mtc1(a2, double_scratch);
+        __ cvt_d_w(double_scratch, double_scratch);
       } else {
-        // Tail call that writes the int32 in a2 to the heap number in v0, using
-        // a3 and a0 as scratch. v0 is preserved and returned.
-        __ mov(v0, t1);
-        WriteInt32ToHeapNumberStub stub(a2, v0, a3, a0);
-        __ TailCallStub(&stub);
+        // The result must be interpreted as an unsigned 32-bit integer.
+        __ mtc1(a2, double_scratch);
+        __ Cvt_d_uw(double_scratch, double_scratch, single_scratch);
       }
 
+      // Store the result.
+      __ mov(v0, heap_number_result);
+      __ sdc1(double_scratch, FieldMemOperand(v0, HeapNumber::kValueOffset));
+      __ Ret();
+
       break;
     }
 
@@ -3455,107 +2842,102 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
   const Register cache_entry = a0;
   const bool tagged = (argument_type_ == TAGGED);
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-
-    if (tagged) {
-      // Argument is a number and is on stack and in a0.
-      // Load argument and check if it is a smi.
-      __ JumpIfNotSmi(a0, &input_not_smi);
-
-      // Input is a smi. Convert to double and load the low and high words
-      // of the double into a2, a3.
-      __ sra(t0, a0, kSmiTagSize);
-      __ mtc1(t0, f4);
-      __ cvt_d_w(f4, f4);
-      __ Move(a2, a3, f4);
-      __ Branch(&loaded);
-
-      __ bind(&input_not_smi);
-      // Check if input is a HeapNumber.
-      __ CheckMap(a0,
-                  a1,
-                  Heap::kHeapNumberMapRootIndex,
-                  &calculate,
-                  DONT_DO_SMI_CHECK);
-      // Input is a HeapNumber. Store the
-      // low and high words into a2, a3.
-      __ lw(a2, FieldMemOperand(a0, HeapNumber::kValueOffset));
-      __ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4));
-    } else {
-      // Input is untagged double in f4. Output goes to f4.
-      __ Move(a2, a3, f4);
-    }
-    __ bind(&loaded);
-    // a2 = low 32 bits of double value.
-    // a3 = high 32 bits of double value.
-    // Compute hash (the shifts are arithmetic):
-    //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
-    __ Xor(a1, a2, a3);
-    __ sra(t0, a1, 16);
-    __ Xor(a1, a1, t0);
-    __ sra(t0, a1, 8);
-    __ Xor(a1, a1, t0);
-    ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
-    __ And(a1, a1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
-
-    // a2 = low 32 bits of double value.
-    // a3 = high 32 bits of double value.
-    // a1 = TranscendentalCache::hash(double value).
-    __ li(cache_entry, Operand(
-        ExternalReference::transcendental_cache_array_address(
-            masm->isolate())));
-    // a0 points to cache array.
-    __ lw(cache_entry, MemOperand(cache_entry, type_ * sizeof(
-        Isolate::Current()->transcendental_cache()->caches_[0])));
-    // a0 points to the cache for the type type_.
-    // If NULL, the cache hasn't been initialized yet, so go through runtime.
-    __ Branch(&invalid_cache, eq, cache_entry, Operand(zero_reg));
+  if (tagged) {
+    // Argument is a number and is on stack and in a0.
+    // Load argument and check if it is a smi.
+    __ JumpIfNotSmi(a0, &input_not_smi);
+
+    // Input is a smi. Convert to double and load the low and high words
+    // of the double into a2, a3.
+    __ sra(t0, a0, kSmiTagSize);
+    __ mtc1(t0, f4);
+    __ cvt_d_w(f4, f4);
+    __ Move(a2, a3, f4);
+    __ Branch(&loaded);
+
+    __ bind(&input_not_smi);
+    // Check if input is a HeapNumber.
+    __ CheckMap(a0,
+                a1,
+                Heap::kHeapNumberMapRootIndex,
+                &calculate,
+                DONT_DO_SMI_CHECK);
+    // Input is a HeapNumber. Store the
+    // low and high words into a2, a3.
+    __ lw(a2, FieldMemOperand(a0, HeapNumber::kValueOffset));
+    __ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4));
+  } else {
+    // Input is untagged double in f4. Output goes to f4.
+    __ Move(a2, a3, f4);
+  }
+  __ bind(&loaded);
+  // a2 = low 32 bits of double value.
+  // a3 = high 32 bits of double value.
+  // Compute hash (the shifts are arithmetic):
+  //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
+  __ Xor(a1, a2, a3);
+  __ sra(t0, a1, 16);
+  __ Xor(a1, a1, t0);
+  __ sra(t0, a1, 8);
+  __ Xor(a1, a1, t0);
+  ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
+  __ And(a1, a1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
+
+  // a2 = low 32 bits of double value.
+  // a3 = high 32 bits of double value.
+  // a1 = TranscendentalCache::hash(double value).
+  __ li(cache_entry, Operand(
+      ExternalReference::transcendental_cache_array_address(
+          masm->isolate())));
+  // a0 points to cache array.
+  __ lw(cache_entry, MemOperand(cache_entry, type_ * sizeof(
+      Isolate::Current()->transcendental_cache()->caches_[0])));
+  // a0 points to the cache for the type type_.
+  // If NULL, the cache hasn't been initialized yet, so go through runtime.
+  __ Branch(&invalid_cache, eq, cache_entry, Operand(zero_reg));
 
 #ifdef DEBUG
-    // Check that the layout of cache elements match expectations.
-    { TranscendentalCache::SubCache::Element test_elem[2];
-      char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
-      char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
-      char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
-      char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
-      char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
-      CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer.
-      CHECK_EQ(0, elem_in0 - elem_start);
-      CHECK_EQ(kIntSize, elem_in1 - elem_start);
-      CHECK_EQ(2 * kIntSize, elem_out - elem_start);
-    }
+  // Check that the layout of cache elements match expectations.
+  { TranscendentalCache::SubCache::Element test_elem[2];
+    char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
+    char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
+    char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
+    char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
+    char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
+    CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer.
+    CHECK_EQ(0, elem_in0 - elem_start);
+    CHECK_EQ(kIntSize, elem_in1 - elem_start);
+    CHECK_EQ(2 * kIntSize, elem_out - elem_start);
+  }
 #endif
 
-    // Find the address of the a1'st entry in the cache, i.e., &a0[a1*12].
-    __ sll(t0, a1, 1);
-    __ Addu(a1, a1, t0);
-    __ sll(t0, a1, 2);
-    __ Addu(cache_entry, cache_entry, t0);
-
-    // Check if cache matches: Double value is stored in uint32_t[2] array.
-    __ lw(t0, MemOperand(cache_entry, 0));
-    __ lw(t1, MemOperand(cache_entry, 4));
-    __ lw(t2, MemOperand(cache_entry, 8));
-    __ Branch(&calculate, ne, a2, Operand(t0));
-    __ Branch(&calculate, ne, a3, Operand(t1));
-    // Cache hit. Load result, cleanup and return.
-    Counters* counters = masm->isolate()->counters();
-    __ IncrementCounter(
-        counters->transcendental_cache_hit(), 1, scratch0, scratch1);
-    if (tagged) {
-      // Pop input value from stack and load result into v0.
-      __ Drop(1);
-      __ mov(v0, t2);
-    } else {
-      // Load result into f4.
-      __ ldc1(f4, FieldMemOperand(t2, HeapNumber::kValueOffset));
-    }
-    __ Ret();
-  }  // if (CpuFeatures::IsSupported(FPU))
+  // Find the address of the a1'st entry in the cache, i.e., &a0[a1*12].
+  __ sll(t0, a1, 1);
+  __ Addu(a1, a1, t0);
+  __ sll(t0, a1, 2);
+  __ Addu(cache_entry, cache_entry, t0);
+
+  // Check if cache matches: Double value is stored in uint32_t[2] array.
+  __ lw(t0, MemOperand(cache_entry, 0));
+  __ lw(t1, MemOperand(cache_entry, 4));
+  __ lw(t2, MemOperand(cache_entry, 8));
+  __ Branch(&calculate, ne, a2, Operand(t0));
+  __ Branch(&calculate, ne, a3, Operand(t1));
+  // Cache hit. Load result, cleanup and return.
+  Counters* counters = masm->isolate()->counters();
+  __ IncrementCounter(
+      counters->transcendental_cache_hit(), 1, scratch0, scratch1);
+  if (tagged) {
+    // Pop input value from stack and load result into v0.
+    __ Drop(1);
+    __ mov(v0, t2);
+  } else {
+    // Load result into f4.
+    __ ldc1(f4, FieldMemOperand(t2, HeapNumber::kValueOffset));
+  }
+  __ Ret();
 
   __ bind(&calculate);
-  Counters* counters = masm->isolate()->counters();
   __ IncrementCounter(
       counters->transcendental_cache_miss(), 1, scratch0, scratch1);
   if (tagged) {
@@ -3565,9 +2947,6 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
                                  1,
                                  1);
   } else {
-    ASSERT(CpuFeatures::IsSupported(FPU));
-    CpuFeatureScope scope(masm, FPU);
-
     Label no_update;
     Label skip_cache;
 
@@ -3694,7 +3073,6 @@ void InterruptStub::Generate(MacroAssembler* masm) {
 
 
 void MathPowStub::Generate(MacroAssembler* masm) {
-  CpuFeatureScope fpu_scope(masm, FPU);
   const Register base = a1;
   const Register exponent = a2;
   const Register heapnumbermap = t1;
@@ -3924,14 +3302,13 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   CEntryStub::GenerateAheadOfTime(isolate);
   WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
   StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+  StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
 }
 
 
 void CodeStub::GenerateFPStubs(Isolate* isolate) {
-  SaveFPRegsMode mode = CpuFeatures::IsSupported(FPU)
-      ? kSaveFPRegs
-      : kDontSaveFPRegs;
+  SaveFPRegsMode mode = kSaveFPRegs;
   CEntryStub save_doubles(1, mode);
   StoreBufferOverflowStub stub(mode);
   // These stubs might already be in the snapshot, detect that and don't
@@ -3940,11 +3317,13 @@ void CodeStub::GenerateFPStubs(Isolate* isolate) {
   Code* save_doubles_code;
   if (!save_doubles.FindCodeInCache(&save_doubles_code, isolate)) {
     save_doubles_code = *save_doubles.GetCode(isolate);
-    save_doubles_code->set_is_pregenerated(true);
-
-    Code* store_buffer_overflow_code = *stub.GetCode(isolate);
-    store_buffer_overflow_code->set_is_pregenerated(true);
   }
+  Code* store_buffer_overflow_code;
+  if (!stub.FindCodeInCache(&store_buffer_overflow_code, isolate)) {
+      store_buffer_overflow_code = *stub.GetCode(isolate);
+  }
+  save_doubles_code->set_is_pregenerated(true);
+  store_buffer_overflow_code->set_is_pregenerated(true);
   isolate->set_fp_stubs_generated(true);
 }
 
@@ -4075,11 +3454,18 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   // Special handling of out of memory exceptions.
   JumpIfOOM(masm, v0, t0, throw_out_of_memory_exception);
 
-  // Retrieve the pending exception and clear the variable.
-  __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
+  // Retrieve the pending exception.
   __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
                                       isolate)));
   __ lw(v0, MemOperand(t0));
+
+  // See if we just retrieved an OOM exception.
+  JumpIfOOM(masm, v0, t0, throw_out_of_memory_exception);
+
+  // Clear the pending exception.
+  __ li(a3, Operand(isolate->factory()->the_hole_value()));
+  __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                      isolate)));
   __ sw(a3, MemOperand(t0));
 
   // Special handling of termination exceptions which are uncatchable
@@ -4200,20 +3586,15 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
   // Save callee saved registers on the stack.
   __ MultiPush(kCalleeSaved | ra.bit());
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    // Save callee-saved FPU registers.
-    __ MultiPushFPU(kCalleeSavedFPU);
-    // Set up the reserved register for 0.0.
-    __ Move(kDoubleRegZero, 0.0);
-  }
+  // Save callee-saved FPU registers.
+  __ MultiPushFPU(kCalleeSavedFPU);
+  // Set up the reserved register for 0.0.
+  __ Move(kDoubleRegZero, 0.0);
 
 
   // Load argv in s0 register.
   int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
-  if (CpuFeatures::IsSupported(FPU)) {
-    offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
-  }
+  offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
 
   __ InitializeRootRegister();
   __ lw(s0, MemOperand(sp, offset_to_argv + kCArgsSlotsSize));
@@ -4349,11 +3730,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
   // Reset the stack to the callee saved registers.
   __ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    // Restore callee-saved fpu registers.
-    __ MultiPopFPU(kCalleeSavedFPU);
-  }
+  // Restore callee-saved fpu registers.
+  __ MultiPopFPU(kCalleeSavedFPU);
 
   // Restore callee saved registers from the stack.
   __ MultiPop(kCalleeSaved | ra.bit());
@@ -7092,59 +6470,55 @@ void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
   }
 
   // Inlining the double comparison and falling back to the general compare
-  // stub if NaN is involved or FPU is unsupported.
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-
-    // Load left and right operand.
-    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);
+  // stub if NaN is involved.
+  // Load left and right operand.
+  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(&done);
+  __ 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);
 
-    // Return a result of -1, 0, or 1, or use CompareStub for NaNs.
-    Label fpu_eq, fpu_lt;
-    // Test if equal, and also handle the unordered/NaN case.
-    __ BranchF(&fpu_eq, &unordered, eq, f0, f2);
+  __ bind(&done);
 
-    // Test if less (unordered case is already handled).
-    __ BranchF(&fpu_lt, NULL, lt, f0, f2);
+  // Return a result of -1, 0, or 1, or use CompareStub for NaNs.
+  Label fpu_eq, fpu_lt;
+  // Test if equal, and also handle the unordered/NaN case.
+  __ BranchF(&fpu_eq, &unordered, eq, f0, f2);
 
-    // Otherwise it's greater, so just fall thru, and return.
-    __ li(v0, Operand(GREATER));
-    __ Ret();
+  // Test if less (unordered case is already handled).
+  __ BranchF(&fpu_lt, NULL, lt, f0, f2);
 
-    __ bind(&fpu_eq);
-    __ li(v0, Operand(EQUAL));
-    __ Ret();
+  // Otherwise it's greater, so just fall thru, and return.
+  __ li(v0, Operand(GREATER));
+  __ Ret();
 
-    __ bind(&fpu_lt);
-    __ li(v0, Operand(LESS));
-    __ Ret();
-  }
+  __ bind(&fpu_eq);
+  __ li(v0, Operand(EQUAL));
+  __ Ret();
+
+  __ bind(&fpu_lt);
+  __ li(v0, Operand(LESS));
+  __ Ret();
 
   __ bind(&unordered);
   __ bind(&generic_stub);
@@ -7785,11 +7159,6 @@ bool RecordWriteStub::IsPregenerated() {
 }
 
 
-bool StoreBufferOverflowStub::IsPregenerated() {
-  return save_doubles_ == kDontSaveFPRegs || ISOLATE->fp_stubs_generated();
-}
-
-
 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
     Isolate* isolate) {
   StoreBufferOverflowStub stub1(kDontSaveFPRegs);
@@ -7812,7 +7181,7 @@ void RecordWriteStub::GenerateFixedRegStubsAheadOfTime(Isolate* isolate) {
 
 
 bool CodeStub::CanUseFPRegisters() {
-  return CpuFeatures::IsSupported(FPU);
+  return true;  // FPU is a base requirement for V8.
 }
 
 
@@ -8080,9 +7449,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
 
 
 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
-  ASSERT(!Serializer::enabled());
-  bool save_fp_regs = CpuFeatures::IsSupported(FPU);
-  CEntryStub ces(1, save_fp_regs ? kSaveFPRegs : kDontSaveFPRegs);
+  CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
   __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
   int parameter_count_offset =
       StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
index 225accc..0ebfe59 100644 (file)
@@ -62,11 +62,11 @@ class TranscendentalCacheStub: public PlatformCodeStub {
 class StoreBufferOverflowStub: public PlatformCodeStub {
  public:
   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
-      : save_doubles_(save_fp) { }
+      : save_doubles_(save_fp) {}
 
   void Generate(MacroAssembler* masm);
 
-  virtual bool IsPregenerated();
+  virtual bool IsPregenerated() { return true; }
   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate);
   virtual bool SometimesSetsUpAFrame() { return false; }
 
@@ -484,7 +484,6 @@ class RecordWriteStub: public PlatformCodeStub {
     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
       masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
       if (mode == kSaveFPRegs) {
-        CpuFeatureScope scope(masm, FPU);
         masm->MultiPushFPU(kCallerSavedFPU);
       }
     }
@@ -492,7 +491,6 @@ class RecordWriteStub: public PlatformCodeStub {
     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
                                            SaveFPRegsMode mode) {
       if (mode == kSaveFPRegs) {
-        CpuFeatureScope scope(masm, FPU);
         masm->MultiPopFPU(kCallerSavedFPU);
       }
       masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
@@ -683,27 +681,6 @@ class FloatingPointHelper : public AllStatic {
                                 FPURegister double_scratch1,
                                 Label* not_int32);
 
-  // Generate non FPU code to check if a double can be exactly represented by a
-  // 32-bit integer. This does not check for 0 or -0, which need
-  // to be checked for separately.
-  // Control jumps to not_int32 if the value is not a 32-bit integer, and falls
-  // through otherwise.
-  // src1 and src2 will be cloberred.
-  //
-  // Expected input:
-  // - src1: higher (exponent) part of the double value.
-  // - src2: lower (mantissa) part of the double value.
-  // Output status:
-  // - dst: 32 higher bits of the mantissa. (mantissa[51:20])
-  // - src2: contains 1.
-  // - other registers are clobbered.
-  static void DoubleIs32BitInteger(MacroAssembler* masm,
-                                   Register src1,
-                                   Register src2,
-                                   Register dst,
-                                   Register scratch,
-                                   Label* not_int32);
-
   // Generates code to call a C function to do a double operation using core
   // registers. (Used when FPU is not supported.)
   // This code never falls through, but returns with a heap number containing
index bd403ce..e874a08 100644 (file)
@@ -62,7 +62,6 @@ double fast_exp_simulator(double x) {
 
 
 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));
@@ -72,7 +71,6 @@ UnaryMathFunction CreateExpFunction() {
   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
 
   {
-    CpuFeatureScope use_fpu(&masm, FPU);
     DoubleRegister input = f12;
     DoubleRegister result = f0;
     DoubleRegister double_scratch1 = f4;
@@ -94,7 +92,7 @@ UnaryMathFunction CreateExpFunction() {
     if (!IsMipsSoftFloatABI) {
       // Result is already in f0, nothing to do.
     } else {
-      __ Move(a0, a1, result);
+      __ Move(v0, v1, result);
     }
     __ Ret();
   }
@@ -184,7 +182,6 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   //  -- t0    : scratch (elements)
   // -----------------------------------
   Label loop, entry, convert_hole, gc_required, only_change_map, done;
-  bool fpu_supported = CpuFeatures::IsSupported(FPU);
 
   Register scratch = t6;
 
@@ -249,8 +246,6 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   // t2: end of destination FixedDoubleArray, not tagged
   // t3: begin of FixedDoubleArray element fields, not tagged
 
-  if (!fpu_supported) __ Push(a1, a0);
-
   __ Branch(&entry);
 
   __ bind(&only_change_map);
@@ -278,25 +273,11 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   __ UntagAndJumpIfNotSmi(t5, t5, &convert_hole);
 
   // Normal smi, convert to double and store.
-  if (fpu_supported) {
-    CpuFeatureScope scope(masm, FPU);
-    __ mtc1(t5, f0);
-    __ cvt_d_w(f0, f0);
-    __ sdc1(f0, MemOperand(t3));
-    __ Addu(t3, t3, kDoubleSize);
-  } else {
-    FloatingPointHelper::ConvertIntToDouble(masm,
-                                            t5,
-                                            FloatingPointHelper::kCoreRegisters,
-                                            f0,
-                                            a0,
-                                            a1,
-                                            t7,
-                                            f0);
-    __ sw(a0, MemOperand(t3));  // mantissa
-    __ sw(a1, MemOperand(t3, kIntSize));  // exponent
-    __ Addu(t3, t3, kDoubleSize);
-  }
+  __ mtc1(t5, f0);
+  __ cvt_d_w(f0, f0);
+  __ sdc1(f0, MemOperand(t3));
+  __ Addu(t3, t3, kDoubleSize);
+
   __ Branch(&entry);
 
   // Hole found, store the-hole NaN.
@@ -315,7 +296,6 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   __ bind(&entry);
   __ Branch(&loop, lt, t3, Operand(t2));
 
-  if (!fpu_supported) __ Pop(a1, a0);
   __ pop(ra);
   __ bind(&done);
 }
index 139e7db..5a0870f 100644 (file)
@@ -61,8 +61,9 @@ enum ArchVariants {
 // -mhard-float is passed to the compiler.
 const bool IsMipsSoftFloatABI = false;
 #elif(defined(__mips_soft_float) && __mips_soft_float != 0)
-// Not using floating-point coprocessor instructions. This flag is raised when
-// -msoft-float is passed to the compiler.
+// This flag is raised when -msoft-float is passed to the compiler.
+// Although FPU is a base requirement for v8, soft-float ABI is used
+// on soft-float systems with FPU kernel emulation.
 const bool IsMipsSoftFloatABI = true;
 #else
 const bool IsMipsSoftFloatABI = true;
index 7158e4f..7896f20 100644 (file)
@@ -116,76 +116,93 @@ void Deoptimizer::DeoptimizeFunctionWithPreparedFunctionList(
 }
 
 
-void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
+// This structure comes from FullCodeGenerator::EmitBackEdgeBookkeeping.
+// The back edge bookkeeping code matches the pattern:
+//
+// sltu at, sp, t0 / slt at, a3, zero_reg (in case of count based interrupts)
+// beq at, zero_reg, ok
+// lui t9, <interrupt stub address> upper
+// ori t9, <interrupt stub address> lower
+// jalr t9
+// nop
+// ok-label ----- pc_after points here
+//
+// We patch the code to the following form:
+//
+// addiu at, zero_reg, 1
+// beq at, zero_reg, ok  ;; Not changed
+// lui t9, <on-stack replacement address> upper
+// ori t9, <on-stack replacement address> lower
+// jalr t9  ;; Not changed
+// nop  ;; Not changed
+// ok-label ----- pc_after points here
+
+void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
                                         Address pc_after,
-                                        Code* check_code,
+                                        Code* interrupt_code,
                                         Code* replacement_code) {
-  const int kInstrSize = Assembler::kInstrSize;
-  // 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
-  // lui t9, <stack guard address> upper
-  // ori t9, <stack guard address> lower
-  // jalr t9
-  // nop
-  // ----- pc_after points here
-
-  ASSERT(Assembler::IsBeq(Assembler::instr_at(pc_after - 5 * kInstrSize)));
-
+  ASSERT(!InterruptCodeIsPatched(unoptimized_code,
+                                 pc_after,
+                                 interrupt_code,
+                                 replacement_code));
+  static const int kInstrSize = Assembler::kInstrSize;
   // Replace the sltu instruction with load-imm 1 to at, so beq is not taken.
   CodePatcher patcher(pc_after - 6 * kInstrSize, 1);
   patcher.masm()->addiu(at, zero_reg, 1);
-
   // Replace the stack check address in the load-immediate (lui/ori pair)
   // with the entry address of the replacement code.
-  ASSERT(reinterpret_cast<uint32_t>(
-      Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
-      reinterpret_cast<uint32_t>(check_code->entry()));
   Assembler::set_target_address_at(pc_after - 4 * kInstrSize,
                                    replacement_code->entry());
 
-  // We patched the code to the following form:
-  // addiu at, zero_reg, 1
-  // beq at, zero_reg, ok  ;; Not changed
-  // lui t9, <on-stack replacement address> upper
-  // ori t9, <on-stack replacement address> lower
-  // jalr t9  ;; Not changed
-  // nop  ;; Not changed
-  // ----- pc_after points here
-
   unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
       unoptimized_code, pc_after - 4 * kInstrSize, replacement_code);
 }
 
 
-void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
-                                         Address pc_after,
-                                         Code* check_code,
-                                         Code* replacement_code) {
-  // Exact opposite of the function above.
-  const int kInstrSize = Assembler::kInstrSize;
-  ASSERT(Assembler::IsAddImmediate(
-      Assembler::instr_at(pc_after - 6 * kInstrSize)));
-  ASSERT(Assembler::IsBeq(Assembler::instr_at(pc_after - 5 * kInstrSize)));
-
+void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
+                                        Address pc_after,
+                                        Code* interrupt_code,
+                                        Code* replacement_code) {
+  ASSERT(InterruptCodeIsPatched(unoptimized_code,
+                                 pc_after,
+                                 interrupt_code,
+                                 replacement_code));
+  static const int kInstrSize = Assembler::kInstrSize;
   // Restore the sltu instruction so beq can be taken again.
   CodePatcher patcher(pc_after - 6 * kInstrSize, 1);
   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.
-  ASSERT(reinterpret_cast<uint32_t>(
-      Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
-      reinterpret_cast<uint32_t>(replacement_code->entry()));
+  // Restore the original call address.
   Assembler::set_target_address_at(pc_after - 4 * kInstrSize,
-                                   check_code->entry());
+                                   interrupt_code->entry());
 
-  check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
-      unoptimized_code, pc_after - 4 * kInstrSize, check_code);
+  interrupt_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+      unoptimized_code, pc_after - 4 * kInstrSize, interrupt_code);
 }
 
 
+#ifdef DEBUG
+bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
+                                         Address pc_after,
+                                         Code* interrupt_code,
+                                         Code* replacement_code) {
+  static const int kInstrSize = Assembler::kInstrSize;
+  ASSERT(Assembler::IsBeq(Assembler::instr_at(pc_after - 5 * kInstrSize)));
+  if (Assembler::IsAddImmediate(
+      Assembler::instr_at(pc_after - 6 * kInstrSize))) {
+    ASSERT(reinterpret_cast<uint32_t>(
+        Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
+        reinterpret_cast<uint32_t>(replacement_code->entry()));
+    return true;
+  } else {
+    ASSERT(reinterpret_cast<uint32_t>(
+        Assembler::target_address_at(pc_after - 4 * kInstrSize)) ==
+        reinterpret_cast<uint32_t>(interrupt_code->entry()));
+    return false;
+  }
+}
+#endif  // DEBUG
+
+
 static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
   ByteArray* translations = data->TranslationByteArray();
   int length = data->DeoptCount();
@@ -586,17 +603,12 @@ void Deoptimizer::EntryGenerator::Generate() {
   const int kDoubleRegsSize =
       kDoubleSize * FPURegister::kMaxNumAllocatableRegisters;
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm(), FPU);
-    // Save all FPU registers before messing with them.
-    __ Subu(sp, sp, Operand(kDoubleRegsSize));
-    for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
-      FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
-      int offset = i * kDoubleSize;
-      __ sdc1(fpu_reg, MemOperand(sp, offset));
-    }
-  } else {
-    __ Subu(sp, sp, Operand(kDoubleRegsSize));
+  // Save all FPU registers before messing with them.
+  __ Subu(sp, sp, Operand(kDoubleRegsSize));
+  for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
+    FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
+    int offset = i * kDoubleSize;
+    __ sdc1(fpu_reg, MemOperand(sp, offset));
   }
 
   // Push saved_regs (needed to populate FrameDescription::registers_).
@@ -669,16 +681,13 @@ void Deoptimizer::EntryGenerator::Generate() {
   }
 
   int double_regs_offset = FrameDescription::double_registers_offset();
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm(), FPU);
-    // Copy FPU registers to
-    // double_registers_[DoubleRegister::kNumAllocatableRegisters]
-    for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
-      int dst_offset = i * kDoubleSize + double_regs_offset;
-      int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
-      __ ldc1(f0, MemOperand(sp, src_offset));
-      __ sdc1(f0, MemOperand(a1, dst_offset));
-    }
+  // Copy FPU registers to
+  // double_registers_[DoubleRegister::kNumAllocatableRegisters]
+  for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
+    int dst_offset = i * kDoubleSize + double_regs_offset;
+    int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
+    __ ldc1(f0, MemOperand(sp, src_offset));
+    __ sdc1(f0, MemOperand(a1, dst_offset));
   }
 
   // Remove the bailout id, eventually return address, and the saved registers
@@ -747,15 +756,11 @@ void Deoptimizer::EntryGenerator::Generate() {
   __ bind(&outer_loop_header);
   __ Branch(&outer_push_loop, lt, t0, Operand(a1));
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm(), FPU);
-
-    __ lw(a1, MemOperand(a0, Deoptimizer::input_offset()));
-    for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
-      const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
-      int src_offset = i * kDoubleSize + double_regs_offset;
-      __ ldc1(fpu_reg, MemOperand(a1, src_offset));
-    }
+  __ lw(a1, MemOperand(a0, Deoptimizer::input_offset()));
+  for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
+    const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
+    int src_offset = i * kDoubleSize + double_regs_offset;
+    __ ldc1(fpu_reg, MemOperand(a1, src_offset));
   }
 
   // Push state, pc, and continuation from the last output frame.
index 0eca71f..b787f13 100644 (file)
@@ -1051,8 +1051,8 @@ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
     buffer[0] = '\0';
     byte* prev_pc = pc;
     pc += d.InstructionDecode(buffer, pc);
-    fprintf(f, "%p    %08x      %s\n",
-            prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
+    v8::internal::PrintF(f, "%p    %08x      %s\n",
+        prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
   }
 }
 
index 1568ce6..f6f20cd 100644 (file)
@@ -152,18 +152,6 @@ const int kSafepointRegisterStackIndexMap[kNumRegs] = {
 
 // ----------------------------------------------------
 
-class StackHandlerConstants : public AllStatic {
- public:
-  static const int kNextOffset     = 0 * kPointerSize;
-  static const int kCodeOffset     = 1 * kPointerSize;
-  static const int kStateOffset    = 2 * kPointerSize;
-  static const int kContextOffset  = 3 * kPointerSize;
-  static const int kFPOffset       = 4 * kPointerSize;
-
-  static const int kSize = kFPOffset + kPointerSize;
-};
-
-
 class EntryFrameConstants : public AllStatic {
  public:
   static const int kCallerFPOffset      = -3 * kPointerSize;
index 3e7c8da..8e2d5ab 100644 (file)
@@ -170,8 +170,6 @@ void FullCodeGenerator::Generate() {
   // the frame (that is done below).
   FrameScope frame_scope(masm_, StackFrame::MANUAL);
 
-  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.
@@ -183,6 +181,9 @@ void FullCodeGenerator::Generate() {
   __ Addu(fp, sp, Operand(2 * kPointerSize));
 
   { Comment cmnt(masm_, "[ Allocate locals");
+    int locals_count = info->scope()->num_stack_slots();
+    // Generators allocate locals, if any, in context slots.
+    ASSERT(!info->function()->is_generator() || locals_count == 0);
     for (int i = 0; i < locals_count; i++) {
       __ push(at);
     }
@@ -673,17 +674,9 @@ void FullCodeGenerator::DoTest(Expression* condition,
                                Label* if_true,
                                Label* if_false,
                                Label* fall_through) {
-  if (CpuFeatures::IsSupported(FPU)) {
-    ToBooleanStub stub(result_register());
-    __ CallStub(&stub, condition->test_id());
-    __ mov(at, zero_reg);
-  } else {
-    // Call the runtime to find the boolean value of the source and then
-    // translate it into control flow to the pair of labels.
-    __ push(result_register());
-    __ CallRuntime(Runtime::kToBool, 1);
-    __ LoadRoot(at, Heap::kFalseValueRootIndex);
-  }
+  ToBooleanStub stub(result_register());
+  __ CallStub(&stub, condition->test_id());
+  __ mov(at, zero_reg);
   Split(ne, v0, Operand(at), if_true, if_false, fall_through);
 }
 
@@ -1276,7 +1269,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
       !pretenure &&
       scope()->is_function_scope() &&
       info->num_literals() == 0) {
-    FastNewClosureStub stub(info->language_mode());
+    FastNewClosureStub stub(info->language_mode(), info->is_generator());
     __ li(a0, Operand(info));
     __ push(a0);
     __ CallStub(&stub);
@@ -1737,7 +1730,6 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
   __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
   __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
   __ li(a1, Operand(constant_elements));
-  __ Push(a3, a2, a1);
   if (has_fast_elements && constant_elements_values->map() ==
       isolate()->heap()->fixed_cow_array_map()) {
     FastCloneShallowArrayStub stub(
@@ -1748,8 +1740,11 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
     __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(),
         1, a1, a2);
   } else if (expr->depth() > 1) {
+    __ Push(a3, a2, a1);
     __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
-  } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+  } else if (Serializer::enabled() ||
+      length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+    __ Push(a3, a2, a1);
     __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
   } else {
     ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
@@ -3042,31 +3037,21 @@ void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
   // Convert 32 random bits in v0 to 0.(32 random bits) in a double
   // by computing:
   // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
-  if (CpuFeatures::IsSupported(FPU)) {
-    __ PrepareCallCFunction(1, a0);
-    __ lw(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
-    __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
-    __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
-
-    CpuFeatureScope scope(masm(), FPU);
-    // 0x41300000 is the top half of 1.0 x 2^20 as a double.
-    __ li(a1, Operand(0x41300000));
-    // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
-    __ Move(f12, v0, a1);
-    // Move 0x4130000000000000 to FPU.
-    __ Move(f14, zero_reg, a1);
-    // Subtract and store the result in the heap number.
-    __ sub_d(f0, f12, f14);
-    __ sdc1(f0, FieldMemOperand(s0, HeapNumber::kValueOffset));
-    __ mov(v0, s0);
-  } else {
-    __ PrepareCallCFunction(2, a0);
-    __ mov(a0, s0);
-    __ lw(a1, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
-    __ lw(a1, FieldMemOperand(a1, GlobalObject::kNativeContextOffset));
-    __ CallCFunction(
-        ExternalReference::fill_heap_number_with_random_function(isolate()), 2);
-  }
+  __ PrepareCallCFunction(1, a0);
+  __ lw(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+  __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
+  __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
+
+  // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+  __ li(a1, Operand(0x41300000));
+  // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
+  __ Move(f12, v0, a1);
+  // Move 0x4130000000000000 to FPU.
+  __ Move(f14, zero_reg, a1);
+  // Subtract and store the result in the heap number.
+  __ sub_d(f0, f12, f14);
+  __ sdc1(f0, FieldMemOperand(s0, HeapNumber::kValueOffset));
+  __ mov(v0, s0);
 
   context()->Plug(v0);
 }
@@ -3204,12 +3189,8 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
   ASSERT(args->length() == 2);
   VisitForStackValue(args->at(0));
   VisitForStackValue(args->at(1));
-  if (CpuFeatures::IsSupported(FPU)) {
-    MathPowStub stub(MathPowStub::ON_STACK);
-    __ CallStub(&stub);
-  } else {
-    __ CallRuntime(Runtime::kMath_pow, 2);
-  }
+  MathPowStub stub(MathPowStub::ON_STACK);
+  __ CallStub(&stub);
   context()->Plug(v0);
 }
 
index b5d6c45..59cfcd9 100644 (file)
@@ -65,7 +65,6 @@ bool LCodeGen::GenerateCode() {
   HPhase phase("Z_Code generation", chunk());
   ASSERT(is_unused());
   status_ = GENERATING;
-  CpuFeatureScope scope(masm(), FPU);
 
   // Open a frame scope to indicate that there is a frame on the stack.  The
   // NONE indicates that the scope shouldn't actually generate code to set up
@@ -114,7 +113,7 @@ void LCodeGen::Comment(const char* format, ...) {
   // issues when the stack allocated buffer goes out of scope.
   size_t length = builder.position();
   Vector<char> copy = Vector<char>::New(length + 1);
-  memcpy(copy.start(), builder.Finalize(), copy.length());
+  OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
   masm()->RecordComment(copy.start());
 }
 
@@ -193,8 +192,7 @@ bool LCodeGen::GeneratePrologue() {
     }
   }
 
-  if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm(), FPU);
+  if (info()->saves_caller_doubles()) {
     Comment(";;; Save clobbered callee double registers");
     int count = 0;
     BitVector* doubles = chunk()->allocated_double_registers();
@@ -829,7 +827,9 @@ void LCodeGen::DeoptimizeIf(Condition cc,
   }
 
   ASSERT(FLAG_deopt_every_n_times < 2);  // Other values not supported on MIPS.
-  if (FLAG_deopt_every_n_times == 1 && info_->opt_count() == id) {
+  if (FLAG_deopt_every_n_times == 1 &&
+      !info()->IsStub() &&
+      info()->opt_count() == id) {
     __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
     return;
   }
@@ -1475,7 +1475,6 @@ void LCodeGen::DoConstantI(LConstantI* instr) {
 void LCodeGen::DoConstantD(LConstantD* instr) {
   ASSERT(instr->result()->IsDoubleRegister());
   DoubleRegister result = ToDoubleRegister(instr->result());
-  CpuFeatureScope scope(masm(), FPU);
   double v = instr->value();
   __ Move(result, v);
 }
@@ -1666,7 +1665,6 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
     __ bind(&done);
   } else {
     ASSERT(instr->hydrogen()->representation().IsDouble());
-    CpuFeatureScope scope(masm(), FPU);
     FPURegister left_reg = ToDoubleRegister(left);
     FPURegister right_reg = ToDoubleRegister(right);
     FPURegister result_reg = ToDoubleRegister(instr->result());
@@ -1707,7 +1705,6 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
 
 
 void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
-  CpuFeatureScope scope(masm(), FPU);
   DoubleRegister left = ToDoubleRegister(instr->left());
   DoubleRegister right = ToDoubleRegister(instr->right());
   DoubleRegister result = ToDoubleRegister(instr->result());
@@ -1817,7 +1814,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
     Register reg = ToRegister(instr->value());
     EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg));
   } else if (r.IsDouble()) {
-    CpuFeatureScope scope(masm(), FPU);
     DoubleRegister reg = ToDoubleRegister(instr->value());
     // Test the double value. Zero and NaN are false.
     EmitBranchF(true_block, false_block, nue, reg, kDoubleRegZero);
@@ -1902,7 +1898,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
       }
 
       if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
-        CpuFeatureScope scope(masm(), FPU);
         // heap number -> false iff +0, -0, or NaN.
         DoubleRegister dbl_scratch = double_scratch0();
         Label not_heap_number;
@@ -1982,7 +1977,6 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
     EmitGoto(next_block);
   } else {
     if (instr->is_double()) {
-      CpuFeatureScope scope(masm(), FPU);
       // Compare left and right as doubles and load the
       // resulting flags into the normal status register.
       FPURegister left_reg = ToDoubleRegister(left);
@@ -2545,8 +2539,7 @@ void LCodeGen::DoReturn(LReturn* instr) {
     __ push(v0);
     __ CallRuntime(Runtime::kTraceExit, 1);
   }
-  if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm(), FPU);
+  if (info()->saves_caller_doubles()) {
     ASSERT(NeedsEagerFrame());
     BitVector* doubles = chunk()->allocated_double_registers();
     BitVector::Iterator save_iterator(doubles);
@@ -2933,61 +2926,11 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
       __ sll(scratch0(), key, shift_size);
       __ Addu(scratch0(), scratch0(), external_pointer);
     }
-    if (CpuFeatures::IsSupported(FPU)) {
-      CpuFeatureScope scope(masm(), FPU);
-      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 {
-      if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
-        Register value = external_pointer;
-        __ lw(value, MemOperand(scratch0(), additional_offset));
-        __ And(sfpd_lo, value, Operand(kBinary32MantissaMask));
-
-        __ srl(scratch0(), value, kBinary32MantissaBits);
-        __ And(scratch0(), scratch0(),
-                Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
-
-        Label exponent_rebiased;
-        __ Xor(at, scratch0(), Operand(0x00));
-        __ Branch(&exponent_rebiased, eq, at, Operand(zero_reg));
-
-        __ Xor(at, scratch0(), Operand(0xff));
-        Label skip;
-        __ Branch(&skip, ne, at, Operand(zero_reg));
-        __ li(scratch0(), Operand(0x7ff));
-        __ bind(&skip);
-        __ Branch(&exponent_rebiased, eq, at, Operand(zero_reg));
-
-        // Rebias exponent.
-        __ Addu(scratch0(),
-                scratch0(),
-                Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
-
-        __ bind(&exponent_rebiased);
-        __ And(sfpd_hi, value, Operand(kBinary32SignMask));
-        __ sll(at, scratch0(), HeapNumber::kMantissaBitsInTopWord);
-        __ Or(sfpd_hi, sfpd_hi, at);
-
-        // Shift mantissa.
-        static const int kMantissaShiftForHiWord =
-            kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
-        static const int kMantissaShiftForLoWord =
-            kBitsPerInt - kMantissaShiftForHiWord;
-
-        __ srl(at, sfpd_lo, kMantissaShiftForHiWord);
-        __ Or(sfpd_hi, sfpd_hi, at);
-        __ sll(sfpd_lo, sfpd_lo, kMantissaShiftForLoWord);
-
-      } else {
-        __ lw(sfpd_lo, MemOperand(scratch0(), additional_offset));
-        __ lw(sfpd_hi, MemOperand(scratch0(),
-                                   additional_offset + kPointerSize));
-      }
+    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());
@@ -3062,21 +3005,11 @@ void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
     __ sll(scratch, key, shift_size);
     __ Addu(elements, elements, scratch);
   }
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm(), FPU);
-    __ Addu(elements, elements, Operand(base_offset));
-    __ ldc1(result, MemOperand(elements));
-    if (instr->hydrogen()->RequiresHoleCheck()) {
-      __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
-      DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
-    }
-  } else {
-      __ lw(sfpd_hi, MemOperand(elements, base_offset + kPointerSize));
-      __ lw(sfpd_lo, MemOperand(elements, base_offset));
-    if (instr->hydrogen()->RequiresHoleCheck()) {
-      ASSERT(kPointerSize == sizeof(kHoleNanLower32));
-      DeoptimizeIf(eq, instr->environment(), sfpd_hi, Operand(kHoleNanUpper32));
-    }
+  __ Addu(elements, elements, Operand(base_offset));
+  __ ldc1(result, MemOperand(elements));
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
+    DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
   }
 }
 
@@ -3445,7 +3378,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
 }
 
 
-void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
+void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
   Register input = ToRegister(instr->value());
   Register result = ToRegister(instr->result());
   Register scratch = scratch0();
@@ -3510,7 +3443,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
   Register input = ToRegister(instr->value());
   Register result = ToRegister(instr->result());
   Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
@@ -3523,20 +3456,18 @@ void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
   // Class for deferred case.
   class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
    public:
-    DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
-                                    LUnaryMathOperation* instr)
+    DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
         : LDeferredCode(codegen), instr_(instr) { }
     virtual void Generate() {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
     virtual LInstruction* instr() { return instr_; }
    private:
-    LUnaryMathOperation* instr_;
+    LMathAbs* instr_;
   };
 
   Representation r = instr->hydrogen()->value()->representation();
@@ -3560,8 +3491,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathFloor(LMathFloor* instr) {
   DoubleRegister input = ToDoubleRegister(instr->value());
   Register result = ToRegister(instr->result());
   Register scratch1 = scratch0();
@@ -3589,8 +3519,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathRound(LMathRound* instr) {
   DoubleRegister input = ToDoubleRegister(instr->value());
   Register result = ToRegister(instr->result());
   DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
@@ -3666,16 +3595,14 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
   DoubleRegister input = ToDoubleRegister(instr->value());
   DoubleRegister result = ToDoubleRegister(instr->result());
   __ sqrt_d(result, input);
 }
 
 
-void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
-  CpuFeatureScope scope(masm(), FPU);
+void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
   DoubleRegister input = ToDoubleRegister(instr->value());
   DoubleRegister result = ToDoubleRegister(instr->result());
   DoubleRegister temp = ToDoubleRegister(instr->temp());
@@ -3700,7 +3627,6 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
 
 
 void LCodeGen::DoPower(LPower* instr) {
-  CpuFeatureScope scope(masm(), FPU);
   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.
@@ -3731,7 +3657,6 @@ void LCodeGen::DoPower(LPower* instr) {
 
 
 void LCodeGen::DoRandom(LRandom* instr) {
-  CpuFeatureScope scope(masm(), FPU);
   class DeferredDoRandom: public LDeferredCode {
    public:
     DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
@@ -3808,7 +3733,6 @@ void LCodeGen::DoDeferredRandom(LRandom* instr) {
 
 
 void LCodeGen::DoMathExp(LMathExp* instr) {
-  CpuFeatureScope scope(masm(), FPU);
   DoubleRegister input = ToDoubleRegister(instr->value());
   DoubleRegister result = ToDoubleRegister(instr->result());
   DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
@@ -3822,7 +3746,7 @@ void LCodeGen::DoMathExp(LMathExp* instr) {
 }
 
 
-void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathLog(LMathLog* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(f4));
   TranscendentalCacheStub stub(TranscendentalCache::LOG,
                                TranscendentalCacheStub::UNTAGGED);
@@ -3830,7 +3754,7 @@ void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathTan(LMathTan* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(f4));
   TranscendentalCacheStub stub(TranscendentalCache::TAN,
                                TranscendentalCacheStub::UNTAGGED);
@@ -3838,7 +3762,7 @@ void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathCos(LMathCos* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(f4));
   TranscendentalCacheStub stub(TranscendentalCache::COS,
                                TranscendentalCacheStub::UNTAGGED);
@@ -3846,7 +3770,7 @@ void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSin(LMathSin* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(f4));
   TranscendentalCacheStub stub(TranscendentalCache::SIN,
                                TranscendentalCacheStub::UNTAGGED);
@@ -3854,42 +3778,6 @@ void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
-  switch (instr->op()) {
-    case kMathAbs:
-      DoMathAbs(instr);
-      break;
-    case kMathFloor:
-      DoMathFloor(instr);
-      break;
-    case kMathRound:
-      DoMathRound(instr);
-      break;
-    case kMathSqrt:
-      DoMathSqrt(instr);
-      break;
-    case kMathPowHalf:
-      DoMathPowHalf(instr);
-      break;
-    case kMathCos:
-      DoMathCos(instr);
-      break;
-    case kMathSin:
-      DoMathSin(instr);
-      break;
-    case kMathTan:
-      DoMathTan(instr);
-      break;
-    case kMathLog:
-      DoMathLog(instr);
-      break;
-    default:
-      Abort("Unimplemented type of LUnaryMathOperation.");
-      UNREACHABLE();
-  }
-}
-
-
 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   ASSERT(ToRegister(instr->function()).is(a1));
   ASSERT(instr->HasPointerMap());
@@ -4111,7 +3999,6 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
 
 
 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
-  CpuFeatureScope scope(masm(), FPU);
   Register external_pointer = ToRegister(instr->elements());
   Register key = no_reg;
   ElementsKind elements_kind = instr->elements_kind();
@@ -4185,7 +4072,6 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
 
 
 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
-  CpuFeatureScope scope(masm(), FPU);
   DoubleRegister value = ToDoubleRegister(instr->value());
   Register elements = ToRegister(instr->elements());
   Register key = no_reg;
@@ -4489,7 +4375,6 @@ void LCodeGen::DoStringLength(LStringLength* instr) {
 
 
 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
-  CpuFeatureScope scope(masm(), FPU);
   LOperand* input = instr->value();
   ASSERT(input->IsRegister() || input->IsStackSlot());
   LOperand* output = instr->result();
@@ -4507,7 +4392,6 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
 
 
 void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
-  CpuFeatureScope scope(masm(), FPU);
   LOperand* input = instr->value();
   LOperand* output = instr->result();
 
@@ -4569,45 +4453,6 @@ void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
 }
 
 
-// Convert unsigned integer with specified number of leading zeroes in binary
-// representation to IEEE 754 double.
-// Integer to convert is passed in register src.
-// Resulting double is returned in registers hiword:loword.
-// This functions does not work correctly for 0.
-static void GenerateUInt2Double(MacroAssembler* masm,
-                                Register src,
-                                Register hiword,
-                                Register loword,
-                                Register scratch,
-                                int leading_zeroes) {
-  const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
-  const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
-
-  const int mantissa_shift_for_hi_word =
-      meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
-  const int mantissa_shift_for_lo_word =
-      kBitsPerInt - mantissa_shift_for_hi_word;
-  masm->li(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
-  if (mantissa_shift_for_hi_word > 0) {
-    masm->sll(loword, src, mantissa_shift_for_lo_word);
-    masm->srl(hiword, src, mantissa_shift_for_hi_word);
-    masm->Or(hiword, scratch, hiword);
-  } else {
-    masm->mov(loword, zero_reg);
-    masm->sll(hiword, src, mantissa_shift_for_hi_word);
-    masm->Or(hiword, scratch, hiword);
-  }
-
-  // If least significant bit of biased exponent was not 1 it was corrupted
-  // by most significant bit of mantissa so we should fix that.
-  if (!(biased_exponent & 1)) {
-    masm->li(scratch, 1 << HeapNumber::kExponentShift);
-    masm->nor(scratch, scratch, scratch);
-    masm->and_(hiword, hiword, scratch);
-  }
-}
-
-
 void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
                                     LOperand* value,
                                     IntegerSignedness signedness) {
@@ -4628,35 +4473,11 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
       __ SmiUntag(src, dst);
       __ Xor(src, src, Operand(0x80000000));
     }
-    if (CpuFeatures::IsSupported(FPU)) {
-      CpuFeatureScope scope(masm(), FPU);
-      __ mtc1(src, dbl_scratch);
-      __ cvt_d_w(dbl_scratch, dbl_scratch);
-    } else {
-      FloatingPointHelper::Destination dest =
-          FloatingPointHelper::kCoreRegisters;
-      FloatingPointHelper::ConvertIntToDouble(masm(), src, dest, f0,
-                                              sfpd_lo, sfpd_hi,
-                                              scratch0(), f2);
-    }
+    __ mtc1(src, dbl_scratch);
+    __ cvt_d_w(dbl_scratch, dbl_scratch);
   } else {
-    if (CpuFeatures::IsSupported(FPU)) {
-      CpuFeatureScope scope(masm(), FPU);
-      __ mtc1(src, dbl_scratch);
-      __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
-    } else {
-      Label no_leading_zero, convert_done;
-      __ And(at, src, Operand(0x80000000));
-      __ Branch(&no_leading_zero, ne, at, Operand(zero_reg));
-
-      // Integer has one leading zeros.
-      GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 1);
-      __ Branch(&convert_done);
-
-      __ bind(&no_leading_zero);
-      GenerateUInt2Double(masm(), src, sfpd_hi, sfpd_lo, t0, 0);
-      __ bind(&convert_done);
-    }
+    __ mtc1(src, dbl_scratch);
+    __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
   }
 
   if (FLAG_inline_new) {
@@ -4680,13 +4501,7 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
   // Done. Put the value in dbl_scratch into the value of the allocated heap
   // number.
   __ bind(&done);
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm(), FPU);
-    __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
-  } else {
-    __ sw(sfpd_lo, MemOperand(dst, HeapNumber::kMantissaOffset));
-    __ sw(sfpd_hi, MemOperand(dst, HeapNumber::kExponentOffset));
-  }
+  __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
   __ Addu(dst, dst, kHeapObjectTag);
   __ StoreToSafepointRegisterSlot(dst, dst);
 }
@@ -4719,39 +4534,16 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
   Label no_special_nan_handling;
   Label done;
   if (convert_hole) {
-    if (CpuFeatures::IsSupported(FPU)) {
-      CpuFeatureScope scope(masm(), FPU);
-      DoubleRegister input_reg = ToDoubleRegister(instr->value());
-      __ BranchF(&no_special_nan_handling, NULL, eq, input_reg, input_reg);
-      __ Move(reg, scratch0(), input_reg);
-      Label canonicalize;
-      __ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32));
-      __ li(reg, factory()->the_hole_value());
-      __ Branch(&done);
-      __ bind(&canonicalize);
-      __ Move(input_reg,
-              FixedDoubleArray::canonical_not_the_hole_nan_as_double());
-    } else {
-      Label not_hole;
-      __ Branch(&not_hole, ne, sfpd_hi, Operand(kHoleNanUpper32));
-      __ li(reg, factory()->the_hole_value());
-      __ Branch(&done);
-      __ bind(&not_hole);
-      __ And(scratch, sfpd_hi, Operand(0x7ff00000));
-      __ Branch(&no_special_nan_handling, ne, scratch, Operand(0x7ff00000));
-      Label special_nan_handling;
-      __ And(at, sfpd_hi, Operand(0x000FFFFF));
-      __ Branch(&special_nan_handling, ne, at, Operand(zero_reg));
-      __ Branch(&no_special_nan_handling, eq, sfpd_lo, Operand(zero_reg));
-      __ bind(&special_nan_handling);
-      double canonical_nan =
-          FixedDoubleArray::canonical_not_the_hole_nan_as_double();
-      uint64_t casted_nan = BitCast<uint64_t>(canonical_nan);
-      __ li(sfpd_lo,
-            Operand(static_cast<uint32_t>(casted_nan & 0xFFFFFFFF)));
-      __ li(sfpd_hi,
-            Operand(static_cast<uint32_t>(casted_nan >> 32)));
-    }
+    DoubleRegister input_reg = ToDoubleRegister(instr->value());
+    __ BranchF(&no_special_nan_handling, NULL, eq, input_reg, input_reg);
+    __ Move(reg, scratch0(), input_reg);
+    Label canonicalize;
+    __ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32));
+    __ li(reg, factory()->the_hole_value());
+    __ Branch(&done);
+    __ bind(&canonicalize);
+    __ Move(input_reg,
+            FixedDoubleArray::canonical_not_the_hole_nan_as_double());
   }
 
   __ bind(&no_special_nan_handling);
@@ -4765,13 +4557,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
     __ Branch(deferred->entry());
   }
   __ bind(deferred->exit());
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm(), FPU);
-    __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
-  } else {
-    __ sw(sfpd_lo, MemOperand(reg, HeapNumber::kValueOffset));
-    __ sw(sfpd_hi, MemOperand(reg, HeapNumber::kValueOffset + kPointerSize));
-  }
+  __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
   // Now that we have finished with the object's real address tag it
   __ Addu(reg, reg, kHeapObjectTag);
   __ bind(&done);
@@ -4821,7 +4607,6 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
                                 LEnvironment* env,
                                 NumberUntagDMode mode) {
   Register scratch = scratch0();
-  CpuFeatureScope scope(masm(), FPU);
 
   Label load_smi, heap_number, done;
 
@@ -4899,7 +4684,6 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
   // of the if.
 
   if (instr->truncating()) {
-    CpuFeatureScope scope(masm(), FPU);
     Register scratch3 = ToRegister(instr->temp2());
     FPURegister single_scratch = double_scratch.low();
     ASSERT(!scratch3.is(input_reg) &&
@@ -5154,7 +4938,6 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
 
 
 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
-  CpuFeatureScope vfp_scope(masm(), FPU);
   DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
   Register result_reg = ToRegister(instr->result());
   DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
@@ -5163,7 +4946,6 @@ void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
 
 
 void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
-  CpuFeatureScope vfp_scope(masm(), FPU);
   Register unclamped_reg = ToRegister(instr->unclamped());
   Register result_reg = ToRegister(instr->result());
   __ ClampUint8(result_reg, unclamped_reg);
@@ -5171,7 +4953,6 @@ void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
 
 
 void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
-  CpuFeatureScope vfp_scope(masm(), FPU);
   Register scratch = scratch0();
   Register input_reg = ToRegister(instr->unclamped());
   Register result_reg = ToRegister(instr->result());
@@ -5207,7 +4988,6 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
 
 
 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
-  ASSERT(instr->temp()->Equals(instr->result()));
   Register prototype_reg = ToRegister(instr->temp());
   Register map_reg = ToRegister(instr->temp2());
 
@@ -5220,8 +5000,6 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
     for (int i = 0; i < maps->length(); i++) {
       prototype_maps_.Add(maps->at(i), info()->zone());
     }
-    __ LoadHeapObject(prototype_reg,
-                      prototypes->at(prototypes->length() - 1));
   } else {
     for (int i = 0; i < prototypes->length(); i++) {
       __ LoadHeapObject(prototype_reg, prototypes->at(i));
@@ -5337,11 +5115,11 @@ void LCodeGen::DoAllocate(LAllocate* instr) {
   if (instr->hydrogen()->MustAllocateDoubleAligned()) {
     flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
   }
+  if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+    flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+  }
   if (instr->size()->IsConstantOperand()) {
     int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
-    if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
-      flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
-    }
     __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
   } else {
     Register size = ToRegister(instr->size());
@@ -5369,7 +5147,13 @@ void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
   PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
   __ SmiTag(size, size);
   __ push(size);
-  CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
+  if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+    CallRuntimeFromDeferred(
+        Runtime::kAllocateInOldPointerSpace, 1, instr);
+  } else {
+    CallRuntimeFromDeferred(
+        Runtime::kAllocateInNewSpace, 1, instr);
+  }
   __ StoreToSafepointRegisterSlot(v0, result);
 }
 
@@ -5405,7 +5189,6 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
   // Boilerplate already exists, constant elements are never accessed.
   // Pass an empty fixed array.
   __ li(a1, Operand(isolate()->factory()->empty_fixed_array()));
-  __ Push(a3, a2, a1);
 
   // Pick the right runtime function or stub to call.
   int length = instr->hydrogen()->length();
@@ -5416,8 +5199,10 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
     FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
     CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
   } else if (instr->hydrogen()->depth() > 1) {
+    __ Push(a3, a2, a1);
     CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
   } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+    __ Push(a3, a2, a1);
     CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
   } else {
     FastCloneShallowArrayStub::Mode mode =
@@ -5430,170 +5215,6 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
 }
 
 
-void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
-                            Register result,
-                            Register source,
-                            int* offset,
-                            AllocationSiteMode mode) {
-  ASSERT(!source.is(a2));
-  ASSERT(!result.is(a2));
-
-  bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
-      object->map()->CanTrackAllocationSite();
-
-  // Only elements backing stores for non-COW arrays need to be copied.
-  Handle<FixedArrayBase> elements(object->elements());
-  bool has_elements = elements->length() > 0 &&
-      elements->map() != isolate()->heap()->fixed_cow_array_map();
-
-  // Increase the offset so that subsequent objects end up right after
-  // this object and its backing store.
-  int object_offset = *offset;
-  int object_size = object->map()->instance_size();
-  int elements_size = has_elements ? elements->Size() : 0;
-  int elements_offset = *offset + object_size;
-  if (create_allocation_site_info) {
-    elements_offset += AllocationSiteInfo::kSize;
-    *offset += AllocationSiteInfo::kSize;
-  }
-
-  *offset += object_size + elements_size;
-
-  // Copy object header.
-  ASSERT(object->properties()->length() == 0);
-  int inobject_properties = object->map()->inobject_properties();
-  int header_size = object_size - inobject_properties * kPointerSize;
-  for (int i = 0; i < header_size; i += kPointerSize) {
-    if (has_elements && i == JSObject::kElementsOffset) {
-      __ Addu(a2, result, Operand(elements_offset));
-    } else {
-      __ lw(a2, FieldMemOperand(source, i));
-    }
-    __ sw(a2, FieldMemOperand(result, object_offset + i));
-  }
-
-  // Copy in-object properties.
-  for (int i = 0; i < inobject_properties; i++) {
-    int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
-    Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
-                                          isolate());
-    if (value->IsJSObject()) {
-      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
-      __ Addu(a2, result, Operand(*offset));
-      __ sw(a2, FieldMemOperand(result, total_offset));
-      __ LoadHeapObject(source, value_object);
-      EmitDeepCopy(value_object, result, source, offset,
-                   DONT_TRACK_ALLOCATION_SITE);
-    } else if (value->IsHeapObject()) {
-      __ LoadHeapObject(a2, Handle<HeapObject>::cast(value));
-      __ sw(a2, FieldMemOperand(result, total_offset));
-    } else {
-      __ li(a2, Operand(value));
-      __ sw(a2, FieldMemOperand(result, total_offset));
-    }
-  }
-
-  // Build Allocation Site Info if desired
-  if (create_allocation_site_info) {
-    __ li(a2, Operand(Handle<Map>(isolate()->heap()->
-                                  allocation_site_info_map())));
-    __ sw(a2, FieldMemOperand(result, object_size));
-    __ sw(source, FieldMemOperand(result, object_size + kPointerSize));
-  }
-
-  if (has_elements) {
-    // Copy elements backing store header.
-    __ LoadHeapObject(source, elements);
-    for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
-      __ lw(a2, FieldMemOperand(source, i));
-      __ sw(a2, FieldMemOperand(result, elements_offset + i));
-    }
-
-    // Copy elements backing store content.
-    int elements_length = has_elements ? elements->length() : 0;
-    if (elements->IsFixedDoubleArray()) {
-      Handle<FixedDoubleArray> double_array =
-          Handle<FixedDoubleArray>::cast(elements);
-      for (int i = 0; i < elements_length; i++) {
-        int64_t value = double_array->get_representation(i);
-        // We only support little endian mode...
-        int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
-        int32_t value_high = static_cast<int32_t>(value >> 32);
-        int total_offset =
-            elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
-        __ li(a2, Operand(value_low));
-        __ sw(a2, FieldMemOperand(result, total_offset));
-        __ li(a2, Operand(value_high));
-        __ sw(a2, FieldMemOperand(result, total_offset + 4));
-      }
-    } else if (elements->IsFixedArray()) {
-      Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
-      for (int i = 0; i < elements_length; i++) {
-        int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
-        Handle<Object> value(fast_elements->get(i), isolate());
-        if (value->IsJSObject()) {
-          Handle<JSObject> value_object = Handle<JSObject>::cast(value);
-          __ Addu(a2, result, Operand(*offset));
-          __ sw(a2, FieldMemOperand(result, total_offset));
-          __ LoadHeapObject(source, value_object);
-          EmitDeepCopy(value_object, result, source, offset,
-                       DONT_TRACK_ALLOCATION_SITE);
-        } else if (value->IsHeapObject()) {
-          __ LoadHeapObject(a2, Handle<HeapObject>::cast(value));
-          __ sw(a2, FieldMemOperand(result, total_offset));
-        } else {
-          __ li(a2, Operand(value));
-          __ sw(a2, FieldMemOperand(result, total_offset));
-        }
-      }
-    } else {
-      UNREACHABLE();
-    }
-  }
-}
-
-
-void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
-  int size = instr->hydrogen()->total_size();
-  ElementsKind boilerplate_elements_kind =
-      instr->hydrogen()->boilerplate()->GetElementsKind();
-
-  // Deopt if the array literal boilerplate ElementsKind is of a type different
-  // than the expected one. The check isn't necessary if the boilerplate has
-  // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
-  if (CanTransitionToMoreGeneralFastElementsKind(
-          boilerplate_elements_kind, true)) {
-    __ LoadHeapObject(a1, instr->hydrogen()->boilerplate());
-    // Load map into a2.
-    __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
-    // Load the map's "bit field 2".
-    __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
-    // Retrieve elements_kind from bit field 2.
-    __ Ext(a2, a2, Map::kElementsKindShift, Map::kElementsKindBitCount);
-    DeoptimizeIf(ne, instr->environment(), a2,
-        Operand(boilerplate_elements_kind));
-  }
-
-  // Allocate all objects that are part of the literal in one big
-  // allocation. This avoids multiple limit checks.
-  Label allocated, runtime_allocate;
-  __ Allocate(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT);
-  __ jmp(&allocated);
-
-  __ bind(&runtime_allocate);
-  __ li(a0, Operand(Smi::FromInt(size)));
-  __ push(a0);
-  CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
-
-  __ bind(&allocated);
-  int offset = 0;
-  __ LoadHeapObject(a1, instr->hydrogen()->boilerplate());
-  EmitDeepCopy(instr->hydrogen()->boilerplate(), v0, a1, &offset,
-               instr->hydrogen()->allocation_site_mode());
-  ASSERT_EQ(size, offset);
-}
-
-
 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
   ASSERT(ToRegister(instr->result()).is(v0));
   Handle<FixedArray> literals(instr->environment()->closure()->literals());
@@ -5691,7 +5312,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
   Handle<SharedFunctionInfo> shared_info = instr->shared_info();
   bool pretenure = instr->hydrogen()->pretenure();
   if (!pretenure && shared_info->num_literals() == 0) {
-    FastNewClosureStub stub(shared_info->language_mode());
+    FastNewClosureStub stub(shared_info->language_mode(),
+                            shared_info->is_generator());
     __ li(a1, Operand(shared_info));
     __ push(a1);
     CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
index bb2003f..a1bc4ba 100644 (file)
@@ -132,7 +132,7 @@ class LCodeGen BASE_EMBEDDED {
                             IntegerSignedness signedness);
 
   void DoDeferredTaggedToI(LTaggedToI* instr);
-  void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
+  void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
   void DoDeferredStackCheck(LStackCheck* instr);
   void DoDeferredRandom(LRandom* instr);
   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
@@ -289,17 +289,7 @@ class LCodeGen BASE_EMBEDDED {
   Register ToRegister(int index) const;
   DoubleRegister ToDoubleRegister(int index) const;
 
-  // Specific math operations - used from DoUnaryMathOperation.
-  void EmitIntegerMathAbs(LUnaryMathOperation* instr);
-  void DoMathAbs(LUnaryMathOperation* instr);
-  void DoMathFloor(LUnaryMathOperation* instr);
-  void DoMathRound(LUnaryMathOperation* instr);
-  void DoMathSqrt(LUnaryMathOperation* instr);
-  void DoMathPowHalf(LUnaryMathOperation* instr);
-  void DoMathLog(LUnaryMathOperation* instr);
-  void DoMathTan(LUnaryMathOperation* instr);
-  void DoMathCos(LUnaryMathOperation* instr);
-  void DoMathSin(LUnaryMathOperation* instr);
+  void EmitIntegerMathAbs(LMathAbs* instr);
 
   // Support for recording safepoint and position information.
   void RecordSafepoint(LPointerMap* pointers,
index b415156..87efae5 100644 (file)
@@ -172,10 +172,8 @@ void LGapResolver::BreakCycle(int index) {
   } else if (source->IsStackSlot()) {
     __ lw(kLithiumScratchReg, cgen_->ToMemOperand(source));
   } else if (source->IsDoubleRegister()) {
-    CpuFeatureScope scope(cgen_->masm(), FPU);
     __ mov_d(kLithiumScratchDouble, cgen_->ToDoubleRegister(source));
   } else if (source->IsDoubleStackSlot()) {
-    CpuFeatureScope scope(cgen_->masm(), FPU);
     __ ldc1(kLithiumScratchDouble, cgen_->ToMemOperand(source));
   } else {
     UNREACHABLE();
@@ -195,11 +193,9 @@ void LGapResolver::RestoreValue() {
   } else if (saved_destination_->IsStackSlot()) {
     __ sw(kLithiumScratchReg, cgen_->ToMemOperand(saved_destination_));
   } else if (saved_destination_->IsDoubleRegister()) {
-    CpuFeatureScope scope(cgen_->masm(), FPU);
     __ mov_d(cgen_->ToDoubleRegister(saved_destination_),
             kLithiumScratchDouble);
   } else if (saved_destination_->IsDoubleStackSlot()) {
-    CpuFeatureScope scope(cgen_->masm(), FPU);
     __ sdc1(kLithiumScratchDouble,
             cgen_->ToMemOperand(saved_destination_));
   } else {
@@ -236,7 +232,6 @@ void LGapResolver::EmitMove(int index) {
       MemOperand destination_operand = cgen_->ToMemOperand(destination);
       if (in_cycle_) {
         if (!destination_operand.OffsetIsInt16Encodable()) {
-          CpuFeatureScope scope(cgen_->masm(), FPU);
           // 'at' is overwritten while saving the value to the destination.
           // Therefore we can't use 'at'.  It is OK if the read from the source
           // destroys 'at', since that happens before the value is read.
@@ -276,7 +271,6 @@ void LGapResolver::EmitMove(int index) {
     }
 
   } else if (source->IsDoubleRegister()) {
-    CpuFeatureScope scope(cgen_->masm(), FPU);
     DoubleRegister source_register = cgen_->ToDoubleRegister(source);
     if (destination->IsDoubleRegister()) {
       __ mov_d(cgen_->ToDoubleRegister(destination), source_register);
@@ -287,7 +281,6 @@ void LGapResolver::EmitMove(int index) {
     }
 
   } else if (source->IsDoubleStackSlot()) {
-    CpuFeatureScope scope(cgen_->masm(), FPU);
     MemOperand source_operand = cgen_->ToMemOperand(source);
     if (destination->IsDoubleRegister()) {
       __ ldc1(cgen_->ToDoubleRegister(destination), source_operand);
index 652c7ca..afa806c 100644 (file)
@@ -302,17 +302,6 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
 }
 
 
-void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
-  stream->Add("/%s ", hydrogen()->OpName());
-  value()->PrintTo(stream);
-}
-
-
-void LMathExp::PrintDataTo(StringStream* stream) {
-  value()->PrintTo(stream);
-}
-
-
 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
   context()->PrintTo(stream);
   stream->Add("[%d]", slot_index());
@@ -1123,50 +1112,103 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
 
 
 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
-  BuiltinFunctionId op = instr->op();
-  if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
-    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.
-    LOperand* input = UseFixedDouble(instr->value(), f8);
-    LOperand* temp = FixedTemp(f6);
-    LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
-    return DefineFixedDouble(result, f4);
-  } else {
-    LOperand* input = UseRegister(instr->value());
-
-    LOperand* temp = (op == kMathRound) ? FixedTemp(f6) :
-        (op == kMathFloor) ? TempRegister() : NULL;
-    LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
-    switch (op) {
-      case kMathAbs:
-        return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
-      case kMathFloor:
-        return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
-      case kMathSqrt:
-        return DefineAsRegister(result);
-      case kMathRound:
-        return AssignEnvironment(DefineAsRegister(result));
-      default:
-        UNREACHABLE();
-        return NULL;
-    }
+  switch (instr->op()) {
+    case kMathFloor: return DoMathFloor(instr);
+    case kMathRound: return DoMathRound(instr);
+    case kMathAbs: return DoMathAbs(instr);
+    case kMathLog: return DoMathLog(instr);
+    case kMathSin: return DoMathSin(instr);
+    case kMathCos: return DoMathCos(instr);
+    case kMathTan: return DoMathTan(instr);
+    case kMathExp: return DoMathExp(instr);
+    case kMathSqrt: return DoMathSqrt(instr);
+    case kMathPowHalf: return DoMathPowHalf(instr);
+    default:
+      UNREACHABLE();
+      return NULL;
   }
 }
 
 
+LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), f4);
+  LMathLog* result = new(zone()) LMathLog(input);
+  return MarkAsCall(DefineFixedDouble(result, f4), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), f4);
+  LMathSin* result = new(zone()) LMathSin(input);
+  return MarkAsCall(DefineFixedDouble(result, f4), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), f4);
+  LMathCos* result = new(zone()) LMathCos(input);
+  return MarkAsCall(DefineFixedDouble(result, f4), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), f4);
+  LMathTan* result = new(zone()) LMathTan(input);
+  return MarkAsCall(DefineFixedDouble(result, f4), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
+  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);
+}
+
+
+LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
+  // Input cannot be the same as the result, see LCodeGen::DoMathPowHalf.
+  LOperand* input = UseFixedDouble(instr->value(), f8);
+  LOperand* temp = FixedTemp(f6);
+  LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
+  return DefineFixedDouble(result, f4);
+}
+
+
+LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LMathAbs* result = new(zone()) LMathAbs(input);
+  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LOperand* temp = TempRegister();
+  LMathFloor* result = new(zone()) LMathFloor(input, temp);
+  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LMathSqrt* result = new(zone()) LMathSqrt(input);
+  return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegister(instr->value());
+  LOperand* temp = FixedTemp(f6);
+  LMathRound* result = new(zone()) LMathRound(input, temp);
+  return AssignEnvironment(DefineAsRegister(result));
+}
+
+
 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
   ASSERT(instr->key()->representation().IsTagged());
   argument_count_ -= instr->argument_count();
@@ -1807,7 +1849,7 @@ LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
   LUnallocated* temp1 = TempRegister();
   LOperand* temp2 = TempRegister();
   LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp1, temp2);
-  return AssignEnvironment(Define(result, temp1));
+  return AssignEnvironment(result);
 }
 
 
@@ -2008,16 +2050,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
         (instr->representation().IsDouble() &&
          ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
           (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
-    // float->double conversion on non-VFP2 requires an extra scratch
-    // register. For convenience, just mark the elements register as "UseTemp"
-    // so that it can be used as a temp during the float->double conversion
-    // after it's no longer needed after the float load.
-    bool needs_temp =
-        !CpuFeatures::IsSupported(FPU) &&
-        (elements_kind == EXTERNAL_FLOAT_ELEMENTS);
-    LOperand* external_pointer = needs_temp
-        ? UseTempRegister(instr->elements())
-        : UseRegister(instr->elements());
+    LOperand* external_pointer = UseRegister(instr->elements());
     result = new(zone()) LLoadKeyed(external_pointer, key);
   }
 
@@ -2217,11 +2250,6 @@ LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
-  return MarkAsCall(DefineFixed(new(zone()) LFastLiteral, v0), instr);
-}
-
-
 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
   return MarkAsCall(DefineFixed(new(zone()) LArrayLiteral, v0), instr);
 }
index e995905..b0fc59a 100644 (file)
@@ -97,7 +97,6 @@ class LCodeGen;
   V(DoubleToI)                                  \
   V(DummyUse)                                   \
   V(ElementsKind)                               \
-  V(FastLiteral)                                \
   V(FixedArrayBaseLength)                       \
   V(FunctionLiteral)                            \
   V(GetCachedArrayIndex)                        \
@@ -134,8 +133,17 @@ class LCodeGen;
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MapEnumLength)                              \
+  V(MathAbs)                                    \
+  V(MathCos)                                    \
   V(MathExp)                                    \
+  V(MathFloor)                                  \
+  V(MathLog)                                    \
   V(MathMinMax)                                 \
+  V(MathPowHalf)                                \
+  V(MathRound)                                  \
+  V(MathSin)                                    \
+  V(MathSqrt)                                   \
+  V(MathTan)                                    \
   V(ModI)                                       \
   V(MulI)                                       \
   V(MultiplyAddD)                               \
@@ -178,7 +186,6 @@ class LCodeGen;
   V(TrapAllocationMemento)                      \
   V(Typeof)                                     \
   V(TypeofIsAndBranch)                          \
-  V(UnaryMathOperation)                         \
   V(UnknownOSRValue)                            \
   V(ValueOf)                                    \
   V(ForInPrepareMap)                            \
@@ -663,9 +670,9 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
 };
 
 
-class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> {
+class LMathFloor: public LTemplateInstruction<1, 1, 1> {
  public:
-  LUnaryMathOperation(LOperand* value, LOperand* temp) {
+  LMathFloor(LOperand* value, LOperand* temp) {
     inputs_[0] = value;
     temps_[0] = temp;
   }
@@ -673,11 +680,84 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 1, 1> {
   LOperand* value() { return inputs_[0]; }
   LOperand* temp() { return temps_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
+  DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
   DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
 
-  virtual void PrintDataTo(StringStream* stream);
-  BuiltinFunctionId op() const { return hydrogen()->op(); }
+
+class LMathRound: public LTemplateInstruction<1, 1, 1> {
+ public:
+  LMathRound(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathAbs: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathAbs(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathLog: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathLog(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathSin: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathSin(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathSin, "math-sin")
+};
+
+
+class LMathCos: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathCos(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathCos, "math-cos")
+};
+
+
+class LMathTan: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathTan(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathTan, "math-tan")
 };
 
 
@@ -700,8 +780,32 @@ class LMathExp: public LTemplateInstruction<1, 1, 3> {
   LOperand* double_temp() { return temps_[2]; }
 
   DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+};
 
-  virtual void PrintDataTo(StringStream* stream);
+
+class LMathSqrt: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathSqrt(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
+};
+
+
+class LMathPowHalf: public LTemplateInstruction<1, 1, 1> {
+ public:
+  LMathPowHalf(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
 };
 
 
@@ -1255,7 +1359,7 @@ class LMathMinMax: public LTemplateInstruction<1, 2, 0> {
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
   DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
 };
 
@@ -2184,7 +2288,7 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> {
 };
 
 
-class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 2> {
+class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 2> {
  public:
   LCheckPrototypeMaps(LOperand* temp, LOperand* temp2)  {
     temps_[0] = temp;
@@ -2300,13 +2404,6 @@ class LAllocate: public LTemplateInstruction<1, 2, 2> {
 };
 
 
-class LFastLiteral: public LTemplateInstruction<1, 0, 0> {
- public:
-  DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
-  DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
-};
-
-
 class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
  public:
   DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
@@ -2550,6 +2647,17 @@ class LChunkBuilder BASE_EMBEDDED {
 
   LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
 
+  LInstruction* DoMathFloor(HUnaryMathOperation* instr);
+  LInstruction* DoMathRound(HUnaryMathOperation* instr);
+  LInstruction* DoMathAbs(HUnaryMathOperation* instr);
+  LInstruction* DoMathLog(HUnaryMathOperation* instr);
+  LInstruction* DoMathSin(HUnaryMathOperation* instr);
+  LInstruction* DoMathCos(HUnaryMathOperation* instr);
+  LInstruction* DoMathTan(HUnaryMathOperation* instr);
+  LInstruction* DoMathExp(HUnaryMathOperation* instr);
+  LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
+  LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
+
  private:
   enum Status {
     UNUSED,
index 12e1025..6f98914 100644 (file)
@@ -369,7 +369,6 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
 
   // Check the context is a native context.
   if (emit_debug_code()) {
-    // TODO(119): Avoid push(holder_reg)/pop(holder_reg).
     push(holder_reg);  // Temporarily save holder on the stack.
     // Read the first word and compare to the native_context_map.
     lw(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
@@ -385,7 +384,6 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
 
   // Check the context is a native context.
   if (emit_debug_code()) {
-    // TODO(119): Avoid push(holder_reg)/pop(holder_reg).
     push(holder_reg);  // Temporarily save holder on the stack.
     mov(holder_reg, at);  // Move at to its holding place.
     LoadRoot(at, Heap::kNullValueRootIndex);
@@ -853,7 +851,6 @@ void MacroAssembler::MultiPopReversed(RegList regs) {
 
 
 void MacroAssembler::MultiPushFPU(RegList regs) {
-  CpuFeatureScope scope(this, FPU);
   int16_t num_to_push = NumberOfBitsSet(regs);
   int16_t stack_offset = num_to_push * kDoubleSize;
 
@@ -868,7 +865,6 @@ void MacroAssembler::MultiPushFPU(RegList regs) {
 
 
 void MacroAssembler::MultiPushReversedFPU(RegList regs) {
-  CpuFeatureScope scope(this, FPU);
   int16_t num_to_push = NumberOfBitsSet(regs);
   int16_t stack_offset = num_to_push * kDoubleSize;
 
@@ -883,7 +879,6 @@ void MacroAssembler::MultiPushReversedFPU(RegList regs) {
 
 
 void MacroAssembler::MultiPopFPU(RegList regs) {
-  CpuFeatureScope scope(this, FPU);
   int16_t stack_offset = 0;
 
   for (int16_t i = 0; i < kNumRegisters; i++) {
@@ -897,7 +892,6 @@ void MacroAssembler::MultiPopFPU(RegList regs) {
 
 
 void MacroAssembler::MultiPopReversedFPU(RegList regs) {
-  CpuFeatureScope scope(this, FPU);
   int16_t stack_offset = 0;
 
   for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
@@ -1170,7 +1164,6 @@ void MacroAssembler::BranchF(Label* target,
 
 
 void MacroAssembler::Move(FPURegister dst, double imm) {
-  ASSERT(IsEnabled(FPU));
   static const DoubleRepresentation minus_zero(-0.0);
   static const DoubleRepresentation zero(0.0);
   DoubleRepresentation value(imm);
@@ -1340,61 +1333,17 @@ void MacroAssembler::ConvertToInt32(Register source,
   Subu(scratch2, scratch2, Operand(zero_exponent));
   // Dest already has a Smi zero.
   Branch(&done, lt, scratch2, Operand(zero_reg));
-  if (!CpuFeatures::IsSupported(FPU)) {
-    // We have a shifted exponent between 0 and 30 in scratch2.
-    srl(dest, scratch2, HeapNumber::kExponentShift);
-    // We now have the exponent in dest.  Subtract from 30 to get
-    // how much to shift down.
-    li(at, Operand(30));
-    subu(dest, at, dest);
-  }
   bind(&right_exponent);
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(this, FPU);
-    // MIPS FPU instructions implementing double precision to integer
-    // conversion using round to zero. Since the FP value was qualified
-    // above, the resulting integer should be a legal int32.
-    // The original 'Exponent' word is still in scratch.
-    lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
-    mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1));
-    trunc_w_d(double_scratch, double_scratch);
-    mfc1(dest, double_scratch);
-  } else {
-    // On entry, dest has final downshift, scratch has original sign/exp/mant.
-    // Save sign bit in top bit of dest.
-    And(scratch2, scratch, Operand(0x80000000));
-    Or(dest, dest, Operand(scratch2));
-    // Put back the implicit 1, just above mantissa field.
-    Or(scratch, scratch, Operand(1 << HeapNumber::kExponentShift));
-
-    // Shift up the mantissa bits to take up the space the exponent used to
-    // take. We just orred in the implicit bit so that took care of one and
-    // we want to leave the sign bit 0 so we subtract 2 bits from the shift
-    // distance. But we want to clear the sign-bit so shift one more bit
-    // left, then shift right one bit.
-    const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
-    sll(scratch, scratch, shift_distance + 1);
-    srl(scratch, scratch, 1);
-
-    // Get the second half of the double. For some exponents we don't
-    // actually need this because the bits get shifted out again, but
-    // it's probably slower to test than just to do it.
-    lw(scratch2, FieldMemOperand(source, HeapNumber::kMantissaOffset));
-    // Extract the top 10 bits, and insert those bottom 10 bits of scratch.
-    // The width of the field here is the same as the shift amount above.
-    const int field_width = shift_distance;
-    Ext(scratch2, scratch2, 32-shift_distance, field_width);
-    Ins(scratch, scratch2, 0, field_width);
-    // Move down according to the exponent.
-    srlv(scratch, scratch, dest);
-    // Prepare the negative version of our integer.
-    subu(scratch2, zero_reg, scratch);
-    // Trick to check sign bit (msb) held in dest, count leading zero.
-    // 0 indicates negative, save negative version with conditional move.
-    Clz(dest, dest);
-    Movz(scratch, scratch2, dest);
-    mov(dest, scratch);
-  }
+
+  // MIPS FPU instructions implementing double precision to integer
+  // conversion using round to zero. Since the FP value was qualified
+  // above, the resulting integer should be a legal int32.
+  // The original 'Exponent' word is still in scratch.
+  lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
+  mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1));
+  trunc_w_d(double_scratch, double_scratch);
+  mfc1(dest, double_scratch);
+
   bind(&done);
 }
 
@@ -1410,8 +1359,6 @@ void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode,
   ASSERT(!double_input.is(double_scratch));
   ASSERT(!except_flag.is(scratch));
 
-  ASSERT(CpuFeatures::IsSupported(FPU));
-  CpuFeatureScope scope(this, FPU);
   Label done;
 
   // Clear the except flag (0 = no exception)
@@ -1553,7 +1500,6 @@ void MacroAssembler::EmitECMATruncate(Register result,
                                       Register scratch,
                                       Register scratch2,
                                       Register scratch3) {
-  CpuFeatureScope scope(this, FPU);
   ASSERT(!scratch2.is(result));
   ASSERT(!scratch3.is(result));
   ASSERT(!scratch3.is(scratch2));
@@ -3461,11 +3407,7 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
   // scratch1 is now effective address of the double element
 
   FloatingPointHelper::Destination destination;
-  if (CpuFeatures::IsSupported(FPU)) {
-    destination = FloatingPointHelper::kFPURegisters;
-  } else {
-    destination = FloatingPointHelper::kCoreRegisters;
-  }
+  destination = FloatingPointHelper::kFPURegisters;
 
   Register untagged_value = elements_reg;
   SmiUntag(untagged_value, value_reg);
@@ -3478,7 +3420,6 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
                                           scratch4,
                                           f2);
   if (destination == FloatingPointHelper::kFPURegisters) {
-    CpuFeatureScope scope(this, FPU);
     sdc1(f0, MemOperand(scratch1, 0));
   } else {
     sw(mantissa_reg, MemOperand(scratch1, 0));
@@ -3571,7 +3512,6 @@ void MacroAssembler::CheckMap(Register obj,
 
 
 void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) {
-  CpuFeatureScope scope(this, FPU);
   if (IsMipsSoftFloatABI) {
     Move(dst, v0, v1);
   } else {
@@ -3581,7 +3521,6 @@ void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) {
 
 
 void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg) {
-  CpuFeatureScope scope(this, FPU);
   if (!IsMipsSoftFloatABI) {
     Move(f12, dreg);
   } else {
@@ -3592,7 +3531,6 @@ void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg) {
 
 void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg1,
                                              DoubleRegister dreg2) {
-  CpuFeatureScope scope(this, FPU);
   if (!IsMipsSoftFloatABI) {
     if (dreg2.is(f12)) {
       ASSERT(!dreg1.is(f14));
@@ -3611,7 +3549,6 @@ void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg1,
 
 void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg,
                                              Register reg) {
-  CpuFeatureScope scope(this, FPU);
   if (!IsMipsSoftFloatABI) {
     Move(f12, dreg);
     Move(a2, reg);
@@ -4254,10 +4191,7 @@ void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) {
   const Runtime::Function* function = Runtime::FunctionForId(id);
   PrepareCEntryArgs(function->nargs);
   PrepareCEntryFunction(ExternalReference(function, isolate()));
-  SaveFPRegsMode mode = CpuFeatures::IsSupported(FPU)
-      ? kSaveFPRegs
-      : kDontSaveFPRegs;
-  CEntryStub stub(1, mode);
+  CEntryStub stub(1, kSaveFPRegs);
   CallStub(&stub);
 }
 
@@ -4649,7 +4583,6 @@ void MacroAssembler::EnterExitFrame(bool save_doubles,
 
   const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
   if (save_doubles) {
-    CpuFeatureScope scope(this, FPU);
     // The stack  must be allign to 0 modulo 8 for stores with sdc1.
     ASSERT(kDoubleSize == frame_alignment);
     if (frame_alignment > 0) {
@@ -4687,7 +4620,6 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles,
                                     bool do_return) {
   // Optionally restore all double registers.
   if (save_doubles) {
-    CpuFeatureScope scope(this, FPU);
     // Remember: we only need to restore every 2nd double FPU value.
     lw(t8, MemOperand(fp, ExitFrameConstants::kSPOffset));
     for (int i = 0; i < FPURegister::kMaxNumRegisters; i+=2) {
index 5eb79eb..bc38435 100644 (file)
@@ -867,7 +867,7 @@ void Simulator::CheckICache(v8::internal::HashMap* i_cache,
                  Instruction::kInstrSize) == 0);
   } else {
     // Cache miss.  Load memory into the cache.
-    memcpy(cached_line, line, CachePage::kLineLength);
+    OS::MemCopy(cached_line, line, CachePage::kLineLength);
     *cache_valid_byte = CachePage::LINE_VALID;
   }
 }
@@ -1059,8 +1059,8 @@ double Simulator::get_double_from_register_pair(int reg) {
   // 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, &registers_[reg], 2 * sizeof(registers_[0]));
-  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
+  OS::MemCopy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
+  OS::MemCopy(&dm_val, buffer, 2 * sizeof(registers_[0]));
   return(dm_val);
 }
 
@@ -1091,12 +1091,14 @@ double Simulator::get_fpu_register_double(int fpureg) const {
 }
 
 
-// For use in calls that take two double values, constructed either
+// Runtime FP routines take up to two double arguments and zero
+// or one integer arguments. All are constructed here,
 // from a0-a3 or f12 and f14.
-void Simulator::GetFpArgs(double* x, double* y) {
+void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
   if (!IsMipsSoftFloatABI) {
     *x = get_fpu_register_double(12);
     *y = get_fpu_register_double(14);
+    *z = get_register(a2);
   } else {
     // We use a char buffer to get around the strict-aliasing rules which
     // otherwise allow the compiler to optimize away the copy.
@@ -1106,53 +1108,14 @@ void Simulator::GetFpArgs(double* x, double* y) {
     // Registers a0 and a1 -> x.
     reg_buffer[0] = get_register(a0);
     reg_buffer[1] = get_register(a1);
-    memcpy(x, buffer, sizeof(buffer));
-
+    OS::MemCopy(x, buffer, sizeof(buffer));
     // Registers a2 and a3 -> y.
     reg_buffer[0] = get_register(a2);
     reg_buffer[1] = get_register(a3);
-    memcpy(y, buffer, sizeof(buffer));
-  }
-}
-
-
-// For use in calls that take one double value, constructed either
-// from a0 and a1 or f12.
-void Simulator::GetFpArgs(double* x) {
-  if (!IsMipsSoftFloatABI) {
-    *x = get_fpu_register_double(12);
-  } else {
-    // We use a char buffer to get around the strict-aliasing rules which
-    // otherwise allow the compiler to optimize away the copy.
-    char buffer[sizeof(*x)];
-    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
-    // Registers a0 and a1 -> x.
-    reg_buffer[0] = get_register(a0);
-    reg_buffer[1] = get_register(a1);
-    memcpy(x, buffer, sizeof(buffer));
-  }
-}
-
-
-// For use in calls that take one double value constructed either
-// from a0 and a1 or f12 and one integer value.
-void Simulator::GetFpArgs(double* x, int32_t* y) {
-  if (!IsMipsSoftFloatABI) {
-    *x = get_fpu_register_double(12);
-    *y = get_register(a2);
-  } else {
-    // We use a char buffer to get around the strict-aliasing rules which
-    // otherwise allow the compiler to optimize away the copy.
-    char buffer[sizeof(*x)];
-    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
-    // Registers 0 and 1 -> x.
-    reg_buffer[0] = get_register(a0);
-    reg_buffer[1] = get_register(a1);
-    memcpy(x, buffer, sizeof(buffer));
-
-    // Register 2 -> y.
+    OS::MemCopy(y, buffer, sizeof(buffer));
+    // Register 2 -> z.
     reg_buffer[0] = get_register(a2);
-    memcpy(y, buffer, sizeof(*y));
+    OS::MemCopy(z, buffer, sizeof(*z));
   }
 }
 
@@ -1164,7 +1127,7 @@ void Simulator::SetFpResult(const double& result) {
   } else {
     char buffer[2 * sizeof(registers_[0])];
     int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
-    memcpy(buffer, &result, sizeof(buffer));
+    OS::MemCopy(buffer, &result, sizeof(buffer));
     // Copy result to v0 and v1.
     set_register(v0, reg_buffer[0]);
     set_register(v1, reg_buffer[1]);
@@ -1415,10 +1378,12 @@ typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
                                         int32_t arg3,
                                         int32_t arg4,
                                         int32_t arg5);
-typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
-                                         int32_t arg1,
-                                         int32_t arg2,
-                                         int32_t arg3);
+
+// These prototypes handle the four types of FP calls.
+typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
+typedef double (*SimulatorRuntimeFPCall)(double darg0);
+typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
 
 // This signature supports direct call in to API function native callback
 // (refer to InvocationCallback in v8.h).
@@ -1495,46 +1460,81 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
     // simulator. Soft-float has additional abstraction of ExternalReference,
     // to support serialization.
     if (fp_call) {
-      SimulatorRuntimeFPCall target =
-                  reinterpret_cast<SimulatorRuntimeFPCall>(external);
+      double dval0, dval1;  // one or two double parameters
+      int32_t ival;         // zero or one integer parameters
+      int64_t iresult = 0;  // integer return value
+      double dresult = 0;   // double return value
+      GetFpArgs(&dval0, &dval1, &ival);
+      SimulatorRuntimeCall generic_target =
+          reinterpret_cast<SimulatorRuntimeCall>(external);
       if (::v8::internal::FLAG_trace_sim) {
-        double dval0, dval1;
-        int32_t ival;
         switch (redirection->type()) {
           case ExternalReference::BUILTIN_FP_FP_CALL:
           case ExternalReference::BUILTIN_COMPARE_CALL:
-            GetFpArgs(&dval0, &dval1);
             PrintF("Call to host function at %p with args %f, %f",
-                FUNCTION_ADDR(target), dval0, dval1);
+                   FUNCTION_ADDR(generic_target), dval0, dval1);
             break;
           case ExternalReference::BUILTIN_FP_CALL:
-            GetFpArgs(&dval0);
             PrintF("Call to host function at %p with arg %f",
-                FUNCTION_ADDR(target), dval0);
+                FUNCTION_ADDR(generic_target), dval0);
             break;
           case ExternalReference::BUILTIN_FP_INT_CALL:
-            GetFpArgs(&dval0, &ival);
             PrintF("Call to host function at %p with args %f, %d",
-                FUNCTION_ADDR(target), dval0, ival);
+                   FUNCTION_ADDR(generic_target), dval0, ival);
             break;
           default:
             UNREACHABLE();
             break;
         }
       }
-      if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) {
+      switch (redirection->type()) {
+      case ExternalReference::BUILTIN_COMPARE_CALL: {
+        SimulatorRuntimeCompareCall target =
+          reinterpret_cast<SimulatorRuntimeCompareCall>(external);
+        iresult = target(dval0, dval1);
+        set_register(v0, static_cast<int32_t>(iresult));
+        set_register(v1, static_cast<int32_t>(iresult >> 32));
+        break;
+      }
+      case ExternalReference::BUILTIN_FP_FP_CALL: {
+        SimulatorRuntimeFPFPCall target =
+          reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
+        dresult = target(dval0, dval1);
+        SetFpResult(dresult);
+        break;
+      }
+      case ExternalReference::BUILTIN_FP_CALL: {
         SimulatorRuntimeFPCall target =
-            reinterpret_cast<SimulatorRuntimeFPCall>(external);
-        double result = target(arg0, arg1, arg2, arg3);
-        SetFpResult(result);
-      } else {
-        SimulatorRuntimeCall target =
-            reinterpret_cast<SimulatorRuntimeCall>(external);
-        uint64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
-        int32_t gpreg_pair[2];
-        memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t));
-        set_register(v0, gpreg_pair[0]);
-        set_register(v1, gpreg_pair[1]);
+          reinterpret_cast<SimulatorRuntimeFPCall>(external);
+        dresult = target(dval0);
+        SetFpResult(dresult);
+        break;
+      }
+      case ExternalReference::BUILTIN_FP_INT_CALL: {
+        SimulatorRuntimeFPIntCall target =
+          reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
+        dresult = target(dval0, ival);
+        SetFpResult(dresult);
+        break;
+      }
+      default:
+        UNREACHABLE();
+        break;
+      }
+      if (::v8::internal::FLAG_trace_sim) {
+        switch (redirection->type()) {
+        case ExternalReference::BUILTIN_COMPARE_CALL:
+          PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
+          break;
+        case ExternalReference::BUILTIN_FP_FP_CALL:
+        case ExternalReference::BUILTIN_FP_CALL:
+        case ExternalReference::BUILTIN_FP_INT_CALL:
+          PrintF("Returned %f\n", dresult);
+          break;
+        default:
+          UNREACHABLE();
+          break;
+        }
       }
     } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
       // See DirectCEntryStub::GenerateCall for explanation of register usage.
@@ -2867,9 +2867,9 @@ double Simulator::CallFP(byte* entry, double d0, double d1) {
   } else {
     int buffer[2];
     ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0));
-    memcpy(buffer, &d0, sizeof(d0));
+    OS::MemCopy(buffer, &d0, sizeof(d0));
     set_dw_register(a0, buffer);
-    memcpy(buffer, &d1, sizeof(d1));
+    OS::MemCopy(buffer, &d1, sizeof(d1));
     set_dw_register(a2, buffer);
   }
   CallInternal(entry);
index ed63443..a091e5f 100644 (file)
@@ -351,10 +351,8 @@ class Simulator {
   static void* RedirectExternalReference(void* external_function,
                                          ExternalReference::Type type);
 
-  // For use in calls that take double value arguments.
-  void GetFpArgs(double* x, double* y);
-  void GetFpArgs(double* x);
-  void GetFpArgs(double* x, int32_t* y);
+  // Handle arguments and return value for runtime FP functions.
+  void GetFpArgs(double* x, double* y, int32_t* z);
   void SetFpResult(const double& result);
 
   void CallInternal(byte* entry);
index da6770a..b9757fa 100644 (file)
@@ -410,29 +410,46 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
 }
 
 
-// Generate StoreField code, value is passed in a0 register.
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+static void GenerateCheckPropertyCell(MacroAssembler* masm,
+                                      Handle<GlobalObject> global,
+                                      Handle<Name> name,
+                                      Register scratch,
+                                      Label* miss) {
+  Handle<JSGlobalPropertyCell> cell =
+      GlobalObject::EnsurePropertyCell(global, name);
+  ASSERT(cell->value()->IsTheHole());
+  __ li(scratch, Operand(cell));
+  __ lw(scratch,
+        FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+  __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+  __ Branch(miss, ne, scratch, Operand(at));
+}
+
+
+// Generate StoreTransition code, value is passed in a0 register.
 // After executing generated code, the receiver_reg and name_reg
 // may be clobbered.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
-                                      Handle<JSObject> object,
-                                      LookupResult* lookup,
-                                      Handle<Map> transition,
-                                      Handle<Name> name,
-                                      Register receiver_reg,
-                                      Register name_reg,
-                                      Register value_reg,
-                                      Register scratch1,
-                                      Register scratch2,
-                                      Label* miss_label,
-                                      Label* miss_restore_name) {
+void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+                                           Handle<JSObject> object,
+                                           LookupResult* lookup,
+                                           Handle<Map> transition,
+                                           Handle<Name> name,
+                                           Register receiver_reg,
+                                           Register name_reg,
+                                           Register value_reg,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           Label* miss_label,
+                                           Label* miss_restore_name) {
   // a0 : value.
   Label exit;
 
   // Check that the map of the object hasn't changed.
-  CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
-                                             : REQUIRE_EXACT_MAP;
   __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
-              DO_SMI_CHECK, mode);
+              DO_SMI_CHECK, REQUIRE_EXACT_MAP);
 
   // Perform global security token check if needed.
   if (object->IsJSGlobalProxy()) {
@@ -440,7 +457,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
   }
 
   // Check that we are allowed to write this.
-  if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
+  if (object->GetPrototype()->IsJSObject()) {
     JSObject* holder;
     // holder == object indicates that no property was found.
     if (lookup->holder() != *object) {
@@ -458,12 +475,18 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     // If no property was found, and the holder (the last object in the
     // prototype chain) is in slow mode, we need to do a negative lookup on the
     // holder.
-    if (lookup->holder() == *object &&
-        !holder->HasFastProperties() &&
-        !holder->IsJSGlobalProxy() &&
-        !holder->IsJSGlobalObject()) {
-      GenerateDictionaryNegativeLookup(
-          masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+    if (lookup->holder() == *object) {
+      if (holder->IsJSGlobalObject()) {
+        GenerateCheckPropertyCell(
+            masm,
+            Handle<GlobalObject>(GlobalObject::cast(holder)),
+            name,
+            scratch1,
+            miss_restore_name);
+      } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+        GenerateDictionaryNegativeLookup(
+            masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+      }
     }
   }
 
@@ -472,7 +495,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
   // Perform map transition for the receiver if necessary.
-  if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
+  if (object->map()->unused_property_fields() == 0) {
     // The properties must be extended before we can store the value.
     // We jump to a runtime call that extends the properties array.
     __ push(receiver_reg);
@@ -485,33 +508,114 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     return;
   }
 
-  int index;
-  if (!transition.is_null()) {
-    // Update the map of the object.
-    __ li(scratch1, Operand(transition));
-    __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+  // Update the map of the object.
+  __ li(scratch1, Operand(transition));
+  __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+
+  // Update the write barrier for the map field and pass the now unused
+  // name_reg as scratch register.
+  __ RecordWriteField(receiver_reg,
+                      HeapObject::kMapOffset,
+                      scratch1,
+                      name_reg,
+                      kRAHasNotBeenSaved,
+                      kDontSaveFPRegs,
+                      OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+
+  int index = transition->instance_descriptors()->GetFieldIndex(
+      transition->LastAdded());
 
-    // Update the write barrier for the map field and pass the now unused
-    // name_reg as scratch register.
+  // Adjust for the number of properties stored in the object. Even in the
+  // face of a transition we can use the old map here because the size of the
+  // object and the number of in-object properties is not going to change.
+  index -= object->map()->inobject_properties();
+
+  // TODO(verwaest): Share this code as a code stub.
+  if (index < 0) {
+    // Set the property straight into the object.
+    int offset = object->map()->instance_size() + (index * kPointerSize);
+    __ sw(value_reg, FieldMemOperand(receiver_reg, offset));
+
+    // Skip updating write barrier if storing a smi.
+    __ JumpIfSmi(value_reg, &exit);
+
+    // Update the write barrier for the array address.
+    // Pass the now unused name_reg as a scratch register.
+    __ mov(name_reg, value_reg);
     __ RecordWriteField(receiver_reg,
-                        HeapObject::kMapOffset,
-                        scratch1,
+                        offset,
                         name_reg,
+                        scratch1,
                         kRAHasNotBeenSaved,
-                        kDontSaveFPRegs,
-                        OMIT_REMEMBERED_SET,
-                        OMIT_SMI_CHECK);
-    index = transition->instance_descriptors()->GetFieldIndex(
-        transition->LastAdded());
+                        kDontSaveFPRegs);
   } else {
-    index = lookup->GetFieldIndex().field_index();
+    // Write to the properties array.
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
+    // Get the properties array
+    __ lw(scratch1,
+          FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
+    __ sw(value_reg, FieldMemOperand(scratch1, offset));
+
+    // Skip updating write barrier if storing a smi.
+    __ JumpIfSmi(value_reg, &exit);
+
+    // Update the write barrier for the array address.
+    // Ok to clobber receiver_reg and name_reg, since we return.
+    __ mov(name_reg, value_reg);
+    __ RecordWriteField(scratch1,
+                        offset,
+                        name_reg,
+                        receiver_reg,
+                        kRAHasNotBeenSaved,
+                        kDontSaveFPRegs);
+  }
+
+  // Return the value (register v0).
+  ASSERT(value_reg.is(a0));
+  __ bind(&exit);
+  __ mov(v0, a0);
+  __ Ret();
+}
+
+
+// Generate StoreField code, value is passed in a0 register.
+// When leaving generated code after success, the receiver_reg and name_reg
+// may be clobbered.  Upon branch to miss_label, the receiver and name
+// registers have their original values.
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+                                      Handle<JSObject> object,
+                                      LookupResult* lookup,
+                                      Register receiver_reg,
+                                      Register name_reg,
+                                      Register value_reg,
+                                      Register scratch1,
+                                      Register scratch2,
+                                      Label* miss_label) {
+  // a0 : value
+  Label exit;
+
+  // Check that the map of the object hasn't changed.
+  __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
+              DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+
+  // Perform global security token check if needed.
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
   }
 
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+  int index = lookup->GetFieldIndex().field_index();
+
   // Adjust for the number of properties stored in the object. Even in the
   // face of a transition we can use the old map here because the size of the
   // object and the number of in-object properties is not going to change.
   index -= object->map()->inobject_properties();
 
+  // TODO(verwaest): Share this code as a code stub.
   if (index < 0) {
     // Set the property straight into the object.
     int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -926,26 +1030,6 @@ class CallInterceptorCompiler BASE_EMBEDDED {
 };
 
 
-
-// Generate code to check that a global property cell is empty. Create
-// the property cell at compilation time if no cell exists for the
-// property.
-static void GenerateCheckPropertyCell(MacroAssembler* masm,
-                                      Handle<GlobalObject> global,
-                                      Handle<Name> name,
-                                      Register scratch,
-                                      Label* miss) {
-  Handle<JSGlobalPropertyCell> cell =
-      GlobalObject::EnsurePropertyCell(global, name);
-  ASSERT(cell->value()->IsTheHole());
-  __ li(scratch, Operand(cell));
-  __ lw(scratch,
-        FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
-  __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-  __ Branch(miss, ne, scratch, Operand(at));
-}
-
-
 // Calls GenerateCheckPropertyCell for each global object in the prototype chain
 // from object to (but not including) holder.
 static void GenerateCheckPropertyCells(MacroAssembler* masm,
@@ -975,72 +1059,12 @@ static void StoreIntAsFloat(MacroAssembler* masm,
                             Register dst,
                             Register wordoffset,
                             Register ival,
-                            Register fval,
-                            Register scratch1,
-                            Register scratch2) {
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    __ mtc1(ival, f0);
-    __ cvt_s_w(f0, f0);
-    __ sll(scratch1, wordoffset, 2);
-    __ addu(scratch1, dst, scratch1);
-    __ swc1(f0, MemOperand(scratch1, 0));
-  } else {
-    // FPU is not available,  do manual conversions.
-
-    Label not_special, done;
-    // Move sign bit from source to destination.  This works because the sign
-    // bit in the exponent word of the double has the same position and polarity
-    // as the 2's complement sign bit in a Smi.
-    ASSERT(kBinary32SignMask == 0x80000000u);
-
-    __ And(fval, ival, Operand(kBinary32SignMask));
-    // Negate value if it is negative.
-    __ subu(scratch1, zero_reg, ival);
-    __ Movn(ival, scratch1, fval);
-
-    // We have -1, 0 or 1, which we treat specially. Register ival contains
-    // absolute value: it is either equal to 1 (special case of -1 and 1),
-    // greater than 1 (not a special case) or less than 1 (special case of 0).
-    __ Branch(&not_special, gt, ival, Operand(1));
-
-    // For 1 or -1 we need to or in the 0 exponent (biased).
-    static const uint32_t exponent_word_for_1 =
-        kBinary32ExponentBias << kBinary32ExponentShift;
-
-    __ Xor(scratch1, ival, Operand(1));
-    __ li(scratch2, exponent_word_for_1);
-    __ or_(scratch2, fval, scratch2);
-    __ Movz(fval, scratch2, scratch1);  // Only if ival is equal to 1.
-    __ Branch(&done);
-
-    __ bind(&not_special);
-    // Count leading zeros.
-    // Gets the wrong answer for 0, but we already checked for that case above.
-    Register zeros = scratch2;
-    __ Clz(zeros, ival);
-
-    // Compute exponent and or it into the exponent register.
-    __ li(scratch1, (kBitsPerInt - 1) + kBinary32ExponentBias);
-    __ subu(scratch1, scratch1, zeros);
-
-    __ sll(scratch1, scratch1, kBinary32ExponentShift);
-    __ or_(fval, fval, scratch1);
-
-    // Shift up the source chopping the top bit off.
-    __ Addu(zeros, zeros, Operand(1));
-    // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
-    __ sllv(ival, ival, zeros);
-    // And the top (top 20 bits).
-    __ srl(scratch1, ival, kBitsPerInt - kBinary32MantissaBits);
-    __ or_(fval, fval, scratch1);
-
-    __ bind(&done);
-
-    __ sll(scratch1, wordoffset, 2);
-    __ addu(scratch1, dst, scratch1);
-    __ sw(fval, MemOperand(scratch1, 0));
-  }
+                            Register scratch1) {
+  __ mtc1(ival, f0);
+  __ cvt_s_w(f0, f0);
+  __ sll(scratch1, wordoffset, 2);
+  __ addu(scratch1, dst, scratch1);
+  __ swc1(f0, MemOperand(scratch1, 0));
 }
 
 
@@ -1229,7 +1253,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     Handle<GlobalObject> global) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
+  HandlerFrontendHeader(object, receiver(), last, name, &miss);
 
   // If the last object in the prototype chain is a global object,
   // check that the global property cell is empty.
@@ -1237,13 +1261,6 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
   }
 
-  if (!last->HasFastProperties()) {
-    __ lw(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset));
-    __ lw(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset));
-    __ Branch(&miss, ne, scratch2(),
-        Operand(isolate()->factory()->null_value()));
-  }
-
   HandlerFrontendFooter(success, &miss);
 }
 
@@ -2100,11 +2117,7 @@ Handle<Code> CallStubCompiler::CompileMathFloorCall(
   //  -- sp[argc * 4]           : receiver
   // -----------------------------------
 
-  if (!CpuFeatures::IsSupported(FPU)) {
-    return Handle<Code>::null();
-  }
 
-  CpuFeatureScope scope_fpu(masm(), FPU);
   const int argc = arguments().immediate();
   // If the object is not a JSObject or we got an unexpected number of
   // arguments, bail out to the regular call.
@@ -3170,36 +3183,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
 }
 
 
-static bool IsElementTypeSigned(ElementsKind elements_kind) {
-  switch (elements_kind) {
-    case EXTERNAL_BYTE_ELEMENTS:
-    case EXTERNAL_SHORT_ELEMENTS:
-    case EXTERNAL_INT_ELEMENTS:
-      return true;
-
-    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-    case EXTERNAL_UNSIGNED_INT_ELEMENTS:
-    case EXTERNAL_PIXEL_ELEMENTS:
-      return false;
-
-    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();
-      return false;
-  }
-  return false;
-}
-
-
 static void GenerateSmiKeyCheck(MacroAssembler* masm,
                                 Register key,
                                 Register scratch0,
@@ -3207,36 +3190,30 @@ static void GenerateSmiKeyCheck(MacroAssembler* masm,
                                 FPURegister double_scratch0,
                                 FPURegister double_scratch1,
                                 Label* fail) {
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(masm, FPU);
-    Label key_ok;
-    // Check for smi or a smi inside a heap number.  We convert the heap
-    // number and check if the conversion is exact and fits into the smi
-    // range.
-    __ JumpIfSmi(key, &key_ok);
-    __ CheckMap(key,
-                scratch0,
-                Heap::kHeapNumberMapRootIndex,
-                fail,
-                DONT_DO_SMI_CHECK);
-    __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
-    __ EmitFPUTruncate(kRoundToZero,
-                       scratch0,
-                       double_scratch0,
-                       at,
-                       double_scratch1,
-                       scratch1,
-                       kCheckForInexactConversion);
-
-    __ Branch(fail, ne, scratch1, Operand(zero_reg));
-
-    __ SmiTagCheckOverflow(key, scratch0, scratch1);
-    __ BranchOnOverflow(fail, scratch1);
-    __ bind(&key_ok);
-  } else {
-    // Check that the key is a smi.
-    __ JumpIfNotSmi(key, fail);
-  }
+  Label key_ok;
+  // Check for smi or a smi inside a heap number.  We convert the heap
+  // number and check if the conversion is exact and fits into the smi
+  // range.
+  __ JumpIfSmi(key, &key_ok);
+  __ CheckMap(key,
+              scratch0,
+              Heap::kHeapNumberMapRootIndex,
+              fail,
+              DONT_DO_SMI_CHECK);
+  __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
+  __ EmitFPUTruncate(kRoundToZero,
+                     scratch0,
+                     double_scratch0,
+                     at,
+                     double_scratch1,
+                     scratch1,
+                     kCheckForInexactConversion);
+
+  __ Branch(fail, ne, scratch1, Operand(zero_reg));
+
+  __ SmiTagCheckOverflow(key, scratch0, scratch1);
+  __ BranchOnOverflow(fail, scratch1);
+  __ bind(&key_ok);
 }
 
 
@@ -3327,29 +3304,19 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
     case EXTERNAL_FLOAT_ELEMENTS:
       // Perform int-to-float conversion and store to memory.
       __ SmiUntag(t0, key);
-      StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
+      StoreIntAsFloat(masm, a3, t0, t1, t2);
       break;
     case EXTERNAL_DOUBLE_ELEMENTS:
       __ sll(t8, key, 2);
       __ addu(a3, a3, t8);
       // a3: effective address of the double element
       FloatingPointHelper::Destination destination;
-      if (CpuFeatures::IsSupported(FPU)) {
-        destination = FloatingPointHelper::kFPURegisters;
-      } else {
-        destination = FloatingPointHelper::kCoreRegisters;
-      }
+      destination = FloatingPointHelper::kFPURegisters;
       FloatingPointHelper::ConvertIntToDouble(
           masm, t1, destination,
           f0, t2, t3,  // These are: double_dst, dst_mantissa, dst_exponent.
           t0, f2);  // These are: scratch2, single_scratch.
-      if (destination == FloatingPointHelper::kFPURegisters) {
-        CpuFeatureScope scope(masm, FPU);
-        __ sdc1(f0, MemOperand(a3, 0));
-      } else {
-        __ sw(t2, MemOperand(a3, 0));
-        __ sw(t3, MemOperand(a3, Register::kSizeInBytes));
-      }
+      __ sdc1(f0, MemOperand(a3, 0));
       break;
     case FAST_ELEMENTS:
     case FAST_SMI_ELEMENTS:
@@ -3381,232 +3348,59 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
     // +/-Infinity into integer arrays basically undefined. For more
     // reproducible behavior, convert these to zero.
 
-    if (CpuFeatures::IsSupported(FPU)) {
-      CpuFeatureScope scope(masm, FPU);
 
-      __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
+    __ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
 
-      if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
-        __ cvt_s_d(f0, f0);
-        __ sll(t8, key, 1);
-        __ addu(t8, a3, t8);
-        __ swc1(f0, MemOperand(t8, 0));
-      } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
-        __ sll(t8, key, 2);
-        __ addu(t8, a3, t8);
-        __ sdc1(f0, MemOperand(t8, 0));
-      } else {
-        __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
-
-        switch (elements_kind) {
-          case EXTERNAL_BYTE_ELEMENTS:
-          case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-            __ srl(t8, key, 1);
-            __ addu(t8, a3, t8);
-            __ sb(t3, MemOperand(t8, 0));
-            break;
-          case EXTERNAL_SHORT_ELEMENTS:
-          case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-            __ addu(t8, a3, key);
-            __ sh(t3, MemOperand(t8, 0));
-            break;
-          case EXTERNAL_INT_ELEMENTS:
-          case EXTERNAL_UNSIGNED_INT_ELEMENTS:
-            __ sll(t8, key, 1);
-            __ addu(t8, a3, t8);
-            __ sw(t3, MemOperand(t8, 0));
-            break;
-          case EXTERNAL_PIXEL_ELEMENTS:
-          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;
-        }
-      }
-
-      // Entry registers are intact, a0 holds the value
-      // which is the return value.
-      __ mov(v0, a0);
-      __ Ret();
+    if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
+      __ cvt_s_d(f0, f0);
+      __ sll(t8, key, 1);
+      __ addu(t8, a3, t8);
+      __ swc1(f0, MemOperand(t8, 0));
+    } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
+      __ sll(t8, key, 2);
+      __ addu(t8, a3, t8);
+      __ sdc1(f0, MemOperand(t8, 0));
     } else {
-      // FPU is not available, do manual conversions.
-
-      __ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
-      __ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
-
-      if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
-        Label done, nan_or_infinity_or_zero;
-        static const int kMantissaInHiWordShift =
-            kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
-
-        static const int kMantissaInLoWordShift =
-            kBitsPerInt - kMantissaInHiWordShift;
-
-        // Test for all special exponent values: zeros, subnormal numbers, NaNs
-        // and infinities. All these should be converted to 0.
-        __ li(t5, HeapNumber::kExponentMask);
-        __ and_(t6, t3, t5);
-        __ Branch(&nan_or_infinity_or_zero, eq, t6, Operand(zero_reg));
-
-        __ xor_(t1, t6, t5);
-        __ li(t2, kBinary32ExponentMask);
-        __ Movz(t6, t2, t1);  // Only if t6 is equal to t5.
-        __ Branch(&nan_or_infinity_or_zero, eq, t1, Operand(zero_reg));
-
-        // Rebias exponent.
-        __ srl(t6, t6, HeapNumber::kExponentShift);
-        __ Addu(t6,
-                t6,
-                Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
-
-        __ li(t1, Operand(kBinary32MaxExponent));
-        __ Slt(t1, t1, t6);
-        __ And(t2, t3, Operand(HeapNumber::kSignMask));
-        __ Or(t2, t2, Operand(kBinary32ExponentMask));
-        __ Movn(t3, t2, t1);  // Only if t6 is gt kBinary32MaxExponent.
-        __ Branch(&done, gt, t6, Operand(kBinary32MaxExponent));
-
-        __ Slt(t1, t6, Operand(kBinary32MinExponent));
-        __ And(t2, t3, Operand(HeapNumber::kSignMask));
-        __ Movn(t3, t2, t1);  // Only if t6 is lt kBinary32MinExponent.
-        __ Branch(&done, lt, t6, Operand(kBinary32MinExponent));
-
-        __ And(t7, t3, Operand(HeapNumber::kSignMask));
-        __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
-        __ sll(t3, t3, kMantissaInHiWordShift);
-        __ or_(t7, t7, t3);
-        __ srl(t4, t4, kMantissaInLoWordShift);
-        __ or_(t7, t7, t4);
-        __ sll(t6, t6, kBinary32ExponentShift);
-        __ or_(t3, t7, t6);
-
-        __ bind(&done);
-        __ sll(t9, key, 1);
-        __ addu(t9, a3, t9);
-        __ sw(t3, MemOperand(t9, 0));
-
-        // Entry registers are intact, a0 holds the value which is the return
-        // value.
-        __ mov(v0, a0);
-        __ Ret();
-
-        __ bind(&nan_or_infinity_or_zero);
-        __ And(t7, t3, Operand(HeapNumber::kSignMask));
-        __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
-        __ or_(t6, t6, t7);
-        __ sll(t3, t3, kMantissaInHiWordShift);
-        __ or_(t6, t6, t3);
-        __ srl(t4, t4, kMantissaInLoWordShift);
-        __ or_(t3, t6, t4);
-        __ Branch(&done);
-      } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
-        __ sll(t8, key, 2);
-        __ addu(t8, a3, t8);
-        // t8: effective address of destination element.
-        __ sw(t4, MemOperand(t8, 0));
-        __ sw(t3, MemOperand(t8, Register::kSizeInBytes));
-        __ mov(v0, a0);
-        __ Ret();
-      } else {
-        bool is_signed_type = IsElementTypeSigned(elements_kind);
-        int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
-        int32_t min_value    = is_signed_type ? 0x80000000 : 0x00000000;
-
-        Label done, sign;
-
-        // Test for all special exponent values: zeros, subnormal numbers, NaNs
-        // and infinities. All these should be converted to 0.
-        __ li(t5, HeapNumber::kExponentMask);
-        __ and_(t6, t3, t5);
-        __ Movz(t3, zero_reg, t6);  // Only if t6 is equal to zero.
-        __ Branch(&done, eq, t6, Operand(zero_reg));
-
-        __ xor_(t2, t6, t5);
-        __ Movz(t3, zero_reg, t2);  // Only if t6 is equal to t5.
-        __ Branch(&done, eq, t6, Operand(t5));
-
-        // Unbias exponent.
-        __ srl(t6, t6, HeapNumber::kExponentShift);
-        __ Subu(t6, t6, Operand(HeapNumber::kExponentBias));
-        // If exponent is negative then result is 0.
-        __ slt(t2, t6, zero_reg);
-        __ Movn(t3, zero_reg, t2);  // Only if exponent is negative.
-        __ Branch(&done, lt, t6, Operand(zero_reg));
-
-        // If exponent is too big then result is minimal value.
-        __ slti(t1, t6, meaningfull_bits - 1);
-        __ li(t2, min_value);
-        __ Movz(t3, t2, t1);  // Only if t6 is ge meaningfull_bits - 1.
-        __ Branch(&done, ge, t6, Operand(meaningfull_bits - 1));
-
-        __ And(t5, t3, Operand(HeapNumber::kSignMask));
-        __ And(t3, t3, Operand(HeapNumber::kMantissaMask));
-        __ Or(t3, t3, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
-
-        __ li(t9, HeapNumber::kMantissaBitsInTopWord);
-        __ subu(t6, t9, t6);
-        __ slt(t1, t6, zero_reg);
-        __ srlv(t2, t3, t6);
-        __ Movz(t3, t2, t1);  // Only if t6 is positive.
-        __ Branch(&sign, ge, t6, Operand(zero_reg));
-
-        __ subu(t6, zero_reg, t6);
-        __ sllv(t3, t3, t6);
-        __ li(t9, meaningfull_bits);
-        __ subu(t6, t9, t6);
-        __ srlv(t4, t4, t6);
-        __ or_(t3, t3, t4);
-
-        __ bind(&sign);
-        __ subu(t2, t3, zero_reg);
-        __ Movz(t3, t2, t5);  // Only if t5 is zero.
-
-        __ bind(&done);
-
-        // Result is in t3.
-        // This switch block should be exactly the same as above (FPU mode).
-        switch (elements_kind) {
-          case EXTERNAL_BYTE_ELEMENTS:
-          case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
-            __ srl(t8, key, 1);
-            __ addu(t8, a3, t8);
-            __ sb(t3, MemOperand(t8, 0));
-            break;
-          case EXTERNAL_SHORT_ELEMENTS:
-          case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
-            __ addu(t8, a3, key);
-            __ sh(t3, MemOperand(t8, 0));
-            break;
-          case EXTERNAL_INT_ELEMENTS:
-          case EXTERNAL_UNSIGNED_INT_ELEMENTS:
-            __ sll(t8, key, 1);
-            __ addu(t8, a3, t8);
-            __ sw(t3, MemOperand(t8, 0));
-            break;
-          case EXTERNAL_PIXEL_ELEMENTS:
-          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;
-        }
+      __ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
+
+      switch (elements_kind) {
+        case EXTERNAL_BYTE_ELEMENTS:
+        case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+          __ srl(t8, key, 1);
+          __ addu(t8, a3, t8);
+          __ sb(t3, MemOperand(t8, 0));
+          break;
+        case EXTERNAL_SHORT_ELEMENTS:
+        case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+          __ addu(t8, a3, key);
+          __ sh(t3, MemOperand(t8, 0));
+          break;
+        case EXTERNAL_INT_ELEMENTS:
+        case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+          __ sll(t8, key, 1);
+          __ addu(t8, a3, t8);
+          __ sw(t3, MemOperand(t8, 0));
+          break;
+        case EXTERNAL_PIXEL_ELEMENTS:
+        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;
       }
     }
+
+    // Entry registers are intact, a0 holds the value
+    // which is the return value.
+    __ mov(v0, a0);
+    __ Ret();
   }
 
   // Slow case, key and receiver still in a0 and a1.
index 44cab53..24730a0 100644 (file)
@@ -139,6 +139,9 @@ void HeapObject::HeapObjectVerify() {
     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
       JSObject::cast(this)->JSObjectVerify();
       break;
+    case JS_GENERATOR_OBJECT_TYPE:
+      JSGeneratorObject::cast(this)->JSGeneratorObjectVerify();
+      break;
     case JS_MODULE_TYPE:
       JSModule::cast(this)->JSModuleVerify();
       break;
@@ -198,6 +201,9 @@ void HeapObject::HeapObjectVerify() {
     case JS_ARRAY_BUFFER_TYPE:
       JSArrayBuffer::cast(this)->JSArrayBufferVerify();
       break;
+    case JS_TYPED_ARRAY_TYPE:
+      JSTypedArray::cast(this)->JSTypedArrayVerify();
+      break;
 
 #define MAKE_STRUCT_CASE(NAME, Name, name) \
   case NAME##_TYPE:                        \
@@ -404,6 +410,17 @@ void FixedDoubleArray::FixedDoubleArrayVerify() {
 }
 
 
+void JSGeneratorObject::JSGeneratorObjectVerify() {
+  // In an expression like "new g()", there can be a point where a generator
+  // object is allocated but its fields are all undefined, as it hasn't yet been
+  // initialized by the generator.  Hence these weak checks.
+  VerifyObjectField(kFunctionOffset);
+  VerifyObjectField(kContextOffset);
+  VerifyObjectField(kOperandStackOffset);
+  VerifyObjectField(kContinuationOffset);
+}
+
+
 void JSModule::JSModuleVerify() {
   VerifyObjectField(kContextOffset);
   VerifyObjectField(kScopeInfoOffset);
@@ -724,6 +741,28 @@ void JSArrayBuffer::JSArrayBufferVerify() {
 }
 
 
+void JSTypedArray::JSTypedArrayVerify() {
+  CHECK(IsJSTypedArray());
+  JSObjectVerify();
+  VerifyPointer(buffer());
+  CHECK(buffer()->IsJSArrayBuffer() || buffer()->IsUndefined());
+
+  VerifyPointer(byte_offset());
+  CHECK(byte_offset()->IsSmi() || byte_offset()->IsHeapNumber()
+        || byte_offset()->IsUndefined());
+
+  VerifyPointer(byte_length());
+  CHECK(byte_length()->IsSmi() || byte_length()->IsHeapNumber()
+        || byte_length()->IsUndefined());
+
+  VerifyPointer(length());
+  CHECK(length()->IsSmi() || length()->IsHeapNumber()
+        || length()->IsUndefined());
+
+  VerifyPointer(elements());
+}
+
+
 void Foreign::ForeignVerify() {
   CHECK(IsForeign());
 }
index ec03405..efc1764 100644 (file)
@@ -653,6 +653,7 @@ TYPE_CHECKER(Code, CODE_TYPE)
 TYPE_CHECKER(Oddball, ODDBALL_TYPE)
 TYPE_CHECKER(JSGlobalPropertyCell, JS_GLOBAL_PROPERTY_CELL_TYPE)
 TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE)
+TYPE_CHECKER(JSGeneratorObject, JS_GENERATOR_OBJECT_TYPE)
 TYPE_CHECKER(JSModule, JS_MODULE_TYPE)
 TYPE_CHECKER(JSValue, JS_VALUE_TYPE)
 TYPE_CHECKER(JSDate, JS_DATE_TYPE)
@@ -675,6 +676,7 @@ bool Object::IsBoolean() {
 
 TYPE_CHECKER(JSArray, JS_ARRAY_TYPE)
 TYPE_CHECKER(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE)
+TYPE_CHECKER(JSTypedArray, JS_TYPED_ARRAY_TYPE)
 TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE)
 
 
@@ -1488,22 +1490,59 @@ MaybeObject* JSObject::AddFastPropertyUsingMap(Map* map) {
 }
 
 
-bool JSObject::TryTransitionToField(Handle<JSObject> object,
-                                    Handle<Name> key) {
-  if (!object->map()->HasTransitionArray()) return false;
-  Handle<Map> target;
-  {
-    AssertNoAllocation no_allocation;
-    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;
-    target = Handle<Map>(transitions->GetTarget(transition));
+MaybeObject* JSObject::TransitionToMap(Map* map) {
+  ASSERT(this->map()->inobject_properties() == map->inobject_properties());
+  ElementsKind expected_kind = this->map()->elements_kind();
+  if (map->elements_kind() != expected_kind) {
+    MaybeObject* maybe_map = map->AsElementsKind(expected_kind);
+    if (!maybe_map->To(&map)) return maybe_map;
   }
-  JSObject::AddFastPropertyUsingMap(object, target);
-  return true;
+  int total_size =
+      map->NumberOfOwnDescriptors() + map->unused_property_fields();
+  int out_of_object = total_size - map->inobject_properties();
+  if (out_of_object != properties()->length()) {
+    FixedArray* new_properties;
+    MaybeObject* maybe_properties = properties()->CopySize(out_of_object);
+    if (!maybe_properties->To(&new_properties)) return maybe_properties;
+    set_properties(new_properties);
+  }
+  set_map(map);
+  return this;
+}
+
+
+Handle<String> JSObject::ExpectedTransitionKey(Handle<Map> map) {
+  AssertNoAllocation no_gc;
+  if (!map->HasTransitionArray()) return Handle<String>::null();
+  TransitionArray* transitions = map->transitions();
+  if (!transitions->IsSimpleTransition()) return Handle<String>::null();
+  int transition = TransitionArray::kSimpleTransitionIndex;
+  PropertyDetails details = transitions->GetTargetDetails(transition);
+  Name* name = transitions->GetKey(transition);
+  if (details.type() != FIELD) return Handle<String>::null();
+  if (details.attributes() != NONE) return Handle<String>::null();
+  if (!name->IsString()) return Handle<String>::null();
+  return Handle<String>(String::cast(name));
+}
+
+
+Handle<Map> JSObject::ExpectedTransitionTarget(Handle<Map> map) {
+  ASSERT(!ExpectedTransitionKey(map).is_null());
+  return Handle<Map>(map->transitions()->GetTarget(
+      TransitionArray::kSimpleTransitionIndex));
+}
+
+
+Handle<Map> JSObject::FindTransitionToField(Handle<Map> map, Handle<Name> key) {
+  AssertNoAllocation no_allocation;
+  if (!map->HasTransitionArray()) return Handle<Map>::null();
+  TransitionArray* transitions = map->transitions();
+  int transition = transitions->Search(*key);
+  if (transition == TransitionArray::kNotFound) return Handle<Map>::null();
+  PropertyDetails target_details = transitions->GetTargetDetails(transition);
+  if (target_details.type() != FIELD) return Handle<Map>::null();
+  if (target_details.attributes() != NONE) return Handle<Map>::null();
+  return Handle<Map>(transitions->GetTarget(transition));
 }
 
 
@@ -1547,6 +1586,8 @@ int JSObject::GetHeaderSize() {
   // field operations considerably on average.
   if (type == JS_OBJECT_TYPE) return JSObject::kHeaderSize;
   switch (type) {
+    case JS_GENERATOR_OBJECT_TYPE:
+      return JSGeneratorObject::kSize;
     case JS_MODULE_TYPE:
       return JSModule::kSize;
     case JS_GLOBAL_PROXY_TYPE:
@@ -1565,6 +1606,8 @@ int JSObject::GetHeaderSize() {
       return JSArray::kSize;
     case JS_ARRAY_BUFFER_TYPE:
       return JSArrayBuffer::kSize;
+    case JS_TYPED_ARRAY_TYPE:
+      return JSTypedArray::kSize;
     case JS_SET_TYPE:
       return JSSet::kSize;
     case JS_MAP_TYPE:
@@ -2452,6 +2495,7 @@ CAST_ACCESSOR(JSBuiltinsObject)
 CAST_ACCESSOR(Code)
 CAST_ACCESSOR(JSArray)
 CAST_ACCESSOR(JSArrayBuffer)
+CAST_ACCESSOR(JSTypedArray)
 CAST_ACCESSOR(JSRegExp)
 CAST_ACCESSOR(JSProxy)
 CAST_ACCESSOR(JSFunctionProxy)
@@ -2508,8 +2552,8 @@ void Name::set_hash_field(uint32_t value) {
 
 bool Name::Equals(Name* other) {
   if (other == this) return true;
-  if (this->IsSymbol() || other->IsSymbol() ||
-      (this->IsInternalizedString() && other->IsInternalizedString())) {
+  if ((this->IsInternalizedString() && other->IsInternalizedString()) ||
+      this->IsSymbol() || other->IsSymbol()) {
     return false;
   }
   return String::cast(this)->SlowEquals(String::cast(other));
@@ -3762,33 +3806,33 @@ void Code::set_safepoint_table_offset(unsigned offset) {
 }
 
 
-unsigned Code::stack_check_table_offset() {
+unsigned Code::back_edge_table_offset() {
   ASSERT_EQ(FUNCTION, kind());
-  return StackCheckTableOffsetField::decode(
+  return BackEdgeTableOffsetField::decode(
       READ_UINT32_FIELD(this, kKindSpecificFlags2Offset));
 }
 
 
-void Code::set_stack_check_table_offset(unsigned offset) {
+void Code::set_back_edge_table_offset(unsigned offset) {
   ASSERT_EQ(FUNCTION, kind());
   ASSERT(IsAligned(offset, static_cast<unsigned>(kIntSize)));
   int previous = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
-  int updated = StackCheckTableOffsetField::update(previous, offset);
+  int updated = BackEdgeTableOffsetField::update(previous, offset);
   WRITE_UINT32_FIELD(this, kKindSpecificFlags2Offset, updated);
 }
 
 
-bool Code::stack_check_patched_for_osr() {
+bool Code::back_edges_patched_for_osr() {
   ASSERT_EQ(FUNCTION, kind());
-  return StackCheckPatchedForOSRField::decode(
+  return BackEdgesPatchedForOSRField::decode(
       READ_UINT32_FIELD(this, kKindSpecificFlags2Offset));
 }
 
 
-void Code::set_stack_check_patched_for_osr(bool value) {
+void Code::set_back_edges_patched_for_osr(bool value) {
   ASSERT_EQ(FUNCTION, kind());
   int previous = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
-  int updated = StackCheckPatchedForOSRField::update(previous, value);
+  int updated = BackEdgesPatchedForOSRField::update(previous, value);
   WRITE_UINT32_FIELD(this, kKindSpecificFlags2Offset, updated);
 }
 
@@ -4973,6 +5017,19 @@ void Foreign::set_foreign_address(Address value) {
 }
 
 
+ACCESSORS(JSGeneratorObject, function, JSFunction, kFunctionOffset)
+ACCESSORS(JSGeneratorObject, context, Object, kContextOffset)
+SMI_ACCESSORS(JSGeneratorObject, continuation, kContinuationOffset)
+ACCESSORS(JSGeneratorObject, operand_stack, FixedArray, kOperandStackOffset)
+
+
+JSGeneratorObject* JSGeneratorObject::cast(Object* obj) {
+  ASSERT(obj->IsJSGeneratorObject());
+  ASSERT(HeapObject::cast(obj)->Size() == JSGeneratorObject::kSize);
+  return reinterpret_cast<JSGeneratorObject*>(obj);
+}
+
+
 ACCESSORS(JSModule, context, Object, kContextOffset)
 ACCESSORS(JSModule, scope_info, ScopeInfo, kScopeInfoOffset)
 
@@ -5154,6 +5211,12 @@ void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) {
 ACCESSORS(JSArrayBuffer, byte_length, Object, kByteLengthOffset)
 
 
+ACCESSORS(JSTypedArray, buffer, Object, kBufferOffset)
+ACCESSORS(JSTypedArray, byte_offset, Object, kByteOffsetOffset)
+ACCESSORS(JSTypedArray, byte_length, Object, kByteLengthOffset)
+ACCESSORS(JSTypedArray, length, Object, kLengthOffset)
+
+
 ACCESSORS(JSRegExp, data, Object, kDataOffset)
 
 
index 8342232..aa71a96 100644 (file)
@@ -132,6 +132,7 @@ void HeapObject::HeapObjectPrint(FILE* out) {
     case JS_OBJECT_TYPE:  // fall through
     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
     case JS_ARRAY_TYPE:
+    case JS_GENERATOR_OBJECT_TYPE:
     case JS_REGEXP_TYPE:
       JSObject::cast(this)->JSObjectPrint(out);
       break;
@@ -186,6 +187,8 @@ void HeapObject::HeapObjectPrint(FILE* out) {
       break;
     case JS_ARRAY_BUFFER_TYPE:
       JSArrayBuffer::cast(this)->JSArrayBufferPrint(out);
+    case JS_TYPED_ARRAY_TYPE:
+      JSTypedArray::cast(this)->JSTypedArrayPrint(out);
 #define MAKE_STRUCT_CASE(NAME, Name, name) \
   case NAME##_TYPE:                        \
     Name::cast(this)->Name##Print(out);    \
@@ -530,6 +533,7 @@ static const char* TypeToString(InstanceType type) {
     case ODDBALL_TYPE: return "ODDBALL";
     case JS_GLOBAL_PROPERTY_CELL_TYPE: return "JS_GLOBAL_PROPERTY_CELL";
     case SHARED_FUNCTION_INFO_TYPE: return "SHARED_FUNCTION_INFO";
+    case JS_GENERATOR_OBJECT_TYPE: return "JS_GENERATOR_OBJECT";
     case JS_MODULE_TYPE: return "JS_MODULE";
     case JS_FUNCTION_TYPE: return "JS_FUNCTION";
     case CODE_TYPE: return "CODE";
@@ -807,6 +811,22 @@ void JSArrayBuffer::JSArrayBufferPrint(FILE* out) {
 }
 
 
+void JSTypedArray::JSTypedArrayPrint(FILE* out) {
+  HeapObject::PrintHeader(out, "JSTypedArray");
+  PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+  PrintF(out, " - buffer =");
+  buffer()->ShortPrint(out);
+  PrintF(out, "\n - byte_offset = ");
+  byte_offset()->ShortPrint(out);
+  PrintF(out, "\n - byte_length = ");
+  byte_length()->ShortPrint(out);
+  PrintF(out, " - length = ");
+  length()->ShortPrint(out);
+  PrintF("\n");
+  PrintElements(out);
+}
+
+
 void JSFunction::JSFunctionPrint(FILE* out) {
   HeapObject::PrintHeader(out, "Function");
   PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
index fa53562..7b5c8be 100644 (file)
@@ -136,6 +136,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
 
     case JS_OBJECT_TYPE:
     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+    case JS_GENERATOR_OBJECT_TYPE:
     case JS_MODULE_TYPE:
     case JS_VALUE_TYPE:
     case JS_DATE_TYPE:
@@ -145,6 +146,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
     case JS_BUILTINS_OBJECT_TYPE:
     case JS_MESSAGE_OBJECT_TYPE:
     case JS_ARRAY_BUFFER_TYPE:
+    case JS_TYPED_ARRAY_TYPE:
       return GetVisitorIdForSize(kVisitJSObject,
                                  kVisitJSObjectGeneric,
                                  instance_size);
index 8f03b10..33be173 100644 (file)
@@ -1290,6 +1290,10 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
       }
       break;
     }
+    case JS_GENERATOR_OBJECT_TYPE: {
+      accumulator->Add("<JS Generator>");
+      break;
+    }
     case JS_MODULE_TYPE: {
       accumulator->Add("<JS Module>");
       break;
@@ -1546,11 +1550,13 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
       break;
     case JS_OBJECT_TYPE:
     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+    case JS_GENERATOR_OBJECT_TYPE:
     case JS_MODULE_TYPE:
     case JS_VALUE_TYPE:
     case JS_DATE_TYPE:
     case JS_ARRAY_TYPE:
     case JS_ARRAY_BUFFER_TYPE:
+    case JS_TYPED_ARRAY_TYPE:
     case JS_SET_TYPE:
     case JS_MAP_TYPE:
     case JS_WEAK_MAP_TYPE:
@@ -2602,13 +2608,18 @@ MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
     return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
   }
 
-  Map* closest_map = FindClosestElementsTransition(start_map, to_kind);
+  return start_map->AsElementsKind(to_kind);
+}
+
 
-  if (closest_map->elements_kind() == to_kind) {
+MaybeObject* Map::AsElementsKind(ElementsKind kind) {
+  Map* closest_map = FindClosestElementsTransition(this, kind);
+
+  if (closest_map->elements_kind() == kind) {
     return closest_map;
   }
 
-  return AddMissingElementsTransitions(closest_map, to_kind);
+  return AddMissingElementsTransitions(closest_map, kind);
 }
 
 
@@ -3073,6 +3084,13 @@ void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object,
 }
 
 
+void JSObject::TransitionToMap(Handle<JSObject> object, Handle<Map> map) {
+  CALL_HEAP_FUNCTION_VOID(
+      object->GetIsolate(),
+      object->TransitionToMap(*map));
+}
+
+
 MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
                                             Name* name_raw,
                                             Object* value_raw,
@@ -7991,7 +8009,7 @@ MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
 void String::PrintOn(FILE* file) {
   int length = this->length();
   for (int i = 0; i < length; i++) {
-    fprintf(file, "%c", Get(i));
+    PrintF(file, "%c", Get(i));
   }
 }
 
@@ -8546,6 +8564,7 @@ bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
   // Check the basic conditions for generating inline constructor code.
   if (!FLAG_inline_new
       || !has_only_simple_this_property_assignments()
+      || is_generator()
       || this_property_assignments_count() == 0) {
     return false;
   }
@@ -9097,13 +9116,6 @@ SafepointEntry Code::GetSafepointEntry(Address pc) {
 }
 
 
-void Code::SetNoStackCheckTable() {
-  // Indicate the absence of a stack-check table by a table start after the
-  // end of the instructions.  Table start must be aligned, so round up.
-  set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
-}
-
-
 Map* Code::FindFirstMap() {
   ASSERT(is_inline_cache_stub());
   AssertNoAllocation no_allocation;
@@ -9622,18 +9634,20 @@ void Code::Disassemble(const char* name, FILE* out) {
     }
     PrintF(out, "\n");
   } else if (kind() == FUNCTION) {
-    unsigned offset = stack_check_table_offset();
-    // If there is no stack check table, the "table start" will at or after
+    unsigned offset = back_edge_table_offset();
+    // If there is no back edge table, the "table start" will be at or after
     // (due to alignment) the end of the instruction stream.
     if (static_cast<int>(offset) < instruction_size()) {
-      unsigned* address =
-          reinterpret_cast<unsigned*>(instruction_start() + offset);
-      unsigned length = address[0];
-      PrintF(out, "Stack checks (size = %u)\n", length);
-      PrintF(out, "ast_id  pc_offset\n");
-      for (unsigned i = 0; i < length; ++i) {
-        unsigned index = (2 * i) + 1;
-        PrintF(out, "%6u  %9u\n", address[index], address[index + 1]);
+      Address back_edge_cursor = instruction_start() + offset;
+      uint32_t table_length = Memory::uint32_at(back_edge_cursor);
+      PrintF(out, "Back edges (size = %u)\n", table_length);
+      PrintF(out, "ast_id  pc_offset  loop_depth\n");
+      for (uint32_t i = 0; i < table_length; ++i) {
+        uint32_t ast_id = Memory::uint32_at(back_edge_cursor);
+        uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
+        uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
+        PrintF(out, "%6u  %9u  %10u\n", ast_id, pc_offset, loop_depth);
+        back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
       }
       PrintF(out, "\n");
     }
@@ -11545,9 +11559,8 @@ MaybeObject* JSObject::GetPropertyWithInterceptor(
 }
 
 
-bool JSObject::HasRealNamedProperty(Name* key) {
+bool JSObject::HasRealNamedProperty(Isolate* isolate, Name* key) {
   // Check access rights if needed.
-  Isolate* isolate = GetIsolate();
   if (IsAccessCheckNeeded()) {
     if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
       isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
@@ -11561,73 +11574,21 @@ bool JSObject::HasRealNamedProperty(Name* key) {
 }
 
 
-bool JSObject::HasRealElementProperty(uint32_t index) {
+bool JSObject::HasRealElementProperty(Isolate* isolate, 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);
+    if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
+      isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
       return false;
     }
   }
 
-  // Handle [] on String objects.
-  if (this->IsStringObjectWithCharacterAt(index)) return true;
-
-  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());
-      return (index < length) &&
-          !FixedArray::cast(elements())->get(index)->IsTheHole();
-    }
-    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());
-      return (index < length) &&
-          !FixedDoubleArray::cast(elements())->is_the_hole(index);
-      break;
-    }
-    case EXTERNAL_PIXEL_ELEMENTS: {
-      ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
-      return index < static_cast<uint32_t>(pixels->length());
-    }
-    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());
-      return index < static_cast<uint32_t>(array->length());
-    }
-    case DICTIONARY_ELEMENTS: {
-      return element_dictionary()->FindEntry(index)
-          != SeededNumberDictionary::kNotFound;
-    }
-    case NON_STRICT_ARGUMENTS_ELEMENTS:
-      UNIMPLEMENTED();
-      break;
-  }
-  // All possibilities have been handled above already.
-  UNREACHABLE();
-  return GetHeap()->null_value();
+  return GetElementAttributeWithoutInterceptor(this, index, false) != ABSENT;
 }
 
 
-bool JSObject::HasRealNamedCallbackProperty(Name* key) {
+bool JSObject::HasRealNamedCallbackProperty(Isolate* isolate, Name* key) {
   // Check access rights if needed.
-  Isolate* isolate = GetIsolate();
   if (IsAccessCheckNeeded()) {
     if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
       isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
@@ -14128,7 +14089,7 @@ Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
     if (previous_length != 0) {
       uint8_t* previous_array =
           previous->serialized_data()->GetDataStartAddress();
-      memcpy(array, previous_array, previous_length);
+      OS::MemCopy(array, previous_array, previous_length);
       array += previous_length;
     }
     ASSERT(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
index 37be25f..898b176 100644 (file)
 //         - JSObject
 //           - JSArray
 //           - JSArrayBuffer
+//           - JSTypedArray
 //           - JSSet
 //           - JSMap
 //           - JSWeakMap
 //           - JSRegExp
 //           - JSFunction
+//           - JSGeneratorObject
 //           - JSModule
 //           - GlobalObject
 //             - JSGlobalObject
@@ -395,12 +397,14 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
   V(JS_DATE_TYPE)                                                              \
   V(JS_OBJECT_TYPE)                                                            \
   V(JS_CONTEXT_EXTENSION_OBJECT_TYPE)                                          \
+  V(JS_GENERATOR_OBJECT_TYPE)                                                  \
   V(JS_MODULE_TYPE)                                                            \
   V(JS_GLOBAL_OBJECT_TYPE)                                                     \
   V(JS_BUILTINS_OBJECT_TYPE)                                                   \
   V(JS_GLOBAL_PROXY_TYPE)                                                      \
   V(JS_ARRAY_TYPE)                                                             \
   V(JS_ARRAY_BUFFER_TYPE)                                                      \
+  V(JS_TYPED_ARRAY_TYPE)                                                       \
   V(JS_PROXY_TYPE)                                                             \
   V(JS_WEAK_MAP_TYPE)                                                          \
   V(JS_REGEXP_TYPE)                                                            \
@@ -726,12 +730,14 @@ enum InstanceType {
   JS_DATE_TYPE,
   JS_OBJECT_TYPE,
   JS_CONTEXT_EXTENSION_OBJECT_TYPE,
+  JS_GENERATOR_OBJECT_TYPE,
   JS_MODULE_TYPE,
   JS_GLOBAL_OBJECT_TYPE,
   JS_BUILTINS_OBJECT_TYPE,
   JS_GLOBAL_PROXY_TYPE,
   JS_ARRAY_TYPE,
   JS_ARRAY_BUFFER_TYPE,
+  JS_TYPED_ARRAY_TYPE,
   JS_SET_TYPE,
   JS_MAP_TYPE,
   JS_WEAK_MAP_TYPE,
@@ -953,13 +959,14 @@ class MaybeObject BASE_EMBEDDED {
   V(JSReceiver)                                \
   V(JSObject)                                  \
   V(JSContextExtensionObject)                  \
+  V(JSGeneratorObject)                         \
   V(JSModule)                                  \
   V(Map)                                       \
   V(DescriptorArray)                           \
   V(TransitionArray)                           \
   V(DeoptimizationInputData)                   \
   V(DeoptimizationOutputData)                  \
-  V(DependentCode)                            \
+  V(DependentCode)                             \
   V(TypeFeedbackCells)                         \
   V(FixedArray)                                \
   V(FixedDoubleArray)                          \
@@ -978,6 +985,7 @@ class MaybeObject BASE_EMBEDDED {
   V(Boolean)                                   \
   V(JSArray)                                   \
   V(JSArrayBuffer)                             \
+  V(JSTypedArray)                              \
   V(JSProxy)                                   \
   V(JSFunctionProxy)                           \
   V(JSSet)                                     \
@@ -1495,6 +1503,8 @@ class HeapNumber: public HeapObject {
   static const int kExponentBits = 11;
   static const int kExponentBias = 1023;
   static const int kExponentShift = 20;
+  static const int kInfinityOrNanExponent =
+      (kExponentMask >> kExponentShift) - kExponentBias;
   static const int kMantissaBitsInTopWord = 20;
   static const int kNonMantissaBitsInTopWord = 12;
 
@@ -1768,10 +1778,13 @@ class JSObject: public JSReceiver {
       Handle<Object> value,
       PropertyAttributes attributes);
 
+  static inline Handle<String> ExpectedTransitionKey(Handle<Map> map);
+  static inline Handle<Map> ExpectedTransitionTarget(Handle<Map> map);
+
   // 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<Name> key);
+  static inline Handle<Map> FindTransitionToField(Handle<Map> map,
+                                                  Handle<Name> key);
 
   inline int LastAddedFieldIndex();
 
@@ -1779,6 +1792,8 @@ class JSObject: public JSReceiver {
   // 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);
+  static void TransitionToMap(Handle<JSObject> object, Handle<Map> map);
+  inline MUST_USE_RESULT MaybeObject* TransitionToMap(Map* map);
 
   // Can cause GC.
   MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
@@ -2034,9 +2049,9 @@ class JSObject: public JSReceiver {
   inline bool HasIndexedInterceptor();
 
   // Support functions for v8 api (needed for correct interceptor behavior).
-  bool HasRealNamedProperty(Name* key);
-  bool HasRealElementProperty(uint32_t index);
-  bool HasRealNamedCallbackProperty(Name* key);
+  bool HasRealNamedProperty(Isolate* isolate, Name* key);
+  bool HasRealElementProperty(Isolate* isolate, uint32_t index);
+  bool HasRealNamedCallbackProperty(Isolate* isolate, Name* key);
 
   // Get the header size for a JSObject.  Used to compute the index of
   // internal fields as well as the number of internal fields.
@@ -4501,13 +4516,13 @@ class Code: public HeapObject {
   inline unsigned safepoint_table_offset();
   inline void set_safepoint_table_offset(unsigned offset);
 
-  // [stack_check_table_start]: For kind FUNCTION, the offset in the
-  // instruction stream where the stack check table starts.
-  inline unsigned stack_check_table_offset();
-  inline void set_stack_check_table_offset(unsigned offset);
+  // [back_edge_table_start]: For kind FUNCTION, the offset in the
+  // instruction stream where the back edge table starts.
+  inline unsigned back_edge_table_offset();
+  inline void set_back_edge_table_offset(unsigned offset);
 
-  inline bool stack_check_patched_for_osr();
-  inline void set_stack_check_patched_for_osr(bool value);
+  inline bool back_edges_patched_for_osr();
+  inline void set_back_edges_patched_for_osr(bool value);
 
   // [check type]: For kind CALL_IC, tells how to check if the
   // receiver is valid for the given call.
@@ -4538,10 +4553,6 @@ class Code: public HeapObject {
   // Get the safepoint entry for the given pc.
   SafepointEntry GetSafepointEntry(Address pc);
 
-  // Mark this code object as not having a stack check table.  Assumes kind
-  // is FUNCTION.
-  void SetNoStackCheckTable();
-
   // Find the first map in an IC stub.
   Map* FindFirstMap();
   void FindAllMaps(MapHandleList* maps);
@@ -4791,8 +4802,8 @@ class Code: public HeapObject {
       kStubMajorKeyFirstBit, kStubMajorKeyBits> {};  // NOLINT
 
   // KindSpecificFlags2 layout (FUNCTION)
-  class StackCheckTableOffsetField: public BitField<int, 0, 31> {};
-  class StackCheckPatchedForOSRField: public BitField<bool, 31, 1> {};
+  class BackEdgeTableOffsetField: public BitField<int, 0, 31> {};
+  class BackEdgesPatchedForOSRField: public BitField<bool, 31, 1> {};
 
   // Signed field cannot be encoded using the BitField class.
   static const int kArgumentsCountShift = 17;
@@ -5242,6 +5253,7 @@ class Map: public HeapObject {
       Descriptor* descriptor,
       int index,
       TransitionFlag flag);
+  MUST_USE_RESULT MaybeObject* AsElementsKind(ElementsKind kind);
   MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind,
                                                   TransitionFlag flag);
 
@@ -6251,6 +6263,40 @@ class SharedFunctionInfo: public HeapObject {
 };
 
 
+class JSGeneratorObject: public JSObject {
+ public:
+  // [function]: The function corresponding to this generator object.
+  DECL_ACCESSORS(function, JSFunction)
+
+  // [context]: The context of the suspended computation, or undefined.
+  DECL_ACCESSORS(context, Object)
+
+  // [continuation]: Offset into code of continuation.
+  inline int continuation();
+  inline void set_continuation(int continuation);
+
+  // [operands]: Saved operand stack.
+  DECL_ACCESSORS(operand_stack, FixedArray)
+
+  // Casting.
+  static inline JSGeneratorObject* cast(Object* obj);
+
+  // Dispatched behavior.
+  DECLARE_PRINTER(JSGeneratorObject)
+  DECLARE_VERIFIER(JSGeneratorObject)
+
+  // Layout description.
+  static const int kFunctionOffset = JSObject::kHeaderSize;
+  static const int kContextOffset = kFunctionOffset + kPointerSize;
+  static const int kContinuationOffset = kContextOffset + kPointerSize;
+  static const int kOperandStackOffset = kContinuationOffset + kPointerSize;
+  static const int kSize = kOperandStackOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSGeneratorObject);
+};
+
+
 // Representation for module instance objects.
 class JSModule: public JSObject {
  public:
@@ -8517,6 +8563,38 @@ class JSArrayBuffer: public JSObject {
 };
 
 
+class JSTypedArray: public JSObject {
+ public:
+  // [buffer]: ArrayBuffer that this typed array views.
+  DECL_ACCESSORS(buffer, Object)
+
+  // [byte_length]: offset of typed array in bytes.
+  DECL_ACCESSORS(byte_offset, Object)
+
+  // [byte_length]: length of typed array in bytes.
+  DECL_ACCESSORS(byte_length, Object)
+
+  // [length]: length of typed array in elements.
+  DECL_ACCESSORS(length, Object)
+
+  // Casting.
+  static inline JSTypedArray* cast(Object* obj);
+
+  // Dispatched behavior.
+  DECLARE_PRINTER(JSTypedArray)
+  DECLARE_VERIFIER(JSTypedArray)
+
+  static const int kBufferOffset = JSObject::kHeaderSize;
+  static const int kByteOffsetOffset = kBufferOffset + kPointerSize;
+  static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize;
+  static const int kLengthOffset = kByteLengthOffset + kPointerSize;
+  static const int kSize = kLengthOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray);
+};
+
+
 // Foreign describes objects pointing from JavaScript to C structures.
 // Since they cannot contain references to JS HeapObjects they can be
 // placed in old_data_space.
index d1228d2..b4ab623 100644 (file)
@@ -486,14 +486,13 @@ class Parser::BlockState BASE_EMBEDDED {
 
 Parser::FunctionState::FunctionState(Parser* parser,
                                      Scope* scope,
-                                     bool is_generator,
                                      Isolate* isolate)
     : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
       next_handler_index_(0),
       expected_property_count_(0),
-      is_generator_(is_generator),
       only_simple_this_property_assignments_(false),
       this_property_assignments_(isolate->factory()->empty_fixed_array()),
+      generator_object_variable_(NULL),
       parser_(parser),
       outer_function_state_(parser->current_function_state_),
       outer_scope_(parser->top_scope_),
@@ -537,36 +536,32 @@ Parser::FunctionState::~FunctionState() {
 // ----------------------------------------------------------------------------
 // Implementation of Parser
 
-Parser::Parser(CompilationInfo* info,
-               int parser_flags,
-               v8::Extension* extension,
-               ScriptDataImpl* pre_data)
+Parser::Parser(CompilationInfo* info)
     : isolate_(info->isolate()),
-      symbol_cache_(pre_data ? pre_data->symbol_count() : 0, info->zone()),
+      symbol_cache_(0, info->zone()),
       script_(info->script()),
       scanner_(isolate_->unicode_cache()),
       reusable_preparser_(NULL),
       top_scope_(NULL),
       current_function_state_(NULL),
       target_stack_(NULL),
-      extension_(extension),
-      pre_data_(pre_data),
+      extension_(info->extension()),
+      pre_parse_data_(NULL),
       fni_(NULL),
-      allow_natives_syntax_((parser_flags & kAllowNativesSyntax) != 0),
-      allow_lazy_((parser_flags & kAllowLazy) != 0),
-      allow_modules_((parser_flags & kAllowModules) != 0),
+      allow_natives_syntax_(false),
+      allow_lazy_(false),
+      allow_generators_(false),
       stack_overflow_(false),
       parenthesized_function_(false),
       zone_(info->zone()),
       info_(info) {
   ASSERT(!script_.is_null());
   isolate_->set_ast_node_id(0);
-  if ((parser_flags & kLanguageModeMask) == EXTENDED_MODE) {
-    scanner().SetHarmonyScoping(true);
-  }
-  if ((parser_flags & kAllowModules) != 0) {
-    scanner().SetHarmonyModules(true);
-  }
+  set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping);
+  set_allow_modules(!info->is_native() && FLAG_harmony_modules);
+  set_allow_natives_syntax(FLAG_allow_natives_syntax || info->is_native());
+  set_allow_lazy(false);  // Must be explicitly enabled.
+  set_allow_generators(FLAG_harmony_generators);
 }
 
 
@@ -617,7 +612,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
                                         ZoneScope* zone_scope) {
   ASSERT(top_scope_ == NULL);
   ASSERT(target_stack_ == NULL);
-  if (pre_data_ != NULL) pre_data_->Initialize();
+  if (pre_parse_data_ != NULL) pre_parse_data_->Initialize();
 
   Handle<String> no_name = isolate()->factory()->empty_string();
 
@@ -638,15 +633,16 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
     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 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);
 
-    bool is_generator = false;
     // Enters 'scope'.
-    FunctionState function_state(this, scope, is_generator, isolate());
+    FunctionState function_state(this, scope, isolate());
 
     top_scope_->SetLanguageMode(info->language_mode());
     ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
@@ -760,8 +756,7 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source,
       scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
                                            zone());
     }
-    bool is_generator = false;  // Top scope is not a generator.
-    FunctionState function_state(this, scope, is_generator, isolate());
+    FunctionState function_state(this, scope, isolate());
     ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode());
     ASSERT(scope->language_mode() != EXTENDED_MODE ||
            info()->is_extended_mode());
@@ -801,8 +796,8 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source,
 
 Handle<String> Parser::GetSymbol(bool* ok) {
   int symbol_id = -1;
-  if (pre_data() != NULL) {
-    symbol_id = pre_data()->GetSymbolIdentifier();
+  if (pre_parse_data() != NULL) {
+    symbol_id = pre_parse_data()->GetSymbolIdentifier();
   }
   return LookupSymbol(symbol_id);
 }
@@ -1092,7 +1087,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
             mode_ = PARSE_EAGERLY;
           }
           // TODO(ES6): Fix entering extended mode, once it is specified.
-          top_scope_->SetLanguageMode(FLAG_harmony_scoping
+          top_scope_->SetLanguageMode(allow_harmony_scoping()
                                       ? EXTENDED_MODE : STRICT_MODE);
           // "use strict" is the only directive for now.
           directive_prologue = false;
@@ -1910,7 +1905,7 @@ Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
   //      '{' FunctionBody '}'
   Expect(Token::FUNCTION, CHECK_OK);
   int function_token_position = scanner().location().beg_pos;
-  bool is_generator = FLAG_harmony_generators && Check(Token::MUL);
+  bool is_generator = allow_generators() && Check(Token::MUL);
   bool is_strict_reserved = false;
   Handle<String> name = ParseIdentifierOrStrictReservedWord(
       &is_strict_reserved, CHECK_OK);
@@ -3105,8 +3100,11 @@ Expression* Parser::ParseYieldExpression(bool* ok) {
   int position = scanner().peek_location().beg_pos;
   Expect(Token::YIELD, CHECK_OK);
   bool is_yield_star = Check(Token::MUL);
+  Expression* generator_object = factory()->NewVariableProxy(
+      current_function_state_->generator_object_variable());
   Expression* expression = ParseAssignmentExpression(false, CHECK_OK);
-  return factory()->NewYield(expression, is_yield_star, position);
+  return factory()->NewYield(generator_object, expression, is_yield_star,
+                             position);
 }
 
 
@@ -3486,7 +3484,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
   if (peek() == Token::FUNCTION) {
     Expect(Token::FUNCTION, CHECK_OK);
     int function_token_position = scanner().location().beg_pos;
-    bool is_generator = FLAG_harmony_generators && Check(Token::MUL);
+    bool is_generator = allow_generators() && Check(Token::MUL);
     Handle<String> name;
     bool is_strict_reserved_name = false;
     if (peek_any_identifier()) {
@@ -3702,7 +3700,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
       break;
 
     case Token::MOD:
-      if (allow_natives_syntax_ || extension_ != NULL) {
+      if (allow_natives_syntax() || extension_ != NULL) {
         result = ParseV8Intrinsic(CHECK_OK);
         break;
       }
@@ -4391,9 +4389,25 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
       : FunctionLiteral::kNotGenerator;
   AstProperties ast_properties;
   // Parse function body.
-  { FunctionState function_state(this, scope, is_generator, isolate());
+  { FunctionState function_state(this, scope, isolate());
     top_scope_->SetScopeName(function_name);
 
+    if (is_generator) {
+      // For generators, allocating variables in contexts is currently a win
+      // because it minimizes the work needed to suspend and resume an
+      // activation.
+      top_scope_->ForceContextAllocation();
+
+      // Calling a generator returns a generator object.  That object is stored
+      // in a temporary variable, a definition that is used by "yield"
+      // expressions.  Presence of a variable for the generator object in the
+      // FunctionState indicates that this function is a generator.
+      Handle<String> tempname = isolate()->factory()->InternalizeOneByteString(
+          STATIC_ASCII_VECTOR(".generator_object"));
+      Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
+      function_state.set_generator_object_variable(temp);
+    }
+
     //  FormalParameterList ::
     //    '(' (Identifier)*[','] ')'
     Expect(Token::LPAREN, CHECK_OK);
@@ -4475,11 +4489,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
     if (is_lazily_compiled) {
       int function_block_pos = scanner().location().beg_pos;
       FunctionEntry entry;
-      if (pre_data_ != NULL) {
-        // If we have pre_data_, we use it to skip parsing the function body.
-        // the preparser data contains the information we need to construct the
-        // lazy function.
-        entry = pre_data()->GetFunctionEntry(function_block_pos);
+      if (pre_parse_data_ != NULL) {
+        // If we have pre_parse_data_, we use it to skip parsing the function
+        // body.  The preparser data contains the information we need to
+        // construct the lazy function.
+        entry = pre_parse_data()->GetFunctionEntry(function_block_pos);
         if (entry.is_valid()) {
           if (entry.end_pos() <= function_block_pos) {
             // End position greater than end of stream is safe, and hard
@@ -4550,6 +4564,26 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
                                      RelocInfo::kNoPosition)),
                                      zone());
       }
+
+      // For generators, allocate and yield an iterator on function entry.
+      if (is_generator) {
+        ZoneList<Expression*>* arguments =
+            new(zone()) ZoneList<Expression*>(0, zone());
+        CallRuntime* allocation = factory()->NewCallRuntime(
+            isolate()->factory()->empty_string(),
+            Runtime::FunctionForId(Runtime::kCreateJSGeneratorObject),
+            arguments);
+        VariableProxy* init_proxy = factory()->NewVariableProxy(
+            current_function_state_->generator_object_variable());
+        Assignment* assignment = factory()->NewAssignment(
+            Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition);
+        VariableProxy* get_proxy = factory()->NewVariableProxy(
+            current_function_state_->generator_object_variable());
+        Yield* yield = factory()->NewYield(
+            get_proxy, assignment, false, RelocInfo::kNoPosition);
+        body->Add(factory()->NewExpressionStatement(yield), zone());
+      }
+
       ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK);
 
       materialized_literal_count = function_state.materialized_literal_count();
@@ -4646,14 +4680,14 @@ preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
 
   if (reusable_preparser_ == NULL) {
     intptr_t stack_limit = isolate()->stack_guard()->real_climit();
-    bool do_allow_lazy = true;
     reusable_preparser_ = new preparser::PreParser(&scanner_,
                                                    NULL,
-                                                   stack_limit,
-                                                   do_allow_lazy,
-                                                   allow_natives_syntax_,
-                                                   allow_modules_,
-                                                   FLAG_harmony_generators);
+                                                   stack_limit);
+    reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping());
+    reusable_preparser_->set_allow_modules(allow_modules());
+    reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax());
+    reusable_preparser_->set_allow_lazy(true);
+    reusable_preparser_->set_allow_generators(allow_generators());
   }
   preparser::PreParser::PreParseResult result =
       reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
@@ -5900,20 +5934,18 @@ int ScriptDataImpl::ReadNumber(byte** source) {
 
 
 // Create a Scanner for the preparser to use as input, and preparse the source.
-static ScriptDataImpl* DoPreParse(Utf16CharacterStream* source,
-                                  int flags,
-                                  ParserRecorder* recorder) {
+ScriptDataImpl* PreParserApi::PreParse(Utf16CharacterStream* source) {
+  CompleteParserRecorder recorder;
   Isolate* isolate = Isolate::Current();
   HistogramTimerScope timer(isolate->counters()->pre_parse());
   Scanner scanner(isolate->unicode_cache());
-  scanner.SetHarmonyScoping(FLAG_harmony_scoping);
-  scanner.Initialize(source);
   intptr_t stack_limit = isolate->stack_guard()->real_climit();
-  preparser::PreParser::PreParseResult result =
-      preparser::PreParser::PreParseProgram(&scanner,
-                                            recorder,
-                                            flags,
-                                            stack_limit);
+  preparser::PreParser preparser(&scanner, &recorder, stack_limit);
+  preparser.set_allow_lazy(true);
+  preparser.set_allow_generators(FLAG_harmony_generators);
+  preparser.set_allow_harmony_scoping(FLAG_harmony_scoping);
+  scanner.Initialize(source);
+  preparser::PreParser::PreParseResult result = preparser.PreParseProgram();
   if (result == preparser::PreParser::kPreParseStackOverflow) {
     isolate->StackOverflow();
     return NULL;
@@ -5921,26 +5953,11 @@ static ScriptDataImpl* DoPreParse(Utf16CharacterStream* source,
 
   // Extract the accumulated data from the recorder as a single
   // contiguous vector that we are responsible for disposing.
-  Vector<unsigned> store = recorder->ExtractData();
+  Vector<unsigned> store = recorder.ExtractData();
   return new ScriptDataImpl(store);
 }
 
 
-ScriptDataImpl* ParserApi::PreParse(Utf16CharacterStream* source,
-                                    v8::Extension* extension,
-                                    int flags) {
-  Handle<Script> no_script;
-  if (FLAG_lazy && (extension == NULL)) {
-    flags |= kAllowLazy;
-  }
-  if (FLAG_harmony_generators) {
-    flags |= kAllowGenerators;
-  }
-  CompleteParserRecorder recorder;
-  return DoPreParse(source, flags, &recorder);
-}
-
-
 bool RegExpParser::ParseRegExp(FlatStringReader* input,
                                bool multiline,
                                RegExpCompileData* result,
@@ -5964,48 +5981,35 @@ bool RegExpParser::ParseRegExp(FlatStringReader* input,
 }
 
 
-bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) {
-  ASSERT(info->function() == NULL);
+bool Parser::Parse() {
+  ASSERT(info()->function() == NULL);
   FunctionLiteral* result = NULL;
-  ASSERT((parsing_flags & kLanguageModeMask) == CLASSIC_MODE);
-  if (!info->is_native() && FLAG_harmony_scoping) {
-    // Harmony scoping is requested.
-    parsing_flags |= EXTENDED_MODE;
-  }
-  if (!info->is_native() && FLAG_harmony_modules) {
-    parsing_flags |= kAllowModules;
-  }
-  if (FLAG_allow_natives_syntax || info->is_native()) {
-    // We require %identifier(..) syntax.
-    parsing_flags |= kAllowNativesSyntax;
-  }
-  if (info->is_lazy()) {
-    ASSERT(!info->is_eval());
-    Parser parser(info, parsing_flags, NULL, NULL);
-    if (info->shared_info()->is_function()) {
-      result = parser.ParseLazy();
+  if (info()->is_lazy()) {
+    ASSERT(!info()->is_eval());
+    if (info()->shared_info()->is_function()) {
+      result = ParseLazy();
     } else {
-      result = parser.ParseProgram();
+      result = ParseProgram();
     }
   } else {
-    ScriptDataImpl* pre_data = info->pre_parse_data();
-    Parser parser(info, parsing_flags, info->extension(), pre_data);
-    if (pre_data != NULL && pre_data->has_error()) {
-      Scanner::Location loc = pre_data->MessageLocation();
-      const char* message = pre_data->BuildMessage();
-      Vector<const char*> args = pre_data->BuildArgs();
-      parser.ReportMessageAt(loc, message, args);
+    ScriptDataImpl* pre_parse_data = info()->pre_parse_data();
+    set_pre_parse_data(pre_parse_data);
+    if (pre_parse_data != NULL && pre_parse_data->has_error()) {
+      Scanner::Location loc = pre_parse_data->MessageLocation();
+      const char* message = pre_parse_data->BuildMessage();
+      Vector<const char*> args = pre_parse_data->BuildArgs();
+      ReportMessageAt(loc, message, args);
       DeleteArray(message);
       for (int i = 0; i < args.length(); i++) {
         DeleteArray(args[i]);
       }
       DeleteArray(args.start());
-      ASSERT(info->isolate()->has_pending_exception());
+      ASSERT(info()->isolate()->has_pending_exception());
     } else {
-      result = parser.ParseProgram();
+      result = ParseProgram();
     }
   }
-  info->SetFunction(result);
+  info()->SetFunction(result);
   return (result != NULL);
 }
 
index fc4aba2..acf47bb 100644 (file)
@@ -163,19 +163,17 @@ class ScriptDataImpl : public ScriptData {
 };
 
 
-class ParserApi {
+class PreParserApi {
  public:
-  // Parses the source code represented by the compilation info and sets its
-  // function literal.  Returns false (and deallocates any allocated AST
-  // nodes) if parsing failed.
-  static bool Parse(CompilationInfo* info, int flags);
-
-  // Generic preparser generating full preparse data.
-  static ScriptDataImpl* PreParse(Utf16CharacterStream* source,
-                                  v8::Extension* extension,
-                                  int flags);
+  // Pre-parse a character stream and return full preparse data.
+  //
+  // This interface is here instead of in preparser.h because it instantiates a
+  // preparser recorder object that is suited to the parser's purposes.  Also,
+  // the preparser doesn't know about ScriptDataImpl.
+  static ScriptDataImpl* PreParse(Utf16CharacterStream* source);
 };
 
+
 // ----------------------------------------------------------------------------
 // REGEXP PARSING
 
@@ -295,7 +293,7 @@ class RegExpBuilder: public ZoneObject {
 };
 
 
-class RegExpParser {
+class RegExpParser BASE_EMBEDDED {
  public:
   RegExpParser(FlatStringReader* in,
                Handle<String>* error,
@@ -425,20 +423,36 @@ class RegExpParser {
 // Forward declaration.
 class SingletonLogger;
 
-class Parser {
+class Parser BASE_EMBEDDED {
  public:
-  Parser(CompilationInfo* info,
-         int parsing_flags,  // Combination of ParsingFlags
-         v8::Extension* extension,
-         ScriptDataImpl* pre_data);
-  virtual ~Parser() {
+  explicit Parser(CompilationInfo* info);
+  ~Parser() {
     delete reusable_preparser_;
     reusable_preparser_ = NULL;
   }
 
+  bool allow_natives_syntax() const { return allow_natives_syntax_; }
+  bool allow_lazy() const { return allow_lazy_; }
+  bool allow_modules() { return scanner().HarmonyModules(); }
+  bool allow_harmony_scoping() { return scanner().HarmonyScoping(); }
+  bool allow_generators() const { return allow_generators_; }
+
+  void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; }
+  void set_allow_lazy(bool allow) { allow_lazy_ = allow; }
+  void set_allow_modules(bool allow) { scanner().SetHarmonyModules(allow); }
+  void set_allow_harmony_scoping(bool allow) {
+    scanner().SetHarmonyScoping(allow);
+  }
+  void set_allow_generators(bool allow) { allow_generators_ = allow; }
+
+  // Parses the source code represented by the compilation info and sets its
+  // function literal.  Returns false (and deallocates any allocated AST
+  // nodes) if parsing failed.
+  static bool Parse(CompilationInfo* info) { return Parser(info).Parse(); }
+  bool Parse();
+
   // Returns NULL if parsing failed.
   FunctionLiteral* ParseProgram();
-  FunctionLiteral* ParseLazy();
 
   void ReportMessageAt(Scanner::Location loc,
                        const char* message,
@@ -474,7 +488,6 @@ class Parser {
    public:
     FunctionState(Parser* parser,
                   Scope* scope,
-                  bool is_generator,
                   Isolate* isolate);
     ~FunctionState();
 
@@ -505,7 +518,17 @@ class Parser {
     void AddProperty() { expected_property_count_++; }
     int expected_property_count() { return expected_property_count_; }
 
-    bool is_generator() const { return is_generator_; }
+    void set_generator_object_variable(Variable *variable) {
+      ASSERT(variable != NULL);
+      ASSERT(!is_generator());
+      generator_object_variable_ = variable;
+    }
+    Variable* generator_object_variable() const {
+      return generator_object_variable_;
+    }
+    bool is_generator() const {
+      return generator_object_variable_ != NULL;
+    }
 
     AstNodeFactory<AstConstructionVisitor>* factory() { return &factory_; }
 
@@ -521,14 +544,16 @@ class Parser {
     // Properties count estimation.
     int expected_property_count_;
 
-    // Indicates that this function is a generator.
-    bool is_generator_;
-
     // Keeps track of assignments to properties of this. Used for
     // optimizing constructors.
     bool only_simple_this_property_assignments_;
     Handle<FixedArray> this_property_assignments_;
 
+    // For generators, the variable that holds the generator object.  This
+    // variable is used by yield expressions and return statements.  NULL
+    // indicates that this function is not a generator.
+    Variable* generator_object_variable_;
+
     Parser* parser_;
     FunctionState* outer_function_state_;
     Scope* outer_scope_;
@@ -552,6 +577,7 @@ class Parser {
     Mode old_mode_;
   };
 
+  FunctionLiteral* ParseLazy();
   FunctionLiteral* ParseLazy(Utf16CharacterStream* source,
                              ZoneScope* zone_scope);
 
@@ -570,10 +596,15 @@ class Parser {
   void ReportMessage(const char* message, Vector<const char*> args);
   void ReportMessage(const char* message, Vector<Handle<String> > args);
 
+  void set_pre_parse_data(ScriptDataImpl *data) {
+    pre_parse_data_ = data;
+    symbol_cache_.Initialize(data ? data->symbol_count() : 0, zone());
+  }
+
   bool inside_with() const { return top_scope_->inside_with(); }
   Scanner& scanner()  { return scanner_; }
   Mode mode() const { return mode_; }
-  ScriptDataImpl* pre_data() const { return pre_data_; }
+  ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
   bool is_extended_mode() {
     ASSERT(top_scope_ != NULL);
     return top_scope_->is_extended_mode();
@@ -835,13 +866,13 @@ class Parser {
   FunctionState* current_function_state_;
   Target* target_stack_;  // for break, continue statements
   v8::Extension* extension_;
-  ScriptDataImpl* pre_data_;
+  ScriptDataImpl* pre_parse_data_;
   FuncNameInferrer* fni_;
 
   Mode mode_;
   bool allow_natives_syntax_;
   bool allow_lazy_;
-  bool allow_modules_;
+  bool allow_generators_;
   bool stack_overflow_;
   // If true, the next (and immediately following) function literal is
   // preceded by a parenthesis.
index 67c389e..6804af8 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "platform-posix.h"
 #include "platform.h"
+#include "simulator.h"
 #include "v8threads.h"
 #include "vm-state-inl.h"
 #include "win32-headers.h"
@@ -193,6 +194,11 @@ void OS::DebugBreak() {
 }
 
 
+void OS::DumpBacktrace() {
+  // Currently unsupported.
+}
+
+
 class PosixMemoryMappedFile : public OS::MemoryMappedFile {
  public:
   PosixMemoryMappedFile(FILE* file, void* memory, int size)
@@ -318,38 +324,127 @@ int OS::StackWalk(Vector<OS::StackFrame> frames) {
 // This causes VirtualMemory::Commit to not always commit the memory region
 // specified.
 
-bool VirtualMemory::IsReserved() {
-  return address_ != NULL;
+static void* GetRandomAddr() {
+  Isolate* isolate = Isolate::UncheckedCurrent();
+  // Note that the current isolate isn't set up in a call path via
+  // CpuFeatures::Probe. We don't care about randomization in this case because
+  // the code page is immediately freed.
+  if (isolate != NULL) {
+    // The address range used to randomize RWX allocations in OS::Allocate
+    // Try not to map pages into the default range that windows loads DLLs
+    // Use a multiple of 64k to prevent committing unused memory.
+    // Note: This does not guarantee RWX regions will be within the
+    // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
+#ifdef V8_HOST_ARCH_64_BIT
+    static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
+    static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
+#else
+    static const intptr_t kAllocationRandomAddressMin = 0x04000000;
+    static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
+#endif
+    uintptr_t address = (V8::RandomPrivate(isolate) << kPageSizeBits)
+        | kAllocationRandomAddressMin;
+    address &= kAllocationRandomAddressMax;
+    return reinterpret_cast<void *>(address);
+  }
+  return NULL;
+}
+
+
+static void* RandomizedVirtualAlloc(size_t size, int action, int protection) {
+  LPVOID base = NULL;
+
+  if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) {
+    // For exectutable pages try and randomize the allocation address
+    for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
+      base = VirtualAlloc(GetRandomAddr(), size, action, protection);
+    }
+  }
+
+  // After three attempts give up and let the OS find an address to use.
+  if (base == NULL) base = VirtualAlloc(NULL, size, action, protection);
+
+  return base;
 }
 
 
-VirtualMemory::VirtualMemory(size_t size) {
-  address_ = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
-  size_ = size;
+VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
+
+
+VirtualMemory::VirtualMemory(size_t size)
+    : address_(ReserveRegion(size)), size_(size) { }
+
+
+VirtualMemory::VirtualMemory(size_t size, size_t alignment)
+    : address_(NULL), size_(0) {
+  ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
+  size_t request_size = RoundUp(size + alignment,
+                                static_cast<intptr_t>(OS::AllocateAlignment()));
+  void* address = ReserveRegion(request_size);
+  if (address == NULL) return;
+  Address base = RoundUp(static_cast<Address>(address), alignment);
+  // Try reducing the size by freeing and then reallocating a specific area.
+  bool result = ReleaseRegion(address, request_size);
+  USE(result);
+  ASSERT(result);
+  address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
+  if (address != NULL) {
+    request_size = size;
+    ASSERT(base == static_cast<Address>(address));
+  } else {
+    // Resizing failed, just go with a bigger area.
+    address = ReserveRegion(request_size);
+    if (address == NULL) return;
+  }
+  address_ = address;
+  size_ = request_size;
 }
 
 
 VirtualMemory::~VirtualMemory() {
   if (IsReserved()) {
-    if (0 == VirtualFree(address(), 0, MEM_RELEASE)) address_ = NULL;
+    bool result = ReleaseRegion(address_, size_);
+    ASSERT(result);
+    USE(result);
   }
 }
 
 
-bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
-  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
-  if (NULL == VirtualAlloc(address, size, MEM_COMMIT, prot)) {
-    return false;
-  }
+bool VirtualMemory::IsReserved() {
+  return address_ != NULL;
+}
 
-  UpdateAllocatedSpaceLimits(address, static_cast<int>(size));
-  return true;
+
+void VirtualMemory::Reset() {
+  address_ = NULL;
+  size_ = 0;
+}
+
+
+bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
+  return CommitRegion(address, size, is_executable);
 }
 
 
 bool VirtualMemory::Uncommit(void* address, size_t size) {
   ASSERT(IsReserved());
-  return VirtualFree(address, size, MEM_DECOMMIT) != false;
+  return UncommitRegion(address, size);
+}
+
+
+void* VirtualMemory::ReserveRegion(size_t size) {
+  return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
+}
+
+
+bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
+  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
+  if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) {
+    return false;
+  }
+
+  UpdateAllocatedSpaceLimits(base, static_cast<int>(size));
+  return true;
 }
 
 
@@ -364,6 +459,16 @@ bool VirtualMemory::Guard(void* address) {
 }
 
 
+bool VirtualMemory::UncommitRegion(void* base, size_t size) {
+  return VirtualFree(base, size, MEM_DECOMMIT) != 0;
+}
+
+
+bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
+  return VirtualFree(base, 0, MEM_RELEASE) != 0;
+}
+
+
 bool VirtualMemory::HasLazyCommits() {
   // TODO(alph): implement for the platform.
   return false;
@@ -377,11 +482,10 @@ class Thread::PlatformData : public Malloced {
 };
 
 
-
-
 Thread::Thread(const Options& options)
     : data_(new PlatformData()),
-      stack_size_(options.stack_size()) {
+      stack_size_(options.stack_size()),
+      start_semaphore_(NULL) {
   set_name(options.name());
 }
 
@@ -398,7 +502,7 @@ static void* ThreadEntry(void* arg) {
   // one) so we initialize it here too.
   thread->data()->thread_ = pthread_self();
   ASSERT(thread->data()->thread_ != kNoThread);
-  thread->Run();
+  thread->NotifyStartedAndRun();
   return NULL;
 }
 
@@ -591,143 +695,6 @@ Semaphore* OS::CreateSemaphore(int count) {
 }
 
 
-// ----------------------------------------------------------------------------
-// Cygwin profiler support.
-//
-// On Cygwin we use the same sampler implementation as on win32.
-
-class Sampler::PlatformData : public Malloced {
- public:
-  // Get a handle to the calling thread. This is the thread that we are
-  // going to profile. We need to make a copy of the handle because we are
-  // going to use it in the sampler thread. Using GetThreadHandle() will
-  // not work in this case. We're using OpenThread because DuplicateHandle
-  // for some reason doesn't work in Chrome's sandbox.
-  PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
-                                               THREAD_SUSPEND_RESUME |
-                                               THREAD_QUERY_INFORMATION,
-                                               false,
-                                               GetCurrentThreadId())) {}
-
-  ~PlatformData() {
-    if (profiled_thread_ != NULL) {
-      CloseHandle(profiled_thread_);
-      profiled_thread_ = NULL;
-    }
-  }
-
-  HANDLE profiled_thread() { return profiled_thread_; }
-
- private:
-  HANDLE profiled_thread_;
-};
-
-
-class SamplerThread : public Thread {
- public:
-  static const int kSamplerThreadStackSize = 64 * KB;
-
-  explicit SamplerThread(int interval)
-      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      instance_ = new SamplerThread(sampler->interval());
-      instance_->Start();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
-      delete instance_;
-      instance_ = NULL;
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      } else {
-        if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
-      }
-      OS::Sleep(interval_);
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
-    if (!sampler->isolate()->IsInitialized()) return;
-    if (!sampler->IsProfiling()) return;
-    SamplerThread* sampler_thread =
-        reinterpret_cast<SamplerThread*>(raw_sampler_thread);
-    sampler_thread->SampleContext(sampler);
-  }
-
-  void SampleContext(Sampler* sampler) {
-    HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
-    if (profiled_thread == NULL) return;
-
-    // Context used for sampling the register state of the profiled thread.
-    CONTEXT context;
-    memset(&context, 0, sizeof(context));
-
-    Isolate* isolate = sampler->isolate();
-    TickSample sample_obj;
-    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-    if (sample == NULL) sample = &sample_obj;
-
-    static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
-    if (SuspendThread(profiled_thread) == kSuspendFailed) return;
-    sample->state = isolate->current_vm_state();
-
-    context.ContextFlags = CONTEXT_FULL;
-    if (GetThreadContext(profiled_thread, &context) != 0) {
-#if V8_HOST_ARCH_X64
-      sample->pc = reinterpret_cast<Address>(context.Rip);
-      sample->sp = reinterpret_cast<Address>(context.Rsp);
-      sample->fp = reinterpret_cast<Address>(context.Rbp);
-#else
-      sample->pc = reinterpret_cast<Address>(context.Eip);
-      sample->sp = reinterpret_cast<Address>(context.Esp);
-      sample->fp = reinterpret_cast<Address>(context.Ebp);
-#endif
-      sampler->SampleStack(sample);
-      sampler->Tick(sample);
-    }
-    ResumeThread(profiled_thread);
-  }
-
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SamplerThread* instance_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
 void OS::SetUp() {
   // Seed the random number generator.
   // Convert the current time to a 64-bit integer first, before converting it
@@ -737,44 +704,12 @@ void OS::SetUp() {
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-  SamplerThread::SetUp();
 }
 
 
 void OS::TearDown() {
-  SamplerThread::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SamplerThread::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
-
 } }  // namespace v8::internal
index 14f7171..735f078 100644 (file)
@@ -357,12 +357,12 @@ int OS::StackWalk(Vector<OS::StackFrame> frames) {
 static const int kMmapFd = -1;
 static const int kMmapFdOffset = 0;
 
+
 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
 
-VirtualMemory::VirtualMemory(size_t size) {
-  address_ = ReserveRegion(size);
-  size_ = size;
-}
+
+VirtualMemory::VirtualMemory(size_t size)
+    : address_(ReserveRegion(size)), size_(size) { }
 
 
 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
@@ -500,7 +500,8 @@ class Thread::PlatformData : public Malloced {
 
 Thread::Thread(const Options& options)
     : data_(new PlatformData),
-      stack_size_(options.stack_size()) {
+      stack_size_(options.stack_size()),
+      start_semaphore_(NULL) {
   set_name(options.name());
 }
 
@@ -517,7 +518,7 @@ static void* ThreadEntry(void* arg) {
   // one) so we initialize it here too.
   thread->data()->thread_ = pthread_self();
   ASSERT(thread->data()->thread_ != kNoThread);
-  thread->Run();
+  thread->NotifyStartedAndRun();
   return NULL;
 }
 
@@ -681,174 +682,6 @@ Semaphore* OS::CreateSemaphore(int count) {
 }
 
 
-static pthread_t GetThreadID() {
-  pthread_t thread_id = pthread_self();
-  return thread_id;
-}
-
-
-class Sampler::PlatformData : public Malloced {
- public:
-  PlatformData() : vm_tid_(GetThreadID()) {}
-
-  pthread_t vm_tid() const { return vm_tid_; }
-
- private:
-  pthread_t vm_tid_;
-};
-
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
-  USE(info);
-  if (signal != SIGPROF) return;
-  Isolate* isolate = Isolate::UncheckedCurrent();
-  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
-    // We require a fully initialized and entered isolate.
-    return;
-  }
-  if (v8::Locker::IsActive() &&
-      !isolate->thread_manager()->IsLockedByCurrentThread()) {
-    return;
-  }
-
-  Sampler* sampler = isolate->logger()->sampler();
-  if (sampler == NULL || !sampler->IsActive()) return;
-
-  TickSample sample_obj;
-  TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-  if (sample == NULL) sample = &sample_obj;
-
-  // Extracting the sample from the context is extremely machine dependent.
-  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
-  mcontext_t& mcontext = ucontext->uc_mcontext;
-  sample->state = isolate->current_vm_state();
-#if V8_HOST_ARCH_IA32
-  sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
-  sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
-  sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
-#elif V8_HOST_ARCH_X64
-  sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
-  sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
-  sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
-#elif V8_HOST_ARCH_ARM
-  sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
-  sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
-  sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
-#endif
-  sampler->SampleStack(sample);
-  sampler->Tick(sample);
-}
-
-
-class SignalSender : public Thread {
- public:
-  static const int kSignalSenderStackSize = 64 * KB;
-
-  explicit SignalSender(int interval)
-      : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      // Install a signal handler.
-      struct sigaction sa;
-      sa.sa_sigaction = ProfilerSignalHandler;
-      sigemptyset(&sa.sa_mask);
-      sa.sa_flags = SA_RESTART | SA_SIGINFO;
-      signal_handler_installed_ =
-          (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
-
-      // Start a thread that sends SIGPROF signal to VM threads.
-      instance_ = new SignalSender(sampler->interval());
-      instance_->Start();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
-      delete instance_;
-      instance_ = NULL;
-
-      // Restore the old signal handler.
-      if (signal_handler_installed_) {
-        sigaction(SIGPROF, &old_signal_handler_, 0);
-        signal_handler_installed_ = false;
-      }
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      } else {
-        if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
-      }
-      Sleep();  // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
-    if (!sampler->IsProfiling()) return;
-    SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
-    sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
-  }
-
-  void SendProfilingSignal(pthread_t tid) {
-    if (!signal_handler_installed_) return;
-    pthread_kill(tid, SIGPROF);
-  }
-
-  void Sleep() {
-    // Convert ms to us and subtract 100 us to compensate delays
-    // occuring during signal delivery.
-    useconds_t interval = interval_ * 1000 - 100;
-    int result = usleep(interval);
-#ifdef DEBUG
-    if (result != 0 && errno != EINTR) {
-      fprintf(stderr,
-              "SignalSender usleep error; interval = %u, errno = %d\n",
-              interval,
-              errno);
-      ASSERT(result == 0 || errno == EINTR);
-    }
-#endif
-    USE(result);
-  }
-
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SignalSender* instance_;
-  static bool signal_handler_installed_;
-  static struct sigaction old_signal_handler_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SignalSender);
-};
-
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
-
-
 void OS::SetUp() {
   // Seed the random number generator.
   // Convert the current time to a 64-bit integer first, before converting it
@@ -858,44 +691,12 @@ void OS::SetUp() {
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-  SignalSender::SetUp();
 }
 
 
 void OS::TearDown() {
-  SignalSender::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SignalSender::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SignalSender::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
-
 } }  // namespace v8::internal
index 1f9cde1..38f7c67 100644 (file)
@@ -38,7 +38,7 @@
 #include <sys/types.h>
 #include <stdlib.h>
 
-#if defined(__GLIBC__)
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
 #include <execinfo.h>
 #include <cxxabi.h>
 #endif
@@ -51,9 +51,6 @@
 #include <sys/stat.h>   // open
 #include <fcntl.h>      // open
 #include <unistd.h>     // sysconf
-#if defined(__GLIBC__) && !defined(__UCLIBC__)
-#include <execinfo.h>   // backtrace, backtrace_symbols
-#endif  // defined(__GLIBC__) && !defined(__UCLIBC__)
 #include <strings.h>    // index
 #include <errno.h>
 #include <stdarg.h>
@@ -146,9 +143,6 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) {
   // facility is universally available on the ARM architectures,
   // so it's up to individual OSes to provide such.
   switch (feature) {
-    case VFP2:
-      search_string = "vfp";
-      break;
     case VFP3:
       search_string = "vfpv3";
       break;
@@ -272,8 +266,10 @@ bool OS::MipsCpuHasFeature(CpuFeature feature) {
   FILE* f = NULL;
   const char* what = search_string;
 
-  if (NULL == (f = fopen(file_name, "r")))
+  if (NULL == (f = fopen(file_name, "r"))) {
+    OS::PrintError("Failed to open /proc/cpuinfo\n");
     return false;
+  }
 
   int k;
   while (EOF != (k = fgetc(f))) {
@@ -428,6 +424,8 @@ void OS::DebugBreak() {
 # endif
 #elif defined(__mips__)
   asm("break");
+#elif defined(__native_client__)
+  asm("hlt");
 #else
   asm("int $3");
 #endif
@@ -435,7 +433,7 @@ void OS::DebugBreak() {
 
 
 void OS::DumpBacktrace() {
-#if defined(__GLIBC__)
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
   void* trace[100];
   int size = backtrace(trace, ARRAY_SIZE(trace));
   char** symbols = backtrace_symbols(trace, size);
@@ -644,12 +642,12 @@ int OS::StackWalk(Vector<OS::StackFrame> frames) {
 static const int kMmapFd = -1;
 static const int kMmapFdOffset = 0;
 
+
 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
 
-VirtualMemory::VirtualMemory(size_t size) {
-  address_ = ReserveRegion(size);
-  size_ = size;
-}
+
+VirtualMemory::VirtualMemory(size_t size)
+    : address_(ReserveRegion(size)), size_(size) { }
 
 
 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
@@ -787,7 +785,8 @@ class Thread::PlatformData : public Malloced {
 
 Thread::Thread(const Options& options)
     : data_(new PlatformData()),
-      stack_size_(options.stack_size()) {
+      stack_size_(options.stack_size()),
+      start_semaphore_(NULL) {
   set_name(options.name());
 }
 
@@ -809,7 +808,7 @@ static void* ThreadEntry(void* arg) {
 #endif
   thread->data()->thread_ = pthread_self();
   ASSERT(thread->data()->thread_ != kNoThread);
-  thread->Run();
+  thread->NotifyStartedAndRun();
   return NULL;
 }
 
@@ -822,12 +821,16 @@ void Thread::set_name(const char* name) {
 
 void Thread::Start() {
   pthread_attr_t* attr_ptr = NULL;
+#if defined(__native_client__)
+  // use default stack size.
+#else
   pthread_attr_t attr;
   if (stack_size_ > 0) {
     pthread_attr_init(&attr);
     pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
     attr_ptr = &attr;
   }
+#endif
   int result = pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
   CHECK_EQ(0, result);
   ASSERT(data_->thread_ != kNoThread);
@@ -988,349 +991,17 @@ Semaphore* OS::CreateSemaphore(int count) {
 }
 
 
-#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
-
-// Not all versions of Android's C library provide ucontext_t.
-// Detect this and provide custom but compatible definitions. Note that these
-// follow the GLibc naming convention to access register values from
-// mcontext_t.
-//
-// See http://code.google.com/p/android/issues/detail?id=34784
-
-#if defined(__arm__)
-
-typedef struct sigcontext mcontext_t;
-
-typedef struct ucontext {
-  uint32_t uc_flags;
-  struct ucontext* uc_link;
-  stack_t uc_stack;
-  mcontext_t uc_mcontext;
-  // Other fields are not used by V8, don't define them here.
-} ucontext_t;
-
-#elif defined(__mips__)
-// MIPS version of sigcontext, for Android bionic.
-typedef struct {
-  uint32_t regmask;
-  uint32_t status;
-  uint64_t pc;
-  uint64_t gregs[32];
-  uint64_t fpregs[32];
-  uint32_t acx;
-  uint32_t fpc_csr;
-  uint32_t fpc_eir;
-  uint32_t used_math;
-  uint32_t dsp;
-  uint64_t mdhi;
-  uint64_t mdlo;
-  uint32_t hi1;
-  uint32_t lo1;
-  uint32_t hi2;
-  uint32_t lo2;
-  uint32_t hi3;
-  uint32_t lo3;
-} mcontext_t;
-
-typedef struct ucontext {
-  uint32_t uc_flags;
-  struct ucontext* uc_link;
-  stack_t uc_stack;
-  mcontext_t uc_mcontext;
-  // Other fields are not used by V8, don't define them here.
-} ucontext_t;
-
-#elif defined(__i386__)
-// x86 version for Android.
-typedef struct {
-  uint32_t gregs[19];
-  void* fpregs;
-  uint32_t oldmask;
-  uint32_t cr2;
-} mcontext_t;
-
-typedef uint32_t kernel_sigset_t[2];  // x86 kernel uses 64-bit signal masks
-typedef struct ucontext {
-  uint32_t uc_flags;
-  struct ucontext* uc_link;
-  stack_t uc_stack;
-  mcontext_t uc_mcontext;
-  // Other fields are not used by V8, don't define them here.
-} ucontext_t;
-enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
-#endif
-
-#endif  // __ANDROID__ && !defined(__BIONIC_HAVE_UCONTEXT_T)
-
-static int GetThreadID() {
-#if defined(__ANDROID__)
-  // Android's C library provides gettid(2).
-  return gettid();
-#else
-  // Glibc doesn't provide a wrapper for gettid(2).
-  return syscall(SYS_gettid);
-#endif
-}
-
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
-  USE(info);
-  if (signal != SIGPROF) return;
-  Isolate* isolate = Isolate::UncheckedCurrent();
-  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
-    // We require a fully initialized and entered isolate.
-    return;
-  }
-  if (v8::Locker::IsActive() &&
-      !isolate->thread_manager()->IsLockedByCurrentThread()) {
-    return;
-  }
-
-  Sampler* sampler = isolate->logger()->sampler();
-  if (sampler == NULL || !sampler->IsActive()) return;
-
-  TickSample sample_obj;
-  TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-  if (sample == NULL) sample = &sample_obj;
-
-  // Extracting the sample from the context is extremely machine dependent.
-  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
-  mcontext_t& mcontext = ucontext->uc_mcontext;
-  sample->state = isolate->current_vm_state();
-#if V8_HOST_ARCH_IA32
-  sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
-  sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
-  sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
-#elif V8_HOST_ARCH_X64
-  sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
-  sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
-  sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
-#elif V8_HOST_ARCH_ARM
-#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
-    (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
-  // Old GLibc ARM versions used a gregs[] array to access the register
-  // values from mcontext_t.
-  sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
-  sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
-  sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
-#else
-  sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
-  sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
-  sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
-#endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
-        // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
-#elif V8_HOST_ARCH_MIPS
-  sample->pc = reinterpret_cast<Address>(mcontext.pc);
-  sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]);
-  sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]);
-#endif  // V8_HOST_ARCH_*
-  sampler->SampleStack(sample);
-  sampler->Tick(sample);
-}
-
-
-class Sampler::PlatformData : public Malloced {
- public:
-  PlatformData() : vm_tid_(GetThreadID()) {}
-
-  int vm_tid() const { return vm_tid_; }
-
- private:
-  const int vm_tid_;
-};
-
-
-class SignalSender : public Thread {
- public:
-  static const int kSignalSenderStackSize = 64 * KB;
-
-  explicit SignalSender(int interval)
-      : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
-        vm_tgid_(getpid()),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void InstallSignalHandler() {
-    struct sigaction sa;
-    sa.sa_sigaction = ProfilerSignalHandler;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESTART | SA_SIGINFO;
-    signal_handler_installed_ =
-        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
-  }
-
-  static void RestoreSignalHandler() {
-    if (signal_handler_installed_) {
-      sigaction(SIGPROF, &old_signal_handler_, 0);
-      signal_handler_installed_ = false;
-    }
-  }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      // Start a thread that will send SIGPROF signal to VM threads,
-      // when CPU profiling will be enabled.
-      instance_ = new SignalSender(sampler->interval());
-      instance_->Start();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
-      delete instance_;
-      instance_ = NULL;
-      RestoreSignalHandler();
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        if (!signal_handler_installed_) InstallSignalHandler();
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      } else {
-        if (signal_handler_installed_) RestoreSignalHandler();
-        if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
-      }
-      Sleep();  // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
-    if (!sampler->IsProfiling()) return;
-    SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
-    sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
-  }
-
-  void SendProfilingSignal(int tid) {
-    if (!signal_handler_installed_) return;
-    // Glibc doesn't provide a wrapper for tgkill(2).
-#if defined(ANDROID)
-    syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
-#else
-    int result = syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
-    USE(result);
-    ASSERT(result == 0);
-#endif
-  }
-
-  void Sleep() {
-    // Convert ms to us and subtract 100 us to compensate delays
-    // occuring during signal delivery.
-    useconds_t interval = interval_ * 1000 - 100;
-#if defined(ANDROID)
-    usleep(interval);
-#else
-    int result = usleep(interval);
-#ifdef DEBUG
-    if (result != 0 && errno != EINTR) {
-      fprintf(stderr,
-              "SignalSender usleep error; interval = %u, errno = %d\n",
-              interval,
-              errno);
-      ASSERT(result == 0 || errno == EINTR);
-    }
-#endif  // DEBUG
-    USE(result);
-#endif  // ANDROID
-  }
-
-  const int vm_tgid_;
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SignalSender* instance_;
-  static bool signal_handler_installed_;
-  static struct sigaction old_signal_handler_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SignalSender);
-};
-
-
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
-
-
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = Ticks() ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-
-#ifdef __arm__
-  // When running on ARM hardware check that the EABI used by V8 and
-  // by the C code is the same.
-  bool hard_float = OS::ArmUsingHardFloat();
-  if (hard_float) {
-#if !USE_EABI_HARDFLOAT
-    PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without "
-           "-DUSE_EABI_HARDFLOAT\n");
-    exit(1);
-#endif
-  } else {
-#if USE_EABI_HARDFLOAT
-    PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with "
-           "-DUSE_EABI_HARDFLOAT\n");
-    exit(1);
-#endif
-  }
-#endif
-  SignalSender::SetUp();
 }
 
 
 void OS::TearDown() {
-  SignalSender::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SignalSender::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SignalSender::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
-
 } }  // namespace v8::internal
index 30e2b89..9bb4dbd 100644 (file)
@@ -60,6 +60,7 @@
 
 #include "platform-posix.h"
 #include "platform.h"
+#include "simulator.h"
 #include "vm-state-inl.h"
 
 // Manually define these here as weak imports, rather than including execinfo.h.
@@ -407,12 +408,33 @@ VirtualMemory::~VirtualMemory() {
 }
 
 
+bool VirtualMemory::IsReserved() {
+  return address_ != NULL;
+}
+
+
 void VirtualMemory::Reset() {
   address_ = NULL;
   size_ = 0;
 }
 
 
+bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
+  return CommitRegion(address, size, is_executable);
+}
+
+
+bool VirtualMemory::Uncommit(void* address, size_t size) {
+  return UncommitRegion(address, size);
+}
+
+
+bool VirtualMemory::Guard(void* address) {
+  OS::Guard(address, OS::CommitPageSize());
+  return true;
+}
+
+
 void* VirtualMemory::ReserveRegion(size_t size) {
   void* result = mmap(OS::GetRandomMmapAddr(),
                       size,
@@ -427,22 +449,6 @@ void* VirtualMemory::ReserveRegion(size_t size) {
 }
 
 
-bool VirtualMemory::IsReserved() {
-  return address_ != NULL;
-}
-
-
-bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
-  return CommitRegion(address, size, is_executable);
-}
-
-
-bool VirtualMemory::Guard(void* address) {
-  OS::Guard(address, OS::CommitPageSize());
-  return true;
-}
-
-
 bool VirtualMemory::CommitRegion(void* address,
                                  size_t size,
                                  bool is_executable) {
@@ -461,11 +467,6 @@ bool VirtualMemory::CommitRegion(void* address,
 }
 
 
-bool VirtualMemory::Uncommit(void* address, size_t size) {
-  return UncommitRegion(address, size);
-}
-
-
 bool VirtualMemory::UncommitRegion(void* address, size_t size) {
   return mmap(address,
               size,
@@ -495,7 +496,8 @@ class Thread::PlatformData : public Malloced {
 
 Thread::Thread(const Options& options)
     : data_(new PlatformData),
-      stack_size_(options.stack_size()) {
+      stack_size_(options.stack_size()),
+      start_semaphore_(NULL) {
   set_name(options.name());
 }
 
@@ -530,7 +532,7 @@ static void* ThreadEntry(void* arg) {
   thread->data()->thread_ = pthread_self();
   SetThreadName(thread->name());
   ASSERT(thread->data()->thread_ != kNoThread);
-  thread->Run();
+  thread->NotifyStartedAndRun();
   return NULL;
 }
 
@@ -741,186 +743,17 @@ Semaphore* OS::CreateSemaphore(int count) {
 }
 
 
-class Sampler::PlatformData : public Malloced {
- public:
-  PlatformData() : profiled_thread_(mach_thread_self()) {}
-
-  ~PlatformData() {
-    // Deallocate Mach port for thread.
-    mach_port_deallocate(mach_task_self(), profiled_thread_);
-  }
-
-  thread_act_t profiled_thread() { return profiled_thread_; }
-
- private:
-  // Note: for profiled_thread_ Mach primitives are used instead of PThread's
-  // because the latter doesn't provide thread manipulation primitives required.
-  // For details, consult "Mac OS X Internals" book, Section 7.3.
-  thread_act_t profiled_thread_;
-};
-
-
-class SamplerThread : public Thread {
- public:
-  static const int kSamplerThreadStackSize = 64 * KB;
-
-  explicit SamplerThread(int interval)
-      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      instance_ = new SamplerThread(sampler->interval());
-      instance_->Start();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
-      delete instance_;
-      instance_ = NULL;
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      } else {
-        if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
-      }
-      OS::Sleep(interval_);
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
-    if (!sampler->isolate()->IsInitialized()) return;
-    if (!sampler->IsProfiling()) return;
-    SamplerThread* sampler_thread =
-        reinterpret_cast<SamplerThread*>(raw_sampler_thread);
-    sampler_thread->SampleContext(sampler);
-  }
-
-  void SampleContext(Sampler* sampler) {
-    thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
-    Isolate* isolate = sampler->isolate();
-    TickSample sample_obj;
-    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-    if (sample == NULL) sample = &sample_obj;
-
-    if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
-
-#if V8_HOST_ARCH_X64
-    thread_state_flavor_t flavor = x86_THREAD_STATE64;
-    x86_thread_state64_t state;
-    mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
-#if __DARWIN_UNIX03
-#define REGISTER_FIELD(name) __r ## name
-#else
-#define REGISTER_FIELD(name) r ## name
-#endif  // __DARWIN_UNIX03
-#elif V8_HOST_ARCH_IA32
-    thread_state_flavor_t flavor = i386_THREAD_STATE;
-    i386_thread_state_t state;
-    mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
-#if __DARWIN_UNIX03
-#define REGISTER_FIELD(name) __e ## name
-#else
-#define REGISTER_FIELD(name) e ## name
-#endif  // __DARWIN_UNIX03
-#else
-#error Unsupported Mac OS X host architecture.
-#endif  // V8_HOST_ARCH
-
-    if (thread_get_state(profiled_thread,
-                         flavor,
-                         reinterpret_cast<natural_t*>(&state),
-                         &count) == KERN_SUCCESS) {
-      sample->state = isolate->current_vm_state();
-      sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
-      sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
-      sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
-      sampler->SampleStack(sample);
-      sampler->Tick(sample);
-    }
-    thread_resume(profiled_thread);
-  }
-
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SamplerThread* instance_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-#undef REGISTER_FIELD
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = Ticks() ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-  SamplerThread::SetUp();
 }
 
 
 void OS::TearDown() {
-  SamplerThread::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SamplerThread::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
-
 } }  // namespace v8::internal
index 0fef063..1b481f4 100644 (file)
@@ -317,6 +317,16 @@ int OS::StackWalk(Vector<OS::StackFrame> frames) {
 }
 
 
+VirtualMemory::VirtualMemory() {
+  UNIMPLEMENTED();
+}
+
+
+VirtualMemory::VirtualMemory(size_t size) {
+  UNIMPLEMENTED();
+}
+
+
 VirtualMemory::VirtualMemory(size_t size, void* address_hint) {
   UNIMPLEMENTED();
 }
@@ -333,6 +343,11 @@ bool VirtualMemory::IsReserved() {
 }
 
 
+void VirtualMemory::Reset() {
+  UNIMPLEMENTED();
+}
+
+
 bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
   UNIMPLEMENTED();
   return false;
@@ -351,6 +366,30 @@ bool VirtualMemory::Guard(void* address) {
 }
 
 
+void* VirtualMemory::ReserveRegion(size_t size) {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
+bool VirtualMemory::UncommitRegion(void* base, size_t size) {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
+bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
+  UNIMPLEMENTED();
+  return false;
+}
+
+
 bool VirtualMemory::HasLazyCommits() {
   // TODO(alph): implement for the platform.
   return false;
@@ -369,7 +408,8 @@ class Thread::PlatformData : public Malloced {
 
 Thread::Thread(const Options& options)
     : data_(new PlatformData()),
-      stack_size_(options.stack_size) {
+      stack_size_(options.stack_size),
+      start_semaphore_(NULL) {
   set_name(options.name);
   UNIMPLEMENTED();
 }
index e48d4cb..e1aff17 100644 (file)
@@ -385,12 +385,12 @@ int OS::StackWalk(Vector<OS::StackFrame> frames) {
 static const int kMmapFd = -1;
 static const int kMmapFdOffset = 0;
 
+
 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
 
-VirtualMemory::VirtualMemory(size_t size) {
-  address_ = ReserveRegion(size);
-  size_ = size;
-}
+
+VirtualMemory::VirtualMemory(size_t size)
+    : address_(ReserveRegion(size)), size_(size) { }
 
 
 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
@@ -529,7 +529,8 @@ class Thread::PlatformData : public Malloced {
 
 Thread::Thread(const Options& options)
     : data_(new PlatformData()),
-      stack_size_(options.stack_size()) {
+      stack_size_(options.stack_size()),
+      start_semaphore_(NULL) {
   set_name(options.name());
 }
 
@@ -551,7 +552,7 @@ static void* ThreadEntry(void* arg) {
 #endif
   thread->data()->thread_ = pthread_self();
   ASSERT(thread->data()->thread_ != kNoThread);
-  thread->Run();
+  thread->NotifyStartedAndRun();
   return NULL;
 }
 
@@ -727,232 +728,17 @@ Semaphore* OS::CreateSemaphore(int count) {
 }
 
 
-static pthread_t GetThreadID() {
-  return pthread_self();
-}
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
-  USE(info);
-  if (signal != SIGPROF) return;
-  Isolate* isolate = Isolate::UncheckedCurrent();
-  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
-    // We require a fully initialized and entered isolate.
-    return;
-  }
-  if (v8::Locker::IsActive() &&
-      !isolate->thread_manager()->IsLockedByCurrentThread()) {
-    return;
-  }
-
-  Sampler* sampler = isolate->logger()->sampler();
-  if (sampler == NULL || !sampler->IsActive()) return;
-
-  TickSample sample_obj;
-  TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-  if (sample == NULL) sample = &sample_obj;
-
-  // Extracting the sample from the context is extremely machine dependent.
-  sample->state = isolate->current_vm_state();
-  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
-#ifdef __NetBSD__
-  mcontext_t& mcontext = ucontext->uc_mcontext;
-#if V8_HOST_ARCH_IA32
-  sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
-  sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
-  sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
-#elif V8_HOST_ARCH_X64
-  sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
-  sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
-  sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
-#endif  // V8_HOST_ARCH
-#else  // OpenBSD
-#if V8_HOST_ARCH_IA32
-  sample->pc = reinterpret_cast<Address>(ucontext->sc_eip);
-  sample->sp = reinterpret_cast<Address>(ucontext->sc_esp);
-  sample->fp = reinterpret_cast<Address>(ucontext->sc_ebp);
-#elif V8_HOST_ARCH_X64
-  sample->pc = reinterpret_cast<Address>(ucontext->sc_rip);
-  sample->sp = reinterpret_cast<Address>(ucontext->sc_rsp);
-  sample->fp = reinterpret_cast<Address>(ucontext->sc_rbp);
-#endif  // V8_HOST_ARCH
-#endif  // __NetBSD__
-  sampler->SampleStack(sample);
-  sampler->Tick(sample);
-}
-
-
-class Sampler::PlatformData : public Malloced {
- public:
-  PlatformData() : vm_tid_(GetThreadID()) {}
-
-  pthread_t vm_tid() const { return vm_tid_; }
-
- private:
-  pthread_t vm_tid_;
-};
-
-
-class SignalSender : public Thread {
- public:
-  static const int kSignalSenderStackSize = 64 * KB;
-
-  explicit SignalSender(int interval)
-      : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
-        vm_tgid_(getpid()),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void InstallSignalHandler() {
-    struct sigaction sa;
-    sa.sa_sigaction = ProfilerSignalHandler;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESTART | SA_SIGINFO;
-    signal_handler_installed_ =
-        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
-  }
-
-  static void RestoreSignalHandler() {
-    if (signal_handler_installed_) {
-      sigaction(SIGPROF, &old_signal_handler_, 0);
-      signal_handler_installed_ = false;
-    }
-  }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      // Start a thread that will send SIGPROF signal to VM threads,
-      // when CPU profiling will be enabled.
-      instance_ = new SignalSender(sampler->interval());
-      instance_->Start();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
-      delete instance_;
-      instance_ = NULL;
-      RestoreSignalHandler();
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        if (!signal_handler_installed_) InstallSignalHandler();
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      } else {
-        if (signal_handler_installed_) RestoreSignalHandler();
-        if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
-      }
-      Sleep();  // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
-    if (!sampler->IsProfiling()) return;
-    SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
-    sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
-  }
-
-  void SendProfilingSignal(pthread_t tid) {
-    if (!signal_handler_installed_) return;
-    pthread_kill(tid, SIGPROF);
-  }
-
-  void Sleep() {
-    // Convert ms to us and subtract 100 us to compensate delays
-    // occuring during signal delivery.
-    useconds_t interval = interval_ * 1000 - 100;
-    int result = usleep(interval);
-#ifdef DEBUG
-    if (result != 0 && errno != EINTR) {
-      fprintf(stderr,
-              "SignalSender usleep error; interval = %u, errno = %d\n",
-              interval,
-              errno);
-      ASSERT(result == 0 || errno == EINTR);
-    }
-#endif
-    USE(result);
-  }
-
-  const int vm_tgid_;
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SignalSender* instance_;
-  static bool signal_handler_installed_;
-  static struct sigaction old_signal_handler_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SignalSender);
-};
-
-
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
-
-
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = Ticks() ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-  SignalSender::SetUp();
 }
 
 
 void OS::TearDown() {
-  SignalSender::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SignalSender::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SignalSender::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
-
 } }  // namespace v8::internal
index 69d3911..48898ed 100644 (file)
@@ -94,6 +94,12 @@ void OS::Guard(void* address, const size_t size) {
 
 
 void* OS::GetRandomMmapAddr() {
+#if defined(__native_client__)
+  // TODO(bradchen): restore randomization once Native Client gets
+  // smarter about using mmap address hints.
+  // See http://code.google.com/p/nativeclient/issues/3341
+  return NULL;
+#endif
   Isolate* isolate = Isolate::UncheckedCurrent();
   // Note that the current isolate isn't set up in a call path via
   // CpuFeatures::Probe. We don't care about randomization in this case because
@@ -109,26 +115,11 @@ void* OS::GetRandomMmapAddr() {
     raw_addr &= V8_UINT64_C(0x3ffffffff000);
 #else
     uint32_t raw_addr = V8::RandomPrivate(isolate);
-
-    raw_addr &= 0x3ffff000;
-
-# ifdef __sun
-    // For our Solaris/illumos 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); Solaris and
-    // illumos will try the hint and if that fails allocate as if there were
-    // no hint at all. The high hint prevents the break from getting hemmed in
-    // at low values, ceding half of the address space to the system heap.
-    raw_addr += 0x80000000;
-# else
     // 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 += 0x20000000;
-# endif
 #endif
     return reinterpret_cast<void*>(raw_addr);
   }
@@ -331,25 +322,32 @@ int OS::VSNPrintF(Vector<char> str,
 
 
 #if defined(V8_TARGET_ARCH_IA32)
-static OS::MemCopyFunction memcopy_function = NULL;
+static void MemMoveWrapper(void* dest, const void* src, size_t size) {
+  memmove(dest, src, size);
+}
+
+// Initialize to library version so we can call this at any time during startup.
+static OS::MemMoveFunction memmove_function = &MemMoveWrapper;
+
 // Defined in codegen-ia32.cc.
-OS::MemCopyFunction CreateMemCopyFunction();
+OS::MemMoveFunction CreateMemMoveFunction();
 
-// Copy memory area to disjoint memory area.
-void OS::MemCopy(void* dest, const void* src, size_t size) {
+// Copy memory area. No restrictions.
+void OS::MemMove(void* dest, const void* src, size_t size) {
   // Note: here we rely on dependent reads being ordered. This is true
   // on all architectures we currently support.
-  (*memcopy_function)(dest, src, size);
-#ifdef DEBUG
-  CHECK_EQ(0, memcmp(dest, src, size));
-#endif
+  (*memmove_function)(dest, src, size);
 }
+
 #endif  // V8_TARGET_ARCH_IA32
 
 
 void POSIXPostSetUp() {
 #if defined(V8_TARGET_ARCH_IA32)
-  memcopy_function = CreateMemCopyFunction();
+  OS::MemMoveFunction generated_memmove = CreateMemMoveFunction();
+  if (generated_memmove != NULL) {
+    memmove_function = generated_memmove;
+  }
 #endif
   init_fast_sin_function();
   init_fast_cos_function();
index 0e616d1..aeacab9 100644 (file)
@@ -327,10 +327,9 @@ static const int kMmapFdOffset = 0;
 
 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
 
-VirtualMemory::VirtualMemory(size_t size) {
-  address_ = ReserveRegion(size);
-  size_ = size;
-}
+
+VirtualMemory::VirtualMemory(size_t size)
+    : address_(ReserveRegion(size)), size_(size) { }
 
 
 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
@@ -470,7 +469,8 @@ class Thread::PlatformData : public Malloced {
 
 Thread::Thread(const Options& options)
     : data_(new PlatformData()),
-      stack_size_(options.stack_size()) {
+      stack_size_(options.stack_size()),
+      start_semaphore_(NULL) {
   set_name(options.name());
 }
 
@@ -487,7 +487,7 @@ static void* ThreadEntry(void* arg) {
   // one) so we initialize it here too.
   thread->data()->thread_ = pthread_self();
   ASSERT(thread->data()->thread_ != kNoThread);
-  thread->Run();
+  thread->NotifyStartedAndRun();
   return NULL;
 }
 
@@ -661,169 +661,6 @@ Semaphore* OS::CreateSemaphore(int count) {
 }
 
 
-static pthread_t GetThreadID() {
-  return pthread_self();
-}
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
-  USE(info);
-  if (signal != SIGPROF) return;
-  Isolate* isolate = Isolate::UncheckedCurrent();
-  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
-    // We require a fully initialized and entered isolate.
-    return;
-  }
-  if (v8::Locker::IsActive() &&
-      !isolate->thread_manager()->IsLockedByCurrentThread()) {
-    return;
-  }
-
-  Sampler* sampler = isolate->logger()->sampler();
-  if (sampler == NULL || !sampler->IsActive()) return;
-
-  TickSample sample_obj;
-  TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-  if (sample == NULL) sample = &sample_obj;
-
-  // Extracting the sample from the context is extremely machine dependent.
-  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
-  mcontext_t& mcontext = ucontext->uc_mcontext;
-  sample->state = isolate->current_vm_state();
-
-  sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
-  sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
-  sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
-
-  sampler->SampleStack(sample);
-  sampler->Tick(sample);
-}
-
-class Sampler::PlatformData : public Malloced {
- public:
-  PlatformData() : vm_tid_(GetThreadID()) {}
-
-  pthread_t vm_tid() const { return vm_tid_; }
-
- private:
-  pthread_t vm_tid_;
-};
-
-
-class SignalSender : public Thread {
- public:
-  static const int kSignalSenderStackSize = 64 * KB;
-
-  explicit SignalSender(int interval)
-      : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void InstallSignalHandler() {
-    struct sigaction sa;
-    sa.sa_sigaction = ProfilerSignalHandler;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESTART | SA_SIGINFO;
-    signal_handler_installed_ =
-        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
-  }
-
-  static void RestoreSignalHandler() {
-    if (signal_handler_installed_) {
-      sigaction(SIGPROF, &old_signal_handler_, 0);
-      signal_handler_installed_ = false;
-    }
-  }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      // Start a thread that will send SIGPROF signal to VM threads,
-      // when CPU profiling will be enabled.
-      instance_ = new SignalSender(sampler->interval());
-      instance_->Start();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
-      delete instance_;
-      instance_ = NULL;
-      RestoreSignalHandler();
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        if (!signal_handler_installed_) InstallSignalHandler();
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      } else {
-        if (signal_handler_installed_) RestoreSignalHandler();
-        if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
-      }
-      Sleep();  // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
-    if (!sampler->IsProfiling()) return;
-    SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
-    sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
-  }
-
-  void SendProfilingSignal(pthread_t tid) {
-    if (!signal_handler_installed_) return;
-    pthread_kill(tid, SIGPROF);
-  }
-
-  void Sleep() {
-    // Convert ms to us and subtract 100 us to compensate delays
-    // occuring during signal delivery.
-    useconds_t interval = interval_ * 1000 - 100;
-    int result = usleep(interval);
-#ifdef DEBUG
-    if (result != 0 && errno != EINTR) {
-      fprintf(stderr,
-              "SignalSender usleep error; interval = %u, errno = %d\n",
-              interval,
-              errno);
-      ASSERT(result == 0 || errno == EINTR);
-    }
-#endif
-    USE(result);
-  }
-
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SignalSender* instance_;
-  static bool signal_handler_installed_;
-  static struct sigaction old_signal_handler_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SignalSender);
-};
-
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
-
-
 void OS::SetUp() {
   // Seed the random number generator.
   // Convert the current time to a 64-bit integer first, before converting it
@@ -833,43 +670,12 @@ void OS::SetUp() {
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srandom(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-  SignalSender::SetUp();
 }
 
 
 void OS::TearDown() {
-  SignalSender::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SignalSender::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SignalSender::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
 } }  // namespace v8::internal
index c1bae93..272678f 100644 (file)
@@ -45,6 +45,7 @@
 
 #include "codegen.h"
 #include "platform.h"
+#include "simulator.h"
 #include "vm-state-inl.h"
 
 #ifdef _MSC_VER
@@ -147,19 +148,23 @@ double ceiling(double x) {
 static Mutex* limit_mutex = NULL;
 
 #if defined(V8_TARGET_ARCH_IA32)
-static OS::MemCopyFunction memcopy_function = NULL;
+static void MemMoveWrapper(void* dest, const void* src, size_t size) {
+  memmove(dest, src, size);
+}
+
+// Initialize to library version so we can call this at any time during startup.
+static OS::MemMoveFunction memmove_function = &MemMoveWrapper;
+
 // Defined in codegen-ia32.cc.
-OS::MemCopyFunction CreateMemCopyFunction();
+OS::MemMoveFunction CreateMemMoveFunction();
 
 // Copy memory area to disjoint memory area.
-void OS::MemCopy(void* dest, const void* src, size_t size) {
+void OS::MemMove(void* dest, const void* src, size_t size) {
   // Note: here we rely on dependent reads being ordered. This is true
   // on all architectures we currently support.
-  (*memcopy_function)(dest, src, size);
-#ifdef DEBUG
-  CHECK_EQ(0, memcmp(dest, src, size));
-#endif
+  (*memmove_function)(dest, src, size);
 }
+
 #endif  // V8_TARGET_ARCH_IA32
 
 #ifdef _WIN64
@@ -575,7 +580,10 @@ void OS::PostSetUp() {
   // CPU.
   MathSetup();
 #if defined(V8_TARGET_ARCH_IA32)
-  memcopy_function = CreateMemCopyFunction();
+  OS::MemMoveFunction generated_memmove = CreateMemMoveFunction();
+  if (generated_memmove != NULL) {
+    memmove_function = generated_memmove;
+  }
 #endif
 }
 
@@ -1061,7 +1069,7 @@ OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
   if (file_mapping == NULL) return NULL;
   // Map a view of the file into memory
   void* memory = MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, size);
-  if (memory) memmove(memory, initial, size);
+  if (memory) OS::MemMove(memory, initial, size);
   return new Win32MemoryMappedFile(file, file_mapping, memory, size);
 }
 
@@ -1517,7 +1525,7 @@ VirtualMemory::VirtualMemory(size_t size, size_t alignment)
 
 VirtualMemory::~VirtualMemory() {
   if (IsReserved()) {
-    bool result = ReleaseRegion(address_, size_);
+    bool result = ReleaseRegion(address(), size());
     ASSERT(result);
     USE(result);
   }
@@ -1536,11 +1544,7 @@ void VirtualMemory::Reset() {
 
 
 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
-  if (CommitRegion(address, size, is_executable)) {
-    UpdateAllocatedSpaceLimits(address, static_cast<int>(size));
-    return true;
-  }
-  return false;
+  return CommitRegion(address, size, is_executable);
 }
 
 
@@ -1550,6 +1554,17 @@ bool VirtualMemory::Uncommit(void* address, size_t size) {
 }
 
 
+bool VirtualMemory::Guard(void* address) {
+  if (NULL == VirtualAlloc(address,
+                           OS::CommitPageSize(),
+                           MEM_COMMIT,
+                           PAGE_READONLY | PAGE_GUARD)) {
+    return false;
+  }
+  return true;
+}
+
+
 void* VirtualMemory::ReserveRegion(size_t size) {
   return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
 }
@@ -1566,17 +1581,6 @@ bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
 }
 
 
-bool VirtualMemory::Guard(void* address) {
-  if (NULL == VirtualAlloc(address,
-                           OS::CommitPageSize(),
-                           MEM_COMMIT,
-                           PAGE_READONLY | PAGE_GUARD)) {
-    return false;
-  }
-  return true;
-}
-
-
 bool VirtualMemory::UncommitRegion(void* base, size_t size) {
   return VirtualFree(base, size, MEM_DECOMMIT) != 0;
 }
@@ -1605,7 +1609,7 @@ static const HANDLE kNoThread = INVALID_HANDLE_VALUE;
 // convention.
 static unsigned int __stdcall ThreadEntry(void* arg) {
   Thread* thread = reinterpret_cast<Thread*>(arg);
-  thread->Run();
+  thread->NotifyStartedAndRun();
   return 0;
 }
 
@@ -1622,7 +1626,8 @@ class Thread::PlatformData : public Malloced {
 // handle until it is started.
 
 Thread::Thread(const Options& options)
-    : stack_size_(options.stack_size()) {
+    : stack_size_(options.stack_size()),
+      start_semaphore_(NULL) {
   data_ = new PlatformData(kNoThread);
   set_name(options.name());
 }
@@ -1970,141 +1975,6 @@ Socket* OS::CreateSocket() {
 }
 
 
-// ----------------------------------------------------------------------------
-// Win32 profiler support.
-
-class Sampler::PlatformData : public Malloced {
- public:
-  // Get a handle to the calling thread. This is the thread that we are
-  // going to profile. We need to make a copy of the handle because we are
-  // going to use it in the sampler thread. Using GetThreadHandle() will
-  // not work in this case. We're using OpenThread because DuplicateHandle
-  // for some reason doesn't work in Chrome's sandbox.
-  PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
-                                               THREAD_SUSPEND_RESUME |
-                                               THREAD_QUERY_INFORMATION,
-                                               false,
-                                               GetCurrentThreadId())) {}
-
-  ~PlatformData() {
-    if (profiled_thread_ != NULL) {
-      CloseHandle(profiled_thread_);
-      profiled_thread_ = NULL;
-    }
-  }
-
-  HANDLE profiled_thread() { return profiled_thread_; }
-
- private:
-  HANDLE profiled_thread_;
-};
-
-
-class SamplerThread : public Thread {
- public:
-  static const int kSamplerThreadStackSize = 64 * KB;
-
-  explicit SamplerThread(int interval)
-      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
-        interval_(interval) {}
-
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
-
-  static void AddActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::AddActiveSampler(sampler);
-    if (instance_ == NULL) {
-      instance_ = new SamplerThread(sampler->interval());
-      instance_->Start();
-    } else {
-      ASSERT(instance_->interval_ == sampler->interval());
-    }
-  }
-
-  static void RemoveActiveSampler(Sampler* sampler) {
-    ScopedLock lock(mutex_);
-    SamplerRegistry::RemoveActiveSampler(sampler);
-    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
-      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
-      delete instance_;
-      instance_ = NULL;
-    }
-  }
-
-  // Implement Thread::Run().
-  virtual void Run() {
-    SamplerRegistry::State state;
-    while ((state = SamplerRegistry::GetState()) !=
-           SamplerRegistry::HAS_NO_SAMPLERS) {
-      // When CPU profiling is enabled both JavaScript and C++ code is
-      // profiled. We must not suspend.
-      if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
-        SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
-      } else {
-        if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
-      }
-      OS::Sleep(interval_);
-    }
-  }
-
-  static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
-    if (!sampler->isolate()->IsInitialized()) return;
-    if (!sampler->IsProfiling()) return;
-    SamplerThread* sampler_thread =
-        reinterpret_cast<SamplerThread*>(raw_sampler_thread);
-    sampler_thread->SampleContext(sampler);
-  }
-
-  void SampleContext(Sampler* sampler) {
-    HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
-    if (profiled_thread == NULL) return;
-
-    // Context used for sampling the register state of the profiled thread.
-    CONTEXT context;
-    memset(&context, 0, sizeof(context));
-
-    Isolate* isolate = sampler->isolate();
-    TickSample sample_obj;
-    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
-    if (sample == NULL) sample = &sample_obj;
-
-    static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
-    if (SuspendThread(profiled_thread) == kSuspendFailed) return;
-    sample->state = isolate->current_vm_state();
-
-    context.ContextFlags = CONTEXT_FULL;
-    if (GetThreadContext(profiled_thread, &context) != 0) {
-#if V8_HOST_ARCH_X64
-      sample->pc = reinterpret_cast<Address>(context.Rip);
-      sample->sp = reinterpret_cast<Address>(context.Rsp);
-      sample->fp = reinterpret_cast<Address>(context.Rbp);
-#else
-      sample->pc = reinterpret_cast<Address>(context.Eip);
-      sample->sp = reinterpret_cast<Address>(context.Esp);
-      sample->fp = reinterpret_cast<Address>(context.Ebp);
-#endif
-      sampler->SampleStack(sample);
-      sampler->Tick(sample);
-    }
-    ResumeThread(profiled_thread);
-  }
-
-  const int interval_;
-
-  // Protects the process wide state below.
-  static Mutex* mutex_;
-  static SamplerThread* instance_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
 void OS::SetUp() {
   // Seed the random number generator.
   // Convert the current time to a 64-bit integer first, before converting it
@@ -2114,44 +1984,12 @@ void OS::SetUp() {
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srand(static_cast<unsigned int>(seed));
   limit_mutex = CreateMutex();
-  SamplerThread::SetUp();
 }
 
 
 void OS::TearDown() {
-  SamplerThread::TearDown();
   delete limit_mutex;
 }
 
 
-Sampler::Sampler(Isolate* isolate, int interval)
-    : isolate_(isolate),
-      interval_(interval),
-      profiling_(false),
-      active_(false),
-      samples_taken_(0) {
-  data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
-  ASSERT(!IsActive());
-  delete data_;
-}
-
-
-void Sampler::Start() {
-  ASSERT(!IsActive());
-  SetActive(true);
-  SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
-  ASSERT(IsActive());
-  SamplerThread::RemoveActiveSampler(this);
-  SetActive(false);
-}
-
-
 } }  // namespace v8::internal
index f2a228c..ab75d74 100644 (file)
@@ -91,8 +91,10 @@ inline int lrint(double flt) {
 
 #endif  // _MSC_VER
 
+#ifndef __CYGWIN__
 // Random is missing on both Visual Studio and MinGW.
 int random();
+#endif
 
 #endif  // WIN32
 
@@ -105,14 +107,6 @@ int random();
 namespace v8 {
 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;
 
@@ -337,17 +331,27 @@ class OS {
   static void ReleaseStore(volatile AtomicWord* ptr, AtomicWord value);
 
 #if defined(V8_TARGET_ARCH_IA32)
-  // Copy memory area to disjoint memory area.
-  static void MemCopy(void* dest, const void* src, size_t size);
   // Limit below which the extra overhead of the MemCopy function is likely
   // to outweigh the benefits of faster copying.
   static const int kMinComplexMemCopy = 64;
-  typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
 
+  // Copy memory area. No restrictions.
+  static void MemMove(void* dest, const void* src, size_t size);
+  typedef void (*MemMoveFunction)(void* dest, const void* src, size_t size);
+
+  // Keep the distinction of "move" vs. "copy" for the benefit of other
+  // architectures.
+  static void MemCopy(void* dest, const void* src, size_t size) {
+    MemMove(dest, src, size);
+  }
 #else  // V8_TARGET_ARCH_IA32
+  // Copy memory area to disjoint memory area.
   static void MemCopy(void* dest, const void* src, size_t size) {
     memcpy(dest, src, size);
   }
+  static void MemMove(void* dest, const void* src, size_t size) {
+    memmove(dest, src, size);
+  }
   static const int kMinComplexMemCopy = 16 * kPointerSize;
 #endif  // V8_TARGET_ARCH_IA32
 
@@ -453,6 +457,59 @@ class VirtualMemory {
 
 
 // ----------------------------------------------------------------------------
+// Semaphore
+//
+// A semaphore object is a synchronization object that maintains a count. The
+// count is decremented each time a thread completes a wait for the semaphore
+// object and incremented each time a thread signals the semaphore. When the
+// count reaches zero,  threads waiting for the semaphore blocks until the
+// count becomes non-zero.
+
+class Semaphore {
+ public:
+  virtual ~Semaphore() {}
+
+  // Suspends the calling thread until the semaphore counter is non zero
+  // and then decrements the semaphore counter.
+  virtual void Wait() = 0;
+
+  // Suspends the calling thread until the counter is non zero or the timeout
+  // time has passed. If timeout happens the return value is false and the
+  // counter is unchanged. Otherwise the semaphore counter is decremented and
+  // true is returned. The timeout value is specified in microseconds.
+  virtual bool Wait(int timeout) = 0;
+
+  // Increments the semaphore counter.
+  virtual void Signal() = 0;
+};
+
+template <int InitialValue>
+struct CreateSemaphoreTrait {
+  static Semaphore* Create() {
+    return OS::CreateSemaphore(InitialValue);
+  }
+};
+
+// POD Semaphore initialized lazily (i.e. the first time Pointer() is called).
+// Usage:
+//   // The following semaphore starts at 0.
+//   static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER;
+//
+//   void my_function() {
+//     // Do something with my_semaphore.Pointer().
+//   }
+//
+template <int InitialValue>
+struct LazySemaphore {
+  typedef typename LazyDynamicInstance<
+      Semaphore, CreateSemaphoreTrait<InitialValue>,
+      ThreadSafeInitOnceTrait>::type type;
+};
+
+#define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
+
+
+// ----------------------------------------------------------------------------
 // Thread
 //
 // Thread objects are used for creating and running threads. When the start()
@@ -489,9 +546,18 @@ class Thread {
   explicit Thread(const Options& options);
   virtual ~Thread();
 
-  // Start new thread by calling the Run() method in the new thread.
+  // Start new thread by calling the Run() method on the new thread.
   void Start();
 
+  // Start new thread and wait until Run() method is called on the new thread.
+  void StartSynchronously() {
+    start_semaphore_ = OS::CreateSemaphore(0);
+    Start();
+    start_semaphore_->Wait();
+    delete start_semaphore_;
+    start_semaphore_ = NULL;
+  }
+
   // Wait until thread terminates.
   void Join();
 
@@ -541,6 +607,11 @@ class Thread {
   class PlatformData;
   PlatformData* data() { return data_; }
 
+  void NotifyStartedAndRun() {
+    if (start_semaphore_) start_semaphore_->Signal();
+    Run();
+  }
+
  private:
   void set_name(const char* name);
 
@@ -548,6 +619,7 @@ class Thread {
 
   char name_[kMaxThreadNameLength];
   int stack_size_;
+  Semaphore* start_semaphore_;
 
   DISALLOW_COPY_AND_ASSIGN(Thread);
 };
@@ -620,59 +692,6 @@ class ScopedLock {
 
 
 // ----------------------------------------------------------------------------
-// Semaphore
-//
-// A semaphore object is a synchronization object that maintains a count. The
-// count is decremented each time a thread completes a wait for the semaphore
-// object and incremented each time a thread signals the semaphore. When the
-// count reaches zero,  threads waiting for the semaphore blocks until the
-// count becomes non-zero.
-
-class Semaphore {
- public:
-  virtual ~Semaphore() {}
-
-  // Suspends the calling thread until the semaphore counter is non zero
-  // and then decrements the semaphore counter.
-  virtual void Wait() = 0;
-
-  // Suspends the calling thread until the counter is non zero or the timeout
-  // time has passed. If timeout happens the return value is false and the
-  // counter is unchanged. Otherwise the semaphore counter is decremented and
-  // true is returned. The timeout value is specified in microseconds.
-  virtual bool Wait(int timeout) = 0;
-
-  // Increments the semaphore counter.
-  virtual void Signal() = 0;
-};
-
-template <int InitialValue>
-struct CreateSemaphoreTrait {
-  static Semaphore* Create() {
-    return OS::CreateSemaphore(InitialValue);
-  }
-};
-
-// POD Semaphore initialized lazily (i.e. the first time Pointer() is called).
-// Usage:
-//   // The following semaphore starts at 0.
-//   static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER;
-//
-//   void my_function() {
-//     // Do something with my_semaphore.Pointer().
-//   }
-//
-template <int InitialValue>
-struct LazySemaphore {
-  typedef typename LazyDynamicInstance<
-      Semaphore, CreateSemaphoreTrait<InitialValue>,
-      ThreadSafeInitOnceTrait>::type type;
-};
-
-#define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
-
-
-// ----------------------------------------------------------------------------
 // Socket
 //
 
@@ -712,96 +731,6 @@ class Socket {
 };
 
 
-// ----------------------------------------------------------------------------
-// Sampler
-//
-// A sampler periodically samples the state of the VM and optionally
-// (if used for profiling) the program counter and stack pointer for
-// the thread that created it.
-
-// TickSample captures the information collected for each sample.
-class TickSample {
- public:
-  TickSample()
-      : state(OTHER),
-        pc(NULL),
-        sp(NULL),
-        fp(NULL),
-        tos(NULL),
-        frames_count(0),
-        has_external_callback(false) {}
-  StateTag state;  // The state of the VM.
-  Address pc;      // Instruction pointer.
-  Address sp;      // Stack pointer.
-  Address fp;      // Frame pointer.
-  union {
-    Address tos;   // Top stack value (*sp).
-    Address external_callback;
-  };
-  static const int kMaxFramesCount = 64;
-  Address stack[kMaxFramesCount];  // Call stack.
-  int frames_count : 8;  // Number of captured frames.
-  bool has_external_callback : 1;
-};
-
-class Sampler {
- public:
-  // Initialize sampler.
-  Sampler(Isolate* isolate, int interval);
-  virtual ~Sampler();
-
-  int interval() const { return interval_; }
-
-  // Performs stack sampling.
-  void SampleStack(TickSample* sample) {
-    DoSampleStack(sample);
-    IncSamplesTaken();
-  }
-
-  // This method is called for each sampling period with the current
-  // program counter.
-  virtual void Tick(TickSample* sample) = 0;
-
-  // Start and stop sampler.
-  void Start();
-  void Stop();
-
-  // Is the sampler used for profiling?
-  bool IsProfiling() const { return NoBarrier_Load(&profiling_) > 0; }
-  void IncreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, 1); }
-  void DecreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, -1); }
-
-  // Whether the sampler is running (that is, consumes resources).
-  bool IsActive() const { return NoBarrier_Load(&active_); }
-
-  Isolate* isolate() { return isolate_; }
-
-  // Used in tests to make sure that stack sampling is performed.
-  int samples_taken() const { return samples_taken_; }
-  void ResetSamplesTaken() { samples_taken_ = 0; }
-
-  class PlatformData;
-  PlatformData* data() { return data_; }
-
-  PlatformData* platform_data() { return data_; }
-
- protected:
-  virtual void DoSampleStack(TickSample* sample) = 0;
-
- private:
-  void SetActive(bool value) { NoBarrier_Store(&active_, value); }
-  void IncSamplesTaken() { if (++samples_taken_ < 0) samples_taken_ = 0; }
-
-  Isolate* isolate_;
-  const int interval_;
-  Atomic32 profiling_;
-  Atomic32 active_;
-  PlatformData* data_;  // Platform specific data.
-  int samples_taken_;  // Counts stack samples taken.
-  DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler);
-};
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_PLATFORM_H_
index d0425b4..287ad66 100644 (file)
@@ -95,7 +95,7 @@ Vector<unsigned> PartialParserRecorder::ExtractData() {
   Vector<unsigned> data = Vector<unsigned>::New(total_size);
   preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
   preamble_[PreparseDataConstants::kSymbolCountOffset] = 0;
-  memcpy(data.start(), preamble_, sizeof(preamble_));
+  OS::MemCopy(data.start(), preamble_, sizeof(preamble_));
   int symbol_start = PreparseDataConstants::kHeaderSize + function_size;
   if (function_size > 0) {
     function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
@@ -151,7 +151,7 @@ Vector<unsigned> CompleteParserRecorder::ExtractData() {
   Vector<unsigned> data = Vector<unsigned>::New(total_size);
   preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
   preamble_[PreparseDataConstants::kSymbolCountOffset] = symbol_id_;
-  memcpy(data.start(), preamble_, sizeof(preamble_));
+  OS::MemCopy(data.start(), preamble_, sizeof(preamble_));
   int symbol_start = PreparseDataConstants::kHeaderSize + function_size;
   if (function_size > 0) {
     function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
index 6e8556a..462dfe2 100644 (file)
@@ -100,9 +100,9 @@ class InputStreamUtf16Buffer : public Utf16CharacterStream {
         // Hit the bottom of the allocated pushback buffer.
         // Double the buffer and continue.
         uc16* new_buffer = NewArray<uc16>(pushback_buffer_backing_size_ * 2);
-        memcpy(new_buffer + pushback_buffer_backing_size_,
-               pushback_buffer_backing_,
-               pushback_buffer_backing_size_);
+        OS::MemCopy(new_buffer + pushback_buffer_backing_size_,
+                    pushback_buffer_backing_,
+                    pushback_buffer_backing_size_);
         DeleteArray(pushback_buffer_backing_);
         buffer_cursor_ = new_buffer + pushback_buffer_backing_size_;
         pushback_buffer_backing_ = pushback_buffer_ = new_buffer;
@@ -168,16 +168,6 @@ class InputStreamUtf16Buffer : public Utf16CharacterStream {
   unsigned pushback_buffer_backing_size_;
 };
 
-
-// Functions declared by allocation.h and implemented in both api.cc (for v8)
-// or here (for a stand-alone preparser).
-
-void FatalProcessOutOfMemory(const char* reason) {
-  V8_Fatal(__FILE__, __LINE__, reason);
-}
-
-bool EnableSlowAsserts() { return true; }
-
 }  // namespace internal.
 
 
@@ -191,11 +181,9 @@ PreParserData Preparse(UnicodeInputStream* input, size_t max_stack) {
   internal::Scanner scanner(&unicode_cache);
   scanner.Initialize(&buffer);
   internal::CompleteParserRecorder recorder;
-  preparser::PreParser::PreParseResult result =
-      preparser::PreParser::PreParseProgram(&scanner,
-                                            &recorder,
-                                            internal::kAllowLazy,
-                                            stack_limit);
+  preparser::PreParser preparser(&scanner, &recorder, stack_limit);
+  preparser.set_allow_lazy(true);
+  preparser::PreParser::PreParseResult result = preparser.PreParseProgram();
   if (result == preparser::PreParser::kPreParseStackOverflow) {
     return PreParserData::StackOverflow();
   }
@@ -206,9 +194,3 @@ PreParserData Preparse(UnicodeInputStream* input, size_t max_stack) {
 }
 
 }  // namespace v8.
-
-
-// Used by ASSERT macros and other immediate exits.
-extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
-  exit(EXIT_FAILURE);
-}
index c61a08d..6e8800e 100644 (file)
@@ -179,7 +179,7 @@ PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
     Statement statement = ParseSourceElement(CHECK_OK);
     if (allow_directive_prologue) {
       if (statement.IsUseStrictLiteral()) {
-        set_language_mode(harmony_scoping_ ?
+        set_language_mode(allow_harmony_scoping() ?
                           i::EXTENDED_MODE : i::STRICT_MODE);
       } else if (!statement.IsStringLiteral()) {
         allow_directive_prologue = false;
index ce9aa75..e3a036f 100644 (file)
@@ -119,11 +119,7 @@ class PreParser {
 
   PreParser(i::Scanner* scanner,
             i::ParserRecorder* log,
-            uintptr_t stack_limit,
-            bool allow_lazy,
-            bool allow_natives_syntax,
-            bool allow_modules,
-            bool allow_generators)
+            uintptr_t stack_limit)
       : scanner_(scanner),
         log_(log),
         scope_(NULL),
@@ -131,30 +127,43 @@ class PreParser {
         strict_mode_violation_location_(i::Scanner::Location::invalid()),
         strict_mode_violation_type_(NULL),
         stack_overflow_(false),
-        allow_lazy_(allow_lazy),
-        allow_modules_(allow_modules),
-        allow_natives_syntax_(allow_natives_syntax),
-        allow_generators_(allow_generators),
-        parenthesized_function_(false),
-        harmony_scoping_(scanner->HarmonyScoping()) { }
+        allow_lazy_(false),
+        allow_natives_syntax_(false),
+        allow_generators_(false),
+        parenthesized_function_(false) { }
 
   ~PreParser() {}
 
+  bool allow_natives_syntax() const { return allow_natives_syntax_; }
+  bool allow_lazy() const { return allow_lazy_; }
+  bool allow_modules() const { return scanner_->HarmonyModules(); }
+  bool allow_harmony_scoping() const { return scanner_->HarmonyScoping(); }
+  bool allow_generators() const { return allow_generators_; }
+
+  void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; }
+  void set_allow_lazy(bool allow) { allow_lazy_ = allow; }
+  void set_allow_modules(bool allow) { scanner_->SetHarmonyModules(allow); }
+  void set_allow_harmony_scoping(bool allow) {
+    scanner_->SetHarmonyScoping(allow);
+  }
+  void set_allow_generators(bool allow) { allow_generators_ = allow; }
+
   // Pre-parse the program from the character stream; returns true on
   // success (even if parsing failed, the pre-parse data successfully
   // captured the syntax error), and false if a stack-overflow happened
   // during parsing.
-  static PreParseResult PreParseProgram(i::Scanner* scanner,
-                                        i::ParserRecorder* log,
-                                        int flags,
-                                        uintptr_t stack_limit) {
-    bool allow_lazy = (flags & i::kAllowLazy) != 0;
-    bool allow_natives_syntax = (flags & i::kAllowNativesSyntax) != 0;
-    bool allow_modules = (flags & i::kAllowModules) != 0;
-    bool allow_generators = (flags & i::kAllowGenerators) != 0;
-    return PreParser(scanner, log, stack_limit, allow_lazy,
-                     allow_natives_syntax, allow_modules,
-                     allow_generators).PreParse();
+  PreParseResult PreParseProgram() {
+    Scope top_scope(&scope_, kTopLevelScope);
+    bool ok = true;
+    int start_position = scanner_->peek_location().beg_pos;
+    ParseSourceElements(i::Token::EOS, &ok);
+    if (stack_overflow_) return kPreParseStackOverflow;
+    if (!ok) {
+      ReportUnexpectedToken(scanner_->current_token());
+    } else if (!scope_->is_classic_mode()) {
+      CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
+    }
+    return kPreParseSuccess;
   }
 
   // Parses a single function literal, from the opening parentheses before
@@ -514,22 +523,6 @@ class PreParser {
     bool is_generator_;
   };
 
-  // Preparse the program. Only called in PreParseProgram after creating
-  // the instance.
-  PreParseResult PreParse() {
-    Scope top_scope(&scope_, kTopLevelScope);
-    bool ok = true;
-    int start_position = scanner_->peek_location().beg_pos;
-    ParseSourceElements(i::Token::EOS, &ok);
-    if (stack_overflow_) return kPreParseStackOverflow;
-    if (!ok) {
-      ReportUnexpectedToken(scanner_->current_token());
-    } else if (!scope_->is_classic_mode()) {
-      CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
-    }
-    return kPreParseSuccess;
-  }
-
   // Report syntax error
   void ReportUnexpectedToken(i::Token::Value token);
   void ReportMessageAt(i::Scanner::Location location,
@@ -683,11 +676,9 @@ class PreParser {
   const char* strict_mode_violation_type_;
   bool stack_overflow_;
   bool allow_lazy_;
-  bool allow_modules_;
   bool allow_natives_syntax_;
   bool allow_generators_;
   bool parenthesized_function_;
-  bool harmony_scoping_;
 };
 } }  // v8::preparser
 
index 50a71ce..4660c0f 100644 (file)
@@ -505,7 +505,7 @@ void PrettyPrinter::Print(const char* format, ...) {
       const int slack = 32;
       int new_size = size_ + (size_ >> 1) + slack;
       char* new_output = NewArray<char>(new_size);
-      memcpy(new_output, output_, pos_);
+      OS::MemCopy(new_output, output_, pos_);
       DeleteArray(output_);
       output_ = new_output;
       size_ = new_size;
index ce07213..eacabef 100644 (file)
@@ -894,20 +894,12 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
   if (sample.pc != NULL) {
     *entry++ = code_map_.FindEntry(sample.pc);
 
-    if (sample.has_external_callback) {
+    if (sample.external_callback) {
       // Don't use PC when in external callback code, as it can point
       // inside callback's code, and we will erroneously report
       // that a callback calls itself.
       *(entries.start()) = NULL;
       *entry++ = code_map_.FindEntry(sample.external_callback);
-    } else if (sample.tos != NULL) {
-      // Find out, if top of stack was pointing inside a JS function
-      // meaning that we have encountered a frameless invocation.
-      *entry = code_map_.FindEntry(sample.tos);
-      if (*entry != NULL && !(*entry)->is_js_function()) {
-        *entry = NULL;
-      }
-      entry++;
     }
 
     for (const Address* stack_pos = sample.stack,
index b16de01..528c47d 100644 (file)
 
 "use strict";
 
-global.Proxy = new $Object();
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Object = global.Object;
 
-var $Proxy = global.Proxy
+var $Proxy = new $Object();
+
+// -------------------------------------------------------------------
 
 function ProxyCreate(handler, proto) {
   if (!IS_SPEC_OBJECT(handler))
@@ -62,16 +66,26 @@ function ProxyCreateFunction(handler, callTrap, constructTrap) {
     handler, callTrap, constructTrap, $Function.prototype)
 }
 
-%CheckIsBootstrapping()
-InstallFunctions($Proxy, DONT_ENUM, [
-  "create", ProxyCreate,
-  "createFunction", ProxyCreateFunction
-])
+
+// -------------------------------------------------------------------
+
+function SetUpProxy() {
+  %CheckIsBootstrapping()
+
+  global.Proxy = $Proxy;
+
+  // Set up non-enumerable properties of the Proxy object.
+  InstallFunctions($Proxy, DONT_ENUM, [
+    "create", ProxyCreate,
+    "createFunction", ProxyCreateFunction
+  ])
+}
+
+SetUpProxy();
 
 
-////////////////////////////////////////////////////////////////////////////////
-// Builtins
-////////////////////////////////////////////////////////////////////////////////
+// -------------------------------------------------------------------
+// Proxy Builtins
 
 function DerivedConstructTrap(callTrap) {
   return function() {
index 16766ca..e678d60 100644 (file)
@@ -479,7 +479,7 @@ int RegExpMacroAssemblerIrregexp::length() {
 
 
 void RegExpMacroAssemblerIrregexp::Copy(Address a) {
-  memcpy(a, buffer_.start(), length());
+  OS::MemCopy(a, buffer_.start(), length());
 }
 
 
@@ -488,7 +488,7 @@ void RegExpMacroAssemblerIrregexp::Expand() {
   Vector<byte> old_buffer = buffer_;
   buffer_ = Vector<byte>::New(old_buffer.length() * 2);
   own_buffer_ = true;
-  memcpy(buffer_.start(), old_buffer.start(), old_buffer.length());
+  OS::MemCopy(buffer_.start(), old_buffer.start(), old_buffer.length());
   if (old_buffer_was_our_own) {
     old_buffer.Dispose();
   }
index 325a149..fc4114a 100644 (file)
@@ -57,9 +57,7 @@ RegExpStack::~RegExpStack() {
 
 char* RegExpStack::ArchiveStack(char* to) {
   size_t size = sizeof(thread_local_);
-  memcpy(reinterpret_cast<void*>(to),
-         &thread_local_,
-         size);
+  OS::MemCopy(reinterpret_cast<void*>(to), &thread_local_, size);
   thread_local_ = ThreadLocal();
   return to + size;
 }
@@ -67,7 +65,7 @@ char* RegExpStack::ArchiveStack(char* to) {
 
 char* RegExpStack::RestoreStack(char* from) {
   size_t size = sizeof(thread_local_);
-  memcpy(&thread_local_, reinterpret_cast<void*>(from), size);
+  OS::MemCopy(&thread_local_, reinterpret_cast<void*>(from), size);
   return from + size;
 }
 
@@ -95,10 +93,11 @@ Address RegExpStack::EnsureCapacity(size_t size) {
     Address new_memory = NewArray<byte>(static_cast<int>(size));
     if (thread_local_.memory_size_ > 0) {
       // Copy original memory into top of new memory.
-      memcpy(reinterpret_cast<void*>(
-          new_memory + size - thread_local_.memory_size_),
-             reinterpret_cast<void*>(thread_local_.memory_),
-             thread_local_.memory_size_);
+      OS::MemCopy(
+          reinterpret_cast<void*>(
+              new_memory + size - thread_local_.memory_size_),
+          reinterpret_cast<void*>(thread_local_.memory_),
+          thread_local_.memory_size_);
       DeleteArray(thread_local_.memory_);
     }
     thread_local_.memory_ = new_memory;
index 2349ca7..cb11ad1 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Expect $Object = global.Object;
-// Expect $Array = global.Array;
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Object = global.Object;
+// var $Array = global.Array;
 
 var $RegExp = global.RegExp;
 
+// -------------------------------------------------------------------
+
 // A recursive descent parser for Patterns according to the grammar of
 // ECMA-262 15.10.1, with deviations noted below.
 function DoConstructRegExp(object, pattern, flags) {
index 2606f8a..752d79c 100644 (file)
@@ -86,17 +86,6 @@ static const int kMaxSizeEarlyOpt =
     5 * FullCodeGenerator::kBackEdgeDistanceUnit;
 
 
-Atomic32 RuntimeProfiler::state_ = 0;
-
-// TODO(isolates): Clean up the semaphore when it is no longer required.
-static LazySemaphore<0>::type semaphore = LAZY_SEMAPHORE_INITIALIZER;
-
-#ifdef DEBUG
-bool RuntimeProfiler::has_been_globally_set_up_ = false;
-#endif
-bool RuntimeProfiler::enabled_ = false;
-
-
 RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
     : isolate_(isolate),
       sampler_threshold_(kSamplerThresholdInit),
@@ -110,15 +99,6 @@ RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
 }
 
 
-void RuntimeProfiler::GlobalSetUp() {
-  ASSERT(!has_been_globally_set_up_);
-  enabled_ = V8::UseCrankshaft() && FLAG_opt;
-#ifdef DEBUG
-  has_been_globally_set_up_ = true;
-#endif
-}
-
-
 static void GetICCounts(JSFunction* function,
                         int* ic_with_type_info_count,
                         int* ic_total_count,
@@ -190,23 +170,22 @@ void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) {
   // any back edge in any unoptimized frame will trigger on-stack
   // replacement for that frame.
   if (FLAG_trace_osr) {
-    PrintF("[patching stack checks in ");
+    PrintF("[patching back edges in ");
     function->PrintName();
     PrintF(" for on-stack replacement]\n");
   }
 
-  // Get the stack check stub code object to match against.  We aren't
+  // Get the interrupt stub code object to match against.  We aren't
   // prepared to generate it, but we don't expect to have to.
-  Code* stack_check_code = NULL;
+  Code* interrupt_code = NULL;
   InterruptStub interrupt_stub;
-  bool found_code = interrupt_stub.FindCodeInCache(&stack_check_code, isolate_);
+  bool found_code = interrupt_stub.FindCodeInCache(&interrupt_code, isolate_);
   if (found_code) {
     Code* replacement_code =
         isolate_->builtins()->builtin(Builtins::kOnStackReplacement);
     Code* unoptimized_code = shared->code();
-    Deoptimizer::PatchStackCheckCode(unoptimized_code,
-                                     stack_check_code,
-                                     replacement_code);
+    Deoptimizer::PatchInterruptCode(
+        unoptimized_code, interrupt_code, replacement_code);
   }
 }
 
@@ -296,9 +275,11 @@ void RuntimeProfiler::OptimizeNow() {
          function->IsMarkedForParallelRecompilation() ||
          function->IsOptimized())) {
       int nesting = shared_code->allow_osr_at_loop_nesting_level();
-      if (nesting == 0) AttemptOnStackReplacement(function);
-      int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker);
-      shared_code->set_allow_osr_at_loop_nesting_level(new_nesting);
+      if (nesting < Code::kMaxLoopNestingMarker) {
+        int new_nesting = nesting + 1;
+        shared_code->set_allow_osr_at_loop_nesting_level(new_nesting);
+        AttemptOnStackReplacement(function);
+      }
     }
 
     // Only record top-level code on top of the execution stack and
@@ -385,13 +366,9 @@ void RuntimeProfiler::OptimizeNow() {
 
 
 void RuntimeProfiler::SetUp() {
-  ASSERT(has_been_globally_set_up_);
   if (!FLAG_watch_ic_patching) {
     ClearSampleBuffer();
   }
-  // If the ticker hasn't already started, make sure to do so to get
-  // the ticks for the runtime profiler.
-  if (IsEnabled()) isolate_->logger()->EnsureTickerStarted();
 }
 
 
@@ -431,48 +408,6 @@ void RuntimeProfiler::UpdateSamplesAfterScavenge() {
 }
 
 
-void RuntimeProfiler::HandleWakeUp(Isolate* isolate) {
-  // The profiler thread must still be waiting.
-  ASSERT(NoBarrier_Load(&state_) >= 0);
-  // In IsolateEnteredJS we have already incremented the counter and
-  // undid the decrement done by the profiler thread. Increment again
-  // to get the right count of active isolates.
-  NoBarrier_AtomicIncrement(&state_, 1);
-  semaphore.Pointer()->Signal();
-}
-
-
-bool RuntimeProfiler::WaitForSomeIsolateToEnterJS() {
-  Atomic32 old_state = NoBarrier_CompareAndSwap(&state_, 0, -1);
-  ASSERT(old_state >= -1);
-  if (old_state != 0) return false;
-  semaphore.Pointer()->Wait();
-  return true;
-}
-
-
-void RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(Thread* thread) {
-  // Do a fake increment. If the profiler is waiting on the semaphore,
-  // the returned state is 0, which can be left as an initial state in
-  // case profiling is restarted later. If the profiler is not
-  // waiting, the increment will prevent it from waiting, but has to
-  // be undone after the profiler is stopped.
-  Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, 1);
-  ASSERT(new_state >= 0);
-  if (new_state == 0) {
-    // The profiler thread is waiting. Wake it up. It must check for
-    // stop conditions before attempting to wait again.
-    semaphore.Pointer()->Signal();
-  }
-  thread->Join();
-  // The profiler thread is now stopped. Undo the increment in case it
-  // was not waiting.
-  if (new_state != 0) {
-    NoBarrier_AtomicIncrement(&state_, -1);
-  }
-}
-
-
 void RuntimeProfiler::RemoveDeadSamples() {
   for (int i = 0; i < kSamplerWindowSize; i++) {
     Object* function = sampler_window_[i];
index 62c48c7..1bf9aa8 100644 (file)
@@ -43,13 +43,6 @@ class RuntimeProfiler {
  public:
   explicit RuntimeProfiler(Isolate* isolate);
 
-  static void GlobalSetUp();
-
-  static inline bool IsEnabled() {
-    ASSERT(has_been_globally_set_up_);
-    return enabled_;
-  }
-
   void OptimizeNow();
 
   void SetUp();
@@ -63,26 +56,6 @@ class RuntimeProfiler {
 
   // Rate limiting support.
 
-  // VM thread interface.
-  //
-  // Called by isolates when their states change.
-  static inline void IsolateEnteredJS(Isolate* isolate);
-  static inline void IsolateExitedJS(Isolate* isolate);
-
-  // Profiler thread interface.
-  //
-  // WaitForSomeIsolateToEnterJS():
-  // When no isolates are running JavaScript code for some time the
-  // profiler thread suspends itself by calling the wait function. The
-  // wait function returns true after it waited or false immediately.
-  // While the function was waiting the profiler may have been
-  // disabled so it *must check* whether it is allowed to continue.
-  static bool WaitForSomeIsolateToEnterJS();
-
-  // Stops the runtime profiler thread when profiling support is being
-  // turned off.
-  static void StopRuntimeProfilerThreadBeforeShutdown(Thread* thread);
-
   void UpdateSamplesAfterScavenge();
   void RemoveDeadSamples();
   void UpdateSamplesAfterCompact(ObjectVisitor* visitor);
@@ -92,8 +65,6 @@ class RuntimeProfiler {
  private:
   static const int kSamplerWindowSize = 16;
 
-  static void HandleWakeUp(Isolate* isolate);
-
   void Optimize(JSFunction* function, const char* reason);
 
   void ClearSampleBuffer();
@@ -116,39 +87,8 @@ class RuntimeProfiler {
 
   bool any_ic_changed_;
   bool code_generated_;
-
-  // Possible state values:
-  //   -1            => the profiler thread is waiting on the semaphore
-  //   0 or positive => the number of isolates running JavaScript code.
-  static Atomic32 state_;
-
-#ifdef DEBUG
-  static bool has_been_globally_set_up_;
-#endif
-  static bool enabled_;
 };
 
-
-// Implementation of RuntimeProfiler inline functions.
-
-void RuntimeProfiler::IsolateEnteredJS(Isolate* isolate) {
-  Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, 1);
-  if (new_state == 0) {
-    // Just incremented from -1 to 0. -1 can only be set by the
-    // profiler thread before it suspends itself and starts waiting on
-    // the semaphore.
-    HandleWakeUp(isolate);
-  }
-  ASSERT(new_state >= 0);
-}
-
-
-void RuntimeProfiler::IsolateExitedJS(Isolate* isolate) {
-  Atomic32 new_state = NoBarrier_AtomicIncrement(&state_, -1);
-  ASSERT(new_state >= 0);
-  USE(new_state);
-}
-
 } }  // namespace v8::internal
 
 #endif  // V8_RUNTIME_PROFILER_H_
index 78efc8d..7e7d6d5 100644 (file)
@@ -43,6 +43,7 @@
 #include "deoptimizer.h"
 #include "date.h"
 #include "execution.h"
+#include "full-codegen.h"
 #include "global-handles.h"
 #include "isolate-inl.h"
 #include "jsregexp.h"
@@ -60,6 +61,7 @@
 #include "string-search.h"
 #include "stub-cache.h"
 #include "uri.h"
+#include "v8conversions.h"
 #include "v8threads.h"
 #include "vm-state-inl.h"
 
@@ -637,19 +639,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
 }
 
 
-static size_t ArrayBufferAllocatedLength(Isolate* isolate,
-                                         JSArrayBuffer* buffer) {
-  NoHandleAllocation hc(isolate);
-  Object* byte_length = buffer->byte_length();
-  if (byte_length->IsSmi()) {
-    return Smi::cast(byte_length)->value();
-  } else {
-    double value = HeapNumber::cast(byte_length)->value();
-    return static_cast<size_t>(value);
-  }
-}
-
-
 static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
                                     Persistent<Value> object,
                                     void* data) {
@@ -657,8 +646,8 @@ static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
   HandleScope scope(isolate);
   Handle<Object> internal_object = Utils::OpenHandle(*object);
 
-  size_t allocated_length = ArrayBufferAllocatedLength(
-      isolate, JSArrayBuffer::cast(*internal_object));
+  size_t allocated_length = NumberToSize(
+      isolate, JSArrayBuffer::cast(*internal_object)->byte_length());
   isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
       -static_cast<intptr_t>(allocated_length));
   if (data != NULL)
@@ -743,12 +732,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
   CONVERT_DOUBLE_ARG_CHECKED(first, 2);
   size_t start = static_cast<size_t>(first);
-  size_t target_length = ArrayBufferAllocatedLength(isolate, *target);
+  size_t target_length = NumberToSize(isolate, target->byte_length());
 
   if (target_length == 0)
     return isolate->heap()->undefined_value();
 
-  ASSERT(ArrayBufferAllocatedLength(isolate, *source) - target_length >= start);
+  ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start);
   uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
   uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
   CopyBytes(target_data, source_data + start, target_length);
@@ -756,6 +745,116 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
 }
 
 
+enum TypedArrayId {
+  // arrayIds below should be synchromized with typedarray.js natives.
+  ARRAY_ID_UINT8 = 1,
+  ARRAY_ID_INT8 = 2,
+  ARRAY_ID_UINT16 = 3,
+  ARRAY_ID_INT16 = 4,
+  ARRAY_ID_UINT32 = 5,
+  ARRAY_ID_INT32 = 6,
+  ARRAY_ID_FLOAT32 = 7,
+  ARRAY_ID_FLOAT64 = 8
+};
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
+  HandleScope scope(isolate);
+  ASSERT(args.length() == 5);
+  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
+  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
+  CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
+
+  ExternalArrayType arrayType;
+  ElementsKind elementsKind;
+  size_t elementSize;
+  switch (arrayId) {
+    case ARRAY_ID_UINT8:
+      elementsKind = EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
+      arrayType = kExternalUnsignedByteArray;
+      elementSize = 1;
+      break;
+    case ARRAY_ID_INT8:
+      elementsKind = EXTERNAL_BYTE_ELEMENTS;
+      arrayType = kExternalByteArray;
+      elementSize = 1;
+      break;
+    case ARRAY_ID_UINT16:
+      elementsKind = EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
+      arrayType = kExternalUnsignedShortArray;
+      elementSize = 2;
+      break;
+    case ARRAY_ID_INT16:
+      elementsKind = EXTERNAL_SHORT_ELEMENTS;
+      arrayType = kExternalShortArray;
+      elementSize = 2;
+      break;
+    case ARRAY_ID_UINT32:
+      elementsKind = EXTERNAL_UNSIGNED_INT_ELEMENTS;
+      arrayType = kExternalUnsignedIntArray;
+      elementSize = 4;
+      break;
+    case ARRAY_ID_INT32:
+      elementsKind = EXTERNAL_INT_ELEMENTS;
+      arrayType = kExternalIntArray;
+      elementSize = 4;
+      break;
+    case ARRAY_ID_FLOAT32:
+      elementsKind = EXTERNAL_FLOAT_ELEMENTS;
+      arrayType = kExternalFloatArray;
+      elementSize = 4;
+      break;
+    case ARRAY_ID_FLOAT64:
+      elementsKind = EXTERNAL_DOUBLE_ELEMENTS;
+      arrayType = kExternalDoubleArray;
+      elementSize = 8;
+      break;
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+
+  holder->set_buffer(*buffer);
+  holder->set_byte_offset(*byte_offset_object);
+  holder->set_byte_length(*byte_length_object);
+
+  size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
+  size_t byte_length = NumberToSize(isolate, *byte_length_object);
+  ASSERT(byte_length % elementSize == 0);
+  size_t length = byte_length / elementSize;
+
+  Handle<Object> length_obj =
+      isolate->factory()->NewNumber(static_cast<double>(length));
+  holder->set_length(*length_obj);
+  Handle<ExternalArray> elements =
+      isolate->factory()->NewExternalArray(
+          static_cast<int>(length), arrayType,
+          static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
+  Handle<Map> map =
+      isolate->factory()->GetElementsTransitionMap(holder, elementsKind);
+  holder->set_map(*map);
+  holder->set_elements(*elements);
+  return isolate->heap()->undefined_value();
+}
+
+
+#define TYPED_ARRAY_GETTER(getter, accessor) \
+  RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
+    HandleScope scope(isolate);                                   \
+    ASSERT(args.length() == 1);                                   \
+    CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);          \
+    return holder->accessor();                                    \
+  }
+
+TYPED_ARRAY_GETTER(Buffer, buffer)
+TYPED_ARRAY_GETTER(ByteLength, byte_length)
+TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
+TYPED_ARRAY_GETTER(Length, length)
+
+#undef TYPED_ARRAY_GETTER
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
   HandleScope scope(isolate);
   ASSERT(args.length() == 1);
@@ -956,8 +1055,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
   NoHandleAllocation ha(isolate);
   ASSERT(args.length() == 1);
-  CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
-  Object* obj = input_obj;
+  CONVERT_ARG_CHECKED(Object, obj, 0);
   // We don't expect access checks to be needed on JSProxy objects.
   ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
   do {
@@ -975,12 +1073,43 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
 }
 
 
+static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate,
+                                                       Object* receiver) {
+  Object* current = receiver->GetPrototype(isolate);
+  while (current->IsJSObject() &&
+         JSObject::cast(current)->map()->is_hidden_prototype()) {
+    current = current->GetPrototype(isolate);
+  }
+  return current;
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
   NoHandleAllocation ha(isolate);
   ASSERT(args.length() == 2);
-  CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
   CONVERT_ARG_CHECKED(Object, prototype, 1);
-  return input_obj->SetPrototype(prototype, true);
+  if (FLAG_harmony_observation && obj->map()->is_observed()) {
+    HandleScope scope(isolate);
+    Handle<JSObject> receiver(obj);
+    Handle<Object> value(prototype, isolate);
+    Handle<Object> old_value(
+        GetPrototypeSkipHiddenPrototypes(isolate, *receiver), isolate);
+
+    MaybeObject* result = receiver->SetPrototype(*value, true);
+    Handle<Object> hresult;
+    if (!result->ToHandle(&hresult, isolate)) return result;
+
+    Handle<Object> new_value(
+        GetPrototypeSkipHiddenPrototypes(isolate, *receiver), isolate);
+    if (!new_value->SameValue(*old_value)) {
+      JSObject::EnqueueChangeRecord(receiver, "prototype",
+                                    isolate->factory()->proto_string(),
+                                    old_value);
+    }
+    return *hresult;
+  }
+  return obj->SetPrototype(prototype, true);
 }
 
 
@@ -1918,6 +2047,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_IsClassicModeFunction) {
+  NoHandleAllocation ha(isolate);
+  ASSERT(args.length() == 1);
+  CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
+  if (!callable->IsJSFunction()) {
+    HandleScope scope(isolate);
+    bool threw = false;
+    Handle<Object> delegate =
+        Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
+    if (threw) return Failure::Exception();
+    callable = JSFunction::cast(*delegate);
+  }
+  JSFunction* function = JSFunction::cast(callable);
+  SharedFunctionInfo* shared = function->shared();
+  return isolate->heap()->ToBoolean(shared->is_classic_mode());
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
   NoHandleAllocation ha(isolate);
   ASSERT(args.length() == 1);
@@ -2243,6 +2390,31 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) {
+  NoHandleAllocation ha(isolate);
+  ASSERT(args.length() == 0);
+  JavaScriptFrameIterator it(isolate);
+  JavaScriptFrame* frame = it.frame();
+  JSFunction* function = JSFunction::cast(frame->function());
+  RUNTIME_ASSERT(function->shared()->is_generator());
+
+  JSGeneratorObject* generator;
+  if (frame->IsConstructor()) {
+    generator = JSGeneratorObject::cast(frame->receiver());
+  } else {
+    MaybeObject* maybe_generator =
+        isolate->heap()->AllocateJSGeneratorObject(function);
+    if (!maybe_generator->To(&generator)) return maybe_generator;
+  }
+  generator->set_function(function);
+  generator->set_context(isolate->heap()->undefined_value());
+  generator->set_continuation(0);
+  generator->set_operand_stack(isolate->heap()->empty_fixed_array());
+
+  return generator;
+}
+
+
 MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
                                                  Object* char_code) {
   uint32_t code;
@@ -3898,6 +4070,33 @@ MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
 }
 
 
+MaybeObject* Runtime::HasObjectProperty(Isolate* isolate,
+                                        Handle<JSReceiver> object,
+                                        Handle<Object> key) {
+  HandleScope scope(isolate);
+
+  // Check if the given key is an array index.
+  uint32_t index;
+  if (key->ToArrayIndex(&index)) {
+    return isolate->heap()->ToBoolean(object->HasElement(index));
+  }
+
+  // Convert the key to a name - possibly by calling back into JavaScript.
+  Handle<Name> name;
+  if (key->IsName()) {
+    name = Handle<Name>::cast(key);
+  } else {
+    bool has_pending_exception = false;
+    Handle<Object> converted =
+        Execution::ToString(key, &has_pending_exception);
+    if (has_pending_exception) return Failure::Exception();
+    name = Handle<Name>::cast(converted);
+  }
+
+  return isolate->heap()->ToBoolean(object->HasProperty(*name));
+}
+
+
 MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
                                         Handle<Object> object,
                                         Handle<Object> key) {
@@ -4109,14 +4308,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
     if (callback->IsAccessorInfo()) {
       return isolate->heap()->undefined_value();
     }
-    // TODO(mstarzinger): The __proto__ property should actually be a real
-    // JavaScript accessor instead of a foreign callback. But for now we just
-    // avoid changing the writability and configurability attribute of this
-    // property.
-    Handle<Name> proto_string = isolate->factory()->proto_string();
-    if (callback->IsForeign() && proto_string->Equals(*name)) {
-      attr = static_cast<PropertyAttributes>(attr & ~(READ_ONLY | DONT_DELETE));
-    }
     // Avoid redefining foreign callback as data property, just use the stored
     // setter to update the value instead.
     // TODO(mstarzinger): So far this only works if property attributes don't
@@ -4323,9 +4514,10 @@ MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
 }
 
 
-MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
-                                                Handle<JSReceiver> receiver,
-                                                Handle<Object> key) {
+MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate,
+                                           Handle<JSReceiver> receiver,
+                                           Handle<Object> key,
+                                           JSReceiver::DeleteMode mode) {
   HandleScope scope(isolate);
 
   // Check if the given key is an array index.
@@ -4341,7 +4533,7 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
       return isolate->heap()->true_value();
     }
 
-    return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
+    return receiver->DeleteElement(index, mode);
   }
 
   Handle<Name> name;
@@ -4356,7 +4548,7 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
   }
 
   if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
-  return receiver->DeleteProperty(*name, JSReceiver::FORCE_DELETION);
+  return receiver->DeleteProperty(*name, mode);
 }
 
 
@@ -4607,7 +4799,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
     // Fast case: either the key is a real named property or it is not
     // an array index and there are no interceptors or hidden
     // prototypes.
-    if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
+    if (object->HasRealNamedProperty(isolate, key))
+      return isolate->heap()->true_value();
     Map* map = object->map();
     if (!key_is_array_index &&
         !map->has_named_interceptor() &&
@@ -7568,9 +7761,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
       unoptimized->kind() == Code::FUNCTION) {
     CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
     if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) {
-      isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
-      unoptimized->set_allow_osr_at_loop_nesting_level(
-          Code::kMaxLoopNestingMarker);
+      for (int i = 0; i <= Code::kMaxLoopNestingMarker; i++) {
+        unoptimized->set_allow_osr_at_loop_nesting_level(i);
+        isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
+      }
     } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("parallel"))) {
       function->MarkForParallelRecompilation();
     }
@@ -7663,25 +7857,28 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
     ASSERT(frame->LookupCode() == *unoptimized);
     ASSERT(unoptimized->contains(frame->pc()));
 
-    // Use linear search of the unoptimized code's stack check table to find
+    // Use linear search of the unoptimized code's back edge table to find
     // the AST id matching the PC.
     Address start = unoptimized->instruction_start();
     unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
-    Address table_cursor = start + unoptimized->stack_check_table_offset();
+    Address table_cursor = start + unoptimized->back_edge_table_offset();
     uint32_t table_length = Memory::uint32_at(table_cursor);
     table_cursor += kIntSize;
+    uint8_t loop_depth = 0;
     for (unsigned i = 0; i < table_length; ++i) {
       // Table entries are (AST id, pc offset) pairs.
       uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
       if (pc_offset == target_pc_offset) {
         ast_id = BailoutId(static_cast<int>(Memory::uint32_at(table_cursor)));
+        loop_depth = Memory::uint8_at(table_cursor + 2 * kIntSize);
         break;
       }
-      table_cursor += 2 * kIntSize;
+      table_cursor += FullCodeGenerator::kBackEdgeEntrySize;
     }
     ASSERT(!ast_id.IsNone());
     if (FLAG_trace_osr) {
-      PrintF("[replacing on-stack at AST id %d in ", ast_id.ToInt());
+      PrintF("[replacing on-stack at AST id %d, loop depth %d in ",
+              ast_id.ToInt(), loop_depth);
       function->PrintName();
       PrintF("]\n");
     }
@@ -7709,18 +7906,18 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
     }
   }
 
-  // Revert to the original stack checks in the original unoptimized code.
+  // Revert to the original interrupt calls in the original unoptimized code.
   if (FLAG_trace_osr) {
-    PrintF("[restoring original stack checks in ");
+    PrintF("[restoring original interrupt calls in ");
     function->PrintName();
     PrintF("]\n");
   }
   InterruptStub interrupt_stub;
-  Handle<Code> check_code = interrupt_stub.GetCode(isolate);
+  Handle<Code> interrupt_code = interrupt_stub.GetCode(isolate);
   Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
-  Deoptimizer::RevertStackCheckCode(*unoptimized,
-                                    *check_code,
-                                    *replacement_code);
+  Deoptimizer::RevertInterruptCode(*unoptimized,
+                                   *interrupt_code,
+                                   *replacement_code);
 
   // Allow OSR only at nesting level zero again.
   unoptimized->set_allow_osr_at_loop_nesting_level(0);
@@ -8821,14 +9018,18 @@ class ArrayConcatVisitor {
       storage_(Handle<FixedArray>::cast(
           isolate->global_handles()->Create(*storage))),
       index_offset_(0u),
-      fast_elements_(fast_elements) { }
+      fast_elements_(fast_elements),
+      exceeds_array_limit_(false) { }
 
   ~ArrayConcatVisitor() {
     clear_storage();
   }
 
   void visit(uint32_t i, Handle<Object> elm) {
-    if (i >= JSObject::kMaxElementCount - index_offset_) return;
+    if (i > JSObject::kMaxElementCount - index_offset_) {
+      exceeds_array_limit_ = true;
+      return;
+    }
     uint32_t index = index_offset_ + i;
 
     if (fast_elements_) {
@@ -8863,6 +9064,10 @@ class ArrayConcatVisitor {
     }
   }
 
+  bool exceeds_array_limit() {
+    return exceeds_array_limit_;
+  }
+
   Handle<JSArray> ToArray() {
     Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
     Handle<Object> length =
@@ -8921,7 +9126,8 @@ class ArrayConcatVisitor {
   // Index after last seen index. Always less than or equal to
   // JSObject::kMaxElementCount.
   uint32_t index_offset_;
-  bool fast_elements_;
+  bool fast_elements_ : 1;
+  bool exceeds_array_limit_ : 1;
 };
 
 
@@ -9477,6 +9683,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
     }
   }
 
+  if (visitor.exceeds_array_limit()) {
+    return isolate->Throw(
+        *isolate->factory()->NewRangeError("invalid_array_length",
+                                           HandleVector<Object>(NULL, 0)));
+  }
   return *visitor.ToArray();
 }
 
@@ -10733,14 +10944,14 @@ class ScopeIterator {
           info.MarkAsEval();
           info.SetContext(Handle<Context>(function_->context()));
         }
-        if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
+        if (Parser::Parse(&info) && Scope::Analyze(&info)) {
           scope = info.function()->scope();
         }
         RetrieveScopeChain(scope, shared_info);
       } else {
         // Function code
         CompilationInfoWithZone info(shared_info);
-        if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
+        if (Parser::Parse(&info) && Scope::Analyze(&info)) {
           scope = info.function()->scope();
         }
         RetrieveScopeChain(scope, shared_info);
@@ -12015,11 +12226,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
   NoHandleAllocation ha(isolate);
   ASSERT(args.length() == 1);
-
   CONVERT_ARG_CHECKED(JSObject, obj, 0);
-
-  // Use the __proto__ accessor.
-  return Accessors::ObjectPrototype.getter(obj, NULL);
+  return GetPrototypeSkipHiddenPrototypes(isolate, obj);
 }
 
 
@@ -12786,7 +12994,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
   String::FlatContent format_content = format->GetFlatContent();
   RUNTIME_ASSERT(format_content.IsAscii());
   Vector<const uint8_t> chars = format_content.ToOneByteVector();
-  LOGGER->LogRuntime(isolate, Vector<const char>::cast(chars), elms);
+  isolate->logger()->LogRuntime(Vector<const char>::cast(chars), elms);
   return isolate->heap()->undefined_value();
 }
 
index b16acd1..cbf70e9 100644 (file)
@@ -64,6 +64,7 @@ namespace internal {
   F(ToFastProperties, 1, 1) \
   F(FinishArrayPrototypeSetup, 1, 1) \
   F(SpecialArrayFunctions, 1, 1) \
+  F(IsClassicModeFunction, 1, 1) \
   F(GetDefaultReceiver, 1, 1) \
   \
   F(GetPrototype, 1, 1) \
@@ -218,6 +219,7 @@ namespace internal {
   F(NumberToExponential, 2, 1) \
   F(NumberToPrecision, 2, 1)
 
+
 #define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
   /* Reflection */ \
   F(FunctionSetInstanceClassName, 2, 1) \
@@ -294,6 +296,9 @@ namespace internal {
   F(CreateArrayLiteral, 3, 1) \
   F(CreateArrayLiteralShallow, 3, 1) \
   \
+  /* Harmony generators */ \
+  F(CreateJSGeneratorObject, 0, 1) \
+  \
   /* Harmony modules */ \
   F(IsJSModule, 1, 1) \
   \
@@ -346,6 +351,12 @@ namespace internal {
   F(ArrayBufferGetByteLength, 1, 1)\
   F(ArrayBufferSliceImpl, 3, 1) \
   \
+  F(TypedArrayInitialize, 5, 1) \
+  F(TypedArrayGetBuffer, 1, 1) \
+  F(TypedArrayGetByteLength, 1, 1) \
+  F(TypedArrayGetByteOffset, 1, 1) \
+  F(TypedArrayGetLength, 1, 1) \
+  \
   /* Statements */ \
   F(NewClosure, 3, 1) \
   F(NewObject, 1, 1) \
@@ -698,7 +709,13 @@ class Runtime : public AllStatic {
       Handle<Object> value,
       PropertyAttributes attr);
 
-  MUST_USE_RESULT static MaybeObject* ForceDeleteObjectProperty(
+  MUST_USE_RESULT static MaybeObject* DeleteObjectProperty(
+      Isolate* isolate,
+      Handle<JSReceiver> object,
+      Handle<Object> key,
+      JSReceiver::DeleteMode mode);
+
+  MUST_USE_RESULT static MaybeObject* HasObjectProperty(
       Isolate* isolate,
       Handle<JSReceiver> object,
       Handle<Object> key);
diff --git a/deps/v8/src/sampler.cc b/deps/v8/src/sampler.cc
new file mode 100644 (file)
index 0000000..948b054
--- /dev/null
@@ -0,0 +1,694 @@
+// Copyright 2013 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.
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
+    || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__)
+
+#define USE_SIGNALS
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+#if !defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)
+#include <ucontext.h>
+#endif
+#include <unistd.h>
+
+// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
+// Old versions of the C library <signal.h> didn't define the type.
+#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
+    defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
+#include <asm/sigcontext.h>
+#endif
+
+#elif defined(__MACH__)
+
+#include <mach/mach.h>
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+#include "win32-headers.h"
+
+#endif
+
+#include "v8.h"
+
+#include "frames-inl.h"
+#include "log.h"
+#include "platform.h"
+#include "simulator.h"
+#include "v8threads.h"
+
+
+#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
+
+// Not all versions of Android's C library provide ucontext_t.
+// Detect this and provide custom but compatible definitions. Note that these
+// follow the GLibc naming convention to access register values from
+// mcontext_t.
+//
+// See http://code.google.com/p/android/issues/detail?id=34784
+
+#if defined(__arm__)
+
+typedef struct sigcontext mcontext_t;
+
+typedef struct ucontext {
+  uint32_t uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  mcontext_t uc_mcontext;
+  // Other fields are not used by V8, don't define them here.
+} ucontext_t;
+
+#elif defined(__mips__)
+// MIPS version of sigcontext, for Android bionic.
+typedef struct {
+  uint32_t regmask;
+  uint32_t status;
+  uint64_t pc;
+  uint64_t gregs[32];
+  uint64_t fpregs[32];
+  uint32_t acx;
+  uint32_t fpc_csr;
+  uint32_t fpc_eir;
+  uint32_t used_math;
+  uint32_t dsp;
+  uint64_t mdhi;
+  uint64_t mdlo;
+  uint32_t hi1;
+  uint32_t lo1;
+  uint32_t hi2;
+  uint32_t lo2;
+  uint32_t hi3;
+  uint32_t lo3;
+} mcontext_t;
+
+typedef struct ucontext {
+  uint32_t uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  mcontext_t uc_mcontext;
+  // Other fields are not used by V8, don't define them here.
+} ucontext_t;
+
+#elif defined(__i386__)
+// x86 version for Android.
+typedef struct {
+  uint32_t gregs[19];
+  void* fpregs;
+  uint32_t oldmask;
+  uint32_t cr2;
+} mcontext_t;
+
+typedef uint32_t kernel_sigset_t[2];  // x86 kernel uses 64-bit signal masks
+typedef struct ucontext {
+  uint32_t uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  mcontext_t uc_mcontext;
+  // Other fields are not used by V8, don't define them here.
+} ucontext_t;
+enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
+#endif
+
+#endif  // __ANDROID__ && !defined(__BIONIC_HAVE_UCONTEXT_T)
+
+
+namespace v8 {
+namespace internal {
+
+#if defined(USE_SIGNALS)
+
+class Sampler::PlatformData : public Malloced {
+ public:
+  PlatformData()
+      : vm_tid_(pthread_self()),
+        profiled_thread_id_(ThreadId::Current()) {}
+
+  pthread_t vm_tid() const { return vm_tid_; }
+  ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+  pthread_t vm_tid_;
+  ThreadId profiled_thread_id_;
+};
+
+
+class SignalHandler : public AllStatic {
+ public:
+  static inline void EnsureInstalled() {
+    if (signal_handler_installed_) return;
+    struct sigaction sa;
+    sa.sa_sigaction = &HandleProfilerSignal;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_RESTART | SA_SIGINFO;
+    signal_handler_installed_ =
+        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
+  }
+
+  static inline void Restore() {
+    if (signal_handler_installed_) {
+      sigaction(SIGPROF, &old_signal_handler_, 0);
+      signal_handler_installed_ = false;
+    }
+  }
+
+  static inline bool Installed() {
+    return signal_handler_installed_;
+  }
+
+ private:
+  static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
+  static bool signal_handler_installed_;
+  static struct sigaction old_signal_handler_;
+};
+
+struct sigaction SignalHandler::old_signal_handler_;
+bool SignalHandler::signal_handler_installed_ = false;
+
+
+void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
+                                         void* context) {
+#if defined(__native_client__)
+  // As Native Client does not support signal handling, profiling
+  // is disabled.
+  return;
+#else
+  USE(info);
+  if (signal != SIGPROF) return;
+  Isolate* isolate = Isolate::UncheckedCurrent();
+  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
+    // We require a fully initialized and entered isolate.
+    return;
+  }
+  if (v8::Locker::IsActive() &&
+      !isolate->thread_manager()->IsLockedByCurrentThread()) {
+    return;
+  }
+
+  Sampler* sampler = isolate->logger()->sampler();
+  if (sampler == NULL || !sampler->IsActive()) return;
+
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+  ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+  Isolate::PerIsolateThreadData* per_thread_data = isolate->
+      FindPerThreadDataForThread(thread_id);
+  if (!per_thread_data) return;
+  Simulator* sim = per_thread_data->simulator();
+  // Check if there is active simulator before allocating TickSample.
+  if (!sim) return;
+#endif
+#endif  // USE_SIMULATOR
+
+  TickSample sample_obj;
+  TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+  if (sample == NULL) sample = &sample_obj;
+
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+  sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+  sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+  sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+  sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+  sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+  sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif  // V8_TARGET_ARCH_*
+#else
+  // Extracting the sample from the context is extremely machine dependent.
+  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+  mcontext_t& mcontext = ucontext->uc_mcontext;
+  sample->state = isolate->current_vm_state();
+#if defined(__linux__) || defined(__ANDROID__)
+#if V8_HOST_ARCH_IA32
+  sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
+  sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
+  sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
+#elif V8_HOST_ARCH_X64
+  sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
+  sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
+  sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
+#elif V8_HOST_ARCH_ARM
+#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
+    (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+  // Old GLibc ARM versions used a gregs[] array to access the register
+  // values from mcontext_t.
+  sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
+  sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
+  sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
+#else
+  sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
+  sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
+  sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
+#endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
+        // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#elif V8_HOST_ARCH_MIPS
+  sample->pc = reinterpret_cast<Address>(mcontext.pc);
+  sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]);
+  sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]);
+#endif  // V8_HOST_ARCH_*
+#elif defined(__FreeBSD__)
+#if V8_HOST_ARCH_IA32
+  sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
+  sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
+  sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
+#elif V8_HOST_ARCH_X64
+  sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
+  sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
+  sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
+#elif V8_HOST_ARCH_ARM
+  sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
+  sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
+  sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
+#endif  // V8_HOST_ARCH_*
+#elif defined(__NetBSD__)
+#if V8_HOST_ARCH_IA32
+  sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
+  sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
+  sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
+#elif V8_HOST_ARCH_X64
+  sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
+  sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
+  sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
+#endif  // V8_HOST_ARCH_*
+#elif defined(__OpenBSD__)
+  USE(mcontext);
+#if V8_HOST_ARCH_IA32
+  sample->pc = reinterpret_cast<Address>(ucontext->sc_eip);
+  sample->sp = reinterpret_cast<Address>(ucontext->sc_esp);
+  sample->fp = reinterpret_cast<Address>(ucontext->sc_ebp);
+#elif V8_HOST_ARCH_X64
+  sample->pc = reinterpret_cast<Address>(ucontext->sc_rip);
+  sample->sp = reinterpret_cast<Address>(ucontext->sc_rsp);
+  sample->fp = reinterpret_cast<Address>(ucontext->sc_rbp);
+#endif  // V8_HOST_ARCH_*
+#elif defined(__sun)
+  sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
+  sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
+  sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
+#endif  // __sun
+#endif  // USE_SIMULATOR
+
+  sampler->SampleStack(sample);
+  sampler->Tick(sample);
+#endif  // __native_client__
+}
+
+#elif defined(__MACH__)
+class Sampler::PlatformData : public Malloced {
+ public:
+  PlatformData()
+      : profiled_thread_(mach_thread_self()),
+        profiled_thread_id_(ThreadId::Current()) {}
+
+  ~PlatformData() {
+    // Deallocate Mach port for thread.
+    mach_port_deallocate(mach_task_self(), profiled_thread_);
+  }
+
+  thread_act_t profiled_thread() { return profiled_thread_; }
+  ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+  // Note: for profiled_thread_ Mach primitives are used instead of PThread's
+  // because the latter doesn't provide thread manipulation primitives required.
+  // For details, consult "Mac OS X Internals" book, Section 7.3.
+  thread_act_t profiled_thread_;
+  ThreadId profiled_thread_id_;
+};
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+// ----------------------------------------------------------------------------
+// Win32 profiler support. On Cygwin we use the same sampler implementation as
+// on Win32.
+
+class Sampler::PlatformData : public Malloced {
+ public:
+  // Get a handle to the calling thread. This is the thread that we are
+  // going to profile. We need to make a copy of the handle because we are
+  // going to use it in the sampler thread. Using GetThreadHandle() will
+  // not work in this case. We're using OpenThread because DuplicateHandle
+  // for some reason doesn't work in Chrome's sandbox.
+  PlatformData()
+      : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
+                                    THREAD_SUSPEND_RESUME |
+                                    THREAD_QUERY_INFORMATION,
+                                    false,
+                                    GetCurrentThreadId())),
+        profiled_thread_id_(ThreadId::Current()) {}
+
+  ~PlatformData() {
+    if (profiled_thread_ != NULL) {
+      CloseHandle(profiled_thread_);
+      profiled_thread_ = NULL;
+    }
+  }
+
+  HANDLE profiled_thread() { return profiled_thread_; }
+  ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+  HANDLE profiled_thread_;
+  ThreadId profiled_thread_id_;
+};
+
+#endif
+
+
+class SamplerThread : public Thread {
+ public:
+  static const int kSamplerThreadStackSize = 64 * KB;
+
+  explicit SamplerThread(int interval)
+      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
+        interval_(interval) {}
+
+  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
+  static void TearDown() { delete mutex_; }
+
+  static void AddActiveSampler(Sampler* sampler) {
+    bool need_to_start = false;
+    ScopedLock lock(mutex_);
+    if (instance_ == NULL) {
+      // Start a thread that will send SIGPROF signal to VM threads,
+      // when CPU profiling will be enabled.
+      instance_ = new SamplerThread(sampler->interval());
+      need_to_start = true;
+    }
+
+    ASSERT(sampler->IsActive());
+    ASSERT(!instance_->active_samplers_.Contains(sampler));
+    ASSERT(instance_->interval_ == sampler->interval());
+    instance_->active_samplers_.Add(sampler);
+
+#if defined(USE_SIGNALS)
+    SignalHandler::EnsureInstalled();
+#endif
+    if (need_to_start) instance_->StartSynchronously();
+  }
+
+  static void RemoveActiveSampler(Sampler* sampler) {
+    SamplerThread* instance_to_remove = NULL;
+    {
+      ScopedLock lock(mutex_);
+
+      ASSERT(sampler->IsActive());
+      bool removed = instance_->active_samplers_.RemoveElement(sampler);
+      ASSERT(removed);
+      USE(removed);
+
+      // We cannot delete the instance immediately as we need to Join() the
+      // thread but we are holding mutex_ and the thread may try to acquire it.
+      if (instance_->active_samplers_.is_empty()) {
+        instance_to_remove = instance_;
+        instance_ = NULL;
+#if defined(USE_SIGNALS)
+        SignalHandler::Restore();
+#endif
+      }
+    }
+
+    if (!instance_to_remove) return;
+    instance_to_remove->Join();
+    delete instance_to_remove;
+  }
+
+  // Implement Thread::Run().
+  virtual void Run() {
+    while (true) {
+      {
+        ScopedLock lock(mutex_);
+        if (active_samplers_.is_empty()) break;
+        // When CPU profiling is enabled both JavaScript and C++ code is
+        // profiled. We must not suspend.
+        for (int i = 0; i < active_samplers_.length(); ++i) {
+          Sampler* sampler = active_samplers_.at(i);
+          if (!sampler->isolate()->IsInitialized()) continue;
+          if (!sampler->IsProfiling()) continue;
+          SampleContext(sampler);
+        }
+      }
+      OS::Sleep(interval_);
+    }
+  }
+
+ private:
+#if defined(USE_SIGNALS)
+
+  void SampleContext(Sampler* sampler) {
+    if (!SignalHandler::Installed()) return;
+    pthread_t tid = sampler->platform_data()->vm_tid();
+    int result = pthread_kill(tid, SIGPROF);
+    USE(result);
+    ASSERT(result == 0);
+  }
+
+#elif defined(__MACH__)
+
+  void SampleContext(Sampler* sampler) {
+    thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
+    Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+    ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+    Isolate::PerIsolateThreadData* per_thread_data = isolate->
+        FindPerThreadDataForThread(thread_id);
+    if (!per_thread_data) return;
+    Simulator* sim = per_thread_data->simulator();
+    // Check if there is active simulator before allocating TickSample.
+    if (!sim) return;
+#endif
+#endif  // USE_SIMULATOR
+    TickSample sample_obj;
+    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+    if (sample == NULL) sample = &sample_obj;
+
+    if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
+
+#if V8_HOST_ARCH_X64
+    thread_state_flavor_t flavor = x86_THREAD_STATE64;
+    x86_thread_state64_t state;
+    mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
+#if __DARWIN_UNIX03
+#define REGISTER_FIELD(name) __r ## name
+#else
+#define REGISTER_FIELD(name) r ## name
+#endif  // __DARWIN_UNIX03
+#elif V8_HOST_ARCH_IA32
+    thread_state_flavor_t flavor = i386_THREAD_STATE;
+    i386_thread_state_t state;
+    mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+#if __DARWIN_UNIX03
+#define REGISTER_FIELD(name) __e ## name
+#else
+#define REGISTER_FIELD(name) e ## name
+#endif  // __DARWIN_UNIX03
+#else
+#error Unsupported Mac OS X host architecture.
+#endif  // V8_HOST_ARCH
+
+    if (thread_get_state(profiled_thread,
+                         flavor,
+                         reinterpret_cast<natural_t*>(&state),
+                         &count) == KERN_SUCCESS) {
+      sample->state = isolate->current_vm_state();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+      sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
+      sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
+      sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
+#endif  // USE_SIMULATOR
+#undef REGISTER_FIELD
+      sampler->SampleStack(sample);
+      sampler->Tick(sample);
+    }
+    thread_resume(profiled_thread);
+  }
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+  void SampleContext(Sampler* sampler) {
+    HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
+    if (profiled_thread == NULL) return;
+
+    // Context used for sampling the register state of the profiled thread.
+    CONTEXT context;
+    memset(&context, 0, sizeof(context));
+
+    Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+    ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+    Isolate::PerIsolateThreadData* per_thread_data = isolate->
+        FindPerThreadDataForThread(thread_id);
+    if (!per_thread_data) return;
+    Simulator* sim = per_thread_data->simulator();
+    // Check if there is active simulator before allocating TickSample.
+    if (!sim) return;
+#endif
+#endif  // USE_SIMULATOR
+    TickSample sample_obj;
+    TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+    if (sample == NULL) sample = &sample_obj;
+
+    static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
+    if (SuspendThread(profiled_thread) == kSuspendFailed) return;
+    sample->state = isolate->current_vm_state();
+
+    context.ContextFlags = CONTEXT_FULL;
+    if (GetThreadContext(profiled_thread, &context) != 0) {
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+      sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+      sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+      sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+#if V8_HOST_ARCH_X64
+      sample->pc = reinterpret_cast<Address>(context.Rip);
+      sample->sp = reinterpret_cast<Address>(context.Rsp);
+      sample->fp = reinterpret_cast<Address>(context.Rbp);
+#else
+      sample->pc = reinterpret_cast<Address>(context.Eip);
+      sample->sp = reinterpret_cast<Address>(context.Esp);
+      sample->fp = reinterpret_cast<Address>(context.Ebp);
+#endif
+#endif  // USE_SIMULATOR
+      sampler->SampleStack(sample);
+      sampler->Tick(sample);
+    }
+    ResumeThread(profiled_thread);
+  }
+
+#endif  // USE_SIGNALS
+
+
+  // Protects the process wide state below.
+  static Mutex* mutex_;
+  static SamplerThread* instance_;
+
+  const int interval_;
+  List<Sampler*> active_samplers_;
+
+  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
+};
+
+
+Mutex* SamplerThread::mutex_ = NULL;
+SamplerThread* SamplerThread::instance_ = NULL;
+
+
+//
+// StackTracer implementation
+//
+DISABLE_ASAN void TickSample::Trace(Isolate* isolate) {
+  ASSERT(isolate->IsInitialized());
+
+  // Avoid collecting traces while doing GC.
+  if (state == GC) return;
+
+  const Address js_entry_sp =
+      Isolate::js_entry_sp(isolate->thread_local_top());
+  if (js_entry_sp == 0) {
+    // Not executing JS now.
+    return;
+  }
+
+  external_callback = isolate->external_callback();
+
+  SafeStackTraceFrameIterator it(isolate, fp, sp, sp, js_entry_sp);
+  int i = 0;
+  while (!it.done() && i < TickSample::kMaxFramesCount) {
+    stack[i++] = it.frame()->pc();
+    it.Advance();
+  }
+  frames_count = i;
+}
+
+
+void Sampler::SetUp() {
+  SamplerThread::SetUp();
+}
+
+
+void Sampler::TearDown() {
+  SamplerThread::TearDown();
+}
+
+
+Sampler::Sampler(Isolate* isolate, int interval)
+    : isolate_(isolate),
+      interval_(interval),
+      profiling_(false),
+      active_(false),
+      samples_taken_(0) {
+  data_ = new PlatformData;
+}
+
+
+Sampler::~Sampler() {
+  ASSERT(!IsActive());
+  delete data_;
+}
+
+void Sampler::Start() {
+  ASSERT(!IsActive());
+  SetActive(true);
+  SamplerThread::AddActiveSampler(this);
+}
+
+
+void Sampler::Stop() {
+  ASSERT(IsActive());
+  SamplerThread::RemoveActiveSampler(this);
+  SetActive(false);
+}
+
+void Sampler::SampleStack(TickSample* sample) {
+  sample->Trace(isolate_);
+  if (++samples_taken_ < 0) samples_taken_ = 0;
+}
+
+} }  // namespace v8::internal
diff --git a/deps/v8/src/sampler.h b/deps/v8/src/sampler.h
new file mode 100644 (file)
index 0000000..a76d8b9
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2013 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_SAMPLER_H_
+#define V8_SAMPLER_H_
+
+#include "atomicops.h"
+#include "v8globals.h"
+
+namespace v8 {
+namespace internal {
+
+class Isolate;
+
+// ----------------------------------------------------------------------------
+// Sampler
+//
+// A sampler periodically samples the state of the VM and optionally
+// (if used for profiling) the program counter and stack pointer for
+// the thread that created it.
+
+// TickSample captures the information collected for each sample.
+struct TickSample {
+  TickSample()
+      : state(OTHER),
+        pc(NULL),
+        sp(NULL),
+        fp(NULL),
+        external_callback(NULL),
+        frames_count(0) {}
+  void Trace(Isolate* isolate);
+  StateTag state;  // The state of the VM.
+  Address pc;      // Instruction pointer.
+  Address sp;      // Stack pointer.
+  Address fp;      // Frame pointer.
+  Address external_callback;
+  static const int kMaxFramesCount = 64;
+  Address stack[kMaxFramesCount];  // Call stack.
+  int frames_count : 8;  // Number of captured frames.
+};
+
+class Sampler {
+ public:
+  // Initializes the Sampler support. Called once at VM startup.
+  static void SetUp();
+  static void TearDown();
+
+  // Initialize sampler.
+  Sampler(Isolate* isolate, int interval);
+  virtual ~Sampler();
+
+  Isolate* isolate() const { return isolate_; }
+  int interval() const { return interval_; }
+
+  // Performs stack sampling.
+  void SampleStack(TickSample* sample);
+
+  // This method is called for each sampling period with the current
+  // program counter.
+  virtual void Tick(TickSample* sample) = 0;
+
+  // Start and stop sampler.
+  void Start();
+  void Stop();
+
+  // Is the sampler used for profiling?
+  bool IsProfiling() const { return NoBarrier_Load(&profiling_) > 0; }
+  void IncreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, 1); }
+  void DecreaseProfilingDepth() { NoBarrier_AtomicIncrement(&profiling_, -1); }
+
+  // Whether the sampler is running (that is, consumes resources).
+  bool IsActive() const { return NoBarrier_Load(&active_); }
+
+  // Used in tests to make sure that stack sampling is performed.
+  int samples_taken() const { return samples_taken_; }
+  void ResetSamplesTaken() { samples_taken_ = 0; }
+
+  class PlatformData;
+  PlatformData* platform_data() const { return data_; }
+
+ private:
+  void SetActive(bool value) { NoBarrier_Store(&active_, value); }
+
+  Isolate* isolate_;
+  const int interval_;
+  Atomic32 profiling_;
+  Atomic32 active_;
+  PlatformData* data_;  // Platform specific data.
+  int samples_taken_;  // Counts stack samples taken.
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_SAMPLER_H_
index dd1bfb8..92418f7 100644 (file)
@@ -42,26 +42,6 @@ namespace v8 {
 namespace internal {
 
 
-// General collection of (multi-)bit-flags that can be passed to scanners and
-// parsers to signify their (initial) mode of operation.
-enum ParsingFlags {
-  kNoParsingFlags = 0,
-  // Embed LanguageMode values in parsing flags, i.e., equivalent to:
-  // CLASSIC_MODE = 0,
-  // STRICT_MODE,
-  // EXTENDED_MODE,
-  kLanguageModeMask = 0x03,
-  kAllowLazy = 0x04,
-  kAllowNativesSyntax = 0x08,
-  kAllowModules = 0x10,
-  kAllowGenerators = 0x20
-};
-
-STATIC_ASSERT((kLanguageModeMask & CLASSIC_MODE) == CLASSIC_MODE);
-STATIC_ASSERT((kLanguageModeMask & STRICT_MODE) == STRICT_MODE);
-STATIC_ASSERT((kLanguageModeMask & EXTENDED_MODE) == EXTENDED_MODE);
-
-
 // Returns the value (0 .. 15) of a hexadecimal character c.
 // If c is not a legal hexadecimal character, returns a value < 0.
 inline int HexValue(uc32 c) {
@@ -235,7 +215,7 @@ class LiteralBuffer {
 
   void ExpandBuffer() {
     Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
-    memcpy(new_store.start(), backing_store_.start(), position_);
+    OS::MemCopy(new_store.start(), backing_store_.start(), position_);
     backing_store_.Dispose();
     backing_store_ = new_store;
   }
index 4ac9d0e..10548f9 100644 (file)
@@ -197,6 +197,8 @@ void Scope::SetDefaults(ScopeType type,
   outer_scope_calls_non_strict_eval_ = false;
   inner_scope_calls_eval_ = false;
   force_eager_compilation_ = false;
+  force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
+      ? outer_scope->has_forced_context_allocation() : false;
   num_var_or_const_ = 0;
   num_stack_slots_ = 0;
   num_heap_slots_ = 0;
@@ -603,12 +605,18 @@ void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
     }
   }
 
-  // Collect temporaries which are always allocated on the stack.
+  // Collect temporaries which are always allocated on the stack, unless the
+  // context as a whole has forced context allocation.
   for (int i = 0; i < temps_.length(); i++) {
     Variable* var = temps_[i];
     if (var->is_used()) {
-      ASSERT(var->IsStackLocal());
-      stack_locals->Add(var, zone());
+      if (var->IsContextSlot()) {
+        ASSERT(has_forced_context_allocation());
+        context_locals->Add(var, zone());
+      } else {
+        ASSERT(var->IsStackLocal());
+        stack_locals->Add(var, zone());
+      }
     }
   }
 
@@ -1182,8 +1190,11 @@ bool Scope::MustAllocateInContext(Variable* var) {
   // an eval() call or a runtime with lookup), it must be allocated in the
   // context.
   //
-  // Exceptions: temporary variables are never allocated in a context;
-  // catch-bound variables are always allocated in a context.
+  // Exceptions: If the scope as a whole has forced context allocation, all
+  // variables will have context allocation, even temporaries.  Otherwise
+  // temporary variables are always stack-allocated.  Catch-bound variables are
+  // always context-allocated.
+  if (has_forced_context_allocation()) return true;
   if (var->mode() == TEMPORARY) return false;
   if (var->mode() == INTERNAL) return true;
   if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
index 3ca2dcf..66384a1 100644 (file)
@@ -269,6 +269,15 @@ class Scope: public ZoneObject {
     end_position_ = statement_pos;
   }
 
+  // In some cases we want to force context allocation for a whole scope.
+  void ForceContextAllocation() {
+    ASSERT(!already_resolved());
+    force_context_allocation_ = true;
+  }
+  bool has_forced_context_allocation() const {
+    return force_context_allocation_;
+  }
+
   // ---------------------------------------------------------------------------
   // Predicates.
 
@@ -494,6 +503,7 @@ class Scope: public ZoneObject {
   bool outer_scope_calls_non_strict_eval_;
   bool inner_scope_calls_eval_;
   bool force_eager_compilation_;
+  bool force_context_allocation_;
 
   // True if it doesn't need scope resolution (e.g., if the scope was
   // constructed based on a serialized scope info or a catch context).
index e0bcf4e..dc9ffd6 100644 (file)
@@ -311,7 +311,7 @@ int SnapshotByteSource::GetInt() {
 
 
 void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
-  memcpy(to, data_ + position_, number_of_bytes);
+  OS::MemCopy(to, data_ + position_, number_of_bytes);
   position_ += number_of_bytes;
 }
 
index f8e6a1e..e413bf1 100644 (file)
@@ -467,6 +467,11 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap,
   chunk->progress_bar_ = 0;
   chunk->high_water_mark_ = static_cast<int>(area_start - base);
   chunk->parallel_sweeping_ = 0;
+  chunk->available_in_small_free_list_ = 0;
+  chunk->available_in_medium_free_list_ = 0;
+  chunk->available_in_large_free_list_ = 0;
+  chunk->available_in_huge_free_list_ = 0;
+  chunk->non_available_small_blocks_ = 0;
   chunk->ResetLiveBytes();
   Bitmap::Clear(chunk);
   chunk->initialize_scan_on_scavenge(false);
@@ -697,6 +702,15 @@ MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t reserve_area_size,
 }
 
 
+void Page::ResetFreeListStatistics() {
+  non_available_small_blocks_ = 0;
+  available_in_small_free_list_ = 0;
+  available_in_medium_free_list_ = 0;
+  available_in_large_free_list_ = 0;
+  available_in_huge_free_list_ = 0;
+}
+
+
 Page* MemoryAllocator::AllocatePage(intptr_t size,
                                     PagedSpace* owner,
                                     Executability executable) {
@@ -1057,6 +1071,23 @@ int PagedSpace::CountTotalPages() {
 }
 
 
+void PagedSpace::ObtainFreeListStatistics(Page* page, SizeStats* sizes) {
+  sizes->huge_size_ = page->available_in_huge_free_list();
+  sizes->small_size_ = page->available_in_small_free_list();
+  sizes->medium_size_ = page->available_in_medium_free_list();
+  sizes->large_size_ = page->available_in_large_free_list();
+}
+
+
+void PagedSpace::ResetFreeListStatistics() {
+  PageIterator page_iterator(this);
+  while (page_iterator.has_next()) {
+    Page* page = page_iterator.next();
+    page->ResetFreeListStatistics();
+  }
+}
+
+
 void PagedSpace::ReleasePage(Page* page, bool unlink) {
   ASSERT(page->LiveBytes() == 0);
   ASSERT(AreaSize() == page->area_size());
@@ -2056,20 +2087,6 @@ void FreeListCategory::Reset() {
 }
 
 
-intptr_t FreeListCategory::CountFreeListItemsInList(Page* p) {
-  int sum = 0;
-  FreeListNode* n = top_;
-  while (n != NULL) {
-    if (Page::FromAddress(n->address()) == p) {
-      FreeSpace* free_space = reinterpret_cast<FreeSpace*>(n);
-      sum += free_space->Size();
-    }
-    n = n->next();
-  }
-  return sum;
-}
-
-
 intptr_t FreeListCategory::EvictFreeListItemsInList(Page* p) {
   int sum = 0;
   FreeListNode** n = &top_;
@@ -2170,20 +2187,28 @@ int FreeList::Free(Address start, int size_in_bytes) {
 
   FreeListNode* node = FreeListNode::FromAddress(start);
   node->set_size(heap_, size_in_bytes);
+  Page* page = Page::FromAddress(start);
 
   // Early return to drop too-small blocks on the floor.
-  if (size_in_bytes < kSmallListMin) return size_in_bytes;
+  if (size_in_bytes < kSmallListMin) {
+    page->add_non_available_small_blocks(size_in_bytes);
+    return size_in_bytes;
+  }
 
   // Insert other blocks at the head of a free list of the appropriate
   // magnitude.
   if (size_in_bytes <= kSmallListMax) {
     small_list_.Free(node, size_in_bytes);
+    page->add_available_in_small_free_list(size_in_bytes);
   } else if (size_in_bytes <= kMediumListMax) {
     medium_list_.Free(node, size_in_bytes);
+    page->add_available_in_medium_free_list(size_in_bytes);
   } else if (size_in_bytes <= kLargeListMax) {
     large_list_.Free(node, size_in_bytes);
+    page->add_available_in_large_free_list(size_in_bytes);
   } else {
     huge_list_.Free(node, size_in_bytes);
+    page->add_available_in_huge_free_list(size_in_bytes);
   }
 
   ASSERT(IsVeryLong() || available() == SumFreeLists());
@@ -2193,20 +2218,33 @@ int FreeList::Free(Address start, int size_in_bytes) {
 
 FreeListNode* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
   FreeListNode* node = NULL;
+  Page* page = NULL;
 
   if (size_in_bytes <= kSmallAllocationMax) {
     node = small_list_.PickNodeFromList(node_size);
-    if (node != NULL) return node;
+    if (node != NULL) {
+      page = Page::FromAddress(node->address());
+      page->add_available_in_small_free_list(-(*node_size));
+      return node;
+    }
   }
 
   if (size_in_bytes <= kMediumAllocationMax) {
     node = medium_list_.PickNodeFromList(node_size);
-    if (node != NULL) return node;
+    if (node != NULL) {
+      page = Page::FromAddress(node->address());
+      page->add_available_in_medium_free_list(-(*node_size));
+      return node;
+    }
   }
 
   if (size_in_bytes <= kLargeAllocationMax) {
     node = large_list_.PickNodeFromList(node_size);
-    if (node != NULL) return node;
+    if (node != NULL) {
+      page = Page::FromAddress(node->address());
+      page->add_available_in_large_free_list(-(*node_size));
+      return node;
+    }
   }
 
   int huge_list_available = huge_list_.available();
@@ -2216,7 +2254,10 @@ FreeListNode* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
     FreeListNode* cur_node = *cur;
     while (cur_node != NULL &&
            Page::FromAddress(cur_node->address())->IsEvacuationCandidate()) {
-      huge_list_available -= reinterpret_cast<FreeSpace*>(cur_node)->Size();
+      int size = reinterpret_cast<FreeSpace*>(cur_node)->Size();
+      huge_list_available -= size;
+      page = Page::FromAddress(cur_node->address());
+      page->add_available_in_huge_free_list(-size);
       cur_node = cur_node->next();
     }
 
@@ -2235,6 +2276,8 @@ FreeListNode* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
       *cur = node->next();
       *node_size = size;
       huge_list_available -= size;
+      page = Page::FromAddress(node->address());
+      page->add_available_in_huge_free_list(-size);
       break;
     }
   }
@@ -2322,27 +2365,17 @@ HeapObject* FreeList::Allocate(int size_in_bytes) {
 }
 
 
-void FreeList::CountFreeListItems(Page* p, SizeStats* sizes) {
-  sizes->huge_size_ = huge_list_.CountFreeListItemsInList(p);
-  if (sizes->huge_size_ < p->area_size()) {
-    sizes->small_size_ = small_list_.CountFreeListItemsInList(p);
-    sizes->medium_size_ = medium_list_.CountFreeListItemsInList(p);
-    sizes->large_size_ = large_list_.CountFreeListItemsInList(p);
-  } else {
-    sizes->small_size_ = 0;
-    sizes->medium_size_ = 0;
-    sizes->large_size_ = 0;
-  }
-}
-
-
 intptr_t FreeList::EvictFreeListItems(Page* p) {
   intptr_t sum = huge_list_.EvictFreeListItemsInList(p);
+  p->set_available_in_huge_free_list(0);
 
   if (sum < p->area_size()) {
     sum += small_list_.EvictFreeListItemsInList(p) +
         medium_list_.EvictFreeListItemsInList(p) +
         large_list_.EvictFreeListItemsInList(p);
+    p->set_available_in_small_free_list(0);
+    p->set_available_in_medium_free_list(0);
+    p->set_available_in_large_free_list(0);
   }
 
   return sum;
index 65eefd0..e7e4d52 100644 (file)
@@ -547,7 +547,8 @@ class MemoryChunk {
       kSlotsBufferOffset + kPointerSize + kPointerSize;
 
   static const size_t kHeaderSize = kWriteBarrierCounterOffset + kPointerSize +
-                                    kIntSize + kIntSize + kPointerSize;
+                                    kIntSize + kIntSize + kPointerSize +
+                                    5 * kPointerSize;
 
   static const int kBodyOffset =
       CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize);
@@ -701,6 +702,13 @@ class MemoryChunk {
 
   intptr_t parallel_sweeping_;
 
+  // PagedSpace free-list statistics.
+  intptr_t available_in_small_free_list_;
+  intptr_t available_in_medium_free_list_;
+  intptr_t available_in_large_free_list_;
+  intptr_t available_in_huge_free_list_;
+  intptr_t non_available_small_blocks_;
+
   static MemoryChunk* Initialize(Heap* heap,
                                  Address base,
                                  size_t size,
@@ -797,6 +805,21 @@ class Page : public MemoryChunk {
   void ClearSweptPrecisely() { ClearFlag(WAS_SWEPT_PRECISELY); }
   void ClearSweptConservatively() { ClearFlag(WAS_SWEPT_CONSERVATIVELY); }
 
+  void ResetFreeListStatistics();
+
+#define FRAGMENTATION_STATS_ACCESSORS(type, name) \
+  type name() { return name##_; }                 \
+  void set_##name(type name) { name##_ = name; }  \
+  void add_##name(type name) { name##_ += name; }
+
+  FRAGMENTATION_STATS_ACCESSORS(intptr_t, non_available_small_blocks)
+  FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_small_free_list)
+  FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_medium_free_list)
+  FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_large_free_list)
+  FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_huge_free_list)
+
+#undef FRAGMENTATION_STATS_ACCESSORS
+
 #ifdef DEBUG
   void Print();
 #endif  // DEBUG
@@ -1432,8 +1455,6 @@ class FreeListCategory {
 
   FreeListNode* PickNodeFromList(int *node_size);
 
-  intptr_t CountFreeListItemsInList(Page* p);
-
   intptr_t EvictFreeListItemsInList(Page* p);
 
   void RepairFreeList(Heap* heap);
@@ -1528,19 +1549,6 @@ class FreeList BASE_EMBEDDED {
   // Used after booting the VM.
   void RepairLists(Heap* heap);
 
-  struct SizeStats {
-    intptr_t Total() {
-      return small_size_ + medium_size_ + large_size_ + huge_size_;
-    }
-
-    intptr_t small_size_;
-    intptr_t medium_size_;
-    intptr_t large_size_;
-    intptr_t huge_size_;
-  };
-
-  void CountFreeListItems(Page* p, SizeStats* sizes);
-
   intptr_t EvictFreeListItems(Page* p);
 
   FreeListCategory* small_list() { return &small_list_; }
@@ -1625,6 +1633,20 @@ class PagedSpace : public Space {
   // Approximate amount of physical memory committed for this space.
   size_t CommittedPhysicalMemory();
 
+  struct SizeStats {
+    intptr_t Total() {
+      return small_size_ + medium_size_ + large_size_ + huge_size_;
+    }
+
+    intptr_t small_size_;
+    intptr_t medium_size_;
+    intptr_t large_size_;
+    intptr_t huge_size_;
+  };
+
+  void ObtainFreeListStatistics(Page* p, SizeStats* sizes);
+  void ResetFreeListStatistics();
+
   // 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
@@ -1632,6 +1654,7 @@ class PagedSpace : public Space {
   // to the available and wasted totals.
   void ClearStats() {
     accounting_stats_.ClearSizeWaste();
+    ResetFreeListStatistics();
   }
 
   // Increases the number of available bytes of that space.
@@ -1785,10 +1808,6 @@ class PagedSpace : public Space {
   Page* FirstPage() { return anchor_.next_page(); }
   Page* LastPage() { return anchor_.prev_page(); }
 
-  void CountFreeListItems(Page* p, FreeList::SizeStats* sizes) {
-    free_list_.CountFreeListItems(p, sizes);
-  }
-
   void EvictEvacuationCandidatesFromFreeLists();
 
   bool CanExpand();
index bcc30f9..61eec0d 100644 (file)
@@ -254,7 +254,7 @@ void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1,
 
 SmartArrayPointer<const char> StringStream::ToCString() const {
   char* str = NewArray<char>(length_ + 1);
-  memcpy(str, buffer_, length_);
+  OS::MemCopy(str, buffer_, length_);
   str[length_] = '\0';
   return SmartArrayPointer<const char>(str);
 }
@@ -575,7 +575,7 @@ char* HeapStringAllocator::grow(unsigned* bytes) {
   if (new_space == NULL) {
     return space_;
   }
-  memcpy(new_space, space_, *bytes);
+  OS::MemCopy(new_space, space_, *bytes);
   *bytes = new_bytes;
   DeleteArray(space_);
   space_ = new_space;
index 2f8043c..4cae85b 100644 (file)
 // (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 relies on the fact that the following declaration has been made
 // in runtime.js:
 // var $String = global.String;
 // var $NaN = 0/0;
 
+// -------------------------------------------------------------------
 
-// Set the String function and constructor.
-%SetCode($String, function(x) {
+function StringConstructor(x) {
   var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x);
   if (%_IsConstructCall()) {
     %_SetValueOf(this, value);
   } else {
     return value;
   }
-});
+}
 
-%FunctionSetPrototype($String, new $String());
 
 // ECMA-262 section 15.5.4.2
 function StringToString() {
@@ -994,16 +992,19 @@ SetUpLockedPrototype(ReplaceResultBuilder,
 
 function SetUpString() {
   %CheckIsBootstrapping();
+
+  // Set the String function and constructor.
+  %SetCode($String, StringConstructor);
+  %FunctionSetPrototype($String, new $String());
+
   // Set up the constructor property on the String prototype object.
   %SetProperty($String.prototype, "constructor", $String, DONT_ENUM);
 
-
   // Set up the non-enumerable functions on the String object.
   InstallFunctions($String, DONT_ENUM, $Array(
     "fromCharCode", StringFromCharCode
   ));
 
-
   // Set up the non-enumerable functions on the String prototype object.
   InstallFunctions($String.prototype, DONT_ENUM, $Array(
     "valueOf", StringValueOf,
index 553c6f5..396e92c 100644 (file)
@@ -402,18 +402,30 @@ Handle<Code> StubCache::ComputeKeyedLoadCallback(
 Handle<Code> StubCache::ComputeStoreField(Handle<Name> name,
                                           Handle<JSObject> receiver,
                                           LookupResult* lookup,
-                                          Handle<Map> transition,
                                           StrictModeFlag strict_mode) {
-  Code::StubType type =
-      transition.is_null() ? Code::FIELD : Code::MAP_TRANSITION;
+  Handle<Code> stub = FindIC(
+      name, receiver, Code::STORE_IC, Code::FIELD, strict_mode);
+  if (!stub.is_null()) return stub;
+
+  StoreStubCompiler compiler(isolate_, strict_mode);
+  Handle<Code> code = compiler.CompileStoreField(receiver, lookup, name);
+  JSObject::UpdateMapCodeCache(receiver, name, code);
+  return code;
+}
+
 
+Handle<Code> StubCache::ComputeStoreTransition(Handle<Name> name,
+                                               Handle<JSObject> receiver,
+                                               LookupResult* lookup,
+                                               Handle<Map> transition,
+                                               StrictModeFlag strict_mode) {
   Handle<Code> stub = FindIC(
-      name, receiver, Code::STORE_IC, type, strict_mode);
+      name, receiver, Code::STORE_IC, Code::MAP_TRANSITION, strict_mode);
   if (!stub.is_null()) return stub;
 
   StoreStubCompiler compiler(isolate_, strict_mode);
   Handle<Code> code =
-      compiler.CompileStoreField(receiver, lookup, transition, name);
+      compiler.CompileStoreTransition(receiver, lookup, transition, name);
   JSObject::UpdateMapCodeCache(receiver, name, code);
   return code;
 }
@@ -534,20 +546,35 @@ Handle<Code> StubCache::ComputeStoreInterceptor(Handle<Name> name,
   return code;
 }
 
+
 Handle<Code> StubCache::ComputeKeyedStoreField(Handle<Name> name,
                                                Handle<JSObject> receiver,
                                                LookupResult* lookup,
-                                               Handle<Map> transition,
                                                StrictModeFlag strict_mode) {
-  Code::StubType type =
-      (transition.is_null()) ? Code::FIELD : Code::MAP_TRANSITION;
   Handle<Code> stub = FindIC(
-      name, receiver, Code::KEYED_STORE_IC, type, strict_mode);
+      name, receiver, Code::KEYED_STORE_IC, Code::FIELD, strict_mode);
+  if (!stub.is_null()) return stub;
+
+  KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
+  Handle<Code> code = compiler.CompileStoreField(receiver, lookup, name);
+  JSObject::UpdateMapCodeCache(receiver, name, code);
+  return code;
+}
+
+
+Handle<Code> StubCache::ComputeKeyedStoreTransition(
+    Handle<Name> name,
+    Handle<JSObject> receiver,
+    LookupResult* lookup,
+    Handle<Map> transition,
+    StrictModeFlag strict_mode) {
+  Handle<Code> stub = FindIC(
+      name, receiver, Code::KEYED_STORE_IC, Code::MAP_TRANSITION, strict_mode);
   if (!stub.is_null()) return stub;
 
   KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
   Handle<Code> code =
-      compiler.CompileStoreField(receiver, lookup, transition, name);
+      compiler.CompileStoreTransition(receiver, lookup, transition, name);
   JSObject::UpdateMapCodeCache(receiver, name, code);
   return code;
 }
@@ -1587,11 +1614,39 @@ Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
 }
 
 
+Handle<Code> BaseStoreStubCompiler::CompileStoreTransition(
+    Handle<JSObject> object,
+    LookupResult* lookup,
+    Handle<Map> transition,
+    Handle<Name> name) {
+  Label miss, miss_restore_name;
+
+  GenerateNameCheck(name, this->name(), &miss);
+
+  GenerateStoreTransition(masm(),
+                          object,
+                          lookup,
+                          transition,
+                          name,
+                          receiver(), this->name(), value(),
+                          scratch1(), scratch2(),
+                          &miss,
+                          &miss_restore_name);
+
+  // Handle store cache miss.
+  GenerateRestoreName(masm(), &miss_restore_name, name);
+  __ bind(&miss);
+  TailCallBuiltin(masm(), MissBuiltin(kind()));
+
+  // Return the generated code.
+  return GetICCode(kind(), Code::MAP_TRANSITION, name);
+}
+
+
 Handle<Code> BaseStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
                                                       LookupResult* lookup,
-                                                      Handle<Map> transition,
                                                       Handle<Name> name) {
-  Label miss, miss_restore_name;
+  Label miss;
 
   GenerateNameCheck(name, this->name(), &miss);
 
@@ -1599,21 +1654,15 @@ Handle<Code> BaseStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
   GenerateStoreField(masm(),
                      object,
                      lookup,
-                     transition,
-                     name,
                      receiver(), this->name(), value(), scratch1(), scratch2(),
-                     &miss,
-                     &miss_restore_name);
+                     &miss);
 
   // Handle store cache miss.
-  GenerateRestoreName(masm(), &miss_restore_name, name);
   __ bind(&miss);
   TailCallBuiltin(masm(), MissBuiltin(kind()));
 
   // Return the generated code.
-  return GetICCode(kind(),
-                   transition.is_null() ? Code::FIELD : Code::MAP_TRANSITION,
-                   name);
+  return GetICCode(kind(), Code::FIELD, name);
 }
 
 
index bca3b7b..02bb541 100644 (file)
@@ -162,9 +162,14 @@ class StubCache {
   Handle<Code> ComputeStoreField(Handle<Name> name,
                                  Handle<JSObject> object,
                                  LookupResult* lookup,
-                                 Handle<Map> transition,
                                  StrictModeFlag strict_mode);
 
+  Handle<Code> ComputeStoreTransition(Handle<Name> name,
+                                      Handle<JSObject> object,
+                                      LookupResult* lookup,
+                                      Handle<Map> transition,
+                                      StrictModeFlag strict_mode);
+
   Handle<Code> ComputeStoreNormal(StrictModeFlag strict_mode);
 
   Handle<Code> ComputeStoreGlobal(Handle<Name> name,
@@ -193,8 +198,12 @@ class StubCache {
   Handle<Code> ComputeKeyedStoreField(Handle<Name> name,
                                       Handle<JSObject> object,
                                       LookupResult* lookup,
-                                      Handle<Map> transition,
                                       StrictModeFlag strict_mode);
+  Handle<Code> ComputeKeyedStoreTransition(Handle<Name> name,
+                                           Handle<JSObject> object,
+                                           LookupResult* lookup,
+                                           Handle<Map> transition,
+                                           StrictModeFlag strict_mode);
 
   Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
 
@@ -509,18 +518,28 @@ class StubCompiler BASE_EMBEDDED {
                                             Register scratch2,
                                             Label* miss_label);
 
+  void GenerateStoreTransition(MacroAssembler* masm,
+                               Handle<JSObject> object,
+                               LookupResult* lookup,
+                               Handle<Map> transition,
+                               Handle<Name> name,
+                               Register receiver_reg,
+                               Register name_reg,
+                               Register value_reg,
+                               Register scratch1,
+                               Register scratch2,
+                               Label* miss_label,
+                               Label* miss_restore_name);
+
   void GenerateStoreField(MacroAssembler* masm,
                           Handle<JSObject> object,
                           LookupResult* lookup,
-                          Handle<Map> transition,
-                          Handle<Name> name,
                           Register receiver_reg,
                           Register name_reg,
                           Register value_reg,
                           Register scratch1,
                           Register scratch2,
-                          Label* miss_label,
-                          Label* miss_restore_name);
+                          Label* miss_label);
 
   static Builtins::Name MissBuiltin(Code::Kind kind) {
     switch (kind) {
@@ -781,9 +800,13 @@ class BaseStoreStubCompiler: public StubCompiler {
 
   virtual ~BaseStoreStubCompiler() { }
 
+  Handle<Code> CompileStoreTransition(Handle<JSObject> object,
+                                      LookupResult* lookup,
+                                      Handle<Map> transition,
+                                      Handle<Name> name);
+
   Handle<Code> CompileStoreField(Handle<JSObject> object,
                                  LookupResult* lookup,
-                                 Handle<Map> transition,
                                  Handle<Name> name);
 
  protected:
index fb7476f..050e7d9 100644 (file)
 
 "use strict";
 
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
 var $Symbol = global.Symbol;
 
+// -------------------------------------------------------------------
+
 function SymbolConstructor(x) {
   var value =
     IS_SYMBOL(x) ? x : %CreateSymbol(IS_UNDEFINED(x) ? x : ToString(x));
diff --git a/deps/v8/src/third_party/vtune/ittnotify_config.h b/deps/v8/src/third_party/vtune/ittnotify_config.h
new file mode 100644 (file)
index 0000000..412e344
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+  This file is provided under a dual BSD/GPLv2 license.  When using or
+  redistributing this file, you may do so under either license.
+
+  GPL LICENSE SUMMARY
+
+  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  The full GNU General Public License is included in this distribution
+  in the file called LICENSE.GPL.
+
+  Contact Information:
+  http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+  BSD LICENSE
+
+  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+  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 Intel Corporation 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 _ITTNOTIFY_CONFIG_H_
+#define _ITTNOTIFY_CONFIG_H_
+
+/** @cond exclude_from_documentation */
+#ifndef ITT_OS_WIN
+#  define ITT_OS_WIN   1
+#endif /* ITT_OS_WIN */
+
+#ifndef ITT_OS_LINUX
+#  define ITT_OS_LINUX 2
+#endif /* ITT_OS_LINUX */
+
+#ifndef ITT_OS_MAC
+#  define ITT_OS_MAC   3
+#endif /* ITT_OS_MAC */
+
+#ifndef ITT_OS
+#  if defined WIN32 || defined _WIN32
+#    define ITT_OS ITT_OS_WIN
+#  elif defined( __APPLE__ ) && defined( __MACH__ )
+#    define ITT_OS ITT_OS_MAC
+#  else
+#    define ITT_OS ITT_OS_LINUX
+#  endif
+#endif /* ITT_OS */
+
+#ifndef ITT_PLATFORM_WIN
+#  define ITT_PLATFORM_WIN 1
+#endif /* ITT_PLATFORM_WIN */
+
+#ifndef ITT_PLATFORM_POSIX
+#  define ITT_PLATFORM_POSIX 2
+#endif /* ITT_PLATFORM_POSIX */
+
+#ifndef ITT_PLATFORM
+#  if ITT_OS==ITT_OS_WIN
+#    define ITT_PLATFORM ITT_PLATFORM_WIN
+#  else
+#    define ITT_PLATFORM ITT_PLATFORM_POSIX
+#  endif /* _WIN32 */
+#endif /* ITT_PLATFORM */
+
+#if defined(_UNICODE) && !defined(UNICODE)
+#define UNICODE
+#endif
+
+#include <stddef.h>
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#include <tchar.h>
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <stdint.h>
+#if defined(UNICODE) || defined(_UNICODE)
+#include <wchar.h>
+#endif /* UNICODE || _UNICODE */
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+#ifndef CDECL
+#  if ITT_PLATFORM==ITT_PLATFORM_WIN
+#    define CDECL __cdecl
+#  else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#    if defined _M_X64 || defined _M_AMD64 || defined __x86_64__
+#      define CDECL /* not actual on x86_64 platform */
+#    else  /* _M_X64 || _M_AMD64 || __x86_64__ */
+#      define CDECL __attribute__ ((cdecl))
+#    endif /* _M_X64 || _M_AMD64 || __x86_64__ */
+#  endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#endif /* CDECL */
+
+#ifndef STDCALL
+#  if ITT_PLATFORM==ITT_PLATFORM_WIN
+#    define STDCALL __stdcall
+#  else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#    if defined _M_X64 || defined _M_AMD64 || defined __x86_64__
+#      define STDCALL /* not supported on x86_64 platform */
+#    else  /* _M_X64 || _M_AMD64 || __x86_64__ */
+#      define STDCALL __attribute__ ((stdcall))
+#    endif /* _M_X64 || _M_AMD64 || __x86_64__ */
+#  endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#endif /* STDCALL */
+
+#define ITTAPI    CDECL
+#define LIBITTAPI CDECL
+
+/* TODO: Temporary for compatibility! */
+#define ITTAPI_CALL    CDECL
+#define LIBITTAPI_CALL CDECL
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+/* use __forceinline (VC++ specific) */
+#define ITT_INLINE           __forceinline
+#define ITT_INLINE_ATTRIBUTE /* nothing */
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+/*
+ * Generally, functions are not inlined unless optimization is specified.
+ * For functions declared inline, this attribute inlines the function even
+ * if no optimization level was specified.
+ */
+#ifdef __STRICT_ANSI__
+#define ITT_INLINE           static
+#else  /* __STRICT_ANSI__ */
+#define ITT_INLINE           static inline
+#endif /* __STRICT_ANSI__ */
+#define ITT_INLINE_ATTRIBUTE __attribute__ ((always_inline))
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+/** @endcond */
+
+#ifndef ITT_ARCH_IA32
+#  define ITT_ARCH_IA32  1
+#endif /* ITT_ARCH_IA32 */
+
+#ifndef ITT_ARCH_IA32E
+#  define ITT_ARCH_IA32E 2
+#endif /* ITT_ARCH_IA32E */
+
+#ifndef ITT_ARCH_IA64
+#  define ITT_ARCH_IA64  3
+#endif /* ITT_ARCH_IA64 */
+
+#ifndef ITT_ARCH
+#  if defined _M_X64 || defined _M_AMD64 || defined __x86_64__
+#    define ITT_ARCH ITT_ARCH_IA32E
+#  elif defined _M_IA64 || defined __ia64
+#    define ITT_ARCH ITT_ARCH_IA64
+#  else
+#    define ITT_ARCH ITT_ARCH_IA32
+#  endif
+#endif
+
+#ifdef __cplusplus
+#  define ITT_EXTERN_C extern "C"
+#else
+#  define ITT_EXTERN_C /* nothing */
+#endif /* __cplusplus */
+
+#define ITT_TO_STR_AUX(x) #x
+#define ITT_TO_STR(x)     ITT_TO_STR_AUX(x)
+
+#define __ITT_BUILD_ASSERT(expr, suffix) do { static char __itt_build_check_##suffix[(expr) ? 1 : -1]; __itt_build_check_##suffix[0] = 0; } while(0)
+#define _ITT_BUILD_ASSERT(expr, suffix)  __ITT_BUILD_ASSERT((expr), suffix)
+#define ITT_BUILD_ASSERT(expr)           _ITT_BUILD_ASSERT((expr), __LINE__)
+
+#define ITT_MAGIC { 0xED, 0xAB, 0xAB, 0xEC, 0x0D, 0xEE, 0xDA, 0x30 }
+
+/* Replace with snapshot date YYYYMMDD for promotion build. */
+#define API_VERSION_BUILD    20111111
+
+#ifndef API_VERSION_NUM
+#define API_VERSION_NUM 0.0.0
+#endif /* API_VERSION_NUM */
+
+#define API_VERSION "ITT-API-Version " ITT_TO_STR(API_VERSION_NUM) " (" ITT_TO_STR(API_VERSION_BUILD) ")"
+
+/* OS communication functions */
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#include <windows.h>
+typedef HMODULE           lib_t;
+typedef DWORD             TIDT;
+typedef CRITICAL_SECTION  mutex_t;
+#define MUTEX_INITIALIZER { 0 }
+#define strong_alias(name, aliasname) /* empty for Windows */
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <dlfcn.h>
+#if defined(UNICODE) || defined(_UNICODE)
+#include <wchar.h>
+#endif /* UNICODE */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1 /* need for PTHREAD_MUTEX_RECURSIVE */
+#endif /* _GNU_SOURCE */
+#include <pthread.h>
+typedef void*             lib_t;
+typedef pthread_t         TIDT;
+typedef pthread_mutex_t   mutex_t;
+#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define _strong_alias(name, aliasname) extern __typeof (name) aliasname __attribute__ ((alias (#name)));
+#define strong_alias(name, aliasname) _strong_alias(name, aliasname)
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#define __itt_get_proc(lib, name) GetProcAddress(lib, name)
+#define __itt_mutex_init(mutex)   InitializeCriticalSection(mutex)
+#define __itt_mutex_lock(mutex)   EnterCriticalSection(mutex)
+#define __itt_mutex_unlock(mutex) LeaveCriticalSection(mutex)
+#define __itt_load_lib(name)      LoadLibraryA(name)
+#define __itt_unload_lib(handle)  FreeLibrary(handle)
+#define __itt_system_error()      (int)GetLastError()
+#define __itt_fstrcmp(s1, s2)     lstrcmpA(s1, s2)
+#define __itt_fstrlen(s)          lstrlenA(s)
+#define __itt_fstrcpyn(s1, s2, l) lstrcpynA(s1, s2, l)
+#define __itt_fstrdup(s)          _strdup(s)
+#define __itt_thread_id()         GetCurrentThreadId()
+#define __itt_thread_yield()      SwitchToThread()
+#ifndef ITT_SIMPLE_INIT
+ITT_INLINE int __itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE;
+ITT_INLINE int __itt_interlocked_increment(volatile long* ptr)
+{
+    return InterlockedIncrement(ptr);
+}
+#endif /* ITT_SIMPLE_INIT */
+#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
+#define __itt_get_proc(lib, name) dlsym(lib, name)
+#define __itt_mutex_init(mutex)   \
+    {                                                                                        \
+        pthread_mutexattr_t mutex_attr;                                                      \
+        int error_code = pthread_mutexattr_init(&mutex_attr);                                \
+        if (error_code)                                                                      \
+            __itt_report_error(__itt_error_system, "pthread_mutexattr_init", error_code);    \
+        error_code = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);        \
+        if (error_code)                                                                      \
+            __itt_report_error(__itt_error_system, "pthread_mutexattr_settype", error_code); \
+        error_code = pthread_mutex_init(mutex, &mutex_attr);                                 \
+        if (error_code)                                                                      \
+            __itt_report_error(__itt_error_system, "pthread_mutex_init", error_code);        \
+        error_code = pthread_mutexattr_destroy(&mutex_attr);                                 \
+        if (error_code)                                                                      \
+            __itt_report_error(__itt_error_system, "pthread_mutexattr_destroy", error_code); \
+    }
+#define __itt_mutex_lock(mutex)   pthread_mutex_lock(mutex)
+#define __itt_mutex_unlock(mutex) pthread_mutex_unlock(mutex)
+#define __itt_load_lib(name)      dlopen(name, RTLD_LAZY)
+#define __itt_unload_lib(handle)  dlclose(handle)
+#define __itt_system_error()      errno
+#define __itt_fstrcmp(s1, s2)     strcmp(s1, s2)
+#define __itt_fstrlen(s)          strlen(s)
+#define __itt_fstrcpyn(s1, s2, l) strncpy(s1, s2, l)
+#define __itt_fstrdup(s)          strdup(s)
+#define __itt_thread_id()         pthread_self()
+#define __itt_thread_yield()      sched_yield()
+#if ITT_ARCH==ITT_ARCH_IA64
+#ifdef __INTEL_COMPILER
+#define __TBB_machine_fetchadd4(addr, val) __fetchadd4_acq((void *)addr, val)
+#else  /* __INTEL_COMPILER */
+/* TODO: Add Support for not Intel compilers for IA64 */
+#endif /* __INTEL_COMPILER */
+#else /* ITT_ARCH!=ITT_ARCH_IA64 */
+/*ITT_INLINE int __TBB_machine_fetchadd4(volatile void* ptr, long addend) ITT_INLINE_ATTRIBUTE;
+ITT_INLINE int __TBB_machine_fetchadd4(volatile void* ptr, long addend)
+{
+    int result;
+    __asm__ __volatile__("lock\nxaddl %0,%1"
+                          : "=r"(result),"=m"(*(long*)ptr)
+                          : "0"(addend), "m"(*(long*)ptr)
+                          : "memory");
+    return result;
+}
+*/
+#endif /* ITT_ARCH==ITT_ARCH_IA64 */
+#ifndef ITT_SIMPLE_INIT
+/*ITT_INLINE int __itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE;
+ITT_INLINE int __itt_interlocked_increment(volatile long* ptr)
+{
+    return __TBB_machine_fetchadd4(ptr, 1) + 1;
+}
+*/
+#endif /* ITT_SIMPLE_INIT */
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+typedef enum {
+    __itt_collection_normal = 0,
+    __itt_collection_paused = 1
+} __itt_collection_state;
+
+typedef enum {
+    __itt_thread_normal  = 0,
+    __itt_thread_ignored = 1
+} __itt_thread_state;
+
+#pragma pack(push, 8)
+
+typedef struct ___itt_thread_info
+{
+    const char* nameA; /*!< Copy of original name in ASCII. */
+#if defined(UNICODE) || defined(_UNICODE)
+    const wchar_t* nameW; /*!< Copy of original name in UNICODE. */
+#else  /* UNICODE || _UNICODE */
+    void* nameW;
+#endif /* UNICODE || _UNICODE */
+    TIDT               tid;
+    __itt_thread_state state;   /*!< Thread state (paused or normal) */
+    int                extra1;  /*!< Reserved to the runtime */
+    void*              extra2;  /*!< Reserved to the runtime */
+    struct ___itt_thread_info* next;
+} __itt_thread_info;
+
+#include "ittnotify_types.h" /* For __itt_group_id definition */
+
+typedef struct ___itt_api_info_20101001
+{
+    const char*    name;
+    void**         func_ptr;
+    void*          init_func;
+    __itt_group_id group;
+}  __itt_api_info_20101001;
+
+typedef struct ___itt_api_info
+{
+    const char*    name;
+    void**         func_ptr;
+    void*          init_func;
+    void*          null_func;
+    __itt_group_id group;
+}  __itt_api_info;
+
+struct ___itt_domain;
+struct ___itt_string_handle;
+
+typedef struct ___itt_global
+{
+    unsigned char          magic[8];
+    unsigned long          version_major;
+    unsigned long          version_minor;
+    unsigned long          version_build;
+    volatile long          api_initialized;
+    volatile long          mutex_initialized;
+    volatile long          atomic_counter;
+    mutex_t                mutex;
+    lib_t                  lib;
+    void*                  error_handler;
+    const char**           dll_path_ptr;
+    __itt_api_info*        api_list_ptr;
+    struct ___itt_global*  next;
+    /* Joinable structures below */
+    __itt_thread_info*     thread_list;
+    struct ___itt_domain*  domain_list;
+    struct ___itt_string_handle* string_list;
+    __itt_collection_state state;
+} __itt_global;
+
+#pragma pack(pop)
+
+#define NEW_THREAD_INFO_W(gptr,h,h_tail,t,s,n) { \
+    h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \
+    if (h != NULL) { \
+        h->tid    = t; \
+        h->nameA  = NULL; \
+        h->nameW  = n ? _wcsdup(n) : NULL; \
+        h->state  = s; \
+        h->extra1 = 0;    /* reserved */ \
+        h->extra2 = NULL; /* reserved */ \
+        h->next   = NULL; \
+        if (h_tail == NULL) \
+            (gptr)->thread_list = h; \
+        else \
+            h_tail->next = h; \
+    } \
+}
+
+#define NEW_THREAD_INFO_A(gptr,h,h_tail,t,s,n) { \
+    h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \
+    if (h != NULL) { \
+        h->tid    = t; \
+        h->nameA  = n ? __itt_fstrdup(n) : NULL; \
+        h->nameW  = NULL; \
+        h->state  = s; \
+        h->extra1 = 0;    /* reserved */ \
+        h->extra2 = NULL; /* reserved */ \
+        h->next   = NULL; \
+        if (h_tail == NULL) \
+            (gptr)->thread_list = h; \
+        else \
+            h_tail->next = h; \
+    } \
+}
+
+#define NEW_DOMAIN_W(gptr,h,h_tail,name) { \
+    h = (__itt_domain*)malloc(sizeof(__itt_domain)); \
+    if (h != NULL) { \
+        h->flags  = 0;    /* domain is disabled by default */ \
+        h->nameA  = NULL; \
+        h->nameW  = name ? _wcsdup(name) : NULL; \
+        h->extra1 = 0;    /* reserved */ \
+        h->extra2 = NULL; /* reserved */ \
+        h->next   = NULL; \
+        if (h_tail == NULL) \
+            (gptr)->domain_list = h; \
+        else \
+            h_tail->next = h; \
+    } \
+}
+
+#define NEW_DOMAIN_A(gptr,h,h_tail,name) { \
+    h = (__itt_domain*)malloc(sizeof(__itt_domain)); \
+    if (h != NULL) { \
+        h->flags  = 0;    /* domain is disabled by default */ \
+        h->nameA  = name ? __itt_fstrdup(name) : NULL; \
+        h->nameW  = NULL; \
+        h->extra1 = 0;    /* reserved */ \
+        h->extra2 = NULL; /* reserved */ \
+        h->next   = NULL; \
+        if (h_tail == NULL) \
+            (gptr)->domain_list = h; \
+        else \
+            h_tail->next = h; \
+    } \
+}
+
+#define NEW_STRING_HANDLE_W(gptr,h,h_tail,name) { \
+    h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \
+    if (h != NULL) { \
+        h->strA   = NULL; \
+        h->strW   = name ? _wcsdup(name) : NULL; \
+        h->extra1 = 0;    /* reserved */ \
+        h->extra2 = NULL; /* reserved */ \
+        h->next   = NULL; \
+        if (h_tail == NULL) \
+            (gptr)->string_list = h; \
+        else \
+            h_tail->next = h; \
+    } \
+}
+
+#define NEW_STRING_HANDLE_A(gptr,h,h_tail,name) { \
+    h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \
+    if (h != NULL) { \
+        h->strA   = name ? __itt_fstrdup(name) : NULL; \
+        h->strW   = NULL; \
+        h->extra1 = 0;    /* reserved */ \
+        h->extra2 = NULL; /* reserved */ \
+        h->next   = NULL; \
+        if (h_tail == NULL) \
+            (gptr)->string_list = h; \
+        else \
+            h_tail->next = h; \
+    } \
+}
+
+#endif /* _ITTNOTIFY_CONFIG_H_ */
+
diff --git a/deps/v8/src/third_party/vtune/ittnotify_types.h b/deps/v8/src/third_party/vtune/ittnotify_types.h
new file mode 100644 (file)
index 0000000..736c1f5
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  This file is provided under a dual BSD/GPLv2 license.  When using or
+  redistributing this file, you may do so under either license.
+
+  GPL LICENSE SUMMARY
+
+  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  The full GNU General Public License is included in this distribution
+  in the file called LICENSE.GPL.
+
+  Contact Information:
+  http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+  BSD LICENSE
+
+  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+  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 Intel Corporation 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 _ITTNOTIFY_TYPES_H_
+#define _ITTNOTIFY_TYPES_H_
+
+typedef enum ___itt_group_id
+{
+    __itt_group_none      = 0,
+    __itt_group_legacy    = 1<<0,
+    __itt_group_control   = 1<<1,
+    __itt_group_thread    = 1<<2,
+    __itt_group_mark      = 1<<3,
+    __itt_group_sync      = 1<<4,
+    __itt_group_fsync     = 1<<5,
+    __itt_group_jit       = 1<<6,
+    __itt_group_model     = 1<<7,
+    __itt_group_splitter_min = 1<<7,
+    __itt_group_counter   = 1<<8,
+    __itt_group_frame     = 1<<9,
+    __itt_group_stitch    = 1<<10,
+    __itt_group_heap      = 1<<11,
+    __itt_group_splitter_max = 1<<12,
+    __itt_group_structure = 1<<12,
+    __itt_group_suppress = 1<<13,
+    __itt_group_all       = -1
+} __itt_group_id;
+
+#pragma pack(push, 8)
+
+typedef struct ___itt_group_list
+{
+    __itt_group_id id;
+    const char*    name;
+} __itt_group_list;
+
+#pragma pack(pop)
+
+#define ITT_GROUP_LIST(varname) \
+    static __itt_group_list varname[] = {       \
+        { __itt_group_all,       "all"       }, \
+        { __itt_group_control,   "control"   }, \
+        { __itt_group_thread,    "thread"    }, \
+        { __itt_group_mark,      "mark"      }, \
+        { __itt_group_sync,      "sync"      }, \
+        { __itt_group_fsync,     "fsync"     }, \
+        { __itt_group_jit,       "jit"       }, \
+        { __itt_group_model,     "model"     }, \
+        { __itt_group_counter,   "counter"   }, \
+        { __itt_group_frame,     "frame"     }, \
+        { __itt_group_stitch,    "stitch"    }, \
+        { __itt_group_heap,      "heap"      }, \
+        { __itt_group_structure, "structure" }, \
+        { __itt_group_suppress,  "suppress"  }, \
+        { __itt_group_none,      NULL        }  \
+    }
+
+#endif /* _ITTNOTIFY_TYPES_H_ */
+
diff --git a/deps/v8/src/third_party/vtune/jitprofiling.cc b/deps/v8/src/third_party/vtune/jitprofiling.cc
new file mode 100644 (file)
index 0000000..b3952b3
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+  This file is provided under a dual BSD/GPLv2 license.  When using or
+  redistributing this file, you may do so under either license.
+
+  GPL LICENSE SUMMARY
+
+  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  The full GNU General Public License is included in this distribution
+  in the file called LICENSE.GPL.
+
+  Contact Information:
+  http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+  BSD LICENSE
+
+  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+  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 Intel Corporation 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 "ittnotify_config.h"
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#include <windows.h>
+#pragma optimize("", off)
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <pthread.h>
+#include <dlfcn.h>
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <malloc.h>
+#include <stdlib.h>
+
+#include "jitprofiling.h"
+
+static const char rcsid[] = "\n@(#) $Revision: 234474 $\n";
+
+#define DLL_ENVIRONMENT_VAR            "VS_PROFILER"
+
+#ifndef NEW_DLL_ENVIRONMENT_VAR
+#if ITT_ARCH==ITT_ARCH_IA32
+#define NEW_DLL_ENVIRONMENT_VAR                "INTEL_JIT_PROFILER32"
+#else
+#define NEW_DLL_ENVIRONMENT_VAR                "INTEL_JIT_PROFILER64"
+#endif
+#endif /* NEW_DLL_ENVIRONMENT_VAR */
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#define DEFAULT_DLLNAME                        "JitPI.dll"
+HINSTANCE m_libHandle = NULL;
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#define DEFAULT_DLLNAME                        "libJitPI.so"
+void* m_libHandle = NULL;
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+/* default location of JIT profiling agent on Android */
+#define ANDROID_JIT_AGENT_PATH  "/data/intel/libittnotify.so"
+
+/* the function pointers */
+typedef unsigned int(*TPInitialize)(void);
+static TPInitialize FUNC_Initialize=NULL;
+
+typedef unsigned int(*TPNotify)(unsigned int, void*);
+static TPNotify FUNC_NotifyEvent=NULL;
+
+static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
+
+/* end collector dll part. */
+
+/* loadiJIT_Funcs() : this function is called just in the beginning and is responsible 
+** to load the functions from BistroJavaCollector.dll
+** result:
+**             on success: the functions loads,    iJIT_DLL_is_missing=0, return value = 1.
+**             on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0.
+*/ 
+static int loadiJIT_Funcs(void);
+
+/* global representing whether the BistroJavaCollector can't be loaded */
+static int iJIT_DLL_is_missing = 0;
+
+/* Virtual stack - the struct is used as a virtual stack for each thread.
+** Every thread initializes with a stack of size INIT_TOP_STACK.
+** Every method entry decreases from the current stack point,
+** and when a thread stack reaches its top of stack (return from the global function),
+** the top of stack and the current stack increase. Notice that when returning from a function
+** the stack pointer is the address of the function return.
+*/
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+static DWORD threadLocalStorageHandle = 0;
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0;
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+#define INIT_TOP_Stack 10000
+
+typedef struct 
+{
+    unsigned int TopStack;
+    unsigned int CurrentStack;
+} ThreadStack, *pThreadStack;
+
+/* end of virtual stack. */
+
+/*
+** The function for reporting virtual-machine related events to VTune.
+** Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill in the stack_id 
+** field in the iJIT_Method_NIDS structure, as VTune fills it.
+** 
+** The return value in iJVM_EVENT_TYPE_ENTER_NIDS && iJVM_EVENT_TYPE_LEAVE_NIDS events
+** will be 0 in case of failure.
+** in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event it will be -1 if EventSpecificData == 0
+** otherwise it will be 0.
+*/
+
+ITT_EXTERN_C int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
+{
+    int ReturnValue;
+
+    /*******************************************************************************
+    ** This section is for debugging outside of VTune. 
+    ** It creates the environment variables that indicates call graph mode.
+    ** If running outside of VTune remove the remark.
+    **
+
+      static int firstTime = 1;
+      char DoCallGraph[12] = "DoCallGraph";
+      if (firstTime)
+      {
+      firstTime = 0;
+      SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph);
+      }
+
+    ** end of section.
+    *******************************************************************************/
+
+    /* initialization part - the functions have not been loaded yet. This part
+    **         will load the functions, and check if we are in Call Graph mode. 
+    **         (for special treatment).
+    */
+    if (!FUNC_NotifyEvent) 
+    {
+        if (iJIT_DLL_is_missing) 
+            return 0;
+
+        // load the Function from the DLL
+        if (!loadiJIT_Funcs()) 
+            return 0;
+
+        /* Call Graph initialization. */
+    }
+
+    /* If the event is method entry/exit, check that in the current mode 
+    ** VTune is allowed to receive it
+    */
+    if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS || event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) &&
+        (executionMode != iJIT_CALLGRAPH_ON))
+    {
+        return 0;
+    }
+    /* This section is performed when method enter event occurs.
+    ** It updates the virtual stack, or creates it if this is the first 
+    ** method entry in the thread. The stack pointer is decreased.
+    */
+    if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS)
+    {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+        pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle);
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+        // check for use of reserved method IDs
+        if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
+            return 0;
+
+        if (!threadStack)
+        {
+            // initialize the stack.
+            threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1);
+            threadStack->TopStack = INIT_TOP_Stack;
+            threadStack->CurrentStack = INIT_TOP_Stack;
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+            TlsSetValue(threadLocalStorageHandle,(void*)threadStack);
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+            pthread_setspecific(threadLocalStorageHandle,(void*)threadStack);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        }
+
+        // decrease the stack.
+        ((piJIT_Method_NIDS) EventSpecificData)->stack_id = (threadStack->CurrentStack)--;
+    }
+
+    /* This section is performed when method leave event occurs
+    ** It updates the virtual stack.
+    **         Increases the stack pointer.
+    **         If the stack pointer reached the top (left the global function)
+    **                 increase the pointer and the top pointer.
+    */
+    if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS)
+    {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+        pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle);
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+        // check for use of reserved method IDs
+        if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 )
+            return 0;
+
+        if (!threadStack)
+        {
+            /* Error: first report in this thread is method exit */
+            exit (1);
+        }
+
+        ((piJIT_Method_NIDS) EventSpecificData)->stack_id = ++(threadStack->CurrentStack) + 1;
+
+        if (((piJIT_Method_NIDS) EventSpecificData)->stack_id > threadStack->TopStack)
+            ((piJIT_Method_NIDS) EventSpecificData)->stack_id = (unsigned int)-1;
+    }
+
+    if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED)
+    {
+        // check for use of reserved method IDs
+        if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 )
+            return 0;
+    }
+
+    ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);   
+
+    return ReturnValue;
+}
+
+ITT_EXTERN_C void JITAPI iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx NewModeCallBackFuncEx) // The new mode call back routine
+{
+    // is it already missing... or the load of functions from the DLL failed
+    if (iJIT_DLL_is_missing || !loadiJIT_Funcs())
+    {
+        NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS);  // then do not bother with notifications
+        /* Error: could not load JIT functions. */
+        return;
+    }
+    // nothing to do with the callback
+}
+
+/*
+** This function allows the user to query in which mode, if at all, VTune is running
+*/
+ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
+{
+    if (!iJIT_DLL_is_missing)
+    {
+        loadiJIT_Funcs();
+    }
+
+    return executionMode;
+}
+#include <stdio.h>
+/* this function loads the collector dll (BistroJavaCollector) and the relevant functions.
+** on success: all functions load,     iJIT_DLL_is_missing = 0, return value = 1.
+** on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0.
+*/ 
+static int loadiJIT_Funcs()
+{
+    static int bDllWasLoaded = 0;
+    char *dllName = (char*)rcsid; // !!! Just to avoid unused code elimination !!!
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+    DWORD dNameLength = 0;
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+    if(bDllWasLoaded)
+    {// dll was already loaded, no need to do it for the second time
+        return 1;
+    }
+
+    // Assumes that the DLL will not be found
+    iJIT_DLL_is_missing = 1;
+    FUNC_NotifyEvent = NULL;
+
+    if (m_libHandle) 
+    {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+        FreeLibrary(m_libHandle);
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        dlclose(m_libHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        m_libHandle = NULL;
+    }
+
+    // try to get the dll name from the environment
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+    dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0);
+    if (dNameLength)
+    {
+        DWORD envret = 0;
+        dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
+        envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, dllName, dNameLength);
+        if (envret)
+        {
+            // Try to load the dll from the PATH...
+            m_libHandle = LoadLibraryExA(dllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+        }
+        free(dllName);
+    } else {
+        // Try to use old VS_PROFILER variable
+        dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);
+        if (dNameLength)
+        {
+            DWORD envret = 0;
+            dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
+            envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, dllName, dNameLength);
+            if (envret)
+            {
+                // Try to load the dll from the PATH...
+                m_libHandle = LoadLibraryA(dllName);
+            }
+            free(dllName);
+        }
+    }
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+    dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);
+    if (!dllName) {
+        dllName = getenv(DLL_ENVIRONMENT_VAR);
+    }
+#ifdef ANDROID
+    if (!dllName)
+        dllName = ANDROID_JIT_AGENT_PATH;
+#endif
+    if (dllName)
+    {
+        // Try to load the dll from the PATH...
+        m_libHandle = dlopen(dllName, RTLD_LAZY);
+    }
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+    if (!m_libHandle)
+    {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+        m_libHandle = LoadLibraryA(DEFAULT_DLLNAME);
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+    }
+
+    // if the dll wasn't loaded - exit.
+    if (!m_libHandle)
+    {
+        iJIT_DLL_is_missing = 1; // don't try to initialize JIT agent the second time
+        return 0;
+    }
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+    FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent");
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+    FUNC_NotifyEvent = reinterpret_cast<TPNotify>(reinterpret_cast<intptr_t>(dlsym(m_libHandle, "NotifyEvent")));
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+    if (!FUNC_NotifyEvent) 
+    {
+        FUNC_Initialize = NULL;
+        return 0;
+    }
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+    FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize");
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+    FUNC_Initialize = reinterpret_cast<TPInitialize>(reinterpret_cast<intptr_t>(dlsym(m_libHandle, "Initialize")));
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+    if (!FUNC_Initialize) 
+    {
+        FUNC_NotifyEvent = NULL;
+        return 0;
+    }
+
+    executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
+    if (executionMode != iJIT_SAMPLING_ON)
+      executionMode = iJIT_SAMPLING_ON;
+
+    bDllWasLoaded = 1;
+    iJIT_DLL_is_missing = 0; // DLL is ok.
+
+    /*
+    ** Call Graph mode: init the thread local storage
+    ** (need to store the virtual stack there).
+    */
+    if ( executionMode == iJIT_CALLGRAPH_ON )
+    {
+        // Allocate a thread local storage slot for the thread "stack"
+        if (!threadLocalStorageHandle)
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+            threadLocalStorageHandle = TlsAlloc();
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        pthread_key_create(&threadLocalStorageHandle, NULL);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+    }
+
+    return 1;
+}
+
+/*
+** This function should be called by the user whenever a thread ends, to free the thread 
+** "virtual stack" storage
+*/
+ITT_EXTERN_C void JITAPI FinalizeThread()
+{
+    if (threadLocalStorageHandle)
+    {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+        pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle);
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        if (threadStack)
+        {
+            free (threadStack);
+            threadStack = NULL;
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+            TlsSetValue (threadLocalStorageHandle, threadStack);
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+            pthread_setspecific(threadLocalStorageHandle, threadStack);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        }
+    }
+}
+
+/*
+** This function should be called by the user when the process ends, to free the local
+** storage index
+*/
+ITT_EXTERN_C void JITAPI FinalizeProcess()
+{
+    if (m_libHandle) 
+    {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+        FreeLibrary(m_libHandle);
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        dlclose(m_libHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+        m_libHandle = NULL;
+    }
+
+    if (threadLocalStorageHandle)
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+        TlsFree (threadLocalStorageHandle);
+#else  /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+    pthread_key_delete(threadLocalStorageHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+}
+
+/*
+** This function should be called by the user for any method once.
+** The function will return a unique method ID, the user should maintain the ID for each 
+** method
+*/
+ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
+{
+    static unsigned int methodID = 0x100000;
+
+    if (methodID == 0)
+        return 0;      // ERROR : this is not a valid value
+
+    return methodID++;
+}
+
diff --git a/deps/v8/src/third_party/vtune/jitprofiling.h b/deps/v8/src/third_party/vtune/jitprofiling.h
new file mode 100644 (file)
index 0000000..abd6d8c
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+  This file is provided under a dual BSD/GPLv2 license.  When using or
+  redistributing this file, you may do so under either license.
+
+  GPL LICENSE SUMMARY
+
+  Copyright (c) 2005-2012 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  The full GNU General Public License is included in this distribution
+  in the file called LICENSE.GPL.
+
+  Contact Information:
+  http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+  BSD LICENSE
+
+  Copyright (c) 2005-2012 Intel Corporation. All rights reserved.
+  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 Intel Corporation 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 __JITPROFILING_H__
+#define __JITPROFILING_H__
+
+/*
+ * Various constants used by functions
+ */
+
+/* event notification */
+typedef enum iJIT_jvm_event
+{
+
+    /* shutdown  */
+    
+    /* 
+     * Program exiting EventSpecificData NA
+     */
+    iJVM_EVENT_TYPE_SHUTDOWN = 2, 
+
+    /* JIT profiling  */
+    
+    /* 
+     * issued after method code jitted into memory but before code is executed
+     * EventSpecificData is an iJIT_Method_Load
+     */
+    iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED=13,     
+
+    /* issued before unload. Method code will no longer be executed, but code 
+     * and info are still in memory. The VTune profiler may capture method 
+     * code only at this point EventSpecificData is iJIT_Method_Id
+     */
+    iJVM_EVENT_TYPE_METHOD_UNLOAD_START,         
+
+    /* Method Profiling */
+
+    /* method name, Id and stack is supplied 
+     * issued when a method is about to be entered EventSpecificData is 
+     * iJIT_Method_NIDS
+     */
+    iJVM_EVENT_TYPE_ENTER_NIDS = 19, 
+
+    /* method name, Id and stack is supplied 
+     * issued when a method is about to be left EventSpecificData is 
+     * iJIT_Method_NIDS
+     */
+    iJVM_EVENT_TYPE_LEAVE_NIDS               
+} iJIT_JVM_EVENT;
+
+typedef enum _iJIT_ModeFlags
+{
+    /* No need to Notify VTune, since VTune is not running */
+    iJIT_NO_NOTIFICATIONS          = 0x0000,     
+
+    /* when turned on the jit must call 
+     * iJIT_NotifyEvent
+     * (
+     *     iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
+     * )
+     * for all the method already jitted
+     */
+    iJIT_BE_NOTIFY_ON_LOAD         = 0x0001,     
+
+    /* when turned on the jit must call
+     * iJIT_NotifyEvent
+     * (
+     *     iJVM_EVENT_TYPE_METHOD_UNLOAD_FINISHED,
+     *  ) for all the method that are unloaded
+     */
+    iJIT_BE_NOTIFY_ON_UNLOAD       = 0x0002,     
+
+    /* when turned on the jit must instrument all
+     * the currently jited code with calls on
+     * method entries
+     */
+    iJIT_BE_NOTIFY_ON_METHOD_ENTRY = 0x0004,     
+
+    /* when turned on the jit must instrument all
+     * the currently jited code with calls
+     * on method exit
+     */
+    iJIT_BE_NOTIFY_ON_METHOD_EXIT  = 0x0008      
+
+} iJIT_ModeFlags;
+
+
+ /* Flags used by iJIT_IsProfilingActive() */
+typedef enum _iJIT_IsProfilingActiveFlags
+{
+    /* No profiler is running. Currently not used */
+    iJIT_NOTHING_RUNNING           = 0x0000,     
+
+    /* Sampling is running. This is the default value
+     * returned by iJIT_IsProfilingActive()
+     */
+    iJIT_SAMPLING_ON               = 0x0001,     
+    
+      /* Call Graph is running */
+    iJIT_CALLGRAPH_ON              = 0x0002
+
+} iJIT_IsProfilingActiveFlags;
+
+/* Enumerator for the environment of methods*/
+typedef enum _iJDEnvironmentType
+{
+    iJDE_JittingAPI = 2
+} iJDEnvironmentType;
+
+/**********************************
+ * Data structures for the events *
+ **********************************/
+
+/* structure for the events:
+ * iJVM_EVENT_TYPE_METHOD_UNLOAD_START
+ */
+
+typedef struct _iJIT_Method_Id
+{
+   /* Id of the method (same as the one passed in
+   * the iJIT_Method_Load struct
+   */
+    unsigned int       method_id;              
+
+} *piJIT_Method_Id, iJIT_Method_Id;
+
+
+/* structure for the events:
+ * iJVM_EVENT_TYPE_ENTER_NIDS,
+ * iJVM_EVENT_TYPE_LEAVE_NIDS,
+ * iJVM_EVENT_TYPE_EXCEPTION_OCCURRED_NIDS
+ */
+
+typedef struct _iJIT_Method_NIDS
+{
+    /* unique method ID */
+    unsigned int       method_id;              
+
+    /* NOTE: no need to fill this field, it's filled by VTune */
+    unsigned int       stack_id;               
+
+    /* method name (just the method, without the class) */
+    char*              method_name;            
+} *piJIT_Method_NIDS, iJIT_Method_NIDS;
+
+/* structures for the events:
+ * iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
+ */
+
+typedef struct _LineNumberInfo
+{
+    /* x86 Offset from the begining of the method*/
+    unsigned int        Offset;                 
+    
+    /* source line number from the begining of the source file */
+    unsigned int        LineNumber;             
+
+} *pLineNumberInfo, LineNumberInfo;
+
+typedef struct _iJIT_Method_Load
+{
+    /* unique method ID - can be any unique value, (except 0 - 999) */
+    unsigned int        method_id;              
+
+    /* method name (can be with or without the class and signature, in any case
+     * the class name will be added to it)
+     */
+    char*               method_name;            
+
+    /* virtual address of that method - This determines the method range for the
+     * iJVM_EVENT_TYPE_ENTER/LEAVE_METHOD_ADDR events
+     */
+    void*               method_load_address;    
+
+    /* Size in memory - Must be exact */
+    unsigned int        method_size;            
+
+    /* Line Table size in number of entries - Zero if none */
+    unsigned int        line_number_size;       
+    
+    /* Pointer to the begining of the line numbers info array */
+    pLineNumberInfo     line_number_table;      
+
+    /* unique class ID */
+    unsigned int        class_id;               
+    
+    /* class file name */
+    char*               class_file_name;        
+
+    /* source file name */
+    char*               source_file_name;       
+
+    /* bits supplied by the user for saving in the JIT file */
+    void*               user_data;              
+
+    /* the size of the user data buffer */
+    unsigned int        user_data_size;         
+
+    /* NOTE: no need to fill this field, it's filled by VTune */
+    iJDEnvironmentType  env;                    
+
+} *piJIT_Method_Load, iJIT_Method_Load;
+
+/* API Functions */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CDECL
+#  if defined WIN32 || defined _WIN32
+#    define CDECL __cdecl
+#  else /* defined WIN32 || defined _WIN32 */
+#    if defined _M_X64 || defined _M_AMD64 || defined __x86_64__
+#      define CDECL /* not actual on x86_64 platform */
+#    else  /* _M_X64 || _M_AMD64 || __x86_64__ */
+#      define CDECL __attribute__ ((cdecl))
+#    endif /* _M_X64 || _M_AMD64 || __x86_64__ */
+#  endif /* defined WIN32 || defined _WIN32 */
+#endif /* CDECL */
+
+#define JITAPI CDECL
+
+/* called when the settings are changed with new settings */
+typedef void (*iJIT_ModeChangedEx)(void *UserData, iJIT_ModeFlags Flags);
+
+int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData);
+
+/* The new mode call back routine */
+void JITAPI iJIT_RegisterCallbackEx(void *userdata, 
+                                    iJIT_ModeChangedEx NewModeCallBackFuncEx);
+
+iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void);
+
+void JITAPI FinalizeThread(void);
+
+void JITAPI FinalizeProcess(void);
+
+unsigned int JITAPI iJIT_GetNewMethodID(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JITPROFILING_H__ */
diff --git a/deps/v8/src/third_party/vtune/v8-vtune.h b/deps/v8/src/third_party/vtune/v8-vtune.h
new file mode 100644 (file)
index 0000000..36c11e6
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+   This file is provided under a dual BSD/GPLv2 license.  When using or
+   redistributing this file, you may do so under either license.
+   GPL LICENSE SUMMARY
+   Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of version 2 of the GNU General Public License as
+   published by the Free Software Foundation.
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+   The full GNU General Public License is included in this distribution
+   in the file called LICENSE.GPL.
+   Contact Information:
+   http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+   BSD LICENSE
+   Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+   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 Intel Corporation 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_VTUNE_H_
+#define V8_VTUNE_H_
+
+namespace vTune {
+
+void InitilizeVtuneForV8();
+
+}  // namespace vTune
+
+
+#endif  // V8_VTUNE_H_
+
diff --git a/deps/v8/src/third_party/vtune/v8vtune.gyp b/deps/v8/src/third_party/vtune/v8vtune.gyp
new file mode 100644 (file)
index 0000000..cabd37a
--- /dev/null
@@ -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.
+
+{
+  'includes': ['../../../build/common.gypi'],
+  'targets': [
+    {
+      'target_name': 'v8_vtune',
+      'type': 'static_library',
+      'dependencies': [
+        '../../../tools/gyp/v8.gyp:v8',
+      ],
+      'sources': [
+        'ittnotify_config.h',
+        'ittnotify_types.h',
+        'jitprofiling.cc',
+        'jitprofiling.h',
+        'v8-vtune.h',
+        'vtune-jit.cc',
+        'vtune-jit.h',
+      ],
+      'direct_dependent_settings': {
+        'defines': ['ENABLE_VTUNE_JIT_INTERFACE',],
+        'conditions': [
+          ['OS != "win"', {
+            'libraries': ['-ldl',],
+          }],   
+        ],
+      },
+    },
+  ],
+}
diff --git a/deps/v8/src/third_party/vtune/vtune-jit.cc b/deps/v8/src/third_party/vtune/vtune-jit.cc
new file mode 100644 (file)
index 0000000..6ff595f
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+  This file is provided under a dual BSD/GPLv2 license.  When using or
+  redistributing this file, you may do so under either license.
+
+  GPL LICENSE SUMMARY
+
+  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  The full GNU General Public License is included in this distribution
+  in the file called LICENSE.GPL.
+
+  Contact Information:
+  http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+  BSD LICENSE
+
+  Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+  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 Intel Corporation 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 <string.h>
+
+#ifdef WIN32
+#include <hash_map>
+using namespace std;
+#else
+// To avoid GCC 4.4 compilation warning about hash_map being deprecated.
+#define OLD_DEPRECATED __DEPRECATED
+#undef __DEPRECATED
+#include <ext/hash_map>
+#define __DEPRECATED OLD_DEPRECATED
+using namespace __gnu_cxx;
+#endif
+
+#include <list>
+
+#include "v8-vtune.h"
+#include "vtune-jit.h"
+
+namespace vTune {
+namespace internal {
+
+
+// This class is used to record the JITted code position info for JIT
+// code profiling.
+class JITCodeLineInfo {
+ public:
+  JITCodeLineInfo() { }
+
+  void SetPosition(intptr_t pc, int pos) {
+    AddCodeLineInfo(LineNumInfo(pc, pos));
+  }
+
+  struct LineNumInfo {
+    LineNumInfo(intptr_t pc, int pos)
+        : pc_(pc), pos_(pos) { }
+
+    intptr_t pc_;
+    int pos_;
+  };
+
+  std::list<LineNumInfo>* GetLineNumInfo() {
+    return &line_num_info_;
+  }
+
+ private:
+  void AddCodeLineInfo(const LineNumInfo& line_info) {
+         line_num_info_.push_back(line_info);
+  }
+  std::list<LineNumInfo> line_num_info_;
+};
+
+struct SameCodeObjects {
+  bool operator () (void* key1, void* key2) const {
+    return key1 == key2;
+  }
+};
+
+struct HashForCodeObject {
+  uint32_t operator () (void* code) const {
+    static const uintptr_t kGoldenRatio = 2654435761u;
+    uintptr_t hash = reinterpret_cast<uintptr_t>(code);
+    return static_cast<uint32_t>(hash * kGoldenRatio);
+  }
+};
+
+#ifdef WIN32
+typedef hash_map<void*, void*> JitInfoMap;
+#else
+typedef hash_map<void*, void*, HashForCodeObject, SameCodeObjects> JitInfoMap;
+#endif
+
+static JitInfoMap* GetEntries() {
+  static JitInfoMap* entries;
+  if (entries == NULL) {
+    entries = new JitInfoMap();
+  }
+  return entries;
+}
+
+static bool IsLineInfoTagged(void* ptr) {
+  return 0 != (reinterpret_cast<intptr_t>(ptr));
+}
+
+static JITCodeLineInfo* UntagLineInfo(void* ptr) {
+  return reinterpret_cast<JITCodeLineInfo*>(
+    reinterpret_cast<intptr_t>(ptr));
+}
+
+// The parameter str is a mixed pattern which contains the
+// function name and some other info. It comes from all the
+// Logger::CodeCreateEvent(...) function. This funtion get the
+// pure function name from the input parameter.
+static char* GetFunctionNameFromMixedName(const char* str, int length) {
+  int index = 0;
+  int count = 0;
+  char* start_ptr = NULL;
+
+  while (str[index++] != ':' && (index < length)) {}
+
+  if (str[index] == '*' || str[index] == '~' ) index++;
+  if (index >= length) return NULL;
+
+  start_ptr = const_cast<char*>(str + index);
+
+  while (index < length && str[index++] != ' ') {
+    count++;
+  }
+
+  char* result = new char[count + 1];
+  memcpy(result, start_ptr, count);
+  result[count] = '\0';
+
+  return result;
+}
+
+// The JitCodeEventHandler for Vtune.
+void VTUNEJITInterface::event_handler(const v8::JitCodeEvent* event) {
+  if (VTUNERUNNING && event != NULL) {
+    switch (event->type) {
+      case v8::JitCodeEvent::CODE_ADDED: {
+        char* temp_file_name = NULL;
+        char* temp_method_name =
+            GetFunctionNameFromMixedName(event->name.str,
+                                         static_cast<int>(event->name.len));
+        iJIT_Method_Load jmethod;
+        memset(&jmethod, 0, sizeof jmethod);
+        jmethod.method_id = iJIT_GetNewMethodID();
+        jmethod.method_load_address = event->code_start;
+        jmethod.method_size = static_cast<unsigned int>(event->code_len);
+        jmethod.method_name = temp_method_name;
+
+        Handle<Script> script = event->script;
+               
+        if (*script != NULL) {
+          // Get the source file name and set it to jmethod.source_file_name
+         if ((*script->GetScriptName())->IsString()) {
+            Handle<String> script_name =
+                Handle<String>(String::Cast(*script->GetScriptName()));
+            temp_file_name = new char[script_name->Length() + 1];
+            script_name->WriteAscii(temp_file_name);
+            jmethod.source_file_name = temp_file_name;
+          }
+
+          JitInfoMap::iterator entry =
+              GetEntries()->find(event->code_start);
+          if (entry != GetEntries()->end() && IsLineInfoTagged(entry->first)) {
+            JITCodeLineInfo* line_info = UntagLineInfo(entry->second);
+            // Get the line_num_info and set it to jmethod.line_number_table
+            std::list<JITCodeLineInfo::LineNumInfo>* vtunelineinfo =
+                line_info->GetLineNumInfo();
+
+            jmethod.line_number_size = (unsigned int)vtunelineinfo->size();
+            jmethod.line_number_table =
+                reinterpret_cast<LineNumberInfo*>(
+                    malloc(sizeof(LineNumberInfo)*jmethod.line_number_size));
+
+            std::list<JITCodeLineInfo::LineNumInfo>::iterator Iter;
+            int index = 0;
+            for (Iter = vtunelineinfo->begin();
+                 Iter != vtunelineinfo->end();
+                 Iter++) {
+              jmethod.line_number_table[index].Offset =
+                  static_cast<unsigned int>(Iter->pc_);
+              jmethod.line_number_table[index++].LineNumber =
+                                 script->GetLineNumber(Iter->pos_)+1;
+            }
+            GetEntries()->erase(event->code_start);
+          }
+        } 
+
+        iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
+                         reinterpret_cast<void*>(&jmethod));
+        if (temp_method_name)
+          delete []temp_method_name;
+        if (temp_file_name)
+          delete []temp_file_name;
+        break;
+      }
+      // TODO(chunyang.dai@intel.com): code_move will be supported.
+      case v8::JitCodeEvent::CODE_MOVED:
+        break;
+      // Currently the CODE_REMOVED event is not issued.
+      case v8::JitCodeEvent::CODE_REMOVED:
+        break;
+      case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
+        JITCodeLineInfo* line_info =
+            reinterpret_cast<JITCodeLineInfo*>(event->user_data);
+        if (line_info != NULL) {
+          line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset),
+                                 static_cast<int>(event->line_info.pos));
+        }
+        break;
+      }
+      case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
+        v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
+        temp_event->user_data = new JITCodeLineInfo();
+        break;
+      }
+      case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
+        GetEntries()->insert(std::pair <void*, void*>(event->code_start, event->user_data));
+        break;
+      } 
+      default:
+        break;
+    }
+  } 
+  return;
+}
+
+}  // namespace internal
+
+void InitilizeVtuneForV8() {
+  if (v8::V8::Initialize()) {
+    v8::V8::SetFlagsFromString("--nocompact_code_space",
+                              (int)strlen("--nocompact_code_space"));
+    v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+        vTune::internal::VTUNEJITInterface::event_handler);
+  }
+}
+
+}  // namespace vTune
diff --git a/deps/v8/src/third_party/vtune/vtune-jit.h b/deps/v8/src/third_party/vtune/vtune-jit.h
new file mode 100644 (file)
index 0000000..42b8c3d
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+   This file is provided under a dual BSD/GPLv2 license.  When using or
+   redistributing this file, you may do so under either license.
+   GPL LICENSE SUMMARY
+   Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of version 2 of the GNU General Public License as
+   published by the Free Software Foundation.
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+   The full GNU General Public License is included in this distribution
+   in the file called LICENSE.GPL.
+   Contact Information:
+   http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+   BSD LICENSE
+   Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
+   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 Intel Corporation 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 VTUNE_VTUNE_JIT_H_
+#define VTUNE_VTUNE_JIT_H_
+
+#include "jitprofiling.h"
+#include "../../../include/v8.h"
+
+#define VTUNERUNNING (iJIT_IsProfilingActive() == iJIT_SAMPLING_ON)
+
+namespace vTune {
+namespace internal {
+using namespace v8;
+class VTUNEJITInterface {
+ public:
+  static void event_handler(const v8::JitCodeEvent* event);
+
+ private:
+  //static Mutex* vtunemutex_;
+};
+
+
+} }  // namespace vTune::internal
+
+
+#endif  // VTUNE_VTUNE_JIT_H_
+
index c3e3ebd..24fcf1e 100644 (file)
 
 "use strict";
 
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
 var $ArrayBuffer = global.__ArrayBuffer;
 
+// -------------------------------------------------------------------
+
 function ArrayBufferConstructor(byteLength) { // length = 1
   if (%_IsConstructCall()) {
     var l = TO_POSITIVE_INTEGER(byteLength);
@@ -76,15 +82,74 @@ function ArrayBufferSlice(start, end) {
   return result;
 }
 
+// --------------- Typed Arrays ---------------------
+
+function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
+  return function (buffer, byteOffset, length) {
+    if (%_IsConstructCall()) {
+      if (!IS_ARRAYBUFFER(buffer)) {
+        throw MakeTypeError("Type error!");
+      }
+      var offset = IS_UNDEFINED(byteOffset)
+        ? 0 : offset = TO_POSITIVE_INTEGER(byteOffset);
+
+      if (offset % elementSize !== 0) {
+        throw MakeRangeError("invalid_typed_array_alignment",
+            "start offset", name, elementSize);
+      }
+      var bufferByteLength = %ArrayBufferGetByteLength(buffer);
+      if (offset >= bufferByteLength) {
+        throw MakeRangeError("invalid_typed_array_offset");
+      }
+
+      var newByteLength;
+      var newLength;
+      if (IS_UNDEFINED(length)) {
+        if (bufferByteLength % elementSize !== 0) {
+          throw MakeRangeError("invalid_typed_array_alignment",
+            "byte length", name, elementSize);
+        }
+        newByteLength = bufferByteLength - offset;
+        newLength = newByteLength / elementSize;
+      } else {
+        var newLength = TO_POSITIVE_INTEGER(length);
+        newByteLength = newLength * elementSize;
+      }
+      if (newByteLength > bufferByteLength) {
+        throw MakeRangeError("invalid_typed_array_length");
+      }
+      %TypedArrayInitialize(this, arrayId, buffer, offset, newByteLength);
+    } else {
+      return new constructor(buffer, byteOffset, length);
+    }
+  }
+}
+
+function TypedArrayGetBuffer() {
+  return %TypedArrayGetBuffer(this);
+}
+
+function TypedArrayGetByteLength() {
+  return %TypedArrayGetByteLength(this);
+}
+
+function TypedArrayGetByteOffset() {
+  return %TypedArrayGetByteOffset(this);
+}
+
+function TypedArrayGetLength() {
+  return %TypedArrayGetLength(this);
+}
 
 
 // -------------------------------------------------------------------
 
-(function () {
+function SetUpArrayBuffer() {
   %CheckIsBootstrapping();
 
-  // Set up the Uint16Array constructor function.
+  // Set up the ArrayBuffer constructor function.
   %SetCode($ArrayBuffer, ArrayBufferConstructor);
+  %FunctionSetPrototype($ArrayBuffer, new $Object());
 
   // Set up the constructor property on the ArrayBuffer prototype object.
   %SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM);
@@ -94,5 +159,34 @@ function ArrayBufferSlice(start, end) {
   InstallFunctions($ArrayBuffer.prototype, DONT_ENUM, $Array(
       "slice", ArrayBufferSlice
   ));
+}
+
+SetUpArrayBuffer();
+
+function SetupTypedArray(arrayId, name, constructor, elementSize) {
+  var f = CreateTypedArrayConstructor(name, elementSize,
+                                      arrayId, constructor);
+  %SetCode(constructor, f);
+  %FunctionSetPrototype(constructor, new $Object());
+
+  %SetProperty(constructor.prototype,
+               "constructor", constructor, DONT_ENUM);
+  %SetProperty(constructor.prototype,
+               "BYTES_PER_ELEMENT", elementSize,
+               READ_ONLY | DONT_ENUM | DONT_DELETE);
+  InstallGetter(constructor.prototype, "buffer", TypedArrayGetBuffer);
+  InstallGetter(constructor.prototype, "byteOffset", TypedArrayGetByteOffset);
+  InstallGetter(constructor.prototype, "byteLength", TypedArrayGetByteLength);
+  InstallGetter(constructor.prototype, "length", TypedArrayGetLength);
+}
+
+// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
+SetupTypedArray(1, "Uint8Array", global.__Uint8Array, 1);
+SetupTypedArray(2, "Int8Array", global.__Int8Array, 1);
+SetupTypedArray(3, "Uint16Array", global.__Uint16Array, 2);
+SetupTypedArray(4, "Int16Array", global.__Int16Array, 2);
+SetupTypedArray(5, "Uint32Array", global.__Uint32Array, 4);
+SetupTypedArray(6, "Int32Array", global.__Int32Array, 4);
+SetupTypedArray(7, "Float32Array", global.__Float32Array, 4);
+SetupTypedArray(8, "Float64Array", global.__Float64Array, 8);
 
-})();
index 02be457..f861f9f 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "unicode.h"
 #include "checks.h"
+#include "platform.h"
 
 namespace unibrow {
 
@@ -202,7 +203,7 @@ unsigned Utf8Decoder<kBufferSize>::WriteUtf16(uint16_t* data,
   unsigned buffer_length =
       last_byte_of_buffer_unused_ ? kBufferSize - 1 : kBufferSize;
   unsigned memcpy_length = length <= buffer_length  ? length : buffer_length;
-  memcpy(data, buffer_, memcpy_length*sizeof(uint16_t));
+  v8::internal::OS::MemCopy(data, buffer_, memcpy_length*sizeof(uint16_t));
   if (length <= buffer_length) return length;
   ASSERT(unbuffered_start_ != NULL);
   // Copy the rest the slow way.
index 1de22f8..4e3f084 100644 (file)
 // (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 relies on the fact that the following declaration has been made
+// in runtime.js:
+// var $Array = global.Array;
+
+// -------------------------------------------------------------------
+
 // This file contains support for URI manipulations written in
 // JavaScript.
 
-// Expect $String = global.String;
-
 // Lazily initialized.
 var hexCharArray = 0;
 var hexCharCodeArray = 0;
@@ -437,6 +441,7 @@ function URIUnescape(str) {
 
 function SetUpUri() {
   %CheckIsBootstrapping();
+
   // Set up non-enumerable URI functions on the global object and set
   // their names.
   InstallFunctions(global, DONT_ENUM, $Array(
index 7e8c088..8462615 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdarg.h>
 #include "../include/v8stdint.h"
 #include "checks.h"
+#include "platform.h"
 #include "utils.h"
 
 namespace v8 {
@@ -46,9 +47,9 @@ void SimpleStringBuilder::AddString(const char* s) {
 
 
 void SimpleStringBuilder::AddSubstring(const char* s, int n) {
-  ASSERT(!is_finalized() && position_ + n < buffer_.length());
+  ASSERT(!is_finalized() && position_ + n <= buffer_.length());
   ASSERT(static_cast<size_t>(n) <= strlen(s));
-  memcpy(&buffer_[position_], s, n * kCharSize);
+  OS::MemCopy(&buffer_[position_], s, n * kCharSize);
   position_ += n;
 }
 
@@ -79,7 +80,13 @@ void SimpleStringBuilder::AddDecimalInteger(int32_t value) {
 
 
 char* SimpleStringBuilder::Finalize() {
-  ASSERT(!is_finalized() && position_ < buffer_.length());
+  ASSERT(!is_finalized() && position_ <= buffer_.length());
+  // If there is no space for null termination, overwrite last character.
+  if (position_ == buffer_.length()) {
+    position_--;
+    // Print ellipsis.
+    for (int i = 3; i > 0 && position_ > i; --i) buffer_[position_ - i] = '.';
+  }
   buffer_[position_] = '\0';
   // Make sure nobody managed to add a 0-character to the
   // buffer while building the string.
index c391b9c..b84d592 100644 (file)
@@ -32,9 +32,9 @@
 #include <string.h>
 #include <climits>
 
-#include "globals.h"
-#include "checks.h"
 #include "allocation.h"
+#include "checks.h"
+#include "globals.h"
 
 namespace v8 {
 namespace internal {
@@ -494,6 +494,7 @@ class EmbeddedVector : public Vector<T> {
   // When copying, make underlying Vector to reference our buffer.
   EmbeddedVector(const EmbeddedVector& rhs)
       : Vector<T>(rhs) {
+    // TODO(jkummerow): Refactor #includes and use OS::MemCopy() instead.
     memcpy(buffer_, rhs.buffer_, sizeof(T) * kSize);
     set_start(buffer_);
   }
@@ -501,6 +502,7 @@ class EmbeddedVector : public Vector<T> {
   EmbeddedVector& operator=(const EmbeddedVector& rhs) {
     if (this == &rhs) return *this;
     Vector<T>::operator=(rhs);
+    // TODO(jkummerow): Refactor #includes and use OS::MemCopy() instead.
     memcpy(buffer_, rhs.buffer_, sizeof(T) * kSize);
     this->set_start(buffer_);
     return *this;
@@ -876,6 +878,7 @@ struct BitCastHelper {
 
   INLINE(static Dest cast(const Source& source)) {
     Dest dest;
+    // TODO(jkummerow): Refactor #includes and use OS::MemCopy() instead.
     memcpy(&dest, &source, sizeof(dest));
     return dest;
   }
@@ -1019,6 +1022,9 @@ class EnumSet {
   void Intersect(const EnumSet& set) { bits_ &= set.bits_; }
   T ToIntegral() const { return bits_; }
   bool operator==(const EnumSet& set) { return bits_ == set.bits_; }
+  EnumSet<E, T> operator|(const EnumSet& set) const {
+    return EnumSet<E, T>(bits_ | set.bits_);
+  }
 
  private:
   T Mask(E element) const {
index 2e8cd50..274128e 100644 (file)
 #include "heap-profiler.h"
 #include "hydrogen.h"
 #include "lithium-allocator.h"
-#include "log.h"
 #include "objects.h"
 #include "once.h"
 #include "platform.h"
+#include "sampler.h"
 #include "runtime-profiler.h"
 #include "serialize.h"
 #include "store-buffer.h"
@@ -123,6 +123,7 @@ void V8::TearDown() {
   delete call_completed_callbacks_;
   call_completed_callbacks_ = NULL;
 
+  Sampler::TearDown();
   OS::TearDown();
 }
 
@@ -270,16 +271,15 @@ void V8::InitializeOncePerProcessImpl() {
   }
   if (FLAG_trace_hydrogen) FLAG_parallel_recompilation = false;
   OS::SetUp();
+  Sampler::SetUp();
   CPU::SetUp();
   use_crankshaft_ = FLAG_crankshaft
       && !Serializer::enabled()
       && CPU::SupportsCrankshaft();
   OS::PostSetUp();
-  RuntimeProfiler::GlobalSetUp();
   ElementsAccessor::InitializeOncePerProcess();
   LOperand::SetUpCaches();
   SetUpJSCallerSavedCodeData();
-  SamplerRegistry::SetUp();
   ExternalReference::SetUp();
 }
 
index 0147d8c..9d618af 100644 (file)
@@ -55,6 +55,19 @@ double StringToDouble(UnicodeCache* unicode_cache,
 // Converts a string into an integer.
 double StringToInt(UnicodeCache* unicode_cache, String* str, int radix);
 
+// Converts a number into size_t.
+inline size_t NumberToSize(Isolate* isolate,
+                           Object* number) {
+  NoHandleAllocation hc(isolate);
+  if (number->IsSmi()) {
+    return Smi::cast(number)->value();
+  } else {
+    ASSERT(number->IsHeapNumber());
+    double value = HeapNumber::cast(number)->value();
+    return static_cast<size_t>(value);
+  }
+}
+
 } }  // namespace v8::internal
 
 #endif  // V8_V8CONVERSIONS_H_
index 4b4d312..82e30f5 100644 (file)
@@ -163,7 +163,6 @@ class RelocInfo;
 class Deserializer;
 class MessageLocation;
 class ObjectGroup;
-class TickSample;
 class VirtualMemory;
 class Mutex;
 
@@ -433,11 +432,10 @@ enum CpuFeature { SSE4_1 = 32 + 19,  // x86
                   CPUID = 10,  // x86
                   VFP3 = 1,    // ARM
                   ARMv7 = 2,   // ARM
-                  VFP2 = 3,    // ARM
-                  SUDIV = 4,   // ARM
-                  UNALIGNED_ACCESSES = 5,  // ARM
-                  MOVW_MOVT_IMMEDIATE_LOADS = 6,  // ARM
-                  VFP32DREGS = 7,  // ARM
+                  SUDIV = 3,   // ARM
+                  UNALIGNED_ACCESSES = 4,  // ARM
+                  MOVW_MOVT_IMMEDIATE_LOADS = 5,  // ARM
+                  VFP32DREGS = 6,  // ARM
                   SAHF = 0,    // x86
                   FPU = 1};    // MIPS
 
@@ -496,8 +494,8 @@ enum VariableMode {
   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
+  TEMPORARY,       // temporary variables (not user-visible), stack-allocated
+                   // unless the scope as a whole has forced context allocation
 
   DYNAMIC,         // always require dynamic lookup (we don't know
                    // the declaration)
index d9dc096..83b5618 100644 (file)
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // This file relies on the fact that the following declarations have been made
-//
 // in runtime.js:
 // var $Object = global.Object;
 // var $Boolean = global.Boolean;
@@ -43,7 +42,6 @@ var $isFinite = GlobalIsFinite;
 
 // ----------------------------------------------------------------------------
 
-
 // Helper function used to install functions on objects.
 function InstallFunctions(object, attributes, functions) {
   if (functions.length >= 8) {
@@ -61,7 +59,7 @@ function InstallFunctions(object, attributes, functions) {
 }
 
 
-// Helper function to install a getter only property.
+// Helper function to install a getter-only accessor property.
 function InstallGetter(object, name, getter) {
   %FunctionSetName(getter, name);
   %FunctionRemovePrototype(getter);
@@ -70,6 +68,18 @@ function InstallGetter(object, name, getter) {
 }
 
 
+// Helper function to install a getter/setter accessor property.
+function InstallGetterSetter(object, name, getter, setter) {
+  %FunctionSetName(getter, name);
+  %FunctionSetName(setter, name);
+  %FunctionRemovePrototype(getter);
+  %FunctionRemovePrototype(setter);
+  %DefineOrRedefineAccessorProperty(object, name, getter, setter, DONT_ENUM);
+  %SetNativeFlag(getter);
+  %SetNativeFlag(setter);
+}
+
+
 // 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
@@ -186,6 +196,7 @@ function GlobalEval(x) {
 // Set up global object.
 function SetUpGlobal() {
   %CheckIsBootstrapping();
+
   // ECMA 262 - 15.1.1.1.
   %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
 
@@ -208,27 +219,10 @@ function SetUpGlobal() {
 
 SetUpGlobal();
 
-// ----------------------------------------------------------------------------
-// Boolean (first part of definition)
-
-
-%SetCode($Boolean, function(x) {
-  if (%_IsConstructCall()) {
-    %_SetValueOf(this, ToBoolean(x));
-  } else {
-    return ToBoolean(x);
-  }
-});
-
-%FunctionSetPrototype($Boolean, new $Boolean(false));
-
-%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
 
 // ----------------------------------------------------------------------------
 // Object
 
-$Object.prototype.constructor = $Object;
-
 // ECMA-262 - 15.2.4.2
 function ObjectToString() {
   if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
@@ -395,7 +389,8 @@ function FromPropertyDescriptor(desc) {
   }
   // Must be an AccessorDescriptor then. We never return a generic descriptor.
   return { get: desc.getGet(),
-           set: desc.getSet(),
+           set: desc.getSet() === ObjectSetProto ? ObjectPoisonProto
+                                                 : desc.getSet(),
            enumerable: desc.isEnumerable(),
            configurable: desc.isConfigurable() };
 }
@@ -937,7 +932,7 @@ function DefineArrayProperty(obj, p, desc, should_throw) {
 
   // Step 4 - Special handling for array index.
   var index = ToUint32(p);
-  if (index == ToNumber(p) && index != 4294967295) {
+  if (ToString(index) == p && index != 4294967295) {
     var length = obj.length;
     var length_desc = GetOwnProperty(obj, "length");
     if ((index >= length && !length_desc.isWritable()) ||
@@ -1326,7 +1321,25 @@ function ObjectIs(obj1, obj2) {
 }
 
 
-%SetCode($Object, function(x) {
+// Harmony __proto__ getter.
+function ObjectGetProto() {
+  return %GetPrototype(this);
+}
+
+
+// Harmony __proto__ setter.
+function ObjectSetProto(obj) {
+  return %SetPrototype(this, obj);
+}
+
+
+// Harmony __proto__ poison pill.
+function ObjectPoisonProto(obj) {
+  throw MakeTypeError("proto_poison_pill", []);
+}
+
+
+function ObjectConstructor(x) {
   if (%_IsConstructCall()) {
     if (x == null) return this;
     return ToObject(x);
@@ -1334,16 +1347,23 @@ function ObjectIs(obj1, obj2) {
     if (x == null) return { };
     return ToObject(x);
   }
-});
+}
 
-%SetExpectedNumberOfProperties($Object, 4);
 
 // ----------------------------------------------------------------------------
 // Object
 
 function SetUpObject() {
   %CheckIsBootstrapping();
-  // Set Up non-enumerable functions on the Object.prototype object.
+
+  %SetCode($Object, ObjectConstructor);
+  %FunctionSetName(ObjectPoisonProto, "__proto__");
+  %FunctionRemovePrototype(ObjectPoisonProto);
+  %SetExpectedNumberOfProperties($Object, 4);
+
+  %SetProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
+
+  // Set up non-enumerable functions on the Object.prototype object.
   InstallFunctions($Object.prototype, DONT_ENUM, $Array(
     "toString", ObjectToString,
     "toLocaleString", ObjectToLocaleString,
@@ -1356,6 +1376,10 @@ function SetUpObject() {
     "__defineSetter__", ObjectDefineSetter,
     "__lookupSetter__", ObjectLookupSetter
   ));
+  InstallGetterSetter($Object.prototype, "__proto__",
+                      ObjectGetProto, ObjectSetProto);
+
+  // Set up non-enumerable functions in the Object object.
   InstallFunctions($Object, DONT_ENUM, $Array(
     "keys", ObjectKeys,
     "create", ObjectCreate,
@@ -1376,9 +1400,19 @@ function SetUpObject() {
 
 SetUpObject();
 
+
 // ----------------------------------------------------------------------------
 // Boolean
 
+function BooleanConstructor(x) {
+  if (%_IsConstructCall()) {
+    %_SetValueOf(this, ToBoolean(x));
+  } else {
+    return ToBoolean(x);
+  }
+}
+
+
 function BooleanToString() {
   // NOTE: Both Boolean objects and values can enter here as
   // 'this'. This is not as dictated by ECMA-262.
@@ -1405,9 +1439,13 @@ function BooleanValueOf() {
 
 // ----------------------------------------------------------------------------
 
-
 function SetUpBoolean () {
   %CheckIsBootstrapping();
+
+  %SetCode($Boolean, BooleanConstructor);
+  %FunctionSetPrototype($Boolean, new $Boolean(false));
+  %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
+
   InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
     "toString", BooleanToString,
     "valueOf", BooleanValueOf
@@ -1420,17 +1458,15 @@ SetUpBoolean();
 // ----------------------------------------------------------------------------
 // Number
 
-// Set the Number function and constructor.
-%SetCode($Number, function(x) {
+function NumberConstructor(x) {
   var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
   if (%_IsConstructCall()) {
     %_SetValueOf(this, value);
   } else {
     return value;
   }
-});
+}
 
-%FunctionSetPrototype($Number, new $Number(0));
 
 // ECMA-262 section 15.7.4.2.
 function NumberToString(radix) {
@@ -1568,6 +1604,10 @@ function NumberIsNaN(number) {
 
 function SetUpNumber() {
   %CheckIsBootstrapping();
+
+  %SetCode($Number, NumberConstructor);
+  %FunctionSetPrototype($Number, new $Number(0));
+
   %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
   // Set up the constructor property on the Number prototype object.
   %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
@@ -1620,13 +1660,12 @@ SetUpNumber();
 // ----------------------------------------------------------------------------
 // Function
 
-$Function.prototype.constructor = $Function;
-
 function FunctionSourceString(func) {
   while (%IsJSFunctionProxy(func)) {
     func = %GetCallTrap(func);
   }
 
+  // TODO(wingo): Print source using function* for generators.
   if (!IS_FUNCTION(func)) {
     throw new $TypeError('Function.prototype.toString is not generic');
   }
@@ -1745,12 +1784,15 @@ function NewFunction(arg1) {  // length == 1
   return %SetNewFunctionAttributes(f);
 }
 
-%SetCode($Function, NewFunction);
 
 // ----------------------------------------------------------------------------
 
 function SetUpFunction() {
   %CheckIsBootstrapping();
+
+  %SetCode($Function, NewFunction);
+  %SetProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
+
   InstallFunctions($Function.prototype, DONT_ENUM, $Array(
     "bind", FunctionBind,
     "toString", FunctionToString
index 58ad4e5..7390d85 100644 (file)
@@ -105,12 +105,12 @@ char* ReadLine(const char* prompt) {
       char* new_result = NewArray<char>(new_len);
       // Copy the existing input into the new array and set the new
       // array as the result.
-      memcpy(new_result, result, offset * kCharSize);
+      OS::MemCopy(new_result, result, offset * kCharSize);
       DeleteArray(result);
       result = new_result;
     }
     // Copy the newly read line into the result.
-    memcpy(result + offset, line_buf, len * kCharSize);
+    OS::MemCopy(result + offset, line_buf, len * kCharSize);
     offset += len;
   }
   ASSERT(result != NULL);
@@ -264,7 +264,7 @@ void StringBuilder::AddFormatted(const char* format, ...) {
 
 
 void StringBuilder::AddFormattedList(const char* format, va_list list) {
-  ASSERT(!is_finalized() && position_ < buffer_.length());
+  ASSERT(!is_finalized() && position_ <= buffer_.length());
   int n = OS::VSNPrintF(buffer_ + position_, format, list);
   if (n < 0 || n >= (buffer_.length() - position_)) {
     position_ = buffer_.length();
index b5c8f08..8661f9b 100644 (file)
@@ -125,49 +125,126 @@ inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
 // ----------------------------------------------------------------------------
 // Memory
 
-// Copies data from |src| to |dst|.  The data spans must not overlap.
+// Copies words from |src| to |dst|. The data spans must not overlap.
 template <typename T>
-inline void CopyWords(T* dst, T* src, int num_words) {
+inline void CopyWords(T* dst, const T* src, size_t num_words) {
   STATIC_ASSERT(sizeof(T) == kPointerSize);
-  ASSERT(Min(dst, src) + num_words <= Max(dst, src));
+  ASSERT(Min(dst, const_cast<T*>(src)) + num_words <=
+         Max(dst, const_cast<T*>(src)));
   ASSERT(num_words > 0);
 
   // Use block copying OS::MemCopy if the segment we're copying is
   // enough to justify the extra call/setup overhead.
-  static const int kBlockCopyLimit = 16;
-  STATIC_ASSERT(kBlockCopyLimit * kPointerSize >= OS::kMinComplexMemCopy);
+  static const size_t kBlockCopyLimit = 16;
 
-  if (num_words >= kBlockCopyLimit) {
-    OS::MemCopy(dst, src, num_words * kPointerSize);
+  if (num_words < kBlockCopyLimit) {
+    do {
+      num_words--;
+      *dst++ = *src++;
+    } while (num_words > 0);
   } else {
-    int remaining = num_words;
+    OS::MemCopy(dst, src, num_words * kPointerSize);
+  }
+}
+
+
+// Copies words from |src| to |dst|. No restrictions.
+template <typename T>
+inline void MoveWords(T* dst, const T* src, size_t num_words) {
+  STATIC_ASSERT(sizeof(T) == kPointerSize);
+  ASSERT(num_words > 0);
+
+  // Use block copying OS::MemCopy if the segment we're copying is
+  // enough to justify the extra call/setup overhead.
+  static const size_t kBlockCopyLimit = 16;
+
+  if (num_words < kBlockCopyLimit &&
+      ((dst < src) || (dst >= (src + num_words * kPointerSize)))) {
+    T* end = dst + num_words;
     do {
-      remaining--;
+      num_words--;
       *dst++ = *src++;
-    } while (remaining > 0);
+    } while (num_words > 0);
+  } else {
+    OS::MemMove(dst, src, num_words * kPointerSize);
   }
 }
 
 
 // Copies data from |src| to |dst|.  The data spans must not overlap.
 template <typename T>
-inline void CopyBytes(T* dst, T* src, size_t num_bytes) {
+inline void CopyBytes(T* dst, const T* src, size_t num_bytes) {
   STATIC_ASSERT(sizeof(T) == 1);
-  ASSERT(Min(dst, src) + num_bytes <= Max(dst, src));
+  ASSERT(Min(dst, const_cast<T*>(src)) + num_bytes <=
+         Max(dst, const_cast<T*>(src)));
   if (num_bytes == 0) return;
 
   // Use block copying OS::MemCopy if the segment we're copying is
   // enough to justify the extra call/setup overhead.
   static const int kBlockCopyLimit = OS::kMinComplexMemCopy;
 
-  if (num_bytes >= static_cast<size_t>(kBlockCopyLimit)) {
-    OS::MemCopy(dst, src, num_bytes);
-  } else {
-    size_t remaining = num_bytes;
+  if (num_bytes < static_cast<size_t>(kBlockCopyLimit)) {
     do {
-      remaining--;
+      num_bytes--;
       *dst++ = *src++;
-    } while (remaining > 0);
+    } while (num_bytes > 0);
+  } else {
+    OS::MemCopy(dst, src, num_bytes);
+  }
+}
+
+
+// Copies data from |src| to |dst|. No restrictions.
+template <typename T>
+inline void MoveBytes(T* dst, const T* src, size_t num_bytes) {
+  STATIC_ASSERT(sizeof(T) == 1);
+  switch (num_bytes) {
+  case 0: return;
+  case 1:
+    *dst = *src;
+    return;
+#ifdef V8_HOST_CAN_READ_UNALIGNED
+  case 2:
+    *reinterpret_cast<uint16_t*>(dst) = *reinterpret_cast<const uint16_t*>(src);
+    return;
+  case 3: {
+    uint16_t part1 = *reinterpret_cast<const uint16_t*>(src);
+    byte part2 = *(src + 2);
+    *reinterpret_cast<uint16_t*>(dst) = part1;
+    *(dst + 2) = part2;
+    return;
+  }
+  case 4:
+    *reinterpret_cast<uint32_t*>(dst) = *reinterpret_cast<const uint32_t*>(src);
+    return;
+  case 5:
+  case 6:
+  case 7:
+  case 8: {
+    uint32_t part1 = *reinterpret_cast<const uint32_t*>(src);
+    uint32_t part2 = *reinterpret_cast<const uint32_t*>(src + num_bytes - 4);
+    *reinterpret_cast<uint32_t*>(dst) = part1;
+    *reinterpret_cast<uint32_t*>(dst + num_bytes - 4) = part2;
+    return;
+  }
+  case 9:
+  case 10:
+  case 11:
+  case 12:
+  case 13:
+  case 14:
+  case 15:
+  case 16: {
+    double part1 = *reinterpret_cast<const double*>(src);
+    double part2 = *reinterpret_cast<const double*>(src + num_bytes - 8);
+    *reinterpret_cast<double*>(dst) = part1;
+    *reinterpret_cast<double*>(dst + num_bytes - 8) = part2;
+    return;
+  }
+#endif
+  default:
+    OS::MemMove(dst, src, num_bytes);
+    return;
   }
 }
 
@@ -185,6 +262,13 @@ inline void MemsetPointer(T** dest, U* value, int counter) {
 #elif defined(V8_HOST_ARCH_X64)
 #define STOS "stosq"
 #endif
+#if defined(__native_client__)
+  // This STOS sequence does not validate for x86_64 Native Client.
+  // Here we #undef STOS to force use of the slower C version.
+  // TODO(bradchen): Profile V8 and implement a faster REP STOS
+  // here if the profile indicates it matters.
+#undef STOS
+#endif
 
 #if defined(__GNUC__) && defined(STOS)
   asm volatile(
index 64ed98d..933e254 100644 (file)
@@ -33,8 +33,8 @@
 // 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     17
-#define BUILD_NUMBER      16
+#define MINOR_VERSION     18
+#define BUILD_NUMBER      0
 #define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
index 57d40f7..25979f9 100644 (file)
@@ -150,9 +150,8 @@ void CpuFeatures::Probe() {
   found_by_runtime_probing_only_
       = probed_features & ~kDefaultCpuFeatures & ~platform_features;
 
-  // SSE2 and CMOV must be available on an X64 CPU.
+  // CMOV must be available on an X64 CPU.
   ASSERT(IsSupported(CPUID));
-  ASSERT(IsSupported(SSE2));
   ASSERT(IsSupported(CMOV));
 
   delete memory;
@@ -486,9 +485,9 @@ void Assembler::GrowBuffer() {
   intptr_t pc_delta = desc.buffer - buffer_;
   intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
       (buffer_ + buffer_size_);
-  memmove(desc.buffer, buffer_, desc.instr_size);
-  memmove(rc_delta + reloc_info_writer.pos(),
-          reloc_info_writer.pos(), desc.reloc_size);
+  OS::MemMove(desc.buffer, buffer_, desc.instr_size);
+  OS::MemMove(rc_delta + reloc_info_writer.pos(),
+              reloc_info_writer.pos(), desc.reloc_size);
 
   // Switch buffers.
   if (isolate() != NULL &&
@@ -2602,6 +2601,26 @@ void Assembler::movdqa(XMMRegister dst, const Operand& src) {
 }
 
 
+void Assembler::movdqu(const Operand& dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_rex_64(src, dst);
+  emit(0x0F);
+  emit(0x7F);
+  emit_sse_operand(src, dst);
+}
+
+
+void Assembler::movdqu(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_rex_64(dst, src);
+  emit(0x0F);
+  emit(0x6F);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
   ASSERT(CpuFeatures::IsSupported(SSE4_1));
   ASSERT(is_uint8(imm8));
index 49a57e6..2445e23 100644 (file)
@@ -448,7 +448,7 @@ class Operand BASE_EMBEDDED {
 //     CpuFeatureScope fscope(assembler, SSE3);
 //     // Generate SSE3 floating point code.
 //   } else {
-//     // Generate standard x87 or SSE2 floating point code.
+//     // Generate standard SSE2 floating point code.
 //   }
 class CpuFeatures : public AllStatic {
  public:
@@ -459,7 +459,6 @@ class CpuFeatures : public AllStatic {
   // Check whether a feature is supported by the target CPU.
   static bool IsSupported(CpuFeature f) {
     ASSERT(initialized_);
-    if (f == SSE2 && !FLAG_enable_sse2) return false;
     if (f == SSE3 && !FLAG_enable_sse3) return false;
     if (f == SSE4_1 && !FLAG_enable_sse4_1) return false;
     if (f == CMOV && !FLAG_enable_cmov) return false;
@@ -480,11 +479,11 @@ class CpuFeatures : public AllStatic {
   }
 
  private:
-  // Safe defaults include SSE2 and CMOV for X64. It is always available, if
+  // Safe defaults include CMOV for X64. It is always available, if
   // anyone checks, but they shouldn't need to check.
   // The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
   //   fpu, tsc, cx8, cmov, mmx, sse, sse2, fxsr, syscall
-  static const uint64_t kDefaultCpuFeatures = (1 << SSE2 | 1 << CMOV);
+  static const uint64_t kDefaultCpuFeatures = (1 << CMOV);
 
 #ifdef DEBUG
   static bool initialized_;
@@ -1310,6 +1309,9 @@ class Assembler : public AssemblerBase {
   void movdqa(const Operand& dst, XMMRegister src);
   void movdqa(XMMRegister dst, const Operand& src);
 
+  void movdqu(const Operand& dst, XMMRegister src);
+  void movdqu(XMMRegister dst, const Operand& src);
+
   void movapd(XMMRegister dst, XMMRegister src);
   void movaps(XMMRegister dst, XMMRegister src);
 
index 2da3de2..ba7647b 100644 (file)
@@ -1837,21 +1837,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
 
 
 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
-  // Get the loop depth of the stack guard check. This is recorded in
-  // a test(rax, depth) instruction right after the call.
-  Label stack_check;
-  __ movq(rbx, Operand(rsp, 0));  // return address
-  __ movzxbq(rbx, Operand(rbx, 1));  // depth
-
-  // Get the loop nesting level at which we allow OSR from the
-  // unoptimized code and check if we want to do OSR yet. If not we
-  // should perform a stack guard check so we can get interrupts while
-  // waiting for on-stack replacement.
   __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
-  __ movq(rcx, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
-  __ movq(rcx, FieldOperand(rcx, SharedFunctionInfo::kCodeOffset));
-  __ cmpb(rbx, FieldOperand(rcx, Code::kAllowOSRAtLoopNestingLevelOffset));
-  __ j(greater, &stack_check);
 
   // Pass the function to optimize as the argument to the on-stack
   // replacement runtime function.
@@ -1868,21 +1854,6 @@ void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
   __ j(not_equal, &skip, Label::kNear);
   __ ret(0);
 
-  // If we decide not to perform on-stack replacement we perform a
-  // stack guard check to enable interrupts.
-  __ bind(&stack_check);
-  Label ok;
-  __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
-  __ j(above_equal, &ok, Label::kNear);
-
-  StackCheckStub stub;
-  __ TailCallStub(&stub);
-  if (FLAG_debug_code) {
-    __ Abort("Unreachable code: returned from tail call.");
-  }
-  __ bind(&ok);
-  __ ret(0);
-
   __ bind(&skip);
   // Untag the AST id and push it on the stack.
   __ SmiToInteger32(rax, rax);
index fffd37f..787c7fb 100644 (file)
@@ -30,6 +30,7 @@
 #if defined(V8_TARGET_ARCH_X64)
 
 #include "bootstrapper.h"
+#include "builtins-decls.h"
 #include "code-stubs.h"
 #include "regexp-macro-assembler.h"
 #include "stub-cache.h"
@@ -39,6 +40,18 @@ namespace v8 {
 namespace internal {
 
 
+void FastCloneShallowArrayStub::InitializeInterfaceDescriptor(
+    Isolate* isolate,
+    CodeStubInterfaceDescriptor* descriptor) {
+  static Register registers[] = { rax, rbx, rcx };
+  descriptor->register_param_count_ = 3;
+  descriptor->register_params_ = registers;
+  descriptor->stack_parameter_count_ = NULL;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry;
+}
+
+
 void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
     Isolate* isolate,
     CodeStubInterfaceDescriptor* descriptor) {
@@ -158,9 +171,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
   // Get the function info from the stack.
   __ movq(rdx, Operand(rsp, 1 * kPointerSize));
 
-  int map_index = (language_mode_ == CLASSIC_MODE)
-      ? Context::FUNCTION_MAP_INDEX
-      : Context::STRICT_MODE_FUNCTION_MAP_INDEX;
+  int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
 
   // Compute the function map in the current native context and set that
   // as the map of the allocated object.
@@ -386,165 +397,6 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
 }
 
 
-static void GenerateFastCloneShallowArrayCommon(
-    MacroAssembler* masm,
-    int length,
-    FastCloneShallowArrayStub::Mode mode,
-    AllocationSiteMode allocation_site_mode,
-    Label* fail) {
-  // Registers on entry:
-  //
-  // rcx: boilerplate literal array.
-  ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS);
-
-  // All sizes here are multiples of kPointerSize.
-  int elements_size = 0;
-  if (length > 0) {
-    elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
-        ? FixedDoubleArray::SizeFor(length)
-        : FixedArray::SizeFor(length);
-  }
-  int size = JSArray::kSize;
-  int allocation_info_start = size;
-  if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-    size += AllocationSiteInfo::kSize;
-  }
-  size += elements_size;
-
-  // Allocate both the JS array and the elements array in one big
-  // allocation. This avoids multiple limit checks.
-  AllocationFlags flags = TAG_OBJECT;
-  if (mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS) {
-    flags = static_cast<AllocationFlags>(DOUBLE_ALIGNMENT | flags);
-  }
-  __ Allocate(size, rax, rbx, rdx, fail, flags);
-
-  if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-    __ LoadRoot(kScratchRegister, Heap::kAllocationSiteInfoMapRootIndex);
-    __ movq(FieldOperand(rax, allocation_info_start), kScratchRegister);
-    __ movq(FieldOperand(rax, allocation_info_start + kPointerSize), rcx);
-  }
-
-  // Copy the JS array part.
-  for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
-    if ((i != JSArray::kElementsOffset) || (length == 0)) {
-      __ movq(rbx, FieldOperand(rcx, i));
-      __ movq(FieldOperand(rax, i), rbx);
-    }
-  }
-
-  if (length > 0) {
-    // Get hold of the elements array of the boilerplate and setup the
-    // elements pointer in the resulting object.
-    __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
-    if (allocation_site_mode == TRACK_ALLOCATION_SITE) {
-      __ lea(rdx, Operand(rax, JSArray::kSize + AllocationSiteInfo::kSize));
-    } else {
-      __ lea(rdx, Operand(rax, JSArray::kSize));
-    }
-    __ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx);
-
-    // Copy the elements array.
-    if (mode == FastCloneShallowArrayStub::CLONE_ELEMENTS) {
-      for (int i = 0; i < elements_size; i += kPointerSize) {
-        __ movq(rbx, FieldOperand(rcx, i));
-        __ movq(FieldOperand(rdx, i), rbx);
-      }
-    } else {
-      ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS);
-      int i;
-      for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
-        __ movq(rbx, FieldOperand(rcx, i));
-        __ movq(FieldOperand(rdx, i), rbx);
-      }
-      while (i < elements_size) {
-        __ movsd(xmm0, FieldOperand(rcx, i));
-        __ movsd(FieldOperand(rdx, i), xmm0);
-        i += kDoubleSize;
-      }
-      ASSERT(i == elements_size);
-    }
-  }
-}
-
-void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
-  // Stack layout on entry:
-  //
-  // [rsp + kPointerSize]: constant elements.
-  // [rsp + (2 * kPointerSize)]: literal index.
-  // [rsp + (3 * kPointerSize)]: literals array.
-
-  // Load boilerplate object into rcx and check if we need to create a
-  // boilerplate.
-  __ movq(rcx, Operand(rsp, 3 * kPointerSize));
-  __ movq(rax, Operand(rsp, 2 * kPointerSize));
-  SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2);
-  __ movq(rcx,
-          FieldOperand(rcx, index.reg, index.scale, FixedArray::kHeaderSize));
-  __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
-  Label slow_case;
-  __ j(equal, &slow_case);
-
-  FastCloneShallowArrayStub::Mode mode = mode_;
-  // rcx is boilerplate object.
-  Factory* factory = masm->isolate()->factory();
-  if (mode == CLONE_ANY_ELEMENTS) {
-    Label double_elements, check_fast_elements;
-    __ movq(rbx, FieldOperand(rcx, JSArray::kElementsOffset));
-    __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
-           factory->fixed_cow_array_map());
-    __ j(not_equal, &check_fast_elements);
-    GenerateFastCloneShallowArrayCommon(masm, 0, COPY_ON_WRITE_ELEMENTS,
-                                        allocation_site_mode_,
-                                        &slow_case);
-    __ ret(3 * kPointerSize);
-
-    __ bind(&check_fast_elements);
-    __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
-           factory->fixed_array_map());
-    __ j(not_equal, &double_elements);
-    GenerateFastCloneShallowArrayCommon(masm, length_, CLONE_ELEMENTS,
-                                        allocation_site_mode_,
-                                        &slow_case);
-    __ ret(3 * kPointerSize);
-
-    __ bind(&double_elements);
-    mode = CLONE_DOUBLE_ELEMENTS;
-    // Fall through to generate the code to handle double elements.
-  }
-
-  if (FLAG_debug_code) {
-    const char* message;
-    Heap::RootListIndex expected_map_index;
-    if (mode == CLONE_ELEMENTS) {
-      message = "Expected (writable) fixed array";
-      expected_map_index = Heap::kFixedArrayMapRootIndex;
-    } else if (mode == CLONE_DOUBLE_ELEMENTS) {
-      message = "Expected (writable) fixed double array";
-      expected_map_index = Heap::kFixedDoubleArrayMapRootIndex;
-    } else {
-      ASSERT(mode == COPY_ON_WRITE_ELEMENTS);
-      message = "Expected copy-on-write fixed array";
-      expected_map_index = Heap::kFixedCOWArrayMapRootIndex;
-    }
-    __ push(rcx);
-    __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset));
-    __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
-                   expected_map_index);
-    __ Assert(equal, message);
-    __ pop(rcx);
-  }
-
-  GenerateFastCloneShallowArrayCommon(masm, length_, mode,
-                                      allocation_site_mode_,
-                                      &slow_case);
-  __ ret(3 * kPointerSize);
-
-  __ bind(&slow_case);
-  __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1);
-}
-
-
 // The stub expects its argument on the stack and returns its result in tos_:
 // zero for false, and a non-zero value for true.
 void ToBooleanStub::Generate(MacroAssembler* masm) {
@@ -4154,6 +4006,7 @@ bool CEntryStub::IsPregenerated() {
 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
   CEntryStub::GenerateAheadOfTime(isolate);
   StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+  StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
   // It is important that the store buffer overflow stubs are generated first.
   RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
 }
@@ -4299,12 +4152,19 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   // Special handling of out of memory exceptions.
   JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception);
 
-  // Retrieve the pending exception and clear the variable.
+  // Retrieve the pending exception.
   ExternalReference pending_exception_address(
       Isolate::kPendingExceptionAddress, masm->isolate());
   Operand pending_exception_operand =
       masm->ExternalOperand(pending_exception_address);
   __ movq(rax, pending_exception_operand);
+
+  // See if we just retrieved an OOM exception.
+  JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception);
+
+  // Clear the pending exception.
+  pending_exception_operand =
+      masm->ExternalOperand(pending_exception_address);
   __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
   __ movq(pending_exception_operand, rdx);
 
@@ -4412,6 +4272,11 @@ void CEntryStub::Generate(MacroAssembler* masm) {
 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
   Label invoke, handler_entry, exit;
   Label not_outermost_js, not_outermost_js_2;
+
+#ifdef _WIN64
+  const int kCalleeSaveXMMRegisters = 10;
+  const int kFullXMMRegisterSize = 16;
+#endif
   {  // NOLINT. Scope block confuses linter.
     MacroAssembler::NoRootArrayScope uninitialized_root_register(masm);
     // Set up frame.
@@ -4438,8 +4303,21 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
     __ push(rsi);  // Only callee save in Win64 ABI, argument in AMD64 ABI.
 #endif
     __ push(rbx);
-    // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are
-    // callee save as well.
+
+#ifdef _WIN64
+    // On Win64 XMM6-XMM15 are callee-save
+    __ subq(rsp, Immediate(kCalleeSaveXMMRegisters * kFullXMMRegisterSize));
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 0), xmm6);
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 1), xmm7);
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 2), xmm8);
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 3), xmm9);
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 4), xmm10);
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 5), xmm11);
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 6), xmm12);
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 7), xmm13);
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 8), xmm14);
+    __ movdqu(Operand(rsp, kFullXMMRegisterSize * 9), xmm15);
+#endif
 
     // Set up the roots and smi constant registers.
     // Needs to be done before any further smi loads.
@@ -4529,6 +4407,21 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
   }
 
   // Restore callee-saved registers (X64 conventions).
+#ifdef _WIN64
+  // On Win64 XMM6-XMM15 are callee-save
+  __ movdqu(xmm6, Operand(rsp, kFullXMMRegisterSize * 0));
+  __ movdqu(xmm7, Operand(rsp, kFullXMMRegisterSize * 1));
+  __ movdqu(xmm8, Operand(rsp, kFullXMMRegisterSize * 2));
+  __ movdqu(xmm8, Operand(rsp, kFullXMMRegisterSize * 3));
+  __ movdqu(xmm10, Operand(rsp, kFullXMMRegisterSize * 4));
+  __ movdqu(xmm11, Operand(rsp, kFullXMMRegisterSize * 5));
+  __ movdqu(xmm12, Operand(rsp, kFullXMMRegisterSize * 6));
+  __ movdqu(xmm13, Operand(rsp, kFullXMMRegisterSize * 7));
+  __ movdqu(xmm14, Operand(rsp, kFullXMMRegisterSize * 8));
+  __ movdqu(xmm15, Operand(rsp, kFullXMMRegisterSize * 9));
+  __ addq(rsp, Immediate(kCalleeSaveXMMRegisters * kFullXMMRegisterSize));
+#endif
+
   __ pop(rbx);
 #ifdef _WIN64
   // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI.
@@ -6775,8 +6668,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
 
 
 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
-  ASSERT(!Serializer::enabled());
-  CEntryStub ces(1, kSaveFPRegs);
+  CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
   __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
   int parameter_count_offset =
       StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
index 0bb02db..bae97cd 100644 (file)
@@ -117,40 +117,39 @@ void Deoptimizer::DeoptimizeFunctionWithPreparedFunctionList(
 
 
 static const byte kJnsInstruction = 0x79;
-static const byte kJnsOffset = 0x1f;
+static const byte kJnsOffset = 0x1d;
 static const byte kCallInstruction = 0xe8;
 static const byte kNopByteOne = 0x66;
 static const byte kNopByteTwo = 0x90;
 
-void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
-                                        Address pc_after,
-                                        Code* check_code,
-                                        Code* replacement_code) {
+// The back edge bookkeeping code matches the pattern:
+//
+//     add <profiling_counter>, <-delta>
+//     jns ok
+//     call <stack guard>
+//   ok:
+//
+// We will patch away the branch so the code is:
+//
+//     add <profiling_counter>, <-delta>  ;; Not changed
+//     nop
+//     nop
+//     call <on-stack replacment>
+//   ok:
+
+void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code,
+                                       Address pc_after,
+                                       Code* interrupt_code,
+                                       Code* replacement_code) {
+  ASSERT(!InterruptCodeIsPatched(unoptimized_code,
+                                 pc_after,
+                                 interrupt_code,
+                                 replacement_code));
+  // Turn the jump into nops.
   Address call_target_address = pc_after - kIntSize;
-  ASSERT_EQ(check_code->entry(),
-            Assembler::target_address_at(call_target_address));
-  // The back edge bookkeeping code matches the pattern:
-  //
-  //     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:
-  //
-  //     add <profiling_counter>, <-delta>  ;; Not changed
-  //     nop
-  //     nop
-  //     call <on-stack replacment>
-  //     test rax, <loop nesting depth>
-  // ok:
-  //
-  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;
+  // Replace the call address.
   Assembler::set_target_address_at(call_target_address,
                                    replacement_code->entry());
 
@@ -159,26 +158,48 @@ void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
 }
 
 
-void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code,
-                                         Address pc_after,
-                                         Code* check_code,
-                                         Code* replacement_code) {
+void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code,
+                                        Address pc_after,
+                                        Code* interrupt_code,
+                                        Code* replacement_code) {
+  ASSERT(InterruptCodeIsPatched(unoptimized_code,
+                                pc_after,
+                                interrupt_code,
+                                replacement_code));
+  // Restore the original jump.
   Address call_target_address = pc_after - kIntSize;
-  ASSERT(replacement_code->entry() ==
-         Assembler::target_address_at(call_target_address));
-  // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to
-  // restore the conditional branch.
-  ASSERT_EQ(kNopByteOne,      *(call_target_address - 3));
-  ASSERT_EQ(kNopByteTwo,      *(call_target_address - 2));
-  ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
   *(call_target_address - 3) = kJnsInstruction;
   *(call_target_address - 2) = kJnsOffset;
+  // Restore the original call address.
   Assembler::set_target_address_at(call_target_address,
-                                   check_code->entry());
+                                   interrupt_code->entry());
+
+  interrupt_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+      unoptimized_code, call_target_address, interrupt_code);
+}
+
 
-  check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
-      unoptimized_code, call_target_address, check_code);
+#ifdef DEBUG
+bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code,
+                                         Address pc_after,
+                                         Code* interrupt_code,
+                                         Code* replacement_code) {
+  Address call_target_address = pc_after - kIntSize;
+  ASSERT_EQ(kCallInstruction, *(call_target_address - 1));
+  if (*(call_target_address - 3) == kNopByteOne) {
+    ASSERT(replacement_code->entry() ==
+           Assembler::target_address_at(call_target_address));
+    ASSERT_EQ(kNopByteTwo,      *(call_target_address - 2));
+    return true;
+  } else {
+    ASSERT_EQ(interrupt_code->entry(),
+              Assembler::target_address_at(call_target_address));
+    ASSERT_EQ(kJnsInstruction,  *(call_target_address - 3));
+    ASSERT_EQ(kJnsOffset,       *(call_target_address - 2));
+    return false;
+  }
 }
+#endif  // DEBUG
 
 
 static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) {
index 53c3459..14cc5b8 100644 (file)
@@ -48,18 +48,6 @@ const int kNumSafepointRegisters = 16;
 
 // ----------------------------------------------------
 
-class StackHandlerConstants : public AllStatic {
- public:
-  static const int kNextOffset     = 0 * kPointerSize;
-  static const int kCodeOffset     = 1 * kPointerSize;
-  static const int kStateOffset    = 2 * kPointerSize;
-  static const int kContextOffset  = 3 * kPointerSize;
-  static const int kFPOffset       = 4 * kPointerSize;
-
-  static const int kSize = kFPOffset + kPointerSize;
-};
-
-
 class EntryFrameConstants : public AllStatic {
  public:
 #ifdef _WIN64
index 322479d..564c3de 100644 (file)
@@ -160,6 +160,8 @@ void FullCodeGenerator::Generate() {
 
   { Comment cmnt(masm_, "[ Allocate locals");
     int locals_count = info->scope()->num_stack_slots();
+    // Generators allocate locals, if any, in context slots.
+    ASSERT(!info->function()->is_generator() || locals_count == 0);
     if (locals_count == 1) {
       __ PushRoot(Heap::kUndefinedValueRootIndex);
     } else if (locals_count > 1) {
@@ -347,13 +349,6 @@ void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
   // the deoptimization input data found in the optimized code.
   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
-  // in a test instruction after the call so we can extract it from the OSR
-  // builtin.
-  ASSERT(loop_depth() > 0);
-  __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
-
   EmitProfilingCounterReset();
 
   __ bind(&ok);
@@ -1240,7 +1235,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
       !pretenure &&
       scope()->is_function_scope() &&
       info->num_literals() == 0) {
-    FastNewClosureStub stub(info->language_mode());
+    FastNewClosureStub stub(info->language_mode(), info->is_generator());
     __ Push(info);
     __ CallStub(&stub);
   } else {
@@ -1695,24 +1690,33 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
   Handle<FixedArrayBase> constant_elements_values(
       FixedArrayBase::cast(constant_elements->get(1)));
 
-  __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
-  __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
-  __ Push(Smi::FromInt(expr->literal_index()));
-  __ Push(constant_elements);
   Heap* heap = isolate()->heap();
   if (has_constant_fast_elements &&
       constant_elements_values->map() == heap->fixed_cow_array_map()) {
     // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
     // change, so it's possible to specialize the stub in advance.
     __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
+    __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+    __ movq(rax, FieldOperand(rbx, JSFunction::kLiteralsOffset));
+    __ Move(rbx, Smi::FromInt(expr->literal_index()));
+    __ Move(rcx, constant_elements);
     FastCloneShallowArrayStub stub(
         FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
         DONT_TRACK_ALLOCATION_SITE,
         length);
     __ CallStub(&stub);
   } else if (expr->depth() > 1) {
+    __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+    __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
+    __ Push(Smi::FromInt(expr->literal_index()));
+    __ Push(constant_elements);
     __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
-  } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+  } else if (Serializer::enabled() ||
+      length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+    __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+    __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
+    __ Push(Smi::FromInt(expr->literal_index()));
+    __ Push(constant_elements);
     __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
   } else {
     ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
@@ -1729,6 +1733,10 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
       allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
     }
 
+    __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+    __ movq(rax, FieldOperand(rbx, JSFunction::kLiteralsOffset));
+    __ Move(rbx, Smi::FromInt(expr->literal_index()));
+    __ Move(rcx, constant_elements);
     FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
     __ CallStub(&stub);
   }
index 817a9d3..6fc56ed 100644 (file)
@@ -118,7 +118,7 @@ void LCodeGen::Comment(const char* format, ...) {
   // issues when the stack allocated buffer goes out of scope.
   int length = builder.position();
   Vector<char> copy = Vector<char>::New(length + 1);
-  memcpy(copy.start(), builder.Finalize(), copy.length());
+  OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
   masm()->RecordComment(copy.start());
 }
 
@@ -1793,6 +1793,8 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
       break;
     case Token::DIV:
       __ divsd(left, right);
+      // Don't delete this mov. It may improve performance on some CPUs,
+      // when there is a mulsd depending on the result
       __ movaps(left, left);
       break;
     case Token::MOD:
@@ -3366,7 +3368,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
 }
 
 
-void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
+void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
   Register input_reg = ToRegister(instr->value());
   __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
                  Heap::kHeapNumberMapRootIndex);
@@ -3418,7 +3420,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
   Register input_reg = ToRegister(instr->value());
   __ testl(input_reg, input_reg);
   Label is_positive;
@@ -3429,19 +3431,18 @@ void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
   // Class for deferred case.
   class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
    public:
-    DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
-                                    LUnaryMathOperation* instr)
+    DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
         : LDeferredCode(codegen), instr_(instr) { }
     virtual void Generate() {
       codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
     }
     virtual LInstruction* instr() { return instr_; }
    private:
-    LUnaryMathOperation* instr_;
+    LMathAbs* instr_;
   };
 
   ASSERT(instr->value()->Equals(instr->result()));
@@ -3469,7 +3470,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathFloor(LMathFloor* instr) {
   XMMRegister xmm_scratch = xmm0;
   Register output_reg = ToRegister(instr->result());
   XMMRegister input_reg = ToDoubleRegister(instr->value());
@@ -3528,7 +3529,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathRound(LMathRound* instr) {
   const XMMRegister xmm_scratch = xmm0;
   Register output_reg = ToRegister(instr->result());
   XMMRegister input_reg = ToDoubleRegister(instr->value());
@@ -3589,14 +3590,14 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
   XMMRegister input_reg = ToDoubleRegister(instr->value());
   ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
   __ sqrtsd(input_reg, input_reg);
 }
 
 
-void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
   XMMRegister xmm_scratch = xmm0;
   XMMRegister input_reg = ToDoubleRegister(instr->value());
   ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
@@ -3763,7 +3764,7 @@ void LCodeGen::DoMathExp(LMathExp* instr) {
 }
 
 
-void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathLog(LMathLog* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
   TranscendentalCacheStub stub(TranscendentalCache::LOG,
                                TranscendentalCacheStub::UNTAGGED);
@@ -3771,7 +3772,7 @@ void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathTan(LMathTan* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
   TranscendentalCacheStub stub(TranscendentalCache::TAN,
                                TranscendentalCacheStub::UNTAGGED);
@@ -3779,7 +3780,7 @@ void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathCos(LMathCos* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
   TranscendentalCacheStub stub(TranscendentalCache::COS,
                                TranscendentalCacheStub::UNTAGGED);
@@ -3787,7 +3788,7 @@ void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathSin(LMathSin* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
   TranscendentalCacheStub stub(TranscendentalCache::SIN,
                                TranscendentalCacheStub::UNTAGGED);
@@ -3795,42 +3796,6 @@ void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
-  switch (instr->op()) {
-    case kMathAbs:
-      DoMathAbs(instr);
-      break;
-    case kMathFloor:
-      DoMathFloor(instr);
-      break;
-    case kMathRound:
-      DoMathRound(instr);
-      break;
-    case kMathSqrt:
-      DoMathSqrt(instr);
-      break;
-    case kMathPowHalf:
-      DoMathPowHalf(instr);
-      break;
-    case kMathCos:
-      DoMathCos(instr);
-      break;
-    case kMathSin:
-      DoMathSin(instr);
-      break;
-    case kMathTan:
-      DoMathTan(instr);
-      break;
-    case kMathLog:
-      DoMathLog(instr);
-      break;
-
-    default:
-      UNREACHABLE();
-  }
-}
-
-
 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   ASSERT(ToRegister(instr->function()).is(rdi));
   ASSERT(instr->HasPointerMap());
@@ -4977,7 +4942,6 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
 
 
 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
-  ASSERT(instr->temp()->Equals(instr->result()));
   Register reg = ToRegister(instr->temp());
 
   ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
@@ -4989,7 +4953,6 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
     for (int i = 0; i < maps->length(); i++) {
       prototype_maps_.Add(maps->at(i), info()->zone());
     }
-    __ LoadHeapObject(reg, prototypes->at(prototypes->length() - 1));
   } else {
     for (int i = 0; i < prototypes->length(); i++) {
       __ LoadHeapObject(reg, prototypes->at(i));
@@ -5114,11 +5077,11 @@ void LCodeGen::DoAllocate(LAllocate* instr) {
   if (instr->hydrogen()->MustAllocateDoubleAligned()) {
     flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
   }
+  if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+    flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+  }
   if (instr->size()->IsConstantOperand()) {
     int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
-    if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
-      flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
-    }
     __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
   } else {
     Register size = ToRegister(instr->size());
@@ -5141,7 +5104,13 @@ void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
   PushSafepointRegistersScope scope(this);
   __ Integer32ToSmi(size, size);
   __ push(size);
-  CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
+  if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
+    CallRuntimeFromDeferred(
+        Runtime::kAllocateInOldPointerSpace, 1, instr);
+  } else {
+    CallRuntimeFromDeferred(
+        Runtime::kAllocateInNewSpace, 1, instr);
+  }
   __ StoreToSafepointRegisterSlot(result, rax);
 }
 
@@ -5169,26 +5138,33 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
     DeoptimizeIf(not_equal, instr->environment());
   }
 
-  // Set up the parameters to the stub/runtime call.
-  __ PushHeapObject(literals);
-  __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
-  // Boilerplate already exists, constant elements are never accessed.
-  // Pass an empty fixed array.
-  __ Push(isolate()->factory()->empty_fixed_array());
-
-  // Pick the right runtime function or stub to call.
+  // Set up the parameters to the stub/runtime call and pick the right
+  // runtime function or stub to call. Boilerplate already exists,
+  // constant elements are never accessed, pass an empty fixed array.
   int length = instr->hydrogen()->length();
   if (instr->hydrogen()->IsCopyOnWrite()) {
     ASSERT(instr->hydrogen()->depth() == 1);
+    __ LoadHeapObject(rax, literals);
+    __ Move(rbx, Smi::FromInt(instr->hydrogen()->literal_index()));
+    __ Move(rcx, isolate()->factory()->empty_fixed_array());
     FastCloneShallowArrayStub::Mode mode =
         FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
     FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
     CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
   } else if (instr->hydrogen()->depth() > 1) {
+    __ PushHeapObject(literals);
+    __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
+    __ Push(isolate()->factory()->empty_fixed_array());
     CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
   } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
+    __ PushHeapObject(literals);
+    __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
+    __ Push(isolate()->factory()->empty_fixed_array());
     CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
   } else {
+    __ LoadHeapObject(rax, literals);
+    __ Move(rbx, Smi::FromInt(instr->hydrogen()->literal_index()));
+    __ Move(rcx, isolate()->factory()->empty_fixed_array());
     FastCloneShallowArrayStub::Mode mode =
         boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
         ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
@@ -5199,163 +5175,6 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
 }
 
 
-void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
-                            Register result,
-                            Register source,
-                            int* offset,
-                            AllocationSiteMode mode) {
-  ASSERT(!source.is(rcx));
-  ASSERT(!result.is(rcx));
-
-  bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
-      object->map()->CanTrackAllocationSite();
-
-  // Only elements backing stores for non-COW arrays need to be copied.
-  Handle<FixedArrayBase> elements(object->elements());
-  bool has_elements = elements->length() > 0 &&
-      elements->map() != isolate()->heap()->fixed_cow_array_map();
-
-  // Increase the offset so that subsequent objects end up right after
-  // this object and its backing store.
-  int object_offset = *offset;
-  int object_size = object->map()->instance_size();
-  int elements_size = has_elements ? elements->Size() : 0;
-  int elements_offset = *offset + object_size;
-  if (create_allocation_site_info) {
-    elements_offset += AllocationSiteInfo::kSize;
-    *offset += AllocationSiteInfo::kSize;
-  }
-
-  *offset += object_size + elements_size;
-
-  // Copy object header.
-  ASSERT(object->properties()->length() == 0);
-  int inobject_properties = object->map()->inobject_properties();
-  int header_size = object_size - inobject_properties * kPointerSize;
-  for (int i = 0; i < header_size; i += kPointerSize) {
-    if (has_elements && i == JSObject::kElementsOffset) {
-      __ lea(rcx, Operand(result, elements_offset));
-    } else {
-      __ movq(rcx, FieldOperand(source, i));
-    }
-    __ movq(FieldOperand(result, object_offset + i), rcx);
-  }
-
-  // Copy in-object properties.
-  for (int i = 0; i < inobject_properties; i++) {
-    int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
-    Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i),
-                                          isolate());
-    if (value->IsJSObject()) {
-      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
-      __ lea(rcx, Operand(result, *offset));
-      __ movq(FieldOperand(result, total_offset), rcx);
-      __ LoadHeapObject(source, value_object);
-      EmitDeepCopy(value_object, result, source, offset,
-                   DONT_TRACK_ALLOCATION_SITE);
-    } else if (value->IsHeapObject()) {
-      __ LoadHeapObject(rcx, Handle<HeapObject>::cast(value));
-      __ movq(FieldOperand(result, total_offset), rcx);
-    } else {
-      __ movq(rcx, value, RelocInfo::NONE64);
-      __ movq(FieldOperand(result, total_offset), rcx);
-    }
-  }
-
-  // Build Allocation Site Info if desired
-  if (create_allocation_site_info) {
-    __ LoadRoot(kScratchRegister, Heap::kAllocationSiteInfoMapRootIndex);
-    __ movq(FieldOperand(result, object_size), kScratchRegister);
-    __ movq(FieldOperand(result, object_size + kPointerSize), source);
-  }
-
-  if (has_elements) {
-    // Copy elements backing store header.
-    __ LoadHeapObject(source, elements);
-    for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
-      __ movq(rcx, FieldOperand(source, i));
-      __ movq(FieldOperand(result, elements_offset + i), rcx);
-    }
-
-    // Copy elements backing store content.
-    int elements_length = elements->length();
-    if (elements->IsFixedDoubleArray()) {
-      Handle<FixedDoubleArray> double_array =
-          Handle<FixedDoubleArray>::cast(elements);
-      for (int i = 0; i < elements_length; i++) {
-        int64_t value = double_array->get_representation(i);
-        int total_offset =
-            elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
-        __ movq(rcx, value, RelocInfo::NONE64);
-        __ movq(FieldOperand(result, total_offset), rcx);
-      }
-    } else if (elements->IsFixedArray()) {
-      Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
-      for (int i = 0; i < elements_length; i++) {
-        int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
-        Handle<Object> value(fast_elements->get(i), isolate());
-        if (value->IsJSObject()) {
-          Handle<JSObject> value_object = Handle<JSObject>::cast(value);
-          __ lea(rcx, Operand(result, *offset));
-          __ movq(FieldOperand(result, total_offset), rcx);
-          __ LoadHeapObject(source, value_object);
-          EmitDeepCopy(value_object, result, source, offset,
-                       DONT_TRACK_ALLOCATION_SITE);
-        } else if (value->IsHeapObject()) {
-          __ LoadHeapObject(rcx, Handle<HeapObject>::cast(value));
-          __ movq(FieldOperand(result, total_offset), rcx);
-        } else {
-          __ movq(rcx, value, RelocInfo::NONE64);
-          __ movq(FieldOperand(result, total_offset), rcx);
-        }
-      }
-    } else {
-      UNREACHABLE();
-    }
-  }
-}
-
-
-void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
-  int size = instr->hydrogen()->total_size();
-  ElementsKind boilerplate_elements_kind =
-      instr->hydrogen()->boilerplate()->GetElementsKind();
-
-  // Deopt if the array literal boilerplate ElementsKind is of a type different
-  // than the expected one. The check isn't necessary if the boilerplate has
-  // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
-  if (CanTransitionToMoreGeneralFastElementsKind(
-          boilerplate_elements_kind, true)) {
-    __ LoadHeapObject(rbx, instr->hydrogen()->boilerplate());
-    __ movq(rcx, FieldOperand(rbx, HeapObject::kMapOffset));
-    // Load the map's "bit field 2".
-    __ movb(rcx, FieldOperand(rcx, Map::kBitField2Offset));
-    // Retrieve elements_kind from bit field 2.
-    __ and_(rcx, Immediate(Map::kElementsKindMask));
-    __ cmpb(rcx, Immediate(boilerplate_elements_kind <<
-                           Map::kElementsKindShift));
-    DeoptimizeIf(not_equal, instr->environment());
-  }
-
-  // Allocate all objects that are part of the literal in one big
-  // allocation. This avoids multiple limit checks.
-  Label allocated, runtime_allocate;
-  __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
-  __ jmp(&allocated);
-
-  __ bind(&runtime_allocate);
-  __ Push(Smi::FromInt(size));
-  CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
-
-  __ bind(&allocated);
-  int offset = 0;
-  __ LoadHeapObject(rbx, instr->hydrogen()->boilerplate());
-  EmitDeepCopy(instr->hydrogen()->boilerplate(), rax, rbx, &offset,
-               instr->hydrogen()->allocation_site_mode());
-  ASSERT_EQ(size, offset);
-}
-
-
 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
   Handle<FixedArray> literals(instr->environment()->closure()->literals());
   Handle<FixedArray> constant_properties =
@@ -5458,7 +5277,8 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
   Handle<SharedFunctionInfo> shared_info = instr->shared_info();
   bool pretenure = instr->hydrogen()->pretenure();
   if (!pretenure && shared_info->num_literals() == 0) {
-    FastNewClosureStub stub(shared_info->language_mode());
+    FastNewClosureStub stub(shared_info->language_mode(),
+                            shared_info->is_generator());
     __ Push(shared_info);
     CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
   } else {
index 5809296..e857606 100644 (file)
@@ -111,7 +111,7 @@ class LCodeGen BASE_EMBEDDED {
   void DoDeferredNumberTagD(LNumberTagD* instr);
   void DoDeferredNumberTagU(LNumberTagU* instr);
   void DoDeferredTaggedToI(LTaggedToI* instr);
-  void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
+  void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
   void DoDeferredStackCheck(LStackCheck* instr);
   void DoDeferredRandom(LRandom* instr);
   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
@@ -258,17 +258,7 @@ class LCodeGen BASE_EMBEDDED {
       uint32_t offset,
       uint32_t additional_index = 0);
 
-  // Specific math operations - used from DoUnaryMathOperation.
-  void EmitIntegerMathAbs(LUnaryMathOperation* instr);
-  void DoMathAbs(LUnaryMathOperation* instr);
-  void DoMathFloor(LUnaryMathOperation* instr);
-  void DoMathRound(LUnaryMathOperation* instr);
-  void DoMathSqrt(LUnaryMathOperation* instr);
-  void DoMathPowHalf(LUnaryMathOperation* instr);
-  void DoMathLog(LUnaryMathOperation* instr);
-  void DoMathTan(LUnaryMathOperation* instr);
-  void DoMathCos(LUnaryMathOperation* instr);
-  void DoMathSin(LUnaryMathOperation* instr);
+  void EmitIntegerMathAbs(LMathAbs* instr);
 
   // Support for recording safepoint and position information.
   void RecordSafepoint(LPointerMap* pointers,
index 9a3166e..ba29ed9 100644 (file)
@@ -304,17 +304,6 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
 }
 
 
-void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
-  stream->Add("/%s ", hydrogen()->OpName());
-  value()->PrintTo(stream);
-}
-
-
-void LMathExp::PrintDataTo(StringStream* stream) {
-  value()->PrintTo(stream);
-}
-
-
 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
   context()->PrintTo(stream);
   stream->Add("[%d]", slot_index());
@@ -1130,41 +1119,97 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
 
 
 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
-  BuiltinFunctionId op = instr->op();
-  if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
-    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);
-    switch (op) {
-      case kMathAbs:
-        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
-      case kMathFloor:
-        return AssignEnvironment(DefineAsRegister(result));
-      case kMathRound:
-        return AssignEnvironment(DefineAsRegister(result));
-      case kMathSqrt:
-        return DefineSameAsFirst(result);
-      case kMathPowHalf:
-        return DefineSameAsFirst(result);
-      default:
-        UNREACHABLE();
-        return NULL;
-    }
+  switch (instr->op()) {
+    case kMathFloor: return DoMathFloor(instr);
+    case kMathRound: return DoMathRound(instr);
+    case kMathAbs: return DoMathAbs(instr);
+    case kMathLog: return DoMathLog(instr);
+    case kMathSin: return DoMathSin(instr);
+    case kMathCos: return DoMathCos(instr);
+    case kMathTan: return DoMathTan(instr);
+    case kMathExp: return DoMathExp(instr);
+    case kMathSqrt: return DoMathSqrt(instr);
+    case kMathPowHalf: return DoMathPowHalf(instr);
+    default:
+      UNREACHABLE();
+      return NULL;
   }
 }
 
 
+LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathFloor* result = new(zone()) LMathFloor(input);
+  return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathRound* result = new(zone()) LMathRound(input);
+  return AssignEnvironment(DefineAsRegister(result));
+}
+
+LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathAbs* result = new(zone()) LMathAbs(input);
+  return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+}
+
+
+LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), xmm1);
+  LMathLog* result = new(zone()) LMathLog(input);
+  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), xmm1);
+  LMathSin* result = new(zone()) LMathSin(input);
+  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), xmm1);
+  LMathCos* result = new(zone()) LMathCos(input);
+  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
+  LOperand* input = UseFixedDouble(instr->value(), xmm1);
+  LMathTan* result = new(zone()) LMathTan(input);
+  return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
+  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);
+}
+
+
+LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathSqrt* result = new(zone()) LMathSqrt(input);
+  return DefineSameAsFirst(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LMathPowHalf* result = new(zone()) LMathPowHalf(input);
+  return DefineSameAsFirst(result);
+}
+
+
 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
   ASSERT(instr->key()->representation().IsTagged());
   LOperand* key = UseFixed(instr->key(), rcx);
@@ -1843,7 +1888,7 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
 LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
   LUnallocated* temp = TempRegister();
   LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
-  return AssignEnvironment(Define(result, temp));
+  return AssignEnvironment(result);
 }
 
 
@@ -2252,11 +2297,6 @@ LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
-  return MarkAsCall(DefineFixed(new(zone()) LFastLiteral, rax), instr);
-}
-
-
 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
   return MarkAsCall(DefineFixed(new(zone()) LArrayLiteral, rax), instr);
 }
index 051f9a4..54f117c 100644 (file)
@@ -97,7 +97,6 @@ class LCodeGen;
   V(DoubleToI)                                  \
   V(DummyUse)                                   \
   V(ElementsKind)                               \
-  V(FastLiteral)                                \
   V(FixedArrayBaseLength)                       \
   V(MapEnumLength)                              \
   V(FunctionLiteral)                            \
@@ -134,9 +133,18 @@ class LCodeGen;
   V(LoadNamedField)                             \
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
+  V(MathAbs)                                    \
+  V(MathCos)                                    \
   V(MathExp)                                    \
+  V(MathFloor)                                  \
   V(MathFloorOfDiv)                             \
+  V(MathLog)                                    \
   V(MathMinMax)                                 \
+  V(MathPowHalf)                                \
+  V(MathRound)                                  \
+  V(MathSin)                                    \
+  V(MathSqrt)                                   \
+  V(MathTan)                                    \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -178,7 +186,6 @@ class LCodeGen;
   V(TrapAllocationMemento)                      \
   V(Typeof)                                     \
   V(TypeofIsAndBranch)                          \
-  V(UnaryMathOperation)                         \
   V(UnknownOSRValue)                            \
   V(ValueOf)                                    \
   V(ForInPrepareMap)                            \
@@ -650,19 +657,90 @@ class LCmpIDAndBranch: public LControlInstruction<2, 0> {
 };
 
 
-class LUnaryMathOperation: public LTemplateInstruction<1, 1, 0> {
+class LMathFloor: public LTemplateInstruction<1, 1, 0> {
  public:
-  explicit LUnaryMathOperation(LOperand* value) {
+  explicit LMathFloor(LOperand* value) {
     inputs_[0] = value;
   }
 
   LOperand* value() { return inputs_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation")
+  DECLARE_CONCRETE_INSTRUCTION(MathFloor, "math-floor")
   DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
 
-  virtual void PrintDataTo(StringStream* stream);
-  BuiltinFunctionId op() const { return hydrogen()->op(); }
+
+class LMathRound: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathRound(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathAbs: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathAbs(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathLog: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathLog(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathSin: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathSin(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathSin, "math-sin")
+};
+
+
+class LMathCos: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathCos(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathCos, "math-cos")
+};
+
+
+class LMathTan: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathTan(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathTan, "math-tan")
 };
 
 
@@ -680,8 +758,30 @@ class LMathExp: public LTemplateInstruction<1, 1, 2> {
   LOperand* temp2() { return temps_[1]; }
 
   DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+};
 
-  virtual void PrintDataTo(StringStream* stream);
+
+class LMathSqrt: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathSqrt(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
+};
+
+
+class LMathPowHalf: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMathPowHalf(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
 };
 
 
@@ -1250,7 +1350,7 @@ class LMathMinMax: public LTemplateInstruction<1, 2, 0> {
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "min-max")
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
   DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
 };
 
@@ -2158,7 +2258,7 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> {
 };
 
 
-class LCheckPrototypeMaps: public LTemplateInstruction<1, 0, 1> {
+class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> {
  public:
   explicit LCheckPrototypeMaps(LOperand* temp)  {
     temps_[0] = temp;
@@ -2267,13 +2367,6 @@ class LAllocate: public LTemplateInstruction<1, 1, 1> {
 };
 
 
-class LFastLiteral: public LTemplateInstruction<1, 0, 0> {
- public:
-  DECLARE_CONCRETE_INSTRUCTION(FastLiteral, "fast-literal")
-  DECLARE_HYDROGEN_ACCESSOR(FastLiteral)
-};
-
-
 class LArrayLiteral: public LTemplateInstruction<1, 0, 0> {
  public:
   DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal")
@@ -2505,6 +2598,17 @@ class LChunkBuilder BASE_EMBEDDED {
   static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
   static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
 
+  LInstruction* DoMathFloor(HUnaryMathOperation* instr);
+  LInstruction* DoMathRound(HUnaryMathOperation* instr);
+  LInstruction* DoMathAbs(HUnaryMathOperation* instr);
+  LInstruction* DoMathLog(HUnaryMathOperation* instr);
+  LInstruction* DoMathSin(HUnaryMathOperation* instr);
+  LInstruction* DoMathCos(HUnaryMathOperation* instr);
+  LInstruction* DoMathTan(HUnaryMathOperation* instr);
+  LInstruction* DoMathExp(HUnaryMathOperation* instr);
+  LInstruction* DoMathSqrt(HUnaryMathOperation* instr);
+  LInstruction* DoMathPowHalf(HUnaryMathOperation* instr);
+
  private:
   enum Status {
     UNUSED,
index 6c1c19d..5865924 100644 (file)
@@ -899,7 +899,6 @@ void MacroAssembler::PushCallerSaved(SaveFPRegsMode fp_mode,
   }
   // R12 to r15 are callee save on all platforms.
   if (fp_mode == kSaveFPRegs) {
-    CpuFeatureScope scope(this, SSE2);
     subq(rsp, Immediate(kDoubleSize * XMMRegister::kMaxNumRegisters));
     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
       XMMRegister reg = XMMRegister::from_code(i);
@@ -914,7 +913,6 @@ void MacroAssembler::PopCallerSaved(SaveFPRegsMode fp_mode,
                                     Register exclusion2,
                                     Register exclusion3) {
   if (fp_mode == kSaveFPRegs) {
-    CpuFeatureScope scope(this, SSE2);
     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
       XMMRegister reg = XMMRegister::from_code(i);
       movsd(reg, Operand(rsp, i * kDoubleSize));
index 7e900db..41e5b88 100644 (file)
@@ -712,25 +712,41 @@ void BaseStoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
 }
 
 
+// Generate code to check that a global property cell is empty. Create
+// the property cell at compilation time if no cell exists for the
+// property.
+static void GenerateCheckPropertyCell(MacroAssembler* masm,
+                                      Handle<GlobalObject> global,
+                                      Handle<Name> name,
+                                      Register scratch,
+                                      Label* miss) {
+  Handle<JSGlobalPropertyCell> cell =
+      GlobalObject::EnsurePropertyCell(global, name);
+  ASSERT(cell->value()->IsTheHole());
+  __ Move(scratch, cell);
+  __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+         masm->isolate()->factory()->the_hole_value());
+  __ j(not_equal, miss);
+}
+
+
 // Both name_reg and receiver_reg are preserved on jumps to miss_label,
 // but may be destroyed if store is successful.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
-                                      Handle<JSObject> object,
-                                      LookupResult* lookup,
-                                      Handle<Map> transition,
-                                      Handle<Name> name,
-                                      Register receiver_reg,
-                                      Register name_reg,
-                                      Register value_reg,
-                                      Register scratch1,
-                                      Register scratch2,
-                                      Label* miss_label,
-                                      Label* miss_restore_name) {
+void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+                                           Handle<JSObject> object,
+                                           LookupResult* lookup,
+                                           Handle<Map> transition,
+                                           Handle<Name> name,
+                                           Register receiver_reg,
+                                           Register name_reg,
+                                           Register value_reg,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           Label* miss_label,
+                                           Label* miss_restore_name) {
   // Check that the map of the object hasn't changed.
-  CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS
-                                             : REQUIRE_EXACT_MAP;
   __ CheckMap(receiver_reg, Handle<Map>(object->map()),
-              miss_label, DO_SMI_CHECK, mode);
+              miss_label, DO_SMI_CHECK, REQUIRE_EXACT_MAP);
 
   // Perform global security token check if needed.
   if (object->IsJSGlobalProxy()) {
@@ -738,7 +754,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
   }
 
   // Check that we are allowed to write this.
-  if (!transition.is_null() && object->GetPrototype()->IsJSObject()) {
+  if (object->GetPrototype()->IsJSObject()) {
     JSObject* holder;
     // holder == object indicates that no property was found.
     if (lookup->holder() != *object) {
@@ -756,12 +772,18 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     // If no property was found, and the holder (the last object in the
     // prototype chain) is in slow mode, we need to do a negative lookup on the
     // holder.
-    if (lookup->holder() == *object &&
-        !holder->HasFastProperties() &&
-        !holder->IsJSGlobalProxy() &&
-        !holder->IsJSGlobalObject()) {
-      GenerateDictionaryNegativeLookup(
-          masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+    if (lookup->holder() == *object) {
+      if (holder->IsJSGlobalObject()) {
+        GenerateCheckPropertyCell(
+            masm,
+            Handle<GlobalObject>(GlobalObject::cast(holder)),
+            name,
+            scratch1,
+            miss_restore_name);
+      } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+        GenerateDictionaryNegativeLookup(
+            masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
+      }
     }
   }
 
@@ -770,7 +792,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
   // Perform map transition for the receiver if necessary.
-  if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) {
+  if (object->map()->unused_property_fields() == 0) {
     // The properties must be extended before we can store the value.
     // We jump to a runtime call that extends the properties array.
     __ pop(scratch1);  // Return address.
@@ -786,32 +808,29 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
     return;
   }
 
-  int index;
-  if (!transition.is_null()) {
-    // Update the map of the object.
-    __ Move(scratch1, transition);
-    __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
-
-    // Update the write barrier for the map field and pass the now unused
-    // name_reg as scratch register.
-    __ RecordWriteField(receiver_reg,
-                        HeapObject::kMapOffset,
-                        scratch1,
-                        name_reg,
-                        kDontSaveFPRegs,
-                        OMIT_REMEMBERED_SET,
-                        OMIT_SMI_CHECK);
-    index = transition->instance_descriptors()->GetFieldIndex(
-        transition->LastAdded());
-  } else {
-    index = lookup->GetFieldIndex().field_index();
-  }
+  // Update the map of the object.
+  __ Move(scratch1, transition);
+  __ movq(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
+
+  // Update the write barrier for the map field and pass the now unused
+  // name_reg as scratch register.
+  __ RecordWriteField(receiver_reg,
+                      HeapObject::kMapOffset,
+                      scratch1,
+                      name_reg,
+                      kDontSaveFPRegs,
+                      OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+
+  int index = transition->instance_descriptors()->GetFieldIndex(
+      transition->LastAdded());
 
   // Adjust for the number of properties stored in the object. Even in the
   // face of a transition we can use the old map here because the size of the
   // object and the number of in-object properties is not going to change.
   index -= object->map()->inobject_properties();
 
+  // TODO(verwaest): Share this code as a code stub.
   if (index < 0) {
     // Set the property straight into the object.
     int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -842,21 +861,65 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
 }
 
 
-// Generate code to check that a global property cell is empty. Create
-// the property cell at compilation time if no cell exists for the
-// property.
-static void GenerateCheckPropertyCell(MacroAssembler* masm,
-                                      Handle<GlobalObject> global,
-                                      Handle<Name> name,
-                                      Register scratch,
-                                      Label* miss) {
-  Handle<JSGlobalPropertyCell> cell =
-      GlobalObject::EnsurePropertyCell(global, name);
-  ASSERT(cell->value()->IsTheHole());
-  __ Move(scratch, cell);
-  __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
-         masm->isolate()->factory()->the_hole_value());
-  __ j(not_equal, miss);
+// Both name_reg and receiver_reg are preserved on jumps to miss_label,
+// but may be destroyed if store is successful.
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+                                      Handle<JSObject> object,
+                                      LookupResult* lookup,
+                                      Register receiver_reg,
+                                      Register name_reg,
+                                      Register value_reg,
+                                      Register scratch1,
+                                      Register scratch2,
+                                      Label* miss_label) {
+  // Check that the map of the object hasn't changed.
+  __ CheckMap(receiver_reg, Handle<Map>(object->map()),
+              miss_label, DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+
+  // Perform global security token check if needed.
+  if (object->IsJSGlobalProxy()) {
+    __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
+  }
+
+  // Stub never generated for non-global objects that require access
+  // checks.
+  ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+  int index = lookup->GetFieldIndex().field_index();
+
+  // Adjust for the number of properties stored in the object. Even in the
+  // face of a transition we can use the old map here because the size of the
+  // object and the number of in-object properties is not going to change.
+  index -= object->map()->inobject_properties();
+
+  // TODO(verwaest): Share this code as a code stub.
+  if (index < 0) {
+    // Set the property straight into the object.
+    int offset = object->map()->instance_size() + (index * kPointerSize);
+    __ movq(FieldOperand(receiver_reg, offset), value_reg);
+
+    // Update the write barrier for the array address.
+    // Pass the value being stored in the now unused name_reg.
+    __ movq(name_reg, value_reg);
+    __ RecordWriteField(
+        receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs);
+  } else {
+    // Write to the properties array.
+    int offset = index * kPointerSize + FixedArray::kHeaderSize;
+    // Get the properties array (optimistically).
+    __ movq(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
+    __ movq(FieldOperand(scratch1, offset), value_reg);
+
+    // Update the write barrier for the array address.
+    // Pass the value being stored in the now unused name_reg.
+    __ movq(name_reg, value_reg);
+    __ RecordWriteField(
+        scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs);
+  }
+
+  // Return the value (register rax).
+  ASSERT(value_reg.is(rax));
+  __ ret(0);
 }
 
 
@@ -1077,7 +1140,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     Handle<GlobalObject> global) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
+  HandlerFrontendHeader(object, receiver(), last, name, &miss);
 
   // If the last object in the prototype chain is a global object,
   // check that the global property cell is empty.
@@ -1085,13 +1148,6 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
   }
 
-  if (!last->HasFastProperties()) {
-    __ movq(scratch2(), FieldOperand(reg, HeapObject::kMapOffset));
-    __ movq(scratch2(), FieldOperand(scratch2(), Map::kPrototypeOffset));
-    __ Cmp(scratch2(), isolate()->factory()->null_value());
-    __ j(not_equal, &miss);
-  }
-
   HandlerFrontendFooter(success, &miss);
 }
 
index f173760..a0091ff 100644 (file)
@@ -57,6 +57,27 @@ CcTest::CcTest(TestFunction* callback, const char* file, const char* name,
 }
 
 
+v8::Persistent<v8::Context> CcTest::context_;
+
+
+void CcTest::InitializeVM(CcTestExtensionFlags extensions) {
+  const char* extension_names[kMaxExtensions];
+  int extension_count = 0;
+#define CHECK_EXTENSION_FLAG(Name, Id) \
+  if (extensions.Contains(Name##_ID)) extension_names[extension_count++] = Id;
+  EXTENSION_LIST(CHECK_EXTENSION_FLAG)
+#undef CHECK_EXTENSION_FLAG
+  if (context_.IsEmpty()) {
+    v8::Isolate* isolate = default_isolate();
+    v8::HandleScope scope(isolate);
+    v8::ExtensionConfiguration config(extension_count, extension_names);
+    v8::Local<v8::Context> context = v8::Context::New(isolate, &config);
+    context_ = v8::Persistent<v8::Context>::New(isolate, context);
+  }
+  context_->Enter();
+}
+
+
 static void PrintTestList(CcTest* current) {
   if (current == NULL) return;
   PrintTestList(current->prev());
@@ -71,6 +92,7 @@ static void PrintTestList(CcTest* current) {
 
 v8::Isolate* CcTest::default_isolate_;
 
+
 int main(int argc, char* argv[]) {
   v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
   CcTest::set_default_isolate(v8::Isolate::GetCurrent());
index ee9995b..f58d958 100644 (file)
@@ -70,6 +70,7 @@
         'test-fixed-dtoa.cc',
         'test-flags.cc',
         'test-func-name-inference.cc',
+        'test-global-handles.cc',
         'test-global-object.cc',
         'test-hashing.cc',
         'test-hashmap.cc',
index 30d9d7e..854d89e 100644 (file)
   static void Test##Name()
 #endif
 
+#define EXTENSION_LIST(V)                                                \
+  V(GC_EXTENSION,    "v8/gc")                                            \
+  V(PRINT_EXTENSION, "v8/print")                                         \
+  V(TRACE_EXTENSION, "v8/trace")
+
+#define DEFINE_EXTENSION_ID(Name, Ident) Name##_ID,
+enum CcTestExtensionIds {
+  EXTENSION_LIST(DEFINE_EXTENSION_ID)
+  kMaxExtensions
+};
+#undef DEFINE_EXTENSION_ID
+
+typedef v8::internal::EnumSet<CcTestExtensionIds> CcTestExtensionFlags;
+#define DEFINE_EXTENSION_FLAG(Name, Ident)                               \
+  static const CcTestExtensionFlags Name(1 << Name##_ID);
+  static const CcTestExtensionFlags NO_EXTENSIONS(0);
+  static const CcTestExtensionFlags ALL_EXTENSIONS((1 << kMaxExtensions) - 1);
+  EXTENSION_LIST(DEFINE_EXTENSION_FLAG)
+#undef DEFINE_EXTENSION_FLAG
+
 class CcTest {
  public:
   typedef void (TestFunction)();
@@ -67,6 +87,11 @@ class CcTest {
     default_isolate_ = default_isolate;
   }
   static v8::Isolate* default_isolate() { return default_isolate_; }
+  static v8::Isolate* isolate() { return context_->GetIsolate(); }
+  static v8::Handle<v8::Context> env() { return context_; }
+
+  // Helper function to initialize the VM.
+  static void InitializeVM(CcTestExtensionFlags extensions = NO_EXTENSIONS);
 
  private:
   TestFunction* callback_;
@@ -74,9 +99,10 @@ class CcTest {
   const char* name_;
   const char* dependency_;
   bool enabled_;
-  static CcTest* last_;
   CcTest* prev_;
+  static CcTest* last_;
   static v8::Isolate* default_isolate_;
+  static v8::Persistent<v8::Context> context_;
 };
 
 // Switches between all the Api tests using the threading support.
index b457ef2..616f712 100644 (file)
@@ -90,3 +90,16 @@ test-platform-tls/FastTLS: SKIP
 
 # This test times out.
 test-threads/ThreadJoinSelf: SKIP
+
+##############################################################################
+[ $arch == nacl_ia32 || $arch == nacl_x64 ]
+
+# These tests fail as there is no /tmp directory in Native Client.
+test-log/LogAccessorCallbacks: SKIP
+test-log/LogCallbacks: SKIP
+test-log/ProfLazyMode: SKIP
+
+# Native Client doesn't support sockets.
+test-debug/DebuggerAgent: SKIP
+test-debug/DebuggerAgentProtocolOverflowHeader: SKIP
+test-sockets/Socket: SKIP
index a9780f0..acc47b9 100644 (file)
 
 static const bool kLogThreading = false;
 
-static bool IsNaN(double x) {
-#ifdef WIN32
-  return _isnan(x);
-#else
-  return isnan(x);
-#endif
-}
-
 using ::v8::AccessorInfo;
 using ::v8::Arguments;
 using ::v8::Context;
@@ -2178,6 +2170,88 @@ THREADED_TEST(IdentityHash) {
 }
 
 
+THREADED_TEST(SymbolProperties) {
+  i::FLAG_harmony_symbols = true;
+
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  v8::Local<v8::Object> obj = v8::Object::New();
+  v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
+  v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
+
+  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+  // Check basic symbol functionality.
+  CHECK(sym1->IsSymbol());
+  CHECK(sym2->IsSymbol());
+  CHECK(!obj->IsSymbol());
+
+  CHECK(sym1->Equals(sym1));
+  CHECK(sym2->Equals(sym2));
+  CHECK(!sym1->Equals(sym2));
+  CHECK(!sym2->Equals(sym1));
+  CHECK(sym1->StrictEquals(sym1));
+  CHECK(sym2->StrictEquals(sym2));
+  CHECK(!sym1->StrictEquals(sym2));
+  CHECK(!sym2->StrictEquals(sym1));
+
+  CHECK(sym2->Name()->Equals(v8::String::New("my-symbol")));
+
+  v8::Local<v8::Value> sym_val = sym2;
+  CHECK(sym_val->IsSymbol());
+  CHECK(sym_val->Equals(sym2));
+  CHECK(sym_val->StrictEquals(sym2));
+  CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
+
+  v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
+  CHECK(sym_obj->IsSymbolObject());
+  CHECK(!sym2->IsSymbolObject());
+  CHECK(!obj->IsSymbolObject());
+  CHECK(sym_obj->Equals(sym2));
+  CHECK(!sym_obj->StrictEquals(sym2));
+  CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
+  CHECK(v8::SymbolObject::Cast(*sym_obj)->SymbolValue()->Equals(sym2));
+
+  // Make sure delete of a non-existent symbol property works.
+  CHECK(obj->Delete(sym1));
+  CHECK(!obj->Has(sym1));
+
+  CHECK(obj->Set(sym1, v8::Integer::New(1503)));
+  CHECK(obj->Has(sym1));
+  CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
+  CHECK(obj->Set(sym1, v8::Integer::New(2002)));
+  CHECK(obj->Has(sym1));
+  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
+  CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
+
+  CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
+  int num_props = obj->GetPropertyNames()->Length();
+  CHECK(obj->Set(v8::String::New("bla"), v8::Integer::New(20)));
+  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+  CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
+
+  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+  // Add another property and delete it afterwards to force the object in
+  // slow case.
+  CHECK(obj->Set(sym2, v8::Integer::New(2008)));
+  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
+  CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
+  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
+  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+
+  CHECK(obj->Has(sym1));
+  CHECK(obj->Has(sym2));
+  CHECK(obj->Delete(sym2));
+  CHECK(obj->Has(sym1));
+  CHECK(!obj->Has(sym2));
+  CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
+  CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
+}
+
+
 THREADED_TEST(HiddenProperties) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
@@ -3270,7 +3344,7 @@ THREADED_TEST(ConversionException) {
   CheckUncle(&try_catch);
 
   double number_value = obj->NumberValue();
-  CHECK_NE(0, IsNaN(number_value));
+  CHECK_NE(0, isnan(number_value));
   CheckUncle(&try_catch);
 
   int64_t integer_value = obj->IntegerValue();
@@ -12417,7 +12491,7 @@ TEST(PreCompileSerialization) {
   // Serialize.
   int serialized_data_length = sd->Length();
   char* serialized_data = i::NewArray<char>(serialized_data_length);
-  memcpy(serialized_data, sd->Data(), serialized_data_length);
+  i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
 
   // Deserialize.
   v8::ScriptData* deserialized_sd =
@@ -13410,6 +13484,7 @@ v8::Persistent<Context> calling_context2;
 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
   CHECK(Context::GetCurrent() == calling_context0);
+  CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
   CHECK(Context::GetCalling() == calling_context1);
   CHECK(Context::GetEntered() == calling_context2);
   return v8::Integer::New(42);
@@ -15356,21 +15431,21 @@ TEST(VisitExternalStrings) {
 
 static double DoubleFromBits(uint64_t value) {
   double target;
-  memcpy(&target, &value, sizeof(target));
+  i::OS::MemCopy(&target, &value, sizeof(target));
   return target;
 }
 
 
 static uint64_t DoubleToBits(double value) {
   uint64_t target;
-  memcpy(&target, &value, sizeof(target));
+  i::OS::MemCopy(&target, &value, sizeof(target));
   return target;
 }
 
 
 static double DoubleToDateTime(double input) {
   double date_limit = 864e13;
-  if (IsNaN(input) || input < -date_limit || input > date_limit) {
+  if (isnan(input) || input < -date_limit || input > date_limit) {
     return i::OS::nan_value();
   }
   return (input < 0) ? -(floor(-input)) : floor(input);
@@ -15431,7 +15506,7 @@ THREADED_TEST(QuietSignalingNaNs) {
     // Check that Number::New preserves non-NaNs and quiets SNaNs.
     v8::Handle<v8::Value> number = v8::Number::New(test_value);
     double stored_number = number->NumberValue();
-    if (!IsNaN(test_value)) {
+    if (!isnan(test_value)) {
       CHECK_EQ(test_value, stored_number);
     } else {
       uint64_t stored_bits = DoubleToBits(stored_number);
@@ -15450,7 +15525,7 @@ THREADED_TEST(QuietSignalingNaNs) {
     v8::Handle<v8::Value> date = v8::Date::New(test_value);
     double expected_stored_date = DoubleToDateTime(test_value);
     double stored_date = date->NumberValue();
-    if (!IsNaN(expected_stored_date)) {
+    if (!isnan(expected_stored_date)) {
       CHECK_EQ(expected_stored_date, stored_date);
     } else {
       uint64_t stored_bits = DoubleToBits(stored_date);
index 5cb4ab3..58ce5ec 100644 (file)
@@ -43,20 +43,10 @@ typedef Object* (*F3)(void* p0, int p1, int p2, int p3, int p4);
 typedef Object* (*F4)(void* p0, void* p1, int p2, int p3, int p4);
 
 
-static v8::Persistent<v8::Context> env;
-
-
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    env = v8::Context::New();
-  }
-}
-
-
 #define __ assm.
 
 TEST(0) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -83,7 +73,7 @@ TEST(0) {
 
 
 TEST(1) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -121,7 +111,7 @@ TEST(1) {
 
 
 TEST(2) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -168,7 +158,7 @@ TEST(2) {
 
 
 TEST(3) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -224,7 +214,7 @@ TEST(3) {
 
 TEST(4) {
   // Test the VFP floating point instructions.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -363,7 +353,7 @@ TEST(4) {
 
 TEST(5) {
   // Test the ARMv7 bitfield instructions.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -400,7 +390,7 @@ TEST(5) {
 
 TEST(6) {
   // Test saturating instructions.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -444,7 +434,7 @@ static void TestRoundingMode(VCVTTypes types,
                              double value,
                              int expected,
                              bool expected_exception = false) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -622,7 +612,7 @@ TEST(7) {
 
 TEST(8) {
   // Test VFP multi load/store with ia_w.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -654,87 +644,83 @@ TEST(8) {
   // single precision values around in memory.
   Assembler assm(isolate, NULL, 0);
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(&assm, VFP2);
-
-    __ mov(ip, Operand(sp));
-    __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
-    __ sub(fp, ip, Operand(4));
+  __ mov(ip, Operand(sp));
+  __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+  __ sub(fp, ip, Operand(4));
 
-    __ add(r4, r0, Operand(OFFSET_OF(D, a)));
-    __ vldm(ia_w, r4, d0, d3);
-    __ vldm(ia_w, r4, d4, d7);
+  __ add(r4, r0, Operand(OFFSET_OF(D, a)));
+  __ vldm(ia_w, r4, d0, d3);
+  __ vldm(ia_w, r4, d4, d7);
 
-    __ add(r4, r0, Operand(OFFSET_OF(D, a)));
-    __ vstm(ia_w, r4, d6, d7);
-    __ vstm(ia_w, r4, d0, d5);
+  __ add(r4, r0, Operand(OFFSET_OF(D, a)));
+  __ vstm(ia_w, r4, d6, d7);
+  __ vstm(ia_w, r4, d0, d5);
 
-    __ add(r4, r1, Operand(OFFSET_OF(F, a)));
-    __ vldm(ia_w, r4, s0, s3);
-    __ vldm(ia_w, r4, s4, s7);
+  __ add(r4, r1, Operand(OFFSET_OF(F, a)));
+  __ vldm(ia_w, r4, s0, s3);
+  __ vldm(ia_w, r4, s4, s7);
 
-    __ add(r4, r1, Operand(OFFSET_OF(F, a)));
-    __ vstm(ia_w, r4, s6, s7);
-    __ vstm(ia_w, r4, s0, s5);
+  __ add(r4, r1, Operand(OFFSET_OF(F, a)));
+  __ vstm(ia_w, r4, s6, s7);
+  __ vstm(ia_w, r4, s0, s5);
 
-    __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+  __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
 
-    CodeDesc desc;
-    assm.GetCode(&desc);
-    Object* code = isolate->heap()->CreateCode(
-        desc,
-        Code::ComputeFlags(Code::STUB),
-        Handle<Code>())->ToObjectChecked();
-    CHECK(code->IsCode());
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = isolate->heap()->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
 #ifdef DEBUG
-    Code::cast(code)->Print();
+  Code::cast(code)->Print();
 #endif
-    F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
-    d.a = 1.1;
-    d.b = 2.2;
-    d.c = 3.3;
-    d.d = 4.4;
-    d.e = 5.5;
-    d.f = 6.6;
-    d.g = 7.7;
-    d.h = 8.8;
-
-    f.a = 1.0;
-    f.b = 2.0;
-    f.c = 3.0;
-    f.d = 4.0;
-    f.e = 5.0;
-    f.f = 6.0;
-    f.g = 7.0;
-    f.h = 8.0;
-
-    Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
-    USE(dummy);
+  F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
+  d.a = 1.1;
+  d.b = 2.2;
+  d.c = 3.3;
+  d.d = 4.4;
+  d.e = 5.5;
+  d.f = 6.6;
+  d.g = 7.7;
+  d.h = 8.8;
+
+  f.a = 1.0;
+  f.b = 2.0;
+  f.c = 3.0;
+  f.d = 4.0;
+  f.e = 5.0;
+  f.f = 6.0;
+  f.g = 7.0;
+  f.h = 8.0;
+
+  Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
+  USE(dummy);
 
-    CHECK_EQ(7.7, d.a);
-    CHECK_EQ(8.8, d.b);
-    CHECK_EQ(1.1, d.c);
-    CHECK_EQ(2.2, d.d);
-    CHECK_EQ(3.3, d.e);
-    CHECK_EQ(4.4, d.f);
-    CHECK_EQ(5.5, d.g);
-    CHECK_EQ(6.6, d.h);
-
-    CHECK_EQ(7.0, f.a);
-    CHECK_EQ(8.0, f.b);
-    CHECK_EQ(1.0, f.c);
-    CHECK_EQ(2.0, f.d);
-    CHECK_EQ(3.0, f.e);
-    CHECK_EQ(4.0, f.f);
-    CHECK_EQ(5.0, f.g);
-    CHECK_EQ(6.0, f.h);
-  }
+  CHECK_EQ(7.7, d.a);
+  CHECK_EQ(8.8, d.b);
+  CHECK_EQ(1.1, d.c);
+  CHECK_EQ(2.2, d.d);
+  CHECK_EQ(3.3, d.e);
+  CHECK_EQ(4.4, d.f);
+  CHECK_EQ(5.5, d.g);
+  CHECK_EQ(6.6, d.h);
+
+  CHECK_EQ(7.0, f.a);
+  CHECK_EQ(8.0, f.b);
+  CHECK_EQ(1.0, f.c);
+  CHECK_EQ(2.0, f.d);
+  CHECK_EQ(3.0, f.e);
+  CHECK_EQ(4.0, f.f);
+  CHECK_EQ(5.0, f.g);
+  CHECK_EQ(6.0, f.h);
 }
 
 
 TEST(9) {
   // Test VFP multi load/store with ia.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -766,91 +752,87 @@ TEST(9) {
   // single precision values around in memory.
   Assembler assm(isolate, NULL, 0);
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(&assm, VFP2);
-
-    __ mov(ip, Operand(sp));
-    __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
-    __ sub(fp, ip, Operand(4));
+  __ mov(ip, Operand(sp));
+  __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+  __ sub(fp, ip, Operand(4));
 
-    __ add(r4, r0, Operand(OFFSET_OF(D, a)));
-    __ vldm(ia, r4, d0, d3);
-    __ add(r4, r4, Operand(4 * 8));
-    __ vldm(ia, r4, d4, d7);
+  __ add(r4, r0, Operand(OFFSET_OF(D, a)));
+  __ vldm(ia, r4, d0, d3);
+  __ add(r4, r4, Operand(4 * 8));
+  __ vldm(ia, r4, d4, d7);
 
-    __ add(r4, r0, Operand(OFFSET_OF(D, a)));
-    __ vstm(ia, r4, d6, d7);
-    __ add(r4, r4, Operand(2 * 8));
-    __ vstm(ia, r4, d0, d5);
+  __ add(r4, r0, Operand(OFFSET_OF(D, a)));
+  __ vstm(ia, r4, d6, d7);
+  __ add(r4, r4, Operand(2 * 8));
+  __ vstm(ia, r4, d0, d5);
 
-    __ add(r4, r1, Operand(OFFSET_OF(F, a)));
-    __ vldm(ia, r4, s0, s3);
-    __ add(r4, r4, Operand(4 * 4));
-    __ vldm(ia, r4, s4, s7);
+  __ add(r4, r1, Operand(OFFSET_OF(F, a)));
+  __ vldm(ia, r4, s0, s3);
+  __ add(r4, r4, Operand(4 * 4));
+  __ vldm(ia, r4, s4, s7);
 
-    __ add(r4, r1, Operand(OFFSET_OF(F, a)));
-    __ vstm(ia, r4, s6, s7);
-    __ add(r4, r4, Operand(2 * 4));
-    __ vstm(ia, r4, s0, s5);
+  __ add(r4, r1, Operand(OFFSET_OF(F, a)));
+  __ vstm(ia, r4, s6, s7);
+  __ add(r4, r4, Operand(2 * 4));
+  __ vstm(ia, r4, s0, s5);
 
-    __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+  __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
 
-    CodeDesc desc;
-    assm.GetCode(&desc);
-    Object* code = isolate->heap()->CreateCode(
-        desc,
-        Code::ComputeFlags(Code::STUB),
-        Handle<Code>())->ToObjectChecked();
-    CHECK(code->IsCode());
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = isolate->heap()->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
 #ifdef DEBUG
-    Code::cast(code)->Print();
+  Code::cast(code)->Print();
 #endif
-    F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
-    d.a = 1.1;
-    d.b = 2.2;
-    d.c = 3.3;
-    d.d = 4.4;
-    d.e = 5.5;
-    d.f = 6.6;
-    d.g = 7.7;
-    d.h = 8.8;
-
-    f.a = 1.0;
-    f.b = 2.0;
-    f.c = 3.0;
-    f.d = 4.0;
-    f.e = 5.0;
-    f.f = 6.0;
-    f.g = 7.0;
-    f.h = 8.0;
-
-    Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
-    USE(dummy);
+  F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
+  d.a = 1.1;
+  d.b = 2.2;
+  d.c = 3.3;
+  d.d = 4.4;
+  d.e = 5.5;
+  d.f = 6.6;
+  d.g = 7.7;
+  d.h = 8.8;
+
+  f.a = 1.0;
+  f.b = 2.0;
+  f.c = 3.0;
+  f.d = 4.0;
+  f.e = 5.0;
+  f.f = 6.0;
+  f.g = 7.0;
+  f.h = 8.0;
+
+  Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
+  USE(dummy);
 
-    CHECK_EQ(7.7, d.a);
-    CHECK_EQ(8.8, d.b);
-    CHECK_EQ(1.1, d.c);
-    CHECK_EQ(2.2, d.d);
-    CHECK_EQ(3.3, d.e);
-    CHECK_EQ(4.4, d.f);
-    CHECK_EQ(5.5, d.g);
-    CHECK_EQ(6.6, d.h);
-
-    CHECK_EQ(7.0, f.a);
-    CHECK_EQ(8.0, f.b);
-    CHECK_EQ(1.0, f.c);
-    CHECK_EQ(2.0, f.d);
-    CHECK_EQ(3.0, f.e);
-    CHECK_EQ(4.0, f.f);
-    CHECK_EQ(5.0, f.g);
-    CHECK_EQ(6.0, f.h);
-  }
+  CHECK_EQ(7.7, d.a);
+  CHECK_EQ(8.8, d.b);
+  CHECK_EQ(1.1, d.c);
+  CHECK_EQ(2.2, d.d);
+  CHECK_EQ(3.3, d.e);
+  CHECK_EQ(4.4, d.f);
+  CHECK_EQ(5.5, d.g);
+  CHECK_EQ(6.6, d.h);
+
+  CHECK_EQ(7.0, f.a);
+  CHECK_EQ(8.0, f.b);
+  CHECK_EQ(1.0, f.c);
+  CHECK_EQ(2.0, f.d);
+  CHECK_EQ(3.0, f.e);
+  CHECK_EQ(4.0, f.f);
+  CHECK_EQ(5.0, f.g);
+  CHECK_EQ(6.0, f.h);
 }
 
 
 TEST(10) {
   // Test VFP multi load/store with db_w.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -882,87 +864,83 @@ TEST(10) {
   // single precision values around in memory.
   Assembler assm(isolate, NULL, 0);
 
-  if (CpuFeatures::IsSupported(VFP2)) {
-    CpuFeatureScope scope(&assm, VFP2);
-
-    __ mov(ip, Operand(sp));
-    __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
-    __ sub(fp, ip, Operand(4));
+  __ mov(ip, Operand(sp));
+  __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+  __ sub(fp, ip, Operand(4));
 
-    __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8));
-    __ vldm(db_w, r4, d4, d7);
-    __ vldm(db_w, r4, d0, d3);
+  __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8));
+  __ vldm(db_w, r4, d4, d7);
+  __ vldm(db_w, r4, d0, d3);
 
-    __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8));
-    __ vstm(db_w, r4, d0, d5);
-    __ vstm(db_w, r4, d6, d7);
+  __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8));
+  __ vstm(db_w, r4, d0, d5);
+  __ vstm(db_w, r4, d6, d7);
 
-    __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4));
-    __ vldm(db_w, r4, s4, s7);
-    __ vldm(db_w, r4, s0, s3);
+  __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4));
+  __ vldm(db_w, r4, s4, s7);
+  __ vldm(db_w, r4, s0, s3);
 
-    __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4));
-    __ vstm(db_w, r4, s0, s5);
-    __ vstm(db_w, r4, s6, s7);
+  __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4));
+  __ vstm(db_w, r4, s0, s5);
+  __ vstm(db_w, r4, s6, s7);
 
-    __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+  __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
 
-    CodeDesc desc;
-    assm.GetCode(&desc);
-    Object* code = isolate->heap()->CreateCode(
-        desc,
-        Code::ComputeFlags(Code::STUB),
-        Handle<Code>())->ToObjectChecked();
-    CHECK(code->IsCode());
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = isolate->heap()->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
 #ifdef DEBUG
-    Code::cast(code)->Print();
+  Code::cast(code)->Print();
 #endif
-    F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
-    d.a = 1.1;
-    d.b = 2.2;
-    d.c = 3.3;
-    d.d = 4.4;
-    d.e = 5.5;
-    d.f = 6.6;
-    d.g = 7.7;
-    d.h = 8.8;
-
-    f.a = 1.0;
-    f.b = 2.0;
-    f.c = 3.0;
-    f.d = 4.0;
-    f.e = 5.0;
-    f.f = 6.0;
-    f.g = 7.0;
-    f.h = 8.0;
-
-    Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
-    USE(dummy);
+  F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
+  d.a = 1.1;
+  d.b = 2.2;
+  d.c = 3.3;
+  d.d = 4.4;
+  d.e = 5.5;
+  d.f = 6.6;
+  d.g = 7.7;
+  d.h = 8.8;
+
+  f.a = 1.0;
+  f.b = 2.0;
+  f.c = 3.0;
+  f.d = 4.0;
+  f.e = 5.0;
+  f.f = 6.0;
+  f.g = 7.0;
+  f.h = 8.0;
+
+  Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
+  USE(dummy);
 
-    CHECK_EQ(7.7, d.a);
-    CHECK_EQ(8.8, d.b);
-    CHECK_EQ(1.1, d.c);
-    CHECK_EQ(2.2, d.d);
-    CHECK_EQ(3.3, d.e);
-    CHECK_EQ(4.4, d.f);
-    CHECK_EQ(5.5, d.g);
-    CHECK_EQ(6.6, d.h);
-
-    CHECK_EQ(7.0, f.a);
-    CHECK_EQ(8.0, f.b);
-    CHECK_EQ(1.0, f.c);
-    CHECK_EQ(2.0, f.d);
-    CHECK_EQ(3.0, f.e);
-    CHECK_EQ(4.0, f.f);
-    CHECK_EQ(5.0, f.g);
-    CHECK_EQ(6.0, f.h);
-  }
+  CHECK_EQ(7.7, d.a);
+  CHECK_EQ(8.8, d.b);
+  CHECK_EQ(1.1, d.c);
+  CHECK_EQ(2.2, d.d);
+  CHECK_EQ(3.3, d.e);
+  CHECK_EQ(4.4, d.f);
+  CHECK_EQ(5.5, d.g);
+  CHECK_EQ(6.6, d.h);
+
+  CHECK_EQ(7.0, f.a);
+  CHECK_EQ(8.0, f.b);
+  CHECK_EQ(1.0, f.c);
+  CHECK_EQ(2.0, f.d);
+  CHECK_EQ(3.0, f.e);
+  CHECK_EQ(4.0, f.f);
+  CHECK_EQ(5.0, f.g);
+  CHECK_EQ(6.0, f.h);
 }
 
 
 TEST(11) {
   // Test instructions using the carry flag.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -1028,7 +1006,7 @@ TEST(11) {
 
 TEST(12) {
   // Test chaining of label usages within instructions (issue 1644).
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -1043,7 +1021,7 @@ TEST(12) {
 
 TEST(13) {
   // Test VFP instructions using registers d16-d31.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -1159,4 +1137,84 @@ TEST(13) {
   }
 }
 
+
+TEST(14) {
+  // Test the VFP Canonicalized Nan mode.
+  CcTest::InitializeVM();
+  Isolate* isolate = Isolate::Current();
+  HandleScope scope(isolate);
+
+  typedef struct {
+    double left;
+    double right;
+    double add_result;
+    double sub_result;
+    double mul_result;
+    double div_result;
+  } T;
+  T t;
+
+  // Create a function that makes the four basic operations.
+  Assembler assm(isolate, NULL, 0);
+
+  // Ensure FPSCR state (as JSEntryStub does).
+  Label fpscr_done;
+  __ vmrs(r1);
+  __ tst(r1, Operand(kVFPDefaultNaNModeControlBit));
+  __ b(ne, &fpscr_done);
+  __ orr(r1, r1, Operand(kVFPDefaultNaNModeControlBit));
+  __ vmsr(r1);
+  __ bind(&fpscr_done);
+
+  __ vldr(d0, r0, OFFSET_OF(T, left));
+  __ vldr(d1, r0, OFFSET_OF(T, right));
+  __ vadd(d2, d0, d1);
+  __ vstr(d2, r0, OFFSET_OF(T, add_result));
+  __ vsub(d2, d0, d1);
+  __ vstr(d2, r0, OFFSET_OF(T, sub_result));
+  __ vmul(d2, d0, d1);
+  __ vstr(d2, r0, OFFSET_OF(T, mul_result));
+  __ vdiv(d2, d0, d1);
+  __ vstr(d2, r0, OFFSET_OF(T, div_result));
+
+  __ mov(pc, Operand(lr));
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = isolate->heap()->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+  t.left = BitCast<double>(kHoleNanInt64);
+  t.right = 1;
+  t.add_result = 0;
+  t.sub_result = 0;
+  t.mul_result = 0;
+  t.div_result = 0;
+  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+  USE(dummy);
+  const uint32_t kArmNanUpper32 = 0x7ff80000;
+  const uint32_t kArmNanLower32 = 0x00000000;
+#ifdef DEBUG
+  const uint64_t kArmNanInt64 =
+      (static_cast<uint64_t>(kArmNanUpper32) << 32) | kArmNanLower32;
+  ASSERT(kArmNanInt64 != kHoleNanInt64);
+#endif
+  // With VFP2 the sign of the canonicalized Nan is undefined. So
+  // we remove the sign bit for the upper tests.
+  CHECK_EQ(kArmNanUpper32, (BitCast<int64_t>(t.add_result) >> 32) & 0x7fffffff);
+  CHECK_EQ(kArmNanLower32, BitCast<int64_t>(t.add_result) & 0xffffffffu);
+  CHECK_EQ(kArmNanUpper32, (BitCast<int64_t>(t.sub_result) >> 32) & 0x7fffffff);
+  CHECK_EQ(kArmNanLower32, BitCast<int64_t>(t.sub_result) & 0xffffffffu);
+  CHECK_EQ(kArmNanUpper32, (BitCast<int64_t>(t.mul_result) >> 32) & 0x7fffffff);
+  CHECK_EQ(kArmNanLower32, BitCast<int64_t>(t.mul_result) & 0xffffffffu);
+  CHECK_EQ(kArmNanUpper32, (BitCast<int64_t>(t.div_result) >> 32) & 0x7fffffff);
+  CHECK_EQ(kArmNanLower32, BitCast<int64_t>(t.div_result) & 0xffffffffu);
+}
+
 #undef __
index 6176285..8d39ee7 100644 (file)
@@ -44,21 +44,11 @@ typedef int (*F1)(int x);
 typedef int (*F2)(int x, int y);
 
 
-static v8::Persistent<v8::Context> env;
-
-
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    env = v8::Context::New();
-  }
-}
-
-
 #define __ assm.
 
 TEST(AssemblerIa320) {
-  InitializeVM();
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  CcTest::InitializeVM();
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
 
   v8::internal::byte buffer[256];
@@ -86,8 +76,8 @@ TEST(AssemblerIa320) {
 
 
 TEST(AssemblerIa321) {
-  InitializeVM();
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  CcTest::InitializeVM();
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
 
   v8::internal::byte buffer[256];
@@ -125,8 +115,8 @@ TEST(AssemblerIa321) {
 
 
 TEST(AssemblerIa322) {
-  InitializeVM();
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  CcTest::InitializeVM();
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
 
   v8::internal::byte buffer[256];
@@ -170,10 +160,10 @@ TEST(AssemblerIa322) {
 typedef int (*F3)(float x);
 
 TEST(AssemblerIa323) {
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!CpuFeatures::IsSupported(SSE2)) return;
 
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
 
   v8::internal::byte buffer[256];
@@ -206,10 +196,10 @@ TEST(AssemblerIa323) {
 typedef int (*F4)(double x);
 
 TEST(AssemblerIa324) {
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!CpuFeatures::IsSupported(SSE2)) return;
 
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
 
   v8::internal::byte buffer[256];
@@ -240,8 +230,8 @@ TEST(AssemblerIa324) {
 
 static int baz = 42;
 TEST(AssemblerIa325) {
-  InitializeVM();
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  CcTest::InitializeVM();
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
 
   v8::internal::byte buffer[256];
@@ -265,10 +255,10 @@ TEST(AssemblerIa325) {
 typedef double (*F5)(double x, double y);
 
 TEST(AssemblerIa326) {
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!CpuFeatures::IsSupported(SSE2)) return;
 
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
   v8::internal::byte buffer[256];
   Assembler assm(isolate, buffer, sizeof buffer);
@@ -311,10 +301,10 @@ TEST(AssemblerIa326) {
 typedef double (*F6)(int x);
 
 TEST(AssemblerIa328) {
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!CpuFeatures::IsSupported(SSE2)) return;
 
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
   v8::internal::byte buffer[256];
   Assembler assm(isolate, buffer, sizeof buffer);
@@ -348,8 +338,8 @@ TEST(AssemblerIa328) {
 typedef int (*F7)(double x, double y);
 
 TEST(AssemblerIa329) {
-  InitializeVM();
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  CcTest::InitializeVM();
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
   v8::internal::byte buffer[256];
   MacroAssembler assm(isolate, buffer, sizeof buffer);
@@ -404,8 +394,8 @@ TEST(AssemblerIa329) {
 
 TEST(AssemblerIa3210) {
   // Test chaining of label usages within instructions (issue 1644).
-  InitializeVM();
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  CcTest::InitializeVM();
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
   Assembler assm(isolate, NULL, 0);
 
@@ -418,8 +408,8 @@ TEST(AssemblerIa3210) {
 
 
 TEST(AssemblerMultiByteNop) {
-  InitializeVM();
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  CcTest::InitializeVM();
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
   v8::internal::byte buffer[1024];
   Assembler assm(isolate, buffer, sizeof(buffer));
index 1e4e9e2..419ef35 100644 (file)
@@ -44,24 +44,11 @@ typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
 typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
 
 
-static v8::Persistent<v8::Context> env;
-
-
-static void InitializeVM() {
-  // Disable compilation of natives.
-  FLAG_disable_native_files = true;
-
-  if (env.IsEmpty()) {
-    env = v8::Context::New();
-  }
-}
-
-
 #define __ assm.
 
 
 TEST(MIPS0) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -87,7 +74,7 @@ TEST(MIPS0) {
 
 
 TEST(MIPS1) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -126,7 +113,7 @@ TEST(MIPS1) {
 
 
 TEST(MIPS2) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -268,7 +255,7 @@ TEST(MIPS2) {
 
 TEST(MIPS3) {
   // Test floating point instructions.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -290,33 +277,30 @@ TEST(MIPS3) {
   MacroAssembler assm(isolate, NULL, 0);
   Label L, C;
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(&assm, FPU);
-
-    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
-    __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
-    __ add_d(f8, f4, f6);
-    __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, c)) );  // c = a + b.
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+  __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
+  __ add_d(f8, f4, f6);
+  __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, c)) );  // c = a + b.
 
-    __ mov_d(f10, f8);  // c
-    __ neg_d(f12, f6);  // -b
-    __ sub_d(f10, f10, f12);
-    __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, d)) );  // d = c - (-b).
+  __ mov_d(f10, f8);  // c
+  __ neg_d(f12, f6);  // -b
+  __ sub_d(f10, f10, f12);
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, d)) );  // d = c - (-b).
 
-    __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, b)) );   // b = a.
+  __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, b)) );   // b = a.
 
-    __ li(t0, 120);
-    __ mtc1(t0, f14);
-    __ cvt_d_w(f14, f14);   // f14 = 120.0.
-    __ mul_d(f10, f10, f14);
-    __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, e)) );  // e = d * 120 = 1.8066e16.
+  __ li(t0, 120);
+  __ mtc1(t0, f14);
+  __ cvt_d_w(f14, f14);   // f14 = 120.0.
+  __ mul_d(f10, f10, f14);
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, e)) );  // e = d * 120 = 1.8066e16.
 
-    __ div_d(f12, f10, f4);
-    __ sdc1(f12, MemOperand(a0, OFFSET_OF(T, f)) );  // f = e / a = 120.44.
+  __ div_d(f12, f10, f4);
+  __ sdc1(f12, MemOperand(a0, OFFSET_OF(T, f)) );  // f = e / a = 120.44.
 
-    __ sqrt_d(f14, f12);
-    __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) );
-    // g = sqrt(f) = 10.97451593465515908537
+  __ sqrt_d(f14, f12);
+  __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) );
+  // g = sqrt(f) = 10.97451593465515908537
 
   if (kArchVariant == kMips32r2) {
     __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, h)) );
@@ -325,42 +309,41 @@ TEST(MIPS3) {
     __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, h)) );
   }
 
-    __ jr(ra);
-    __ nop();
+  __ jr(ra);
+  __ nop();
 
-    CodeDesc desc;
-    assm.GetCode(&desc);
-    Object* code = HEAP->CreateCode(
-        desc,
-        Code::ComputeFlags(Code::STUB),
-        Handle<Code>())->ToObjectChecked();
-    CHECK(code->IsCode());
-    F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
-    t.a = 1.5e14;
-    t.b = 2.75e11;
-    t.c = 0.0;
-    t.d = 0.0;
-    t.e = 0.0;
-    t.f = 0.0;
-    t.h = 1.5;
-    t.i = 2.75;
-    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
-    USE(dummy);
-    CHECK_EQ(1.5e14, t.a);
-    CHECK_EQ(1.5e14, t.b);
-    CHECK_EQ(1.50275e14, t.c);
-    CHECK_EQ(1.50550e14, t.d);
-    CHECK_EQ(1.8066e16, t.e);
-    CHECK_EQ(120.44, t.f);
-    CHECK_EQ(10.97451593465515908537, t.g);
-    CHECK_EQ(6.875, t.h);
-  }
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = HEAP->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
+  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+  t.a = 1.5e14;
+  t.b = 2.75e11;
+  t.c = 0.0;
+  t.d = 0.0;
+  t.e = 0.0;
+  t.f = 0.0;
+  t.h = 1.5;
+  t.i = 2.75;
+  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+  USE(dummy);
+  CHECK_EQ(1.5e14, t.a);
+  CHECK_EQ(1.5e14, t.b);
+  CHECK_EQ(1.50275e14, t.c);
+  CHECK_EQ(1.50550e14, t.d);
+  CHECK_EQ(1.8066e16, t.e);
+  CHECK_EQ(120.44, t.f);
+  CHECK_EQ(10.97451593465515908537, t.g);
+  CHECK_EQ(6.875, t.h);
 }
 
 
 TEST(MIPS4) {
   // Test moves between floating point and integer registers.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -374,54 +357,50 @@ TEST(MIPS4) {
   Assembler assm(isolate, NULL, 0);
   Label L, C;
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(&assm, FPU);
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+  __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
 
-    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
-    __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
+  // Swap f4 and f6, by using four integer registers, t0-t3.
+  __ mfc1(t0, f4);
+  __ mfc1(t1, f5);
+  __ mfc1(t2, f6);
+  __ mfc1(t3, f7);
 
-    // Swap f4 and f6, by using four integer registers, t0-t3.
-    __ mfc1(t0, f4);
-    __ mfc1(t1, f5);
-    __ mfc1(t2, f6);
-    __ mfc1(t3, f7);
+  __ mtc1(t0, f6);
+  __ mtc1(t1, f7);
+  __ mtc1(t2, f4);
+  __ mtc1(t3, f5);
 
-    __ mtc1(t0, f6);
-    __ mtc1(t1, f7);
-    __ mtc1(t2, f4);
-    __ mtc1(t3, f5);
+  // Store the swapped f4 and f5 back to memory.
+  __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+  __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, c)) );
 
-    // Store the swapped f4 and f5 back to memory.
-    __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
-    __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, c)) );
-
-    __ jr(ra);
-    __ nop();
+  __ jr(ra);
+  __ nop();
 
-    CodeDesc desc;
-    assm.GetCode(&desc);
-    Object* code = HEAP->CreateCode(
-        desc,
-        Code::ComputeFlags(Code::STUB),
-        Handle<Code>())->ToObjectChecked();
-    CHECK(code->IsCode());
-    F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
-    t.a = 1.5e22;
-    t.b = 2.75e11;
-    t.c = 17.17;
-    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
-    USE(dummy);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = HEAP->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
+  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+  t.a = 1.5e22;
+  t.b = 2.75e11;
+  t.c = 17.17;
+  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+  USE(dummy);
 
-    CHECK_EQ(2.75e11, t.a);
-    CHECK_EQ(2.75e11, t.b);
-    CHECK_EQ(1.5e22, t.c);
-  }
+  CHECK_EQ(2.75e11, t.a);
+  CHECK_EQ(2.75e11, t.b);
+  CHECK_EQ(1.5e22, t.c);
 }
 
 
 TEST(MIPS5) {
   // Test conversions between doubles and integers.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -436,64 +415,60 @@ TEST(MIPS5) {
   Assembler assm(isolate, NULL, 0);
   Label L, C;
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(&assm, FPU);
+  // Load all structure elements to registers.
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+  __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
+  __ lw(t0, MemOperand(a0, OFFSET_OF(T, i)) );
+  __ lw(t1, MemOperand(a0, OFFSET_OF(T, j)) );
 
-    // Load all structure elements to registers.
-    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
-    __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
-    __ lw(t0, MemOperand(a0, OFFSET_OF(T, i)) );
-    __ lw(t1, MemOperand(a0, OFFSET_OF(T, j)) );
-
-    // Convert double in f4 to int in element i.
-    __ cvt_w_d(f8, f4);
-    __ mfc1(t2, f8);
-    __ sw(t2, MemOperand(a0, OFFSET_OF(T, i)) );
-
-    // Convert double in f6 to int in element j.
-    __ cvt_w_d(f10, f6);
-    __ mfc1(t3, f10);
-    __ sw(t3, MemOperand(a0, OFFSET_OF(T, j)) );
-
-    // Convert int in original i (t0) to double in a.
-    __ mtc1(t0, f12);
-    __ cvt_d_w(f0, f12);
-    __ sdc1(f0, MemOperand(a0, OFFSET_OF(T, a)) );
-
-    // Convert int in original j (t1) to double in b.
-    __ mtc1(t1, f14);
-    __ cvt_d_w(f2, f14);
-    __ sdc1(f2, MemOperand(a0, OFFSET_OF(T, b)) );
+  // Convert double in f4 to int in element i.
+  __ cvt_w_d(f8, f4);
+  __ mfc1(t2, f8);
+  __ sw(t2, MemOperand(a0, OFFSET_OF(T, i)) );
 
-    __ jr(ra);
-    __ nop();
+  // Convert double in f6 to int in element j.
+  __ cvt_w_d(f10, f6);
+  __ mfc1(t3, f10);
+  __ sw(t3, MemOperand(a0, OFFSET_OF(T, j)) );
 
-    CodeDesc desc;
-    assm.GetCode(&desc);
-    Object* code = HEAP->CreateCode(
-        desc,
-        Code::ComputeFlags(Code::STUB),
-        Handle<Code>())->ToObjectChecked();
-    CHECK(code->IsCode());
-    F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
-    t.a = 1.5e4;
-    t.b = 2.75e8;
-    t.i = 12345678;
-    t.j = -100000;
-    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
-    USE(dummy);
+  // Convert int in original i (t0) to double in a.
+  __ mtc1(t0, f12);
+  __ cvt_d_w(f0, f12);
+  __ sdc1(f0, MemOperand(a0, OFFSET_OF(T, a)) );
 
-    CHECK_EQ(12345678.0, t.a);
-    CHECK_EQ(-100000.0, t.b);
-    CHECK_EQ(15000, t.i);
-    CHECK_EQ(275000000, t.j);
-  }
+  // Convert int in original j (t1) to double in b.
+  __ mtc1(t1, f14);
+  __ cvt_d_w(f2, f14);
+  __ sdc1(f2, MemOperand(a0, OFFSET_OF(T, b)) );
+
+  __ jr(ra);
+  __ nop();
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = HEAP->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
+  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+  t.a = 1.5e4;
+  t.b = 2.75e8;
+  t.i = 12345678;
+  t.j = -100000;
+  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+  USE(dummy);
+
+  CHECK_EQ(12345678.0, t.a);
+  CHECK_EQ(-100000.0, t.b);
+  CHECK_EQ(15000, t.i);
+  CHECK_EQ(275000000, t.j);
 }
 
 
 TEST(MIPS6) {
   // Test simple memory loads and stores.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -566,7 +541,7 @@ TEST(MIPS6) {
 
 TEST(MIPS7) {
   // Test floating point compare and branch instructions.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -586,69 +561,65 @@ TEST(MIPS7) {
   MacroAssembler assm(isolate, NULL, 0);
   Label neither_is_nan, less_than, outa_here;
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(&assm, FPU);
+  __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
+  __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
+  __ c(UN, D, f4, f6);
+  __ bc1f(&neither_is_nan);
+  __ nop();
+  __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
+  __ Branch(&outa_here);
 
-    __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) );
-    __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) );
-    __ c(UN, D, f4, f6);
-    __ bc1f(&neither_is_nan);
-    __ nop();
-    __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
-    __ Branch(&outa_here);
-
-    __ bind(&neither_is_nan);
-
-    if (kArchVariant == kLoongson) {
-      __ c(OLT, D, f6, f4);
-      __ bc1t(&less_than);
-    } else {
-      __ c(OLT, D, f6, f4, 2);
-      __ bc1t(&less_than, 2);
-    }
-    __ nop();
-    __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
-    __ Branch(&outa_here);
+  __ bind(&neither_is_nan);
 
-    __ bind(&less_than);
-    __ Addu(t0, zero_reg, Operand(1));
-    __ sw(t0, MemOperand(a0, OFFSET_OF(T, result)) );  // Set true.
+  if (kArchVariant == kLoongson) {
+    __ c(OLT, D, f6, f4);
+    __ bc1t(&less_than);
+  } else {
+    __ c(OLT, D, f6, f4, 2);
+    __ bc1t(&less_than, 2);
+  }
+  __ nop();
+  __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) );
+  __ Branch(&outa_here);
 
+  __ bind(&less_than);
+  __ Addu(t0, zero_reg, Operand(1));
+  __ sw(t0, MemOperand(a0, OFFSET_OF(T, result)) );  // Set true.
 
-    // This test-case should have additional tests.
 
-    __ bind(&outa_here);
+  // This test-case should have additional tests.
 
-    __ jr(ra);
-    __ nop();
+  __ bind(&outa_here);
 
-    CodeDesc desc;
-    assm.GetCode(&desc);
-    Object* code = HEAP->CreateCode(
-        desc,
-        Code::ComputeFlags(Code::STUB),
-        Handle<Code>())->ToObjectChecked();
-    CHECK(code->IsCode());
-    F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
-    t.a = 1.5e14;
-    t.b = 2.75e11;
-    t.c = 2.0;
-    t.d = -4.0;
-    t.e = 0.0;
-    t.f = 0.0;
-    t.result = 0;
-    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
-    USE(dummy);
-    CHECK_EQ(1.5e14, t.a);
-    CHECK_EQ(2.75e11, t.b);
-    CHECK_EQ(1, t.result);
-  }
+  __ jr(ra);
+  __ nop();
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = HEAP->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
+  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+  t.a = 1.5e14;
+  t.b = 2.75e11;
+  t.c = 2.0;
+  t.d = -4.0;
+  t.e = 0.0;
+  t.f = 0.0;
+  t.result = 0;
+  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+  USE(dummy);
+  CHECK_EQ(1.5e14, t.a);
+  CHECK_EQ(2.75e11, t.b);
+  CHECK_EQ(1, t.result);
 }
 
 
 TEST(MIPS8) {
   // Test ROTR and ROTRV instructions.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -753,7 +724,7 @@ TEST(MIPS8) {
 
 TEST(MIPS9) {
   // Test BRANCH improvements.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -783,7 +754,7 @@ TEST(MIPS9) {
 TEST(MIPS10) {
   // Test conversions between doubles and long integers.
   // Test hos the long ints map to FP regs pairs.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -802,9 +773,7 @@ TEST(MIPS10) {
   Assembler assm(isolate, NULL, 0);
   Label L, C;
 
-  if (CpuFeatures::IsSupported(FPU) && kArchVariant == kMips32r2) {
-    CpuFeatureScope scope(&assm, FPU);
-
+  if (kArchVariant == kMips32r2) {
     // Load all structure elements to registers.
     __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, a)));
 
@@ -858,7 +827,7 @@ TEST(MIPS10) {
 
 TEST(MIPS11) {
   // Test LWL, LWR, SWL and SWR instructions.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -1002,7 +971,7 @@ TEST(MIPS11) {
 
 
 TEST(MIPS12) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -1094,7 +1063,7 @@ TEST(MIPS12) {
 
 TEST(MIPS13) {
   // Test Cvt_d_uw and Trunc_uw_d macros.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -1110,54 +1079,50 @@ TEST(MIPS13) {
 
   MacroAssembler assm(isolate, NULL, 0);
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(&assm, FPU);
-
-    __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_small_in)));
-    __ Cvt_d_uw(f10, t0, f22);
-    __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, cvt_small_out)));
+  __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_small_in)));
+  __ Cvt_d_uw(f10, t0, f22);
+  __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, cvt_small_out)));
 
-    __ Trunc_uw_d(f10, f10, f22);
-    __ swc1(f10, MemOperand(a0, OFFSET_OF(T, trunc_small_out)));
+  __ Trunc_uw_d(f10, f10, f22);
+  __ swc1(f10, MemOperand(a0, OFFSET_OF(T, trunc_small_out)));
 
-    __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_big_in)));
-    __ Cvt_d_uw(f8, t0, f22);
-    __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, cvt_big_out)));
+  __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_big_in)));
+  __ Cvt_d_uw(f8, t0, f22);
+  __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, cvt_big_out)));
 
-    __ Trunc_uw_d(f8, f8, f22);
-    __ swc1(f8, MemOperand(a0, OFFSET_OF(T, trunc_big_out)));
+  __ Trunc_uw_d(f8, f8, f22);
+  __ swc1(f8, MemOperand(a0, OFFSET_OF(T, trunc_big_out)));
 
-    __ jr(ra);
-    __ nop();
+  __ jr(ra);
+  __ nop();
 
-    CodeDesc desc;
-    assm.GetCode(&desc);
-    Object* code = HEAP->CreateCode(
-        desc,
-        Code::ComputeFlags(Code::STUB),
-        Handle<Code>())->ToObjectChecked();
-    CHECK(code->IsCode());
-    F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = HEAP->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
+  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
 
-    t.cvt_big_in = 0xFFFFFFFF;
-    t.cvt_small_in  = 333;
+  t.cvt_big_in = 0xFFFFFFFF;
+  t.cvt_small_in  = 333;
 
-    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
-    USE(dummy);
+  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+  USE(dummy);
 
-    CHECK_EQ(t.cvt_big_out, static_cast<double>(t.cvt_big_in));
-    CHECK_EQ(t.cvt_small_out, static_cast<double>(t.cvt_small_in));
+  CHECK_EQ(t.cvt_big_out, static_cast<double>(t.cvt_big_in));
+  CHECK_EQ(t.cvt_small_out, static_cast<double>(t.cvt_small_in));
 
-    CHECK_EQ(static_cast<int>(t.trunc_big_out), static_cast<int>(t.cvt_big_in));
-    CHECK_EQ(static_cast<int>(t.trunc_small_out),
-             static_cast<int>(t.cvt_small_in));
-  }
+  CHECK_EQ(static_cast<int>(t.trunc_big_out), static_cast<int>(t.cvt_big_in));
+  CHECK_EQ(static_cast<int>(t.trunc_small_out),
+           static_cast<int>(t.cvt_small_in));
 }
 
 
 TEST(MIPS14) {
   // Test round, floor, ceil, trunc, cvt.
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
@@ -1194,87 +1159,84 @@ TEST(MIPS14) {
 
   MacroAssembler assm(isolate, NULL, 0);
 
-  if (CpuFeatures::IsSupported(FPU)) {
-    CpuFeatureScope scope(&assm, FPU);
-
-    // Save FCSR.
-    __ cfc1(a1, FCSR);
-    // Disable FPU exceptions.
-    __ ctc1(zero_reg, FCSR);
+  // Save FCSR.
+  __ cfc1(a1, FCSR);
+  // Disable FPU exceptions.
+  __ ctc1(zero_reg, FCSR);
 #define RUN_ROUND_TEST(x) \
-    __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_up_in))); \
-    __ x##_w_d(f0, f0); \
-    __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_up_out))); \
-    \
-    __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_down_in))); \
-    __ x##_w_d(f0, f0); \
-    __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_down_out))); \
-    \
-    __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_up_in))); \
-    __ x##_w_d(f0, f0); \
-    __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_up_out))); \
-    \
-    __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_down_in))); \
-    __ x##_w_d(f0, f0); \
-    __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_down_out))); \
-    \
-    __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err1_in))); \
-    __ ctc1(zero_reg, FCSR); \
-    __ x##_w_d(f0, f0); \
-    __ cfc1(a2, FCSR); \
-    __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err1_out))); \
-    \
-    __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err2_in))); \
-    __ ctc1(zero_reg, FCSR); \
-    __ x##_w_d(f0, f0); \
-    __ cfc1(a2, FCSR); \
-    __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err2_out))); \
-    \
-    __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err3_in))); \
-    __ ctc1(zero_reg, FCSR); \
-    __ x##_w_d(f0, f0); \
-    __ cfc1(a2, FCSR); \
-    __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err3_out))); \
-    \
-    __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err4_in))); \
-    __ ctc1(zero_reg, FCSR); \
-    __ x##_w_d(f0, f0); \
-    __ cfc1(a2, FCSR); \
-    __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err4_out))); \
-    __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_invalid_result)));
-
-    RUN_ROUND_TEST(round)
-    RUN_ROUND_TEST(floor)
-    RUN_ROUND_TEST(ceil)
-    RUN_ROUND_TEST(trunc)
-    RUN_ROUND_TEST(cvt)
-
-    // Restore FCSR.
-    __ ctc1(a1, FCSR);
+  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_up_in))); \
+  __ x##_w_d(f0, f0); \
+  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_up_out))); \
+  \
+  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_down_in))); \
+  __ x##_w_d(f0, f0); \
+  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_down_out))); \
+  \
+  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_up_in))); \
+  __ x##_w_d(f0, f0); \
+  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_up_out))); \
+  \
+  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_down_in))); \
+  __ x##_w_d(f0, f0); \
+  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_down_out))); \
+  \
+  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err1_in))); \
+  __ ctc1(zero_reg, FCSR); \
+  __ x##_w_d(f0, f0); \
+  __ cfc1(a2, FCSR); \
+  __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err1_out))); \
+  \
+  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err2_in))); \
+  __ ctc1(zero_reg, FCSR); \
+  __ x##_w_d(f0, f0); \
+  __ cfc1(a2, FCSR); \
+  __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err2_out))); \
+  \
+  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err3_in))); \
+  __ ctc1(zero_reg, FCSR); \
+  __ x##_w_d(f0, f0); \
+  __ cfc1(a2, FCSR); \
+  __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err3_out))); \
+  \
+  __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err4_in))); \
+  __ ctc1(zero_reg, FCSR); \
+  __ x##_w_d(f0, f0); \
+  __ cfc1(a2, FCSR); \
+  __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err4_out))); \
+  __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_invalid_result)));
+
+  RUN_ROUND_TEST(round)
+  RUN_ROUND_TEST(floor)
+  RUN_ROUND_TEST(ceil)
+  RUN_ROUND_TEST(trunc)
+  RUN_ROUND_TEST(cvt)
+
+  // Restore FCSR.
+  __ ctc1(a1, FCSR);
 
-    __ jr(ra);
-    __ nop();
+  __ jr(ra);
+  __ nop();
 
-    CodeDesc desc;
-    assm.GetCode(&desc);
-    Object* code = HEAP->CreateCode(
-        desc,
-        Code::ComputeFlags(Code::STUB),
-        Handle<Code>())->ToObjectChecked();
-    CHECK(code->IsCode());
-    F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = HEAP->CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Code>())->ToObjectChecked();
+  CHECK(code->IsCode());
+  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
 
-    t.round_up_in = 123.51;
-    t.round_down_in = 123.49;
-    t.neg_round_up_in = -123.5;
-    t.neg_round_down_in = -123.49;
-    t.err1_in = 123.51;
-    t.err2_in = 1;
-    t.err3_in = static_cast<double>(1) + 0xFFFFFFFF;
-    t.err4_in = NAN;
+  t.round_up_in = 123.51;
+  t.round_down_in = 123.49;
+  t.neg_round_up_in = -123.5;
+  t.neg_round_down_in = -123.49;
+  t.err1_in = 123.51;
+  t.err2_in = 1;
+  t.err3_in = static_cast<double>(1) + 0xFFFFFFFF;
+  t.err4_in = NAN;
 
-    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
-    USE(dummy);
+  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+  USE(dummy);
 
 #define GET_FPU_ERR(x) (static_cast<int>(x & kFCSRFlagMask))
 #define CHECK_ROUND_RESULT(type) \
@@ -1284,17 +1246,16 @@ TEST(MIPS14) {
   CHECK(GET_FPU_ERR(t.type##_err4_out) & kFCSRInvalidOpFlagMask); \
   CHECK_EQ(kFPUInvalidResult, t.type##_invalid_result);
 
-    CHECK_ROUND_RESULT(round);
-    CHECK_ROUND_RESULT(floor);
-    CHECK_ROUND_RESULT(ceil);
-    CHECK_ROUND_RESULT(cvt);
-  }
+  CHECK_ROUND_RESULT(round);
+  CHECK_ROUND_RESULT(floor);
+  CHECK_ROUND_RESULT(ceil);
+  CHECK_ROUND_RESULT(cvt);
 }
 
 
 TEST(MIPS15) {
   // Test chaining of label usages within instructions (issue 1644).
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
   Assembler assm(isolate, NULL, 0);
index d2ea771..669475a 100644 (file)
@@ -88,16 +88,6 @@ static const v8::internal::Register arg2 = rsi;
 #define __ assm.
 
 
-static v8::Persistent<v8::Context> env;
-
-
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    env = v8::Context::New();
-  }
-}
-
-
 TEST(AssemblerX64ReturnOperation) {
   OS::SetUp();
   // Allocate an executable page of memory.
@@ -361,8 +351,8 @@ TEST(OperandRegisterDependency) {
 
 TEST(AssemblerX64LabelChaining) {
   // Test chaining of label usages within instructions (issue 1644).
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   Assembler assm(Isolate::Current(), NULL, 0);
 
   Label target;
@@ -374,8 +364,8 @@ TEST(AssemblerX64LabelChaining) {
 
 
 TEST(AssemblerMultiByteNop) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   v8::internal::byte buffer[1024];
   Isolate* isolate = Isolate::Current();
   Assembler assm(isolate, buffer, sizeof(buffer));
index 6c100b0..f200435 100644 (file)
@@ -40,8 +40,6 @@
 
 using namespace v8::internal;
 
-static v8::Persistent<v8::Context> env;
-
 // --- P r i n t   E x t e n s i o n ---
 
 class PrintExtension : public v8::Extension {
@@ -81,16 +79,6 @@ static PrintExtension kPrintExtension;
 v8::DeclareExtension kPrintExtensionDeclaration(&kPrintExtension);
 
 
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    const char* extensions[] = { "v8/print", "v8/gc" };
-    v8::ExtensionConfiguration config(2, extensions);
-    env = v8::Context::New(&config);
-  }
-  env->Enter();
-}
-
-
 static MaybeObject* GetGlobalProperty(const char* name) {
   Handle<String> internalized_name = FACTORY->InternalizeUtf8String(name);
   return Isolate::Current()->context()->global_object()->GetProperty(
@@ -142,8 +130,8 @@ static double Inc(int x) {
 
 
 TEST(Inc) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   CHECK_EQ(4.0, Inc(3));
 }
 
@@ -163,8 +151,8 @@ static double Add(int x, int y) {
 
 
 TEST(Add) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   CHECK_EQ(5.0, Add(2, 3));
 }
 
@@ -183,8 +171,8 @@ static double Abs(int x) {
 
 
 TEST(Abs) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   CHECK_EQ(3.0, Abs(-3));
 }
 
@@ -204,15 +192,15 @@ static double Sum(int n) {
 
 
 TEST(Sum) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   CHECK_EQ(5050.0, Sum(100));
 }
 
 
 TEST(Print) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM(PRINT_EXTENSION);
+  v8::HandleScope scope(CcTest::isolate());
   const char* source = "for (n = 0; n < 100; ++n) print(n, 1, 2);";
   Handle<JSFunction> fun = Compile(source);
   if (fun.is_null()) return;
@@ -226,8 +214,8 @@ TEST(Print) {
 // The following test method stems from my coding efforts today. It
 // tests all the functionality I have added to the compiler today
 TEST(Stuff) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   const char* source =
     "r = 0;\n"
     "a = new Object;\n"
@@ -258,8 +246,8 @@ TEST(Stuff) {
 
 
 TEST(UncaughtThrow) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   const char* source = "throw 42;";
   Handle<JSFunction> fun = Compile(source);
@@ -280,8 +268,8 @@ TEST(UncaughtThrow) {
 //   |      JS       |
 //   |   C-to-JS     |
 TEST(C2JSFrames) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM(PRINT_EXTENSION | GC_EXTENSION);
+  v8::HandleScope scope(CcTest::isolate());
 
   const char* source = "function foo(a) { gc(), print(a); }";
 
@@ -317,8 +305,8 @@ TEST(C2JSFrames) {
 // Regression 236. Calling InitLineEnds on a Script with undefined
 // source resulted in crash.
 TEST(Regression236) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   Handle<Script> script = FACTORY->NewScript(FACTORY->empty_string());
   script->set_source(HEAP->undefined_value());
@@ -329,8 +317,8 @@ TEST(Regression236) {
 
 
 TEST(GetScriptLineNumber) {
-  LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
   const char function_f[] = "function f() {}";
   const int max_rows = 1000;
@@ -342,11 +330,11 @@ TEST(GetScriptLineNumber) {
   for (int i = 0; i < max_rows; ++i) {
     if (i > 0)
       buffer[i - 1] = '\n';
-    memcpy(&buffer[i], function_f, sizeof(function_f) - 1);
+    OS::MemCopy(&buffer[i], function_f, sizeof(function_f) - 1);
     v8::Handle<v8::String> script_body = v8::String::New(buffer.start());
     v8::Script::Compile(script_body, &origin)->Run();
     v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
-        env->Global()->Get(v8::String::New("f")));
+        CcTest::env()->Global()->Get(v8::String::New("f")));
     CHECK_EQ(i, f->GetScriptLineNumber());
   }
 }
@@ -359,8 +347,8 @@ TEST(OptimizedCodeSharing) {
   // FastNewClosureStub that is baked into the snapshot is incorrect.
   if (!FLAG_cache_optimized_code) return;
   FLAG_allow_natives_syntax = true;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   for (int i = 0; i < 10; i++) {
     LocalContext env;
     env->Global()->Set(v8::String::New("x"), v8::Integer::New(i));
@@ -402,7 +390,7 @@ static void CheckCodeForUnsafeLiteral(Handle<JSFunction> f) {
     Address pc = f->code()->instruction_start();
     int decode_size =
         Min(f->code()->instruction_size(),
-            static_cast<int>(f->code()->stack_check_table_offset()));
+            static_cast<int>(f->code()->back_edge_table_offset()));
     Address end = pc + decode_size;
 
     v8::internal::EmbeddedVector<char, 128> decode_buffer;
@@ -423,16 +411,16 @@ static void CheckCodeForUnsafeLiteral(Handle<JSFunction> f) {
 
 
 TEST(SplitConstantsInFullCompiler) {
-  LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   CompileRun("function f() { a = 12345678 }; f();");
-  CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
+  CheckCodeForUnsafeLiteral(GetJSFunction(CcTest::env()->Global(), "f"));
   CompileRun("function f(x) { a = 12345678 + x}; f(1);");
-  CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
+  CheckCodeForUnsafeLiteral(GetJSFunction(CcTest::env()->Global(), "f"));
   CompileRun("function f(x) { var arguments = 1; x += 12345678}; f(1);");
-  CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
+  CheckCodeForUnsafeLiteral(GetJSFunction(CcTest::env()->Global(), "f"));
   CompileRun("function f(x) { var arguments = 1; x = 12345678}; f(1);");
-  CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
+  CheckCodeForUnsafeLiteral(GetJSFunction(CcTest::env()->Global(), "f"));
 }
 #endif
index 0bf8000..2eece46 100644 (file)
@@ -30,6 +30,7 @@
 #include "v8.h"
 #include "cpu-profiler-inl.h"
 #include "cctest.h"
+#include "utils.h"
 #include "../include/v8-profiler.h"
 
 using i::CodeEntry;
@@ -39,7 +40,9 @@ using i::CpuProfilesCollection;
 using i::ProfileGenerator;
 using i::ProfileNode;
 using i::ProfilerEventsProcessor;
+using i::ScopedVector;
 using i::TokenEnumerator;
+using i::Vector;
 
 
 TEST(StartStop) {
@@ -51,14 +54,6 @@ TEST(StartStop) {
   processor.Join();
 }
 
-static v8::Persistent<v8::Context> env;
-
-static void InitializeVM() {
-  if (env.IsEmpty()) env = v8::Context::New();
-  v8::HandleScope scope(env->GetIsolate());
-  env->Enter();
-}
-
 static inline i::Address ToAddress(int n) {
   return reinterpret_cast<i::Address>(n);
 }
@@ -69,7 +64,6 @@ static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
                                    i::Address frame3 = NULL) {
   i::TickSample* sample = proc->TickSampleEvent();
   sample->pc = frame1;
-  sample->tos = frame1;
   sample->frames_count = 0;
   if (frame2 != NULL) {
     sample->stack[0] = frame2;
@@ -101,7 +95,7 @@ class TestSetup {
 }  // namespace
 
 TEST(CodeEvents) {
-  InitializeVM();
+  CcTest::InitializeVM();
   i::Isolate* isolate = i::Isolate::Current();
   i::Heap* heap = isolate->heap();
   i::Factory* factory = isolate->factory();
@@ -217,7 +211,7 @@ TEST(TickEvents) {
 // http://crbug/51594
 // This test must not crash.
 TEST(CrashIfStoppingLastNonExistentProfile) {
-  InitializeVM();
+  CcTest::InitializeVM();
   TestSetup test_setup;
   CpuProfiler* profiler = i::Isolate::Current()->cpu_profiler();
   profiler->StartProfiling("1");
@@ -244,7 +238,6 @@ TEST(Issue1398) {
 
   i::TickSample* sample = processor.TickSampleEvent();
   sample->pc = ToAddress(0x1200);
-  sample->tos = 0;
   sample->frames_count = i::TickSample::kMaxFramesCount;
   for (int i = 0; i < sample->frames_count; ++i) {
     sample->stack[i] = ToAddress(0x1200);
@@ -268,7 +261,7 @@ TEST(Issue1398) {
 
 
 TEST(DeleteAllCpuProfiles) {
-  InitializeVM();
+  CcTest::InitializeVM();
   TestSetup test_setup;
   CpuProfiler* profiler = i::Isolate::Current()->cpu_profiler();
   CHECK_EQ(0, profiler->GetProfilesCount());
@@ -399,3 +392,154 @@ TEST(DeleteCpuProfileDifferentTokens) {
   CHECK_EQ(0, cpu_profiler->GetProfileCount());
   CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid3));
 }
+
+
+static bool ContainsString(v8::Handle<v8::String> string,
+                           const Vector<v8::Handle<v8::String> >& vector) {
+  for (int i = 0; i < vector.length(); i++) {
+    if (string->Equals(vector[i]))
+      return true;
+  }
+  return false;
+}
+
+
+static void CheckChildrenNames(const v8::CpuProfileNode* node,
+                               const Vector<v8::Handle<v8::String> >& names) {
+  int count = node->GetChildrenCount();
+  for (int i = 0; i < count; i++) {
+    v8::Handle<v8::String> name = node->GetChild(i)->GetFunctionName();
+    CHECK(ContainsString(name, names));
+    // Check that there are no duplicates.
+    for (int j = 0; j < count; j++) {
+      if (j == i) continue;
+      CHECK_NE(name, node->GetChild(j)->GetFunctionName());
+    }
+  }
+}
+
+
+static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node,
+                                           const char* name) {
+  int count = node->GetChildrenCount();
+  v8::Handle<v8::String> nameHandle = v8::String::New(name);
+  for (int i = 0; i < count; i++) {
+    const v8::CpuProfileNode* child = node->GetChild(i);
+    if (nameHandle->Equals(child->GetFunctionName())) return child;
+  }
+  CHECK(false);
+  return NULL;
+}
+
+
+static void CheckSimpleBranch(const v8::CpuProfileNode* node,
+                              const char* names[], int length) {
+  for (int i = 0; i < length; i++) {
+    const char* name = names[i];
+    node = FindChild(node, name);
+    CHECK(node);
+    int expectedChildrenCount = (i == length - 1) ? 0 : 1;
+    CHECK_EQ(expectedChildrenCount, node->GetChildrenCount());
+  }
+}
+
+
+static const char* cpu_profiler_test_source = "function loop(timeout) {\n"
+"  this.mmm = 0;\n"
+"  var start = Date.now();\n"
+"  while (Date.now() - start < timeout) {\n"
+"    var n = 100*1000;\n"
+"    while(n > 1) {\n"
+"      n--;\n"
+"      this.mmm += n * n * n;\n"
+"    }\n"
+"  }\n"
+"}\n"
+"function delay() { try { loop(10); } catch(e) { } }\n"
+"function bar() { delay(); }\n"
+"function baz() { delay(); }\n"
+"function foo() {\n"
+"    try {\n"
+"       delay();\n"
+"       bar();\n"
+"       delay();\n"
+"       baz();\n"
+"    } catch (e) { }\n"
+"}\n"
+"function start(timeout) {\n"
+"  var start = Date.now();\n"
+"  do {\n"
+"    foo();\n"
+"    var duration = Date.now() - start;\n"
+"  } while (duration < timeout);\n"
+"  return duration;\n"
+"}\n";
+
+
+// Check that the profile tree for the script above will look like the
+// following:
+//
+// [Top down]:
+//  1062     0   (root) [-1]
+//  1054     0    start [-1]
+//  1054     1      foo [-1]
+//   265     0        baz [-1]
+//   265     1          delay [-1]
+//   264   264            loop [-1]
+//   525     3        delay [-1]
+//   522   522          loop [-1]
+//   263     0        bar [-1]
+//   263     1          delay [-1]
+//   262   262            loop [-1]
+//     2     2    (program) [-1]
+//     6     6    (garbage collector) [-1]
+TEST(CollectCpuProfile) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+
+  v8::Script::Compile(v8::String::New(cpu_profiler_test_source))->Run();
+  v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
+      env->Global()->Get(v8::String::New("start")));
+
+  v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
+  v8::Local<v8::String> profile_name = v8::String::New("my_profile");
+
+  cpu_profiler->StartCpuProfiling(profile_name);
+  int32_t profiling_interval_ms = 200;
+#if defined(_WIN32) || defined(_WIN64)
+  // 200ms is not enough on Windows. See
+  // https://code.google.com/p/v8/issues/detail?id=2628
+  profiling_interval_ms = 500;
+#endif
+  v8::Handle<v8::Value> args[] = { v8::Integer::New(profiling_interval_ms) };
+  function->Call(env->Global(), ARRAY_SIZE(args), args);
+  const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
+
+  CHECK_NE(NULL, profile);
+  // Dump collected profile to have a better diagnostic in case of failure.
+  reinterpret_cast<i::CpuProfile*>(
+      const_cast<v8::CpuProfile*>(profile))->Print();
+
+  const v8::CpuProfileNode* root = profile->GetTopDownRoot();
+
+  ScopedVector<v8::Handle<v8::String> > names(3);
+  names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
+  names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
+  names[2] = v8::String::New("start");
+  CheckChildrenNames(root, names);
+
+  const v8::CpuProfileNode* startNode = FindChild(root, "start");
+  CHECK_EQ(1, startNode->GetChildrenCount());
+
+  const v8::CpuProfileNode* fooNode = FindChild(startNode, "foo");
+  CHECK_EQ(3, fooNode->GetChildrenCount());
+
+  const char* barBranch[] = { "bar", "delay", "loop" };
+  CheckSimpleBranch(fooNode, barBranch, ARRAY_SIZE(barBranch));
+  const char* bazBranch[] = { "baz", "delay", "loop" };
+  CheckSimpleBranch(fooNode, bazBranch, ARRAY_SIZE(bazBranch));
+  const char* delayBranch[] = { "delay", "loop" };
+  CheckSimpleBranch(fooNode, delayBranch, ARRAY_SIZE(delayBranch));
+
+  cpu_profiler->DeleteAllCpuProfiles();
+}
index ae2ec71..ed8da5c 100644 (file)
@@ -695,7 +695,7 @@ TEST(ExistsInHiddenPrototype) {
 class SimpleContext {
  public:
   SimpleContext() {
-    context_ = Context::New(0);
+    context_ = Context::New();
     context_->Enter();
   }
 
index c7c770f..9f12232 100644 (file)
 using namespace v8::internal;
 
 
-static v8::Persistent<v8::Context> env;
-
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    env = v8::Context::New();
-  }
-}
-
-
 bool DisassembleAndCompare(byte* pc, const char* compare_string) {
   disasm::NameConverter converter;
   disasm::Disassembler disasm(converter);
@@ -73,7 +64,7 @@ bool DisassembleAndCompare(byte* pc, const char* compare_string) {
 // disassembler. Declare the variables and allocate the data structures used
 // in the rest of the macros.
 #define SET_UP()                                          \
-  InitializeVM();                                         \
+  CcTest::InitializeVM();                                 \
   Isolate* isolate = Isolate::Current();                  \
   HandleScope scope(isolate);                             \
   byte *buffer = reinterpret_cast<byte*>(malloc(4*1024)); \
index 8240a95..ca81a5a 100644 (file)
 
 using namespace v8::internal;
 
-static v8::Persistent<v8::Context> env;
-
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    env = v8::Context::New();
-  }
-}
-
 
 #define __ assm.
 
@@ -55,8 +47,8 @@ static void DummyStaticFunction(Object* result) {
 
 
 TEST(DisasmIa320) {
-  InitializeVM();
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  CcTest::InitializeVM();
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
   HandleScope scope(isolate);
   v8::internal::byte buffer[2048];
   Assembler assm(isolate, buffer, sizeof buffer);
index 37aa5eb..0e79a58 100644 (file)
 using namespace v8::internal;
 
 
-static v8::Persistent<v8::Context> env;
-
-static void InitializeVM() {
-  // Disable compilation of natives.
-  FLAG_disable_native_files = true;
-  if (env.IsEmpty()) {
-    env = v8::Context::New();
-  }
-}
-
-
 bool DisassembleAndCompare(byte* pc, const char* compare_string) {
   disasm::NameConverter converter;
   disasm::Disassembler disasm(converter);
@@ -75,7 +64,7 @@ bool DisassembleAndCompare(byte* pc, const char* compare_string) {
 // disassembler. Declare the variables and allocate the data structures used
 // in the rest of the macros.
 #define SET_UP()                                          \
-  InitializeVM();                                         \
+  CcTest::InitializeVM();                                 \
   Isolate* isolate = Isolate::Current();                  \
   HandleScope scope(isolate);                             \
   byte *buffer = reinterpret_cast<byte*>(malloc(4*1024)); \
index fe7aab8..1c7f416 100644 (file)
 
 using namespace v8::internal;
 
-static v8::Persistent<v8::Context> env;
-
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    env = v8::Context::New();
-  }
-}
-
 
 #define __ assm.
 
@@ -55,7 +47,7 @@ static void DummyStaticFunction(Object* result) {
 
 
 TEST(DisasmX64) {
-  InitializeVM();
+  CcTest::InitializeVM();
   v8::HandleScope scope;
   v8::internal::byte buffer[2048];
   Assembler assm(Isolate::Current(), buffer, sizeof buffer);
index 364a4f6..5b8293f 100644 (file)
@@ -47,17 +47,6 @@ using ::v8::internal::SharedFunctionInfo;
 using ::v8::internal::String;
 
 
-static v8::Persistent<v8::Context> env;
-
-
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    env = v8::Context::New();
-  }
-  env->Enter();
-}
-
-
 static void CheckFunctionName(v8::Handle<v8::Script> script,
                               const char* func_pos_src,
                               const char* ref_inferred_name) {
@@ -108,8 +97,8 @@ static v8::Handle<v8::Script> Compile(const char* src) {
 
 
 TEST(GlobalProperty) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "fun1 = function() { return 1; }\n"
@@ -120,8 +109,8 @@ TEST(GlobalProperty) {
 
 
 TEST(GlobalVar) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "var fun1 = function() { return 1; }\n"
@@ -132,8 +121,8 @@ TEST(GlobalVar) {
 
 
 TEST(LocalVar) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function outer() {\n"
@@ -146,8 +135,8 @@ TEST(LocalVar) {
 
 
 TEST(InConstructor) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function MyClass() {\n"
@@ -160,8 +149,8 @@ TEST(InConstructor) {
 
 
 TEST(Factory) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function createMyObj() {\n"
@@ -176,8 +165,8 @@ TEST(Factory) {
 
 
 TEST(Static) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function MyClass() {}\n"
@@ -194,8 +183,8 @@ TEST(Static) {
 
 
 TEST(Prototype) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function MyClass() {}\n"
@@ -212,8 +201,8 @@ TEST(Prototype) {
 
 
 TEST(ObjectLiteral) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function MyClass() {}\n"
@@ -226,8 +215,8 @@ TEST(ObjectLiteral) {
 
 
 TEST(AsParameter) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function f1(a) { return a(); }\n"
@@ -242,8 +231,8 @@ TEST(AsParameter) {
 
 
 TEST(MultipleFuncsConditional) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "fun1 = 0 ?\n"
@@ -255,8 +244,8 @@ TEST(MultipleFuncsConditional) {
 
 
 TEST(MultipleFuncsInLiteral) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function MyClass() {}\n"
@@ -270,8 +259,8 @@ TEST(MultipleFuncsInLiteral) {
 
 // See http://code.google.com/p/v8/issues/detail?id=380
 TEST(Issue380) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function a() {\n"
@@ -283,8 +272,8 @@ TEST(Issue380) {
 
 
 TEST(MultipleAssignments) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "var fun1 = fun2 = function () { return 1; }\n"
@@ -299,8 +288,8 @@ TEST(MultipleAssignments) {
 
 
 TEST(AsConstructorParameter) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function Foo() {}\n"
@@ -313,8 +302,8 @@ TEST(AsConstructorParameter) {
 
 
 TEST(FactoryHashmap) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function createMyObj() {\n"
@@ -329,8 +318,8 @@ TEST(FactoryHashmap) {
 
 
 TEST(FactoryHashmapVariable) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function createMyObj() {\n"
@@ -348,8 +337,8 @@ TEST(FactoryHashmapVariable) {
 
 
 TEST(FactoryHashmapConditional) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "function createMyObj() {\n"
@@ -363,8 +352,8 @@ TEST(FactoryHashmapConditional) {
 
 
 TEST(GlobalAssignmentAndCall) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "var Foo = function() {\n"
@@ -381,8 +370,8 @@ TEST(GlobalAssignmentAndCall) {
 
 
 TEST(AssignmentAndCall) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "(function Enclosing() {\n"
@@ -404,8 +393,8 @@ TEST(AssignmentAndCall) {
 
 
 TEST(MethodAssignmentInAnonymousFunctionCall) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "(function () {\n"
@@ -420,8 +409,8 @@ TEST(MethodAssignmentInAnonymousFunctionCall) {
 
 
 TEST(ReturnAnonymousFunction) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::Script> script = Compile(
       "(function() {\n"
diff --git a/deps/v8/test/cctest/test-global-handles.cc b/deps/v8/test/cctest/test-global-handles.cc
new file mode 100644 (file)
index 0000000..1959a40
--- /dev/null
@@ -0,0 +1,198 @@
+// Copyright 2013 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 "global-handles.h"
+
+#include "cctest.h"
+
+using namespace v8::internal;
+
+static int NumberOfWeakCalls = 0;
+static void WeakPointerCallback(v8::Isolate* isolate,
+                                v8::Persistent<v8::Value> handle,
+                                void* id) {
+  ASSERT(id == reinterpret_cast<void*>(1234));
+  NumberOfWeakCalls++;
+  handle.Dispose(isolate);
+}
+
+static List<Object*> skippable_objects;
+static List<Object*> can_skip_called_objects;
+
+static bool CanSkipCallback(Heap* heap, Object** pointer) {
+  can_skip_called_objects.Add(*pointer);
+  return skippable_objects.Contains(*pointer);
+}
+
+static void ResetCanSkipData() {
+  skippable_objects.Clear();
+  can_skip_called_objects.Clear();
+}
+
+class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
+ public:
+  TestRetainedObjectInfo() : has_been_disposed_(false) {}
+
+  bool has_been_disposed() { return has_been_disposed_; }
+
+  virtual void Dispose() {
+    ASSERT(!has_been_disposed_);
+    has_been_disposed_ = true;
+  }
+
+  virtual bool IsEquivalent(v8::RetainedObjectInfo* other) {
+    return other == this;
+  }
+
+  virtual intptr_t GetHash() { return 0; }
+
+  virtual const char* GetLabel() { return "whatever"; }
+
+ private:
+  bool has_been_disposed_;
+};
+
+class TestObjectVisitor : public ObjectVisitor {
+ public:
+  virtual void VisitPointers(Object** start, Object** end) {
+    for (Object** o = start; o != end; ++o)
+      visited.Add(*o);
+  }
+
+  List<Object*> visited;
+};
+
+TEST(IterateObjectGroupsOldApi) {
+  CcTest::InitializeVM();
+  GlobalHandles* global_handles = Isolate::Current()->global_handles();
+
+  v8::HandleScope handle_scope(CcTest::isolate());
+
+  Handle<Object> g1s1 =
+      global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+  Handle<Object> g1s2 =
+      global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+  global_handles->MakeWeak(g1s1.location(),
+                           reinterpret_cast<void*>(1234),
+                           NULL,
+                           &WeakPointerCallback);
+  global_handles->MakeWeak(g1s2.location(),
+                           reinterpret_cast<void*>(1234),
+                           NULL,
+                           &WeakPointerCallback);
+
+  Handle<Object> g2s1 =
+      global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+  Handle<Object> g2s2 =
+      global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+  global_handles->MakeWeak(g2s1.location(),
+                           reinterpret_cast<void*>(1234),
+                           NULL,
+                           &WeakPointerCallback);
+  global_handles->MakeWeak(g2s2.location(),
+                           reinterpret_cast<void*>(1234),
+                           NULL,
+                           &WeakPointerCallback);
+
+  TestRetainedObjectInfo info1;
+  TestRetainedObjectInfo info2;
+  {
+    Object** g1_objects[] = { g1s1.location(), g1s2.location() };
+    Object** g2_objects[] = { g2s1.location(), g2s2.location() };
+
+    global_handles->AddObjectGroup(g1_objects, 2, &info1);
+    global_handles->AddObjectGroup(g2_objects, 2, &info2);
+  }
+
+  // Iterate the object groups. First skip all.
+  {
+    ResetCanSkipData();
+    skippable_objects.Add(*g1s1.location());
+    skippable_objects.Add(*g1s2.location());
+    skippable_objects.Add(*g2s1.location());
+    skippable_objects.Add(*g2s2.location());
+    TestObjectVisitor visitor;
+    global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
+
+    // CanSkipCallback was called for all objects.
+    ASSERT(can_skip_called_objects.length() == 4);
+    ASSERT(can_skip_called_objects.Contains(*g1s1.location()));
+    ASSERT(can_skip_called_objects.Contains(*g1s2.location()));
+    ASSERT(can_skip_called_objects.Contains(*g2s1.location()));
+    ASSERT(can_skip_called_objects.Contains(*g2s2.location()));
+
+    // Nothing was visited.
+    ASSERT(visitor.visited.length() == 0);
+    ASSERT(!info1.has_been_disposed());
+    ASSERT(!info2.has_been_disposed());
+  }
+
+  // Iterate again, now only skip the second object group.
+  {
+    ResetCanSkipData();
+    // The first grough should still be visited, since only one object is
+    // skipped.
+    skippable_objects.Add(*g1s1.location());
+    skippable_objects.Add(*g2s1.location());
+    skippable_objects.Add(*g2s2.location());
+    TestObjectVisitor visitor;
+    global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
+
+    // CanSkipCallback was called for all objects.
+    ASSERT(can_skip_called_objects.length() == 3 ||
+           can_skip_called_objects.length() == 4);
+    ASSERT(can_skip_called_objects.Contains(*g1s2.location()));
+    ASSERT(can_skip_called_objects.Contains(*g2s1.location()));
+    ASSERT(can_skip_called_objects.Contains(*g2s2.location()));
+
+    // The first group was visited.
+    ASSERT(visitor.visited.length() == 2);
+    ASSERT(visitor.visited.Contains(*g1s1.location()));
+    ASSERT(visitor.visited.Contains(*g1s2.location()));
+    ASSERT(info1.has_been_disposed());
+    ASSERT(!info2.has_been_disposed());
+  }
+
+  // Iterate again, don't skip anything.
+  {
+    ResetCanSkipData();
+    TestObjectVisitor visitor;
+    global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
+
+    // CanSkipCallback was called for all objects.
+    fprintf(stderr, "can skip len %d\n", can_skip_called_objects.length());
+    ASSERT(can_skip_called_objects.length() == 1);
+    ASSERT(can_skip_called_objects.Contains(*g2s1.location()) ||
+           can_skip_called_objects.Contains(*g2s2.location()));
+
+    // The second group was visited.
+    ASSERT(visitor.visited.length() == 2);
+    ASSERT(visitor.visited.Contains(*g2s1.location()));
+    ASSERT(visitor.visited.Contains(*g2s2.location()));
+    ASSERT(info2.has_been_disposed());
+  }
+}
index a536f30..59e7b8f 100644 (file)
@@ -571,7 +571,7 @@ class TestJSONStream : public v8::OutputStream {
     if (abort_countdown_ == 0) return kAbort;
     CHECK_GT(chars_written, 0);
     i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
-    memcpy(chunk.start(), buffer, chars_written);
+    i::OS::MemCopy(chunk.start(), buffer, chars_written);
     return kContinue;
   }
   virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) {
@@ -1663,41 +1663,6 @@ TEST(NoDebugObjectInSnapshot) {
 #endif  // ENABLE_DEBUGGER_SUPPORT
 
 
-TEST(PersistentHandleCount) {
-  LocalContext env;
-  v8::Isolate* isolate = env->GetIsolate();
-  v8::HandleScope scope(isolate);
-
-  // V8 also uses global handles internally, so we can't test for an absolute
-  // number.
-  int global_handle_count = v8::HeapProfiler::GetPersistentHandleCount();
-
-  // Create some persistent handles.
-  v8::Persistent<v8::String> p_AAA =
-      v8::Persistent<v8::String>::New(isolate, v8_str("AAA"));
-  CHECK_EQ(global_handle_count + 1,
-           v8::HeapProfiler::GetPersistentHandleCount());
-  v8::Persistent<v8::String> p_BBB =
-      v8::Persistent<v8::String>::New(isolate, v8_str("BBB"));
-  CHECK_EQ(global_handle_count + 2,
-           v8::HeapProfiler::GetPersistentHandleCount());
-  v8::Persistent<v8::String> p_CCC =
-      v8::Persistent<v8::String>::New(isolate, v8_str("CCC"));
-  CHECK_EQ(global_handle_count + 3,
-           v8::HeapProfiler::GetPersistentHandleCount());
-
-  // Dipose the persistent handles in a different order.
-  p_AAA.Dispose(env->GetIsolate());
-  CHECK_EQ(global_handle_count + 2,
-           v8::HeapProfiler::GetPersistentHandleCount());
-  p_CCC.Dispose(env->GetIsolate());
-  CHECK_EQ(global_handle_count + 1,
-           v8::HeapProfiler::GetPersistentHandleCount());
-  p_BBB.Dispose(env->GetIsolate());
-  CHECK_EQ(global_handle_count, v8::HeapProfiler::GetPersistentHandleCount());
-}
-
-
 TEST(AllStrongGcRootsHaveNames) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
index d0bec93..9aa839b 100644 (file)
 
 using namespace v8::internal;
 
-static v8::Persistent<v8::Context> env;
-
-static void InitializeVM() {
-  if (env.IsEmpty()) env = v8::Context::New();
-  env->Enter();
-}
-
 
 // Go through all incremental marking steps in one swoop.
 static void SimulateIncrementalMarking() {
@@ -78,7 +71,7 @@ static void CheckMap(Map* map, int type, int instance_size) {
 
 
 TEST(HeapMaps) {
-  InitializeVM();
+  CcTest::InitializeVM();
   CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
   CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
   CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
@@ -151,7 +144,7 @@ static void CheckFindCodeObject(Isolate* isolate) {
 
 
 TEST(HeapObjects) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
 
@@ -236,7 +229,7 @@ TEST(HeapObjects) {
 
 
 TEST(Tagging) {
-  InitializeVM();
+  CcTest::InitializeVM();
   int request = 24;
   CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
   CHECK(Smi::FromInt(42)->IsSmi());
@@ -252,7 +245,7 @@ TEST(Tagging) {
 
 
 TEST(GarbageCollection) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   Factory* factory = isolate->factory();
@@ -333,8 +326,8 @@ static void VerifyStringAllocation(Isolate* isolate, const char* string) {
 
 
 TEST(String) {
-  InitializeVM();
-  Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
+  CcTest::InitializeVM();
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
 
   VerifyStringAllocation(isolate, "a");
   VerifyStringAllocation(isolate, "ab");
@@ -345,9 +338,9 @@ TEST(String) {
 
 
 TEST(LocalHandles) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(CcTest::isolate());
   const char* name = "Kasper the spunky";
   Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
   CHECK_EQ(StrLength(name), string->length());
@@ -355,7 +348,7 @@ TEST(LocalHandles) {
 
 
 TEST(GlobalHandles) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   Factory* factory = isolate->factory();
@@ -407,7 +400,7 @@ static void TestWeakGlobalHandleCallback(v8::Isolate* isolate,
 
 
 TEST(WeakGlobalHandlesScavenge) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   Factory* factory = isolate->factory();
@@ -449,7 +442,7 @@ TEST(WeakGlobalHandlesScavenge) {
 
 
 TEST(WeakGlobalHandlesMark) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   Factory* factory = isolate->factory();
@@ -495,7 +488,7 @@ TEST(WeakGlobalHandlesMark) {
 
 
 TEST(DeleteWeakGlobalHandle) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   Factory* factory = isolate->factory();
@@ -610,7 +603,7 @@ static void CheckInternalizedStrings(const char** strings) {
 
 
 TEST(StringTable) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
   CheckInternalizedStrings(not_so_random_string_table);
   CheckInternalizedStrings(not_so_random_string_table);
@@ -618,9 +611,9 @@ TEST(StringTable) {
 
 
 TEST(FunctionAllocation) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope sc(env->GetIsolate());
+  v8::HandleScope sc(CcTest::isolate());
   Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
   Handle<JSFunction> function =
       FACTORY->NewFunction(name, FACTORY->undefined_value());
@@ -641,9 +634,9 @@ TEST(FunctionAllocation) {
 
 
 TEST(ObjectProperties) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope sc(env->GetIsolate());
+  v8::HandleScope sc(CcTest::isolate());
   String* object_string = String::cast(HEAP->Object_string());
   Object* raw_object = Isolate::Current()->context()->global_object()->
       GetProperty(object_string)->ToObjectChecked();
@@ -714,9 +707,9 @@ TEST(ObjectProperties) {
 
 
 TEST(JSObjectMaps) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope sc(env->GetIsolate());
+  v8::HandleScope sc(CcTest::isolate());
   Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
   Handle<JSFunction> function =
       FACTORY->NewFunction(name, FACTORY->undefined_value());
@@ -738,9 +731,9 @@ TEST(JSObjectMaps) {
 
 
 TEST(JSArray) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope sc(env->GetIsolate());
+  v8::HandleScope sc(CcTest::isolate());
   Handle<String> name = FACTORY->InternalizeUtf8String("Array");
   Object* raw_object = Isolate::Current()->context()->global_object()->
       GetProperty(*name)->ToObjectChecked();
@@ -785,9 +778,9 @@ TEST(JSArray) {
 
 
 TEST(JSObjectCopy) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope sc(env->GetIsolate());
+  v8::HandleScope sc(CcTest::isolate());
   String* object_string = String::cast(HEAP->Object_string());
   Object* raw_object = Isolate::Current()->context()->global_object()->
       GetProperty(object_string)->ToObjectChecked();
@@ -833,11 +826,11 @@ TEST(JSObjectCopy) {
 
 
 TEST(StringAllocation) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
   const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
   for (int length = 0; length < 100; length++) {
-    v8::HandleScope scope(env->GetIsolate());
+    v8::HandleScope scope(CcTest::isolate());
     char* non_ascii = NewArray<char>(3 * length + 1);
     char* ascii = NewArray<char>(length + 1);
     non_ascii[3 * length] = 0;
@@ -885,8 +878,8 @@ static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
 
 
 TEST(Iteration) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   // Array of objects to scan haep for.
   const int objs_count = 6;
@@ -923,13 +916,13 @@ TEST(Iteration) {
 
 
 TEST(EmptyHandleEscapeFrom) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(CcTest::isolate());
   Handle<JSObject> runaway;
 
   {
-      v8::HandleScope nested(env->GetIsolate());
+      v8::HandleScope nested(CcTest::isolate());
       Handle<JSObject> empty;
       runaway = empty.EscapeFrom(&nested);
   }
@@ -945,12 +938,12 @@ static int LenFromSize(int size) {
 
 TEST(Regression39128) {
   // Test case for crbug.com/39128.
-  InitializeVM();
+  CcTest::InitializeVM();
 
   // Increase the chance of 'bump-the-pointer' allocation in old space.
   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
 
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(CcTest::isolate());
 
   // The plan: create JSObject which references objects in new space.
   // Then clone this object (forcing it to go into old space) and check
@@ -1022,8 +1015,8 @@ TEST(TestCodeFlushing) {
   // 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(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   const char* source = "function foo() {"
                        "  var x = 42;"
                        "  var y = 42;"
@@ -1033,7 +1026,7 @@ TEST(TestCodeFlushing) {
   Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
 
   // This compile will add the code to the compilation cache.
-  { v8::HandleScope scope(env->GetIsolate());
+  { v8::HandleScope scope(CcTest::isolate());
     CompileRun(source);
   }
 
@@ -1069,8 +1062,8 @@ 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(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   const char* source = "function foo() {"
                        "  var x = 42;"
                        "  var y = 42;"
@@ -1080,7 +1073,7 @@ TEST(TestCodeFlushingIncremental) {
   Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
 
   // This compile will add the code to the compilation cache.
-  { v8::HandleScope scope(env->GetIsolate());
+  { v8::HandleScope scope(CcTest::isolate());
     CompileRun(source);
   }
 
@@ -1106,7 +1099,7 @@ TEST(TestCodeFlushingIncremental) {
   CHECK(!function->is_compiled() || function->IsOptimized());
 
   // This compile will compile the function again.
-  { v8::HandleScope scope(env->GetIsolate());
+  { v8::HandleScope scope(CcTest::isolate());
     CompileRun("foo();");
   }
 
@@ -1120,7 +1113,7 @@ TEST(TestCodeFlushingIncremental) {
 
   // Force optimization while incremental marking is active and while
   // the function is enqueued as a candidate.
-  { v8::HandleScope scope(env->GetIsolate());
+  { v8::HandleScope scope(CcTest::isolate());
     CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
   }
 
@@ -1135,8 +1128,8 @@ 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(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   const char* source = "var foo = function() {"
                        "  var x = 42;"
                        "  var y = 42;"
@@ -1154,7 +1147,7 @@ TEST(TestCodeFlushingIncrementalScavenge) {
   HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
 
   // This compile will add the code to the compilation cache.
-  { v8::HandleScope scope(env->GetIsolate());
+  { v8::HandleScope scope(CcTest::isolate());
     CompileRun(source);
   }
 
@@ -1171,7 +1164,7 @@ TEST(TestCodeFlushingIncrementalScavenge) {
   CHECK(function2->shared()->is_compiled());
 
   // Clear references to functions so that one of them can die.
-  { v8::HandleScope scope(env->GetIsolate());
+  { v8::HandleScope scope(CcTest::isolate());
     CompileRun("foo = 0; bar = 0;");
   }
 
@@ -1201,10 +1194,10 @@ 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();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(CcTest::isolate());
   const char* source = "function foo() {"
                        "  var x = 42;"
                        "  var y = 42;"
@@ -1214,7 +1207,7 @@ TEST(TestCodeFlushingIncrementalAbort) {
   Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
 
   // This compile will add the code to the compilation cache.
-  { v8::HandleScope scope(env->GetIsolate());
+  { v8::HandleScope scope(CcTest::isolate());
     CompileRun(source);
   }
 
@@ -1251,7 +1244,7 @@ TEST(TestCodeFlushingIncrementalAbort) {
 #endif  // ENABLE_DEBUGGER_SUPPORT
 
   // Force optimization now that code flushing is disabled.
-  { v8::HandleScope scope(env->GetIsolate());
+  { v8::HandleScope scope(CcTest::isolate());
     CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
   }
 
@@ -1523,7 +1516,7 @@ TEST(TestSizeOfObjects) {
 
 
 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
-  InitializeVM();
+  CcTest::InitializeVM();
   HEAP->EnsureHeapIsIterable();
   intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
   HeapIterator iterator(HEAP);
@@ -1574,7 +1567,7 @@ static void FillUpNewSpace(NewSpace* new_space) {
 
 
 TEST(GrowAndShrinkNewSpace) {
-  InitializeVM();
+  CcTest::InitializeVM();
   NewSpace* new_space = HEAP->new_space();
 
   if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
@@ -1624,7 +1617,7 @@ TEST(GrowAndShrinkNewSpace) {
 
 
 TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
   if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
       HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
@@ -1634,7 +1627,7 @@ TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
     return;
   }
 
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(CcTest::isolate());
   NewSpace* new_space = HEAP->new_space();
   intptr_t old_capacity, new_capacity;
   old_capacity = new_space->Capacity();
@@ -1816,7 +1809,7 @@ TEST(InstanceOfStubWriteBarrier) {
   i::FLAG_verify_heap = true;
 #endif
 
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!i::V8::UseCrankshaft()) return;
   if (i::FLAG_force_marking_deque_overflows) return;
   v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
@@ -1867,8 +1860,8 @@ TEST(InstanceOfStubWriteBarrier) {
 
 
 TEST(PrototypeTransitionClearing) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   CompileRun(
       "var base = {};"
@@ -1930,7 +1923,7 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
   i::FLAG_verify_heap = true;
 #endif
 
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!i::V8::UseCrankshaft()) return;
   v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
 
@@ -1986,12 +1979,12 @@ TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
   i::FLAG_verify_heap = true;
 #endif
 
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!i::V8::UseCrankshaft()) return;
-  v8::HandleScope outer_scope(env->GetIsolate());
+  v8::HandleScope outer_scope(CcTest::isolate());
 
   {
-    v8::HandleScope scope(env->GetIsolate());
+    v8::HandleScope scope(CcTest::isolate());
     CompileRun(
         "function f () {"
         "  var s = 0;"
@@ -2025,10 +2018,10 @@ TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
 // Test that HAllocateObject will always return an object in new-space.
 TEST(OptimizedAllocationAlwaysInNewSpace) {
   i::FLAG_allow_natives_syntax = true;
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(CcTest::isolate());
 
   SimulateFullSpace(HEAP->new_space());
   AlwaysAllocateScope always_allocate;
@@ -2056,10 +2049,10 @@ TEST(OptimizedAllocationAlwaysInNewSpace) {
 TEST(OptimizedPretenuringArrayLiterals) {
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_pretenure_literals = true;
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(CcTest::isolate());
 
   AlwaysAllocateScope always_allocate;
   v8::Local<v8::Value> res = CompileRun(
@@ -2079,13 +2072,37 @@ TEST(OptimizedPretenuringArrayLiterals) {
 }
 
 
+TEST(OptimizedPretenuringSimpleArrayLiterals) {
+  i::FLAG_allow_natives_syntax = true;
+  i::FLAG_pretenure_literals = false;
+  CcTest::InitializeVM();
+  if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
+  if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
+  v8::HandleScope scope(CcTest::isolate());
+
+  AlwaysAllocateScope always_allocate;
+  v8::Local<v8::Value> res = CompileRun(
+      "function f() {"
+      "  return [1, 2, 3];"
+      "};"
+      "f(); f(); f();"
+      "%OptimizeFunctionOnNextCall(f);"
+      "f();");
+
+  Handle<JSObject> o =
+      v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
+
+  CHECK(HEAP->InNewSpace(*o));
+}
+
+
 // Test regular array literals allocation.
 TEST(OptimizedAllocationArrayLiterals) {
   i::FLAG_allow_natives_syntax = true;
-  InitializeVM();
+  CcTest::InitializeVM();
   if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(CcTest::isolate());
 
   AlwaysAllocateScope always_allocate;
   v8::Local<v8::Value> res = CompileRun(
@@ -2117,8 +2134,8 @@ static int CountMapTransitions(Map* map) {
 TEST(Regress1465) {
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_trace_incremental_marking = true;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   static const int transitions_count = 256;
 
   {
@@ -2155,8 +2172,8 @@ TEST(Regress1465) {
 TEST(Regress2143a) {
   i::FLAG_collect_maps = true;
   i::FLAG_incremental_marking = true;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   // Prepare a map transition from the root object together with a yet
   // untransitioned root object.
@@ -2196,8 +2213,8 @@ TEST(Regress2143b) {
   i::FLAG_collect_maps = true;
   i::FLAG_incremental_marking = true;
   i::FLAG_allow_natives_syntax = true;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   // Prepare a map transition from the root object together with a yet
   // untransitioned root object.
@@ -2241,8 +2258,8 @@ TEST(ReleaseOverReservedPages) {
   // The optimizer can allocate stuff, messing up the test.
   i::FLAG_crankshaft = false;
   i::FLAG_always_opt = false;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   static const int number_of_test_pages = 20;
 
   // Prepare many pages with low live-bytes count.
@@ -2280,13 +2297,13 @@ TEST(ReleaseOverReservedPages) {
 
 
 TEST(Regress2237) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   Handle<String> slice(HEAP->empty_string());
 
   {
     // Generate a parent that lives in new-space.
-    v8::HandleScope inner_scope(env->GetIsolate());
+    v8::HandleScope inner_scope(CcTest::isolate());
     const char* c = "This text is long enough to trigger sliced strings.";
     Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
     CHECK(s->IsSeqOneByteString());
@@ -2310,8 +2327,8 @@ TEST(Regress2237) {
 
 #ifdef OBJECT_PRINT
 TEST(PrintSharedFunctionInfo) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   const char* source = "f = function() { return 987654321; }\n"
                        "g = function() { return 123456789; }\n";
   CompileRun(source);
@@ -2327,8 +2344,8 @@ TEST(PrintSharedFunctionInfo) {
 
 
 TEST(Regress2211) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   v8::Handle<v8::String> value = v8_str("val string");
   Smi* hash = Smi::FromInt(321);
@@ -2365,8 +2382,8 @@ TEST(Regress2211) {
 
 TEST(IncrementalMarkingClearsTypeFeedbackCells) {
   if (i::FLAG_always_opt) return;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   v8::Local<v8::Value> fun1, fun2;
 
   {
@@ -2424,8 +2441,8 @@ static Code* FindFirstIC(Code* code, Code::Kind kind) {
 
 TEST(IncrementalMarkingPreservesMonomorhpicIC) {
   if (i::FLAG_always_opt) return;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   // Prepare function f that contains a monomorphic IC for object
   // originating from the same native context.
@@ -2449,8 +2466,8 @@ TEST(IncrementalMarkingPreservesMonomorhpicIC) {
 
 TEST(IncrementalMarkingClearsMonomorhpicIC) {
   if (i::FLAG_always_opt) return;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   v8::Local<v8::Value> obj1;
 
   {
@@ -2483,8 +2500,8 @@ TEST(IncrementalMarkingClearsMonomorhpicIC) {
 
 TEST(IncrementalMarkingClearsPolymorhpicIC) {
   if (i::FLAG_always_opt) return;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   v8::Local<v8::Value> obj1, obj2;
 
   {
@@ -2549,11 +2566,11 @@ void ReleaseStackTraceDataTest(const char* source) {
   // 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(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   SourceResource* resource = new SourceResource(i::StrDup(source));
   {
-    v8::HandleScope scope(env->GetIsolate());
+    v8::HandleScope scope(CcTest::isolate());
     v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
     v8::Script::Compile(source_string)->Run();
     CHECK(!resource->IsDisposed());
@@ -2585,7 +2602,7 @@ TEST(ReleaseStackTraceData) {
 
 
 TEST(Regression144230) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   HandleScope scope(isolate);
@@ -2648,7 +2665,7 @@ TEST(Regression144230) {
 TEST(Regress159140) {
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_flush_code_incrementally = true;
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   HandleScope scope(isolate);
@@ -2710,7 +2727,7 @@ TEST(Regress159140) {
 TEST(Regress165495) {
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_flush_code_incrementally = true;
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   HandleScope scope(isolate);
@@ -2758,7 +2775,7 @@ TEST(Regress169209) {
   i::FLAG_stress_compaction = false;
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_flush_code_incrementally = true;
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   HandleScope scope(isolate);
@@ -2844,8 +2861,8 @@ static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
 TEST(Regress169928) {
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_crankshaft = false;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   // Some flags turn Scavenge collections into Mark-sweep collections
   // and hence are incompatible with this test case.
@@ -2917,7 +2934,7 @@ TEST(Regress168801) {
   i::FLAG_cache_optimized_code = false;
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_flush_code_incrementally = true;
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   HandleScope scope(isolate);
@@ -2973,7 +2990,7 @@ TEST(Regress173458) {
   i::FLAG_cache_optimized_code = false;
   i::FLAG_allow_natives_syntax = true;
   i::FLAG_flush_code_incrementally = true;
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   HandleScope scope(isolate);
@@ -3030,7 +3047,7 @@ class DummyVisitor : public ObjectVisitor {
 
 
 TEST(DeferredHandles) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   v8::HandleScope scope;
index c27d5b8..5bfc1d3 100644 (file)
@@ -51,13 +51,9 @@ using v8::internal::Address;
 using v8::internal::Handle;
 using v8::internal::Isolate;
 using v8::internal::JSFunction;
-using v8::internal::StackTracer;
 using v8::internal::TickSample;
 
 
-static v8::Persistent<v8::Context> env;
-
-
 static struct {
   TickSample* sample;
 } trace_env = { NULL };
@@ -73,7 +69,7 @@ static void DoTrace(Address fp) {
   // sp is only used to define stack high bound
   trace_env.sample->sp =
       reinterpret_cast<Address>(trace_env.sample) - 10240;
-  StackTracer::Trace(Isolate::Current(), trace_env.sample);
+  trace_env.sample->Trace(Isolate::Current());
 }
 
 
@@ -185,23 +181,13 @@ static TraceExtension kTraceExtension;
 v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
 
 
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    const char* extensions[] = { "v8/trace" };
-    v8::ExtensionConfiguration config(1, extensions);
-    env = v8::Context::New(&config);
-  }
-  env->Enter();
-}
-
-
 static bool IsAddressWithinFuncCode(JSFunction* function, Address addr) {
   i::Code* code = function->code();
   return code->contains(addr);
 }
 
 static bool IsAddressWithinFuncCode(const char* func_name, Address addr) {
-  v8::Local<v8::Value> func = env->Global()->Get(v8_str(func_name));
+  v8::Local<v8::Value> func = CcTest::env()->Global()->Get(v8_str(func_name));
   CHECK(func->IsFunction());
   JSFunction* js_func = JSFunction::cast(*v8::Utils::OpenHandle(*func));
   return IsAddressWithinFuncCode(js_func, addr);
@@ -243,7 +229,7 @@ void CreateFramePointerGrabberConstructor(const char* constructor_name) {
         v8::FunctionTemplate::New(construct_call);
     constructor_template->SetClassName(v8_str("FPGrabber"));
     Local<Function> fun = constructor_template->GetFunction();
-    env->Global()->Set(v8_str(constructor_name), fun);
+    CcTest::env()->Global()->Set(v8_str(constructor_name), fun);
 }
 
 
@@ -271,7 +257,7 @@ static void CreateTraceCallerFunction(const char* func_name,
 
 // This test verifies that stack tracing works when called during
 // execution of a native function called from JS code. In this case,
-// StackTracer uses Isolate::c_entry_fp as a starting point for stack
+// TickSample::Trace uses Isolate::c_entry_fp as a starting point for stack
 // walking.
 TEST(CFromJSStackTrace) {
   // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test.
@@ -280,8 +266,8 @@ TEST(CFromJSStackTrace) {
   TickSample sample;
   InitTraceEnv(&sample);
 
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM(TRACE_EXTENSION);
+  v8::HandleScope scope(CcTest::isolate());
   // Create global function JSFuncDoTrace which calls
   // extension function trace() with the current frame pointer value.
   CreateTraceCallerFunction("JSFuncDoTrace", "trace");
@@ -298,9 +284,9 @@ TEST(CFromJSStackTrace) {
   //     JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi]
   //       trace(EBP) [native (extension)]
   //         DoTrace(EBP) [native]
-  //           StackTracer::Trace
+  //           TickSample::Trace
 
-  CHECK(sample.has_external_callback);
+  CHECK(sample.external_callback);
   CHECK_EQ(FUNCTION_ADDR(TraceExtension::Trace), sample.external_callback);
 
   // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
@@ -313,9 +299,9 @@ TEST(CFromJSStackTrace) {
 
 
 // This test verifies that stack tracing works when called during
-// execution of JS code. However, as calling StackTracer requires
+// execution of JS code. However, as calling TickSample::Trace requires
 // entering native code, we can only emulate pure JS by erasing
-// Isolate::c_entry_fp value. In this case, StackTracer uses passed frame
+// Isolate::c_entry_fp value. In this case, TickSample::Trace uses passed frame
 // pointer value as a starting point for stack walking.
 TEST(PureJSStackTrace) {
   // This test does not pass with inlining enabled since inlined functions
@@ -325,8 +311,8 @@ TEST(PureJSStackTrace) {
   TickSample sample;
   InitTraceEnv(&sample);
 
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM(TRACE_EXTENSION);
+  v8::HandleScope scope(CcTest::isolate());
   // Create global function JSFuncDoTrace which calls
   // extension function js_trace() with the current frame pointer value.
   CreateTraceCallerFunction("JSFuncDoTrace", "js_trace");
@@ -347,10 +333,10 @@ TEST(PureJSStackTrace) {
   //       JSFuncDoTrace() [JS]
   //         js_trace(EBP) [native (extension)]
   //           DoTraceHideCEntryFPAddress(EBP) [native]
-  //             StackTracer::Trace
+  //             TickSample::Trace
   //
 
-  CHECK(sample.has_external_callback);
+  CHECK(sample.external_callback);
   CHECK_EQ(FUNCTION_ADDR(TraceExtension::JSTrace), sample.external_callback);
 
   // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
@@ -387,20 +373,20 @@ static int CFunc(int depth) {
 
 
 // This test verifies that stack tracing doesn't crash when called on
-// pure native code. StackTracer only unrolls JS code, so we can't
+// pure native code. TickSample::Trace only unrolls JS code, so we can't
 // get any meaningful info here.
 TEST(PureCStackTrace) {
   TickSample sample;
   InitTraceEnv(&sample);
-  InitializeVM();
+  CcTest::InitializeVM(TRACE_EXTENSION);
   // Check that sampler doesn't crash
   CHECK_EQ(10, CFunc(10));
 }
 
 
 TEST(JsEntrySp) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM(TRACE_EXTENSION);
+  v8::HandleScope scope(CcTest::isolate());
   CHECK_EQ(0, GetJsEntrySp());
   CompileRun("a = 1; b = a + 1;");
   CHECK_EQ(0, GetJsEntrySp());
index 53ccd3e..24e5db9 100644 (file)
@@ -62,13 +62,14 @@ class ScopedLoggerInitializer {
         // Need to run this prior to creating the scope.
         trick_to_run_init_flags_(init_flags_(prof_lazy)),
         scope_(v8::Isolate::GetCurrent()),
-        env_(v8::Context::New()) {
+        env_(v8::Context::New()),
+        logger_(i::Isolate::Current()->logger()) {
     env_->Enter();
   }
 
   ~ScopedLoggerInitializer() {
     env_->Exit();
-    LOGGER->TearDown();
+    logger_->TearDown();
     if (temp_file_ != NULL) fclose(temp_file_);
     i::FLAG_prof_lazy = saved_prof_lazy_;
     i::FLAG_prof = saved_prof_;
@@ -78,8 +79,10 @@ class ScopedLoggerInitializer {
 
   v8::Handle<v8::Context>& env() { return env_; }
 
+  Logger* logger() { return logger_; }
+
   FILE* StopLoggingGetTempFile() {
-    temp_file_ = LOGGER->TearDown();
+    temp_file_ = logger_->TearDown();
     CHECK_NE(NULL, temp_file_);
     fflush(temp_file_);
     rewind(temp_file_);
@@ -104,6 +107,7 @@ class ScopedLoggerInitializer {
   const bool trick_to_run_init_flags_;
   v8::HandleScope scope_;
   v8::Handle<v8::Context> env_;
+  Logger* logger_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedLoggerInitializer);
 };
@@ -123,12 +127,13 @@ static const char* StrNStr(const char* s1, const char* s2, int n) {
 
 TEST(ProfLazyMode) {
   ScopedLoggerInitializer initialize_logger(true);
+  Logger* logger = initialize_logger.logger();
 
   if (!i::V8::UseCrankshaft()) return;
 
-  LOGGER->StringEvent("test-start", "");
+  logger->StringEvent("test-start", "");
   CompileRun("var a = (function(x) { return x + 1; })(10);");
-  LOGGER->StringEvent("test-profiler-start", "");
+  logger->StringEvent("test-profiler-start", "");
   v8::V8::ResumeProfiler();
   CompileRun(
       "var b = (function(x) { return x + 2; })(10);\n"
@@ -136,10 +141,10 @@ TEST(ProfLazyMode) {
       "var d = (function(x) { return x + 4; })(10);\n"
       "var e = (function(x) { return x + 5; })(10);");
   v8::V8::PauseProfiler();
-  LOGGER->StringEvent("test-profiler-stop", "");
+  logger->StringEvent("test-profiler-stop", "");
   CompileRun("var f = (function(x) { return x + 6; })(10);");
   // Check that profiling can be resumed again.
-  LOGGER->StringEvent("test-profiler-start-2", "");
+  logger->StringEvent("test-profiler-start-2", "");
   v8::V8::ResumeProfiler();
   CompileRun(
       "var g = (function(x) { return x + 7; })(10);\n"
@@ -147,8 +152,8 @@ TEST(ProfLazyMode) {
       "var i = (function(x) { return x + 9; })(10);\n"
       "var j = (function(x) { return x + 10; })(10);");
   v8::V8::PauseProfiler();
-  LOGGER->StringEvent("test-profiler-stop-2", "");
-  LOGGER->StringEvent("test-stop", "");
+  logger->StringEvent("test-profiler-stop-2", "");
+  logger->StringEvent("test-stop", "");
 
   bool exists = false;
   i::Vector<const char> log(
@@ -383,7 +388,7 @@ TEST(Issue23768) {
   i_source->set_resource(NULL);
 
   // Must not crash.
-  LOGGER->LogCompiledFunctions();
+  i::Isolate::Current()->logger()->LogCompiledFunctions();
 }
 
 
@@ -393,6 +398,7 @@ static v8::Handle<v8::Value> ObjMethod1(const v8::Arguments& args) {
 
 TEST(LogCallbacks) {
   ScopedLoggerInitializer initialize_logger(false);
+  Logger* logger = initialize_logger.logger();
 
   v8::Persistent<v8::FunctionTemplate> obj =
       v8::Persistent<v8::FunctionTemplate>::New(v8::Isolate::GetCurrent(),
@@ -409,7 +415,7 @@ TEST(LogCallbacks) {
   initialize_logger.env()->Global()->Set(v8_str("Obj"), obj->GetFunction());
   CompileRun("Obj.prototype.method1.toString();");
 
-  LOGGER->LogCompiledFunctions();
+  logger->LogCompiledFunctions();
 
   bool exists = false;
   i::Vector<const char> log(
@@ -444,6 +450,7 @@ static v8::Handle<v8::Value> Prop2Getter(v8::Local<v8::String> property,
 
 TEST(LogAccessorCallbacks) {
   ScopedLoggerInitializer initialize_logger(false);
+  Logger* logger = initialize_logger.logger();
 
   v8::Persistent<v8::FunctionTemplate> obj =
       v8::Persistent<v8::FunctionTemplate>::New(v8::Isolate::GetCurrent(),
@@ -453,7 +460,7 @@ TEST(LogAccessorCallbacks) {
   inst->SetAccessor(v8_str("prop1"), Prop1Getter, Prop1Setter);
   inst->SetAccessor(v8_str("prop2"), Prop2Getter);
 
-  LOGGER->LogAccessorCallbacks();
+  logger->LogAccessorCallbacks();
 
   bool exists = false;
   i::Vector<const char> log(
@@ -487,12 +494,13 @@ TEST(LogAccessorCallbacks) {
 
 TEST(IsLoggingPreserved) {
   ScopedLoggerInitializer initialize_logger(false);
+  Logger* logger = initialize_logger.logger();
 
-  CHECK(LOGGER->is_logging());
-  LOGGER->ResumeProfiler();
-  CHECK(LOGGER->is_logging());
-  LOGGER->PauseProfiler();
-  CHECK(LOGGER->is_logging());
+  CHECK(logger->is_logging());
+  logger->ResumeProfiler();
+  CHECK(logger->is_logging());
+  logger->PauseProfiler();
+  CHECK(logger->is_logging());
 }
 
 
@@ -513,6 +521,7 @@ TEST(EquivalenceOfLoggingAndTraversal) {
 
   // Start with profiling to capture all code events from the beginning.
   ScopedLoggerInitializer initialize_logger(false);
+  Logger* logger = initialize_logger.logger();
 
   // Compile and run a function that creates other functions.
   CompileRun(
@@ -522,11 +531,11 @@ TEST(EquivalenceOfLoggingAndTraversal) {
       "})(this);");
   v8::V8::PauseProfiler();
   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
-  LOGGER->StringEvent("test-logging-done", "");
+  logger->StringEvent("test-logging-done", "");
 
   // Iterate heap to find compiled functions, will write to log.
-  LOGGER->LogCompiledFunctions();
-  LOGGER->StringEvent("test-traversal-done", "");
+  logger->LogCompiledFunctions();
+  logger->StringEvent("test-traversal-done", "");
 
   bool exists = false;
   i::Vector<const char> log(
index 4640599..db8c3e4 100644 (file)
 
 using namespace v8::internal;
 
-static v8::Persistent<v8::Context> env;
-
-static void InitializeVM() {
-  if (env.IsEmpty()) env = v8::Context::New();
-  env->Enter();
-}
-
 
 TEST(MarkingDeque) {
-  InitializeVM();
+  CcTest::InitializeVM();
   int mem_size = 20 * kPointerSize;
   byte* mem = NewArray<byte>(20*kPointerSize);
   Address low = reinterpret_cast<Address>(mem);
@@ -89,9 +82,9 @@ TEST(Promotion) {
   FLAG_always_compact = true;
   HEAP->ConfigureHeap(2*256*KB, 8*MB, 8*MB);
 
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope sc(env->GetIsolate());
+  v8::HandleScope sc(CcTest::isolate());
 
   // Allocate a fixed array in the new space.
   int array_size =
@@ -117,9 +110,9 @@ TEST(NoPromotion) {
 
   // Test the situation that some objects in new space are promoted to
   // the old space
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope sc(env->GetIsolate());
+  v8::HandleScope sc(CcTest::isolate());
 
   // Do a mark compact GC to shrink the heap.
   HEAP->CollectGarbage(OLD_POINTER_SPACE);
@@ -155,9 +148,9 @@ TEST(NoPromotion) {
 
 
 TEST(MarkCompactCollector) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
-  v8::HandleScope sc(env->GetIsolate());
+  v8::HandleScope sc(CcTest::isolate());
   // call mark-compact when heap is empty
   HEAP->CollectGarbage(OLD_POINTER_SPACE);
 
@@ -248,7 +241,7 @@ static Handle<Map> CreateMap() {
 
 TEST(MapCompact) {
   FLAG_max_map_space_pages = 16;
-  InitializeVM();
+  CcTest::InitializeVM();
 
   {
     v8::HandleScope sc;
@@ -287,7 +280,7 @@ static void GCEpilogueCallbackFunc() {
 
 
 TEST(GCCallback) {
-  InitializeVM();
+  CcTest::InitializeVM();
 
   HEAP->SetGlobalGCPrologueCallback(&GCPrologueCallbackFunc);
   HEAP->SetGlobalGCEpilogueCallback(&GCEpilogueCallbackFunc);
@@ -315,11 +308,11 @@ static void WeakPointerCallback(v8::Isolate* isolate,
 
 TEST(ObjectGroups) {
   FLAG_incremental_marking = false;
-  InitializeVM();
+  CcTest::InitializeVM();
   GlobalHandles* global_handles = Isolate::Current()->global_handles();
 
   NumberOfWeakCalls = 0;
-  v8::HandleScope handle_scope(env->GetIsolate());
+  v8::HandleScope handle_scope(CcTest::isolate());
 
   Handle<Object> g1s1 =
       global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
@@ -452,10 +445,10 @@ class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
 
 
 TEST(EmptyObjectGroups) {
-  InitializeVM();
+  CcTest::InitializeVM();
   GlobalHandles* global_handles = Isolate::Current()->global_handles();
 
-  v8::HandleScope handle_scope(env->GetIsolate());
+  v8::HandleScope handle_scope(CcTest::isolate());
 
   Handle<Object> object =
       global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
@@ -552,7 +545,7 @@ TEST(BootUpMemoryUse) {
   // Only Linux has the proc filesystem and only if it is mapped.  If it's not
   // there we just skip the test.
   if (initial_memory >= 0) {
-    InitializeVM();
+    CcTest::InitializeVM();
     intptr_t delta = MemoryInUse() - initial_memory;
     printf("delta: %" V8_PTR_PREFIX "d kB\n", delta / 1024);
     if (sizeof(initial_memory) == 8) {  // 64-bit.
index c8956c9..c7331bd 100644 (file)
@@ -83,7 +83,7 @@ TEST(ScanKeywords) {
     // Adding characters will make keyword matching fail.
     static const char chars_to_append[] = { 'z', '0', '_' };
     for (int j = 0; j < static_cast<int>(ARRAY_SIZE(chars_to_append)); ++j) {
-      memmove(buffer, keyword, length);
+      i::OS::MemMove(buffer, keyword, length);
       buffer[length] = chars_to_append[j];
       i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
       i::Scanner scanner(&unicode_cache);
@@ -93,7 +93,7 @@ TEST(ScanKeywords) {
     }
     // Replacing characters will make keyword matching fail.
     {
-      memmove(buffer, keyword, length);
+      i::OS::MemMove(buffer, keyword, length);
       buffer[length - 1] = '_';
       i::Utf8ToUtf16CharacterStream stream(buffer, length);
       i::Scanner scanner(&unicode_cache);
@@ -262,12 +262,11 @@ TEST(StandAlonePreParser) {
     i::Scanner scanner(i::Isolate::Current()->unicode_cache());
     scanner.Initialize(&stream);
 
-    int flags = i::kAllowLazy | i::kAllowNativesSyntax;
+    v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
+    preparser.set_allow_lazy(true);
+    preparser.set_allow_natives_syntax(true);
     v8::preparser::PreParser::PreParseResult result =
-        v8::preparser::PreParser::PreParseProgram(&scanner,
-                                                  &log,
-                                                  flags,
-                                                  stack_limit);
+        preparser.PreParseProgram();
     CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
     i::ScriptDataImpl data(log.ExtractData());
     CHECK(!data.has_error());
@@ -298,12 +297,11 @@ TEST(StandAlonePreParserNoNatives) {
     i::Scanner scanner(i::Isolate::Current()->unicode_cache());
     scanner.Initialize(&stream);
 
-    // Flags don't allow natives syntax.
+    // Preparser defaults to disallowing natives syntax.
+    v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
+    preparser.set_allow_lazy(true);
     v8::preparser::PreParser::PreParseResult result =
-        v8::preparser::PreParser::PreParseProgram(&scanner,
-                                                  &log,
-                                                  i::kAllowLazy,
-                                                  stack_limit);
+        preparser.PreParseProgram();
     CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
     i::ScriptDataImpl data(log.ExtractData());
     // Data contains syntax error.
@@ -329,8 +327,7 @@ TEST(RegressChromium62639) {
   i::Utf8ToUtf16CharacterStream stream(
       reinterpret_cast<const i::byte*>(program),
       static_cast<unsigned>(strlen(program)));
-  i::ScriptDataImpl* data =
-      i::ParserApi::PreParse(&stream, NULL, false);
+  i::ScriptDataImpl* data = i::PreParserApi::PreParse(&stream);
   CHECK(data->HasError());
   delete data;
 }
@@ -355,7 +352,7 @@ TEST(Regress928) {
   i::Handle<i::String> source(
       FACTORY->NewStringFromAscii(i::CStrVector(program)));
   i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
-  i::ScriptDataImpl* data = i::ParserApi::PreParse(&stream, NULL, false);
+  i::ScriptDataImpl* data = i::PreParserApi::PreParse(&stream);
   CHECK(!data->HasError());
 
   data->Initialize();
@@ -401,12 +398,10 @@ TEST(PreParseOverflow) {
   i::Scanner scanner(i::Isolate::Current()->unicode_cache());
   scanner.Initialize(&stream);
 
-
+  v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
+  preparser.set_allow_lazy(true);
   v8::preparser::PreParser::PreParseResult result =
-      v8::preparser::PreParser::PreParseProgram(&scanner,
-                                                &log,
-                                                true,
-                                                stack_limit);
+      preparser.PreParseProgram();
   CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
 }
 
@@ -995,7 +990,6 @@ TEST(ScopePositions) {
   int marker;
   i::Isolate::Current()->stack_guard()->SetStackLimit(
       reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
-  i::FLAG_harmony_scoping = true;
 
   for (int i = 0; source_data[i].outer_prefix; i++) {
     int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
@@ -1018,7 +1012,9 @@ TEST(ScopePositions) {
     CHECK_EQ(source->length(), kProgramSize);
     i::Handle<i::Script> script = FACTORY->NewScript(source);
     i::CompilationInfoWithZone info(script);
-    i::Parser parser(&info, i::kAllowLazy | i::EXTENDED_MODE, NULL, NULL);
+    i::Parser parser(&info);
+    parser.set_allow_lazy(true);
+    parser.set_allow_harmony_scoping(true);
     info.MarkAsGlobal();
     info.SetLanguageMode(source_data[i].language_mode);
     i::FunctionLiteral* function = parser.ParseProgram();
@@ -1066,31 +1062,57 @@ i::Handle<i::String> FormatMessage(i::ScriptDataImpl* data) {
 }
 
 
-void TestParserSync(i::Handle<i::String> source, int flags) {
+enum ParserFlag {
+  kAllowLazy,
+  kAllowNativesSyntax,
+  kAllowHarmonyScoping,
+  kAllowModules,
+  kAllowGenerators,
+  kParserFlagCount
+};
+
+
+static bool checkParserFlag(unsigned flags, ParserFlag flag) {
+  return flags & (1 << flag);
+}
+
+
+#define SET_PARSER_FLAGS(parser, flags) \
+  parser.set_allow_lazy(checkParserFlag(flags, kAllowLazy)); \
+  parser.set_allow_natives_syntax(checkParserFlag(flags, \
+                                                  kAllowNativesSyntax)); \
+  parser.set_allow_harmony_scoping(checkParserFlag(flags, \
+                                                   kAllowHarmonyScoping)); \
+  parser.set_allow_modules(checkParserFlag(flags, kAllowModules)); \
+  parser.set_allow_generators(checkParserFlag(flags, kAllowGenerators));
+
+void TestParserSyncWithFlags(i::Handle<i::String> source, unsigned flags) {
   uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
-  bool harmony_scoping = ((i::kLanguageModeMask & flags) == i::EXTENDED_MODE);
 
   // Preparse the data.
   i::CompleteParserRecorder log;
-  i::Scanner scanner(i::Isolate::Current()->unicode_cache());
-  i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
-  scanner.SetHarmonyScoping(harmony_scoping);
-  scanner.Initialize(&stream);
-  v8::preparser::PreParser::PreParseResult result =
-      v8::preparser::PreParser::PreParseProgram(
-          &scanner, &log, flags, stack_limit);
-  CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
+  {
+    i::Scanner scanner(i::Isolate::Current()->unicode_cache());
+    i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
+    v8::preparser::PreParser preparser(&scanner, &log, stack_limit);
+    SET_PARSER_FLAGS(preparser, flags);
+    scanner.Initialize(&stream);
+    v8::preparser::PreParser::PreParseResult result =
+        preparser.PreParseProgram();
+    CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
+  }
   i::ScriptDataImpl data(log.ExtractData());
 
   // Parse the data
-  i::Handle<i::Script> script = FACTORY->NewScript(source);
-  bool save_harmony_scoping = i::FLAG_harmony_scoping;
-  i::FLAG_harmony_scoping = harmony_scoping;
-  i::CompilationInfoWithZone info(script);
-  i::Parser parser(&info, flags, NULL, NULL);
-  info.MarkAsGlobal();
-  i::FunctionLiteral* function = parser.ParseProgram();
-  i::FLAG_harmony_scoping = save_harmony_scoping;
+  i::FunctionLiteral* function;
+  {
+    i::Handle<i::Script> script = FACTORY->NewScript(source);
+    i::CompilationInfoWithZone info(script);
+    i::Parser parser(&info);
+    SET_PARSER_FLAGS(parser, flags);
+    info.MarkAsGlobal();
+    function = parser.ParseProgram();
+  }
 
   // Check that preparsing fails iff parsing fails.
   if (function == NULL) {
@@ -1140,19 +1162,9 @@ void TestParserSync(i::Handle<i::String> source, int flags) {
 }
 
 
-void TestParserSyncWithFlags(i::Handle<i::String> source) {
-  static const int kFlagsCount = 6;
-  const int flags[kFlagsCount] = {
-    i::kNoParsingFlags | i::CLASSIC_MODE,
-    i::kNoParsingFlags | i::STRICT_MODE,
-    i::kNoParsingFlags | i::EXTENDED_MODE,
-    i::kAllowLazy | i::CLASSIC_MODE,
-    i::kAllowLazy | i::STRICT_MODE,
-    i::kAllowLazy | i::EXTENDED_MODE
-  };
-
-  for (int k = 0; k < kFlagsCount; ++k) {
-    TestParserSync(source, flags[k]);
+void TestParserSync(i::Handle<i::String> source) {
+  for (unsigned flags = 0; flags < (1 << kParserFlagCount); ++flags) {
+    TestParserSyncWithFlags(source, flags);
   }
 }
 
@@ -1255,7 +1267,7 @@ TEST(ParserSync) {
         CHECK(length == kProgramSize);
         i::Handle<i::String> source =
             FACTORY->NewStringFromAscii(i::CStrVector(program.start()));
-        TestParserSyncWithFlags(source);
+        TestParserSync(source);
       }
     }
   }
index 1f96ce6..a5089d3 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "platform.h"
 #include "cctest.h"
+#include "win32-headers.h"
 
 using namespace ::v8::internal;
 
index 56b1788..0682fbc 100644 (file)
@@ -624,13 +624,11 @@ TEST(RecordTickSample) {
   //      -> ccc -> aaa  - sample3
   TickSample sample1;
   sample1.pc = ToAddress(0x1600);
-  sample1.tos = ToAddress(0x1500);
   sample1.stack[0] = ToAddress(0x1510);
   sample1.frames_count = 1;
   generator.RecordTickSample(sample1);
   TickSample sample2;
   sample2.pc = ToAddress(0x1925);
-  sample2.tos = ToAddress(0x1900);
   sample2.stack[0] = ToAddress(0x1780);
   sample2.stack[1] = ToAddress(0x10000);  // non-existent.
   sample2.stack[2] = ToAddress(0x1620);
@@ -638,7 +636,6 @@ TEST(RecordTickSample) {
   generator.RecordTickSample(sample2);
   TickSample sample3;
   sample3.pc = ToAddress(0x1510);
-  sample3.tos = ToAddress(0x1500);
   sample3.stack[0] = ToAddress(0x1910);
   sample3.stack[1] = ToAddress(0x1610);
   sample3.frames_count = 2;
index 9aebdb1..2889172 100644 (file)
@@ -95,18 +95,6 @@ class RandomNumberGenerator {
 
 using namespace v8::internal;
 
-static v8::Persistent<v8::Context> env;
-
-
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    const char* extensions[] = { "v8/print" };
-    v8::ExtensionConfiguration config(1, extensions);
-    env = v8::Context::New(&config);
-  }
-  env->Enter();
-}
-
 
 static const int DEEP_DEPTH = 8 * 1024;
 static const int SUPER_DEEP_DEPTH = 80 * 1024;
@@ -574,8 +562,8 @@ static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
 
 TEST(Traverse) {
   printf("TestTraverse\n");
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   ZoneScope zone(Isolate::Current()->runtime_zone(), DELETE_ON_EXIT);
   ConsStringGenerationData data(false);
   Handle<String> flat = ConstructBalanced(&data);
@@ -663,7 +651,7 @@ printf(
 
 template<typename BuildString>
 void TestStringCharacterStream(BuildString build, int test_cases) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope outer_scope(isolate);
   ZoneScope zone(Isolate::Current()->runtime_zone(), DELETE_ON_EXIT);
@@ -863,8 +851,8 @@ static const int DEEP_ASCII_DEPTH = 100000;
 
 TEST(DeepAscii) {
   printf("TestDeepAscii\n");
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
 
   char* foo = NewArray<char>(DEEP_ASCII_DEPTH);
   for (int i = 0; i < DEEP_ASCII_DEPTH; i++) {
@@ -888,8 +876,8 @@ TEST(DeepAscii) {
 
 TEST(Utf8Conversion) {
   // Smoke test for converting strings to utf-8.
-  InitializeVM();
-  v8::HandleScope handle_scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope handle_scope(CcTest::isolate());
   // A simple ascii string
   const char* ascii_string = "abcdef12345";
   int len =
@@ -935,8 +923,8 @@ TEST(Utf8Conversion) {
 TEST(ExternalShortStringAdd) {
   ZoneScope zonescope(Isolate::Current()->runtime_zone(), DELETE_ON_EXIT);
 
-  InitializeVM();
-  v8::HandleScope handle_scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope handle_scope(CcTest::isolate());
   Zone* zone = Isolate::Current()->runtime_zone();
 
   // Make sure we cover all always-flat lengths and at least one above.
@@ -977,7 +965,7 @@ TEST(ExternalShortStringAdd) {
   }
 
   // Add the arrays with the short external strings in the global object.
-  v8::Handle<v8::Object> global = env->Global();
+  v8::Handle<v8::Object> global = CcTest::env()->Global();
   global->Set(v8_str("external_ascii"), ascii_external_strings);
   global->Set(v8_str("external_non_ascii"), non_ascii_external_strings);
   global->Set(v8_str("max_length"), v8::Integer::New(kMaxLength));
@@ -1027,8 +1015,8 @@ TEST(CachedHashOverflow) {
   Isolate* isolate = Isolate::Current();
   ZoneScope zone(isolate->runtime_zone(), DELETE_ON_EXIT);
 
-  InitializeVM();
-  v8::HandleScope handle_scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope handle_scope(CcTest::isolate());
   // Lines must be executed sequentially. Combining them into one script
   // makes the bug go away.
   const char* lines[] = {
@@ -1070,8 +1058,8 @@ TEST(CachedHashOverflow) {
 
 TEST(SliceFromCons) {
   FLAG_string_slices = true;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   Handle<String> string =
       FACTORY->NewStringFromAscii(CStrVector("parentparentparent"));
   Handle<String> parent = FACTORY->NewConsString(string, string);
@@ -1104,8 +1092,8 @@ class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
 
 TEST(SliceFromExternal) {
   FLAG_string_slices = true;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   AsciiVectorResource resource(
       i::Vector<const char>("abcdefghijklmnopqrstuvwxyz", 26));
   Handle<String> string = FACTORY->NewExternalStringFromAscii(&resource);
@@ -1123,8 +1111,8 @@ TEST(TrivialSlice) {
   // This tests whether a slice that contains the entire parent string
   // actually creates a new string (it should not).
   FLAG_string_slices = true;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   v8::Local<v8::Value> result;
   Handle<String> string;
   const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
@@ -1152,8 +1140,8 @@ TEST(SliceFromSlice) {
   // This tests whether a slice that contains the entire parent string
   // actually creates a new string (it should not).
   FLAG_string_slices = true;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   v8::Local<v8::Value> result;
   Handle<String> string;
   const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
@@ -1220,8 +1208,8 @@ TEST(RobustSubStringStub) {
   // This tests whether the SubStringStub can handle unsafe arguments.
   // If not recognized, those unsafe arguments lead to out-of-bounds reads.
   FLAG_allow_natives_syntax = true;
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   v8::Local<v8::Value> result;
   Handle<String> string;
   CompileRun("var short = 'abcdef';");
@@ -1264,8 +1252,8 @@ TEST(RobustSubStringStub) {
 
 TEST(RegExpOverflow) {
   // Result string has the length 2^32, causing a 32-bit integer overflow.
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   LocalContext context;
   v8::V8::IgnoreOutOfMemoryException();
   v8::Local<v8::Value> result = CompileRun(
@@ -1280,8 +1268,8 @@ TEST(RegExpOverflow) {
 
 
 TEST(StringReplaceAtomTwoByteResult) {
-  InitializeVM();
-  v8::HandleScope scope(env->GetIsolate());
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
   LocalContext context;
   v8::Local<v8::Value> result = CompileRun(
       "var subject = 'ascii~only~string~'; "
index e953457..6a8323b 100644 (file)
 
 using namespace v8::internal;
 
-static v8::Persistent<v8::Context> env;
-
-static void InitializeVM() {
-  if (env.IsEmpty()) {
-    const char* extensions[] = { "v8/print" };
-    v8::ExtensionConfiguration config(1, extensions);
-    env = v8::Context::New(&config);
-  }
-  env->Enter();
-}
-
 
 TEST(Create) {
-  InitializeVM();
+  CcTest::InitializeVM();
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
 
index c83acb9..541c423 100644 (file)
@@ -98,57 +98,68 @@ TEST(SNPrintF) {
 }
 
 
-void TestMemCopy(Vector<byte> src,
-                 Vector<byte> dst,
-                 int source_alignment,
-                 int destination_alignment,
-                 int length_alignment) {
-  memset(dst.start(), 0xFF, dst.length());
-  byte* to = dst.start() + 32 + destination_alignment;
-  byte* from = src.start() + source_alignment;
-  int length = OS::kMinComplexMemCopy + length_alignment;
-  OS::MemCopy(to, from, static_cast<size_t>(length));
-  printf("[%d,%d,%d]\n",
-         source_alignment, destination_alignment, length_alignment);
-  for (int i = 0; i < length; i++) {
-    CHECK_EQ(from[i], to[i]);
+static const int kAreaSize = 512;
+
+
+void TestMemMove(byte* area1,
+                 byte* area2,
+                 byte* area3,
+                 int src_offset,
+                 int dest_offset,
+                 int length) {
+  for (int i = 0; i < kAreaSize; i++) {
+    area1[i] = i & 0xFF;
+    area2[i] = i & 0xFF;
+    area3[i] = i & 0xFF;
+  }
+  OS::MemMove(area1 + dest_offset, area1 + src_offset, length);
+  MoveBytes(area2 + dest_offset, area2 + src_offset, length);
+  memmove(area3 + dest_offset, area3 + src_offset, length);
+  if (memcmp(area1, area3, kAreaSize) != 0) {
+    printf("OS::MemMove(): src_offset: %d, dest_offset: %d, length: %d\n",
+           src_offset, dest_offset, length);
+    for (int i = 0; i < kAreaSize; i++) {
+      if (area1[i] == area3[i]) continue;
+      printf("diff at offset %d (%p): is %d, should be %d\n",
+             i, reinterpret_cast<void*>(area1 + i), area1[i], area3[i]);
+    }
+    CHECK(false);
+  }
+  if (memcmp(area2, area3, kAreaSize) != 0) {
+    printf("MoveBytes(): src_offset: %d, dest_offset: %d, length: %d\n",
+           src_offset, dest_offset, length);
+    for (int i = 0; i < kAreaSize; i++) {
+      if (area2[i] == area3[i]) continue;
+      printf("diff at offset %d (%p): is %d, should be %d\n",
+             i, reinterpret_cast<void*>(area2 + i), area2[i], area3[i]);
+    }
+    CHECK(false);
   }
-  CHECK_EQ(0xFF, to[-1]);
-  CHECK_EQ(0xFF, to[length]);
 }
 
 
-
-TEST(MemCopy) {
+TEST(MemMove) {
   v8::V8::Initialize();
   OS::SetUp();
-  const int N = OS::kMinComplexMemCopy + 128;
-  Vector<byte> buffer1 = Vector<byte>::New(N);
-  Vector<byte> buffer2 = Vector<byte>::New(N);
-
-  for (int i = 0; i < N; i++) {
-    buffer1[i] = static_cast<byte>(i & 0x7F);
-  }
-
-  // Same alignment.
-  for (int i = 0; i < 32; i++) {
-    TestMemCopy(buffer1, buffer2, i, i, i * 2);
-  }
-
-  // Different alignment.
-  for (int i = 0; i < 32; i++) {
-    for (int j = 1; j < 32; j++) {
-      TestMemCopy(buffer1, buffer2, i, (i + j) & 0x1F , 0);
+  byte* area1 = new byte[kAreaSize];
+  byte* area2 = new byte[kAreaSize];
+  byte* area3 = new byte[kAreaSize];
+
+  static const int kMinOffset = 32;
+  static const int kMaxOffset = 64;
+  static const int kMaxLength = 128;
+  STATIC_ASSERT(kMaxOffset + kMaxLength < kAreaSize);
+
+  for (int src_offset = kMinOffset; src_offset <= kMaxOffset; src_offset++) {
+    for (int dst_offset = kMinOffset; dst_offset <= kMaxOffset; dst_offset++) {
+      for (int length = 0; length <= kMaxLength; length++) {
+        TestMemMove(area1, area2, area3, src_offset, dst_offset, length);
+      }
     }
   }
-
-  // Different lengths
-  for (int i = 0; i < 32; i++) {
-    TestMemCopy(buffer1, buffer2, 3, 7, i);
-  }
-
-  buffer2.Dispose();
-  buffer1.Dispose();
+  delete[] area1;
+  delete[] area2;
+  delete[] area3;
 }
 
 
index 86dc740..4c2cd23 100644 (file)
@@ -57,6 +57,10 @@ class CcTestSuite(testsuite.TestSuite):
       return []
     tests = []
     for test_desc in output.stdout.strip().split():
+      if test_desc.find('<') < 0:
+        # Native Client output can contain a few non-test arguments
+        # before the tests. Skip these.
+        continue
       raw_test, dependency = test_desc.split('<')
       if dependency != '':
         dependency = raw_test.split('/')[0] + '/' + dependency
index 1b788d5..dba65a9 100644 (file)
@@ -74,7 +74,13 @@ class MessageTestSuite(testsuite.TestSuite):
     """Ignore empty lines, valgrind output and Android output."""
     if not string: return True
     return (string.startswith("==") or string.startswith("**") or
-            string.startswith("ANDROID"))
+            string.startswith("ANDROID") or
+            # These five patterns appear in normal Native Client output.
+            string.startswith("DEBUG MODE ENABLED") or
+            string.startswith("tools/nacl-run.py") or
+            string.find("BYPASSING ALL ACL CHECKS") > 0 or
+            string.find("Native Client module will be loaded") > 0 or
+            string.find("NaClHostDescOpen:") > 0)
 
   def IsFailureOutput(self, output, testpath):
     expected_path = os.path.join(self.root, testpath + ".out")
index d57fd32..4d534e3 100644 (file)
@@ -144,7 +144,9 @@ if (support_smi_only_arrays) {
   obj = fastliteralcase(get_standard_literal(), 1.5);
   assertKind(elements_kind.fast_double, obj);
   obj = fastliteralcase(get_standard_literal(), 2);
-  assertKind(elements_kind.fast_double, obj);
+  // TODO(hpayer): bring the following assert back as soon as allocation
+  // sites work again for fast literals
+  //assertKind(elements_kind.fast_double, obj);
 
   obj = fastliteralcase([5, 3, 2], 1.5);
   assertKind(elements_kind.fast_double, obj);
@@ -173,7 +175,9 @@ if (support_smi_only_arrays) {
   obj = fastliteralcase_smifast("carter");
   assertKind(elements_kind.fast, obj);
   obj = fastliteralcase_smifast(2);
-  assertKind(elements_kind.fast, obj);
+  // TODO(hpayer): bring the following assert back as soon as allocation
+  // sites work again for fast literals
+  //assertKind(elements_kind.fast, obj);
 
   if (optimize_constructed_arrays) {
     function newarraycase_smidouble(value) {
diff --git a/deps/v8/test/mjsunit/bugs/bug-2615.js b/deps/v8/test/mjsunit/bugs/bug-2615.js
new file mode 100644 (file)
index 0000000..51aeaf4
--- /dev/null
@@ -0,0 +1,126 @@
+// Copyright 2013 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 = [];
+a[0xfffffffe] = 10;
+assertThrows("a.unshift(1);", RangeError);
+assertEquals(0xffffffff, a.length);
+assertEquals(10, a[0xffffffff]);
+assertEquals(undefined, a[0xfffffffe]);
+
+a = [1,2,3];
+a[0xfffffffe] = 10;
+assertThrows("a.splice(1,1,7,7,7,7,7);", RangeError);
+assertEquals([1,7,7,7,7,7,3], a.slice(0, 7));
+assertEquals(0xffffffff, a.length);
+assertEquals(10, a[0xfffffffe + 5 - 1]);
+
+a = [1];
+Object.defineProperty(a, "1", {writable:false, configurable:false, value: 100});
+assertThrows("a.unshift(4);", TypeError);
+assertEquals([1, 100, 100], a);
+var desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.writable);
+assertEquals(false, desc.configurable);
+
+a = [1];
+var g = function() { return 100; };
+Object.defineProperty(a, "1", {get:g});
+assertThrows("a.unshift(0);", TypeError);
+assertEquals([1, 100, 100], a);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+assertEquals(g, desc.get);
+
+a = [1];
+var c = 0;
+var s = function(v) { c += 1; };
+Object.defineProperty(a, "1", {set:s});
+a.unshift(10);
+assertEquals([10, undefined, undefined], a);
+assertEquals(1, c);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+assertEquals(s, desc.set);
+
+a = [1];
+Object.defineProperty(a, "1", {configurable:false, value:10});
+assertThrows("a.splice(1,1);", TypeError);
+assertEquals([1, 10], a);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+
+a = [0,1,2,3,4,5,6];
+Object.defineProperty(a, "3", {configurable:false, writable:false, value:3});
+assertThrows("a.splice(1,4);", TypeError);
+assertEquals([0,5,6,3,,,,,], a);
+desc = Object.getOwnPropertyDescriptor(a, "3");
+assertEquals(false, desc.configurable);
+assertEquals(false, desc.writable);
+
+a = [0,1,2,3,4,5,6];
+Object.defineProperty(a, "5", {configurable:false, value:5});
+assertThrows("a.splice(1,4);", TypeError);
+assertEquals([0,5,6,3,4,5,,,], a);
+desc = Object.getOwnPropertyDescriptor(a, "5");
+assertEquals(false, desc.configurable);
+
+a = [1,2,3,,5];
+Object.defineProperty(a, "1", {configurable:false, writable:true, value:2});
+assertEquals(1, a.shift());
+assertEquals([2,3,,5], a);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+assertEquals(true, desc.writable);
+assertThrows("a.shift();", TypeError);
+assertEquals([3,3,,5], a);
+desc = Object.getOwnPropertyDescriptor(a, "1");
+assertEquals(false, desc.configurable);
+assertEquals(true, desc.writable);
+
+a = [1,2,3];
+Object.defineProperty(a, "2", {configurable:false, value:3});
+assertThrows("a.pop();", TypeError);
+assertEquals([1,2,3], a);
+desc = Object.getOwnPropertyDescriptor(a, "2");
+assertEquals(false, desc.configurable);
+
+a = [1,2,,,5];
+Object.defineProperty(a, "4", {writable:true, configurable:false, value:5});
+assertThrows("a.sort();", TypeError);
+assertEquals([1,2,5,,5], a);
+desc = Object.getOwnPropertyDescriptor(a, "2");
+assertEquals(true, desc.configurable);
+desc = Object.getOwnPropertyDescriptor(a, "4");
+assertEquals(false, desc.configurable);
+
+a = [1,2,3,,5,6];
+Object.defineProperty(a, "4", {value:5, writable:false});
+assertThrows("a.sort();", TypeError);
+assertEquals([1,2,3,5,5,6], a);
+desc = Object.getOwnPropertyDescriptor(a, "4");
+assertEquals(false, desc.writable);
index 062cfd5..ce2c680 100644 (file)
@@ -54,7 +54,9 @@ function checkConstructor(func, name) {
   assertFalse(proto_desc.writable, name);
   assertFalse(proto_desc.configurable, name);
   var prototype = proto_desc.value;
-  assertEquals(null, Object.getPrototypeOf(prototype), name);
+  assertEquals(name == "GeneratorFunctionPrototype" ? Object.prototype : null,
+               Object.getPrototypeOf(prototype),
+               name);
   for (var i = 0; i < propNames.length; i++) {
     var propName = propNames[i];
     if (propName == "constructor") continue;
diff --git a/deps/v8/test/mjsunit/external-array-no-sse2.js b/deps/v8/test/mjsunit/external-array-no-sse2.js
new file mode 100644 (file)
index 0000000..0b843d8
--- /dev/null
@@ -0,0 +1,716 @@
+// 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 --noenable-sse2
+
+// Helper
+function assertInstance(o, f) {
+  assertSame(o.constructor, f);
+  assertInstanceof(o, f);
+}
+
+// This is a regression test for overlapping key and value registers.
+function f(a) {
+  a[0] = 0;
+  a[1] = 0;
+}
+
+var a = new Int32Array(2);
+for (var i = 0; i < 5; i++) {
+  f(a);
+}
+%OptimizeFunctionOnNextCall(f);
+f(a);
+
+assertEquals(0, a[0]);
+assertEquals(0, a[1]);
+
+// No-parameter constructor should fail right now.
+function abfunc1() {
+  return new ArrayBuffer();
+}
+assertThrows(abfunc1);
+
+// Test derivation from an ArrayBuffer
+var ab = new ArrayBuffer(12);
+assertInstance(ab, ArrayBuffer);
+var derived_uint8 = new Uint8Array(ab);
+assertInstance(derived_uint8, Uint8Array);
+assertSame(ab, derived_uint8.buffer);
+assertEquals(12, derived_uint8.length);
+assertEquals(12, derived_uint8.byteLength);
+assertEquals(0, derived_uint8.byteOffset);
+assertEquals(1, derived_uint8.BYTES_PER_ELEMENT);
+var derived_uint8_2 = new Uint8Array(ab,7);
+assertInstance(derived_uint8_2, Uint8Array);
+assertSame(ab, derived_uint8_2.buffer);
+assertEquals(5, derived_uint8_2.length);
+assertEquals(5, derived_uint8_2.byteLength);
+assertEquals(7, derived_uint8_2.byteOffset);
+assertEquals(1, derived_uint8_2.BYTES_PER_ELEMENT);
+var derived_int16 = new Int16Array(ab);
+assertInstance(derived_int16, Int16Array);
+assertSame(ab, derived_int16.buffer);
+assertEquals(6, derived_int16.length);
+assertEquals(12, derived_int16.byteLength);
+assertEquals(0, derived_int16.byteOffset);
+assertEquals(2, derived_int16.BYTES_PER_ELEMENT);
+var derived_int16_2 = new Int16Array(ab,6);
+assertInstance(derived_int16_2, Int16Array);
+assertSame(ab, derived_int16_2.buffer);
+assertEquals(3, derived_int16_2.length);
+assertEquals(6, derived_int16_2.byteLength);
+assertEquals(6, derived_int16_2.byteOffset);
+assertEquals(2, derived_int16_2.BYTES_PER_ELEMENT);
+var derived_uint32 = new Uint32Array(ab);
+assertInstance(derived_uint32, Uint32Array);
+assertSame(ab, derived_uint32.buffer);
+assertEquals(3, derived_uint32.length);
+assertEquals(12, derived_uint32.byteLength);
+assertEquals(0, derived_uint32.byteOffset);
+assertEquals(4, derived_uint32.BYTES_PER_ELEMENT);
+var derived_uint32_2 = new Uint32Array(ab,4);
+assertInstance(derived_uint32_2, Uint32Array);
+assertSame(ab, derived_uint32_2.buffer);
+assertEquals(2, derived_uint32_2.length);
+assertEquals(8, derived_uint32_2.byteLength);
+assertEquals(4, derived_uint32_2.byteOffset);
+assertEquals(4, derived_uint32_2.BYTES_PER_ELEMENT);
+var derived_uint32_3 = new Uint32Array(ab,4,1);
+assertInstance(derived_uint32_3, Uint32Array);
+assertSame(ab, derived_uint32_3.buffer);
+assertEquals(1, derived_uint32_3.length);
+assertEquals(4, derived_uint32_3.byteLength);
+assertEquals(4, derived_uint32_3.byteOffset);
+assertEquals(4, derived_uint32_3.BYTES_PER_ELEMENT);
+var derived_float64 = new Float64Array(ab,0,1);
+assertInstance(derived_float64, Float64Array);
+assertSame(ab, derived_float64.buffer);
+assertEquals(1, derived_float64.length);
+assertEquals(8, derived_float64.byteLength);
+assertEquals(0, derived_float64.byteOffset);
+assertEquals(8, derived_float64.BYTES_PER_ELEMENT);
+
+// If a given byteOffset and length references an area beyond the end of the
+// ArrayBuffer an exception is raised.
+function abfunc3() {
+  new Uint32Array(ab,4,3);
+}
+assertThrows(abfunc3);
+function abfunc4() {
+  new Uint32Array(ab,16);
+}
+assertThrows(abfunc4);
+
+// The given byteOffset must be a multiple of the element size of the specific
+// type, otherwise an exception is raised.
+function abfunc5() {
+  new Uint32Array(ab,5);
+}
+assertThrows(abfunc5);
+
+// If length is not explicitly specified, the length of the ArrayBuffer minus
+// the byteOffset must be a multiple of the element size of the specific type,
+// or an exception is raised.
+var ab2 = new ArrayBuffer(13);
+function abfunc6() {
+  new Uint32Array(ab2,4);
+}
+assertThrows(abfunc6);
+
+// Test that an array constructed without an array buffer creates one properly.
+a = new Uint8Array(31);
+assertEquals(a.byteLength, a.buffer.byteLength);
+assertEquals(a.length, a.buffer.byteLength);
+assertEquals(a.length * a.BYTES_PER_ELEMENT, a.buffer.byteLength);
+a = new Int16Array(5);
+assertEquals(a.byteLength, a.buffer.byteLength);
+assertEquals(a.length * a.BYTES_PER_ELEMENT, a.buffer.byteLength);
+a = new Float64Array(7);
+assertEquals(a.byteLength, a.buffer.byteLength);
+assertEquals(a.length * a.BYTES_PER_ELEMENT, a.buffer.byteLength);
+
+// Test that an implicitly created buffer is a valid buffer.
+a = new Float64Array(7);
+assertSame(a.buffer, (new Uint16Array(a.buffer)).buffer);
+assertSame(a.buffer, (new Float32Array(a.buffer,4)).buffer);
+assertSame(a.buffer, (new Int8Array(a.buffer,3,51)).buffer);
+assertInstance(a.buffer, ArrayBuffer);
+
+// Test the correct behavior of the |BYTES_PER_ELEMENT| property (which is
+// "constant", but not read-only).
+a = new Int32Array(2);
+assertEquals(4, a.BYTES_PER_ELEMENT);
+a.BYTES_PER_ELEMENT = 42;
+assertEquals(42, a.BYTES_PER_ELEMENT);
+a = new Uint8Array(2);
+assertEquals(1, a.BYTES_PER_ELEMENT);
+a = new Int16Array(2);
+assertEquals(2, a.BYTES_PER_ELEMENT);
+
+// Test Float64Arrays.
+function get(a, index) {
+  return a[index];
+}
+function set(a, index, value) {
+  a[index] = value;
+}
+function temp() {
+var array = new Float64Array(2);
+for (var i = 0; i < 5; i++) {
+  set(array, 0, 2.5);
+  assertEquals(2.5, array[0]);
+}
+%OptimizeFunctionOnNextCall(set);
+set(array, 0, 2.5);
+assertEquals(2.5, array[0]);
+set(array, 1, 3.5);
+assertEquals(3.5, array[1]);
+for (var i = 0; i < 5; i++) {
+  assertEquals(2.5, get(array, 0));
+  assertEquals(3.5, array[1]);
+}
+%OptimizeFunctionOnNextCall(get);
+assertEquals(2.5, get(array, 0));
+assertEquals(3.5, get(array, 1));
+}
+
+// Test non-number parameters.
+var array_with_length_from_non_number = new Int32Array("2");
+assertEquals(2, array_with_length_from_non_number.length);
+array_with_length_from_non_number = new Int32Array(undefined);
+assertEquals(0, array_with_length_from_non_number.length);
+var foo = { valueOf: function() { return 3; } };
+array_with_length_from_non_number = new Int32Array(foo);
+assertEquals(3, array_with_length_from_non_number.length);
+foo = { toString: function() { return "4"; } };
+array_with_length_from_non_number = new Int32Array(foo);
+assertEquals(4, array_with_length_from_non_number.length);
+
+
+// Test loads and stores.
+types = [Array, Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array,
+         Uint32Array, Uint8ClampedArray, Float32Array, Float64Array];
+
+test_result_nan = [NaN, 0, 0, 0, 0, 0, 0, 0, NaN, NaN];
+test_result_low_int = [-1, -1, 255, -1, 65535, -1, 0xFFFFFFFF, 0, -1, -1];
+test_result_low_double = [-1.25, -1, 255, -1, 65535, -1, 0xFFFFFFFF, 0, -1.25, -1.25];
+test_result_middle = [253.75, -3, 253, 253, 253, 253, 253, 254, 253.75, 253.75];
+test_result_high_int = [256, 0, 0, 256, 256, 256, 256, 255, 256, 256];
+test_result_high_double = [256.25, 0, 0, 256, 256, 256, 256, 255, 256.25, 256.25];
+
+const kElementCount = 40;
+
+function test_load(array, sum) {
+  for (var i = 0; i < kElementCount; i++) {
+    sum += array[i];
+  }
+  return sum;
+}
+
+function test_load_const_key(array, sum) {
+  sum += array[0];
+  sum += array[1];
+  sum += array[2];
+  return sum;
+}
+
+function test_store(array, sum) {
+  for (var i = 0; i < kElementCount; i++) {
+    sum += array[i] = i+1;
+  }
+  return sum;
+}
+
+function test_store_const_key(array, sum) {
+  sum += array[0] = 1;
+  sum += array[1] = 2;
+  sum += array[2] = 3;
+  return sum;
+}
+
+function zero() {
+  return 0.0;
+}
+
+function test_store_middle_tagged(array, sum) {
+  array[0] = 253.75;
+  return array[0];
+}
+
+function test_store_high_tagged(array, sum) {
+  array[0] = 256.25;
+  return array[0];
+}
+
+function test_store_middle_double(array, sum) {
+  array[0] = 253.75 + zero(); // + forces double type feedback
+  return array[0];
+}
+
+function test_store_high_double(array, sum) {
+  array[0] = 256.25 + zero(); // + forces double type feedback
+  return array[0];
+}
+
+function test_store_high_double(array, sum) {
+  array[0] = 256.25;
+  return array[0];
+}
+
+function test_store_low_int(array, sum) {
+  array[0] = -1;
+  return array[0];
+}
+
+function test_store_low_tagged(array, sum) {
+  array[0] = -1.25;
+  return array[0];
+}
+
+function test_store_low_double(array, sum) {
+  array[0] = -1.25 + zero(); // + forces double type feedback
+  return array[0];
+}
+
+function test_store_high_int(array, sum) {
+  array[0] = 256;
+  return array[0];
+}
+
+function test_store_nan(array, sum) {
+  array[0] = NaN;
+  return array[0];
+}
+
+const kRuns = 10;
+
+function run_test(test_func, array, expected_result) {
+  for (var i = 0; i < 5; i++) test_func(array, 0);
+  %OptimizeFunctionOnNextCall(test_func);
+  var sum = 0;
+  for (var i = 0; i < kRuns; i++) {
+    sum = test_func(array, sum);
+  }
+  assertEquals(expected_result, sum);
+  %DeoptimizeFunction(test_func);
+  gc();  // Makes V8 forget about type information for test_func.
+}
+
+function run_bounds_test(test_func, array, expected_result) {
+  assertEquals(undefined, a[kElementCount]);
+  a[kElementCount] = 456;
+  assertEquals(undefined, a[kElementCount]);
+  assertEquals(undefined, a[kElementCount+1]);
+  a[kElementCount+1] = 456;
+  assertEquals(undefined, a[kElementCount+1]);
+}
+
+for (var t = 0; t < types.length; t++) {
+  var type = types[t];
+  var a = new type(kElementCount);
+
+  for (var i = 0; i < kElementCount; i++) {
+    a[i] = i;
+  }
+
+  // Run test functions defined above.
+  run_test(test_load, a, 780 * kRuns);
+  run_test(test_load_const_key, a, 3 * kRuns);
+  run_test(test_store, a, 820 * kRuns);
+  run_test(test_store_const_key, a, 6 * kRuns);
+  run_test(test_store_low_int, a, test_result_low_int[t]);
+  run_test(test_store_low_double, a, test_result_low_double[t]);
+  run_test(test_store_low_tagged, a, test_result_low_double[t]);
+  run_test(test_store_high_int, a, test_result_high_int[t]);
+  run_test(test_store_nan, a, test_result_nan[t]);
+  run_test(test_store_middle_double, a, test_result_middle[t]);
+  run_test(test_store_middle_tagged, a, test_result_middle[t]);
+  run_test(test_store_high_double, a, test_result_high_double[t]);
+  run_test(test_store_high_tagged, a, test_result_high_double[t]);
+
+  // Test the correct behavior of the |length| property (which is read-only).
+  if (t != 0) {
+    assertEquals(kElementCount, a.length);
+    a.length = 2;
+    assertEquals(kElementCount, a.length);
+    assertTrue(delete a.length);
+    a.length = 2;
+    assertEquals(2, a.length);
+
+    // Make sure bounds checks are handled correctly for external arrays.
+    run_bounds_test(a);
+    run_bounds_test(a);
+    run_bounds_test(a);
+    %OptimizeFunctionOnNextCall(run_bounds_test);
+    run_bounds_test(a);
+    %DeoptimizeFunction(run_bounds_test);
+    gc();  // Makes V8 forget about type information for test_func.
+
+  }
+
+  function array_load_set_smi_check(a) {
+    return a[0] = a[0] = 1;
+  }
+
+  array_load_set_smi_check(a);
+  array_load_set_smi_check(0);
+
+  function array_load_set_smi_check2(a) {
+    return a[0] = a[0] = 1;
+  }
+
+  array_load_set_smi_check2(a);
+  %OptimizeFunctionOnNextCall(array_load_set_smi_check2);
+  array_load_set_smi_check2(a);
+  array_load_set_smi_check2(0);
+  %DeoptimizeFunction(array_load_set_smi_check2);
+  gc();  // Makes V8 forget about type information for array_load_set_smi_check.
+}
+
+// Check handling of undefined in 32- and 64-bit external float arrays.
+
+function store_float32_undefined(ext_array) {
+  ext_array[0] = undefined;
+}
+
+var float32_array = new Float32Array(1);
+// Make sure runtime does it right
+store_float32_undefined(float32_array);
+assertTrue(isNaN(float32_array[0]));
+// Make sure the ICs do it right
+store_float32_undefined(float32_array);
+assertTrue(isNaN(float32_array[0]));
+// Make sure that Cranskshft does it right.
+%OptimizeFunctionOnNextCall(store_float32_undefined);
+store_float32_undefined(float32_array);
+assertTrue(isNaN(float32_array[0]));
+
+function store_float64_undefined(ext_array) {
+  ext_array[0] = undefined;
+}
+
+var float64_array = new Float64Array(1);
+// Make sure runtime does it right
+store_float64_undefined(float64_array);
+assertTrue(isNaN(float64_array[0]));
+// Make sure the ICs do it right
+store_float64_undefined(float64_array);
+assertTrue(isNaN(float64_array[0]));
+// Make sure that Cranskshft does it right.
+%OptimizeFunctionOnNextCall(store_float64_undefined);
+store_float64_undefined(float64_array);
+assertTrue(isNaN(float64_array[0]));
+
+
+// Check handling of 0-sized buffers and arrays.
+ab = new ArrayBuffer(0);
+assertInstance(ab, ArrayBuffer);
+assertEquals(0, ab.byteLength);
+a = new Int8Array(ab);
+assertInstance(a, Int8Array);
+assertEquals(0, a.byteLength);
+assertEquals(0, a.length);
+a[0] = 1;
+assertEquals(undefined, a[0]);
+ab = new ArrayBuffer(16);
+assertInstance(ab, ArrayBuffer);
+a = new Float32Array(ab,4,0);
+assertInstance(a, Float32Array);
+assertEquals(0, a.byteLength);
+assertEquals(0, a.length);
+a[0] = 1;
+assertEquals(undefined, a[0]);
+a = new Uint16Array(0);
+assertInstance(a, Uint16Array);
+assertEquals(0, a.byteLength);
+assertEquals(0, a.length);
+a[0] = 1;
+assertEquals(undefined, a[0]);
+
+
+// Check construction from arrays.
+a = new Uint32Array([]);
+assertInstance(a, Uint32Array);
+assertEquals(0, a.length);
+assertEquals(0, a.byteLength);
+assertEquals(0, a.buffer.byteLength);
+assertEquals(4, a.BYTES_PER_ELEMENT);
+assertInstance(a.buffer, ArrayBuffer);
+a = new Uint16Array([1,2,3]);
+assertInstance(a, Uint16Array);
+assertEquals(3, a.length);
+assertEquals(6, a.byteLength);
+assertEquals(6, a.buffer.byteLength);
+assertEquals(2, a.BYTES_PER_ELEMENT);
+assertEquals(1, a[0]);
+assertEquals(3, a[2]);
+assertInstance(a.buffer, ArrayBuffer);
+a = new Uint32Array(a);
+assertInstance(a, Uint32Array);
+assertEquals(3, a.length);
+assertEquals(12, a.byteLength);
+assertEquals(12, a.buffer.byteLength);
+assertEquals(4, a.BYTES_PER_ELEMENT);
+assertEquals(1, a[0]);
+assertEquals(3, a[2]);
+assertInstance(a.buffer, ArrayBuffer);
+
+// Check subarrays.
+a = new Uint16Array([1,2,3,4,5,6]);
+aa = a.subarray(3);
+assertInstance(aa, Uint16Array);
+assertEquals(3, aa.length);
+assertEquals(6, aa.byteLength);
+assertEquals(2, aa.BYTES_PER_ELEMENT);
+assertSame(a.buffer, aa.buffer);
+aa = a.subarray(3,5);
+assertInstance(aa, Uint16Array);
+assertEquals(2, aa.length);
+assertEquals(4, aa.byteLength);
+assertEquals(2, aa.BYTES_PER_ELEMENT);
+assertSame(a.buffer, aa.buffer);
+aa = a.subarray(4,8);
+assertInstance(aa, Uint16Array);
+assertEquals(2, aa.length);
+assertEquals(4, aa.byteLength);
+assertEquals(2, aa.BYTES_PER_ELEMENT);
+assertSame(a.buffer, aa.buffer);
+aa = a.subarray(9);
+assertInstance(aa, Uint16Array);
+assertEquals(0, aa.length);
+assertEquals(0, aa.byteLength);
+assertEquals(2, aa.BYTES_PER_ELEMENT);
+assertSame(a.buffer, aa.buffer);
+aa = a.subarray(-4);
+assertInstance(aa, Uint16Array);
+assertEquals(4, aa.length);
+assertEquals(8, aa.byteLength);
+assertEquals(2, aa.BYTES_PER_ELEMENT);
+assertSame(a.buffer, aa.buffer);
+aa = a.subarray(-3,-1);
+assertInstance(aa, Uint16Array);
+assertEquals(2, aa.length);
+assertEquals(4, aa.byteLength);
+assertEquals(2, aa.BYTES_PER_ELEMENT);
+assertSame(a.buffer, aa.buffer);
+aa = a.subarray(3,2);
+assertInstance(aa, Uint16Array);
+assertEquals(0, aa.length);
+assertEquals(0, aa.byteLength);
+assertEquals(2, aa.BYTES_PER_ELEMENT);
+assertSame(a.buffer, aa.buffer);
+aa = a.subarray(-3,-4);
+assertInstance(aa, Uint16Array);
+assertEquals(0, aa.length);
+assertEquals(0, aa.byteLength);
+assertEquals(2, aa.BYTES_PER_ELEMENT);
+assertSame(a.buffer, aa.buffer);
+aa = a.subarray(0,-8);
+assertInstance(aa, Uint16Array);
+assertEquals(0, aa.length);
+assertEquals(0, aa.byteLength);
+assertEquals(2, aa.BYTES_PER_ELEMENT);
+assertSame(a.buffer, aa.buffer);
+
+assertThrows(function(){ a.subarray.call({}, 0) });
+assertThrows(function(){ a.subarray.call([], 0) });
+assertThrows(function(){ a.subarray.call(a) });
+
+
+// Call constructors directly as functions, and through .call and .apply
+
+b = ArrayBuffer(100)
+a = Int8Array(b, 5, 77)
+assertInstance(b, ArrayBuffer)
+assertInstance(a, Int8Array)
+assertSame(b, a.buffer)
+assertEquals(5, a.byteOffset)
+assertEquals(77, a.byteLength)
+b = ArrayBuffer.call(null, 10)
+a = Uint16Array.call(null, b, 2, 4)
+assertInstance(b, ArrayBuffer)
+assertInstance(a, Uint16Array)
+assertSame(b, a.buffer)
+assertEquals(2, a.byteOffset)
+assertEquals(8, a.byteLength)
+b = ArrayBuffer.apply(null, [1000])
+a = Float32Array.apply(null, [b, 128, 1])
+assertInstance(b, ArrayBuffer)
+assertInstance(a, Float32Array)
+assertSame(b, a.buffer)
+assertEquals(128, a.byteOffset)
+assertEquals(4, a.byteLength)
+
+
+// Test array.set in different combinations.
+
+function assertArrayPrefix(expected, array) {
+  for (var i = 0; i < expected.length; ++i) {
+    assertEquals(expected[i], array[i]);
+  }
+}
+
+var a11 = new Int16Array([1, 2, 3, 4, 0, -1])
+var a12 = new Uint16Array(15)
+a12.set(a11, 3)
+assertArrayPrefix([0, 0, 0, 1, 2, 3, 4, 0, 0xffff, 0, 0], a12)
+assertThrows(function(){ a11.set(a12) })
+
+var a21 = [1, undefined, 10, NaN, 0, -1, {valueOf: function() {return 3}}]
+var a22 = new Int32Array(12)
+a22.set(a21, 2)
+assertArrayPrefix([0, 0, 1, 0, 10, 0, 0, -1, 3, 0], a22)
+
+var a31 = new Float32Array([2, 4, 6, 8, 11, NaN, 1/0, -3])
+var a32 = a31.subarray(2, 6)
+a31.set(a32, 4)
+assertArrayPrefix([2, 4, 6, 8, 6, 8, 11, NaN], a31)
+assertArrayPrefix([6, 8, 6, 8], a32)
+
+var a4 = new Uint8ClampedArray([3,2,5,6])
+a4.set(a4)
+assertArrayPrefix([3, 2, 5, 6], a4)
+
+// Cases with overlapping backing store but different element sizes.
+var b = new ArrayBuffer(4)
+var a5 = new Int16Array(b)
+var a50 = new Int8Array(b)
+var a51 = new Int8Array(b, 0, 2)
+var a52 = new Int8Array(b, 1, 2)
+var a53 = new Int8Array(b, 2, 2)
+
+a5.set([0x5050, 0x0a0a])
+assertArrayPrefix([0x50, 0x50, 0x0a, 0x0a], a50)
+assertArrayPrefix([0x50, 0x50], a51)
+assertArrayPrefix([0x50, 0x0a], a52)
+assertArrayPrefix([0x0a, 0x0a], a53)
+
+a50.set([0x50, 0x50, 0x0a, 0x0a])
+a51.set(a5)
+assertArrayPrefix([0x50, 0x0a, 0x0a, 0x0a], a50)
+
+a50.set([0x50, 0x50, 0x0a, 0x0a])
+a52.set(a5)
+assertArrayPrefix([0x50, 0x50, 0x0a, 0x0a], a50)
+
+a50.set([0x50, 0x50, 0x0a, 0x0a])
+a53.set(a5)
+assertArrayPrefix([0x50, 0x50, 0x50, 0x0a], a50)
+
+a50.set([0x50, 0x51, 0x0a, 0x0b])
+a5.set(a51)
+assertArrayPrefix([0x0050, 0x0051], a5)
+
+a50.set([0x50, 0x51, 0x0a, 0x0b])
+a5.set(a52)
+assertArrayPrefix([0x0051, 0x000a], a5)
+
+a50.set([0x50, 0x51, 0x0a, 0x0b])
+a5.set(a53)
+assertArrayPrefix([0x000a, 0x000b], a5)
+
+// Mixed types of same size.
+var a61 = new Float32Array([1.2, 12.3])
+var a62 = new Int32Array(2)
+a62.set(a61)
+assertArrayPrefix([1, 12], a62)
+a61.set(a62)
+assertArrayPrefix([1, 12], a61)
+
+// Invalid source
+assertThrows(function() { a.set(0) })
+assertThrows(function() { a.set({}) })
+
+
+// Test arraybuffer.slice
+
+var a0 = new Int8Array([1, 2, 3, 4, 5, 6])
+var b0 = a0.buffer
+
+var b1 = b0.slice(0)
+assertEquals(b0.byteLength, b1.byteLength)
+assertArrayPrefix([1, 2, 3, 4, 5, 6], Int8Array(b1))
+
+var b2 = b0.slice(3)
+assertEquals(b0.byteLength - 3, b2.byteLength)
+assertArrayPrefix([4, 5, 6], Int8Array(b2))
+
+var b3 = b0.slice(2, 4)
+assertEquals(2, b3.byteLength)
+assertArrayPrefix([3, 4], Int8Array(b3))
+
+function goo(a, i) {
+  return a[i];
+}
+
+function boo(a, i, v) {
+  return a[i] = v;
+}
+
+function do_tagged_index_external_array_test(constructor) {
+  var t_array = new constructor([1, 2, 3, 4, 5, 6]);
+  assertEquals(1, goo(t_array, 0));
+  assertEquals(1, goo(t_array, 0));
+  boo(t_array, 0, 13);
+  assertEquals(13, goo(t_array, 0));
+  %OptimizeFunctionOnNextCall(goo);
+  %OptimizeFunctionOnNextCall(boo);
+  boo(t_array, 0, 15);
+  assertEquals(15, goo(t_array, 0));
+  %ClearFunctionTypeFeedback(goo);
+  %ClearFunctionTypeFeedback(boo);
+}
+
+do_tagged_index_external_array_test(Int8Array);
+do_tagged_index_external_array_test(Uint8Array);
+do_tagged_index_external_array_test(Int16Array);
+do_tagged_index_external_array_test(Uint16Array);
+do_tagged_index_external_array_test(Int32Array);
+do_tagged_index_external_array_test(Uint32Array);
+do_tagged_index_external_array_test(Float32Array);
+do_tagged_index_external_array_test(Float64Array);
+
+var built_in_array = new Array(1, 2, 3, 4, 5, 6);
+assertEquals(1, goo(built_in_array, 0));
+assertEquals(1, goo(built_in_array, 0));
+%OptimizeFunctionOnNextCall(goo);
+%OptimizeFunctionOnNextCall(boo);
+boo(built_in_array, 0, 11);
+assertEquals(11, goo(built_in_array, 0));
+%ClearFunctionTypeFeedback(goo);
+%ClearFunctionTypeFeedback(boo);
+
+built_in_array = new Array(1.5, 2, 3, 4, 5, 6);
+assertEquals(1.5, goo(built_in_array, 0));
+assertEquals(1.5, goo(built_in_array, 0));
+%OptimizeFunctionOnNextCall(goo);
+%OptimizeFunctionOnNextCall(boo);
+boo(built_in_array, 0, 2.5);
+assertEquals(2.5, goo(built_in_array, 0));
+%ClearFunctionTypeFeedback(goo);
+%ClearFunctionTypeFeedback(boo);
index 0219f39..d60c59c 100644 (file)
@@ -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: --harmony-collections --expose-gc
+// Flags: --harmony-collections --expose-gc --allow-natives-syntax
 
 
 // Test valid getter and setter calls on Sets.
@@ -254,6 +254,27 @@ assertTrue(WeakMap.prototype.has instanceof Function)
 assertTrue(WeakMap.prototype.delete instanceof Function)
 
 
+// Test class of the Set, Map and WeakMap instance and prototype.
+assertEquals("Set", %_ClassOf(new Set))
+assertEquals("Object", %_ClassOf(Set.prototype))
+assertEquals("Map", %_ClassOf(new Map))
+assertEquals("Object", %_ClassOf(Map.prototype))
+assertEquals("WeakMap", %_ClassOf(new WeakMap))
+assertEquals("Object", %_ClassOf(WeakMap.prototype))
+
+
+// Test constructor property of the Set, Map and WeakMap prototype.
+function TestConstructor(C) {
+  assertFalse(C === Object.prototype.constructor);
+  assertSame(C, C.prototype.constructor);
+  assertSame(C, C().__proto__.constructor);
+  assertSame(C, (new C).__proto__.constructor);
+}
+TestConstructor(Set);
+TestConstructor(Map);
+TestConstructor(WeakMap);
+
+
 // Regression test for WeakMap prototype.
 assertTrue(WeakMap.prototype.constructor === WeakMap)
 assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype)
diff --git a/deps/v8/test/mjsunit/harmony/generators-objects.js b/deps/v8/test/mjsunit/harmony/generators-objects.js
new file mode 100644 (file)
index 0000000..0c36818
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2013 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-generators --harmony-scoping
+
+// Test instantations of generators.
+
+// Generators shouldn't allocate stack slots.  This test will abort in debug
+// mode if generators have stack slots.
+function TestContextAllocation() {
+  function* g1(a, b, c) { yield 1; return [a, b, c]; }
+  function* g2() { yield 1; return arguments; }
+  function* g3() { yield 1; return this; }
+  function* g4() { var x = 10; yield 1; return x; }
+  // Temporary variable context allocation
+  function* g5(l) { "use strict"; yield 1; for (let x in l) { yield x; } }
+
+  g1();
+  g2();
+  g3();
+  g4();
+  g5(["foo"]);
+}
+TestContextAllocation();
+
+
+// Test the properties and prototype of a generator object.
+function TestGeneratorObject() {
+  function* g() { yield 1; }
+
+  var iter = g();
+  assertSame(g.prototype, Object.getPrototypeOf(iter));
+  assertTrue(iter instanceof g);
+  assertEquals([], Object.getOwnPropertyNames(iter));
+  assertTrue(iter !== g());
+
+  // g() is the same as new g().
+  iter = new g();
+  assertSame(g.prototype, Object.getPrototypeOf(iter));
+  assertTrue(iter instanceof g);
+  assertEquals([], Object.getOwnPropertyNames(iter));
+  assertTrue(iter !== new g());
+}
+TestGeneratorObject();
index 0e5494d..49a44ba 100644 (file)
@@ -74,7 +74,7 @@ function* g() { yield ({ get yield() { return 1; }}) }
 // mode or in generators.
 function f() { yield: 1 }
 assertThrows("function f() { \"use strict\"; yield: 1 }", SyntaxError)
-assertThrows("function f*() { yield: 1 }", SyntaxError)
+assertThrows("function* g() { yield: 1 }", SyntaxError)
 
 // Yield is only a keyword in the body of the generator, not in nested
 // functions.
diff --git a/deps/v8/test/mjsunit/harmony/generators-runtime.js b/deps/v8/test/mjsunit/harmony/generators-runtime.js
new file mode 100644 (file)
index 0000000..d28140c
--- /dev/null
@@ -0,0 +1,126 @@
+// Copyright 2013 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-generators
+
+// Test aspects of the generator runtime.
+
+// FIXME(wingo): Replace this reference with a more official link.
+// See:
+// http://wiki.ecmascript.org/lib/exe/fetch.php?cache=cache&media=harmony:es6_generator_object_model_3-29-13.png
+
+function f() { }
+function* g() { yield 1; }
+var GeneratorFunctionPrototype = Object.getPrototypeOf(g);
+var GeneratorFunction = GeneratorFunctionPrototype.constructor;
+var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
+
+// A generator function should have the same set of properties as any
+// other function.
+function TestGeneratorFunctionInstance() {
+  var f_own_property_names = Object.getOwnPropertyNames(f);
+  var g_own_property_names = Object.getOwnPropertyNames(g);
+
+  f_own_property_names.sort();
+  g_own_property_names.sort();
+
+  assertArrayEquals(f_own_property_names, g_own_property_names);
+  var i;
+  for (i = 0; i < f_own_property_names.length; i++) {
+    var prop = f_own_property_names[i];
+    var f_desc = Object.getOwnPropertyDescriptor(f, prop);
+    var g_desc = Object.getOwnPropertyDescriptor(g, prop);
+    assertEquals(f_desc.configurable, g_desc.configurable, prop);
+    assertEquals(f_desc.writable, g_desc.writable, prop);
+    assertEquals(f_desc.enumerable, g_desc.enumerable, prop);
+  }
+}
+TestGeneratorFunctionInstance();
+
+
+// Generators have an additional object interposed in the chain between
+// themselves and Function.prototype.
+function TestGeneratorFunctionPrototype() {
+  // Sanity check.
+  assertSame(Object.getPrototypeOf(f), Function.prototype);
+  assertFalse(GeneratorFunctionPrototype === Function.prototype);
+  assertSame(Function.prototype,
+             Object.getPrototypeOf(GeneratorFunctionPrototype));
+  assertSame(GeneratorFunctionPrototype,
+             Object.getPrototypeOf(function* () {}));
+}
+TestGeneratorFunctionPrototype();
+
+
+// Functions that we associate with generator objects are actually defined by
+// a common prototype.
+function TestGeneratorObjectPrototype() {
+  assertSame(Object.prototype,
+             Object.getPrototypeOf(GeneratorObjectPrototype));
+  assertSame(GeneratorObjectPrototype,
+             Object.getPrototypeOf((function*(){yield 1}).prototype));
+
+  var expected_property_names = ["next", "send", "throw", "close",
+                                 "constructor"];
+  var found_property_names =
+      Object.getOwnPropertyNames(GeneratorObjectPrototype);
+
+  expected_property_names.sort();
+  found_property_names.sort();
+
+  assertArrayEquals(expected_property_names, found_property_names);
+}
+TestGeneratorObjectPrototype();
+
+
+// This tests the object that would be called "GeneratorFunction", if it were
+// like "Function".
+function TestGeneratorFunction() {
+  assertSame(GeneratorFunctionPrototype, GeneratorFunction.prototype);
+  assertTrue(g instanceof GeneratorFunction);
+
+  assertSame(Function, Object.getPrototypeOf(GeneratorFunction));
+  assertTrue(g instanceof Function);
+
+  // Not all functions are generators.
+  assertTrue(f instanceof Function);  // Sanity check.
+  assertTrue(!(f instanceof GeneratorFunction));
+}
+TestGeneratorFunction();
+
+
+function TestPerGeneratorPrototype() {
+  assertTrue((function*(){}).prototype !== (function*(){}).prototype);
+  assertTrue((function*(){}).prototype !== g.prototype);
+  assertTrue(g.prototype instanceof GeneratorFunctionPrototype);
+  assertSame(GeneratorObjectPrototype, Object.getPrototypeOf(g.prototype));
+  assertTrue(!(g.prototype instanceof Function));
+  assertSame(typeof (g.prototype), "object");
+
+  assertArrayEquals([], Object.getOwnPropertyNames(g.prototype));
+}
+TestPerGeneratorPrototype();
index a3f6e57..5eaa1a3 100644 (file)
@@ -82,6 +82,23 @@ function TestPrototype() {
 TestPrototype()
 
 
+function TestConstructor() {
+  assertFalse(Object === Symbol.prototype.constructor)
+  assertFalse(Symbol === Object.prototype.constructor)
+  assertSame(Symbol, Symbol.prototype.constructor)
+  assertSame(Symbol, Symbol().__proto__.constructor)
+  assertSame(Symbol, Symbol(Symbol()).__proto__.constructor)
+  assertSame(Symbol, (new Symbol).__proto__.constructor)
+  assertSame(Symbol, (new Symbol()).__proto__.constructor)
+  assertSame(Symbol, (new Symbol(Symbol())).__proto__.constructor)
+  assertSame(Symbol, Object(Symbol()).__proto__.constructor)
+  for (var i in symbols) {
+    assertSame(Symbol, symbols[i].__proto__.constructor)
+  }
+}
+TestConstructor()
+
+
 function TestName() {
   for (var i in symbols) {
     var name = symbols[i].name
index 9b01ba6..75ff3da 100644 (file)
@@ -27,6 +27,8 @@
 
 // Flags: --harmony-typed-arrays
 
+// ArrayBuffer
+
 function TestByteLength(param, expectedByteLength) {
   var ab = new __ArrayBuffer(param);
   assertSame(expectedByteLength, ab.byteLength);
@@ -104,8 +106,98 @@ function TestArrayBufferSlice() {
 
 TestArrayBufferSlice();
 
+// Typed arrays
+
+function TestTypedArray(proto, elementSize, typicalElement) {
+  var ab = new __ArrayBuffer(256*elementSize);
+
+  var a1 = new proto(ab, 128*elementSize, 128);
+  assertSame(ab, a1.buffer);
+  assertSame(elementSize, a1.BYTES_PER_ELEMENT);
+  assertSame(128, a1.length);
+  assertSame(128*elementSize, a1.byteLength);
+  assertSame(128*elementSize, a1.byteOffset);
+
+
+  var a2 = new proto(ab, 64*elementSize, 128);
+  assertSame(ab, a2.buffer);
+  assertSame(elementSize, a2.BYTES_PER_ELEMENT);
+  assertSame(128, a2.length);
+  assertSame(128*elementSize, a2.byteLength);
+  assertSame(64*elementSize, a2.byteOffset);
+
+  var a3 = new proto(ab, 192*elementSize);
+  assertSame(ab, a3.buffer);
+  assertSame(64, a3.length);
+  assertSame(64*elementSize, a3.byteLength);
+  assertSame(192*elementSize, a3.byteOffset);
+
+  var a4 = new proto(ab);
+  assertSame(ab, a4.buffer);
+  assertSame(256, a4.length);
+  assertSame(256*elementSize, a4.byteLength);
+  assertSame(0, a4.byteOffset);
+
+
+  var i;
+  for (i = 0; i < 128; i++) {
+    a1[i] = typicalElement;
+  }
+
+  for (i = 0; i < 128; i++) {
+    assertSame(typicalElement, a1[i]);
+  }
+
+  for (i = 0; i < 64; i++) {
+    assertSame(0, a2[i]);
+  }
+
+  for (i = 64; i < 128; i++) {
+    assertSame(typicalElement, a2[i]);
+  }
+
+  for (i = 0; i < 64; i++) {
+    assertSame(typicalElement, a3[i]);
+  }
+
+  for (i = 0; i < 128; i++) {
+    assertSame(0, a4[i]);
+  }
+
+  for (i = 128; i < 256; i++) {
+    assertSame(typicalElement, a4[i]);
+  }
+
+  assertThrows(function () { new proto(ab, 256*elementSize); }, RangeError);
+
+  if (elementSize !== 1) {
+    assertThrows(function() { new proto(ab, 128*elementSize - 1, 10); },
+                 RangeError);
+    var unalignedArrayBuffer = new __ArrayBuffer(10*elementSize + 1);
+    var goodArray = new proto(unalignedArrayBuffer, 0, 10);
+    assertSame(10, goodArray.length);
+    assertSame(10*elementSize, goodArray.byteLength);
+    assertThrows(function() { new proto(unalignedArrayBuffer)}, RangeError);
+    assertThrows(function() { new proto(unalignedArrayBuffer, 5*elementSize)},
+                 RangeError);
+  }
+
+}
+
+TestTypedArray(__Uint8Array, 1, 0xFF);
+TestTypedArray(__Int8Array, 1, -0x7F);
+TestTypedArray(__Uint16Array, 2, 0xFFFF);
+TestTypedArray(__Int16Array, 2, -0x7FFF);
+TestTypedArray(__Uint32Array, 4, 0xFFFFFFFF);
+TestTypedArray(__Int32Array, 4, -0x7FFFFFFF);
+TestTypedArray(__Float32Array, 4, 0.5);
+TestTypedArray(__Float64Array, 8, 0.5);
+
+
+// General tests for properties
+
 // Test property attribute [[Enumerable]]
-function TestEnumerable(func) {
+function TestEnumerable(func, obj) {
   function props(x) {
     var array = [];
     for (var p in x) array.push(p);
@@ -113,9 +205,11 @@ function TestEnumerable(func) {
   }
   assertArrayEquals([], props(func));
   assertArrayEquals([], props(func.prototype));
-  assertArrayEquals([], props(new func()));
+  if (obj)
+    assertArrayEquals([], props(obj));
 }
-TestEnumerable(__ArrayBuffer);
+TestEnumerable(__ArrayBuffer, new __ArrayBuffer());
+TestEnumerable(__Uint8Array);
 
 
 // Test arbitrary properties on ArrayBuffer
@@ -131,6 +225,5 @@ function TestArbitrary(m) {
 }
 TestArbitrary(new __ArrayBuffer(256));
 
-
 // Test direct constructor call
 assertTrue(__ArrayBuffer() instanceof __ArrayBuffer);
index 1c3602c..09097db 100644 (file)
@@ -44,11 +44,16 @@ regress/regress-524: SKIP
 stack-traces-gc: PASS || FAIL
 
 ##############################################################################
-# Too slow in debug mode with --stress-opt
+# Too slow in debug mode with --stress-opt mode.
 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
+regress/regress-2612: PASS, SKIP if $mode == debug
+
+##############################################################################
+# Too slow in debug mode for GC stress mode.
+regress/regress-crbug-217858: PASS, SKIP if $mode == debug
 
 ##############################################################################
 # These use a built-in that's only present in debug mode. They take
@@ -197,3 +202,34 @@ debug-liveedit-stack-padding: SKIP
 debug-liveedit-restart-frame: SKIP
 debug-liveedit-double-call: SKIP
 
+##############################################################################
+# Native Client uses the ARM simulator so will behave similarly to arm
+# on mjsunit tests.
+# TODO(bradchen): enable more tests for NaCl V8 when it stops using
+# the ARM simulator.
+##############################################################################
+[ $arch == nacl_ia32 || $arch == nacl_x64 ]
+# There is no /tmp directory for NaCl runs
+d8-os: SKIP
+
+# Stack manipulations in LiveEdit is not implemented for this arch.
+debug-liveedit-check-stack: SKIP
+debug-liveedit-stack-padding: SKIP
+debug-liveedit-restart-frame: SKIP
+debug-liveedit-double-call: SKIP
+
+# This test dumps core for arm.debug, so no reason to expect it to work
+# for NaCl. The other three fuzz-natives tests seem to run fine.
+# As noted above none of them are run in the arm.debug case.
+fuzz-natives-part4: SKIP
+
+# Requires bigger stack size in the Genesis and if stack size is increased,
+# the test requires too much time to run.  However, the problem test covers
+# should be platform-independent.
+regress/regress-1132: SKIP
+
+# Poor performance for NaCl V8 causes an assertion failure for this test.
+regress/regress-165637: SKIP
+
+# Skip long running test that times out in debug mode and goes OOM on NaCl.
+regress/regress-crbug-160010: SKIP
index 970a803..835d0e0 100644 (file)
@@ -918,6 +918,11 @@ assertFalse(desc.writable);
 assertFalse(desc.enumerable);
 assertFalse(desc.configurable);
 
+// Define non-array property, check that .length is unaffected.
+assertEquals(16, arr.length);
+Object.defineProperty(arr, '0x20', descElement);
+assertEquals(16, arr.length);
+
 // See issue 968: http://code.google.com/p/v8/issues/detail?id=968
 var o = { x : 42 };
 Object.defineProperty(o, "x", { writable: false });
index 0c307e6..b7db51c 100755 (executable)
 
 // Flags: --allow-natives-syntax
 
-var pixels = new Uint8ClampedArray(8);
+var pixels = new Uint8ClampedArray(11);
 
 function f() {
   for (var i = 0; i < 8; i++) {
     pixels[i] = (i * 1.1);
   }
+  pixels[8] = 255.5;
+  pixels[9] = NaN;
+  pixels[10] = -0.5;
   return pixels[1] + pixels[6];
 }
 
@@ -42,3 +45,6 @@ assertEquals(6, pixels[5]);
 %OptimizeFunctionOnNextCall(f);
 f();
 assertEquals(6, pixels[5]);
+assertEquals(255, pixels[8]);
+assertEquals(0, pixels[9]);
+assertEquals(0, pixels[10]);
diff --git a/deps/v8/test/mjsunit/proto-poison.js b/deps/v8/test/mjsunit/proto-poison.js
new file mode 100644 (file)
index 0000000..ca3b5d6
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2013 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 the __proto__ accessor is properly poisoned when extracted
+// from Object.prototype using the property descriptor.
+var desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
+assertEquals("function", typeof desc.get);
+assertEquals("function", typeof desc.set);
+assertDoesNotThrow("desc.get.call({})");
+assertThrows("desc.set.call({})", TypeError);
+
+// Check that any redefinition of the __proto__ accessor causes poising
+// to cease and the accessor to be extracted normally.
+Object.defineProperty(Object.prototype, "__proto__", { get:function(){} });
+desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
+assertDoesNotThrow("desc.get.call({})");
+assertThrows("desc.set.call({})", TypeError);
+Object.defineProperty(Object.prototype, "__proto__", { set:function(x){} });
+desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
+assertDoesNotThrow("desc.get.call({})");
+assertDoesNotThrow("desc.set.call({})");
diff --git a/deps/v8/test/mjsunit/regress/readonly5.js b/deps/v8/test/mjsunit/regress/readonly5.js
new file mode 100644 (file)
index 0000000..b1499dd
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2013 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.__proto__ = null;
+this.x = 10;
+delete this.x;
+
+function s(v) {
+  return v.x = 1;
+}
+
+function s_strict(v) {
+  "use strict";
+  return v.x = 1;
+}
+
+function c() {
+  var o = {__proto__:this};
+  return o;
+}
+
+var o1 = c();
+var o2 = c();
+var o1_strict = c();
+var o2_strict = c();
+var o3 = c();
+var o4 = c();
+
+// Initialize the store IC.
+s(o1);
+s(o2);
+s_strict(o1_strict);
+s_strict(o2_strict);
+
+Object.defineProperty(this, "x", {writable:false, configurable:true});
+
+// Verify that directly setting x fails.
+o3.x = 1;
+assertEquals(undefined, o3.x);
+
+// Verify that setting x through the IC fails.
+assertThrows("s_strict(o4)", TypeError);
+s(o4);
+assertEquals(undefined, o4.x);
diff --git a/deps/v8/test/mjsunit/regress/regress-2273.js b/deps/v8/test/mjsunit/regress/regress-2273.js
new file mode 100644 (file)
index 0000000..7868b8d
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2013 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 CheckStringReceiver = function() {
+  "use strict";
+  // Receivers of strict functions are not coerced.
+  assertEquals("string", typeof this);
+};
+
+var CheckNumberReceiver = function() {
+  "use strict";
+  // Receivers of strict functions are not coerced.
+  assertEquals("number", typeof this);
+};
+
+var CheckUndefinedReceiver = function() {
+  "use strict";
+  // Receivers of strict functions are not coerced.
+  assertEquals("undefined", String(this));
+};
+
+var CheckNullReceiver = function() {
+  "use strict";
+  // Receivers of strict functions are not coerced.
+  assertEquals("null", String(this));
+};
+
+var CheckCoersion = function() {
+  // Receivers of non-strict functions are coerced to objects.
+  assertEquals("object", typeof this);
+};
+
+
+function strict_mode() {
+  "use strict";
+  CheckStringReceiver.call("foo");
+  CheckNumberReceiver.call(42);
+  CheckUndefinedReceiver.call(undefined);
+  CheckNullReceiver.call(null);
+  [1].forEach(CheckStringReceiver, "foo");
+  [2].every(CheckStringReceiver, "foo");
+  [3].filter(CheckStringReceiver, "foo");
+  [4].some(CheckNumberReceiver, 42);
+  [5].map(CheckNumberReceiver, 42);
+
+  CheckCoersion.call("foo");
+  CheckCoersion.call(42);
+  CheckCoersion.call(undefined);
+  CheckCoersion.call(null);
+  [1].forEach(CheckCoersion, "foo");
+  [2].every(CheckCoersion, "foo");
+  [3].filter(CheckCoersion, "foo");
+  [4].some(CheckCoersion, 42);
+  [5].map(CheckCoersion, 42);
+};
+strict_mode();
+
+function classic_mode() {
+  CheckStringReceiver.call("foo");
+  CheckNumberReceiver.call(42);
+  CheckUndefinedReceiver.call(undefined);
+  CheckNullReceiver.call(null);
+  [1].forEach(CheckStringReceiver, "foo");
+  [2].every(CheckStringReceiver, "foo");
+  [3].filter(CheckStringReceiver, "foo");
+  [4].some(CheckNumberReceiver, 42);
+  [5].map(CheckNumberReceiver, 42);
+
+  CheckCoersion.call("foo");
+  CheckCoersion.call(42);
+  CheckCoersion.call(undefined);
+  CheckCoersion.call(null);
+  [1].forEach(CheckCoersion, "foo");
+  [2].every(CheckCoersion, "foo");
+  [3].filter(CheckCoersion, "foo");
+  [4].some(CheckCoersion, 42);
+  [5].map(CheckCoersion, 42);
+};
+classic_mode();
diff --git a/deps/v8/test/mjsunit/regress/regress-2595.js b/deps/v8/test/mjsunit/regress/regress-2595.js
new file mode 100644 (file)
index 0000000..5bb5f6d
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2013 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 p = { f: function () { return "p"; } };
+var o = Object.create(p);
+o.x = true;
+delete o.x;  // slow case object
+
+var u = { x: 0, f: function () { return "u"; } };  // object with some other map
+
+function F(x) {
+  return x.f();
+}
+
+// First make CALL IC in F go MEGAMORPHIC and ensure that we put the stub
+// that calls p.f (guarded by a negative dictionary lookup on the reciever)
+// into the stub cache
+assertEquals("p", F(o));
+assertEquals("p", F(o));
+assertEquals("u", F(u));
+assertEquals("p", F(o));
+assertEquals("u", F(u));
+
+// Optimize F. We will inline p.f into F guarded by map checked against
+// receiver which does not work for slow case objects.
+%OptimizeFunctionOnNextCall(F);
+assertEquals("p", F(o));
+
+// Add f to o. o's map will *not* change.
+o.f = function () { return "o"; };
+assertEquals("o", F(o));
diff --git a/deps/v8/test/mjsunit/regress/regress-2606.js b/deps/v8/test/mjsunit/regress/regress-2606.js
new file mode 100644 (file)
index 0000000..b704f7d
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2013 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 baseline for __proto__.
+var desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
+assertFalse(desc.enumerable);
+assertTrue(desc.configurable);
+assertEquals("function", typeof desc.get);
+assertEquals("function", typeof desc.set);
+
+// Check redefining getter for __proto__.
+function replaced_get() {};
+Object.defineProperty(Object.prototype, "__proto__", { get:replaced_get });
+desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
+assertFalse(desc.enumerable);
+assertTrue(desc.configurable);
+assertSame(replaced_get, desc.get);
+
+// Check redefining setter for __proto__.
+function replaced_set(x) {};
+Object.defineProperty(Object.prototype, "__proto__", { set:replaced_set });
+desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
+assertFalse(desc.enumerable);
+assertTrue(desc.configurable);
+assertSame(replaced_set, desc.set);
+
+// Check changing configurability of __proto__.
+Object.defineProperty(Object.prototype, "__proto__", { configurable:false });
+desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
+assertFalse(desc.enumerable);
+assertFalse(desc.configurable);
+assertSame(replaced_get, desc.get);
+assertSame(replaced_set, desc.set);
+
+// Check freezing Object.prototype completely.
+Object.freeze(Object.prototype);
+assertTrue(Object.isFrozen(Object.prototype));
diff --git a/deps/v8/test/mjsunit/regress/regress-2612.js b/deps/v8/test/mjsunit/regress/regress-2612.js
new file mode 100644 (file)
index 0000000..06db077
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2013 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 --nodead-code-elimination
+// Flags: --nofold-constants --nouse-gvn
+
+// Create a function to get a long series of removable simulates.
+// f() {
+//   var _0 = <random>, _1 = <random>, ... _1000 = <random>,
+//   _1001 = <random var> + <random var>,
+//   _1002 = <random var> + <random var>,
+//   ...
+//   _99999 = <random var> + <random var>,
+//   x = 1;
+//   return _0;
+// }
+
+var seed = 1;
+
+function rand() {
+  seed = seed * 171 % 1337 + 17;
+  return (seed % 1000) / 1000;
+}
+
+function randi(max) {
+  seed = seed * 131 % 1773 + 13;
+  return seed % max;
+}
+
+function varname(i) {
+  return "_" + i;
+}
+
+var source = "var ";
+
+for (var i = 0; i < 1000; i++) {
+  source += [varname(i), "=", rand(), ","].join("");
+}
+
+for (var i = 1000; i < 100000; i++) {
+  source += [varname(i), "=",
+             varname(randi(i)), "+",
+             varname(randi(i)), ","].join("");
+}
+
+source += "x=1; return _0;"
+var f = new Function(source);
+
+f();
+%OptimizeFunctionOnNextCall(f);
+f();
+
diff --git a/deps/v8/test/mjsunit/regress/regress-2618.js b/deps/v8/test/mjsunit/regress/regress-2618.js
new file mode 100644 (file)
index 0000000..638b71e
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2013 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: --use-osr --allow-natives-syntax
+
+function f() {
+  do {
+    do {
+      for (i = 0; i < 10000000; i++) {
+        // This should run long enough to trigger OSR.
+      }
+    } while (false);
+  } while (false);
+}
+
+f();
+assertTrue(%GetOptimizationStatus(f) != 2);
+
+
+function g() {
+  for (var i = 0; i < 1; i++) { }
+
+  do {
+    do {
+      for (i = 0; i < 1; i++) { }
+    } while (false);
+  } while (false);
+
+  do {
+    do {
+      do {
+        do {
+          do {
+            do {
+              do {
+                do {
+                  for (i = 0; i < 10000000; i++) { }
+                } while (false);
+              } while (false);
+            } while (false);
+          } while (false);
+        } while (false);
+      } while (false);
+    } while (false);
+  } while (false);
+}
+
+g();
+assertTrue(%GetOptimizationStatus(g) != 2);
+
diff --git a/deps/v8/test/mjsunit/regress/regress-2624.js b/deps/v8/test/mjsunit/regress/regress-2624.js
new file mode 100644 (file)
index 0000000..2bfd7b2
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2013 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: --print-code
+
+var source = '"snowmen invasion " + "';
+for(var i = 0; i < 800; i++) {
+  source += '\u2603';
+}
+source += '"';
+eval(source);
+
diff --git a/deps/v8/test/mjsunit/regress/regress-581.js b/deps/v8/test/mjsunit/regress/regress-581.js
new file mode 100644 (file)
index 0000000..65cd87d
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2013 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 pow30 = Math.pow(2, 30);
+var pow31 = Math.pow(2, 31);
+
+var a = [];
+a[pow31] = 31;
+
+assertEquals(pow31 + 1, a.length);
+assertThrows(function() { a.concat(a); }, RangeError);
+
+var b = [];
+b[pow31 - 2] = 32;
+var ab = a.concat(b);
+assertEquals(2 * pow31 - 1, ab.length);
+assertEquals(31, ab[pow31]);
+assertEquals(32, ab[2 * pow31 - 1]);
+
+var c = [];
+c[pow30] = 30;
+assertThrows(function() { c.concat(c, a); }, RangeError);
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-229923.js b/deps/v8/test/mjsunit/regress/regress-crbug-229923.js
new file mode 100644 (file)
index 0000000..95c0ded
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2013 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-externalize-string
+
+var slice = "slow path of JSON.stringify for sliced string".substring(1);
+assertEquals('"' + slice + '"', JSON.stringify(slice, null, 0));
+
+var parent = "external string turned into two byte";
+var slice_of_external = parent.substring(1);
+try {
+  // Turn the string to a two-byte external string, so that the sliced
+  // string looks like one-byte, but its parent is actually two-byte.
+  externalizeString(parent, true);
+} catch (e) { }
+assertEquals('"' + slice_of_external + '"',
+             JSON.stringify(slice_of_external, null, 0));
index c0a71bf..4b355ae 100644 (file)
@@ -39,3 +39,13 @@ json1 = JSON.stringify(a);
 json2 = JSON.stringify(a);
 assertTrue(json1 == json2, "GC caused JSON.stringify to fail.");
 
+// Check that the slow path of JSON.stringify works correctly wrt GC.
+for (var i = 0; i < 100000; i++) {
+  var s = i.toString();
+  assertEquals('"' + s + '"', JSON.stringify(s, null, 0));
+}
+
+for (var i = 0; i < 100000; i++) {
+  var s = i.toString() + "\u2603";
+  assertEquals('"' + s + '"', JSON.stringify(s, null, 0));
+}
index b117553..d285205 100644 (file)
               # The dependency on v8_base should come from a transitive
               # dependency however the Android toolchain requires libv8_base.a
               # to appear before libv8_snapshot.a so it's listed explicitly.
-              'dependencies': ['v8_base', 'v8_snapshot'],
+              'dependencies': ['v8_base.<(v8_target_arch)', 'v8_snapshot'],
             },
             {
               # The dependency on v8_base should come from a transitive
               # dependency however the Android toolchain requires libv8_base.a
               # to appear before libv8_snapshot.a so it's listed explicitly.
-              'dependencies': ['v8_base', 'v8_nosnapshot'],
+              'dependencies': [
+                'v8_base.<(v8_target_arch)',
+                'v8_nosnapshot.<(v8_target_arch)',
+              ],
             }],
             ['component=="shared_library"', {
               'type': '<(component)',
           'conditions': [
             ['want_separate_host_toolset==1', {
               'toolsets': ['host', 'target'],
-              'dependencies': ['mksnapshot#host', 'js2c#host'],
+              'dependencies': [
+                'mksnapshot.<(v8_target_arch)#host',
+                'js2c#host',
+              ],
             }, {
               'toolsets': ['target'],
-              'dependencies': ['mksnapshot', 'js2c'],
+              'dependencies': ['mksnapshot.<(v8_target_arch)', 'js2c'],
             }],
             ['component=="shared_library"', {
               'defines': [
             }],
           ],
           'dependencies': [
-            'v8_base',
+            'v8_base.<(v8_target_arch)',
           ],
           'include_dirs+': [
             '../../src',
             {
               'action_name': 'run_mksnapshot',
               'inputs': [
-                '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot<(EXECUTABLE_SUFFIX)',
+                '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mksnapshot.<(v8_target_arch)<(EXECUTABLE_SUFFIX)',
               ],
               'outputs': [
                 '<(INTERMEDIATE_DIR)/snapshot.cc',
                   '--logfile', '<(INTERMEDIATE_DIR)/snapshot.log',
                 ],
               },
-              'conditions': [
-                ['v8_target_arch=="arm"', {
-                  # The following rules should be consistent with chromium's
-                  # common.gypi and V8's runtime rule to ensure they all generate
-                  # the same correct machine code. The following issue is about
-                  # V8's runtime rule about vfpv3 and neon:
-                  # http://code.google.com/p/v8/issues/detail?id=914
-                  'conditions': [
-                    ['armv7==1', {
-                      # The ARM Architecture Manual mandates VFPv3 if NEON is
-                      # available.
-                      # V8 does not use d16-d31 unless explicitly enabled
-                      # (--enable_32dregs) or detected at run-time, so for vfpv3-d16,
-                      # we can also enable vfp3 for the better performance.
-                      'conditions': [
-                        ['arm_neon!=1 and arm_fpu!="vfpv3" and arm_fpu!="vfpv3-d16"', {
-                          'variables': {
-                            'mksnapshot_flags': [
-                              '--noenable_vfp3',
-                            ],
-                          },
-                        }],
-                      ],
-                    },{ # else: armv7!=1
-                      'variables': {
-                        'mksnapshot_flags': [
-                          '--noenable_armv7',
-                          '--noenable_vfp3',
-                        ],
-                      },
-                    }],
-                  ],
-                }],
-              ],
               'action': [
                 '<@(_inputs)',
                 '<@(mksnapshot_flags)',
           ],
         },
         {
-          'target_name': 'v8_nosnapshot',
+          'target_name': 'v8_nosnapshot.<(v8_target_arch)',
           'type': 'static_library',
           'dependencies': [
-            'v8_base',
+            'v8_base.<(v8_target_arch)',
           ],
           'include_dirs+': [
             '../../src',
           ]
         },
         {
-          'target_name': 'v8_base',
+          'target_name': 'v8_base.<(v8_target_arch)',
           'type': 'static_library',
           'variables': {
             'optimize': 'max',
             '../../src/runtime.h',
             '../../src/safepoint-table.cc',
             '../../src/safepoint-table.h',
+            '../../src/sampler.cc',
+            '../../src/sampler.h',
             '../../src/scanner-character-streams.cc',
             '../../src/scanner-character-streams.h',
             '../../src/scanner.cc',
               ]},
             ],
             ['OS=="win"', {
-              'sources': [
-                '../../src/platform-win32.cc',
-                '../../src/win32-math.cc',
-                '../../src/win32-math.h',
-              ],
-              'msvs_disabled_warnings': [4351, 4355, 4800],
-              'link_settings':  {
-                'libraries': [ '-lwinmm.lib', '-lws2_32.lib' ],
+              'variables': {
+                'gyp_generators': '<!(echo $GYP_GENERATORS)',
               },
+              'conditions': [
+                ['gyp_generators=="make"', {
+                  'variables': {
+                    'build_env': '<!(uname -o)',
+                  },
+                  'conditions': [
+                    ['build_env=="Cygwin"', {
+                      'sources': [
+                        '../../src/platform-cygwin.cc',
+                        '../../src/platform-posix.cc',
+                      ],
+                    }, {
+                      'sources': [
+                        '../../src/platform-win32.cc',
+                        '../../src/win32-math.h',
+                        '../../src/win32-math.cc',
+                      ],
+                    }],
+                  ],
+                  'link_settings':  {
+                    'libraries': [ '-lwinmm', '-lws2_32' ],
+                  },
+                }, {
+                  'sources': [
+                    '../../src/platform-win32.cc',
+                    '../../src/win32-math.h',
+                    '../../src/win32-math.cc',
+                  ],
+                  'msvs_disabled_warnings': [4351, 4355, 4800],
+                  'link_settings':  {
+                    'libraries': [ '-lwinmm.lib', '-lws2_32.lib' ],
+                  },
+                }],
+              ],
             }],
             ['component=="shared_library"', {
               'defines': [
               '../../src/proxy.js',
               '../../src/collection.js',
               '../../src/object-observe.js',
-              '../../src/typedarray.js'
+              '../../src/typedarray.js',
+              '../../src/generator.js'
             ],
           },
           'actions': [
            ]
         },
         {
-          'target_name': 'mksnapshot',
+          'target_name': 'mksnapshot.<(v8_target_arch)',
           'type': 'executable',
           'dependencies': [
-            'v8_base',
-            'v8_nosnapshot',
+            'v8_base.<(v8_target_arch)',
+            'v8_nosnapshot.<(v8_target_arch)',
           ],
           'include_dirs+': [
             '../../src',
             }],
           ],
         },
-        {
-          'target_name': 'preparser_lib',
-          'type': 'static_library',
-          'include_dirs+': [
-            '../../src',
-          ],
-          'sources': [
-            '../../include/v8-preparser.h',
-            '../../include/v8stdint.h',
-            '../../src/allocation.cc',
-            '../../src/allocation.h',
-            '../../src/atomicops.h',
-            '../../src/atomicops_internals_x86_gcc.cc',
-            '../../src/bignum.cc',
-            '../../src/bignum.h',
-            '../../src/bignum-dtoa.cc',
-            '../../src/bignum-dtoa.h',
-            '../../src/cached-powers.cc',
-            '../../src/cached-powers.h',
-            '../../src/char-predicates-inl.h',
-            '../../src/char-predicates.h',
-            '../../src/checks.h',
-            '../../src/conversions-inl.h',
-            '../../src/conversions.cc',
-            '../../src/conversions.h',
-            '../../src/diy-fp.cc',
-            '../../src/diy-fp.h',
-            '../../src/double.h',
-            '../../src/dtoa.cc',
-            '../../src/dtoa.h',
-            '../../src/fast-dtoa.cc',
-            '../../src/fast-dtoa.h',
-            '../../src/fixed-dtoa.cc',
-            '../../src/fixed-dtoa.h',
-            '../../src/globals.h',
-            '../../src/hashmap.h',
-            '../../src/list-inl.h',
-            '../../src/list.h',
-            '../../src/once.cc',
-            '../../src/once.h',
-            '../../src/preparse-data-format.h',
-            '../../src/preparse-data.cc',
-            '../../src/preparse-data.h',
-            '../../src/preparser.cc',
-            '../../src/preparser.h',
-            '../../src/preparser-api.cc',
-            '../../src/scanner.cc',
-            '../../src/scanner.h',
-            '../../src/strtod.cc',
-            '../../src/strtod.h',
-            '../../src/token.cc',
-            '../../src/token.h',
-            '../../src/unicode-inl.h',
-            '../../src/unicode.cc',
-            '../../src/unicode.h',
-            '../../src/utils-inl.h',
-            '../../src/utils.cc',
-            '../../src/utils.h',
-          ],
-          'conditions': [
-            ['OS=="win"', {
-              'sources': [
-                '../../src/win32-math.cc',
-                '../../src/win32-math.h',
-              ]}],
-          ],
-        },
       ],
     }, { # use_system_v8 != 0
       'targets': [
diff --git a/deps/v8/tools/mingw-generate-makefiles.sh b/deps/v8/tools/mingw-generate-makefiles.sh
new file mode 100755 (executable)
index 0000000..32af52d
--- /dev/null
@@ -0,0 +1,97 @@
+#!/bin/sh
+# Copyright 2013 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.
+
+# Monkey-patch GYP.
+cat > build/gyp/gyp.mingw << EOF
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+# TODO(mark): sys.path manipulation is some temporary testing stuff.
+try:
+  import gyp
+except ImportError, e:
+  import os.path
+  sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'pylib'))
+  import gyp
+  
+def MonkeyBuildFileTargets(target_list, build_file):
+  """From a target_list, returns the subset from the specified build_file.
+  """
+  build_file = build_file.replace('/', '\\\\')
+  return [p for p in target_list if gyp.common.BuildFile(p) == build_file]
+gyp.common.BuildFileTargets = MonkeyBuildFileTargets
+
+import gyp.generator.make
+import os
+def Monkey_ITIP(self):
+  """Returns the location of the final output for an installable target."""
+  sep = os.path.sep
+  # Xcode puts shared_library results into PRODUCT_DIR, and some gyp files
+  # rely on this. Emulate this behavior for mac.
+  if (self.type == 'shared_library' and
+      (self.flavor != 'mac' or self.toolset != 'target')):
+    # Install all shared libs into a common directory (per toolset) for
+    # convenient access with LD_LIBRARY_PATH.
+    return '\$(builddir)%slib.%s%s%s' % (sep, self.toolset, sep, self.alias)
+  return '\$(builddir)' + sep + self.alias
+gyp.generator.make.MakefileWriter._InstallableTargetInstallPath = Monkey_ITIP
+
+if __name__ == '__main__':
+  sys.exit(gyp.main(sys.argv[1:]))
+EOF
+
+# Delete old generated Makefiles.
+find out -name '*.mk' -or -name 'Makefile*' -exec rm {} \;
+
+# Generate fresh Makefiles.
+mv build/gyp/gyp build/gyp/gyp.original
+mv build/gyp/gyp.mingw build/gyp/gyp
+make out/Makefile.ia32
+mv build/gyp/gyp build/gyp/gyp.mingw
+mv build/gyp/gyp.original build/gyp/gyp
+
+# Patch generated Makefiles: replace most backslashes with forward slashes,
+# fix library names in linker flags.
+FILES=$(find out -name '*.mk' -or -name 'Makefile*')
+for F in $FILES ; do
+  echo "Patching $F..."
+  cp $F $F.orig
+  cat $F.orig \
+    | sed -e 's|\([)a-zA-Z0-9]\)\\\([a-zA-Z]\)|\1/\2|g' \
+          -e 's|\([)a-zA-Z0-9]\)\\\\\([a-zA-Z]\)|\1/\2|g' \
+          -e 's|'%s/n'|'%s\\\\n'|g' \
+          -e 's|-lwinmm\.lib|-lwinmm|g' \
+          -e 's|-lws2_32\.lib|-lws2_32|g' \
+    > $F
+  rm $F.orig
+done
diff --git a/deps/v8/tools/nacl-run.py b/deps/v8/tools/nacl-run.py
new file mode 100755 (executable)
index 0000000..135172c
--- /dev/null
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 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 script executes the passed command line using the Native Client
+# 'sel_ldr' container. It is derived from android-run.py.
+
+import os
+from os.path import join, dirname, abspath
+import subprocess
+import sys
+import tempfile
+
+def Check(output, errors):
+  failed = any([s.startswith('/system/bin/sh:') or s.startswith('ANDROID')
+                for s in output.split('\n')])
+  return 1 if failed else 0
+
+def Execute(cmdline):
+  (fd_out, outname) = tempfile.mkstemp()
+  (fd_err, errname) = tempfile.mkstemp()
+  process = subprocess.Popen(
+    args=cmdline,
+    shell=True,
+    stdout=fd_out,
+    stderr=fd_err,
+  )
+  exit_code = process.wait()
+  os.close(fd_out)
+  os.close(fd_err)
+  output = file(outname).read()
+  errors = file(errname).read()
+  os.unlink(outname)
+  os.unlink(errname)
+  sys.stdout.write(output)
+  sys.stderr.write(errors)
+  return exit_code or Check(output, errors)
+
+def Escape(arg):
+  def ShouldEscape():
+    for x in arg:
+      if not x.isalnum() and x != '-' and x != '_':
+        return True
+    return False
+
+  return arg if not ShouldEscape() else '"%s"' % (arg.replace('"', '\\"'))
+
+def WriteToTemporaryFile(data):
+  (fd, fname) = tempfile.mkstemp()
+  os.close(fd)
+  tmp_file = open(fname, "w")
+  tmp_file.write(data)
+  tmp_file.close()
+  return fname
+
+def GetNaClArchFromNexe(nexe):
+  try:
+    p = subprocess.Popen(['file', nexe], stdout=subprocess.PIPE)
+    out, err = p.communicate()
+    lines = out.split('\n')
+    if lines[0].find(": ELF 32-bit LSB executable, Intel 80386") > 0:
+      return "x86_32"
+    if lines[0].find(": ELF 64-bit LSB executable, x86-64") > 0:
+      return "x86_64"
+  except:
+    print 'file ' + sys.argv[1] + ' failed'
+  return None
+
+def GetNaClResources(nexe):
+  nacl_sdk_dir = os.environ["NACL_SDK_ROOT"]
+  nacl_arch = GetNaClArchFromNexe(nexe)
+  if sys.platform.startswith("linux"):
+    platform = "linux"
+  elif sys.platform == "darwin":
+    platform = "mac"
+  else:
+    print("NaCl V8 testing is supported on Linux and MacOS only.")
+    sys.exit(1)
+
+  if nacl_arch is "x86_64":
+    toolchain = platform + "_x86_glibc"
+    sel_ldr = "sel_ldr_x86_64"
+    irt = "irt_core_x86_64.nexe"
+    libdir = "lib64"
+  elif nacl_arch is "x86_32":
+    toolchain = platform + "_x86_glibc"
+    sel_ldr = "sel_ldr_x86_32"
+    irt = "irt_core_x86_32.nexe"
+    libdir = "lib32"
+  elif nacl_arch is "arm":
+    print("NaCl V8 ARM support is not ready yet.")
+    sys.exit(1)
+  else:
+    print("Invalid nexe %s" % nexe)
+    sys.exit(1)
+
+  nacl_sel_ldr = os.path.join(nacl_sdk_dir, "tools", sel_ldr)
+  nacl_irt = os.path.join(nacl_sdk_dir, "tools", irt)
+  nacl_ld_so = os.path.join(nacl_sdk_dir, "toolchain", toolchain,
+                            "x86_64-nacl", libdir, "runnable-ld.so")
+  nacl_lib_path = os.path.join(nacl_sdk_dir, "toolchain", toolchain,
+                               "x86_64-nacl", libdir)
+
+  return (nacl_sdk_dir, nacl_sel_ldr, nacl_irt, nacl_ld_so, nacl_lib_path)
+
+def Main():
+  if (len(sys.argv) == 1):
+    print("Usage: %s <command-to-run-on-device>" % sys.argv[0])
+    return 1
+
+  args = [Escape(arg) for arg in sys.argv[1:]]
+
+  (nacl_sdk_dir, nacl_sel_ldr, nacl_irt, nacl_ld_so,
+   nacl_lib_path) = GetNaClResources(sys.argv[1])
+
+  # sel_ldr Options:
+  # -c -c: disable validation (for performance)
+  # -a: allow file access
+  # -B <irt>: load the IRT
+  command = ' '.join([nacl_sel_ldr, '-c', '-c', '-a', '-B', nacl_irt, '--',
+                     nacl_ld_so, '--library-path', nacl_lib_path] + args)
+  error_code = Execute(command)
+  return error_code
+
+if __name__ == '__main__':
+  sys.exit(Main())
index efa8724..616505f 100755 (executable)
@@ -228,6 +228,15 @@ class CppLintProcessor(SourceFileProcessor):
   def GetPathsToSearch(self):
     return ['src', 'preparser', 'include', 'samples', join('test', 'cctest')]
 
+  def GetCpplintScript(self, prio_path):
+    for path in [prio_path] + os.environ["PATH"].split(os.pathsep):
+      path = path.strip('"')
+      cpplint = os.path.join(path, "cpplint.py")
+      if os.path.isfile(cpplint):
+        return cpplint
+
+    return None
+
   def ProcessFiles(self, files, path):
     good_files_cache = FileContentsCache('.cpplint-cache')
     good_files_cache.Load()
@@ -237,10 +246,14 @@ class CppLintProcessor(SourceFileProcessor):
       return True
 
     filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES])
-    command = ['cpplint.py', '--filter', filt]
-    local_cpplint = join(path, "tools", "cpplint.py")
-    if exists(local_cpplint):
-      command = ['python', local_cpplint, '--filter', filt]
+    command = [sys.executable, 'cpplint.py', '--filter', filt]
+    cpplint = self.GetCpplintScript(join(path, "tools"))
+    if cpplint is None:
+      print('Could not find cpplint.py. Make sure '
+            'depot_tools is installed and in the path.')
+      sys.exit(1)
+
+    command = [sys.executable, cpplint, '--filter', filt]
 
     commands = join([command + [file] for file in files])
     count = multiprocessing.cpu_count()
index cb64b45..959fe48 100755 (executable)
@@ -68,12 +68,16 @@ SUPPORTED_ARCHS = ["android_arm",
                    "arm",
                    "ia32",
                    "mipsel",
+                   "nacl_ia32",
+                   "nacl_x64",
                    "x64"]
 # Double the timeout for these:
 SLOW_ARCHS = ["android_arm",
               "android_ia32",
               "arm",
-              "mipsel"]
+              "mipsel",
+              "nacl_ia32",
+              "nacl_x64"]
 
 
 def BuildOptions():
@@ -145,6 +149,10 @@ def BuildOptions():
                     default=False, action="store_true")
   result.add_option("--warn-unused", help="Report unused rules",
                     default=False, action="store_true")
+  result.add_option("--junitout", help="File name of the JUnit output")
+  result.add_option("--junittestsuite",
+                    help="The testsuite name in the JUnit output file",
+                    default="v8tests")
   return result
 
 
@@ -332,6 +340,9 @@ def Execute(arch, mode, args, options, suites, workspace):
   try:
     start_time = time.time()
     progress_indicator = progress.PROGRESS_INDICATORS[options.progress]()
+    if options.junitout:
+      progress_indicator = progress.JUnitTestProgressIndicator(
+          progress_indicator, options.junitout, options.junittestsuite)
 
     run_networked = not options.no_network
     if not run_networked:
diff --git a/deps/v8/tools/testrunner/local/junit_output.py b/deps/v8/tools/testrunner/local/junit_output.py
new file mode 100644 (file)
index 0000000..437adb1
--- /dev/null
@@ -0,0 +1,49 @@
+# Copyright 2013 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 xml.etree.ElementTree as xml
+
+
+class JUnitTestOutput:
+  def __init__(self, test_suite_name):
+    self.root = xml.Element("testsuite")
+    self.root.attrib["name"] = test_suite_name
+
+  def HasRunTest(self, test_name, test_duration, test_failure):
+    testCaseElement = xml.Element("testcase")
+    testCaseElement.attrib["name"] = " ".join(test_name)
+    testCaseElement.attrib["time"] = str(round(test_duration, 3))
+    if len(test_failure):
+      failureElement = xml.Element("failure")
+      failureElement.text = test_failure
+      testCaseElement.append(failureElement)
+    self.root.append(testCaseElement)
+
+  def FinishAndWrite(self, file):
+    xml.ElementTree(self.root).write(file, "UTF-8")
+
index 9075a95..c13c0eb 100644 (file)
@@ -29,6 +29,8 @@
 import sys
 import time
 
+from . import junit_output
+
 def EscapeCommand(command):
   parts = []
   for part in command:
@@ -230,6 +232,50 @@ class MonochromeProgressIndicator(CompactProgressIndicator):
     print ("\r" + (" " * last_line_length) + "\r"),
 
 
+class JUnitTestProgressIndicator(ProgressIndicator):
+
+  def __init__(self, progress_indicator, junitout, junittestsuite):
+    self.progress_indicator = progress_indicator
+    self.outputter = junit_output.JUnitTestOutput(junittestsuite)
+    if junitout:
+      self.outfile = open(junitout, "w")
+    else:
+      self.outfile = sys.stdout
+
+  def Starting(self):
+    self.progress_indicator.runner = self.runner
+    self.progress_indicator.Starting()
+
+  def Done(self):
+    self.progress_indicator.Done()
+    self.outputter.FinishAndWrite(self.outfile)
+    if self.outfile != sys.stdout:
+      self.outfile.close()
+
+  def AboutToRun(self, test):
+    self.progress_indicator.AboutToRun(test)
+
+  def HasRun(self, test):
+    self.progress_indicator.HasRun(test)
+    fail_text = ""
+    if test.suite.HasUnexpectedOutput(test):
+      stdout = test.output.stdout.strip()
+      if len(stdout):
+        fail_text += "stdout:\n%s\n" % stdout
+      stderr = test.output.stderr.strip()
+      if len(stderr):
+        fail_text += "stderr:\n%s\n" % stderr
+      fail_text += "Command: %s" % EscapeCommand(self.runner.GetCommand(test))
+      if test.output.HasCrashed():
+        fail_text += "exit code: %d\n--- CRASHED ---" % test.output.exit_code
+      if test.output.HasTimedOut():
+        fail_text += "--- TIMEOUT ---"
+    self.outputter.HasRunTest(
+        [test.GetLabel()] + self.runner.context.mode_flags + test.flags,
+        test.duration,
+        fail_text)
+
+
 PROGRESS_INDICATORS = {
   'verbose': VerboseProgressIndicator,
   'dots': DotsProgressIndicator,
index bf1de45..634fe6a 100644 (file)
@@ -59,7 +59,7 @@ DEFS = {FAIL_OK: [FAIL, OKAY],
 # 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"]:
+            "mipsel", "x64", "nacl_ia32", "nacl_x64"]:
   VARIABLES[var] = var
 
 
index c9ee101..0ffe734 100644 (file)
@@ -170,7 +170,7 @@ function TickProcessor(
           processor: this.processSnapshotPosition },
       'tick': {
           parsers: [parseInt, parseInt, parseInt, parseInt,
-                    parseInt, parseInt, 'var-args'],
+                    parseInt, 'var-args'],
           processor: this.processTick },
       'heap-sample-begin': { parsers: [null, null, parseInt],
           processor: this.processHeapSampleBegin },
@@ -368,8 +368,7 @@ TickProcessor.prototype.includeTick = function(vmState) {
 TickProcessor.prototype.processTick = function(pc,
                                                sp,
                                                ns_since_start,
-                                               is_external_callback,
-                                               tos_or_external_callback,
+                                               external_callback,
                                                vmState,
                                                stack) {
   this.distortion += this.distortion_per_entry;
@@ -383,23 +382,15 @@ TickProcessor.prototype.processTick = function(pc,
     this.ticks_.excluded++;
     return;
   }
-  if (is_external_callback) {
+  if (external_callback) {
     // Don't use PC when in external callback code, as it can point
     // inside callback's code, and we will erroneously report
     // that a callback calls itself. Instead we use tos_or_external_callback,
     // as simply resetting PC will produce unaccounted ticks.
-    pc = tos_or_external_callback;
-    tos_or_external_callback = 0;
-  } else if (tos_or_external_callback) {
-    // Find out, if top of stack was pointing inside a JS function
-    // meaning that we have encountered a frameless invocation.
-    var funcEntry = this.profile_.findEntry(tos_or_external_callback);
-    if (!funcEntry || !funcEntry.isJSFunction || !funcEntry.isJSFunction()) {
-      tos_or_external_callback = 0;
-    }
-  }
+    pc = 0;
+ }
 
-  this.profile_.recordTick(this.processStack(pc, tos_or_external_callback, stack));
+  this.profile_.recordTick(this.processStack(pc, external_callback, stack));
 };