Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / v8 / src / ia32 / codegen-ia32.cc
index 350a8fb..444f98b 100644 (file)
@@ -1,37 +1,14 @@
 // Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "v8.h"
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
 
 #if V8_TARGET_ARCH_IA32
 
-#include "codegen.h"
-#include "heap.h"
-#include "macro-assembler.h"
+#include "src/codegen.h"
+#include "src/heap/heap.h"
+#include "src/macro-assembler.h"
 
 namespace v8 {
 namespace internal {
@@ -42,14 +19,14 @@ namespace internal {
 
 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
   masm->EnterFrame(StackFrame::INTERNAL);
-  ASSERT(!masm->has_frame());
+  DCHECK(!masm->has_frame());
   masm->set_has_frame(true);
 }
 
 
 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
   masm->LeaveFrame(StackFrame::INTERNAL);
-  ASSERT(masm->has_frame());
+  DCHECK(masm->has_frame());
   masm->set_has_frame(false);
 }
 
@@ -58,10 +35,10 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
 
 
 UnaryMathFunction CreateExpFunction() {
-  if (!CpuFeatures::IsSupported(SSE2)) return &std::exp;
   if (!FLAG_fast_math) return &std::exp;
   size_t actual_size;
-  byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
+  byte* buffer =
+      static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
   if (buffer == NULL) return &std::exp;
   ExternalReference::InitializeMathExpData();
 
@@ -69,7 +46,6 @@ UnaryMathFunction CreateExpFunction() {
   // esp[1 * kPointerSize]: raw double input
   // esp[0 * kPointerSize]: return address
   {
-    CpuFeatureScope use_sse2(&masm, SSE2);
     XMMRegister input = xmm1;
     XMMRegister result = xmm2;
     __ movsd(input, Operand(esp, 1 * kPointerSize));
@@ -87,10 +63,10 @@ UnaryMathFunction CreateExpFunction() {
 
   CodeDesc desc;
   masm.GetCode(&desc);
-  ASSERT(!RelocInfo::RequiresRelocation(desc));
+  DCHECK(!RelocInfo::RequiresRelocation(desc));
 
-  CPU::FlushICache(buffer, actual_size);
-  OS::ProtectCode(buffer, actual_size);
+  CpuFeatures::FlushICache(buffer, actual_size);
+  base::OS::ProtectCode(buffer, actual_size);
   return FUNCTION_CAST<UnaryMathFunction>(buffer);
 }
 
@@ -98,18 +74,14 @@ UnaryMathFunction CreateExpFunction() {
 UnaryMathFunction CreateSqrtFunction() {
   size_t actual_size;
   // Allocate buffer in executable space.
-  byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
-                                                 &actual_size,
-                                                 true));
-  // If SSE2 is not available, we can use libc's implementation to ensure
-  // consistency since code by fullcodegen's calls into runtime in that case.
-  if (buffer == NULL || !CpuFeatures::IsSupported(SSE2)) return &std::sqrt;
+  byte* buffer =
+      static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
+  if (buffer == NULL) return &std::sqrt;
   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
   // esp[1 * kPointerSize]: raw double input
   // esp[0 * kPointerSize]: return address
   // Move double input into registers.
   {
-    CpuFeatureScope use_sse2(&masm, SSE2);
     __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
     __ sqrtsd(xmm0, xmm0);
     __ movsd(Operand(esp, 1 * kPointerSize), xmm0);
@@ -120,10 +92,10 @@ UnaryMathFunction CreateSqrtFunction() {
 
   CodeDesc desc;
   masm.GetCode(&desc);
-  ASSERT(!RelocInfo::RequiresRelocation(desc));
+  DCHECK(!RelocInfo::RequiresRelocation(desc));
 
-  CPU::FlushICache(buffer, actual_size);
-  OS::ProtectCode(buffer, actual_size);
+  CpuFeatures::FlushICache(buffer, actual_size);
+  base::OS::ProtectCode(buffer, actual_size);
   return FUNCTION_CAST<UnaryMathFunction>(buffer);
 }
 
@@ -214,10 +186,11 @@ class LabelConverter {
 };
 
 
-OS::MemMoveFunction CreateMemMoveFunction() {
+MemMoveFunction CreateMemMoveFunction() {
   size_t actual_size;
   // Allocate buffer in executable space.
-  byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
+  byte* buffer =
+      static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
   if (buffer == NULL) return NULL;
   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
   LabelConverter conv(buffer);
@@ -266,325 +239,264 @@ OS::MemMoveFunction CreateMemMoveFunction() {
   __ cmp(dst, src);
   __ j(equal, &pop_and_return);
 
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope sse2_scope(&masm, SSE2);
-    __ prefetch(Operand(src, 0), 1);
+  __ prefetch(Operand(src, 0), 1);
+  __ cmp(count, kSmallCopySize);
+  __ j(below_equal, &small_size);
+  __ cmp(count, kMediumCopySize);
+  __ j(below_equal, &medium_size);
+  __ cmp(dst, src);
+  __ j(above, &backward);
+
+  {
+    // |dst| is a lower address than |src|. Copy front-to-back.
+    Label unaligned_source, move_last_15, skip_last_move;
+    __ mov(eax, src);
+    __ sub(eax, dst);
+    __ cmp(eax, kMinMoveDistance);
+    __ j(below, &forward_much_overlap);
+    // Copy first 16 bytes.
+    __ movdqu(xmm0, Operand(src, 0));
+    __ movdqu(Operand(dst, 0), xmm0);
+    // Determine distance to alignment: 16 - (dst & 0xF).
+    __ mov(edx, dst);
+    __ and_(edx, 0xF);
+    __ neg(edx);
+    __ add(edx, Immediate(16));
+    __ add(dst, edx);
+    __ add(src, edx);
+    __ sub(count, edx);
+    // dst is now aligned. Main copy loop.
+    __ mov(loop_count, count);
+    __ shr(loop_count, 6);
+    // Check if src is also aligned.
+    __ test(src, Immediate(0xF));
+    __ j(not_zero, &unaligned_source);
+    // Copy loop for aligned source and destination.
+    MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
+    // At most 15 bytes to copy. Copy 16 bytes at end of string.
+    __ bind(&move_last_15);
+    __ and_(count, 0xF);
+    __ j(zero, &skip_last_move, Label::kNear);
+    __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
+    __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
+    __ bind(&skip_last_move);
+    MemMoveEmitPopAndReturn(&masm);
+
+    // Copy loop for unaligned source and aligned destination.
+    __ bind(&unaligned_source);
+    MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
+    __ jmp(&move_last_15);
+
+    // Less than kMinMoveDistance offset between dst and src.
+    Label loop_until_aligned, last_15_much_overlap;
+    __ bind(&loop_until_aligned);
+    __ mov_b(eax, Operand(src, 0));
+    __ inc(src);
+    __ mov_b(Operand(dst, 0), eax);
+    __ inc(dst);
+    __ dec(count);
+    __ bind(&forward_much_overlap);  // Entry point into this block.
+    __ test(dst, Immediate(0xF));
+    __ j(not_zero, &loop_until_aligned);
+    // dst is now aligned, src can't be. Main copy loop.
+    __ mov(loop_count, count);
+    __ shr(loop_count, 6);
+    MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
+                        FORWARD, MOVE_UNALIGNED);
+    __ bind(&last_15_much_overlap);
+    __ and_(count, 0xF);
+    __ j(zero, &pop_and_return);
     __ cmp(count, kSmallCopySize);
     __ j(below_equal, &small_size);
-    __ cmp(count, kMediumCopySize);
-    __ j(below_equal, &medium_size);
-    __ cmp(dst, src);
-    __ j(above, &backward);
-
-    {
-      // |dst| is a lower address than |src|. Copy front-to-back.
-      Label unaligned_source, move_last_15, skip_last_move;
-      __ mov(eax, src);
-      __ sub(eax, dst);
-      __ cmp(eax, kMinMoveDistance);
-      __ j(below, &forward_much_overlap);
-      // Copy first 16 bytes.
-      __ movdqu(xmm0, Operand(src, 0));
-      __ movdqu(Operand(dst, 0), xmm0);
-      // Determine distance to alignment: 16 - (dst & 0xF).
-      __ mov(edx, dst);
-      __ and_(edx, 0xF);
-      __ neg(edx);
-      __ add(edx, Immediate(16));
-      __ add(dst, edx);
-      __ add(src, edx);
-      __ sub(count, edx);
-      // dst is now aligned. Main copy loop.
-      __ mov(loop_count, count);
-      __ shr(loop_count, 6);
-      // Check if src is also aligned.
-      __ test(src, Immediate(0xF));
-      __ j(not_zero, &unaligned_source);
-      // Copy loop for aligned source and destination.
-      MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
-      // At most 15 bytes to copy. Copy 16 bytes at end of string.
-      __ bind(&move_last_15);
-      __ and_(count, 0xF);
-      __ j(zero, &skip_last_move, Label::kNear);
-      __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
-      __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
-      __ bind(&skip_last_move);
-      MemMoveEmitPopAndReturn(&masm);
-
-      // Copy loop for unaligned source and aligned destination.
-      __ bind(&unaligned_source);
-      MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
-      __ jmp(&move_last_15);
-
-      // Less than kMinMoveDistance offset between dst and src.
-      Label loop_until_aligned, last_15_much_overlap;
-      __ bind(&loop_until_aligned);
-      __ mov_b(eax, Operand(src, 0));
-      __ inc(src);
-      __ mov_b(Operand(dst, 0), eax);
-      __ inc(dst);
-      __ dec(count);
-      __ bind(&forward_much_overlap);  // Entry point into this block.
-      __ test(dst, Immediate(0xF));
-      __ j(not_zero, &loop_until_aligned);
-      // dst is now aligned, src can't be. Main copy loop.
-      __ mov(loop_count, count);
-      __ shr(loop_count, 6);
-      MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
-                          FORWARD, MOVE_UNALIGNED);
-      __ bind(&last_15_much_overlap);
-      __ and_(count, 0xF);
-      __ j(zero, &pop_and_return);
-      __ cmp(count, kSmallCopySize);
-      __ j(below_equal, &small_size);
-      __ jmp(&medium_size);
-    }
+    __ jmp(&medium_size);
+  }
 
-    {
-      // |dst| is a higher address than |src|. Copy backwards.
-      Label unaligned_source, move_first_15, skip_last_move;
-      __ bind(&backward);
-      // |dst| and |src| always point to the end of what's left to copy.
-      __ add(dst, count);
-      __ add(src, count);
-      __ mov(eax, dst);
-      __ sub(eax, src);
-      __ cmp(eax, kMinMoveDistance);
-      __ j(below, &backward_much_overlap);
-      // Copy last 16 bytes.
-      __ movdqu(xmm0, Operand(src, -0x10));
-      __ movdqu(Operand(dst, -0x10), xmm0);
-      // Find distance to alignment: dst & 0xF
-      __ mov(edx, dst);
-      __ and_(edx, 0xF);
-      __ sub(dst, edx);
-      __ sub(src, edx);
-      __ sub(count, edx);
-      // dst is now aligned. Main copy loop.
-      __ mov(loop_count, count);
-      __ shr(loop_count, 6);
-      // Check if src is also aligned.
-      __ test(src, Immediate(0xF));
-      __ j(not_zero, &unaligned_source);
-      // Copy loop for aligned source and destination.
-      MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
-      // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
-      __ bind(&move_first_15);
-      __ and_(count, 0xF);
-      __ j(zero, &skip_last_move, Label::kNear);
-      __ sub(src, count);
-      __ sub(dst, count);
-      __ movdqu(xmm0, Operand(src, 0));
-      __ movdqu(Operand(dst, 0), xmm0);
-      __ bind(&skip_last_move);
-      MemMoveEmitPopAndReturn(&masm);
-
-      // Copy loop for unaligned source and aligned destination.
-      __ bind(&unaligned_source);
-      MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED);
-      __ jmp(&move_first_15);
-
-      // Less than kMinMoveDistance offset between dst and src.
-      Label loop_until_aligned, first_15_much_overlap;
-      __ bind(&loop_until_aligned);
-      __ dec(src);
-      __ dec(dst);
-      __ mov_b(eax, Operand(src, 0));
-      __ mov_b(Operand(dst, 0), eax);
-      __ dec(count);
-      __ bind(&backward_much_overlap);  // Entry point into this block.
-      __ test(dst, Immediate(0xF));
-      __ j(not_zero, &loop_until_aligned);
-      // dst is now aligned, src can't be. Main copy loop.
-      __ mov(loop_count, count);
-      __ shr(loop_count, 6);
-      MemMoveEmitMainLoop(&masm, &first_15_much_overlap,
-                          BACKWARD, MOVE_UNALIGNED);
-      __ bind(&first_15_much_overlap);
-      __ and_(count, 0xF);
-      __ j(zero, &pop_and_return);
-      // Small/medium handlers expect dst/src to point to the beginning.
-      __ sub(dst, count);
-      __ sub(src, count);
-      __ cmp(count, kSmallCopySize);
-      __ j(below_equal, &small_size);
-      __ jmp(&medium_size);
-    }
-    {
-      // Special handlers for 9 <= copy_size < 64. No assumptions about
-      // alignment or move distance, so all reads must be unaligned and
-      // must happen before any writes.
-      Label medium_handlers, f9_16, f17_32, f33_48, f49_63;
-
-      __ bind(&f9_16);
-      __ movsd(xmm0, Operand(src, 0));
-      __ movsd(xmm1, Operand(src, count, times_1, -8));
-      __ movsd(Operand(dst, 0), xmm0);
-      __ movsd(Operand(dst, count, times_1, -8), xmm1);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&f17_32);
-      __ movdqu(xmm0, Operand(src, 0));
-      __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
-      __ movdqu(Operand(dst, 0x00), xmm0);
-      __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&f33_48);
-      __ movdqu(xmm0, Operand(src, 0x00));
-      __ movdqu(xmm1, Operand(src, 0x10));
-      __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
-      __ movdqu(Operand(dst, 0x00), xmm0);
-      __ movdqu(Operand(dst, 0x10), xmm1);
-      __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&f49_63);
-      __ movdqu(xmm0, Operand(src, 0x00));
-      __ movdqu(xmm1, Operand(src, 0x10));
-      __ movdqu(xmm2, Operand(src, 0x20));
-      __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
-      __ movdqu(Operand(dst, 0x00), xmm0);
-      __ movdqu(Operand(dst, 0x10), xmm1);
-      __ movdqu(Operand(dst, 0x20), xmm2);
-      __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&medium_handlers);
-      __ dd(conv.address(&f9_16));
-      __ dd(conv.address(&f17_32));
-      __ dd(conv.address(&f33_48));
-      __ dd(conv.address(&f49_63));
-
-      __ bind(&medium_size);  // Entry point into this block.
-      __ mov(eax, count);
-      __ dec(eax);
-      __ shr(eax, 4);
-      if (FLAG_debug_code) {
-        Label ok;
-        __ cmp(eax, 3);
-        __ j(below_equal, &ok);
-        __ int3();
-        __ bind(&ok);
-      }
-      __ mov(eax, Operand(eax, times_4, conv.address(&medium_handlers)));
-      __ jmp(eax);
-    }
-    {
-      // Specialized copiers for copy_size <= 8 bytes.
-      Label small_handlers, f0, f1, f2, f3, f4, f5_8;
-      __ bind(&f0);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&f1);
-      __ mov_b(eax, Operand(src, 0));
-      __ mov_b(Operand(dst, 0), eax);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&f2);
-      __ mov_w(eax, Operand(src, 0));
-      __ mov_w(Operand(dst, 0), eax);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&f3);
-      __ mov_w(eax, Operand(src, 0));
-      __ mov_b(edx, Operand(src, 2));
-      __ mov_w(Operand(dst, 0), eax);
-      __ mov_b(Operand(dst, 2), edx);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&f4);
-      __ mov(eax, Operand(src, 0));
-      __ mov(Operand(dst, 0), eax);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&f5_8);
-      __ mov(eax, Operand(src, 0));
-      __ mov(edx, Operand(src, count, times_1, -4));
-      __ mov(Operand(dst, 0), eax);
-      __ mov(Operand(dst, count, times_1, -4), edx);
-      MemMoveEmitPopAndReturn(&masm);
-
-      __ bind(&small_handlers);
-      __ dd(conv.address(&f0));
-      __ dd(conv.address(&f1));
-      __ dd(conv.address(&f2));
-      __ dd(conv.address(&f3));
-      __ dd(conv.address(&f4));
-      __ dd(conv.address(&f5_8));
-      __ dd(conv.address(&f5_8));
-      __ dd(conv.address(&f5_8));
-      __ dd(conv.address(&f5_8));
-
-      __ bind(&small_size);  // Entry point into this block.
-      if (FLAG_debug_code) {
-        Label ok;
-        __ cmp(count, 8);
-        __ j(below_equal, &ok);
-        __ int3();
-        __ bind(&ok);
-      }
-      __ mov(eax, Operand(count, times_4, conv.address(&small_handlers)));
-      __ jmp(eax);
-    }
-  } else {
-    // No SSE2.
-    Label forward;
-    __ cmp(count, 0);
-    __ j(equal, &pop_and_return);
-    __ cmp(dst, src);
-    __ j(above, &backward);
-    __ jmp(&forward);
-    {
-      // Simple forward copier.
-      Label forward_loop_1byte, forward_loop_4byte;
-      __ bind(&forward_loop_4byte);
-      __ mov(eax, Operand(src, 0));
-      __ sub(count, Immediate(4));
-      __ add(src, Immediate(4));
-      __ mov(Operand(dst, 0), eax);
-      __ add(dst, Immediate(4));
-      __ bind(&forward);  // Entry point.
-      __ cmp(count, 3);
-      __ j(above, &forward_loop_4byte);
-      __ bind(&forward_loop_1byte);
-      __ cmp(count, 0);
-      __ j(below_equal, &pop_and_return);
-      __ mov_b(eax, Operand(src, 0));
-      __ dec(count);
-      __ inc(src);
-      __ mov_b(Operand(dst, 0), eax);
-      __ inc(dst);
-      __ jmp(&forward_loop_1byte);
+  {
+    // |dst| is a higher address than |src|. Copy backwards.
+    Label unaligned_source, move_first_15, skip_last_move;
+    __ bind(&backward);
+    // |dst| and |src| always point to the end of what's left to copy.
+    __ add(dst, count);
+    __ add(src, count);
+    __ mov(eax, dst);
+    __ sub(eax, src);
+    __ cmp(eax, kMinMoveDistance);
+    __ j(below, &backward_much_overlap);
+    // Copy last 16 bytes.
+    __ movdqu(xmm0, Operand(src, -0x10));
+    __ movdqu(Operand(dst, -0x10), xmm0);
+    // Find distance to alignment: dst & 0xF
+    __ mov(edx, dst);
+    __ and_(edx, 0xF);
+    __ sub(dst, edx);
+    __ sub(src, edx);
+    __ sub(count, edx);
+    // dst is now aligned. Main copy loop.
+    __ mov(loop_count, count);
+    __ shr(loop_count, 6);
+    // Check if src is also aligned.
+    __ test(src, Immediate(0xF));
+    __ j(not_zero, &unaligned_source);
+    // Copy loop for aligned source and destination.
+    MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
+    // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
+    __ bind(&move_first_15);
+    __ and_(count, 0xF);
+    __ j(zero, &skip_last_move, Label::kNear);
+    __ sub(src, count);
+    __ sub(dst, count);
+    __ movdqu(xmm0, Operand(src, 0));
+    __ movdqu(Operand(dst, 0), xmm0);
+    __ bind(&skip_last_move);
+    MemMoveEmitPopAndReturn(&masm);
+
+    // Copy loop for unaligned source and aligned destination.
+    __ bind(&unaligned_source);
+    MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED);
+    __ jmp(&move_first_15);
+
+    // Less than kMinMoveDistance offset between dst and src.
+    Label loop_until_aligned, first_15_much_overlap;
+    __ bind(&loop_until_aligned);
+    __ dec(src);
+    __ dec(dst);
+    __ mov_b(eax, Operand(src, 0));
+    __ mov_b(Operand(dst, 0), eax);
+    __ dec(count);
+    __ bind(&backward_much_overlap);  // Entry point into this block.
+    __ test(dst, Immediate(0xF));
+    __ j(not_zero, &loop_until_aligned);
+    // dst is now aligned, src can't be. Main copy loop.
+    __ mov(loop_count, count);
+    __ shr(loop_count, 6);
+    MemMoveEmitMainLoop(&masm, &first_15_much_overlap,
+                        BACKWARD, MOVE_UNALIGNED);
+    __ bind(&first_15_much_overlap);
+    __ and_(count, 0xF);
+    __ j(zero, &pop_and_return);
+    // Small/medium handlers expect dst/src to point to the beginning.
+    __ sub(dst, count);
+    __ sub(src, count);
+    __ cmp(count, kSmallCopySize);
+    __ j(below_equal, &small_size);
+    __ jmp(&medium_size);
+  }
+  {
+    // Special handlers for 9 <= copy_size < 64. No assumptions about
+    // alignment or move distance, so all reads must be unaligned and
+    // must happen before any writes.
+    Label medium_handlers, f9_16, f17_32, f33_48, f49_63;
+
+    __ bind(&f9_16);
+    __ movsd(xmm0, Operand(src, 0));
+    __ movsd(xmm1, Operand(src, count, times_1, -8));
+    __ movsd(Operand(dst, 0), xmm0);
+    __ movsd(Operand(dst, count, times_1, -8), xmm1);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&f17_32);
+    __ movdqu(xmm0, Operand(src, 0));
+    __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
+    __ movdqu(Operand(dst, 0x00), xmm0);
+    __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&f33_48);
+    __ movdqu(xmm0, Operand(src, 0x00));
+    __ movdqu(xmm1, Operand(src, 0x10));
+    __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
+    __ movdqu(Operand(dst, 0x00), xmm0);
+    __ movdqu(Operand(dst, 0x10), xmm1);
+    __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&f49_63);
+    __ movdqu(xmm0, Operand(src, 0x00));
+    __ movdqu(xmm1, Operand(src, 0x10));
+    __ movdqu(xmm2, Operand(src, 0x20));
+    __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
+    __ movdqu(Operand(dst, 0x00), xmm0);
+    __ movdqu(Operand(dst, 0x10), xmm1);
+    __ movdqu(Operand(dst, 0x20), xmm2);
+    __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&medium_handlers);
+    __ dd(conv.address(&f9_16));
+    __ dd(conv.address(&f17_32));
+    __ dd(conv.address(&f33_48));
+    __ dd(conv.address(&f49_63));
+
+    __ bind(&medium_size);  // Entry point into this block.
+    __ mov(eax, count);
+    __ dec(eax);
+    __ shr(eax, 4);
+    if (FLAG_debug_code) {
+      Label ok;
+      __ cmp(eax, 3);
+      __ j(below_equal, &ok);
+      __ int3();
+      __ bind(&ok);
     }
