Revision: 12994
Author:
yan...@chromium.org
Date: Fri Nov 16 06:43:43 2012
Log: Version 3.15.4
Fixed Array.prototype.join evaluation order. (issue 2263)
Perform CPU sampling by CPU sampling thread only iff processing thread is
not running. (issue 2364)
When using an Object as a set in Object.getOwnPropertyNames, null out the
proto. (issue 2410)
Disabled EXTRA_CHECKS in Release build.
Heap explorer: Show representation of strings.
Removed 'type' and 'arguments' properties from Error object. (issue 2397)
Added atomics implementation for ThreadSanitizer v2. (Chromium issue 128314)
Fixed LiveEdit crashes when object/array literal is added. (issue 2368)
Performance and stability improvements on all platforms.
http://code.google.com/p/v8/source/detail?r=12994
Added:
/trunk/src/atomicops_internals_tsan.h
/trunk/test/mjsunit/array-natives-elements.js
/trunk/test/mjsunit/compiler/multiply-add.js
/trunk/test/mjsunit/debug-liveedit-literals.js
/trunk/test/mjsunit/manual-parallel-recompile.js
/trunk/test/mjsunit/regress/regress-2263.js
/trunk/test/mjsunit/regress/regress-2410.js
Modified:
/trunk/.gitignore
/trunk/ChangeLog
/trunk/build/common.gypi
/trunk/src/accessors.cc
/trunk/src/api.cc
/trunk/src/arm/assembler-arm.cc
/trunk/src/arm/assembler-arm.h
/trunk/src/arm/code-stubs-arm.cc
/trunk/src/arm/code-stubs-arm.h
/trunk/src/arm/codegen-arm.cc
/trunk/src/arm/disasm-arm.cc
/trunk/src/arm/full-codegen-arm.cc
/trunk/src/arm/ic-arm.cc
/trunk/src/arm/lithium-arm.cc
/trunk/src/arm/lithium-arm.h
/trunk/src/arm/lithium-codegen-arm.cc
/trunk/src/arm/macro-assembler-arm.cc
/trunk/src/arm/macro-assembler-arm.h
/trunk/src/arm/simulator-arm.cc
/trunk/src/arm/stub-cache-arm.cc
/trunk/src/array.js
/trunk/src/ast.cc
/trunk/src/ast.h
/trunk/src/atomicops.h
/trunk/src/bootstrapper.h
/trunk/src/builtins.cc
/trunk/src/code-stubs.cc
/trunk/src/code-stubs.h
/trunk/src/compiler.cc
/trunk/src/cpu-profiler-inl.h
/trunk/src/cpu-profiler.cc
/trunk/src/cpu-profiler.h
/trunk/src/d8.cc
/trunk/src/date.js
/trunk/src/elements.cc
/trunk/src/elements.h
/trunk/src/execution.cc
/trunk/src/factory.cc
/trunk/src/factory.h
/trunk/src/flag-definitions.h
/trunk/src/handles.h
/trunk/src/heap-inl.h
/trunk/src/heap.cc
/trunk/src/heap.h
/trunk/src/hydrogen-instructions.cc
/trunk/src/hydrogen-instructions.h
/trunk/src/hydrogen.cc
/trunk/src/hydrogen.h
/trunk/src/ia32/code-stubs-ia32.cc
/trunk/src/ia32/code-stubs-ia32.h
/trunk/src/ia32/codegen-ia32.cc
/trunk/src/ia32/full-codegen-ia32.cc
/trunk/src/ia32/ic-ia32.cc
/trunk/src/ia32/lithium-codegen-ia32.cc
/trunk/src/ia32/lithium-ia32.cc
/trunk/src/ia32/lithium-ia32.h
/trunk/src/ia32/macro-assembler-ia32.cc
/trunk/src/ia32/macro-assembler-ia32.h
/trunk/src/ia32/stub-cache-ia32.cc
/trunk/src/ic-inl.h
/trunk/src/ic.cc
/trunk/src/ic.h
/trunk/src/incremental-marking.cc
/trunk/src/incremental-marking.h
/trunk/src/json-parser.h
/trunk/src/json-stringifier.h
/trunk/src/liveedit.cc
/trunk/src/liveobjectlist.cc
/trunk/src/mark-compact.cc
/trunk/src/messages.js
/trunk/src/mips/assembler-mips-inl.h
/trunk/src/mips/assembler-mips.h
/trunk/src/mips/builtins-mips.cc
/trunk/src/mips/code-stubs-mips.cc
/trunk/src/mips/codegen-mips.cc
/trunk/src/mips/codegen-mips.h
/trunk/src/mips/full-codegen-mips.cc
/trunk/src/mips/lithium-codegen-mips.cc
/trunk/src/mips/lithium-mips.cc
/trunk/src/mips/macro-assembler-mips.cc
/trunk/src/mips/stub-cache-mips.cc
/trunk/src/object-observe.js
/trunk/src/objects-debug.cc
/trunk/src/objects-inl.h
/trunk/src/objects-visiting-inl.h
/trunk/src/objects-visiting.cc
/trunk/src/objects-visiting.h
/trunk/src/objects.cc
/trunk/src/objects.h
/trunk/src/optimizing-compiler-thread.cc
/trunk/src/optimizing-compiler-thread.h
/trunk/src/parser.cc
/trunk/src/platform-cygwin.cc
/trunk/src/platform-freebsd.cc
/trunk/src/platform-linux.cc
/trunk/src/platform-macos.cc
/trunk/src/platform-nullos.cc
/trunk/src/platform-openbsd.cc
/trunk/src/platform-solaris.cc
/trunk/src/platform-win32.cc
/trunk/src/platform.h
/trunk/src/profile-generator.cc
/trunk/src/regexp-macro-assembler.cc
/trunk/src/runtime-profiler.cc
/trunk/src/runtime.cc
/trunk/src/runtime.h
/trunk/src/spaces.cc
/trunk/src/spaces.h
/trunk/src/stub-cache.cc
/trunk/src/type-info.cc
/trunk/src/type-info.h
/trunk/src/v8conversions.cc
/trunk/src/v8natives.js
/trunk/src/variables.h
/trunk/src/version.cc
/trunk/src/x64/code-stubs-x64.cc
/trunk/src/x64/code-stubs-x64.h
/trunk/src/x64/codegen-x64.cc
/trunk/src/x64/full-codegen-x64.cc
/trunk/src/x64/ic-x64.cc
/trunk/src/x64/lithium-codegen-x64.cc
/trunk/src/x64/lithium-x64.cc
/trunk/src/x64/lithium-x64.h
/trunk/src/x64/macro-assembler-x64.cc
/trunk/src/x64/macro-assembler-x64.h
/trunk/src/x64/stub-cache-x64.cc
/trunk/test/cctest/test-api.cc
/trunk/test/cctest/test-assembler-arm.cc
/trunk/test/cctest/test-cpu-profiler.cc
/trunk/test/cctest/test-disasm-arm.cc
/trunk/test/cctest/test-heap.cc
/trunk/test/cctest/test-object-observe.cc
/trunk/test/cctest/test-parsing.cc
/trunk/test/cctest/test-regexp.cc
/trunk/test/mjsunit/array-reduce.js
/trunk/test/mjsunit/array-slice.js
/trunk/test/mjsunit/elements-kind.js
/trunk/test/mjsunit/error-constructors.js
/trunk/test/mjsunit/function-call.js
/trunk/test/mjsunit/fuzz-natives-part1.js
/trunk/test/mjsunit/harmony/object-observe.js
/trunk/test/mjsunit/math-floor-of-div-minus-zero.js
/trunk/test/mjsunit/regress/regress-1692.js
/trunk/test/mjsunit/regress/regress-1980.js
/trunk/test/test262/README
/trunk/test/test262/test262.status
/trunk/test/test262/testcfg.py
/trunk/tools/gen-postmortem-metadata.py
=======================================
--- /dev/null
+++ /trunk/src/atomicops_internals_tsan.h Fri Nov 16 06:43:43 2012
@@ -0,0 +1,335 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// This file is an internal atomic implementation for compiler-based
+// ThreadSanitizer. Use base/atomicops.h instead.
+
+#ifndef V8_ATOMICOPS_INTERNALS_TSAN_H_
+#define V8_ATOMICOPS_INTERNALS_TSAN_H_
+
+// This struct is not part of the public API of this module; clients may
not
+// use it. (However, it's exported via BASE_EXPORT because clients
implicitly
+// do use it at link time by inlining these functions.)
+// Features of this x86. Values may not be correct before main() is run,
+// but are set conservatively.
+struct AtomicOps_x86CPUFeatureStruct {
+ bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do
lfence
+ // after acquire compare-and-swap.
+ bool has_sse2; // Processor has SSE2.
+};
+extern struct AtomicOps_x86CPUFeatureStruct
+ AtomicOps_Internalx86CPUFeatures;
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__
__volatile__("" : : : "memory")
+
+namespace v8 {
+namespace internal {
+
+#ifndef TSAN_INTERFACE_ATOMIC_H
+#define TSAN_INTERFACE_ATOMIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef char __tsan_atomic8;
+typedef short __tsan_atomic16; // NOLINT
+typedef int __tsan_atomic32;
+typedef long __tsan_atomic64; // NOLINT
+
+typedef enum {
+ __tsan_memory_order_relaxed = (1 << 0) + 100500,
+ __tsan_memory_order_consume = (1 << 1) + 100500,
+ __tsan_memory_order_acquire = (1 << 2) + 100500,
+ __tsan_memory_order_release = (1 << 3) + 100500,
+ __tsan_memory_order_acq_rel = (1 << 4) + 100500,
+ __tsan_memory_order_seq_cst = (1 << 5) + 100500,
+} __tsan_memory_order;
+
+__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8* a,
+ __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16* a,
+ __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32* a,
+ __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64* a,
+ __tsan_memory_order mo);
+
+void __tsan_atomic8_store(volatile __tsan_atomic8* a, __tsan_atomic8 v,
+ __tsan_memory_order mo);
+void __tsan_atomic16_store(volatile __tsan_atomic16* a, __tsan_atomic16 v,
+ __tsan_memory_order mo);
+void __tsan_atomic32_store(volatile __tsan_atomic32* a, __tsan_atomic32 v,
+ __tsan_memory_order mo);
+void __tsan_atomic64_store(volatile __tsan_atomic64* a, __tsan_atomic64 v,
+ __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8* a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16* a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32* a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64* a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8* a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16* a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32* a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64* a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8* a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16* a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32* a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64* a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8* a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16* a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32* a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64* a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8* a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16* a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32* a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64* a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+
+int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8* a,
+ __tsan_atomic8* c, __tsan_atomic8 v, __tsan_memory_order mo);
+int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16* a,
+ __tsan_atomic16* c, __tsan_atomic16 v, __tsan_memory_order mo);
+int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32* a,
+ __tsan_atomic32* c, __tsan_atomic32 v, __tsan_memory_order mo);
+int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64* a,
+ __tsan_atomic64* c, __tsan_atomic64 v, __tsan_memory_order mo);
+
+int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8* a,
+ __tsan_atomic8* c, __tsan_atomic8 v, __tsan_memory_order mo);
+int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16* a,
+ __tsan_atomic16* c, __tsan_atomic16 v, __tsan_memory_order mo);
+int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32* a,
+ __tsan_atomic32* c, __tsan_atomic32 v, __tsan_memory_order mo);
+int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64* a,
+ __tsan_atomic64* c, __tsan_atomic64 v, __tsan_memory_order mo);
+
+void __tsan_atomic_thread_fence(__tsan_memory_order mo);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // #ifndef TSAN_INTERFACE_ATOMIC_H
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 cmp = old_value;
+ __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ return __tsan_atomic32_exchange(ptr, new_value,
+ __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ return __tsan_atomic32_exchange(ptr, new_value,
+ __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ return __tsan_atomic32_exchange(ptr, new_value,
+ __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return increment + __tsan_atomic32_fetch_add(ptr, increment,
+
__tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return increment + __tsan_atomic32_fetch_add(ptr, increment,
+
__tsan_memory_order_acq_rel);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 cmp = old_value;
+ __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_acquire);
+ return cmp;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 cmp = old_value;
+ __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_release);
+ return cmp;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ __tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+ return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 cmp = old_value;
+ __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ return __tsan_atomic64_exchange(ptr, new_value,
__tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ return __tsan_atomic64_exchange(ptr, new_value,
__tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ return __tsan_atomic64_exchange(ptr, new_value,
__tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return increment + __tsan_atomic64_fetch_add(ptr, increment,
+
__tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return increment + __tsan_atomic64_fetch_add(ptr, increment,
+
__tsan_memory_order_acq_rel);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ __tsan_atomic64_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+ return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 cmp = old_value;
+ __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_acquire);
+ return cmp;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 cmp = old_value;
+ __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_release);
+ return cmp;
+}
+
+inline void MemoryBarrier() {
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+} // namespace internal
+} // namespace v8
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif // V8_ATOMICOPS_INTERNALS_TSAN_H_
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/array-natives-elements.js Fri Nov 16 06:43:43 2012
@@ -0,0 +1,307 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --smi-only-arrays
+// Flags: --noparallel-recompilation
+
+// Test element kind of objects.
+// Since --smi-only-arrays affects builtins, its default setting at
compile time
+// sticks if built with snapshot. If --smi-only-arrays is deactivated by
+// default, only a no-snapshot build actually has smi-only arrays enabled
in
+// this test case. Depending on whether smi-only arrays are actually
enabled,
+// this test takes the appropriate code path to check smi-only arrays.
+
+support_smi_only_arrays = %HasFastSmiElements([1,2,3,4,5,6,7,8,9,10]);
+
+if (support_smi_only_arrays) {
+ print("Tests include smi-only arrays.");
+} else {
+ print("Tests do NOT include smi-only arrays.");
+}
+
+// IC and Crankshaft support for smi-only elements in dynamic array
literals.
+function get(foo) { return foo; } // Used to generate dynamic values.
+
+function array_natives_test() {
+
+ // Ensure small array literals start in specific element kind mode.
+ assertTrue(%HasFastSmiElements([]));
+ assertTrue(%HasFastSmiElements([1]));
+ assertTrue(%HasFastSmiElements([1,2]));
+ assertTrue(%HasFastDoubleElements([1.1]));
+ assertTrue(%HasFastDoubleElements([1.1,2]));
+
+ // Push
+ var a0 = [1, 2, 3];
+ assertTrue(%HasFastSmiElements(a0));
+ a0.push(4);
+ assertTrue(%HasFastSmiElements(a0));
+ a0.push(1.3);
+ assertTrue(%HasFastDoubleElements(a0));
+ a0.push(1.5);
+ assertTrue(%HasFastDoubleElements(a0));
+ a0.push({});
+ assertTrue(%HasFastObjectElements(a0));
+ a0.push({});
+ assertTrue(%HasFastObjectElements(a0));
+ assertEquals([1,2,3,4,1.3,1.5,{},{}], a0);
+
+ // Concat
+ var a1;
+ a1 = [1,2,3].concat([]);
+ assertTrue(%HasFastSmiElements(a1));
+ assertEquals([1,2,3], a1);
+ a1 = [1,2,3].concat([4,5,6]);
+ assertTrue(%HasFastSmiElements(a1));
+ assertEquals([1,2,3,4,5,6], a1);
+ a1 = [1,2,3].concat([4,5,6], [7,8,9]);
+ assertTrue(%HasFastSmiElements(a1));
+ assertEquals([1,2,3,4,5,6,7,8,9], a1);
+ a1 = [1.1,2,3].concat([]);
+ assertTrue(%HasFastDoubleElements(a1));
+ assertEquals([1.1,2,3], a1);
+ a1 = [1,2,3].concat([1.1, 2]);
+ assertTrue(%HasFastDoubleElements(a1));
+ assertEquals([1,2,3,1.1,2], a1);
+ a1 = [1.1,2,3].concat([1, 2]);
+ assertTrue(%HasFastDoubleElements(a1));
+ assertEquals([1.1,2,3,1,2], a1);
+ a1 = [1.1,2,3].concat([1.2, 2]);
+ assertTrue(%HasFastDoubleElements(a1));
+ assertEquals([1.1,2,3,1.2,2], a1);
+
+ a1 = [1,2,3].concat([{}]);
+ assertTrue(%HasFastObjectElements(a1));
+ assertEquals([1,2,3,{}], a1);
+ a1 = [1.1,2,3].concat([{}]);
+ assertTrue(%HasFastObjectElements(a1));
+ assertEquals([1.1,2,3,{}], a1);
+ a1 = [{}].concat([1,2,3]);
+ assertTrue(%HasFastObjectElements(a1));
+ assertEquals([{},1,2,3], a1);
+ a1 = [{}].concat([1.1,2,3]);
+ assertTrue(%HasFastObjectElements(a1));
+ assertEquals([{},1.1,2,3], a1);
+
+ // Slice
+ var a2 = [1,2,3];
+ assertTrue(%HasFastSmiElements(a2.slice()));
+ assertTrue(%HasFastSmiElements(a2.slice(1)));
+ assertTrue(%HasFastSmiElements(a2.slice(1, 2)));
+ assertEquals([1,2,3], a2.slice());
+ assertEquals([2,3], a2.slice(1));
+ assertEquals([2], a2.slice(1,2));
+ a2 = [1.1,2,3];
+ assertTrue(%HasFastDoubleElements(a2.slice()));
+ assertTrue(%HasFastDoubleElements(a2.slice(1)));
+ assertTrue(%HasFastDoubleElements(a2.slice(1, 2)));
+ assertEquals([1.1,2,3], a2.slice());
+ assertEquals([2,3], a2.slice(1));
+ assertEquals([2], a2.slice(1,2));
+ a2 = [{},2,3];
+ assertTrue(%HasFastObjectElements(a2.slice()));
+ assertTrue(%HasFastObjectElements(a2.slice(1)));
+ assertTrue(%HasFastObjectElements(a2.slice(1, 2)));
+ assertEquals([{},2,3], a2.slice());
+ assertEquals([2,3], a2.slice(1));
+ assertEquals([2], a2.slice(1,2));
+
+ // Splice
+ var a3 = [1,2,3];
+ var a3r;
+ a3r = a3.splice(0, 0);
+ assertTrue(%HasFastSmiElements(a3r));
+ assertTrue(%HasFastSmiElements(a3));
+ assertEquals([], a3r);
+ assertEquals([1, 2, 3], a3);
+ a3 = [1,2,3];
+ a3r = a3.splice(0, 1);
+ assertTrue(%HasFastSmiElements(a3r));
+ assertTrue(%HasFastSmiElements(a3));
+ assertEquals([1], a3r);
+ assertEquals([2, 3], a3);
+ a3 = [1,2,3];
+ a3r = a3.splice(0, 0, 2);
+ assertTrue(%HasFastSmiElements(a3r));
+ assertTrue(%HasFastSmiElements(a3));
+ assertEquals([], a3r);
+ assertEquals([2, 1, 2, 3], a3);
+ a3 = [1,2,3];
+ a3r = a3.splice(0, 1, 2);
+ assertTrue(%HasFastSmiElements(a3r));
+ assertTrue(%HasFastSmiElements(a3));
+ assertEquals([1], a3r);
+ assertEquals([2, 2, 3], a3);
+
+ a3 = [1.1,2,3];
+ a3r = a3.splice(0, 0);
+ assertTrue(%HasFastDoubleElements(a3r));
+ assertTrue(%HasFastDoubleElements(a3));
+ assertEquals([], a3r);
+ assertEquals([1.1, 2, 3], a3);
+ a3 = [1.1,2,3];
+ a3r = a3.splice(0, 1);
+ assertTrue(%HasFastDoubleElements(a3r));
+ assertTrue(%HasFastDoubleElements(a3));
+ assertEquals([1.1], a3r);
+ assertEquals([2, 3], a3);
+ a3 = [1.1,2,3];
+ a3r = a3.splice(0, 0, 2);
+ // Commented out since handled in js, which takes the best fit.
+ // assertTrue(%HasFastDoubleElements(a3r));
+ assertTrue(%HasFastSmiElements(a3r));
+ assertTrue(%HasFastDoubleElements(a3));
+ assertEquals([], a3r);
+ assertEquals([2, 1.1, 2, 3], a3);
+ a3 = [1.1,2,3];
+ a3r = a3.splice(0, 1, 2);
+ assertTrue(%HasFastDoubleElements(a3r));
+ assertTrue(%HasFastDoubleElements(a3));
+ assertEquals([1.1], a3r);
+ assertEquals([2, 2, 3], a3);
+ a3 = [1.1,2,3];
+ a3r = a3.splice(0, 0, 2.1);
+ // Commented out since handled in js, which takes the best fit.
+ // assertTrue(%HasFastDoubleElements(a3r));
+ assertTrue(%HasFastSmiElements(a3r));
+ assertTrue(%HasFastDoubleElements(a3));
+ assertEquals([], a3r);
+ assertEquals([2.1, 1.1, 2, 3], a3);
+ a3 = [1.1,2,3];
+ a3r = a3.splice(0, 1, 2.2);
+ assertTrue(%HasFastDoubleElements(a3r));
+ assertTrue(%HasFastDoubleElements(a3));
+ assertEquals([1.1], a3r);
+ assertEquals([2.2, 2, 3], a3);
+ a3 = [1,2,3];
+ a3r = a3.splice(0, 0, 2.1);
+ // Commented out since handled in js, which takes the best fit.
+ // assertTrue(%HasFastDoubleElements(a3r));
+ assertTrue(%HasFastSmiElements(a3r));
+ assertTrue(%HasFastDoubleElements(a3));
+ assertEquals([], a3r);
+ assertEquals([2.1, 1, 2, 3], a3);
+ a3 = [1,2,3];
+ a3r = a3.splice(0, 1, 2.2);
+ assertTrue(%HasFastDoubleElements(a3r));
+ assertTrue(%HasFastDoubleElements(a3));
+ assertEquals([1], a3r);
+ assertEquals([2.2, 2, 3], a3);
+
+ a3 = [{},2,3];
+ a3r = a3.splice(0, 0);
+ assertTrue(%HasFastObjectElements(a3r));
+ assertTrue(%HasFastObjectElements(a3));
+ assertEquals([], a3r);
+ assertEquals([{}, 2, 3], a3);
+ a3 = [1,2,{}];
+ a3r = a3.splice(0, 1);
+ assertTrue(%HasFastObjectElements(a3r));
+ assertTrue(%HasFastObjectElements(a3));
+ assertEquals([1], a3r);
+ assertEquals([2, {}], a3);
+ a3 = [1,2,3];
+ a3r = a3.splice(0, 0, {});
+ assertTrue(%HasFastObjectElements(a3r));
+ assertTrue(%HasFastObjectElements(a3));
+ assertEquals([], a3r);
+ assertEquals([{}, 1, 2, 3], a3);
+ a3 = [1,2,3];
+ a3r = a3.splice(0, 1, {});
+ assertTrue(%HasFastObjectElements(a3r));
+ assertTrue(%HasFastObjectElements(a3));
+ assertEquals([1], a3r);
+ assertEquals([{}, 2, 3], a3);
+
+ a3 = [1.1,2,3];
+ a3r = a3.splice(0, 0, {});
+ assertTrue(%HasFastObjectElements(a3r));
+ assertTrue(%HasFastObjectElements(a3));
+ assertEquals([], a3r);
+ assertEquals([{}, 1.1, 2, 3], a3);
+ a3 = [1.1,2,3];
+ a3r = a3.splice(0, 1, {});
+ assertTrue(%HasFastObjectElements(a3r));
+ assertTrue(%HasFastObjectElements(a3));
+ assertEquals([1.1], a3r);
+ assertEquals([{}, 2, 3], a3);
+
+ // Pop
+ var a4 = [1,2,3];
+ assertEquals(3, a4.pop());
+ assertTrue(%HasFastSmiElements(a4));
+ a4 = [1.1,2,3];
+ assertEquals(3, a4.pop());
+ assertTrue(%HasFastDoubleElements(a4));
+ a4 = [{},2,3];
+ assertEquals(3, a4.pop());
+ assertTrue(%HasFastObjectElements(a4));
+
+ // Shift
+ var a4 = [1,2,3];
+ assertEquals(1, a4.shift());
+ assertTrue(%HasFastSmiElements(a4));
+ a4 = [1.1,2,3];
+ assertEquals(1.1, a4.shift());
+ assertTrue(%HasFastDoubleElements(a4));
+ a4 = [{},2,3];
+ assertEquals({}, a4.shift());
+ assertTrue(%HasFastObjectElements(a4));
+
+ // Unshift
+ var a4 = [1,2,3];
+ a4.unshift(1);
+ assertTrue(%HasFastSmiElements(a4));
+ assertEquals([1,1,2,3], a4);
+ a4 = [1,2,3];
+ a4.unshift(1.1);
+ // TODO(verwaest): We'll want to support double unshifting as well.
+ // assertTrue(%HasFastDoubleElements(a4));
+ assertTrue(%HasFastObjectElements(a4));
+ assertEquals([1.1,1,2,3], a4);
+ a4 = [1.1,2,3];
+ a4.unshift(1);
+ // assertTrue(%HasFastDoubleElements(a4));
+ assertTrue(%HasFastObjectElements(a4));
+ assertEquals([1,1.1,2,3], a4);
+ a4 = [{},2,3];
+ a4.unshift(1);
+ assertTrue(%HasFastObjectElements(a4));
+ assertEquals([1,{},2,3], a4);
+ a4 = [{},2,3];
+ a4.unshift(1.1);
+ assertTrue(%HasFastObjectElements(a4));
+ assertEquals([1.1,{},2,3], a4);
+}
+
+if (support_smi_only_arrays) {
+ for (var i = 0; i < 3; i++) {
+ array_natives_test();
+ }
+ %OptimizeFunctionOnNextCall(array_natives_test);
+ array_natives_test();
+}
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/compiler/multiply-add.js Fri Nov 16 06:43:43 2012
@@ -0,0 +1,69 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+// Test expressions that can be computed with a multiply-add instruction.
+
+function f(a, b, c) {
+ return a * b + c;
+}
+
+function g(a, b, c) {
+ return a + b * c;
+}
+
+function h(a, b, c, d) {
+ return a * b + c * d;
+}
+
+assertEquals(5, f(1, 2, 3));
+assertEquals(5, f(1, 2, 3));
+%OptimizeFunctionOnNextCall(f);
+assertEquals(5, f(1, 2, 3));
+assertEquals("2foo", f(1, 2, "foo"));
+assertEquals(5.41, f(1.1, 2.1, 3.1));
+assertEquals(5.41, f(1.1, 2.1, 3.1));
+%OptimizeFunctionOnNextCall(f);
+assertEquals(5.41, f(1.1, 2.1, 3.1));
+
+assertEquals(7, g(1, 2, 3));
+assertEquals(7, g(1, 2, 3));
+%OptimizeFunctionOnNextCall(g);
+assertEquals(7, g(1, 2, 3));
+assertEquals(8.36, g(1.1, 2.2, 3.3));
+assertEquals(8.36, g(1.1, 2.2, 3.3));
+%OptimizeFunctionOnNextCall(g);
+assertEquals(8.36, g(1.1, 2.2, 3.3));
+
+assertEquals(14, h(1, 2, 3, 4));
+assertEquals(14, h(1, 2, 3, 4));
+%OptimizeFunctionOnNextCall(h);
+assertEquals(14, h(1, 2, 3, 4));
+assertEquals(15.02, h(1.1, 2.1, 3.1, 4.1));
+assertEquals(15.02, h(1.1, 2.1, 3.1, 4.1));
+%OptimizeFunctionOnNextCall(h);
+assertEquals(15.02, h(1.1, 2.1, 3.1, 4.1));
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/debug-liveedit-literals.js Fri Nov 16 06:43:43 2012
@@ -0,0 +1,94 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+
+Debug = debug.Debug
+
+function Test(old_expression, new_expression) {
+ // Generate several instances of function to test that we correctly fix
+ // all functions in memory.
+ var function_instance_number = 11;
+ eval("var t1 =1;\n" +
+ "ChooseAnimalArray = [];\n" +
+ "for (var i = 0; i < function_instance_number; i++) {\n" +
+ " ChooseAnimalArray.push(\n" +
+ " function ChooseAnimal() {\n" +
+ " return " + old_expression + ";\n" +
+ " });\n" +
+ "}\n" +
+ "var t2 =1;\n");
+
+ for (var i = 0; i < ChooseAnimalArray.length; i++) {
+ assertEquals("Cat", ChooseAnimalArray[i]());
+ }
+
+ var script = Debug.findScript(ChooseAnimalArray[0]);
+
+ var patch_pos = script.source.indexOf(old_expression);
+ var new_animal_patch = new_expression;
+
+ var change_log = new Array();
+ Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos,
+ old_expression.length, new_expression, change_log);
+
+ for (var i = 0; i < ChooseAnimalArray.length; i++) {
+ assertEquals("Capybara", ChooseAnimalArray[i]());
+ }
+}
+
+// Check that old literal boilerplate was reset.
+Test("['Cat'][0]", "['Capybara'][0]");
+Test("['Cat'][0]", "{a:'Capybara'}.a");
+
+// No literals -> 1 literal.
+Test("'Cat'", "['Capybara'][0]");
+
+// No literals -> 2 literals.
+Test("'Cat'", "['Capy'][0] + {a:'bara'}.a");
+
+// 1 literal -> no literals.
+Test("['Cat'][0]", "'Capybara'");
+
+// 2 literals -> no literals.
+Test("['Ca'][0] + {a:'t'}.a", "'Capybara'");
+
+// No literals -> regexp.
+Test("'Cat'", "(/.A.Y.A.A/i).exec('Capybara')[0]");
+
+// Array literal -> regexp.
+Test("['Cat'][0]", "(/.A.Y.A.A/i).exec('Capybara')[0]");
+
+// Regexp -> object literal.
+Test("(/.A./i).exec('Cat')[0]", "{c:'Capybara'}.c");
+
+// No literals -> regexp.
+Test("'Cat'", "(/.A.Y.A.A/i).exec('Capybara')[0]");
+
+// Regexp -> no literals.
+Test("(/.A./i).exec('Cat')[0]", "'Capybara'");
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/manual-parallel-recompile.js Fri Nov 16 06:43:43
2012
@@ -0,0 +1,79 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --expose-gc
+// Flags: --parallel-recompilation --manual-parallel-recompilation
+
+function assertOptimized(fun) {
+ // This assertion takes --always-opt and --nocrankshaft flags into
account.
+ assertTrue(%GetOptimizationStatus(fun) != 2);
+}
+
+function assertUnoptimized(fun) {
+ assertTrue(%GetOptimizationStatus(fun) != 1);
+}
+
+function f(x) {
+ var xx = x * x;
+ var xxstr = xx.toString();
+ return xxstr.length;
+}
+
+function g(x) {
+ var xxx = Math.sqrt(x) | 0;
+ var xxxstr = xxx.toString();
+ return xxxstr.length;
+}
+
+function k(x) {
+ return x * x;
+}
+
+f(g(1));
+f(g(2));
+assertUnoptimized(f);
+assertUnoptimized(g);
+
+%ForceParallelRecompile(f);
+%ForceParallelRecompile(g);
+assertUnoptimized(f);
+assertUnoptimized(g);
+
+var sum = 0;
+for (var i = 0; i < 10000; i++) sum += f(i) + g(i);
+gc();
+
+assertEquals(95274, sum);
+assertUnoptimized(f);
+assertUnoptimized(g);
+
+%InstallRecompiledCode(f);
+assertOptimized(f);
+assertUnoptimized(g);
+
+%InstallRecompiledCode(g);
+assertOptimized(g);
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-2263.js Fri Nov 16 06:43:43 2012
@@ -0,0 +1,30 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var obj = { length: { valueOf: function(){ throw { type: "length" }}}};
+var sep = { toString: function(){ throw { type: "toString" }}};
+assertThrows("Array.prototype.join.call(obj, sep)", undefined, "length");
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-2410.js Fri Nov 16 06:43:43 2012
@@ -0,0 +1,36 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Object.prototype should be ignored in Object.getOwnPropertyNames
+//
+// See
http://code.google.com/p/v8/issues/detail?id=2410 for details.
+
+Object.defineProperty(Object.prototype,
+ 'thrower',
+ { get: function() { throw Error('bug') } });
+var obj = { thrower: 'local' };
+assertEquals(['thrower'], Object.getOwnPropertyNames(obj));
=======================================
--- /trunk/.gitignore Mon Nov 12 06:53:34 2012
+++ /trunk/.gitignore Fri Nov 16 06:43:43 2012
@@ -18,6 +18,7 @@
#*#
*~
.cpplint-cache
+.d8_history
d8
d8_g
shell
=======================================
--- /trunk/ChangeLog Tue Nov 13 05:56:09 2012
+++ /trunk/ChangeLog Fri Nov 16 06:43:43 2012
@@ -1,3 +1,28 @@
+2012-11-16: Version 3.15.4
+
+ Fixed Array.prototype.join evaluation order. (issue 2263)
+
+ Perform CPU sampling by CPU sampling thread only iff processing
thread
+ is not running. (issue 2364)
+
+ When using an Object as a set in Object.getOwnPropertyNames, null
out
+ the proto. (issue 2410)
+
+ Disabled EXTRA_CHECKS in Release build.
+
+ Heap explorer: Show representation of strings.
+
+ Removed 'type' and 'arguments' properties from Error object.
+ (issue 2397)
+
+ Added atomics implementation for ThreadSanitizer v2.
+ (Chromium issue 128314)
+
+ Fixed LiveEdit crashes when object/array literal is added. (issue
2368)
+
+ Performance and stability improvements on all platforms.
+
+
2012-11-13: Version 3.15.3
Changed sample shell to send non-JS output (e.g. errors) to stderr
=======================================
--- /trunk/build/common.gypi Wed Oct 31 03:02:10 2012
+++ /trunk/build/common.gypi Fri Nov 16 06:43:43 2012
@@ -70,9 +70,6 @@
'v8_enable_disassembler%': 0,
- # Enable extra checks in API functions and other strategic places.
- 'v8_enable_extra_checks%': 1,
-
'v8_enable_gdbjit%': 0,
'v8_object_print%': 0,
@@ -114,9 +111,6 @@
['v8_enable_disassembler==1', {
'defines': ['ENABLE_DISASSEMBLER',],
}],
- ['v8_enable_extra_checks==1', {
- 'defines': ['ENABLE_EXTRA_CHECKS',],
- }],
['v8_enable_gdbjit==1', {
'defines': ['ENABLE_GDB_JIT_INTERFACE',],
}],
@@ -336,6 +330,9 @@
], # conditions
'configurations': {
'Debug': {
+ 'variables': {
+ 'v8_enable_extra_checks%': 1,
+ },
'defines': [
'DEBUG',
'ENABLE_DISASSEMBLER',
@@ -360,6 +357,9 @@
},
},
'conditions': [
+ ['v8_enable_extra_checks==1', {
+ 'defines': ['ENABLE_EXTRA_CHECKS',],
+ }],
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or
OS=="netbsd"', {
'cflags':
[ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter',
'-Wnon-virtual-dtor', '-Woverloaded-virtual' ],
@@ -381,7 +381,13 @@
],
}, # Debug
'Release': {
+ 'variables': {
+ 'v8_enable_extra_checks%': 0,
+ },
'conditions': [
+ ['v8_enable_extra_checks==1', {
+ 'defines': ['ENABLE_EXTRA_CHECKS',],
+ }],
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" \
or OS=="android"', {
'cflags!': [
=======================================
--- /trunk/src/accessors.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/accessors.cc Fri Nov 16 06:43:43 2012
@@ -93,47 +93,6 @@
if (wrapper->map() == number_map) return wrapper->value();
return value;
}
-
-
-static MaybeObject* ArraySetLengthObserved(Isolate* isolate,
- Handle<JSArray> array,
- Handle<Object>
new_length_handle) {
- List<Handle<String> > indices;
- List<Handle<Object> > old_values;
- Handle<Object> old_length_handle(array->length(), isolate);
- uint32_t old_length = 0;
- CHECK(old_length_handle->ToArrayIndex(&old_length));
- uint32_t new_length = 0;
- CHECK(new_length_handle->ToArrayIndex(&new_length));
- // TODO(adamk): This loop can be very slow for arrays in dictionary mode.
- // Find another way to iterate over arrays with dictionary elements.
- for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
- PropertyAttributes attributes = array->GetLocalElementAttribute(i);
- if (attributes == ABSENT) continue;
- // A non-configurable property will cause the truncation operation to
- // stop at this index.
- if (attributes == DONT_DELETE) break;
- // TODO(adamk): Don't fetch the old value if it's an accessor.
- old_values.Add(Object::GetElement(array, i));
- indices.Add(isolate->factory()->Uint32ToString(i));
- }
-
- MaybeObject* result = array->SetElementsLength(*new_length_handle);
- Handle<Object> hresult;
- if (!result->ToHandle(&hresult)) return result;
-
- CHECK(array->length()->ToArrayIndex(&new_length));
- if (old_length != new_length) {
- for (int i = 0; i < indices.length(); ++i) {
- JSObject::EnqueueChangeRecord(
- array, "deleted", indices[i], old_values[i]);
- }
- JSObject::EnqueueChangeRecord(
- array, "updated", isolate->factory()->length_symbol(),
- old_length_handle);
- }
- return *hresult;
-}
MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value,
void*) {
@@ -163,11 +122,7 @@
if (has_exception) return Failure::Exception();
if (uint32_v->Number() == number_v->Number()) {
- if (FLAG_harmony_observation && array_handle->map()->is_observed()) {
- return ArraySetLengthObserved(isolate, array_handle, uint32_v);
- } else {
- return array_handle->SetElementsLength(*uint32_v);
- }
+ return array_handle->SetElementsLength(*uint32_v);
}
return isolate->Throw(
*isolate->factory()->NewRangeError("invalid_array_length",
=======================================
--- /trunk/src/api.cc Tue Nov 13 05:56:09 2012
+++ /trunk/src/api.cc Fri Nov 16 06:43:43 2012
@@ -905,7 +905,7 @@
}
// Allocate a new handle on the previous handle block.
- i::Handle<i::Object> handle(result);
+ i::Handle<i::Object> handle(result, isolate_);
return handle.location();
}
@@ -3414,7 +3414,7 @@
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj);
- i::Handle<i::Object> result(self->GetHiddenProperty(*key_symbol));
+ i::Handle<i::Object> result(self->GetHiddenProperty(*key_symbol),
isolate);
if (result->IsUndefined()) return v8::Local<v8::Value>();
return Utils::ToLocal(result);
}
@@ -4649,13 +4649,14 @@
v8::Local<v8::Object> Context::Global() {
- if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::Context::Global()")) {
return Local<v8::Object>();
}
i::Object** ctx = reinterpret_cast<i::Object**>(this);
i::Handle<i::Context> context =
i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
- i::Handle<i::Object> global(context->global_proxy());
+ i::Handle<i::Object> global(context->global_proxy(), isolate);
return Utils::ToLocal(i::Handle<i::JSObject>::cast(global));
}
=======================================
--- /trunk/src/arm/assembler-arm.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/arm/assembler-arm.cc Fri Nov 16 06:43:43 2012
@@ -2388,6 +2388,20 @@
emit(cond | 0xE*B24 | 0x2*B20 | src1.code()*B16 |
dst.code()*B12 | 0x5*B9 | B8 | src2.code());
}
+
+
+void Assembler::vmla(const DwVfpRegister dst,
+ const DwVfpRegister src1,
+ const DwVfpRegister src2,
+ const Condition cond) {
+ // Instruction details available in ARM DDI 0406C.b, A8-892.
+ // cond(31-28) | 11100(27-23) | D=?(22) | 00(21-20) | Vn(19-16) |
+ // Vd(15-12) | 101(11-9) | sz(8)=1 | N=?(7) | op(6)=0 | M=?(5) | 0(4) |
+ // Vm(3-0)
+ unsigned x = (cond | 0x1C*B23 | src1.code()*B16 |
+ dst.code()*B12 | 0x5*B9 | B8 | src2.code());
+ emit(x);
+}
void Assembler::vdiv(const DwVfpRegister dst,
=======================================
--- /trunk/src/arm/assembler-arm.h Mon Nov 12 06:53:34 2012
+++ /trunk/src/arm/assembler-arm.h Fri Nov 16 06:43:43 2012
@@ -1126,6 +1126,10 @@
const DwVfpRegister src1,
const DwVfpRegister src2,
const Condition cond = al);
+ void vmla(const DwVfpRegister dst,
+ const DwVfpRegister src1,
+ const DwVfpRegister src2,
+ const Condition cond = al);
void vdiv(const DwVfpRegister dst,
const DwVfpRegister src1,
const DwVfpRegister src2,
=======================================
--- /trunk/src/arm/code-stubs-arm.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/arm/code-stubs-arm.cc Fri Nov 16 06:43:43 2012
@@ -41,8 +41,7 @@
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
Label* slow,
- Condition cond,
- bool never_nan_nan);
+ Condition cond);
static void EmitSmiNonsmiComparison(MacroAssembler* masm,
Register lhs,
Register rhs,
@@ -625,24 +624,6 @@
__ pop(lr);
}
}
-
-
-void FloatingPointHelper::LoadOperands(
- MacroAssembler* masm,
- FloatingPointHelper::Destination destination,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- Label* slow) {
-
- // Load right operand (r0) to d6 or r2/r3.
- LoadNumber(masm, destination,
- r0, d7, r2, r3, heap_number_map, scratch1, scratch2, slow);
-
- // Load left operand (r1) to d7 or r0/r1.
- LoadNumber(masm, destination,
- r1, d6, r0, r1, heap_number_map, scratch1, scratch2, slow);
-}
void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
@@ -748,13 +729,13 @@
Register int_scratch,
Destination destination,
DwVfpRegister double_dst,
- Register dst1,
- Register dst2,
+ Register dst_mantissa,
+ Register dst_exponent,
Register scratch2,
SwVfpRegister single_scratch)
{
ASSERT(!
int_scratch.is(scratch2));
- ASSERT(!
int_scratch.is(dst1));
- ASSERT(!
int_scratch.is(dst2));
+ ASSERT(!
int_scratch.is(dst_mantissa));
+ ASSERT(!
int_scratch.is(dst_exponent));
Label done;
@@ -763,56 +744,57 @@
__ vmov(single_scratch, int_scratch);
__ vcvt_f64_s32(double_dst, single_scratch);
if (destination == kCoreRegisters) {
- __ vmov(dst1, dst2, double_dst);
+ __ vmov(dst_mantissa, dst_exponent, double_dst);
}
} else {
Label fewer_than_20_useful_bits;
// Expected output:
- // | dst2 | dst1 |
+ // | dst_exponent | dst_mantissa |
// | s | exp | mantissa |
// Check for zero.
__ cmp(int_scratch, Operand::Zero());
- __ mov(dst2, int_scratch);
- __ mov(dst1, int_scratch);
+ __ mov(dst_exponent, int_scratch);
+ __ mov(dst_mantissa, int_scratch);
__ b(eq, &done);
// Preload the sign of the value.
- __ and_(dst2, int_scratch, Operand(HeapNumber::kSignMask), SetCC);
+ __ and_(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask),
SetCC);
// Get the absolute value of the object (as an unsigned integer).
__ rsb(int_scratch, int_scratch, Operand::Zero(), SetCC, mi);
// Get mantissa[51:20].
// Get the position of the first set bit.
- __ CountLeadingZeros(dst1, int_scratch, scratch2);
- __ rsb(dst1, dst1, Operand(31));
+ __ CountLeadingZeros(dst_mantissa, int_scratch, scratch2);
+ __ rsb(dst_mantissa, dst_mantissa, Operand(31));
// Set the exponent.
- __ add(scratch2, dst1, Operand(HeapNumber::kExponentBias));
- __ Bfi(dst2, scratch2, scratch2,
+ __ add(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias));
+ __ Bfi(dst_exponent, scratch2, scratch2,
HeapNumber::kExponentShift, HeapNumber::kExponentBits);
// Clear the first non null bit.
__ mov(scratch2, Operand(1));
- __ bic(int_scratch, int_scratch, Operand(scratch2, LSL, dst1));
+ __ bic(int_scratch, int_scratch, Operand(scratch2, LSL, dst_mantissa));
- __ cmp(dst1, Operand(HeapNumber::kMantissaBitsInTopWord));
+ __ cmp(dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord));
// Get the number of bits to set in the lower part of the mantissa.
- __ sub(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord),
SetCC);
+ __ sub(scratch2, dst_mantissa,
Operand(HeapNumber::kMantissaBitsInTopWord),
+ SetCC);
__ b(mi, &fewer_than_20_useful_bits);
// Set the higher 20 bits of the mantissa.
- __ orr(dst2, dst2, Operand(int_scratch, LSR, scratch2));
+ __ orr(dst_exponent, dst_exponent, Operand(int_scratch, LSR,
scratch2));
__ rsb(scratch2, scratch2, Operand(32));
- __ mov(dst1, Operand(int_scratch, LSL, scratch2));
+ __ mov(dst_mantissa, Operand(int_scratch, LSL, scratch2));
__ b(&done);
__ bind(&fewer_than_20_useful_bits);
- __ rsb(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord));
+ __ rsb(scratch2, dst_mantissa,
Operand(HeapNumber::kMantissaBitsInTopWord));
__ mov(scratch2, Operand(int_scratch, LSL, scratch2));
- __ orr(dst2, dst2, scratch2);
+ __ orr(dst_exponent, dst_exponent, scratch2);
// Set dst1 to 0.
- __ mov(dst1, Operand::Zero());
+ __ mov(dst_mantissa, Operand::Zero());
}
__ bind(&done);
}
@@ -823,8 +805,8 @@
Destination destination,
DwVfpRegister double_dst,
DwVfpRegister
double_scratch,
- Register dst1,
- Register dst2,
+ Register dst_mantissa,
+ Register dst_exponent,
Register heap_number_map,
Register scratch1,
Register scratch2,
@@ -840,8 +822,8 @@
__ JumpIfNotSmi(object, &obj_is_not_smi);
__ SmiUntag(scratch1, object);
- ConvertIntToDouble(masm, scratch1, destination, double_dst, dst1, dst2,
- scratch2, single_scratch);
+ ConvertIntToDouble(masm, scratch1, destination, double_dst, dst_mantissa,
+ dst_exponent, scratch2, single_scratch);
__ b(&done);
__ bind(&obj_is_not_smi);
@@ -868,26 +850,52 @@
__ b(ne, not_int32);
if (destination == kCoreRegisters) {
- __ vmov(dst1, dst2, double_dst);
+ __ vmov(dst_mantissa, dst_exponent, double_dst);
}
} else {
ASSERT(!
scratch1.is(object) && !
scratch2.is(object));
- // Load the double value in the destination registers..
- __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset));
+ // Load the double value in the destination registers.
+ bool save_registers =
object.is(dst_mantissa) ||
object.is(dst_exponent);
+ if (save_registers) {
+ // Save both output registers, because the other one probably holds
+ // an important value too.
+ __ Push(dst_exponent, dst_mantissa);
+ }
+ __ Ldrd(dst_mantissa, dst_exponent,
+ FieldMemOperand(object, HeapNumber::kValueOffset));
// Check for 0 and -0.
- __ bic(scratch1, dst1, Operand(HeapNumber::kSignMask));
- __ orr(scratch1, scratch1, Operand(dst2));
+ Label zero;
+ __ bic(scratch1, dst_exponent, Operand(HeapNumber::kSignMask));
+ __ orr(scratch1, scratch1, Operand(dst_mantissa));
__ cmp(scratch1, Operand::Zero());
- __ b(eq, &done);
+ __ b(eq, &zero);
// Check that the value can be exactly represented by a 32-bit integer.
// Jump to not_int32 if that's not the case.
- DoubleIs32BitInteger(masm, dst1, dst2, scratch1, scratch2, not_int32);
+ Label restore_input_and_miss;
+ DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1,
scratch2,
+ &restore_input_and_miss);
+
+ // 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);
- // dst1 and dst2 were trashed. Reload the double value.
- __ Ldrd(dst1, dst2, FieldMemOperand(object, HeapNumber::kValueOffset));
+ __ bind(&restore_input_and_miss);
+ if (save_registers) {
+ __ Pop(dst_exponent, dst_mantissa);
+ }
+ __ b(not_int32);
+
+ __ bind(&zero);
+ if (save_registers) {
+ __ Drop(2);
+ }
}
__ bind(&done);
@@ -910,14 +918,15 @@
!
scratch1.is(scratch3) &&
!
scratch2.is(scratch3));
- Label done;
+ Label done, maybe_undefined;
__ UntagAndJumpIfSmi(dst, object, &done);
__ AssertRootValue(heap_number_map,
Heap::kHeapNumberMapRootIndex,
"HeapNumberMap register clobbered.");
- __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
+
+ __ JumpIfNotHeapNumber(object, heap_number_map, scratch1,
&maybe_undefined);
// Object is a heap number.
// Convert the floating point value to a 32-bit integer.
@@ -964,20 +973,28 @@
__ tst(scratch1, Operand(HeapNumber::kSignMask));
__ rsb(dst, dst, Operand::Zero(), LeaveCC, mi);
}
+ __ b(&done);
+
+ __ bind(&maybe_undefined);
+ __ CompareRoot(object, Heap::kUndefinedValueRootIndex);
+ __ b(ne, not_int32);
+ // |undefined| is truncated to 0.
+ __ mov(dst, Operand(Smi::FromInt(0)));
+ // Fall through.
__ bind(&done);
}
void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm,
- Register src1,
- Register src2,
+ Register src_exponent,
+ Register src_mantissa,
Register dst,
Register scratch,
Label* not_int32) {
// Get exponent alone in scratch.
__ Ubfx(scratch,
- src1,
+ src_exponent,
HeapNumber::kExponentShift,
HeapNumber::kExponentBits);
@@ -997,11 +1014,11 @@
// Another way to put it is that if (exponent - signbit) > 30 then the
// number cannot be represented as an int32.
Register tmp = dst;
- __ sub(tmp, scratch, Operand(src1, LSR, 31));
+ __ sub(tmp, scratch, Operand(src_exponent, LSR, 31));
__ cmp(tmp, Operand(30));
__ b(gt, not_int32);
// - Bits [21:0] in the mantissa are not null.
- __ tst(src2, Operand(0x3fffff));
+ __ tst(src_mantissa, Operand(0x3fffff));
__ b(ne, not_int32);
// Otherwise the exponent needs to be big enough to shift left all the
@@ -1012,19 +1029,19 @@
// Get the 32 higher bits of the mantissa in dst.
__ Ubfx(dst,
- src2,
+ src_mantissa,
HeapNumber::kMantissaBitsInTopWord,
32 - HeapNumber::kMantissaBitsInTopWord);
__ orr(dst,
dst,
- Operand(src1, LSL, HeapNumber::kNonMantissaBitsInTopWord));
+ Operand(src_exponent, LSL,
HeapNumber::kNonMantissaBitsInTopWord));
// Create the mask and test the lower bits (of the higher bits).
__ rsb(scratch, scratch, Operand(32));
- __ mov(src2, Operand(1));
- __ mov(src1, Operand(src2, LSL, scratch));
- __ sub(src1, src1, Operand(1));
- __ tst(dst, src1);
+ __ mov(src_mantissa, Operand(1));
+ __ mov(src_exponent, Operand(src_mantissa, LSL, scratch));
+ __ sub(src_exponent, src_exponent, Operand(1));
+ __ tst(dst, src_exponent);
__ b(ne, not_int32);
}
@@ -1148,48 +1165,43 @@
// for "identity and not NaN".
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
Label* slow,
- Condition cond,
- bool never_nan_nan) {
+ Condition cond) {
Label not_identical;
Label heap_number, return_equal;
__ cmp(r0, r1);
__ b(ne, ¬_identical);
- // The two objects are identical. If we know that one of them isn't NaN
then
- // we now know they test equal.
- if (cond != eq || !never_nan_nan) {
- // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
- // so we do the second best thing - test it ourselves.
- // They are both equal and they are not both Smis so both of them are
not
- // Smis. If it's not a heap number, then return equal.
- if (cond == lt || cond == gt) {
- __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
+ // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
+ // so we do the second best thing - test it ourselves.
+ // They are both equal and they are not both Smis so both of them are not
+ // Smis. If it's not a heap number, then return equal.
+ if (cond == lt || cond == gt) {
+ __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
+ __ b(ge, slow);
+ } else {
+ __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
+ __ b(eq, &heap_number);
+ // Comparing JS objects with <=, >= is complicated.
+ if (cond != eq) {
+ __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
__ b(ge, slow);
- } else {
- __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
- __ b(eq, &heap_number);
- // Comparing JS objects with <=, >= is complicated.
- if (cond != eq) {
- __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
- __ b(ge, slow);
- // Normally here we fall through to return_equal, but undefined is
- // special: (undefined == undefined) == true, but
- // (undefined <= undefined) == false! See ECMAScript 11.8.5.
- if (cond == le || cond == ge) {
- __ cmp(r4, Operand(ODDBALL_TYPE));
- __ b(ne, &return_equal);
- __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
- __ cmp(r0, r2);
- __ b(ne, &return_equal);
- if (cond == le) {
- // undefined <= undefined should fail.
- __ mov(r0, Operand(GREATER));
- } else {
- // undefined >= undefined should fail.
- __ mov(r0, Operand(LESS));
- }
- __ Ret();
+ // Normally here we fall through to return_equal, but undefined is
+ // special: (undefined == undefined) == true, but
+ // (undefined <= undefined) == false! See ECMAScript 11.8.5.
+ if (cond == le || cond == ge) {
+ __ cmp(r4, Operand(ODDBALL_TYPE));
+ __ b(ne, &return_equal);
+ __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
+ __ cmp(r0, r2);
+ __ b(ne, &return_equal);
+ if (cond == le) {
+ // undefined <= undefined should fail.
+ __ mov(r0, Operand(GREATER));
+ } else {
+ // undefined >= undefined should fail.
+ __ mov(r0, Operand(LESS));
}
+ __ Ret();
}
}
}
@@ -1204,47 +1216,45 @@
}
__ Ret();
- if (cond != eq || !never_nan_nan) {
- // For less and greater we don't have to check for NaN since the
result of
- // x < x is false regardless. For the others here is some code to
check
- // for NaN.
- if (cond != lt && cond != gt) {
- __ bind(&heap_number);
- // It is a heap number, so return non-equal if it's NaN and equal if
it's
- // not NaN.
+ // For less and greater we don't have to check for NaN since the result
of
+ // x < x is false regardless. For the others here is some code to check
+ // for NaN.
+ if (cond != lt && cond != gt) {
+ __ bind(&heap_number);
+ // It is a heap number, so return non-equal if it's NaN and equal if
it's
+ // not NaN.
- // The representation of NaN values has all exponent bits (52..62)
set,
- // and not all mantissa bits (0..51) clear.
- // Read top bits of double representation (second word of value).
- __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
- // Test that exponent bits are all set.
- __ Sbfx(r3, r2, HeapNumber::kExponentShift,
HeapNumber::kExponentBits);
- // NaNs have all-one exponents so they sign extend to -1.
- __ cmp(r3, Operand(-1));
- __ b(ne, &return_equal);
+ // The representation of NaN values has all exponent bits (52..62) set,
+ // and not all mantissa bits (0..51) clear.
+ // Read top bits of double representation (second word of value).
+ __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
+ // Test that exponent bits are all set.
+ __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
+ // NaNs have all-one exponents so they sign extend to -1.
+ __ cmp(r3, Operand(-1));
+ __ b(ne, &return_equal);
- // Shift out flag and all exponent bits, retaining only mantissa.
- __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
- // Or with all low-bits of mantissa.
- __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
- __ orr(r0, r3, Operand(r2), SetCC);
- // For equal we already have the right value in r0: Return zero
(equal)
- // if all bits in mantissa are zero (it's an Infinity) and non-zero
if
- // not (it's a NaN). For <= and >= we need to load r0 with the
failing
- // value if it's a NaN.
- if (cond != eq) {
- // All-zero means Infinity means equal.
- __ Ret(eq);
- if (cond == le) {
- __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
- } else {
- __ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
- }
+ // Shift out flag and all exponent bits, retaining only mantissa.
+ __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
+ // Or with all low-bits of mantissa.
+ __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
+ __ orr(r0, r3, Operand(r2), SetCC);
+ // For equal we already have the right value in r0: Return zero
(equal)
+ // if all bits in mantissa are zero (it's an Infinity) and non-zero if
+ // not (it's a NaN). For <= and >= we need to load r0 with the failing
+ // value if it's a NaN.
+ if (cond != eq) {
+ // All-zero means Infinity means equal.
+ __ Ret(eq);
+ if (cond == le) {
+ __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
+ } else {
+ __ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
}
- __ Ret();
}
- // No fall through here.
+ __ Ret();
}
+ // No fall through here.
__ bind(¬_identical);
}
@@ -1678,42 +1688,60 @@
}
-// On entry lhs_ and rhs_ are the values to be compared.
+static void ICCompareStub_CheckInputType(MacroAssembler* masm,
+ Register input,
+ Register scratch,
+ CompareIC::State expected,
+ Label* fail) {
+ Label ok;
+ if (expected == CompareIC::SMI) {
+ __ JumpIfNotSmi(input, fail);
+ } else if (expected == CompareIC::HEAP_NUMBER) {
+ __ JumpIfSmi(input, &ok);
+ __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
+ DONT_DO_SMI_CHECK);
+ }
+ // We could be strict about symbol/string here, but as long as
+ // hydrogen doesn't care, the stub doesn't have to care either.
+ __ bind(&ok);
+}
+
+
+// On entry r1 and r2 are the values to be compared.
// On exit r0 is 0, positive or negative to indicate the result of
// the comparison.
-void CompareStub::Generate(MacroAssembler* masm) {
- ASSERT((lhs_.is(r0) && rhs_.is(r1)) ||
- (lhs_.is(r1) && rhs_.is(r0)));
+void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
+ Register lhs = r1;
+ Register rhs = r0;
+ Condition cc = GetCondition();
+
+ Label miss;
+ ICCompareStub_CheckInputType(masm, lhs, r2, left_, &miss);
+ ICCompareStub_CheckInputType(masm, rhs, r3, right_, &miss);
Label slow; // Call builtin.
Label not_smis, both_loaded_as_doubles, lhs_not_nan;
- if (include_smi_compare_) {
- Label not_two_smis, smi_done;
- __ orr(r2, r1, r0);
- __ JumpIfNotSmi(r2, ¬_two_smis);
- __ mov(r1, Operand(r1, ASR, 1));
- __ sub(r0, r1, Operand(r0, ASR, 1));
- __ Ret();
- __ bind(¬_two_smis);
- } else if (FLAG_debug_code) {
- __ orr(r2, r1, r0);
- __ tst(r2, Operand(kSmiTagMask));
- __ Assert(ne, "CompareStub: unexpected smi operands.");
- }
+ Label not_two_smis, smi_done;
+ __ orr(r2, r1, r0);
+ __ JumpIfNotSmi(r2, ¬_two_smis);
+ __ mov(r1, Operand(r1, ASR, 1));
+ __ sub(r0, r1, Operand(r0, ASR, 1));
+ __ Ret();
+ __ bind(¬_two_smis);
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
// Handle the case where the objects are identical. Either returns the
answer
// or goes to slow. Only falls through if the objects were not
identical.
- EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
+ EmitIdenticalObjectComparison(masm, &slow, cc);
// If either is a Smi (we know that not both are), then they can only
// be strictly equal if the other is a HeapNumber.
STATIC_ASSERT(kSmiTag == 0);
ASSERT_EQ(0, Smi::FromInt(0));
- __ and_(r2, lhs_, Operand(rhs_));
+ __ and_(r2, lhs, Operand(rhs));
__ JumpIfNotSmi(r2, ¬_smis);
// One operand is a smi. EmitSmiNonsmiComparison generates code that
can:
// 1) Return the answer.
@@ -1724,7 +1752,7 @@
// comparison. If VFP3 is supported the double values of the numbers
have
// been loaded into d7 and d6. Otherwise, the double values have been
loaded
// into r0, r1, r2, and r3.
- EmitSmiNonsmiComparison(masm, lhs_, rhs_, &lhs_not_nan, &slow, strict_);
+ EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict());
__ bind(&both_loaded_as_doubles);
// The arguments have been converted to doubles and stored in d6 and d7,
if
@@ -1747,7 +1775,7 @@
// If one of the sides was a NaN then the v flag is set. Load r0 with
// whatever it takes to make the comparison fail, since comparisons
with NaN
// always fail.
- if (cc_ == lt || cc_ == le) {
+ if (cc == lt || cc == le) {
__ mov(r0, Operand(GREATER));
} else {
__ mov(r0, Operand(LESS));
@@ -1756,19 +1784,19 @@
} else {
// Checks for NaN in the doubles we have loaded. Can return the
answer or
// fall through if neither is a NaN. Also binds lhs_not_nan.
- EmitNanCheck(masm, &lhs_not_nan, cc_);
+ EmitNanCheck(masm, &lhs_not_nan, cc);
// Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns
the
// answer. Never falls through.
- EmitTwoNonNanDoubleComparison(masm, cc_);
+ EmitTwoNonNanDoubleComparison(masm, cc);
}
__ bind(¬_smis);
// At this point we know we are dealing with two different objects,
// and neither of them is a Smi. The objects are in rhs_ and lhs_.
- if (strict_) {
+ if (strict()) {
// This returns non-equal for some object types, or falls through if it
// was not lucky.
- EmitStrictTwoHeapObjectCompare(masm, lhs_, rhs_);
+ EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
}
Label check_for_symbols;
@@ -1778,8 +1806,8 @@
// that case. If the inputs are not doubles then jumps to
check_for_symbols.
// In this case r2 will contain the type of rhs_. Never falls through.
EmitCheckForTwoHeapNumbers(masm,
- lhs_,
- rhs_,
+ lhs,
+ rhs,
&both_loaded_as_doubles,
&check_for_symbols,
&flat_string_check);
@@ -1787,31 +1815,31 @@
__ bind(&check_for_symbols);
// In the strict case the EmitStrictTwoHeapObjectCompare already took
care of
// symbols.
- if (cc_ == eq && !strict_) {
+ if (cc == eq && !strict()) {
// Returns an answer for two symbols or two detectable objects.
// Otherwise jumps to string case or not both strings case.
// Assumes that r2 is the type of rhs_ on entry.
- EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check,
&slow);
+ EmitCheckForSymbolsOrObjects(masm, lhs, rhs, &flat_string_check,
&slow);
}
// Check for both being sequential ASCII strings, and inline if that is
the
// case.
__ bind(&flat_string_check);
- __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow);
+ __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, r2, r3, &slow);
__ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2,
r3);
- if (cc_ == eq) {
+ if (cc == eq) {
StringCompareStub::GenerateFlatAsciiStringEquals(masm,
- lhs_,
- rhs_,
+ lhs,
+ rhs,
r2,
r3,
r4);
} else {
StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
- lhs_,
- rhs_,
+ lhs,
+ rhs,
r2,
r3,
r4,
@@ -1821,18 +1849,18 @@
__ bind(&slow);
- __ Push(lhs_, rhs_);
+ __ Push(lhs, rhs);
// Figure out which native to call and setup the arguments.
Builtins::JavaScript native;
- if (cc_ == eq) {
- native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+ if (cc == eq) {
+ native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
} else {
native = Builtins::COMPARE;
int ncr; // NaN compare result
- if (cc_ == lt || cc_ == le) {
+ if (cc == lt || cc == le) {
ncr = GREATER;
} else {
- ASSERT(cc_ == gt || cc_ == ge); // remaining cases
+ ASSERT(cc == gt || cc == ge); // remaining cases
ncr = LESS;
}
__ mov(r0, Operand(Smi::FromInt(ncr)));
@@ -1842,6 +1870,9 @@
// Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
// tagged as a small integer.
__ InvokeBuiltin(native, JUMP_FUNCTION);
+
+ __ bind(&miss);
+ GenerateMiss(masm);
}
@@ -2323,6 +2354,11 @@
UNREACHABLE();
}
}
+
+
+void BinaryOpStub::Initialize() {
+ platform_specific_bit_ = CpuFeatures::IsSupported(VFP2);
+}
void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
@@ -2331,14 +2367,12 @@
__ Push(r1, r0);
__ mov(r2, Operand(Smi::FromInt(MinorKey())));
- __ mov(r1, Operand(Smi::FromInt(op_)));
- __ mov(r0, Operand(Smi::FromInt(operands_type_)));
- __ Push(r2, r1, r0);
+ __ push(r2);
__ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
masm->isolate()),
- 5,
+ 3,
1);
}
@@ -2349,59 +2383,8 @@
}
-void BinaryOpStub::Generate(MacroAssembler* masm) {
- // Explicitly allow generation of nested stubs. It is safe here because
- // generation code does not use any raw pointers.
- AllowStubCallsScope allow_stub_calls(masm, true);
-
- switch (operands_type_) {
- case BinaryOpIC::UNINITIALIZED:
- GenerateTypeTransition(masm);
- break;
- case BinaryOpIC::SMI:
- GenerateSmiStub(masm);
- break;
- case BinaryOpIC::INT32:
- GenerateInt32Stub(masm);
- break;
- case BinaryOpIC::HEAP_NUMBER:
- GenerateHeapNumberStub(masm);
- break;
- case BinaryOpIC::ODDBALL:
- GenerateOddballStub(masm);
- break;
- case BinaryOpIC::BOTH_STRING:
- GenerateBothStringStub(masm);
- break;
- case BinaryOpIC::STRING:
- GenerateStringStub(masm);
- break;
- case BinaryOpIC::GENERIC:
- GenerateGeneric(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void BinaryOpStub::PrintName(StringStream* stream) {
- const char* op_name = Token::Name(op_);
- const char* overwrite_name;
- switch (mode_) {
- case NO_OVERWRITE: overwrite_name = "Alloc"; break;
- case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
- case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
- default: overwrite_name = "UnknownOverwrite"; break;
- }
- stream->Add("BinaryOpStub_%s_%s_%s",
- op_name,
- overwrite_name,
- BinaryOpIC::GetName(operands_type_));
-}
-
-
-void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) {
+void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm,
+ Token::Value op) {
Register left = r1;
Register right = r0;
Register scratch1 = r7;
@@ -2411,7 +2394,7 @@
STATIC_ASSERT(kSmiTag == 0);
Label not_smi_result;
- switch (op_) {
+ switch (op) {
case Token::ADD:
__ add(right, left, Operand(right), SetCC); // Add optimistically.
__ Ret(vc);
@@ -2526,10 +2509,24 @@
}
-void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm,
- bool smi_operands,
- Label* not_numbers,
- Label* gc_required) {
+void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
+ Register result,
+ Register heap_number_map,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required,
+ OverwriteMode mode);
+
+
+void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
+ BinaryOpIC::TypeInfo left_type,
+ BinaryOpIC::TypeInfo right_type,
+ bool smi_operands,
+ Label* not_numbers,
+ Label* gc_required,
+ Label* miss,
+ Token::Value op,
+ OverwriteMode mode) {
Register left = r1;
Register right = r0;
Register scratch1 = r7;
@@ -2541,11 +2538,17 @@
__ AssertSmi(left);
__ AssertSmi(right);
}
+ if (left_type == BinaryOpIC::SMI) {
+ __ JumpIfNotSmi(left, miss);
+ }
+ if (right_type == BinaryOpIC::SMI) {
+ __ JumpIfNotSmi(right, miss);
+ }
Register heap_number_map = r6;
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
- switch (op_) {
+ switch (op) {
case Token::ADD:
case Token::SUB:
case Token::MUL:
@@ -2555,25 +2558,44 @@
// depending on whether VFP3 is available or not.
FloatingPointHelper::Destination destination =
CpuFeatures::IsSupported(VFP2) &&
- op_ != Token::MOD ?
+ op != Token::MOD ?
FloatingPointHelper::kVFPRegisters :
FloatingPointHelper::kCoreRegisters;
// Allocate new heap number for result.
Register result = r5;
- GenerateHeapResultAllocation(
- masm, result, heap_number_map, scratch1, scratch2, gc_required);
+ BinaryOpStub_GenerateHeapResultAllocation(
+ masm, result, heap_number_map, scratch1, scratch2, gc_required,
mode);
// Load the operands.
if (smi_operands) {
FloatingPointHelper::LoadSmis(masm, destination, scratch1,
scratch2);
} else {
- FloatingPointHelper::LoadOperands(masm,
- destination,
- heap_number_map,
- scratch1,
- scratch2,
- not_numbers);
+ // Load right operand to d7 or r2/r3.
+ if (right_type == BinaryOpIC::INT32) {
+ FloatingPointHelper::LoadNumberAsInt32Double(
+ masm, right, destination, d7, d8, r2, r3, heap_number_map,
+ scratch1, scratch2, s0, miss);
+ } else {
+ Label* fail = (right_type == BinaryOpIC::HEAP_NUMBER) ? miss
+ :
not_numbers;
+ FloatingPointHelper::LoadNumber(
+ masm, destination, right, d7, r2, r3, heap_number_map,
+ scratch1, scratch2, fail);
+ }
+ // Load left operand to d6 or r0/r1. This keeps r0/r1 intact if it
+ // jumps to |miss|.
+ if (left_type == BinaryOpIC::INT32) {
+ FloatingPointHelper::LoadNumberAsInt32Double(
+ masm, left, destination, d6, d8, r0, r1, heap_number_map,
+ scratch1, scratch2, s0, miss);
+ } else {
+ Label* fail = (left_type == BinaryOpIC::HEAP_NUMBER) ? miss
+ :
not_numbers;
+ FloatingPointHelper::LoadNumber(
+ masm, destination, left, d6, r0, r1, heap_number_map,
+ scratch1, scratch2, fail);
+ }
}
// Calculate the result.
@@ -2582,7 +2604,7 @@
// d6: Left value
// d7: Right value
CpuFeatures::Scope scope(VFP2);
- switch (op_) {
+ switch (op) {
case Token::ADD:
__ vadd(d5, d6, d7);
break;
@@ -2606,7 +2628,7 @@
} else {
// Call the C function to handle the double operation.
FloatingPointHelper::CallCCodeForDoubleOperation(masm,
- op_,
+ op,
result,
scratch1);
if (FLAG_debug_code) {
@@ -2647,7 +2669,7 @@
}
Label result_not_a_smi;
- switch (op_) {
+ switch (op) {
case Token::BIT_OR:
__ orr(r2, r3, Operand(r2));
break;
@@ -2698,8 +2720,9 @@
__ AllocateHeapNumber(
result, scratch1, scratch2, heap_number_map, gc_required);
} else {
- GenerateHeapResultAllocation(
- masm, result, heap_number_map, scratch1, scratch2,
gc_required);
+ BinaryOpStub_GenerateHeapResultAllocation(
+ masm, result, heap_number_map, scratch1, scratch2, gc_required,
+ mode);
}
// r2: Answer as signed int32.
@@ -2714,7 +2737,7 @@
// mentioned above SHR needs to always produce a positive result.
CpuFeatures::Scope scope(VFP2);
__ vmov(s0, r2);
- if (op_ == Token::SHR) {
+ if (op == Token::SHR) {
__ vcvt_f64_u32(d0, s0);
} else {
__ vcvt_f64_s32(d0, s0);
@@ -2739,12 +2762,14 @@
// Generate the smi code. If the operation on smis are successful this
return is
// generated. If the result is not a smi and heap number allocation is not
// requested the code falls through. If number allocation is requested but
a
-// heap number cannot be allocated the code jumps to the lable gc_required.
-void BinaryOpStub::GenerateSmiCode(
+// heap number cannot be allocated the code jumps to the label gc_required.
+void BinaryOpStub_GenerateSmiCode(
MacroAssembler* masm,
Label* use_runtime,
Label* gc_required,
- SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
+ Token::Value op,
+ BinaryOpStub::SmiCodeGenerateHeapNumberResults
allow_heapnumber_results,
+ OverwriteMode mode) {
Label not_smis;
Register left = r1;
@@ -2757,12 +2782,14 @@
__ JumpIfNotSmi(scratch1, ¬_smis);
// If the smi-smi operation results in a smi return is generated.
- GenerateSmiSmiOperation(masm);
+ BinaryOpStub_GenerateSmiSmiOperation(masm, op);
// If heap number results are possible generate the result in an
allocated
// heap number.
- if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) {
- GenerateFPOperation(masm, true, use_runtime, gc_required);
+ if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) {
+ BinaryOpStub_GenerateFPOperation(
+ masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true,
+ use_runtime, gc_required, ¬_smis, op, mode);
}
__ bind(¬_smis);
}
@@ -2774,14 +2801,14 @@
if (result_type_ == BinaryOpIC::UNINITIALIZED ||
result_type_ == BinaryOpIC::SMI) {
// Only allow smi results.
- GenerateSmiCode(masm, &call_runtime, NULL, NO_HEAPNUMBER_RESULTS);
+ BinaryOpStub_GenerateSmiCode(
+ masm, &call_runtime, NULL, op_, NO_HEAPNUMBER_RESULTS, mode_);
} else {
// Allow heap number result and don't make a transition if a heap
number
// cannot be allocated.
- GenerateSmiCode(masm,
- &call_runtime,
- &call_runtime,
- ALLOW_HEAPNUMBER_RESULTS);
+ BinaryOpStub_GenerateSmiCode(
+ masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS,
+ mode_);
}
// Code falls through if the result is not returned as either a smi or
heap
@@ -2789,23 +2816,14 @@
GenerateTypeTransition(masm);
__ bind(&call_runtime);
+ GenerateRegisterArgsPush(masm);
GenerateCallRuntime(masm);
}
-
-
-void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
- ASSERT(operands_type_ == BinaryOpIC::STRING);
- ASSERT(op_ == Token::ADD);
- // Try to add arguments as strings, otherwise, transition to the generic
- // BinaryOpIC type.
- GenerateAddStrings(masm);
- GenerateTypeTransition(masm);
-}
void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
Label call_runtime;
- ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING);
+ ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ ==
BinaryOpIC::STRING);
***The diff for this file has been truncated for email.***
=======================================
--- /trunk/src/arm/code-stubs-arm.h Wed Oct 10 10:07:22 2012
+++ /trunk/src/arm/code-stubs-arm.h Fri Nov 16 06:43:43 2012
@@ -142,108 +142,6 @@
};
-class BinaryOpStub: public CodeStub {
- public:
- BinaryOpStub(Token::Value op, OverwriteMode mode)
- : op_(op),
- mode_(mode),
- operands_type_(BinaryOpIC::UNINITIALIZED),
- result_type_(BinaryOpIC::UNINITIALIZED) {
- use_vfp2_ = CpuFeatures::IsSupported(VFP2);
- ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
- }
-
- BinaryOpStub(
- int key,
- BinaryOpIC::TypeInfo operands_type,
- BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
- : op_(OpBits::decode(key)),
- mode_(ModeBits::decode(key)),
- use_vfp2_(VFP2Bits::decode(key)),
- operands_type_(operands_type),
- result_type_(result_type) { }
-
- private:
- enum SmiCodeGenerateHeapNumberResults {
- ALLOW_HEAPNUMBER_RESULTS,
- NO_HEAPNUMBER_RESULTS
- };
-
- Token::Value op_;
- OverwriteMode mode_;
- bool use_vfp2_;
-
- // Operand type information determined at runtime.
- BinaryOpIC::TypeInfo operands_type_;
- BinaryOpIC::TypeInfo result_type_;
-
- virtual void PrintName(StringStream* stream);
-
- // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM.
- class ModeBits: public BitField<OverwriteMode, 0, 2> {};
- class OpBits: public BitField<Token::Value, 2, 7> {};
- class VFP2Bits: public BitField<bool, 9, 1> {};
- class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3>
{};
- class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3>
{};
-
- Major MajorKey() { return BinaryOp; }
- int MinorKey() {
- return OpBits::encode(op_)
- | ModeBits::encode(mode_)
- | VFP2Bits::encode(use_vfp2_)
- | OperandTypeInfoBits::encode(operands_type_)
- | ResultTypeInfoBits::encode(result_type_);
- }
-
- void Generate(MacroAssembler* masm);
- void GenerateGeneric(MacroAssembler* masm);
- void GenerateSmiSmiOperation(MacroAssembler* masm);
- void GenerateFPOperation(MacroAssembler* masm,
- bool smi_operands,
- Label* not_numbers,
- Label* gc_required);
- void GenerateSmiCode(MacroAssembler* masm,
- Label* use_runtime,
- Label* gc_required,
- SmiCodeGenerateHeapNumberResults
heapnumber_results);
- void GenerateLoadArguments(MacroAssembler* masm);
- void GenerateReturn(MacroAssembler* masm);
- void GenerateUninitializedStub(MacroAssembler* masm);
- void GenerateSmiStub(MacroAssembler* masm);
- void GenerateInt32Stub(MacroAssembler* masm);
- void GenerateHeapNumberStub(MacroAssembler* masm);
- void GenerateOddballStub(MacroAssembler* masm);
- void GenerateStringStub(MacroAssembler* masm);
- void GenerateBothStringStub(MacroAssembler* masm);
- void GenerateGenericStub(MacroAssembler* masm);
- void GenerateAddStrings(MacroAssembler* masm);
- void GenerateCallRuntime(MacroAssembler* masm);
-
- void GenerateHeapResultAllocation(MacroAssembler* masm,
- Register result,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- Label* gc_required);
- void GenerateRegisterArgsPush(MacroAssembler* masm);
- void GenerateTypeTransition(MacroAssembler* masm);
- void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
-
- virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
-
- virtual InlineCacheState GetICState() {
- return BinaryOpIC::ToState(operands_type_);
- }
-
- virtual void FinishCode(Handle<Code> code) {
- code->set_binary_op_type(operands_type_);
- code->set_binary_op_result_type(result_type_);
- }
-
- friend class CodeGenerator;
-};
-
-
class StringHelper : public AllStatic {
public:
// Generate code for copying characters using a simple loop. This should
only
@@ -724,20 +622,6 @@
Register scratch1,
Register scratch2);
- // Loads objects from r0 and r1 (right and left in binary operations)
into
- // floating point registers. Depending on the destination the values
ends up
- // either d7 and d6 or in r2/r3 and r0/r1 respectively. If the
destination is
- // floating point registers VFP3 must be supported. If core registers are
- // requested when VFP3 is supported d6 and d7 will still be scratched. If
- // either r0 or r1 is not a number (not smi and not heap number object)
the
- // not_number label is jumped to with r0 and r1 intact.
- static void LoadOperands(MacroAssembler* masm,
- FloatingPointHelper::Destination destination,
- Register heap_number_map,
- Register scratch1,
- Register scratch2,
- Label* not_number);
-
// Convert the smi or heap number in object to an int32 using the rules
// for ToInt32 as described in ECMAScript 9.5.: the value is truncated
// and brought into the range -2^31 .. +2^31 - 1.
@@ -836,7 +720,12 @@
Register heap_number_result,
Register scratch);
- private:
+ // Loads the objects from |object| into floating point registers.
+ // Depending on |destination| the value ends up either in |dst| or
+ // in |dst1|/|dst2|. If |destination| is kVFPRegisters, then VFP3
+ // must be supported. If kCoreRegisters are requested and VFP3 is
+ // supported, |dst| will be scratched. If |object| is neither smi nor
+ // heap number, |not_number| is jumped to with |object| still intact.
static void LoadNumber(MacroAssembler* masm,
FloatingPointHelper::Destination destination,
Register object,
=======================================
--- /trunk/src/arm/codegen-arm.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/arm/codegen-arm.cc Fri Nov 16 06:43:43 2012
@@ -416,7 +416,7 @@
__ b(ne, &external_string);
// Prepare sequential strings
- STATIC_ASSERT(SeqTwoByteString::kHeaderSize ==
SeqAsciiString::kHeaderSize);
+ STATIC_ASSERT(SeqTwoByteString::kHeaderSize ==
SeqOneByteString::kHeaderSize);
__ add(string,
string,
Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
=======================================
--- /trunk/src/arm/disasm-arm.cc Wed Oct 31 03:02:10 2012
+++ /trunk/src/arm/disasm-arm.cc Fri Nov 16 06:43:43 2012
@@ -1098,6 +1098,7 @@
// Dd = vadd(Dn, Dm)
// Dd = vsub(Dn, Dm)
// Dd = vmul(Dn, Dm)
+// Dd = vmla(Dn, Dm)
// Dd = vdiv(Dn, Dm)
// vcmp(Dd, Dm)
// vmrs
@@ -1160,6 +1161,12 @@
} else {
Unknown(instr); // Not used by V8.
}
+ } else if ((instr->Opc1Value() == 0x0) && !(instr->Opc3Value() & 0x1))
{
+ if (instr->SzValue() == 0x1) {
+ Format(instr, "vmla.f64'cond 'Dd, 'Dn, 'Dm");
+ } else {
+ Unknown(instr); // Not used by V8.
+ }
} else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1))
{
if (instr->SzValue() == 0x1) {
Format(instr, "vdiv.f64'cond 'Dd, 'Dn, 'Dm");
=======================================
--- /trunk/src/arm/full-codegen-arm.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/arm/full-codegen-arm.cc Fri Nov 16 06:43:43 2012
@@ -130,7 +130,7 @@
handler_table_ =
isolate()->factory()->NewFixedArray(function()->handler_count(),
TENURED);
profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell(
- Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget)));
+ Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
SetFunctionPosition(function());
Comment cmnt(masm_, "[ function compiled by full code generator");
@@ -2377,7 +2377,7 @@
VariableProxy* proxy = callee->AsVariableProxy();
Property* property = callee->AsProperty();
- if (proxy != NULL && proxy->var()->is_possibly_eval()) {
+ if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
// In a call to eval, we first call %ResolvePossiblyDirectEval to
// resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given
@@ -3624,7 +3624,7 @@
__ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
__ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
__ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
- __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset));
+ __ ldr(scratch1, FieldMemOperand(string,
SeqOneByteString::kLengthOffset));
__ add(string_length, string_length, Operand(scratch1), SetCC);
__ b(vs, &bailout);
__ cmp(element, elements_end);
@@ -3653,7 +3653,7 @@
// Add (separator length times array_length) - separator length to the
// string_length to get the length of the result string. array_length is
not
// smi but the other values are, so the result is a smi
- __ ldr(scratch1, FieldMemOperand(separator,
SeqAsciiString::kLengthOffset));
+ __ ldr(scratch1, FieldMemOperand(separator,
SeqOneByteString::kLengthOffset));
__ sub(string_length, string_length, Operand(scratch1));
__ smull(scratch2, ip, array_length, scratch1);
// Check for smi overflow. No overflow if higher 33 bits of 64-bit
result are
@@ -3691,10 +3691,10 @@
array_length = no_reg;
__ add(result_pos,
result,
- Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+ Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
// Check the length of the separator.
- __ ldr(scratch1, FieldMemOperand(separator,
SeqAsciiString::kLengthOffset));
+ __ ldr(scratch1, FieldMemOperand(separator,
SeqOneByteString::kLengthOffset));
__ cmp(scratch1, Operand(Smi::FromInt(1)));
__ b(eq, &one_char_separator);
__ b(gt, &long_separator);
@@ -3710,7 +3710,9 @@
__ ldr(string, MemOperand(element, kPointerSize, PostIndex));
__ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
__ SmiUntag(string_length);
- __ add(string, string, Operand(SeqAsciiString::kHeaderSize -
kHeapObjectTag));
+ __ add(string,
+ string,
+ Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
__ CopyBytes(string, result_pos, string_length, scratch1);
__ cmp(element, elements_end);
__ b(lt, &empty_separator_loop); // End while (element < elements_end).
@@ -3720,7 +3722,7 @@
// One-character separator case
__ bind(&one_char_separator);
// Replace separator with its ASCII character value.
- __ ldrb(separator, FieldMemOperand(separator,
SeqAsciiString::kHeaderSize));
+ __ ldrb(separator, FieldMemOperand(separator,
SeqOneByteString::kHeaderSize));
// Jump into the loop after the code that copies the separator, so the
first
// element is not preceded by a separator
__ jmp(&one_char_separator_loop_entry);
@@ -3740,7 +3742,9 @@
__ ldr(string, MemOperand(element, kPointerSize, PostIndex));
__ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
__ SmiUntag(string_length);
- __ add(string, string, Operand(SeqAsciiString::kHeaderSize -
kHeapObjectTag));
+ __ add(string,
+ string,
+ Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
__ CopyBytes(string, result_pos, string_length, scratch1);
__ cmp(element, elements_end);
__ b(lt, &one_char_separator_loop); // End while (element <
elements_end).
@@ -3761,14 +3765,16 @@
__ SmiUntag(string_length);
__ add(string,
separator,
- Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+ Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
__ CopyBytes(string, result_pos, string_length, scratch1);
__ bind(&long_separator);
__ ldr(string, MemOperand(element, kPointerSize, PostIndex));
__ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
__ SmiUntag(string_length);
- __ add(string, string, Operand(SeqAsciiString::kHeaderSize -
kHeapObjectTag));
+ __ add(string,
+ string,
+ Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
__ CopyBytes(string, result_pos, string_length, scratch1);
__ cmp(element, elements_end);
__ b(lt, &long_separator_loop); // End while (element < elements_end).
@@ -4073,7 +4079,8 @@
// Call stub. Undo operation first.
__ sub(r0, r0, Operand(Smi::FromInt(count_value)));
}
- __ mov(r1, Operand(Smi::FromInt(count_value)));
+ __ mov(r1, r0);
+ __ mov(r0, Operand(Smi::FromInt(count_value)));
// Record position before stub call.
SetSourcePosition(expr->position());
@@ -4298,29 +4305,7 @@
default: {
VisitForAccumulatorValue(expr->right());
- Condition cond = eq;
- switch (op) {
- case Token::EQ_STRICT:
- case Token::EQ:
- cond = eq;
- break;
- case Token::LT:
- cond = lt;
- break;
- case Token::GT:
- cond = gt;
- break;
- case Token::LTE:
- cond = le;
- break;
- case Token::GTE:
- cond = ge;
- break;
- case Token::IN:
- case Token::INSTANCEOF:
- default:
- UNREACHABLE();
- }
+ Condition cond = CompareIC::ComputeCondition(op);
__ pop(r1);
bool inline_smi_code = ShouldInlineSmiCase(op);
=======================================
--- /trunk/src/arm/ic-arm.cc Mon Oct 22 06:09:53 2012
+++ /trunk/src/arm/ic-arm.cc Fri Nov 16 06:43:43 2012
@@ -1379,7 +1379,6 @@
__ bind(&fast_double_without_map_check);
__ StoreNumberToDoubleElements(value,
key,
- receiver,
elements, // Overwritten.
r3, // Scratch regs...
r4,
@@ -1699,36 +1698,15 @@
}
-void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
- HandleScope scope;
- Handle<Code> rewritten;
- State previous_state = GetState();
- State state = TargetState(previous_state, false, x, y);
- if (state == GENERIC) {
- CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
- rewritten = stub.GetCode();
- } else {
- ICCompareStub stub(op_, state);
- if (state == KNOWN_OBJECTS) {
- stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
- }
- rewritten = stub.GetCode();
- }
- set_target(*rewritten);
-
-#ifdef DEBUG
- if (FLAG_trace_ic) {
- PrintF("[CompareIC (%s->%s)#%s]\n",
- GetStateName(previous_state),
- GetStateName(state),
- Token::Name(op_));
- }
-#endif
+bool CompareIC::HasInlinedSmiCode(Address address) {
+ // The address of the instruction following the call.
+ Address cmp_instruction_address =
+ Assembler::return_address_from_call_start(address);
- // Activate inlined smi code.
- if (previous_state == UNINITIALIZED) {
- PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
- }
+ // If the instruction following the call is not a cmp rx, #yyy, nothing
+ // was inlined.
+ Instr instr = Assembler::instr_at(cmp_instruction_address);
+ return Assembler::IsCmpImmediate(instr);
}
=======================================
--- /trunk/src/arm/lithium-arm.cc Tue Nov 13 05:56:09 2012
+++ /trunk/src/arm/lithium-arm.cc Fri Nov 16 06:43:43 2012
@@ -1303,8 +1303,21 @@
return DefineAsRegister(mul);
} else if (instr->representation().IsDouble()) {
+ if (instr->UseCount() == 1 && instr->uses().value()->IsAdd()) {
+ HAdd* add = HAdd::cast(instr->uses().value());
+ if (instr == add->left()) {
+ // This mul is the lhs of an add. The add and mul will be folded
+ // into a multiply-add.
+ return NULL;
+ }
+ if (instr == add->right() && !add->left()->IsMul()) {
+ // This mul is the rhs of an add, where the lhs is not another mul.
+ // The add and mul will be folded into a multiply-add.
+ return NULL;
+ }
+ }
+
return DoArithmeticD(Token::MUL, instr);
-
} else {
return DoArithmeticT(Token::MUL, instr);
}
@@ -1330,6 +1343,13 @@
}
}
+LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
+ LOperand* multiplier_op = UseRegisterAtStart(mul->left());
+ LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
+ LOperand* addend_op = UseRegisterAtStart(addend);
+ return DefineSameAsFirst(new(zone()) LMultiplyAddD(addend_op,
multiplier_op,
+ multiplicand_op));
+}
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
if (instr->representation().IsInteger32()) {
@@ -1344,6 +1364,14 @@
}
return result;
} else if (instr->representation().IsDouble()) {
+ if (instr->left()->IsMul())
+ return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
+
+ if (instr->right()->IsMul()) {
+ ASSERT(!instr->left()->IsMul());
+ return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
+ }
+
return DoArithmeticD(Token::ADD, instr);
} else {
ASSERT(instr->representation().IsTagged());
@@ -1409,7 +1437,7 @@
LInstruction* LChunkBuilder::DoCompareIDAndBranch(
HCompareIDAndBranch* instr) {
- Representation r = instr->GetInputRepresentation();
+ Representation r = instr->representation();
if (r.IsInteger32()) {
ASSERT(instr->left()->representation().IsInteger32());
ASSERT(instr->right()->representation().IsInteger32());
@@ -2168,7 +2196,7 @@
env->set_ast_id(instr->ast_id());
env->Drop(instr->pop_count());
- for (int i = 0; i < instr->values()->length(); ++i) {
+ for (int i = instr->values()->length() - 1; i >= 0; --i) {
HValue* value = instr->values()->at(i);
if (instr->HasAssignedIndexAt(i)) {
env->Bind(instr->GetAssignedIndexAt(i), value);
=======================================
--- /trunk/src/arm/lithium-arm.h Tue Nov 6 04:13:00 2012
+++ /trunk/src/arm/lithium-arm.h Fri Nov 16 06:43:43 2012
@@ -135,6 +135,7 @@
V(MathMinMax) \
V(ModI) \
V(MulI) \
+ V(MultiplyAddD) \
V(NumberTagD) \
V(NumberTagI) \
V(NumberTagU) \
@@ -621,6 +622,24 @@
};
+// Instruction for computing multiplier * multiplicand + addend.
+class LMultiplyAddD: public LTemplateInstruction<1, 3, 0> {
+ public:
+ LMultiplyAddD(LOperand* addend, LOperand* multiplier,
+ LOperand* multiplicand) {
+ inputs_[0] = addend;
+ inputs_[1] = multiplier;
+ inputs_[2] = multiplicand;
+ }
+
+ LOperand* addend() { return inputs_[0]; }
+ LOperand* multiplier() { return inputs_[1]; }
+ LOperand* multiplicand() { return inputs_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MultiplyAddD, "multiply-add-d")
+};
+
+
class LCmpIDAndBranch: public LControlInstruction<2, 0> {
public:
LCmpIDAndBranch(LOperand* left, LOperand* right) {
@@ -636,7 +655,7 @@
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const {
- return hydrogen()->GetInputRepresentation().IsDouble();
+ return hydrogen()->representation().IsDouble();
}
virtual void PrintDataTo(StringStream* stream);
@@ -2396,6 +2415,8 @@
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
#undef DECLARE_DO
+ LInstruction* DoMultiplyAdd(HMul* mul, HValue* addend);
+
static bool HasMagicNumberForDivisor(int32_t divisor);
static HValue* SimplifiedDividendForMathFloorOfDiv(HValue* val);
static HValue* SimplifiedDivisorForMathFloorOfDiv(HValue* val);
=======================================
--- /trunk/src/arm/lithium-codegen-arm.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/arm/lithium-codegen-arm.cc Fri Nov 16 06:43:43 2012
@@ -230,7 +230,30 @@
}
if (emit_instructions) {
- Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
+ if (FLAG_code_comments) {
+ HValue* hydrogen = instr->hydrogen_value();
+ if (hydrogen != NULL) {
+ if (hydrogen->IsChange()) {
+ HValue* changed_value = HChange::cast(hydrogen)->value();
+ int use_id = 0;
+ const char* use_mnemo = "dead";
+ if (hydrogen->UseCount() >= 1) {
+ HValue* use_value = hydrogen->uses().value();
+ use_id = use_value->id();
+ use_mnemo = use_value->Mnemonic();
+ }
+ Comment(";;; @%d: %s. <of #%d %s for #%d %s>",
+ current_instruction_, instr->Mnemonic(),
+ changed_value->id(), changed_value->Mnemonic(),
+ use_id, use_mnemo);
+ } else {
+ Comment(";;; @%d: %s. <#%d>", current_instruction_,
+ instr->Mnemonic(), hydrogen->id());
+ }
+ } else {
+ Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
+ }
+ }
instr->CompileToNative(this);
}
}
@@ -1295,6 +1318,18 @@
DeoptimizeIf(al, instr->environment());
__ bind(&done);
}
+
+
+void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) {
+ DwVfpRegister addend = ToDoubleRegister(instr->addend());
+ DwVfpRegister multiplier = ToDoubleRegister(instr->multiplier());
+ DwVfpRegister multiplicand = ToDoubleRegister(instr->multiplicand());
+
+ // This is computed in-place.
+ ASSERT(
addend.is(ToDoubleRegister(instr->result())));
+
+ __ vmla(addend, multiplier, multiplicand);
+}
void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
=======================================
--- /trunk/src/arm/macro-assembler-arm.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/arm/macro-assembler-arm.cc Fri Nov 16 06:43:43 2012
@@ -1786,10 +1786,10 @@
Label* gc_required) {
// Calculate the number of bytes needed for the characters in the string
while
// observing object alignment.
- ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
+ ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
ASSERT(kCharSize == 1);
add(scratch1, length,
- Operand(kObjectAlignmentMask + SeqAsciiString::kHeaderSize));
+ Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize));
and_(scratch1, scratch1, Operand(~kObjectAlignmentMask));
// Allocate ASCII string in new space.
@@ -1955,13 +1955,13 @@
void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
Register key_reg,
- Register receiver_reg,
Register elements_reg,
Register scratch1,
Register scratch2,
Register scratch3,
Register scratch4,
- Label* fail) {
+ Label* fail,
+ int elements_offset) {
Label smi_value, maybe_nan, have_double_value, is_nan, done;
Register mantissa_reg = scratch2;
Register exponent_reg = scratch3;
@@ -1988,8 +1988,10 @@
bind(&have_double_value);
add(scratch1, elements_reg,
Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
- str(mantissa_reg, FieldMemOperand(scratch1,
FixedDoubleArray::kHeaderSize));
- uint32_t offset = FixedDoubleArray::kHeaderSize +
sizeof(kHoleNanLower32);
+ str(mantissa_reg, FieldMemOperand(
+ scratch1, FixedDoubleArray::kHeaderSize - elements_offset));
+ uint32_t offset = FixedDoubleArray::kHeaderSize - elements_offset +
+ sizeof(kHoleNanLower32);
str(exponent_reg, FieldMemOperand(scratch1, offset));
jmp(&done);
@@ -2010,7 +2012,8 @@
bind(&smi_value);
add(scratch1, elements_reg,
- Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
+ Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag -
+ elements_offset));
add(scratch1, scratch1,
Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
// scratch1 is now effective address of the double element
@@ -3338,8 +3341,10 @@
Register scratch2,
Label* failure) {
int kFlatAsciiStringMask =
- kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+ kIsNotStringMask | kStringEncodingMask | kAsciiDataHintMask |
+ kStringRepresentationMask;
int kFlatAsciiStringTag = ASCII_STRING_TYPE;
+ ASSERT_EQ(ASCII_STRING_TYPE, ASCII_STRING_TYPE & kFlatAsciiStringMask);
and_(scratch1, first, Operand(kFlatAsciiStringMask));
and_(scratch2, second, Operand(kFlatAsciiStringMask));
cmp(scratch1, Operand(kFlatAsciiStringTag));
@@ -3353,8 +3358,10 @@
Register
scratch,
Label*
failure) {
int kFlatAsciiStringMask =
- kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+ kIsNotStringMask | kStringEncodingMask | kAsciiDataHintMask |
+ kStringRepresentationMask;
int kFlatAsciiStringTag = ASCII_STRING_TYPE;
+ ASSERT_EQ(ASCII_STRING_TYPE, ASCII_STRING_TYPE & kFlatAsciiStringMask);
and_(scratch, type, Operand(kFlatAsciiStringMask));
cmp(scratch, Operand(kFlatAsciiStringTag));
b(ne, failure);
=======================================
--- /trunk/src/arm/macro-assembler-arm.h Mon Nov 12 06:53:34 2012
+++ /trunk/src/arm/macro-assembler-arm.h Fri Nov 16 06:43:43 2012
@@ -831,14 +831,14 @@
// case scratch2, scratch3 and scratch4 are unmodified.
void StoreNumberToDoubleElements(Register value_reg,
Register key_reg,
- Register receiver_reg,
// All regs below here overwritten.
Register elements_reg,
Register scratch1,
Register scratch2,
Register scratch3,
Register scratch4,
- Label* fail);
+ Label* fail,
+ int elements_offset = 0);
// Compare an object's map with the specified map and its transitioned
// elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Condition
flags are
=======================================
--- /trunk/src/arm/simulator-arm.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/arm/simulator-arm.cc Fri Nov 16 06:43:43 2012
@@ -2778,6 +2778,20 @@
double dm_value = get_double_from_d_register(vm);
double dd_value = dn_value * dm_value;
set_d_register_from_double(vd, dd_value);
+ } else if ((instr->Opc1Value() == 0x0) && !(instr->Opc3Value() & 0x1))
{
+ // vmla
+ if (instr->SzValue() != 0x1) {
+ UNREACHABLE(); // Not used by V8.
+ }
+
+ double dd_value = get_double_from_d_register(vd);
+ double dn_value = get_double_from_d_register(vn);
+ double dm_value = get_double_from_d_register(vm);
+
+ // Note: we do the mul and add in separate steps to avoid getting a
result
+ // with too high precision.
+ set_d_register_from_double(vd, dn_value * dm_value);
+ set_d_register_from_double(vd, get_double_from_d_register(vd) +
dd_value);
} else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1))
{
// vdiv
if (instr->SzValue() != 0x1) {
=======================================
--- /trunk/src/arm/stub-cache-arm.cc Tue Nov 13 05:56:09 2012
+++ /trunk/src/arm/stub-cache-arm.cc Fri Nov 16 06:43:43 2012
@@ -1623,7 +1623,7 @@
Label call_builtin;
if (argc == 1) { // Otherwise fall through to call the builtin.
- Label attempt_to_grow_elements;
+ Label attempt_to_grow_elements, with_write_barrier, check_double;
Register elements = r6;
Register end_elements = r5;
@@ -1634,10 +1634,9 @@
__ CheckMap(elements,
r0,
Heap::kFixedArrayMapRootIndex,
- &call_builtin,
+ &check_double,
DONT_DO_SMI_CHECK);
-
// Get the array's length into r0 and calculate new length.
__ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
STATIC_ASSERT(kSmiTagSize == 1);
@@ -1652,7 +1651,6 @@
__ b(gt, &attempt_to_grow_elements);
// Check if value is a smi.
- Label with_write_barrier;
__ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
__ JumpIfNotSmi(r4, &with_write_barrier);
@@ -1668,6 +1666,40 @@
FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
__ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex));
+ // Check for a smi.
+ __ Drop(argc + 1);
+ __ Ret();
+
+ __ bind(&check_double);
+
+ // Check that the elements are in fast mode and writable.
+ __ CheckMap(elements,
+ r0,
+ Heap::kFixedDoubleArrayMapRootIndex,
+ &call_builtin,
+ DONT_DO_SMI_CHECK);
+
+ // Get the array's length into r0 and calculate new length.
+ __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
+ STATIC_ASSERT(kSmiTagSize == 1);
+ STATIC_ASSERT(kSmiTag == 0);
+ __ add(r0, r0, Operand(Smi::FromInt(argc)));
+
+ // Get the elements' length.
+ __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
+
+ // Check if we could survive without allocation.
+ __ cmp(r0, r4);
+ __ b(gt, &call_builtin);
+
+ __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
+ __ StoreNumberToDoubleElements(
+ r4, r0, elements, r3, r5, r2, r9,
+ &call_builtin, argc * kDoubleSize);
+
+ // Save new length.
+ __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
+
// Check for a smi.
__ Drop(argc + 1);
__ Ret();
@@ -1683,6 +1715,11 @@
// In case of fast smi-only, convert to fast object, otherwise
bail out.
__ bind(¬_fast_object);
__ CheckFastSmiElements(r3, r7, &call_builtin);
+
+ __ ldr(r7, FieldMemOperand(r4, HeapObject::kMapOffset));
+ __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
+ __ cmp(r7, ip);
+ __ b(eq, &call_builtin);
// edx: receiver
// r3: map
Label try_holey_map;
@@ -3819,20 +3856,20 @@
__ AllocateHeapNumber(r5, r3, r4, r6, &slow, TAG_RESULT);
// Now we can use r0 for the result as key is not needed any more.
__ mov(r0, r5);
- Register dst1 = r1;
- Register dst2 = r3;
+ Register dst_mantissa = r1;
+ Register dst_exponent = r3;
FloatingPointHelper::Destination dest =
FloatingPointHelper::kCoreRegisters;
FloatingPointHelper::ConvertIntToDouble(masm,
value,
dest,
d0,
- dst1,
- dst2,
+ dst_mantissa,
+ dst_exponent,
r9,
s0);
- __ str(dst1, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
- __ str(dst2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
+ __ str(dst_mantissa, FieldMemOperand(r0,
HeapNumber::kMantissaOffset));
+ __ str(dst_exponent, FieldMemOperand(r0,
HeapNumber::kExponentOffset));
__ Ret();
}
} else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
@@ -4101,7 +4138,7 @@
}
FloatingPointHelper::ConvertIntToDouble(
masm, r5, destination,
- d0, r6, r7, // These are: double_dst, dst1, dst2.
+ d0, r6, r7, // These are: double_dst, dst_mantissa,
dst_exponent.
r4, s2); // These are: scratch2, single_scratch.
if (destination == FloatingPointHelper::kVFPRegisters) {
CpuFeatures::Scope scope(VFP2);
@@ -4698,7 +4735,6 @@
__ bind(&finish_store);
__ StoreNumberToDoubleElements(value_reg,
key_reg,
- receiver_reg,
// All registers after this are
overwritten.
elements_reg,
scratch1,
=======================================
--- /trunk/src/array.js Mon Nov 12 06:53:34 2012
+++ /trunk/src/array.js Fri Nov 16 06:43:43 2012
@@ -413,6 +413,7 @@
["Array.prototype.join"]);
}
+ var length = TO_UINT32(this.length);
if (IS_UNDEFINED(separator)) {
separator = ',';
} else if (!IS_STRING(separator)) {
@@ -422,7 +423,7 @@
var result = %_FastAsciiArrayJoin(this, separator);
if (!IS_UNDEFINED(result)) return result;
- return Join(this, TO_UINT32(this.length), separator, ConvertToString);
+ return Join(this, length, separator, ConvertToString);
}
=======================================
--- /trunk/src/ast.cc Wed Oct 10 10:07:22 2012
+++ /trunk/src/ast.cc Fri Nov 16 06:43:43 2012
@@ -476,6 +476,7 @@
void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
TypeInfo info = oracle->SwitchType(this);
+ if (info.IsUninitialized()) info = TypeInfo::Unknown();
if (info.IsSmi()) {
compare_type_ = SMI_ONLY;
} else if (info.IsSymbol()) {
@@ -602,18 +603,6 @@
target_ = oracle->GetCallNewTarget(this);
}
}
-
-
-void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
- TypeInfo info = oracle->CompareType(this);
- if (info.IsSmi()) {
- compare_type_ = SMI_ONLY;
- } else if (info.IsNonPrimitive()) {
- compare_type_ = OBJECT_ONLY;
- } else {
- ASSERT(compare_type_ == NONE);
- }
-}
void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle*
oracle) {
=======================================
--- /trunk/src/ast.h Wed Oct 10 10:07:22 2012
+++ /trunk/src/ast.h Fri Nov 16 06:43:43 2012
@@ -1777,9 +1777,6 @@
// Type feedback information.
TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); }
- void RecordTypeFeedback(TypeFeedbackOracle* oracle);
- bool IsSmiCompare() { return compare_type_ == SMI_ONLY; }
- bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; }
// Match special cases.
bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
@@ -1796,8 +1793,7 @@
op_(op),
left_(left),
right_(right),
- pos_(pos),
- compare_type_(NONE) {
+ pos_(pos) {
ASSERT(Token::IsCompareOp(op));
}
@@ -1806,9 +1802,6 @@
Expression* left_;
Expression* right_;
int pos_;
-
- enum CompareTypeFeedback { NONE, SMI_ONLY, OBJECT_ONLY };
- CompareTypeFeedback compare_type_;
};
=======================================
--- /trunk/src/atomicops.h Thu Sep 20 05:51:09 2012
+++ /trunk/src/atomicops.h Fri Nov 16 06:43:43 2012
@@ -151,7 +151,9 @@
} } // namespace v8::internal
// Include our platform specific implementation.
-#if defined(_MSC_VER) && \
+#if defined(THREAD_SANITIZER)
+#include "atomicops_internals_tsan.h"
+#elif defined(_MSC_VER) && \
(defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64))
#include "atomicops_internals_x86_msvc.h"
#elif defined(__APPLE__) && \
=======================================
--- /trunk/src/bootstrapper.h Wed Aug 29 08:32:24 2012
+++ /trunk/src/bootstrapper.h Fri Nov 16 06:43:43 2012
@@ -54,7 +54,7 @@
bool Lookup(Vector<const char> name, Handle<SharedFunctionInfo>* handle)
{
for (int i = 0; i < cache_->length(); i+=2) {
- SeqAsciiString* str = SeqAsciiString::cast(cache_->get(i));
+ SeqOneByteString* str = SeqOneByteString::cast(cache_->get(i));
if (str->IsEqualTo(name)) {
*handle = Handle<SharedFunctionInfo>(
SharedFunctionInfo::cast(cache_->get(i + 1)));
=======================================
--- /trunk/src/builtins.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/builtins.cc Fri Nov 16 06:43:43 2012
@@ -323,6 +323,18 @@
isolate,
isolate->context()->native_context()->array_function());
}
+
+
+static void MoveDoubleElements(FixedDoubleArray* dst,
+ int dst_index,
+ FixedDoubleArray* src,
+ int src_index,
+ int len) {
+ if (len == 0) return;
+ memmove(dst->data_start() + dst_index,
+ src->data_start() + src_index,
+ len * kDoubleSize);
+}
static void MoveElements(Heap* heap,
@@ -351,24 +363,39 @@
}
-static FixedArray* LeftTrimFixedArray(Heap* heap,
- FixedArray* elms,
- int to_trim) {
+static void FillWithHoles(FixedDoubleArray* dst, int from, int to) {
+ for (int i = from; i < to; i++) {
+ dst->set_the_hole(i);
+ }
+}
+
+
+static FixedArrayBase* LeftTrimFixedArray(Heap* heap,
+ FixedArrayBase* elms,
+ int to_trim) {
+ Map* map = elms->map();
+ int entry_size;
+ if (elms->IsFixedArray()) {
+ entry_size = kPointerSize;
+ } else {
+ entry_size = kDoubleSize;
+ }
ASSERT(elms->map() != HEAP->fixed_cow_array_map());
// For now this trick is only applied to fixed arrays in new and paged
space.
// In large object space the object's start must coincide with chunk
// and thus the trick is just not applicable.
ASSERT(!HEAP->lo_space()->Contains(elms));
- STATIC_ASSERT(FixedArray::kMapOffset == 0);
- STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
- STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
+ STATIC_ASSERT(FixedArrayBase::kMapOffset == 0);
+ STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize);
+ STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize);
Object** former_start = HeapObject::RawField(elms, 0);
const int len = elms->length();
- if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
+ if (to_trim > FixedArrayBase::kHeaderSize / entry_size &&
+ elms->IsFixedArray() &&
!heap->new_space()->Contains(elms)) {
// If we are doing a big trim in old space then we zap the space that
was
// formerly part of the array so that the GC (aided by the card-based
@@ -382,14 +409,15 @@
// Technically in new space this write might be omitted (except for
// debug mode which iterates through the heap), but to play safer
// we still do it.
- heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
+ heap->CreateFillerObjectAt(elms->address(), to_trim * entry_size);
- former_start[to_trim] = heap->fixed_array_map();
- former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
+ int new_start_index = to_trim * (entry_size / kPointerSize);
+ former_start[new_start_index] = map;
+ former_start[new_start_index + 1] = Smi::FromInt(len - to_trim);
// Maintain marking consistency for HeapObjectIterator and
// IncrementalMarking.
- int size_delta = to_trim * kPointerSize;
+ int size_delta = to_trim * entry_size;
if (heap->marking()->TransferMark(elms->address(),
elms->address() + size_delta)) {
MemoryChunk::IncrementLiveBytesFromMutator(elms->address(),
-size_delta);
@@ -397,8 +425,8 @@
HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(),
elms->address() + size_delta));
- return FixedArray::cast(HeapObject::FromAddress(
- elms->address() + to_trim * kPointerSize));
+ return FixedArrayBase::cast(HeapObject::FromAddress(
+ elms->address() + to_trim * entry_size));
}
@@ -427,19 +455,14 @@
Map* map = elms->map();
if (map == heap->fixed_array_map()) {
if (args == NULL || array->HasFastObjectElements()) return elms;
- if (array->HasFastDoubleElements()) {
- ASSERT(elms == heap->empty_fixed_array());
- MaybeObject* maybe_transition =
- array->TransitionElementsKind(FAST_ELEMENTS);
- if (maybe_transition->IsFailure()) return maybe_transition;
- return elms;
- }
} else if (map == heap->fixed_cow_array_map()) {
MaybeObject* maybe_writable_result =
array->EnsureWritableFastElements();
if (args == NULL || array->HasFastObjectElements() ||
- maybe_writable_result->IsFailure()) {
+ !maybe_writable_result->To(&elms)) {
return maybe_writable_result;
}
+ } else if (map == heap->fixed_double_array_map()) {
+ if (args == NULL) return elms;
} else {
return NULL;
}
@@ -449,13 +472,28 @@
int args_length = args->length();
if (first_added_arg >= args_length) return array->elements();
- MaybeObject* maybe_array = array->EnsureCanContainElements(
- args,
- first_added_arg,
- args_length - first_added_arg,
- DONT_ALLOW_DOUBLE_ELEMENTS);
- if (maybe_array->IsFailure()) return maybe_array;
- return array->elements();
+ ElementsKind origin_kind = array->map()->elements_kind();
+ ASSERT(!IsFastObjectElementsKind(origin_kind));
+ ElementsKind target_kind = origin_kind;
+ int arg_count = args->length() - first_added_arg;
+ Object** arguments = args->arguments() - first_added_arg - (arg_count -
1);
+ for (int i = 0; i < arg_count; i++) {
+ Object* arg = arguments[i];
+ if (arg->IsHeapObject()) {
+ if (arg->IsHeapNumber()) {
+ target_kind = FAST_DOUBLE_ELEMENTS;
+ } else {
+ target_kind = FAST_ELEMENTS;
+ break;
+ }
+ }
+ }
+ if (target_kind != origin_kind) {
+ MaybeObject* maybe_failure =
array->TransitionElementsKind(target_kind);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ return array->elements();
+ }
+ return elms;
}
@@ -499,75 +537,131 @@
BUILTIN(ArrayPush) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
- if (maybe_elms_obj == NULL) {
- return CallJsBuiltin(isolate, "ArrayPush", args);
- }
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms_obj =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
+ if (maybe_elms_obj == NULL) {
+ return CallJsBuiltin(isolate, "ArrayPush", args);
}
- FixedArray* elms = FixedArray::cast(elms_obj);
- JSArray* array = JSArray::cast(receiver);
+ if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
- if (FLAG_harmony_observation && array->map()->is_observed()) {
+ if (FLAG_harmony_observation &&
+ JSObject::cast(receiver)->map()->is_observed()) {
return CallJsBuiltin(isolate, "ArrayPush", args);
}
- int len = Smi::cast(array->length())->value();
- int to_add = args.length() - 1;
- if (to_add == 0) {
- return Smi::FromInt(len);
- }
- // Currently fixed arrays cannot grow too big, so
- // we should never hit this case.
- ASSERT(to_add <= (Smi::kMaxValue - len));
+ JSArray* array = JSArray::cast(receiver);
+ ElementsKind kind = array->GetElementsKind();
- int new_length = len + to_add;
+ if (IsFastSmiOrObjectElementsKind(kind)) {
+ FixedArray* elms = FixedArray::cast(elms_obj);
- if (new_length > elms->length()) {
- // New backing storage is needed.
- int capacity = new_length + (new_length >> 1) + 16;
- Object* obj;
- { MaybeObject* maybe_obj =
heap->AllocateUninitializedFixedArray(capacity);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ int len = Smi::cast(array->length())->value();
+ int to_add = args.length() - 1;
+ if (to_add == 0) {
+ return Smi::FromInt(len);
}
- FixedArray* new_elms = FixedArray::cast(obj);
+ // Currently fixed arrays cannot grow too big, so
+ // we should never hit this case.
+ ASSERT(to_add <= (Smi::kMaxValue - len));
- ElementsKind kind = array->GetElementsKind();
- CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, 0, len);
- FillWithHoles(heap, new_elms, new_length, capacity);
+ int new_length = len + to_add;
- elms = new_elms;
- }
+ if (new_length > elms->length()) {
+ // New backing storage is needed.
+ int capacity = new_length + (new_length >> 1) + 16;
+ FixedArray* new_elms;
+ MaybeObject* maybe_obj =
heap->AllocateUninitializedFixedArray(capacity);
+ if (!maybe_obj->To(&new_elms)) return maybe_obj;
- // Add the provided values.
- AssertNoAllocation no_gc;
- WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
- for (int index = 0; index < to_add; index++) {
- elms->set(index + len, args[index + 1], mode);
- }
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, 0, new_elms, kind, 0, len,
elms_obj);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
+ FillWithHoles(heap, new_elms, new_length, capacity);
+
+ elms = new_elms;
+ }
+
+ // Add the provided values.
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+ for (int index = 0; index < to_add; index++) {
+ elms->set(index + len, args[index + 1], mode);
+ }
+
+ if (elms != array->elements()) {
+ array->set_elements(elms);
+ }
+
+ // Set the length.
+ array->set_length(Smi::FromInt(new_length));
+ return Smi::FromInt(new_length);
+ } else {
+ int len = Smi::cast(array->length())->value();
+ int elms_len = elms_obj->length();
+
+ int to_add = args.length() - 1;
+ if (to_add == 0) {
+ return Smi::FromInt(len);
+ }
+ // Currently fixed arrays cannot grow too big, so
+ // we should never hit this case.
+ ASSERT(to_add <= (Smi::kMaxValue - len));
+
+ int new_length = len + to_add;
+
+ FixedDoubleArray* new_elms;
+
+ if (new_length > elms_len) {
+ // New backing storage is needed.
+ int capacity = new_length + (new_length >> 1) + 16;
+ MaybeObject* maybe_obj =
+ heap->AllocateUninitializedFixedDoubleArray(capacity);
+ if (!maybe_obj->To(&new_elms)) return maybe_obj;
+
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, 0, new_elms, kind, 0, len,
elms_obj);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
+
+ FillWithHoles(new_elms, len + to_add, new_elms->length());
+ } else {
+ // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be
the
+ // empty_fixed_array.
+ new_elms = FixedDoubleArray::cast(elms_obj);
+ }
+
+ // Add the provided values.
+ AssertNoAllocation no_gc;
+ int index;
+ for (index = 0; index < to_add; index++) {
+ Object* arg = args[index + 1];
+ new_elms->set(index + len, arg->Number());
+ }
+
+ if (new_elms != array->elements()) {
+ array->set_elements(new_elms);
+ }
- if (elms != array->elements()) {
- array->set_elements(elms);
+ // Set the length.
+ array->set_length(Smi::FromInt(new_length));
+ return Smi::FromInt(new_length);
}
-
- // Set the length.
- array->set_length(Smi::FromInt(new_length));
- return Smi::FromInt(new_length);
}
BUILTIN(ArrayPop) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
- if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop",
args);
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
- }
- FixedArray* elms = FixedArray::cast(elms_obj);
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
+ if (maybe_elms == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
+ if (!maybe_elms->To(&elms_obj)) return maybe_elms;
+
JSArray* array = JSArray::cast(receiver);
if (FLAG_harmony_observation && array->map()->is_observed()) {
@@ -577,38 +671,36 @@
int len = Smi::cast(array->length())->value();
if (len == 0) return heap->undefined_value();
- // Get top element
- Object* top = elms->get(len - 1);
-
- // Set the length.
- array->set_length(Smi::FromInt(len - 1));
-
- if (!top->IsTheHole()) {
- // Delete the top element.
- elms->set_the_hole(len - 1);
- return top;
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ int new_length = len - 1;
+ MaybeObject* maybe_result;
+ if (accessor->HasElement(array, array, new_length, elms_obj)) {
+ maybe_result = accessor->Get(array, array, new_length, elms_obj);
+ } else {
+ maybe_result = array->GetPrototype()->GetElement(len - 1);
}
-
- return array->GetPrototype()->GetElement(len - 1);
+ if (maybe_result->IsFailure()) return maybe_result;
+ MaybeObject* maybe_failure =
+ accessor->SetLength(array, Smi::FromInt(new_length));
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ return maybe_result;
}
BUILTIN(ArrayShift) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
- if (maybe_elms_obj == NULL)
- return CallJsBuiltin(isolate, "ArrayShift", args);
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
- }
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms_obj =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
+ if (maybe_elms_obj == NULL)
+ return CallJsBuiltin(isolate, "ArrayShift", args);
+ if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
+
if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
return CallJsBuiltin(isolate, "ArrayShift", args);
}
- FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastSmiOrObjectElements());
if (FLAG_harmony_observation && array->map()->is_observed()) {
return CallJsBuiltin(isolate, "ArrayShift", args);
@@ -618,18 +710,28 @@
if (len == 0) return heap->undefined_value();
// Get first element
- Object* first = elms->get(0);
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ Object* first;
+ MaybeObject* maybe_first = accessor->Get(receiver, array, 0, elms_obj);
+ if (!maybe_first->To(&first)) return maybe_first;
if (first->IsTheHole()) {
first = heap->undefined_value();
}
- if (!heap->lo_space()->Contains(elms)) {
- array->set_elements(LeftTrimFixedArray(heap, elms, 1));
+ if (!heap->lo_space()->Contains(elms_obj)) {
+ array->set_elements(LeftTrimFixedArray(heap, elms_obj, 1));
} else {
// Shift the elements.
- AssertNoAllocation no_gc;
- MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
- elms->set(len - 1, heap->the_hole_value());
+ if (elms_obj->IsFixedArray()) {
+ FixedArray* elms = FixedArray::cast(elms_obj);
+ AssertNoAllocation no_gc;
+ MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
+ elms->set(len - 1, heap->the_hole_value());
+ } else {
+ FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
+ MoveDoubleElements(elms, 0, elms, 1, len - 1);
+ elms->set_the_hole(len - 1);
+ }
}
// Set the length.
@@ -642,19 +744,21 @@
BUILTIN(ArrayUnshift) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
- if (maybe_elms_obj == NULL)
- return CallJsBuiltin(isolate, "ArrayUnshift", args);
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
- }
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms_obj =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
+ if (maybe_elms_obj == NULL)
+ return CallJsBuiltin(isolate, "ArrayUnshift", args);
+ if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
+
if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
return CallJsBuiltin(isolate, "ArrayUnshift", args);
}
+ JSArray* array = JSArray::cast(receiver);
+ if (!array->HasFastSmiOrObjectElements()) {
+ return CallJsBuiltin(isolate, "ArrayUnshift", args);
+ }
FixedArray* elms = FixedArray::cast(elms_obj);
- JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastSmiOrObjectElements());
if (FLAG_harmony_observation && array->map()->is_observed()) {
return CallJsBuiltin(isolate, "ArrayUnshift", args);
@@ -675,13 +779,17 @@
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
- Object* obj;
- { MaybeObject* maybe_obj =
heap->AllocateUninitializedFixedArray(capacity);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- FixedArray* new_elms = FixedArray::cast(obj);
+ FixedArray* new_elms;
+ MaybeObject* maybe_elms =
heap->AllocateUninitializedFixedArray(capacity);
+ if (!maybe_elms->To(&new_elms)) return maybe_elms;
+
ElementsKind kind = array->GetElementsKind();
- CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, to_add, len);
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, 0, new_elms, kind, to_add, len,
elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
+
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
@@ -706,16 +814,20 @@
BUILTIN(ArraySlice) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- FixedArray* elms;
+ FixedArrayBase* elms;
int len = -1;
if (receiver->IsJSArray()) {
JSArray* array = JSArray::cast(receiver);
- if (!array->HasFastSmiOrObjectElements() ||
- !IsJSArrayFastElementMovingAllowed(heap, array)) {
+ if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
- elms = FixedArray::cast(array->elements());
+ if (array->HasFastElements()) {
+ elms = array->elements();
+ } else {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
+
len = Smi::cast(array->length())->value();
} else {
// Array.slice(arguments, ...) is quite a common idiom (notably more
@@ -724,15 +836,19 @@
isolate->context()->native_context()->arguments_boilerplate()->map();
bool is_arguments_object_with_fast_elements =
- receiver->IsJSObject()
- && JSObject::cast(receiver)->map() == arguments_map
- && JSObject::cast(receiver)->HasFastSmiOrObjectElements();
+ receiver->IsJSObject() &&
+ JSObject::cast(receiver)->map() == arguments_map;
if (!is_arguments_object_with_fast_elements) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
- elms = FixedArray::cast(JSObject::cast(receiver)->elements());
- Object* len_obj = JSObject::cast(receiver)
- ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
+ JSObject* object = JSObject::cast(receiver);
+
+ if (object->HasFastElements()) {
+ elms = object->elements();
+ } else {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
+ Object* len_obj =
object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
if (!len_obj->IsSmi()) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@@ -740,12 +856,27 @@
if (len > elms->length()) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
+ }
+
+ JSObject* object = JSObject::cast(receiver);
+ ElementsKind kind = object->GetElementsKind();
+
+ if (IsHoleyElementsKind(kind)) {
+ bool packed = true;
+ ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
for (int i = 0; i < len; i++) {
- if (elms->get(i) == heap->the_hole_value()) {
- return CallJsBuiltin(isolate, "ArraySlice", args);
+ if (!accessor->HasElement(object, object, i, elms)) {
+ packed = false;
+ break;
}
}
+ if (packed) {
+ kind = GetPackedElementsKind(kind);
+ } else if (!receiver->IsJSArray()) {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
}
+
ASSERT(len >= 0);
int n_arguments = args.length() - 1;
@@ -758,6 +889,12 @@
Object* arg1 = args[1];
if (arg1->IsSmi()) {
relative_start = Smi::cast(arg1)->value();
+ } else if (arg1->IsHeapNumber()) {
+ double start = HeapNumber::cast(arg1)->value();
+ if (start < kMinInt || start > kMaxInt) {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
+ relative_start = static_cast<int>(start);
} else if (!arg1->IsUndefined()) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@@ -765,6 +902,12 @@
Object* arg2 = args[2];
if (arg2->IsSmi()) {
relative_end = Smi::cast(arg2)->value();
+ } else if (arg2->IsHeapNumber()) {
+ double end = HeapNumber::cast(arg2)->value();
+ if (end < kMinInt || end > kMaxInt) {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
+ relative_end = static_cast<int>(end);
} else if (!arg2->IsUndefined()) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@@ -779,21 +922,21 @@
int final = (relative_end < 0) ? Max(len + relative_end, 0)
: Min(relative_end, len);
- ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
-
// Calculate the length of result array.
int result_len = Max(final - k, 0);
- MaybeObject* maybe_array =
- heap->AllocateJSArrayAndStorage(elements_kind,
- result_len,
- result_len);
JSArray* result_array;
+ MaybeObject* maybe_array = heap->AllocateJSArrayAndStorage(kind,
+ result_len,
+ result_len);
if (!maybe_array->To(&result_array)) return maybe_array;
- CopyObjectToObjectElements(elms, elements_kind, k,
- FixedArray::cast(result_array->elements()),
- elements_kind, 0, result_len);
+ ElementsAccessor* accessor = object->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(object, k, result_array->elements(),
+ kind, 0, result_len, elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
return result_array;
}
@@ -802,19 +945,18 @@
BUILTIN(ArraySplice) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
- if (maybe_elms_obj == NULL)
- return CallJsBuiltin(isolate, "ArraySplice", args);
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
+ if (maybe_elms == NULL) {
+ return CallJsBuiltin(isolate, "ArraySplice", args);
}
+ if (!maybe_elms->To(&elms_obj)) return maybe_elms;
+
if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
return CallJsBuiltin(isolate, "ArraySplice", args);
}
- FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastSmiOrObjectElements());
if (FLAG_harmony_observation && array->map()->is_observed()) {
return CallJsBuiltin(isolate, "ArraySplice", args);
@@ -829,6 +971,12 @@
Object* arg1 = args[1];
if (arg1->IsSmi()) {
relative_start = Smi::cast(arg1)->value();
+ } else if (arg1->IsHeapNumber()) {
+ double start = HeapNumber::cast(arg1)->value();
+ if (start < kMinInt || start > kMaxInt) {
+ return CallJsBuiltin(isolate, "ArraySplice", args);
+ }
+ relative_start = static_cast<int>(start);
} else if (!arg1->IsUndefined()) {
return CallJsBuiltin(isolate, "ArraySplice", args);
}
@@ -857,52 +1005,84 @@
}
actual_delete_count = Min(Max(value, 0), len - actual_start);
}
+
+ ElementsKind elements_kind = array->GetElementsKind();
+
+ int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
+ int new_length = len - actual_delete_count + item_count;
+
+ // For double mode we do not support changing the length.
+ if (new_length > len && IsFastDoubleElementsKind(elements_kind)) {
+ return CallJsBuiltin(isolate, "ArraySplice", args);
+ }
+
+ if (new_length == 0) {
+ MaybeObject* maybe_array = heap->AllocateJSArrayWithElements(
+ elms_obj, elements_kind, actual_delete_count);
+ if (maybe_array->IsFailure()) return maybe_array;
+ array->set_elements(heap->empty_fixed_array());
+ array->set_length(Smi::FromInt(0));
+ return maybe_array;
+ }
JSArray* result_array = NULL;
- ElementsKind elements_kind =
- JSObject::cast(receiver)->GetElementsKind();
MaybeObject* maybe_array =
heap->AllocateJSArrayAndStorage(elements_kind,
actual_delete_count,
actual_delete_count);
if (!maybe_array->To(&result_array)) return maybe_array;
- {
- // Fill newly created array.
- CopyObjectToObjectElements(elms, elements_kind, actual_start,
- FixedArray::cast(result_array->elements()),
- elements_kind, 0, actual_delete_count);
+ if (actual_delete_count > 0) {
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, actual_start,
result_array->elements(),
+ elements_kind, 0, actual_delete_count,
elms_obj);
+ // Cannot fail since the origin and target array are of the same
elements
+ // kind.
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
}
-
- int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
- int new_length = len - actual_delete_count + item_count;
bool elms_changed = false;
if (item_count < actual_delete_count) {
// Shrink the array.
- const bool trim_array = !heap->lo_space()->Contains(elms) &&
+ const bool trim_array = !heap->lo_space()->Contains(elms_obj) &&
((actual_start + item_count) <
(len - actual_delete_count - actual_start));
if (trim_array) {
const int delta = actual_delete_count - item_count;
- {
+ if (elms_obj->IsFixedDoubleArray()) {
+ FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
+ MoveDoubleElements(elms, delta, elms, 0, actual_start);
+ } else {
+ FixedArray* elms = FixedArray::cast(elms_obj);
AssertNoAllocation no_gc;
MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
}
- elms = LeftTrimFixedArray(heap, elms, delta);
+ elms_obj = LeftTrimFixedArray(heap, elms_obj, delta);
elms_changed = true;
} else {
- AssertNoAllocation no_gc;
- MoveElements(heap, &no_gc,
- elms, actual_start + item_count,
- elms, actual_start + actual_delete_count,
- (len - actual_delete_count - actual_start));
- FillWithHoles(heap, elms, new_length, len);
+ if (elms_obj->IsFixedDoubleArray()) {
+ FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
+ MoveDoubleElements(elms, actual_start + item_count,
+ elms, actual_start + actual_delete_count,
+ (len - actual_delete_count - actual_start));
+ FillWithHoles(elms, new_length, len);
+ } else {
+ FixedArray* elms = FixedArray::cast(elms_obj);
+ AssertNoAllocation no_gc;
+ MoveElements(heap, &no_gc,
+ elms, actual_start + item_count,
+ elms, actual_start + actual_delete_count,
+ (len - actual_delete_count - actual_start));
+ FillWithHoles(heap, elms, new_length, len);
+ }
}
} else if (item_count > actual_delete_count) {
+ FixedArray* elms = FixedArray::cast(elms_obj);
// Currently fixed arrays cannot grow too big, so
// we should never hit this case.
ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
@@ -911,28 +1091,27 @@
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
- Object* obj;
- { MaybeObject* maybe_obj =
- heap->AllocateUninitializedFixedArray(capacity);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- FixedArray* new_elms = FixedArray::cast(obj);
+ FixedArray* new_elms;
+ MaybeObject* maybe_obj =
heap->AllocateUninitializedFixedArray(capacity);
+ if (!maybe_obj->To(&new_elms)) return maybe_obj;
- {
- // Copy the part before actual_start as is.
- ElementsKind kind = array->GetElementsKind();
- CopyObjectToObjectElements(elms, kind, 0,
- new_elms, kind, 0, actual_start);
- const int to_copy = len - actual_delete_count - actual_start;
- CopyObjectToObjectElements(elms, kind,
- actual_start + actual_delete_count,
- new_elms, kind,
- actual_start + item_count, to_copy);
- }
+ // Copy the part before actual_start as is.
+ ElementsKind kind = array->GetElementsKind();
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure = accessor->CopyElements(
+ array, 0, new_elms, kind, 0, actual_start, elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
+ const int to_copy = len - actual_delete_count - actual_start;
+ maybe_failure = accessor->CopyElements(
+ array, actual_start + actual_delete_count, new_elms, kind,
+ actual_start + item_count, to_copy, elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
FillWithHoles(heap, new_elms, new_length, capacity);
- elms = new_elms;
+ elms_obj = new_elms;
elms_changed = true;
} else {
AssertNoAllocation no_gc;
@@ -943,16 +1122,28 @@
}
}
- AssertNoAllocation no_gc;
- WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
- for (int k = actual_start; k < actual_start + item_count; k++) {
- elms->set(k, args[3 + k - actual_start], mode);
+ if (IsFastDoubleElementsKind(elements_kind)) {
+ FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
+ for (int k = actual_start; k < actual_start + item_count; k++) {
+ Object* arg = args[3 + k - actual_start];
+ if (arg->IsSmi()) {
+ elms->set(k, Smi::cast(arg)->value());
+ } else {
+ elms->set(k, HeapNumber::cast(arg)->value());
+ }
+ }
+ } else {
+ FixedArray* elms = FixedArray::cast(elms_obj);
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+ for (int k = actual_start; k < actual_start + item_count; k++) {
+ elms->set(k, args[3 + k - actual_start], mode);
+ }
}
if (elms_changed) {
- array->set_elements(elms);
+ array->set_elements(elms_obj);
}
-
// Set the length.
array->set_length(Smi::FromInt(new_length));
@@ -977,11 +1168,10 @@
for (int i = 0; i < n_arguments; i++) {
Object* arg = args[i];
if (!arg->IsJSArray() ||
- !JSArray::cast(arg)->HasFastSmiOrObjectElements() ||
+ !JSArray::cast(arg)->HasFastElements() ||
JSArray::cast(arg)->GetPrototype() != array_proto) {
return CallJsBuiltin(isolate, "ArrayConcat", args);
}
-
int len = Smi::cast(JSArray::cast(arg)->length())->value();
// We shouldn't overflow when adding another len.
@@ -991,27 +1181,24 @@
result_len += len;
ASSERT(result_len >= 0);
- if (result_len > FixedArray::kMaxLength) {
+ if (result_len > FixedDoubleArray::kMaxLength) {
return CallJsBuiltin(isolate, "ArrayConcat", args);
}
- if (!JSArray::cast(arg)->HasFastSmiElements()) {
- if (IsFastSmiElementsKind(elements_kind)) {
- if (IsFastHoleyElementsKind(elements_kind)) {
- elements_kind = FAST_HOLEY_ELEMENTS;
- } else {
- elements_kind = FAST_ELEMENTS;
- }
+ ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
+ ElementsKind packed_kind = GetPackedElementsKind(arg_kind);
+ if (IsMoreGeneralElementsKindTransition(
+ GetPackedElementsKind(elements_kind), packed_kind)) {
+ if (IsFastHoleyElementsKind(elements_kind)) {
+ elements_kind = GetHoleyElementsKind(arg_kind);
+ } else {
+ elements_kind = arg_kind;
}
}
-
- if (JSArray::cast(arg)->HasFastHoleyElements()) {
- elements_kind = GetHoleyElementsKind(elements_kind);
- }
}
+ JSArray* result_array;
// Allocate result.
- JSArray* result_array;
MaybeObject* maybe_array =
heap->AllocateJSArrayAndStorage(elements_kind,
result_len,
@@ -1019,19 +1206,19 @@
if (!maybe_array->To(&result_array)) return maybe_array;
if (result_len == 0) return result_array;
- // Copy data.
- int start_pos = 0;
- FixedArray* result_elms(FixedArray::cast(result_array->elements()));
+ int j = 0;
+ FixedArrayBase* storage = result_array->elements();
for (int i = 0; i < n_arguments; i++) {
JSArray* array = JSArray::cast(args[i]);
+ ElementsAccessor* accessor = array->GetElementsAccessor();
int len = Smi::cast(array->length())->value();
- FixedArray* elms = FixedArray::cast(array->elements());
- CopyObjectToObjectElements(elms, elements_kind, 0,
- result_elms, elements_kind,
- start_pos, len);
- start_pos += len;
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, 0, storage, elements_kind, j, len);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ j += len;
}
- ASSERT(start_pos == result_len);
+
+ ASSERT(j == result_len);
return result_array;
}
=======================================
--- /trunk/src/code-stubs.cc Thu Sep 20 05:51:09 2012
+++ /trunk/src/code-stubs.cc Fri Nov 16 06:43:43 2012
@@ -167,6 +167,122 @@
void CodeStub::PrintName(StringStream* stream) {
stream->Add("%s", MajorName(MajorKey(), false));
}
+
+
+void BinaryOpStub::Generate(MacroAssembler* masm) {
+ // Explicitly allow generation of nested stubs. It is safe here because
+ // generation code does not use any raw pointers.
+ AllowStubCallsScope allow_stub_calls(masm, true);
+
+ BinaryOpIC::TypeInfo operands_type = Max(left_type_, right_type_);
+ if (left_type_ == BinaryOpIC::ODDBALL && right_type_ ==
BinaryOpIC::ODDBALL) {
+ // The OddballStub handles a number and an oddball, not two oddballs.
+ operands_type = BinaryOpIC::GENERIC;
+ }
+ switch (operands_type) {
+ case BinaryOpIC::UNINITIALIZED:
+ GenerateTypeTransition(masm);
+ break;
+ case BinaryOpIC::SMI:
+ GenerateSmiStub(masm);
+ break;
+ case BinaryOpIC::INT32:
+ GenerateInt32Stub(masm);
+ break;
+ case BinaryOpIC::HEAP_NUMBER:
+ GenerateHeapNumberStub(masm);
+ break;
+ case BinaryOpIC::ODDBALL:
+ GenerateOddballStub(masm);
+ break;
+ case BinaryOpIC::STRING:
+ GenerateStringStub(masm);
+ break;
+ case BinaryOpIC::GENERIC:
+ GenerateGeneric(masm);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+
+#define __ ACCESS_MASM(masm)
+
+
+void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
+ switch (op_) {
+ case Token::ADD:
+ __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
+ break;
+ case Token::SUB:
+ __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
+ break;
+ case Token::MUL:
+ __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
+ break;
+ case Token::DIV:
+ __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
+ break;
+ case Token::MOD:
+ __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
+ break;
+ case Token::BIT_OR:
+ __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
+ break;
+ case Token::BIT_AND:
+ __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
+ break;
+ case Token::BIT_XOR:
+ __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
+ break;
+ case Token::SAR:
+ __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
+ break;
+ case Token::SHR:
+ __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
+ break;
+ case Token::SHL:
+ __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+
+#undef __
+
+
+void BinaryOpStub::PrintName(StringStream* stream) {
+ const char* op_name = Token::Name(op_);
+ const char* overwrite_name;
+ switch (mode_) {
+ case NO_OVERWRITE: overwrite_name = "Alloc"; break;
+ case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
+ case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
+ default: overwrite_name = "UnknownOverwrite"; break;
+ }
+ stream->Add("BinaryOpStub_%s_%s_%s+%s",
+ op_name,
+ overwrite_name,
+ BinaryOpIC::GetName(left_type_),
+ BinaryOpIC::GetName(right_type_));
+}
+
+
+void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
+ ASSERT(left_type_ == BinaryOpIC::STRING || right_type_ ==
BinaryOpIC::STRING);
+ ASSERT(op_ == Token::ADD);
+ if (left_type_ == BinaryOpIC::STRING && right_type_ ==
BinaryOpIC::STRING) {
+ GenerateBothStringStub(masm);
+ return;
+ }
+ // Try to add arguments as strings, otherwise, transition to the generic
+ // BinaryOpIC type.
+ GenerateAddStrings(masm);
+ GenerateTypeTransition(masm);
+}
void ICCompareStub::AddToSpecialCache(Handle<Code> new_object) {
@@ -196,7 +312,12 @@
flags));
if (probe->IsCode()) {
*code_out = Code::cast(*probe);
- ASSERT(op_ == (*code_out)->compare_operation() + Token::EQ);
+#ifdef DEBUG
+ Token::Value cached_op;
+ ICCompareStub::DecodeMinorKey((*code_out)->stub_info(), NULL, NULL,
NULL,
+ &cached_op);
+ ASSERT(op_ == cached_op);
+#endif
return true;
}
return false;
@@ -204,7 +325,33 @@
int ICCompareStub::MinorKey() {
- return OpField::encode(op_ - Token::EQ) | StateField::encode(state_);
+ return OpField::encode(op_ - Token::EQ) |
+ LeftStateField::encode(left_) |
+ RightStateField::encode(right_) |
+ HandlerStateField::encode(state_);
+}
+
+
+void ICCompareStub::DecodeMinorKey(int minor_key,
+ CompareIC::State* left_state,
+ CompareIC::State* right_state,
+ CompareIC::State* handler_state,
+ Token::Value* op) {
+ if (left_state) {
+ *left_state =
+ static_cast<CompareIC::State>(LeftStateField::decode(minor_key));
+ }
+ if (right_state) {
+ *right_state =
+ static_cast<CompareIC::State>(RightStateField::decode(minor_key));
+ }
+ if (handler_state) {
+ *handler_state =
+
static_cast<CompareIC::State>(HandlerStateField::decode(minor_key));
+ }
+ if (op) {
+ *op = static_cast<Token::Value>(OpField::decode(minor_key) +
Token::EQ);
+ }
}
@@ -213,27 +360,28 @@
case CompareIC::UNINITIALIZED:
GenerateMiss(masm);
break;
- case CompareIC::SMIS:
+ case CompareIC::SMI:
GenerateSmis(masm);
break;
- case CompareIC::HEAP_NUMBERS:
+ case CompareIC::HEAP_NUMBER:
GenerateHeapNumbers(masm);
break;
- case CompareIC::STRINGS:
+ case CompareIC::STRING:
GenerateStrings(masm);
break;
- case CompareIC::SYMBOLS:
+ case CompareIC::SYMBOL:
GenerateSymbols(masm);
break;
- case CompareIC::OBJECTS:
+ case CompareIC::OBJECT:
GenerateObjects(masm);
break;
case CompareIC::KNOWN_OBJECTS:
ASSERT(*known_map_ != NULL);
GenerateKnownObjects(masm);
break;
- default:
- UNREACHABLE();
+ case CompareIC::GENERIC:
+ GenerateGeneric(masm);
+ break;
}
}
=======================================
--- /trunk/src/code-stubs.h Mon Nov 12 06:53:34 2012
+++ /trunk/src/code-stubs.h Fri Nov 16 06:43:43 2012
@@ -482,24 +482,157 @@
};
+class BinaryOpStub: public CodeStub {
+ public:
+ BinaryOpStub(Token::Value op, OverwriteMode mode)
+ : op_(op),
+ mode_(mode),
+ platform_specific_bit_(false),
+ left_type_(BinaryOpIC::UNINITIALIZED),
+ right_type_(BinaryOpIC::UNINITIALIZED),
+ result_type_(BinaryOpIC::UNINITIALIZED) {
+ Initialize();
+ ASSERT(OpBits::is_valid(Token::NUM_TOKENS));
+ }
+
+ BinaryOpStub(
+ int key,
+ BinaryOpIC::TypeInfo left_type,
+ BinaryOpIC::TypeInfo right_type,
+ BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED)
+ : op_(OpBits::decode(key)),
+ mode_(ModeBits::decode(key)),
+ platform_specific_bit_(PlatformSpecificBits::decode(key)),
+ left_type_(left_type),
+ right_type_(right_type),
+ result_type_(result_type) { }
+
+ static void decode_types_from_minor_key(int minor_key,
+ BinaryOpIC::TypeInfo* left_type,
+ BinaryOpIC::TypeInfo* right_type,
+ BinaryOpIC::TypeInfo*
result_type) {
+ *left_type =
+ static_cast<BinaryOpIC::TypeInfo>(LeftTypeBits::decode(minor_key));
+ *right_type =
+
static_cast<BinaryOpIC::TypeInfo>(RightTypeBits::decode(minor_key));
+ *result_type =
+
static_cast<BinaryOpIC::TypeInfo>(ResultTypeBits::decode(minor_key));
+ }
+
+ static Token::Value decode_op_from_minor_key(int minor_key) {
+ return static_cast<Token::Value>(OpBits::decode(minor_key));
+ }
+
+ enum SmiCodeGenerateHeapNumberResults {
+ ALLOW_HEAPNUMBER_RESULTS,
+ NO_HEAPNUMBER_RESULTS
+ };
+
+ private:
+ Token::Value op_;
+ OverwriteMode mode_;
+ bool platform_specific_bit_; // Indicates SSE3 on IA32, VFP2 on ARM.
+
+ // Operand type information determined at runtime.
+ BinaryOpIC::TypeInfo left_type_;
+ BinaryOpIC::TypeInfo right_type_;
+ BinaryOpIC::TypeInfo result_type_;
+
+ virtual void PrintName(StringStream* stream);
+
+ // Minor key encoding in 19 bits TTTRRRLLLSOOOOOOOMM.
+ class ModeBits: public BitField<OverwriteMode, 0, 2> {};
+ class OpBits: public BitField<Token::Value, 2, 7> {};
+ class PlatformSpecificBits: public BitField<bool, 9, 1> {};
+ class LeftTypeBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {};
+ class RightTypeBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {};
+ class ResultTypeBits: public BitField<BinaryOpIC::TypeInfo, 16, 3> {};
+
+ Major MajorKey() { return BinaryOp; }
+ int MinorKey() {
+ return OpBits::encode(op_)
+ | ModeBits::encode(mode_)
+ | PlatformSpecificBits::encode(platform_specific_bit_)
+ | LeftTypeBits::encode(left_type_)
+ | RightTypeBits::encode(right_type_)
+ | ResultTypeBits::encode(result_type_);
+ }
+
+
+ // Platform-independent implementation.
+ void Generate(MacroAssembler* masm);
+ void GenerateCallRuntime(MacroAssembler* masm);
+
+ // Platform-independent signature, platform-specific implementation.
+ void Initialize();
+ void GenerateAddStrings(MacroAssembler* masm);
+ void GenerateBothStringStub(MacroAssembler* masm);
+ void GenerateGeneric(MacroAssembler* masm);
+ void GenerateGenericStub(MacroAssembler* masm);
+ void GenerateHeapNumberStub(MacroAssembler* masm);
+ void GenerateInt32Stub(MacroAssembler* masm);
+ void GenerateLoadArguments(MacroAssembler* masm);
+ void GenerateOddballStub(MacroAssembler* masm);
+ void GenerateRegisterArgsPush(MacroAssembler* masm);
+ void GenerateReturn(MacroAssembler* masm);
+ void GenerateSmiStub(MacroAssembler* masm);
+ void GenerateStringStub(MacroAssembler* masm);
+ void GenerateTypeTransition(MacroAssembler* masm);
+ void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm);
+ void GenerateUninitializedStub(MacroAssembler* masm);
+
+ // Entirely platform-specific methods are defined as static helper
+ // functions in the <arch>/code-stubs-<arch>.cc files.
+
+ virtual int GetCodeKind() { return Code::BINARY_OP_IC; }
+
+ virtual InlineCacheState GetICState() {
+ return BinaryOpIC::ToState(Max(left_type_, right_type_));
+ }
+
+ virtual void FinishCode(Handle<Code> code) {
+ code->set_stub_info(MinorKey());
+ }
+
+ friend class CodeGenerator;
+};
+
+
class ICCompareStub: public CodeStub {
public:
- ICCompareStub(Token::Value op, CompareIC::State state)
- : op_(op), state_(state) {
+ ICCompareStub(Token::Value op,
+ CompareIC::State left,
+ CompareIC::State right,
+ CompareIC::State handler)
+ : op_(op),
+ left_(left),
+ right_(right),
+ state_(handler) {
ASSERT(Token::IsCompareOp(op));
}
virtual void Generate(MacroAssembler* masm);
void set_known_map(Handle<Map> map) { known_map_ = map; }
+
+ static void DecodeMinorKey(int minor_key,
+ CompareIC::State* left_state,
+ CompareIC::State* right_state,
+ CompareIC::State* handler_state,
+ Token::Value* op);
+
+ static CompareIC::State CompareState(int minor_key) {
+ return
static_cast<CompareIC::State>(HandlerStateField::decode(minor_key));
+ }
private:
class OpField: public BitField<int, 0, 3> { };
- class StateField: public BitField<int, 3, 5> { };
+ class LeftStateField: public BitField<int, 3, 3> { };
+ class RightStateField: public BitField<int, 6, 3> { };
+ class HandlerStateField: public BitField<int, 9, 3> { };
virtual void FinishCode(Handle<Code> code) {
- code->set_compare_state(state_);
- code->set_compare_operation(op_ - Token::EQ);
+ code->set_stub_info(MinorKey());
}
virtual CodeStub::Major MajorKey() { return CompareIC; }
@@ -514,6 +647,7 @@
void GenerateObjects(MacroAssembler* masm);
void GenerateMiss(MacroAssembler* masm);
void GenerateKnownObjects(MacroAssembler* masm);
+ void GenerateGeneric(MacroAssembler* masm);
bool strict() const { return op_ == Token::EQ_STRICT; }
Condition GetCondition() const { return
CompareIC::ComputeCondition(op_); }
@@ -523,108 +657,13 @@
virtual bool UseSpecialCache() { return state_ ==
CompareIC::KNOWN_OBJECTS; }
Token::Value op_;
+ CompareIC::State left_;
+ CompareIC::State right_;
CompareIC::State state_;
Handle<Map> known_map_;
};
-// Flags that control the compare stub code generation.
-enum CompareFlags {
- NO_COMPARE_FLAGS = 0,
- NO_SMI_COMPARE_IN_STUB = 1 << 0,
- NO_NUMBER_COMPARE_IN_STUB = 1 << 1,
- CANT_BOTH_BE_NAN = 1 << 2
-};
-
-
-enum NaNInformation {
- kBothCouldBeNaN,
- kCantBothBeNaN
-};
-
-
-class CompareStub: public CodeStub {
- public:
- CompareStub(Condition cc,
- bool strict,
- CompareFlags flags,
- Register lhs,
- Register rhs) :
- cc_(cc),
- strict_(strict),
- never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
- include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
- include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
- lhs_(lhs),
- rhs_(rhs) { }
-
- CompareStub(Condition cc,
- bool strict,
- CompareFlags flags) :
- cc_(cc),
- strict_(strict),
- never_nan_nan_((flags & CANT_BOTH_BE_NAN) != 0),
- include_number_compare_((flags & NO_NUMBER_COMPARE_IN_STUB) == 0),
- include_smi_compare_((flags & NO_SMI_COMPARE_IN_STUB) == 0),
- lhs_(no_reg),
- rhs_(no_reg) { }
-
- void Generate(MacroAssembler* masm);
-
- private:
- Condition cc_;
- bool strict_;
- // Only used for 'equal' comparisons. Tells the stub that we already
know
- // that at least one side of the comparison is not NaN. This allows the
- // stub to use object identity in the positive case. We ignore it when
- // generating the minor key for other comparisons to avoid creating more
- // stubs.
- bool never_nan_nan_;
- // Do generate the number comparison code in the stub. Stubs without
number
- // comparison code is used when the number comparison has been inlined,
and
- // the stub will be called if one of the operands is not a number.
- bool include_number_compare_;
-
- // Generate the comparison code for two smi operands in the stub.
- bool include_smi_compare_;
-
- // Register holding the left hand side of the comparison if the stub
gives
- // a choice, no_reg otherwise.
-
- Register lhs_;
- // Register holding the right hand side of the comparison if the stub
gives
- // a choice, no_reg otherwise.
- Register rhs_;
-
- // Encoding of the minor key in 16 bits.
- class StrictField: public BitField<bool, 0, 1> {};
- class NeverNanNanField: public BitField<bool, 1, 1> {};
- class IncludeNumberCompareField: public BitField<bool, 2, 1> {};
- class IncludeSmiCompareField: public BitField<bool, 3, 1> {};
- class RegisterField: public BitField<bool, 4, 1> {};
- class ConditionField: public BitField<int, 5, 11> {};
-
- Major MajorKey() { return Compare; }
-
- int MinorKey();
-
- virtual int GetCodeKind() { return Code::COMPARE_IC; }
- virtual void FinishCode(Handle<Code> code) {
- code->set_compare_state(CompareIC::GENERIC);
- }
-
- // Branch to the label if the given object isn't a symbol.
- void BranchIfNonSymbol(MacroAssembler* masm,
- Label* label,
- Register object,
- Register scratch);
-
- // Unfortunately you have to run without snapshots to see most of these
- // names in the profile since most compare stubs end up in the snapshot.
- virtual void PrintName(StringStream* stream);
-};
-
-
class CEntryStub : public CodeStub {
public:
explicit CEntryStub(int result_size,
@@ -1053,6 +1092,9 @@
bool IsEmpty() const { return set_.IsEmpty(); }
bool Contains(Type type) const { return set_.Contains(type); }
+ bool ContainsAnyOf(Types types) const {
+ return set_.ContainsAnyOf(types.set_);
+ }
void Add(Type type) { set_.Add(type); }
byte ToByte() const { return set_.ToIntegral(); }
void Print(StringStream* stream) const;
=======================================
--- /trunk/src/compiler.cc Tue Nov 13 05:56:09 2012
+++ /trunk/src/compiler.cc Fri Nov 16 06:43:43 2012
@@ -864,7 +864,10 @@
{
CompilationHandleScope handle_scope(*info);
- if (InstallCodeFromOptimizedCodeMap(*info)) return;
+ if (!FLAG_manual_parallel_recompilation &&
+ InstallCodeFromOptimizedCodeMap(*info)) {
+ return;
+ }
if (ParserApi::Parse(*info, kNoParsingFlags)) {
LanguageMode language_mode = info->function()->language_mode();
=======================================
--- /trunk/src/cpu-profiler-inl.h Mon Oct 22 06:09:53 2012
+++ /trunk/src/cpu-profiler-inl.h Fri Nov 16 06:43:43 2012
@@ -31,7 +31,6 @@
#include "cpu-profiler.h"
#include <new>
-#include "circular-queue-inl.h"
#include "profile-generator-inl.h"
#include "unbound-queue-inl.h"
@@ -56,11 +55,18 @@
}
-TickSample* ProfilerEventsProcessor::TickSampleEvent() {
+TickSample* ProfilerEventsProcessor::StartTickSampleEvent() {
+ if (!ticks_buffer_is_empty_ || ticks_buffer_is_initialized_) return NULL;
+ ticks_buffer_is_initialized_ = true;
generator_->Tick();
- TickSampleEventRecord* evt =
- new(ticks_buffer_.Enqueue()) TickSampleEventRecord(enqueue_order_);
- return &evt->sample;
+ ticks_buffer_ = TickSampleEventRecord(enqueue_order_);
+ return &ticks_buffer_.sample;
+}
+
+
+void ProfilerEventsProcessor::FinishTickSampleEvent() {
+ ASSERT(ticks_buffer_is_initialized_ && ticks_buffer_is_empty_);
+ ticks_buffer_is_empty_ = false;
}
=======================================
--- /trunk/src/cpu-profiler.cc Mon Oct 22 06:09:53 2012
+++ /trunk/src/cpu-profiler.cc Fri Nov 16 06:43:43 2012
@@ -39,19 +39,19 @@
namespace v8 {
namespace internal {
-static const int kEventsBufferSize = 256 * KB;
-static const int kTickSamplesBufferChunkSize = 64 * KB;
-static const int kTickSamplesBufferChunksCount = 16;
static const int kProfilerStackSize = 64 * KB;
-ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator*
generator)
+ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator*
generator,
+ Sampler* sampler,
+ int period_in_useconds)
: Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
generator_(generator),
+ sampler_(sampler),
running_(true),
- ticks_buffer_(sizeof(TickSampleEventRecord),
- kTickSamplesBufferChunkSize,
- kTickSamplesBufferChunksCount),
+ period_in_useconds_(period_in_useconds),
+ ticks_buffer_is_empty_(true),
+ ticks_buffer_is_initialized_(false),
enqueue_order_(0) {
}
@@ -215,46 +215,47 @@
generator_->RecordTickSample(record.sample);
}
- const TickSampleEventRecord* rec =
- TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
- if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty();
- // Make a local copy of tick sample record to ensure that it won't
- // be modified as we are processing it. This is possible as the
- // sampler writes w/o any sync to the queue, so if the processor
- // will get far behind, a record may be modified right under its
- // feet.
- TickSampleEventRecord record = *rec;
- if (record.order == dequeue_order) {
+ if (ticks_buffer_is_empty_) return !ticks_from_vm_buffer_.IsEmpty();
+ if (ticks_buffer_.order == dequeue_order) {
// A paranoid check to make sure that we don't get a memory overrun
// in case of frames_count having a wild value.
- if (record.sample.frames_count < 0
- || record.sample.frames_count > TickSample::kMaxFramesCount)
- record.sample.frames_count = 0;
- generator_->RecordTickSample(record.sample);
- ticks_buffer_.FinishDequeue();
+ if (ticks_buffer_.sample.frames_count < 0
+ || ticks_buffer_.sample.frames_count >
TickSample::kMaxFramesCount) {
+ ticks_buffer_.sample.frames_count = 0;
+ }
+ generator_->RecordTickSample(ticks_buffer_.sample);
+ ticks_buffer_is_empty_ = true;
+ ticks_buffer_is_initialized_ = false;
} else {
return true;
}
}
}
+
+
+void ProfilerEventsProcessor::ProcessEventsQueue(int64_t stop_time,
+ unsigned* dequeue_order) {
+ while (OS::Ticks() < stop_time) {
+ if (ProcessTicks(*dequeue_order)) {
+ // All ticks of the current dequeue_order are processed,
+ // proceed to the next code event.
+ ProcessCodeEvent(dequeue_order);
+ }
+ }
+}
void ProfilerEventsProcessor::Run() {
unsigned dequeue_order = 0;
while (running_) {
- // Process ticks until we have any.
- if (ProcessTicks(dequeue_order)) {
- // All ticks of the current dequeue_order are processed,
- // proceed to the next code event.
- ProcessCodeEvent(&dequeue_order);
+ int64_t stop_time = OS::Ticks() + period_in_useconds_;
+ if (sampler_ != NULL) {
+ sampler_->DoSample();
}
- YieldCPU();
+ ProcessEventsQueue(stop_time, &dequeue_order);
}
- // Process remaining tick events.
- ticks_buffer_.FlushResidualRecords();
- // Perform processing until we have tick events, skip remaining code
events.
while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order))
{ }
}
@@ -310,13 +311,20 @@
}
-TickSample* CpuProfiler::TickSampleEvent(Isolate* isolate) {
+TickSample* CpuProfiler::StartTickSampleEvent(Isolate* isolate) {
if (CpuProfiler::is_profiling(isolate)) {
- return isolate->cpu_profiler()->processor_->TickSampleEvent();
+ return isolate->cpu_profiler()->processor_->StartTickSampleEvent();
} else {
return NULL;
}
}
+
+
+void CpuProfiler::FinishTickSampleEvent(Isolate* isolate) {
+ if (CpuProfiler::is_profiling(isolate)) {
+ isolate->cpu_profiler()->processor_->FinishTickSampleEvent();
+ }
+}
void CpuProfiler::DeleteAllProfiles() {
@@ -486,13 +494,15 @@
if (processor_ == NULL) {
Isolate* isolate = Isolate::Current();
+ Sampler* sampler = isolate->logger()->sampler();
// Disable logging when using the new implementation.
saved_logging_nesting_ = isolate->logger()->logging_nesting_;
isolate->logger()->logging_nesting_ = 0;
generator_ = new ProfileGenerator(profiles_);
- processor_ = new ProfilerEventsProcessor(generator_);
+ processor_ = new ProfilerEventsProcessor(generator_,
+ sampler,
+
FLAG_cpu_profiler_sampling_period);
NoBarrier_Store(&is_profiling_, true);
- processor_->Start();
// Enumerate stuff we already have in the heap.
if (isolate->heap()->HasBeenSetUp()) {
if (!FLAG_prof_browser_mode) {
@@ -505,12 +515,13 @@
isolate->logger()->LogAccessorCallbacks();
}
// Enable stack sampling.
- Sampler* sampler =
reinterpret_cast<Sampler*>(isolate->logger()->ticker_);
if (!sampler->IsActive()) {
sampler->Start();
need_to_stop_sampler_ = true;
}
+ sampler->SetHasProcessingThread(true);
sampler->IncreaseProfilingDepth();
+ processor_->Start();
}
}
@@ -545,16 +556,17 @@
void CpuProfiler::StopProcessor() {
+ NoBarrier_Store(&is_profiling_, false);
+ processor_->Stop();
+ processor_->Join();
Logger* logger = Isolate::Current()->logger();
- Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
+ Sampler* sampler = logger->sampler();
sampler->DecreaseProfilingDepth();
+ sampler->SetHasProcessingThread(false);
if (need_to_stop_sampler_) {
sampler->Stop();
need_to_stop_sampler_ = false;
}
- NoBarrier_Store(&is_profiling_, false);
- processor_->Stop();
- processor_->Join();
delete processor_;
delete generator_;
processor_ = NULL;
=======================================
--- /trunk/src/cpu-profiler.h Mon Oct 22 06:09:53 2012
+++ /trunk/src/cpu-profiler.h Fri Nov 16 06:43:43 2012
@@ -124,7 +124,9 @@
// methods called by event producers: VM and stack sampler threads.
class ProfilerEventsProcessor : public Thread {
public:
- explicit ProfilerEventsProcessor(ProfileGenerator* generator);
+ explicit ProfilerEventsProcessor(ProfileGenerator* generator,
+ Sampler* sampler,
+ int period_in_useconds);
virtual ~ProfilerEventsProcessor() {}
// Thread control.
@@ -156,11 +158,12 @@
// Puts current stack into tick sample events buffer.
void AddCurrentStack();
- // Tick sample events are filled directly in the buffer of the circular
- // queue (because the structure is of fixed width, but usually not all
- // stack frame entries are filled.) This method returns a pointer to the
- // next record of the buffer.
- INLINE(TickSample* TickSampleEvent());
+ // StartTickSampleEvent returns a pointer only if the ticks_buffer_ is
empty,
+ // FinishTickSampleEvent marks the ticks_buffer_ as filled.
+ // Finish should be called only after successful Start (returning
non-NULL
+ // pointer).
+ INLINE(TickSample* StartTickSampleEvent());
+ INLINE(void FinishTickSampleEvent());
private:
union CodeEventsContainer {
@@ -173,13 +176,19 @@
// Called from events processing thread (Run() method.)
bool ProcessCodeEvent(unsigned* dequeue_order);
bool ProcessTicks(unsigned dequeue_order);
+ void ProcessEventsQueue(int64_t stop_time, unsigned* dequeue_order);
INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags
tag));
ProfileGenerator* generator_;
+ Sampler* sampler_;
bool running_;
+ // Sampling period in microseconds.
+ const int period_in_useconds_;
UnboundQueue<CodeEventsContainer> events_buffer_;
- SamplingCircularQueue ticks_buffer_;
+ TickSampleEventRecord ticks_buffer_;
+ bool ticks_buffer_is_empty_;
+ bool ticks_buffer_is_initialized_;
UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
unsigned enqueue_order_;
};
@@ -218,7 +227,10 @@
static bool HasDetachedProfiles();
// Invoked from stack sampler (thread or signal handler.)
- static TickSample* TickSampleEvent(Isolate* isolate);
+ // Finish should be called only after successful Start (returning
non-NULL
+ // pointer).
+ static TickSample* StartTickSampleEvent(Isolate* isolate);
+ static void FinishTickSampleEvent(Isolate* isolate);
// Must be called via PROFILE macro, otherwise will crash when
// profiling is not enabled.
=======================================
--- /trunk/src/d8.cc Thu Sep 20 05:51:09 2012
+++ /trunk/src/d8.cc Fri Nov 16 06:43:43 2012
@@ -67,6 +67,49 @@
namespace v8 {
+
+static Handle<Value> Throw(const char* message) {
+ return ThrowException(String::New(message));
+}
+
+
+// TODO(rossberg): should replace these by proper uses of HasInstance,
+// once we figure out a good way to make the templates global.
+const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_";
+const char kArrayMarkerPropName[] = "d8::_is_typed_array_";
+
+
+namespace Symbols {
+#define FOR_EACH_SYMBOL(V) \
+ V(ArrayBuffer, "ArrayBuffer") \
+ V(ArrayBufferMarkerPropName, kArrayBufferMarkerPropName) \
+ V(ArrayMarkerPropName, kArrayMarkerPropName) \
+ V(buffer, "buffer") \
+ V(byteLength, "byteLength") \
+ V(byteOffset, "byteOffset") \
+ V(BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \
+ V(length, "length")
+
+#define DEFINE_SYMBOL(name, value) Persistent<String> name;
+FOR_EACH_SYMBOL(DEFINE_SYMBOL)
+#undef DEFINE_SYMBOL
+
+void Initialize() {
+ HandleScope scope;
+#define INIT_SYMBOL(name, value) \
+ name = Persistent<String>::New(String::NewSymbol(value));
+FOR_EACH_SYMBOL(INIT_SYMBOL)
+#undef INIT_SYMBOL
+}
+
+void TearDown() {
+#define DISPOSE_SYMBOL(name, value) name.Dispose();
+ FOR_EACH_SYMBOL(DISPOSE_SYMBOL)
+#undef DISPOSE_SYMBOL
+}
+}
+
+
LineEditor *LineEditor::first_ = NULL;
@@ -232,11 +275,11 @@
Handle<Value> Shell::Read(const Arguments& args) {
String::Utf8Value file(args[0]);
if (*file == NULL) {
- return ThrowException(String::New("Error loading file"));
+ return Throw("Error loading file");
}
Handle<String> source = ReadFile(*file);
if (source.IsEmpty()) {
- return ThrowException(String::New("Error loading file"));
+ return Throw("Error loading file");
}
return source;
}
@@ -277,14 +320,14 @@
HandleScope handle_scope;
String::Utf8Value file(args[i]);
if (*file == NULL) {
- return ThrowException(String::New("Error loading file"));
+ return Throw("Error loading file");
}
Handle<String> source = ReadFile(*file);
if (source.IsEmpty()) {
- return ThrowException(String::New("Error loading file"));
+ return Throw("Error loading file");
}
if (!ExecuteString(source, String::New(*file), false, true)) {
- return ThrowException(String::New("Error executing file"));
+ return Throw("Error executing file");
}
}
return Undefined();
@@ -314,7 +357,7 @@
if (try_catch->HasCaught()) return 0;
if (raw_value < 0) {
- ThrowException(String::New("Array length must not be negative."));
+ Throw("Array length must not be negative.");
return 0;
}
@@ -323,17 +366,10 @@
ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
#endif // V8_SHARED
if (raw_value > static_cast<int32_t>(kMaxLength)) {
- ThrowException(
- String::New("Array length exceeds maximum length."));
+ Throw("Array length exceeds maximum length.");
}
return raw_value;
}
-
-
-// TODO(rossberg): should replace these by proper uses of HasInstance,
-// once we figure out a good way to make the templates global.
-const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_";
-const char kArrayMarkerPropName[] = "d8::_is_typed_array_";
Handle<Value> Shell::CreateExternalArrayBuffer(Handle<Object> buffer,
@@ -341,15 +377,15 @@
static const int32_t kMaxSize = 0x7fffffff;
// Make sure the total size fits into a (signed) int.
if (length < 0 || length > kMaxSize) {
- return ThrowException(String::New("ArrayBuffer exceeds maximum size
(2G)"));
+ return Throw("ArrayBuffer exceeds maximum size (2G)");
}
uint8_t* data = new uint8_t[length];
if (data == NULL) {
- return ThrowException(String::New("Memory allocation failed"));
+ return Throw("Memory allocation failed");
}
memset(data, 0, length);
- buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True());
+ buffer->SetHiddenValue(Symbols::ArrayBufferMarkerPropName, True());
Persistent<Object> persistent_array = Persistent<Object>::New(buffer);
persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
persistent_array.MarkIndependent();
@@ -357,7 +393,7 @@
buffer->SetIndexedPropertiesToExternalArrayData(
data, v8::kExternalByteArray, length);
- buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly);
+ buffer->Set(Symbols::byteLength, Int32::New(length), ReadOnly);
return buffer;
}
@@ -373,8 +409,7 @@
}
if (args.Length() == 0) {
- return ThrowException(
- String::New("ArrayBuffer constructor must have one argument"));
+ return Throw("ArrayBuffer constructor must have one argument");
}
TryCatch try_catch;
int32_t length = convertToUint(args[0], &try_catch);
@@ -400,12 +435,12 @@
array->SetIndexedPropertiesToExternalArrayData(
static_cast<uint8_t*>(data) + byteOffset, type, length);
- array->SetHiddenValue(String::New(kArrayMarkerPropName),
Int32::New(type));
- array->Set(String::New("byteLength"), Int32::New(byteLength), ReadOnly);
- array->Set(String::New("byteOffset"), Int32::New(byteOffset), ReadOnly);
- array->Set(String::New("length"), Int32::New(length), ReadOnly);
- array->Set(String::New("BYTES_PER_ELEMENT"), Int32::New(element_size));
- array->Set(String::New("buffer"), buffer, ReadOnly);
+ array->SetHiddenValue(Symbols::ArrayMarkerPropName, Int32::New(type));
+ array->Set(Symbols::byteLength, Int32::New(byteLength), ReadOnly);
+ array->Set(Symbols::byteOffset, Int32::New(byteOffset), ReadOnly);
+ array->Set(Symbols::length, Int32::New(length), ReadOnly);
+ array->Set(Symbols::BYTES_PER_ELEMENT, Int32::New(element_size));
+ array->Set(Symbols::buffer, buffer, ReadOnly);
return array;
}
@@ -439,16 +474,15 @@
int32_t byteOffset;
bool init_from_array = false;
if (args.Length() == 0) {
- return ThrowException(
- String::New("Array constructor must have at least one argument"));
+ return Throw("Array constructor must have at least one argument");
}
if (args[0]->IsObject() &&
!args[0]->ToObject()->GetHiddenValue(
- String::New(kArrayBufferMarkerPropName)).IsEmpty()) {
+ Symbols::ArrayBufferMarkerPropName).IsEmpty()) {
// Construct from ArrayBuffer.
buffer = args[0]->ToObject();
int32_t bufferLength =
- convertToUint(buffer->Get(String::New("byteLength")), &try_catch);
+ convertToUint(buffer->Get(Symbols::byteLength), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
if (args.Length() < 2 || args[1]->IsUndefined()) {
@@ -457,11 +491,10 @@
byteOffset = convertToUint(args[1], &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
if (byteOffset > bufferLength) {
- return ThrowException(String::New("byteOffset out of bounds"));
+ return Throw("byteOffset out of bounds");
}
if (byteOffset % element_size != 0) {
- return ThrowException(
- String::New("byteOffset must be multiple of element size"));
+ return Throw("byteOffset must be multiple of element size");
}
}
@@ -469,23 +502,22 @@
byteLength = bufferLength - byteOffset;
length = byteLength / element_size;
if (byteLength % element_size != 0) {
- return ThrowException(
- String::New("buffer size must be multiple of element size"));
+ return Throw("buffer size must be multiple of element size");
}
} else {
length = convertToUint(args[2], &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
byteLength = length * element_size;
if (byteOffset + byteLength > bufferLength) {
- return ThrowException(String::New("length out of bounds"));
+ return Throw("length out of bounds");
}
}
} else {
if (args[0]->IsObject() &&
- args[0]->ToObject()->Has(String::New("length"))) {
+ args[0]->ToObject()->Has(Symbols::length)) {
// Construct from array.
length = convertToUint(
- args[0]->ToObject()->Get(String::New("length")), &try_catch);
+ args[0]->ToObject()->Get(Symbols::length), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
init_from_array = true;
} else {
@@ -497,7 +529,7 @@
byteOffset = 0;
Handle<Object> global = Context::GetCurrent()->Global();
- Handle<Value> array_buffer = global->Get(String::New("ArrayBuffer"));
+ Handle<Value> array_buffer = global->Get(Symbols::ArrayBuffer);
ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction());
Handle<Value> buffer_args[] = { Uint32::New(byteLength) };
Handle<Value> result =
Handle<Function>::Cast(array_buffer)->NewInstance(
@@ -522,25 +554,22 @@
TryCatch try_catch;
if (!args.This()->IsObject()) {
- return ThrowException(
- String::New("'slice' invoked on non-object receiver"));
+ return Throw("'slice' invoked on non-object receiver");
}
Local<Object> self = args.This();
Local<Value> marker =
- self->GetHiddenValue(String::New(kArrayBufferMarkerPropName));
+ self->GetHiddenValue(Symbols::ArrayBufferMarkerPropName);
if (marker.IsEmpty()) {
- return ThrowException(
- String::New("'slice' invoked on wrong receiver type"));
+ return Throw("'slice' invoked on wrong receiver type");
}
int32_t length =
- convertToUint(self->Get(String::New("byteLength")), &try_catch);
+ convertToUint(self->Get(Symbols::byteLength), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
if (args.Length() == 0) {
- return ThrowException(
- String::New("'slice' must have at least one argument"));
+ return Throw("'slice' must have at least one argument");
}
int32_t begin = convertToInt(args[0], &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
@@ -579,32 +608,29 @@
TryCatch try_catch;
if (!args.This()->IsObject()) {
- return ThrowException(
- String::New("'subarray' invoked on non-object receiver"));
+ return Throw("'subarray' invoked on non-object receiver");
}
Local<Object> self = args.This();
- Local<Value> marker =
self->GetHiddenValue(String::New(kArrayMarkerPropName));
+ Local<Value> marker = self->GetHiddenValue(Symbols::ArrayMarkerPropName);
if (marker.IsEmpty()) {
- return ThrowException(
- String::New("'subarray' invoked on wrong receiver type"));
+ return Throw("'subarray' invoked on wrong receiver type");
}
- Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject();
+ Handle<Object> buffer = self->Get(Symbols::buffer)->ToObject();
if (try_catch.HasCaught()) return try_catch.ReThrow();
int32_t length =
- convertToUint(self->Get(String::New("length")), &try_catch);
+ convertToUint(self->Get(Symbols::length), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
int32_t byteOffset =
- convertToUint(self->Get(String::New("byteOffset")), &try_catch);
+ convertToUint(self->Get(Symbols::byteOffset), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
int32_t element_size =
- convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")),
&try_catch);
+ convertToUint(self->Get(Symbols::BYTES_PER_ELEMENT), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
if (args.Length() == 0) {
- return ThrowException(
- String::New("'subarray' must have at least one argument"));
+ return Throw("'subarray' must have at least one argument");
}
int32_t begin = convertToInt(args[0], &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
@@ -639,35 +665,31 @@
TryCatch try_catch;
if (!args.This()->IsObject()) {
- return ThrowException(
- String::New("'set' invoked on non-object receiver"));
+ return Throw("'set' invoked on non-object receiver");
}
Local<Object> self = args.This();
- Local<Value> marker =
self->GetHiddenValue(String::New(kArrayMarkerPropName));
+ Local<Value> marker = self->GetHiddenValue(Symbols::ArrayMarkerPropName);
if (marker.IsEmpty()) {
- return ThrowException(
- String::New("'set' invoked on wrong receiver type"));
+ return Throw("'set' invoked on wrong receiver type");
}
int32_t length =
- convertToUint(self->Get(String::New("length")), &try_catch);
+ convertToUint(self->Get(Symbols::length), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
int32_t element_size =
- convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")),
&try_catch);
+ convertToUint(self->Get(Symbols::BYTES_PER_ELEMENT), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
if (args.Length() == 0) {
- return ThrowException(
- String::New("'set' must have at least one argument"));
+ return Throw("'set' must have at least one argument");
}
if (!args[0]->IsObject() ||
- !args[0]->ToObject()->Has(String::New("length"))) {
- return ThrowException(
- String::New("'set' invoked with non-array argument"));
+ !args[0]->ToObject()->Has(Symbols::length)) {
+ return Throw("'set' invoked with non-array argument");
}
Handle<Object> source = args[0]->ToObject();
int32_t source_length =
- convertToUint(source->Get(String::New("length")), &try_catch);
+ convertToUint(source->Get(Symbols::length), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
int32_t offset;
@@ -678,31 +700,31 @@
if (try_catch.HasCaught()) return try_catch.ReThrow();
}
if (offset + source_length > length) {
- return ThrowException(String::New("offset or source length out of
bounds"));
+ return Throw("offset or source length out of bounds");
}
int32_t source_element_size;
- if (source->GetHiddenValue(String::New(kArrayMarkerPropName)).IsEmpty())
{
+ if (source->GetHiddenValue(Symbols::ArrayMarkerPropName).IsEmpty()) {
source_element_size = 0;
} else {
source_element_size =
- convertToUint(source->Get(String::New("BYTES_PER_ELEMENT")),
&try_catch);
+ convertToUint(source->Get(Symbols::BYTES_PER_ELEMENT), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
}
if (element_size == source_element_size &&
self->GetConstructor()->StrictEquals(source->GetConstructor())) {
// Use memmove on the array buffers.
- Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject();
+ Handle<Object> buffer = self->Get(Symbols::buffer)->ToObject();
if (try_catch.HasCaught()) return try_catch.ReThrow();
Handle<Object> source_buffer =
- source->Get(String::New("buffer"))->ToObject();
+ source->Get(Symbols::buffer)->ToObject();
if (try_catch.HasCaught()) return try_catch.ReThrow();
int32_t byteOffset =
- convertToUint(self->Get(String::New("byteOffset")), &try_catch);
+ convertToUint(self->Get(Symbols::byteOffset), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
int32_t source_byteOffset =
- convertToUint(source->Get(String::New("byteOffset")), &try_catch);
+ convertToUint(source->Get(Symbols::byteOffset), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
uint8_t* dest = byteOffset + offset * element_size +
static_cast<uint8_t*>(
@@ -718,10 +740,10 @@
}
} else {
// Need to copy element-wise to make the right conversions.
- Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject();
+ Handle<Object> buffer = self->Get(Symbols::buffer)->ToObject();
if (try_catch.HasCaught()) return try_catch.ReThrow();
Handle<Object> source_buffer =
- source->Get(String::New("buffer"))->ToObject();
+ source->Get(Symbols::buffer)->ToObject();
if (try_catch.HasCaught()) return try_catch.ReThrow();
if (buffer->StrictEquals(source_buffer)) {
@@ -729,10 +751,10 @@
// This gets a bit tricky in the case of different element sizes
// (which, of course, is extremely unlikely to ever occur in
practice).
int32_t byteOffset =
- convertToUint(self->Get(String::New("byteOffset")), &try_catch);
+ convertToUint(self->Get(Symbols::byteOffset), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
int32_t source_byteOffset =
- convertToUint(source->Get(String::New("byteOffset")),
&try_catch);
+ convertToUint(source->Get(Symbols::byteOffset), &try_catch);
if (try_catch.HasCaught()) return try_catch.ReThrow();
// Copy as much as we can from left to right.
@@ -779,7 +801,7 @@
void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void*
data) {
HandleScope scope;
int32_t length =
- object->ToObject()->Get(String::New("byteLength"))->Uint32Value();
+ object->ToObject()->Get(Symbols::byteLength)->Uint32Value();
V8::AdjustAmountOfExternalAllocatedMemory(-length);
delete[] static_cast<uint8_t*>(data);
object.Dispose();
@@ -1165,7 +1187,7 @@
// Bind the handlers for external arrays.
PropertyAttribute attr =
static_cast<PropertyAttribute>(ReadOnly | DontDelete);
- global_template->Set(String::New("ArrayBuffer"),
+ global_template->Set(Symbols::ArrayBuffer,
CreateArrayBufferTemplate(ArrayBuffer), attr);
global_template->Set(String::New("Int8Array"),
CreateArrayTemplate(Int8Array), attr);
@@ -1223,6 +1245,8 @@
V8::SetAddHistogramSampleFunction(AddHistogramSample);
}
#endif // V8_SHARED
+
+ Symbols::Initialize();
if (options.test_shell) return;
#ifndef V8_SHARED
@@ -1381,15 +1405,15 @@
String::Utf8Value filename(args[0]);
int length;
if (*filename == NULL) {
- return ThrowException(String::New("Error loading file"));
+ return Throw("Error loading file");
}
uint8_t* data = reinterpret_cast<uint8_t*>(ReadChars(*filename,
&length));
if (data == NULL) {
- return ThrowException(String::New("Error reading file"));
+ return Throw("Error reading file");
}
Handle<Object> buffer = Object::New();
- buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True());
+ buffer->SetHiddenValue(Symbols::ArrayBufferMarkerPropName, True());
Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer);
persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback);
persistent_buffer.MarkIndependent();
@@ -1397,7 +1421,7 @@
buffer->SetIndexedPropertiesToExternalArrayData(
data, kExternalUnsignedByteArray, length);
- buffer->Set(String::New("byteLength"),
+ buffer->Set(Symbols::byteLength,
Int32::New(static_cast<int32_t>(length)), ReadOnly);
return buffer;
}
@@ -1895,6 +1919,7 @@
RunShell();
}
+ Symbols::TearDown();
V8::Dispose();
#ifndef V8_SHARED
=======================================
--- /trunk/src/date.js Tue Sep 11 06:22:37 2012
+++ /trunk/src/date.js Fri Nov 16 06:43:43 2012
@@ -107,7 +107,7 @@
}
// Now we rely on year and month being SMIs.
- return %DateMakeDay(year, month) + date - 1;
+ return %DateMakeDay(year | 0, month | 0) + date - 1;
}
=======================================
--- /trunk/src/elements.cc Mon Nov 12 06:53:34 2012
+++ /trunk/src/elements.cc Fri Nov 16 06:43:43 2012
@@ -146,13 +146,13 @@
}
-void CopyObjectToObjectElements(FixedArray* from,
- ElementsKind from_kind,
- uint32_t from_start,
- FixedArray* to,
- ElementsKind to_kind,
- uint32_t to_start,
- int raw_copy_size) {
+static void CopyObjectToObjectElements(FixedArray* from,
+ ElementsKind from_kind,
+ uint32_t from_start,
+ FixedArray* to,
+ ElementsKind to_kind,
+ uint32_t to_start,
+ int raw_copy_size) {
ASSERT(to->map() != HEAP->fixed_cow_array_map());
int copy_size = raw_copy_size;
if (raw_copy_size < 0) {
@@ -585,6 +585,49 @@
}
return backing_store->is_the_hole(key) ? ABSENT : NONE;
}
+
+ MUST_USE_RESULT virtual PropertyType GetType(
+ Object* receiver,
+ JSObject* holder,
+ uint32_t key,
+ FixedArrayBase* backing_store) {
+ if (backing_store == NULL) {
+ backing_store = holder->elements();
+ }
+ return ElementsAccessorSubclass::GetTypeImpl(
+ receiver, holder, key, BackingStore::cast(backing_store));
+ }
+
+ MUST_USE_RESULT static PropertyType GetTypeImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ BackingStore* backing_store) {
+ if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
+ return NONEXISTENT;
+ }
+ return backing_store->is_the_hole(key) ? NONEXISTENT : FIELD;
+ }
+
+ MUST_USE_RESULT virtual AccessorPair* GetAccessorPair(
+ Object* receiver,
+ JSObject* holder,
+ uint32_t key,
+ FixedArrayBase* backing_store) {
+ if (backing_store == NULL) {
+ backing_store = holder->elements();
+ }
+ return ElementsAccessorSubclass::GetAccessorPairImpl(
+ receiver, holder, key, BackingStore::cast(backing_store));
+ }
+
+ MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ BackingStore* backing_store) {
+ return NULL;
+ }
MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array,
Object* length) {
@@ -653,7 +696,7 @@
}
}
}
- if (from->length() == 0) {
+ if (from->length() == 0 || copy_size == 0) {
return from;
}
return ElementsAccessorSubclass::CopyElementsImpl(
@@ -1172,7 +1215,17 @@
BackingStore* backing_store) {
return
key <
ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
- ? NONE : ABSENT;
+ ? NONE : ABSENT;
+ }
+
+ MUST_USE_RESULT static PropertyType GetTypeImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ BackingStore* backing_store) {
+ return
+ key <
ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
+ ? FIELD : NONEXISTENT;
}
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
@@ -1474,6 +1527,32 @@
}
return ABSENT;
}
+
+ MUST_USE_RESULT static PropertyType GetTypeImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ SeededNumberDictionary* backing_store) {
+ int entry = backing_store->FindEntry(key);
+ if (entry != SeededNumberDictionary::kNotFound) {
+ return backing_store->DetailsAt(entry).type();
+ }
+ return NONEXISTENT;
+ }
+
+ MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ BackingStore* backing_store) {
+ int entry = backing_store->FindEntry(key);
+ if (entry != SeededNumberDictionary::kNotFound &&
+ backing_store->DetailsAt(entry).type() == CALLBACKS &&
+ backing_store->ValueAt(entry)->IsAccessorPair()) {
+ return AccessorPair::cast(backing_store->ValueAt(entry));
+ }
+ return NULL;
+ }
static bool HasElementImpl(Object* receiver,
JSObject* holder,
@@ -1549,6 +1628,38 @@
receiver, obj, key, arguments);
}
}
+
+ MUST_USE_RESULT static PropertyType GetTypeImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ FixedArray* parameter_map) {
+ Object* probe = GetParameterMapArg(obj, parameter_map, key);
+ if (!probe->IsTheHole()) {
+ return FIELD;
+ } else {
+ // If not aliased, check the arguments.
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ return ElementsAccessor::ForArray(arguments)->GetType(
+ receiver, obj, key, arguments);
+ }
+ }
+
+ MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ FixedArray* parameter_map) {
+ Object* probe = GetParameterMapArg(obj, parameter_map, key);
+ if (!probe->IsTheHole()) {
+ return NULL;
+ } else {
+ // If not aliased, check the arguments.
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ return ElementsAccessor::ForArray(arguments)->GetAccessorPair(
+ receiver, obj, key, arguments);
+ }
+ }
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
JSObject* obj,
=======================================
--- /trunk/src/elements.h Mon Nov 12 06:53:34 2012
+++ /trunk/src/elements.h Fri Nov 16 06:43:43 2012
@@ -82,6 +82,28 @@
uint32_t key,
FixedArrayBase* backing_store = NULL) = 0;
+ // Returns an element's type, or NONEXISTENT if there is no such
+ // element. This method doesn't iterate up the prototype chain. The
caller
+ // can optionally pass in the backing store to use for the check, which
must
+ // be compatible with the ElementsKind of the ElementsAccessor. If
+ // backing_store is NULL, the holder->elements() is used as the backing
store.
+ MUST_USE_RESULT virtual PropertyType GetType(
+ Object* receiver,
+ JSObject* holder,
+ uint32_t key,
+ FixedArrayBase* backing_store = NULL) = 0;
+
+ // Returns an element's accessors, or NULL if the element does not exist
or
+ // is plain. This method doesn't iterate up the prototype chain. The
caller
+ // can optionally pass in the backing store to use for the check, which
must
+ // be compatible with the ElementsKind of the ElementsAccessor. If
+ // backing_store is NULL, the holder->elements() is used as the backing
store.
+ MUST_USE_RESULT virtual AccessorPair* GetAccessorPair(
+ Object* receiver,
+ JSObject* holder,
+ uint32_t key,
+ FixedArrayBase* backing_store = NULL) = 0;
+
// Modifies the length data property as specified for JSArrays and
resizes the
// underlying backing store accordingly. The method honors the semantics
of
// changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e.
array that
@@ -175,16 +197,6 @@
DISALLOW_COPY_AND_ASSIGN(ElementsAccessor);
};
-
-void CopyObjectToObjectElements(FixedArray* from_obj,
- ElementsKind from_kind,
- uint32_t from_start,
- FixedArray* to_obj,
- ElementsKind to_kind,
- uint32_t to_start,
- int copy_size);
-
-
} } // namespace v8::internal
#endif // V8_ELEMENTS_H_
=======================================
--- /trunk/src/execution.cc Mon Oct 15 04:51:39 2012
+++ /trunk/src/execution.cc Fri Nov 16 06:43:43 2012
@@ -937,7 +937,8 @@
}
stack_guard->Continue(CODE_READY);
}
- if (!stack_guard->IsTerminateExecution()) {
+ if (!stack_guard->IsTerminateExecution() &&
+ !FLAG_manual_parallel_recompilation) {
isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
}
=======================================
--- /trunk/src/factory.cc Tue Nov 13 05:56:09 2012
+++ /trunk/src/factory.cc Fri Nov 16 06:43:43 2012
@@ -178,7 +178,7 @@
}
-Handle<String> Factory::LookupAsciiSymbol(Handle<SeqAsciiString> string,
+Handle<String> Factory::LookupAsciiSymbol(Handle<SeqOneByteString> string,
int from,
int length) {
CALL_HEAP_FUNCTION(isolate(),
@@ -222,12 +222,12 @@
}
-Handle<SeqAsciiString> Factory::NewRawAsciiString(int length,
+Handle<SeqOneByteString> Factory::NewRawOneByteString(int length,
PretenureFlag pretenure)
{
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateRawAsciiString(length, pretenure),
- SeqAsciiString);
+ SeqOneByteString);
}
@@ -968,6 +968,7 @@
isolate(),
isolate()->heap()->AllocateJSArrayWithElements(*elements,
elements_kind,
+ elements->length(),
pretenure),
JSArray);
}
@@ -1366,7 +1367,7 @@
// Check to see whether there is a matching element in the cache.
Handle<MapCache> cache =
Handle<MapCache>(MapCache::cast(context->map_cache()));
- Handle<Object> result = Handle<Object>(cache->Lookup(*keys));
+ Handle<Object> result = Handle<Object>(cache->Lookup(*keys), isolate());
if (result->IsMap()) return Handle<Map>::cast(result);
// Create a new map and add it to the cache.
Handle<Map> map =
@@ -1418,7 +1419,7 @@
bool* pending_exception) {
// Configure the instance by adding the properties specified by the
// instance template.
- Handle<Object> instance_template =
Handle<Object>(desc->instance_template());
+ Handle<Object> instance_template(desc->instance_template(), isolate());
if (!instance_template->IsUndefined()) {
Execution::ConfigureInstance(instance,
instance_template,
=======================================
--- /trunk/src/factory.h Tue Nov 13 05:56:09 2012
+++ /trunk/src/factory.h Fri Nov 16 06:43:43 2012
@@ -82,7 +82,7 @@
Handle<String> LookupSymbol(Vector<const char> str);
Handle<String> LookupSymbol(Handle<String> str);
Handle<String> LookupAsciiSymbol(Vector<const char> str);
- Handle<String> LookupAsciiSymbol(Handle<SeqAsciiString>,
+ Handle<String> LookupAsciiSymbol(Handle<SeqOneByteString>,
int from,
int length);
Handle<String> LookupTwoByteSymbol(Vector<const uc16> str);
@@ -130,7 +130,7 @@
// Allocates and partially initializes an ASCII or TwoByte String. The
// characters of the string are uninitialized. Currently used in regexp
code
// only, where they are pretenured.
- Handle<SeqAsciiString> NewRawAsciiString(
+ Handle<SeqOneByteString> NewRawOneByteString(
int length,
PretenureFlag pretenure = NOT_TENURED);
Handle<SeqTwoByteString> NewRawTwoByteString(
=======================================
--- /trunk/src/flag-definitions.h Mon Nov 12 06:53:34 2012
+++ /trunk/src/flag-definitions.h Fri Nov 16 06:43:43 2012
@@ -225,7 +225,7 @@
DEFINE_bool(optimize_for_in, true,
"optimize functions containing for-in loops")
DEFINE_bool(opt_safe_uint32_operations, true,
- "allow uint32 values on optimize frames if they are used only
in"
+ "allow uint32 values on optimize frames if they are used only
in "
"safe operations")
DEFINE_bool(parallel_recompilation, false,
@@ -233,6 +233,9 @@
DEFINE_bool(trace_parallel_recompilation, false, "track parallel
recompilation")
DEFINE_int(parallel_recompilation_queue_length, 2,
"the length of the parallel compilation queue")
+DEFINE_bool(manual_parallel_recompilation, false,
+ "disable automatic optimization")
+DEFINE_implication(manual_parallel_recompilation, parallel_recompilation)
// Experimental profiler changes.
DEFINE_bool(experimental_profiler, true, "enable all profiler experiments")
@@ -346,6 +349,10 @@
DEFINE_bool(cache_prototype_transitions, true, "cache prototype
transitions")
+// cpu-profiler.cc
+DEFINE_int(cpu_profiler_sampling_period, 1000,
+ "CPU profiler sampling period in microseconds")
+
// debug.cc
DEFINE_bool(trace_debug_json, false, "trace debugging JSON
request/response")
DEFINE_bool(debugger_auto_break, true,
@@ -438,6 +445,9 @@
DEFINE_bool(cleanup_code_caches_at_gc, true,
"Flush inline caches prior to mark compact collection and "
"flush code caches in maps during mark compact cycle.")
+DEFINE_bool(use_marking_progress_bar, false,
+ "Use a progress bar to scan large objects in increments when "
+ "incremental marking is active.")
DEFINE_int(random_seed, 0,
"Default seed for initializing random generator "
"(0, the default, means to use system random).")
=======================================
--- /trunk/src/handles.h Mon Nov 12 06:53:34 2012
+++ /trunk/src/handles.h Fri Nov 16 06:43:43 2012
@@ -97,8 +97,8 @@
// Convenience wrapper.
template<class T>
-inline Handle<T> handle(T* t) {
- return Handle<T>(t);
+inline Handle<T> handle(T* t, Isolate* isolate) {
+ return Handle<T>(t, isolate);
}
=======================================
--- /trunk/src/heap-inl.h Wed Oct 31 03:02:10 2012
+++ /trunk/src/heap-inl.h Fri Nov 16 06:43:43 2012
@@ -109,12 +109,12 @@
MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str,
uint32_t hash_field) {
- if (str.length() > SeqAsciiString::kMaxLength) {
+ if (str.length() > SeqOneByteString::kMaxLength) {
return Failure::OutOfMemoryException();
}
// Compute map and object size.
Map* map = ascii_symbol_map();
- int size = SeqAsciiString::SizeFor(str.length());
+ int size = SeqOneByteString::SizeFor(str.length());
// Allocate string.
Object* result;
@@ -134,7 +134,7 @@
ASSERT_EQ(size, answer->Size());
// Fill in the characters.
- memcpy(answer->address() + SeqAsciiString::kHeaderSize,
+ memcpy(answer->address() + SeqOneByteString::kHeaderSize,
str.start(), str.length());
return answer;
=======================================
--- /trunk/src/heap.cc Tue Nov 13 05:56:09 2012
+++ /trunk/src/heap.cc Fri Nov 16 06:43:43 2012
@@ -137,6 +137,7 @@
tracer_(NULL),
young_survivors_after_last_gc_(0),
high_survival_rate_period_length_(0),
+ low_survival_rate_period_length_(0),
survival_rate_(0),
previous_survival_rate_trend_(Heap::STABLE),
survival_rate_trend_(Heap::STABLE),
@@ -1763,7 +1764,7 @@
class ScavengingVisitor : public StaticVisitorBase {
public:
static void Initialize() {
- table_.Register(kVisitSeqAsciiString, &EvacuateSeqAsciiString);
+ table_.Register(kVisitSeqOneByteString, &EvacuateSeqOneByteString);
table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString);
table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
table_.Register(kVisitByteArray, &EvacuateByteArray);
@@ -2007,11 +2008,11 @@
}
- static inline void EvacuateSeqAsciiString(Map* map,
+ static inline void EvacuateSeqOneByteString(Map* map,
HeapObject** slot,
HeapObject* object) {
- int object_size = SeqAsciiString::cast(object)->
- SeqAsciiStringSize(map->instance_type());
+ int object_size = SeqOneByteString::cast(object)->
+ SeqOneByteStringSize(map->instance_type());
EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
map, slot, object, object_size);
}
@@ -3353,7 +3354,7 @@
{ MaybeObject* maybe_result = heap->AllocateRawAsciiString(2);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- char* dest = SeqAsciiString::cast(result)->GetChars();
+ char* dest = SeqOneByteString::cast(result)->GetChars();
dest[0] = c1;
dest[1] = c2;
return result;
@@ -3427,20 +3428,20 @@
if (!maybe_result->ToObject(&result)) return maybe_result;
}
// Copy the characters into the new object.
- char* dest = SeqAsciiString::cast(result)->GetChars();
+ char* dest = SeqOneByteString::cast(result)->GetChars();
// Copy first part.
const char* src;
if (first->IsExternalString()) {
src = ExternalAsciiString::cast(first)->GetChars();
} else {
- src = SeqAsciiString::cast(first)->GetChars();
+ src = SeqOneByteString::cast(first)->GetChars();
}
for (int i = 0; i < first_length; i++) *dest++ = src[i];
// Copy second part.
if (second->IsExternalString()) {
src = ExternalAsciiString::cast(second)->GetChars();
} else {
- src = SeqAsciiString::cast(second)->GetChars();
+ src = SeqOneByteString::cast(second)->GetChars();
}
for (int i = 0; i < second_length; i++) *dest++ = src[i];
return result;
@@ -3451,7 +3452,7 @@
if (!maybe_result->ToObject(&result)) return maybe_result;
}
// Copy the characters into the new object.
- char* dest = SeqAsciiString::cast(result)->GetChars();
+ char* dest = SeqOneByteString::cast(result)->GetChars();
String::WriteToFlat(first, dest, 0, first_length);
String::WriteToFlat(second, dest + first_length, 0, second_length);
isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
@@ -3528,7 +3529,7 @@
// Copy the characters into the new object.
if (is_ascii) {
ASSERT(string_result->IsAsciiRepresentation());
- char* dest = SeqAsciiString::cast(string_result)->GetChars();
+ char* dest = SeqOneByteString::cast(string_result)->GetChars();
String::WriteToFlat(buffer, dest, start, end);
} else {
ASSERT(string_result->IsTwoByteRepresentation());
@@ -3787,7 +3788,7 @@
code->set_check_type(RECEIVER_MAP_CHECK);
}
code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
- code->set_type_feedback_info(undefined_value(), SKIP_WRITE_BARRIER);
+ code->InitializeTypeFeedbackInfoNoWriteBarrier(undefined_value());
code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
code->set_gc_metadata(Smi::FromInt(0));
code->set_ic_age(global_ic_age_);
@@ -4181,7 +4182,7 @@
InitializeJSObjectFromMap(JSObject::cast(obj),
FixedArray::cast(properties),
map);
- ASSERT(JSObject::cast(obj)->HasFastSmiOrObjectElements());
+ ASSERT(JSObject::cast(obj)->HasFastElements());
return obj;
}
@@ -4246,7 +4247,7 @@
FixedArrayBase* elms;
MaybeObject* maybe_elms = NULL;
- if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+ if (IsFastDoubleElementsKind(elements_kind)) {
if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
} else {
@@ -4273,13 +4274,14 @@
MaybeObject* Heap::AllocateJSArrayWithElements(
FixedArrayBase* elements,
ElementsKind elements_kind,
+ int length,
PretenureFlag pretenure) {
MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
JSArray* array;
if (!maybe_array->To(&array)) return maybe_array;
array->set_elements(elements);
- array->set_length(Smi::FromInt(elements->length()));
+ array->set_length(Smi::FromInt(length));
array->ValidateElements();
return array;
}
@@ -4570,7 +4572,7 @@
}
// Copy the characters into the new object.
- CopyChars(SeqAsciiString::cast(result)->GetChars(), string.start(),
length);
+ CopyChars(SeqOneByteString::cast(result)->GetChars(), string.start(),
length);
return result;
}
@@ -4625,7 +4627,7 @@
if (String::IsAscii(start, length)) {
MaybeObject* maybe_result = AllocateRawAsciiString(length, pretenure);
if (!maybe_result->ToObject(&result)) return maybe_result;
- CopyChars(SeqAsciiString::cast(result)->GetChars(), start, length);
+ CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length);
} else { // It's not an ASCII string.
MaybeObject* maybe_result = AllocateRawTwoByteString(length,
pretenure);
if (!maybe_result->ToObject(&result)) return maybe_result;
@@ -4680,11 +4682,11 @@
Map* map;
if (is_ascii) {
- if (chars > SeqAsciiString::kMaxLength) {
+ if (chars > SeqOneByteString::kMaxLength) {
return Failure::OutOfMemoryException();
}
map = ascii_symbol_map();
- size = SeqAsciiString::SizeFor(chars);
+ size = SeqOneByteString::SizeFor(chars);
} else {
if (chars > SeqTwoByteString::kMaxLength) {
return Failure::OutOfMemoryException();
@@ -4725,12 +4727,12 @@
MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag
pretenure) {
- if (length < 0 || length > SeqAsciiString::kMaxLength) {
+ if (length < 0 || length > SeqOneByteString::kMaxLength) {
return Failure::OutOfMemoryException();
}
- int size = SeqAsciiString::SizeFor(length);
- ASSERT(size <= SeqAsciiString::kMaxSize);
+ int size = SeqOneByteString::SizeFor(length);
+ ASSERT(size <= SeqOneByteString::kMaxSize);
AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE :
NEW_SPACE;
AllocationSpace retry_space = OLD_DATA_SPACE;
@@ -4762,7 +4764,7 @@
if (FLAG_verify_heap) {
// Initialize string's content to ensure ASCII-ness (character range
0-127)
// as required when verifying the heap.
- char* dest = SeqAsciiString::cast(result)->GetChars();
+ char* dest = SeqOneByteString::cast(result)->GetChars();
memset(dest, 0x0F, length * kCharSize);
}
#endif
@@ -5623,7 +5625,7 @@
}
-MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqAsciiString> string,
+MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqOneByteString> string,
int from,
int length) {
Object* symbol = NULL;
@@ -7227,6 +7229,7 @@
} else {
PrintF("stepscount=%d ", steps_count_);
PrintF("stepstook=%d ", static_cast<int>(steps_took_));
+ PrintF("longeststep=%.f ", longest_step_);
}
PrintF("\n");
=======================================
***Additional files exist in this changeset.***