-    {
-      // Simple backward copier.
-      Label backward_loop_1byte, backward_loop_4byte, entry_shortcut;
-      __ bind(&backward);
-      __ add(src, count);
-      __ add(dst, count);
-      __ cmp(count, 3);
-      __ j(below_equal, &entry_shortcut);
-
-      __ bind(&backward_loop_4byte);
-      __ sub(src, Immediate(4));
-      __ sub(count, Immediate(4));
-      __ mov(eax, Operand(src, 0));
-      __ sub(dst, Immediate(4));
-      __ mov(Operand(dst, 0), eax);
-      __ cmp(count, 3);
-      __ j(above, &backward_loop_4byte);
-      __ bind(&backward_loop_1byte);
-      __ cmp(count, 0);
-      __ j(below_equal, &pop_and_return);
-      __ bind(&entry_shortcut);
-      __ dec(src);
-      __ dec(count);
-      __ mov_b(eax, Operand(src, 0));
-      __ dec(dst);
-      __ mov_b(Operand(dst, 0), eax);
-      __ jmp(&backward_loop_1byte);
+    __ mov(eax, Operand(eax, times_4, conv.address(&medium_handlers)));
+    __ jmp(eax);
+  }
+  {
+    // Specialized copiers for copy_size <= 8 bytes.
+    Label small_handlers, f0, f1, f2, f3, f4, f5_8;
+    __ bind(&f0);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&f1);
+    __ mov_b(eax, Operand(src, 0));
+    __ mov_b(Operand(dst, 0), eax);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&f2);
+    __ mov_w(eax, Operand(src, 0));
+    __ mov_w(Operand(dst, 0), eax);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&f3);
+    __ mov_w(eax, Operand(src, 0));
+    __ mov_b(edx, Operand(src, 2));
+    __ mov_w(Operand(dst, 0), eax);
+    __ mov_b(Operand(dst, 2), edx);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&f4);
+    __ mov(eax, Operand(src, 0));
+    __ mov(Operand(dst, 0), eax);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&f5_8);
+    __ mov(eax, Operand(src, 0));
+    __ mov(edx, Operand(src, count, times_1, -4));
+    __ mov(Operand(dst, 0), eax);
+    __ mov(Operand(dst, count, times_1, -4), edx);
+    MemMoveEmitPopAndReturn(&masm);
+
+    __ bind(&small_handlers);
+    __ dd(conv.address(&f0));
+    __ dd(conv.address(&f1));
+    __ dd(conv.address(&f2));
+    __ dd(conv.address(&f3));
+    __ dd(conv.address(&f4));
+    __ dd(conv.address(&f5_8));
+    __ dd(conv.address(&f5_8));
+    __ dd(conv.address(&f5_8));
+    __ dd(conv.address(&f5_8));
+
+    __ bind(&small_size);  // Entry point into this block.
+    if (FLAG_debug_code) {
+      Label ok;
+      __ cmp(count, 8);
+      __ j(below_equal, &ok);
+      __ int3();
+      __ bind(&ok);
     }
+    __ mov(eax, Operand(count, times_4, conv.address(&small_handlers)));
+    __ jmp(eax);
   }
 
   __ bind(&pop_and_return);
@@ -592,12 +504,12 @@ OS::MemMoveFunction CreateMemMoveFunction() {
 
   CodeDesc desc;
   masm.GetCode(&desc);
-  ASSERT(!RelocInfo::RequiresRelocation(desc));
-  CPU::FlushICache(buffer, actual_size);
-  OS::ProtectCode(buffer, actual_size);
+  DCHECK(!RelocInfo::RequiresRelocation(desc));
+  CpuFeatures::FlushICache(buffer, actual_size);
+  base::OS::ProtectCode(buffer, actual_size);
   // TODO(jkummerow): It would be nice to register this code creation event
   // with the PROFILE / GDBJIT system.
-  return FUNCTION_CAST<OS::MemMoveFunction>(buffer);
+  return FUNCTION_CAST<MemMoveFunction>(buffer);
 }
 
 
@@ -610,26 +522,28 @@ OS::MemMoveFunction CreateMemMoveFunction() {
 
 
 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
-    MacroAssembler* masm, AllocationSiteMode mode,
+    MacroAssembler* masm,
+    Register receiver,
+    Register key,
+    Register value,
+    Register target_map,
+    AllocationSiteMode mode,
     Label* allocation_memento_found) {
-  // ----------- S t a t e -------------
-  //  -- eax    : value
-  //  -- ebx    : target map
-  //  -- ecx    : key
-  //  -- edx    : receiver
-  //  -- esp[0] : return address
-  // -----------------------------------
+  Register scratch = edi;
+  DCHECK(!AreAliased(receiver, key, value, target_map, scratch));
+
   if (mode == TRACK_ALLOCATION_SITE) {
-    ASSERT(allocation_memento_found != NULL);
-    __ JumpIfJSArrayHasAllocationMemento(edx, edi, allocation_memento_found);
+    DCHECK(allocation_memento_found != NULL);
+    __ JumpIfJSArrayHasAllocationMemento(
+        receiver, scratch, allocation_memento_found);
   }
 
   // Set transitioned map.
-  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
-  __ RecordWriteField(edx,
+  __ mov(FieldOperand(receiver, HeapObject::kMapOffset), target_map);
+  __ RecordWriteField(receiver,
                       HeapObject::kMapOffset,
-                      ebx,
-                      edi,
+                      target_map,
+                      scratch,
                       kDontSaveFPRegs,
                       EMIT_REMEMBERED_SET,
                       OMIT_SMI_CHECK);
@@ -637,14 +551,19 @@ void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
 
 
 void ElementsTransitionGenerator::GenerateSmiToDouble(
-    MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
-  // ----------- S t a t e -------------
-  //  -- eax    : value
-  //  -- ebx    : target map
-  //  -- ecx    : key
-  //  -- edx    : receiver
-  //  -- esp[0] : return address
-  // -----------------------------------
+    MacroAssembler* masm,
+    Register receiver,
+    Register key,
+    Register value,
+    Register target_map,
+    AllocationSiteMode mode,
+    Label* fail) {
+  // Return address is on the stack.
+  DCHECK(receiver.is(edx));
+  DCHECK(key.is(ecx));
+  DCHECK(value.is(eax));
+  DCHECK(target_map.is(ebx));
+
   Label loop, entry, convert_hole, gc_required, only_change_map;
 
   if (mode == TRACK_ALLOCATION_SITE) {
@@ -694,11 +613,8 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   ExternalReference canonical_the_hole_nan_reference =
       ExternalReference::address_of_the_hole_nan();
   XMMRegister the_hole_nan = xmm1;
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope use_sse2(masm, SSE2);
-    __ movsd(the_hole_nan,
-              Operand::StaticVariable(canonical_the_hole_nan_reference));
-  }
+  __ movsd(the_hole_nan,
+           Operand::StaticVariable(canonical_the_hole_nan_reference));
   __ jmp(&entry);
 
   // Call into runtime if GC is required.
@@ -719,17 +635,9 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
 
   // Normal smi, convert it to double and store.
   __ SmiUntag(ebx);
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope fscope(masm, SSE2);
-    __ Cvtsi2sd(xmm0, ebx);
-    __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
-              xmm0);
-  } else {
-    __ push(ebx);
-    __ fild_s(Operand(esp, 0));
-    __ pop(ebx);
-    __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
-  }
+  __ Cvtsi2sd(xmm0, ebx);
+  __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
+           xmm0);
   __ jmp(&entry);
 
   // Found hole, store hole_nan_as_double instead.
@@ -740,14 +648,8 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
     __ Assert(equal, kObjectFoundInSmiOnlyArray);
   }
 
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope use_sse2(masm, SSE2);
-    __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
-              the_hole_nan);
-  } else {
-    __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
-    __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
-  }
+  __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
+           the_hole_nan);
 
   __ bind(&entry);
   __ sub(edi, Immediate(Smi::FromInt(1)));
@@ -775,14 +677,19 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
 
 
 void ElementsTransitionGenerator::GenerateDoubleToObject(
-    MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
-  // ----------- S t a t e -------------
-  //  -- eax    : value
-  //  -- ebx    : target map
-  //  -- ecx    : key
-  //  -- edx    : receiver
-  //  -- esp[0] : return address
-  // -----------------------------------
+    MacroAssembler* masm,
+    Register receiver,
+    Register key,
+    Register value,
+    Register target_map,
+    AllocationSiteMode mode,
+    Label* fail) {
+  // Return address is on the stack.
+  DCHECK(receiver.is(edx));
+  DCHECK(key.is(ecx));
+  DCHECK(value.is(eax));
+  DCHECK(target_map.is(ebx));
+
   Label loop, entry, convert_hole, gc_required, only_change_map, success;
 
   if (mode == TRACK_ALLOCATION_SITE) {
@@ -849,17 +756,9 @@ void ElementsTransitionGenerator::GenerateDoubleToObject(
   // Non-hole double, copy value into a heap number.
   __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
   // edx: new heap number
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope fscope(masm, SSE2);
-    __ movsd(xmm0,
-              FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
-    __ movsd(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
-  } else {
-    __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
-    __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
-    __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
-    __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
-  }
+  __ movsd(xmm0,
+           FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
+  __ movsd(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
   __ mov(esi, ebx);
   __ RecordWriteArray(eax,
@@ -971,7 +870,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
     __ Assert(zero, kExternalStringExpectedButNotFound);
   }
   // Rule out short external strings.
-  STATIC_CHECK(kShortExternalStringTag != 0);
+  STATIC_ASSERT(kShortExternalStringTag != 0);
   __ test_b(result, kShortExternalStringMask);
   __ j(not_zero, call_runtime);
   // Check encoding.
@@ -1025,11 +924,12 @@ void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
                                    XMMRegister double_scratch,
                                    Register temp1,
                                    Register temp2) {
-  ASSERT(!input.is(double_scratch));
-  ASSERT(!input.is(result));
-  ASSERT(!result.is(double_scratch));
-  ASSERT(!temp1.is(temp2));
-  ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
+  DCHECK(!input.is(double_scratch));
+  DCHECK(!input.is(result));
+  DCHECK(!result.is(double_scratch));
+  DCHECK(!temp1.is(temp2));
+  DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
+  DCHECK(!masm->serializer_enabled());  // External references not serializable.
 
   Label done;
 
@@ -1073,37 +973,33 @@ void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
 #undef __
 
 
-static byte* GetNoCodeAgeSequence(uint32_t* length) {
-  static bool initialized = false;
-  static byte sequence[kNoCodeAgeSequenceLength];
-  *length = kNoCodeAgeSequenceLength;
-  if (!initialized) {
-    // The sequence of instructions that is patched out for aging code is the
-    // following boilerplate stack-building prologue that is found both in
-    // FUNCTION and OPTIMIZED_FUNCTION code:
-    CodePatcher patcher(sequence, kNoCodeAgeSequenceLength);
-    patcher.masm()->push(ebp);
-    patcher.masm()->mov(ebp, esp);
-    patcher.masm()->push(esi);
-    patcher.masm()->push(edi);
-    initialized = true;
-  }
-  return sequence;
+CodeAgingHelper::CodeAgingHelper() {
+  DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength);
+  CodePatcher patcher(young_sequence_.start(), young_sequence_.length());
+  patcher.masm()->push(ebp);
+  patcher.masm()->mov(ebp, esp);
+  patcher.masm()->push(esi);
+  patcher.masm()->push(edi);
+}
+
+
+#ifdef DEBUG
+bool CodeAgingHelper::IsOld(byte* candidate) const {
+  return *candidate == kCallOpcode;
 }
+#endif
 
 
-bool Code::IsYoungSequence(byte* sequence) {
-  uint32_t young_length;
-  byte* young_sequence = GetNoCodeAgeSequence(&young_length);
-  bool result = (!memcmp(sequence, young_sequence, young_length));
-  ASSERT(result || *sequence == kCallOpcode);
+bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
+  bool result = isolate->code_aging_helper()->IsYoung(sequence);
+  DCHECK(result || isolate->code_aging_helper()->IsOld(sequence));
   return result;
 }
 
 
-void Code::GetCodeAgeAndParity(byte* sequence, Age* age,
+void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
                                MarkingParity* parity) {
-  if (IsYoungSequence(sequence)) {
+  if (IsYoungSequence(isolate, sequence)) {
     *age = kNoAgeCodeAge;
     *parity = NO_MARKING_PARITY;
   } else {
@@ -1120,11 +1016,10 @@ void Code::PatchPlatformCodeAge(Isolate* isolate,
                                 byte* sequence,
                                 Code::Age age,
                                 MarkingParity parity) {
-  uint32_t young_length;
-  byte* young_sequence = GetNoCodeAgeSequence(&young_length);
+  uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
   if (age == kNoAgeCodeAge) {
-    CopyBytes(sequence, young_sequence, young_length);
-    CPU::FlushICache(sequence, young_length);
+    isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
+    CpuFeatures::FlushICache(sequence, young_length);
   } else {
     Code* stub = GetCodeAgeStub(isolate, age, parity);
     CodePatcher patcher(sequence, young_length);