Home | History | Annotate | Download | only in ia32
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #if V8_TARGET_ARCH_IA32
     31 
     32 #include "codegen.h"
     33 #include "heap.h"
     34 #include "macro-assembler.h"
     35 
     36 namespace v8 {
     37 namespace internal {
     38 
     39 
     40 // -------------------------------------------------------------------------
     41 // Platform-specific RuntimeCallHelper functions.
     42 
     43 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
     44   masm->EnterFrame(StackFrame::INTERNAL);
     45   ASSERT(!masm->has_frame());
     46   masm->set_has_frame(true);
     47 }
     48 
     49 
     50 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
     51   masm->LeaveFrame(StackFrame::INTERNAL);
     52   ASSERT(masm->has_frame());
     53   masm->set_has_frame(false);
     54 }
     55 
     56 
     57 #define __ masm.
     58 
     59 
     60 UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) {
     61   size_t actual_size;
     62   // Allocate buffer in executable space.
     63   byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
     64                                                  &actual_size,
     65                                                  true));
     66   if (buffer == NULL) {
     67     // Fallback to library function if function cannot be created.
     68     switch (type) {
     69       case TranscendentalCache::SIN: return &sin;
     70       case TranscendentalCache::COS: return &cos;
     71       case TranscendentalCache::TAN: return &tan;
     72       case TranscendentalCache::LOG: return &log;
     73       default: UNIMPLEMENTED();
     74     }
     75   }
     76 
     77   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
     78   // esp[1 * kPointerSize]: raw double input
     79   // esp[0 * kPointerSize]: return address
     80   // Move double input into registers.
     81 
     82   __ push(ebx);
     83   __ push(edx);
     84   __ push(edi);
     85   __ fld_d(Operand(esp, 4 * kPointerSize));
     86   __ mov(ebx, Operand(esp, 4 * kPointerSize));
     87   __ mov(edx, Operand(esp, 5 * kPointerSize));
     88   TranscendentalCacheStub::GenerateOperation(&masm, type);
     89   // The return value is expected to be on ST(0) of the FPU stack.
     90   __ pop(edi);
     91   __ pop(edx);
     92   __ pop(ebx);
     93   __ Ret();
     94 
     95   CodeDesc desc;
     96   masm.GetCode(&desc);
     97   ASSERT(!RelocInfo::RequiresRelocation(desc));
     98 
     99   CPU::FlushICache(buffer, actual_size);
    100   OS::ProtectCode(buffer, actual_size);
    101   return FUNCTION_CAST<UnaryMathFunction>(buffer);
    102 }
    103 
    104 
    105 UnaryMathFunction CreateExpFunction() {
    106   if (!CpuFeatures::IsSupported(SSE2)) return &exp;
    107   if (!FLAG_fast_math) return &exp;
    108   size_t actual_size;
    109   byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
    110   if (buffer == NULL) return &exp;
    111   ExternalReference::InitializeMathExpData();
    112 
    113   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
    114   // esp[1 * kPointerSize]: raw double input
    115   // esp[0 * kPointerSize]: return address
    116   {
    117     CpuFeatureScope use_sse2(&masm, SSE2);
    118     XMMRegister input = xmm1;
    119     XMMRegister result = xmm2;
    120     __ movdbl(input, Operand(esp, 1 * kPointerSize));
    121     __ push(eax);
    122     __ push(ebx);
    123 
    124     MathExpGenerator::EmitMathExp(&masm, input, result, xmm0, eax, ebx);
    125 
    126     __ pop(ebx);
    127     __ pop(eax);
    128     __ movdbl(Operand(esp, 1 * kPointerSize), result);
    129     __ fld_d(Operand(esp, 1 * kPointerSize));
    130     __ Ret();
    131   }
    132 
    133   CodeDesc desc;
    134   masm.GetCode(&desc);
    135   ASSERT(!RelocInfo::RequiresRelocation(desc));
    136 
    137   CPU::FlushICache(buffer, actual_size);
    138   OS::ProtectCode(buffer, actual_size);
    139   return FUNCTION_CAST<UnaryMathFunction>(buffer);
    140 }
    141 
    142 
    143 UnaryMathFunction CreateSqrtFunction() {
    144   size_t actual_size;
    145   // Allocate buffer in executable space.
    146   byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
    147                                                  &actual_size,
    148                                                  true));
    149   // If SSE2 is not available, we can use libc's implementation to ensure
    150   // consistency since code by fullcodegen's calls into runtime in that case.
    151   if (buffer == NULL || !CpuFeatures::IsSupported(SSE2)) return &sqrt;
    152   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
    153   // esp[1 * kPointerSize]: raw double input
    154   // esp[0 * kPointerSize]: return address
    155   // Move double input into registers.
    156   {
    157     CpuFeatureScope use_sse2(&masm, SSE2);
    158     __ movdbl(xmm0, Operand(esp, 1 * kPointerSize));
    159     __ sqrtsd(xmm0, xmm0);
    160     __ movdbl(Operand(esp, 1 * kPointerSize), xmm0);
    161     // Load result into floating point register as return value.
    162     __ fld_d(Operand(esp, 1 * kPointerSize));
    163     __ Ret();
    164   }
    165 
    166   CodeDesc desc;
    167   masm.GetCode(&desc);
    168   ASSERT(!RelocInfo::RequiresRelocation(desc));
    169 
    170   CPU::FlushICache(buffer, actual_size);
    171   OS::ProtectCode(buffer, actual_size);
    172   return FUNCTION_CAST<UnaryMathFunction>(buffer);
    173 }
    174 
    175 
    176 // Helper functions for CreateMemMoveFunction.
    177 #undef __
    178 #define __ ACCESS_MASM(masm)
    179 
    180 // Keep around global pointers to these objects so that Valgrind won't complain.
    181 static size_t* medium_handlers = NULL;
    182 static size_t* small_handlers = NULL;
    183 
    184 
    185 enum Direction { FORWARD, BACKWARD };
    186 enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
    187 
    188 // Expects registers:
    189 // esi - source, aligned if alignment == ALIGNED
    190 // edi - destination, always aligned
    191 // ecx - count (copy size in bytes)
    192 // edx - loop count (number of 64 byte chunks)
    193 void MemMoveEmitMainLoop(MacroAssembler* masm,
    194                          Label* move_last_15,
    195                          Direction direction,
    196                          Alignment alignment) {
    197   Register src = esi;
    198   Register dst = edi;
    199   Register count = ecx;
    200   Register loop_count = edx;
    201   Label loop, move_last_31, move_last_63;
    202   __ cmp(loop_count, 0);
    203   __ j(equal, &move_last_63);
    204   __ bind(&loop);
    205   // Main loop. Copy in 64 byte chunks.
    206   if (direction == BACKWARD) __ sub(src, Immediate(0x40));
    207   __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
    208   __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
    209   __ movdq(alignment == MOVE_ALIGNED, xmm2, Operand(src, 0x20));
    210   __ movdq(alignment == MOVE_ALIGNED, xmm3, Operand(src, 0x30));
    211   if (direction == FORWARD) __ add(src, Immediate(0x40));
    212   if (direction == BACKWARD) __ sub(dst, Immediate(0x40));
    213   __ movdqa(Operand(dst, 0x00), xmm0);
    214   __ movdqa(Operand(dst, 0x10), xmm1);
    215   __ movdqa(Operand(dst, 0x20), xmm2);
    216   __ movdqa(Operand(dst, 0x30), xmm3);
    217   if (direction == FORWARD) __ add(dst, Immediate(0x40));
    218   __ dec(loop_count);
    219   __ j(not_zero, &loop);
    220   // At most 63 bytes left to copy.
    221   __ bind(&move_last_63);
    222   __ test(count, Immediate(0x20));
    223   __ j(zero, &move_last_31);
    224   if (direction == BACKWARD) __ sub(src, Immediate(0x20));
    225   __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
    226   __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
    227   if (direction == FORWARD) __ add(src, Immediate(0x20));
    228   if (direction == BACKWARD) __ sub(dst, Immediate(0x20));
    229   __ movdqa(Operand(dst, 0x00), xmm0);
    230   __ movdqa(Operand(dst, 0x10), xmm1);
    231   if (direction == FORWARD) __ add(dst, Immediate(0x20));
    232   // At most 31 bytes left to copy.
    233   __ bind(&move_last_31);
    234   __ test(count, Immediate(0x10));
    235   __ j(zero, move_last_15);
    236   if (direction == BACKWARD) __ sub(src, Immediate(0x10));
    237   __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0));
    238   if (direction == FORWARD) __ add(src, Immediate(0x10));
    239   if (direction == BACKWARD) __ sub(dst, Immediate(0x10));
    240   __ movdqa(Operand(dst, 0), xmm0);
    241   if (direction == FORWARD) __ add(dst, Immediate(0x10));
    242 }
    243 
    244 
    245 void MemMoveEmitPopAndReturn(MacroAssembler* masm) {
    246   __ pop(esi);
    247   __ pop(edi);
    248   __ ret(0);
    249 }
    250 
    251 
    252 #undef __
    253 #define __ masm.
    254 
    255 
    256 OS::MemMoveFunction CreateMemMoveFunction() {
    257   size_t actual_size;
    258   // Allocate buffer in executable space.
    259   byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
    260   if (buffer == NULL) return NULL;
    261   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
    262 
    263   // Generated code is put into a fixed, unmovable buffer, and not into
    264   // the V8 heap. We can't, and don't, refer to any relocatable addresses
    265   // (e.g. the JavaScript nan-object).
    266 
    267   // 32-bit C declaration function calls pass arguments on stack.
    268 
    269   // Stack layout:
    270   // esp[12]: Third argument, size.
    271   // esp[8]: Second argument, source pointer.
    272   // esp[4]: First argument, destination pointer.
    273   // esp[0]: return address
    274 
    275   const int kDestinationOffset = 1 * kPointerSize;
    276   const int kSourceOffset = 2 * kPointerSize;
    277   const int kSizeOffset = 3 * kPointerSize;
    278 
    279   // When copying up to this many bytes, use special "small" handlers.
    280   const size_t kSmallCopySize = 8;
    281   // When copying up to this many bytes, use special "medium" handlers.
    282   const size_t kMediumCopySize = 63;
    283   // When non-overlapping region of src and dst is less than this,
    284   // use a more careful implementation (slightly slower).
    285   const size_t kMinMoveDistance = 16;
    286   // Note that these values are dictated by the implementation below,
    287   // do not just change them and hope things will work!
    288 
    289   int stack_offset = 0;  // Update if we change the stack height.
    290 
    291   Label backward, backward_much_overlap;
    292   Label forward_much_overlap, small_size, medium_size, pop_and_return;
    293   __ push(edi);
    294   __ push(esi);
    295   stack_offset += 2 * kPointerSize;
    296   Register dst = edi;
    297   Register src = esi;
    298   Register count = ecx;
    299   Register loop_count = edx;
    300   __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
    301   __ mov(src, Operand(esp, stack_offset + kSourceOffset));
    302   __ mov(count, Operand(esp, stack_offset + kSizeOffset));
    303 
    304   __ cmp(dst, src);
    305   __ j(equal, &pop_and_return);
    306 
    307   if (CpuFeatures::IsSupported(SSE2)) {
    308     CpuFeatureScope sse2_scope(&masm, SSE2);
    309     __ prefetch(Operand(src, 0), 1);
    310     __ cmp(count, kSmallCopySize);
    311     __ j(below_equal, &small_size);
    312     __ cmp(count, kMediumCopySize);
    313     __ j(below_equal, &medium_size);
    314     __ cmp(dst, src);
    315     __ j(above, &backward);
    316 
    317     {
    318       // |dst| is a lower address than |src|. Copy front-to-back.
    319       Label unaligned_source, move_last_15, skip_last_move;
    320       __ mov(eax, src);
    321       __ sub(eax, dst);
    322       __ cmp(eax, kMinMoveDistance);
    323       __ j(below, &forward_much_overlap);
    324       // Copy first 16 bytes.
    325       __ movdqu(xmm0, Operand(src, 0));
    326       __ movdqu(Operand(dst, 0), xmm0);
    327       // Determine distance to alignment: 16 - (dst & 0xF).
    328       __ mov(edx, dst);
    329       __ and_(edx, 0xF);
    330       __ neg(edx);
    331       __ add(edx, Immediate(16));
    332       __ add(dst, edx);
    333       __ add(src, edx);
    334       __ sub(count, edx);
    335       // dst is now aligned. Main copy loop.
    336       __ mov(loop_count, count);
    337       __ shr(loop_count, 6);
    338       // Check if src is also aligned.
    339       __ test(src, Immediate(0xF));
    340       __ j(not_zero, &unaligned_source);
    341       // Copy loop for aligned source and destination.
    342       MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
    343       // At most 15 bytes to copy. Copy 16 bytes at end of string.
    344       __ bind(&move_last_15);
    345       __ and_(count, 0xF);
    346       __ j(zero, &skip_last_move, Label::kNear);
    347       __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
    348       __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
    349       __ bind(&skip_last_move);
    350       MemMoveEmitPopAndReturn(&masm);
    351 
    352       // Copy loop for unaligned source and aligned destination.
    353       __ bind(&unaligned_source);
    354       MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
    355       __ jmp(&move_last_15);
    356 
    357       // Less than kMinMoveDistance offset between dst and src.
    358       Label loop_until_aligned, last_15_much_overlap;
    359       __ bind(&loop_until_aligned);
    360       __ mov_b(eax, Operand(src, 0));
    361       __ inc(src);
    362       __ mov_b(Operand(dst, 0), eax);
    363       __ inc(dst);
    364       __ dec(count);
    365       __ bind(&forward_much_overlap);  // Entry point into this block.
    366       __ test(dst, Immediate(0xF));
    367       __ j(not_zero, &loop_until_aligned);
    368       // dst is now aligned, src can't be. Main copy loop.
    369       __ mov(loop_count, count);
    370       __ shr(loop_count, 6);
    371       MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
    372                           FORWARD, MOVE_UNALIGNED);
    373       __ bind(&last_15_much_overlap);
    374       __ and_(count, 0xF);
    375       __ j(zero, &pop_and_return);
    376       __ cmp(count, kSmallCopySize);
    377       __ j(below_equal, &small_size);
    378       __ jmp(&medium_size);
    379     }
    380 
    381     {
    382       // |dst| is a higher address than |src|. Copy backwards.
    383       Label unaligned_source, move_first_15, skip_last_move;
    384       __ bind(&backward);
    385       // |dst| and |src| always point to the end of what's left to copy.
    386       __ add(dst, count);
    387       __ add(src, count);
    388       __ mov(eax, dst);
    389       __ sub(eax, src);
    390       __ cmp(eax, kMinMoveDistance);
    391       __ j(below, &backward_much_overlap);
    392       // Copy last 16 bytes.
    393       __ movdqu(xmm0, Operand(src, -0x10));
    394       __ movdqu(Operand(dst, -0x10), xmm0);
    395       // Find distance to alignment: dst & 0xF
    396       __ mov(edx, dst);
    397       __ and_(edx, 0xF);
    398       __ sub(dst, edx);
    399       __ sub(src, edx);
    400       __ sub(count, edx);
    401       // dst is now aligned. Main copy loop.
    402       __ mov(loop_count, count);
    403       __ shr(loop_count, 6);
    404       // Check if src is also aligned.
    405       __ test(src, Immediate(0xF));
    406       __ j(not_zero, &unaligned_source);
    407       // Copy loop for aligned source and destination.
    408       MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
    409       // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
    410       __ bind(&move_first_15);
    411       __ and_(count, 0xF);
    412       __ j(zero, &skip_last_move, Label::kNear);
    413       __ sub(src, count);
    414       __ sub(dst, count);
    415       __ movdqu(xmm0, Operand(src, 0));
    416       __ movdqu(Operand(dst, 0), xmm0);
    417       __ bind(&skip_last_move);
    418       MemMoveEmitPopAndReturn(&masm);
    419 
    420       // Copy loop for unaligned source and aligned destination.
    421       __ bind(&unaligned_source);
    422       MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED);
    423       __ jmp(&move_first_15);
    424 
    425       // Less than kMinMoveDistance offset between dst and src.
    426       Label loop_until_aligned, first_15_much_overlap;
    427       __ bind(&loop_until_aligned);
    428       __ dec(src);
    429       __ dec(dst);
    430       __ mov_b(eax, Operand(src, 0));
    431       __ mov_b(Operand(dst, 0), eax);
    432       __ dec(count);
    433       __ bind(&backward_much_overlap);  // Entry point into this block.
    434       __ test(dst, Immediate(0xF));
    435       __ j(not_zero, &loop_until_aligned);
    436       // dst is now aligned, src can't be. Main copy loop.
    437       __ mov(loop_count, count);
    438       __ shr(loop_count, 6);
    439       MemMoveEmitMainLoop(&masm, &first_15_much_overlap,
    440                           BACKWARD, MOVE_UNALIGNED);
    441       __ bind(&first_15_much_overlap);
    442       __ and_(count, 0xF);
    443       __ j(zero, &pop_and_return);
    444       // Small/medium handlers expect dst/src to point to the beginning.
    445       __ sub(dst, count);
    446       __ sub(src, count);
    447       __ cmp(count, kSmallCopySize);
    448       __ j(below_equal, &small_size);
    449       __ jmp(&medium_size);
    450     }
    451     {
    452       // Special handlers for 9 <= copy_size < 64. No assumptions about
    453       // alignment or move distance, so all reads must be unaligned and
    454       // must happen before any writes.
    455       Label f9_16, f17_32, f33_48, f49_63;
    456 
    457       __ bind(&f9_16);
    458       __ movdbl(xmm0, Operand(src, 0));
    459       __ movdbl(xmm1, Operand(src, count, times_1, -8));
    460       __ movdbl(Operand(dst, 0), xmm0);
    461       __ movdbl(Operand(dst, count, times_1, -8), xmm1);
    462       MemMoveEmitPopAndReturn(&masm);
    463 
    464       __ bind(&f17_32);
    465       __ movdqu(xmm0, Operand(src, 0));
    466       __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
    467       __ movdqu(Operand(dst, 0x00), xmm0);
    468       __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
    469       MemMoveEmitPopAndReturn(&masm);
    470 
    471       __ bind(&f33_48);
    472       __ movdqu(xmm0, Operand(src, 0x00));
    473       __ movdqu(xmm1, Operand(src, 0x10));
    474       __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
    475       __ movdqu(Operand(dst, 0x00), xmm0);
    476       __ movdqu(Operand(dst, 0x10), xmm1);
    477       __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
    478       MemMoveEmitPopAndReturn(&masm);
    479 
    480       __ bind(&f49_63);
    481       __ movdqu(xmm0, Operand(src, 0x00));
    482       __ movdqu(xmm1, Operand(src, 0x10));
    483       __ movdqu(xmm2, Operand(src, 0x20));
    484       __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
    485       __ movdqu(Operand(dst, 0x00), xmm0);
    486       __ movdqu(Operand(dst, 0x10), xmm1);
    487       __ movdqu(Operand(dst, 0x20), xmm2);
    488       __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
    489       MemMoveEmitPopAndReturn(&masm);
    490 
    491       medium_handlers = new size_t[4];
    492       medium_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f9_16.pos();
    493       medium_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f17_32.pos();
    494       medium_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f33_48.pos();
    495       medium_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f49_63.pos();
    496 
    497       __ bind(&medium_size);  // Entry point into this block.
    498       __ mov(eax, count);
    499       __ dec(eax);
    500       __ shr(eax, 4);
    501       if (FLAG_debug_code) {
    502         Label ok;
    503         __ cmp(eax, 3);
    504         __ j(below_equal, &ok);
    505         __ int3();
    506         __ bind(&ok);
    507       }
    508       __ mov(eax, Operand(eax, times_4,
    509                           reinterpret_cast<intptr_t>(medium_handlers)));
    510       __ jmp(eax);
    511     }
    512     {
    513       // Specialized copiers for copy_size <= 8 bytes.
    514       Label f0, f1, f2, f3, f4, f5_8;
    515       __ bind(&f0);
    516       MemMoveEmitPopAndReturn(&masm);
    517 
    518       __ bind(&f1);
    519       __ mov_b(eax, Operand(src, 0));
    520       __ mov_b(Operand(dst, 0), eax);
    521       MemMoveEmitPopAndReturn(&masm);
    522 
    523       __ bind(&f2);
    524       __ mov_w(eax, Operand(src, 0));
    525       __ mov_w(Operand(dst, 0), eax);
    526       MemMoveEmitPopAndReturn(&masm);
    527 
    528       __ bind(&f3);
    529       __ mov_w(eax, Operand(src, 0));
    530       __ mov_b(edx, Operand(src, 2));
    531       __ mov_w(Operand(dst, 0), eax);
    532       __ mov_b(Operand(dst, 2), edx);
    533       MemMoveEmitPopAndReturn(&masm);
    534 
    535       __ bind(&f4);
    536       __ mov(eax, Operand(src, 0));
    537       __ mov(Operand(dst, 0), eax);
    538       MemMoveEmitPopAndReturn(&masm);
    539 
    540       __ bind(&f5_8);
    541       __ mov(eax, Operand(src, 0));
    542       __ mov(edx, Operand(src, count, times_1, -4));
    543       __ mov(Operand(dst, 0), eax);
    544       __ mov(Operand(dst, count, times_1, -4), edx);
    545       MemMoveEmitPopAndReturn(&masm);
    546 
    547       small_handlers = new size_t[9];
    548       small_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f0.pos();
    549       small_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f1.pos();
    550       small_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f2.pos();
    551       small_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f3.pos();
    552       small_handlers[4] = reinterpret_cast<intptr_t>(buffer) + f4.pos();
    553       small_handlers[5] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
    554       small_handlers[6] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
    555       small_handlers[7] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
    556       small_handlers[8] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos();
    557 
    558       __ bind(&small_size);  // Entry point into this block.
    559       if (FLAG_debug_code) {
    560         Label ok;
    561         __ cmp(count, 8);
    562         __ j(below_equal, &ok);
    563         __ int3();
    564         __ bind(&ok);
    565       }
    566       __ mov(eax, Operand(count, times_4,
    567                           reinterpret_cast<intptr_t>(small_handlers)));
    568       __ jmp(eax);
    569     }
    570   } else {
    571     // No SSE2.
    572     Label forward;
    573     __ cmp(count, 0);
    574     __ j(equal, &pop_and_return);
    575     __ cmp(dst, src);
    576     __ j(above, &backward);
    577     __ jmp(&forward);
    578     {
    579       // Simple forward copier.
    580       Label forward_loop_1byte, forward_loop_4byte;
    581       __ bind(&forward_loop_4byte);
    582       __ mov(eax, Operand(src, 0));
    583       __ sub(count, Immediate(4));
    584       __ add(src, Immediate(4));
    585       __ mov(Operand(dst, 0), eax);
    586       __ add(dst, Immediate(4));
    587       __ bind(&forward);  // Entry point.
    588       __ cmp(count, 3);
    589       __ j(above, &forward_loop_4byte);
    590       __ bind(&forward_loop_1byte);
    591       __ cmp(count, 0);
    592       __ j(below_equal, &pop_and_return);
    593       __ mov_b(eax, Operand(src, 0));
    594       __ dec(count);
    595       __ inc(src);
    596       __ mov_b(Operand(dst, 0), eax);
    597       __ inc(dst);
    598       __ jmp(&forward_loop_1byte);
    599     }
    600     {
    601       // Simple backward copier.
    602       Label backward_loop_1byte, backward_loop_4byte, entry_shortcut;
    603       __ bind(&backward);
    604       __ add(src, count);
    605       __ add(dst, count);
    606       __ cmp(count, 3);
    607       __ j(below_equal, &entry_shortcut);
    608 
    609       __ bind(&backward_loop_4byte);
    610       __ sub(src, Immediate(4));
    611       __ sub(count, Immediate(4));
    612       __ mov(eax, Operand(src, 0));
    613       __ sub(dst, Immediate(4));
    614       __ mov(Operand(dst, 0), eax);
    615       __ cmp(count, 3);
    616       __ j(above, &backward_loop_4byte);
    617       __ bind(&backward_loop_1byte);
    618       __ cmp(count, 0);
    619       __ j(below_equal, &pop_and_return);
    620       __ bind(&entry_shortcut);
    621       __ dec(src);
    622       __ dec(count);
    623       __ mov_b(eax, Operand(src, 0));
    624       __ dec(dst);
    625       __ mov_b(Operand(dst, 0), eax);
    626       __ jmp(&backward_loop_1byte);
    627     }
    628   }
    629 
    630   __ bind(&pop_and_return);
    631   MemMoveEmitPopAndReturn(&masm);
    632 
    633   CodeDesc desc;
    634   masm.GetCode(&desc);
    635   ASSERT(!RelocInfo::RequiresRelocation(desc));
    636   CPU::FlushICache(buffer, actual_size);
    637   OS::ProtectCode(buffer, actual_size);
    638   // TODO(jkummerow): It would be nice to register this code creation event
    639   // with the PROFILE / GDBJIT system.
    640   return FUNCTION_CAST<OS::MemMoveFunction>(buffer);
    641 }
    642 
    643 
    644 #undef __
    645 
    646 // -------------------------------------------------------------------------
    647 // Code generators
    648 
    649 #define __ ACCESS_MASM(masm)
    650 
    651 
    652 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
    653     MacroAssembler* masm, AllocationSiteMode mode,
    654     Label* allocation_memento_found) {
    655   // ----------- S t a t e -------------
    656   //  -- eax    : value
    657   //  -- ebx    : target map
    658   //  -- ecx    : key
    659   //  -- edx    : receiver
    660   //  -- esp[0] : return address
    661   // -----------------------------------
    662   if (mode == TRACK_ALLOCATION_SITE) {
    663     ASSERT(allocation_memento_found != NULL);
    664     __ TestJSArrayForAllocationMemento(edx, edi);
    665     __ j(equal, allocation_memento_found);
    666   }
    667 
    668   // Set transitioned map.
    669   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
    670   __ RecordWriteField(edx,
    671                       HeapObject::kMapOffset,
    672                       ebx,
    673                       edi,
    674                       kDontSaveFPRegs,
    675                       EMIT_REMEMBERED_SET,
    676                       OMIT_SMI_CHECK);
    677 }
    678 
    679 
    680 void ElementsTransitionGenerator::GenerateSmiToDouble(
    681     MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
    682   // ----------- S t a t e -------------
    683   //  -- eax    : value
    684   //  -- ebx    : target map
    685   //  -- ecx    : key
    686   //  -- edx    : receiver
    687   //  -- esp[0] : return address
    688   // -----------------------------------
    689   Label loop, entry, convert_hole, gc_required, only_change_map;
    690 
    691   if (mode == TRACK_ALLOCATION_SITE) {
    692     __ TestJSArrayForAllocationMemento(edx, edi);
    693     __ j(equal, fail);
    694   }
    695 
    696   // Check for empty arrays, which only require a map transition and no changes
    697   // to the backing store.
    698   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
    699   __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
    700   __ j(equal, &only_change_map);
    701 
    702   __ push(eax);
    703   __ push(ebx);
    704 
    705   __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
    706 
    707   // Allocate new FixedDoubleArray.
    708   // edx: receiver
    709   // edi: length of source FixedArray (smi-tagged)
    710   AllocationFlags flags =
    711       static_cast<AllocationFlags>(TAG_OBJECT | DOUBLE_ALIGNMENT);
    712   __ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi,
    713               REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags);
    714 
    715   // eax: destination FixedDoubleArray
    716   // edi: number of elements
    717   // edx: receiver
    718   __ mov(FieldOperand(eax, HeapObject::kMapOffset),
    719          Immediate(masm->isolate()->factory()->fixed_double_array_map()));
    720   __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
    721   __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
    722   // Replace receiver's backing store with newly created FixedDoubleArray.
    723   __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
    724   __ mov(ebx, eax);
    725   __ RecordWriteField(edx,
    726                       JSObject::kElementsOffset,
    727                       ebx,
    728                       edi,
    729                       kDontSaveFPRegs,
    730                       EMIT_REMEMBERED_SET,
    731                       OMIT_SMI_CHECK);
    732 
    733   __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
    734 
    735   // Prepare for conversion loop.
    736   ExternalReference canonical_the_hole_nan_reference =
    737       ExternalReference::address_of_the_hole_nan();
    738   XMMRegister the_hole_nan = xmm1;
    739   if (CpuFeatures::IsSupported(SSE2)) {
    740     CpuFeatureScope use_sse2(masm, SSE2);
    741     __ movdbl(the_hole_nan,
    742               Operand::StaticVariable(canonical_the_hole_nan_reference));
    743   }
    744   __ jmp(&entry);
    745 
    746   // Call into runtime if GC is required.
    747   __ bind(&gc_required);
    748   // Restore registers before jumping into runtime.
    749   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
    750   __ pop(ebx);
    751   __ pop(eax);
    752   __ jmp(fail);
    753 
    754   // Convert and copy elements
    755   // esi: source FixedArray
    756   __ bind(&loop);
    757   __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
    758   // ebx: current element from source
    759   // edi: index of current element
    760   __ JumpIfNotSmi(ebx, &convert_hole);
    761 
    762   // Normal smi, convert it to double and store.
    763   __ SmiUntag(ebx);
    764   if (CpuFeatures::IsSupported(SSE2)) {
    765     CpuFeatureScope fscope(masm, SSE2);
    766     __ cvtsi2sd(xmm0, ebx);
    767     __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
    768               xmm0);
    769   } else {
    770     __ push(ebx);
    771     __ fild_s(Operand(esp, 0));
    772     __ pop(ebx);
    773     __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
    774   }
    775   __ jmp(&entry);
    776 
    777   // Found hole, store hole_nan_as_double instead.
    778   __ bind(&convert_hole);
    779 
    780   if (FLAG_debug_code) {
    781     __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
    782     __ Assert(equal, kObjectFoundInSmiOnlyArray);
    783   }
    784 
    785   if (CpuFeatures::IsSupported(SSE2)) {
    786     CpuFeatureScope use_sse2(masm, SSE2);
    787     __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
    788               the_hole_nan);
    789   } else {
    790     __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
    791     __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
    792   }
    793 
    794   __ bind(&entry);
    795   __ sub(edi, Immediate(Smi::FromInt(1)));
    796   __ j(not_sign, &loop);
    797 
    798   __ pop(ebx);
    799   __ pop(eax);
    800 
    801   // Restore esi.
    802   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
    803 
    804   __ bind(&only_change_map);
    805   // eax: value
    806   // ebx: target map
    807   // Set transitioned map.
    808   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
    809   __ RecordWriteField(edx,
    810                       HeapObject::kMapOffset,
    811                       ebx,
    812                       edi,
    813                       kDontSaveFPRegs,
    814                       OMIT_REMEMBERED_SET,
    815                       OMIT_SMI_CHECK);
    816 }
    817 
    818 
    819 void ElementsTransitionGenerator::GenerateDoubleToObject(
    820     MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
    821   // ----------- S t a t e -------------
    822   //  -- eax    : value
    823   //  -- ebx    : target map
    824   //  -- ecx    : key
    825   //  -- edx    : receiver
    826   //  -- esp[0] : return address
    827   // -----------------------------------
    828   Label loop, entry, convert_hole, gc_required, only_change_map, success;
    829 
    830   if (mode == TRACK_ALLOCATION_SITE) {
    831     __ TestJSArrayForAllocationMemento(edx, edi);
    832     __ j(equal, fail);
    833   }
    834 
    835   // Check for empty arrays, which only require a map transition and no changes
    836   // to the backing store.
    837   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
    838   __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
    839   __ j(equal, &only_change_map);
    840 
    841   __ push(eax);
    842   __ push(edx);
    843   __ push(ebx);
    844 
    845   __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
    846 
    847   // Allocate new FixedArray.
    848   // ebx: length of source FixedDoubleArray (smi-tagged)
    849   __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
    850   __ Allocate(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
    851 
    852   // eax: destination FixedArray
    853   // ebx: number of elements
    854   __ mov(FieldOperand(eax, HeapObject::kMapOffset),
    855          Immediate(masm->isolate()->factory()->fixed_array_map()));
    856   __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
    857   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
    858 
    859   __ jmp(&entry);
    860 
    861   // ebx: target map
    862   // edx: receiver
    863   // Set transitioned map.
    864   __ bind(&only_change_map);
    865   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
    866   __ RecordWriteField(edx,
    867                       HeapObject::kMapOffset,
    868                       ebx,
    869                       edi,
    870                       kDontSaveFPRegs,
    871                       OMIT_REMEMBERED_SET,
    872                       OMIT_SMI_CHECK);
    873   __ jmp(&success);
    874 
    875   // Call into runtime if GC is required.
    876   __ bind(&gc_required);
    877   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
    878   __ pop(ebx);
    879   __ pop(edx);
    880   __ pop(eax);
    881   __ jmp(fail);
    882 
    883   // Box doubles into heap numbers.
    884   // edi: source FixedDoubleArray
    885   // eax: destination FixedArray
    886   __ bind(&loop);
    887   // ebx: index of current element (smi-tagged)
    888   uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
    889   __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
    890   __ j(equal, &convert_hole);
    891 
    892   // Non-hole double, copy value into a heap number.
    893   __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
    894   // edx: new heap number
    895   if (CpuFeatures::IsSupported(SSE2)) {
    896     CpuFeatureScope fscope(masm, SSE2);
    897     __ movdbl(xmm0,
    898               FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
    899     __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
    900   } else {
    901     __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
    902     __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
    903     __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
    904     __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
    905   }
    906   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
    907   __ mov(esi, ebx);
    908   __ RecordWriteArray(eax,
    909                       edx,
    910                       esi,
    911                       kDontSaveFPRegs,
    912                       EMIT_REMEMBERED_SET,
    913                       OMIT_SMI_CHECK);
    914   __ jmp(&entry, Label::kNear);
    915 
    916   // Replace the-hole NaN with the-hole pointer.
    917   __ bind(&convert_hole);
    918   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
    919          masm->isolate()->factory()->the_hole_value());
    920 
    921   __ bind(&entry);
    922   __ sub(ebx, Immediate(Smi::FromInt(1)));
    923   __ j(not_sign, &loop);
    924 
    925   __ pop(ebx);
    926   __ pop(edx);
    927   // ebx: target map
    928   // edx: receiver
    929   // Set transitioned map.
    930   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
    931   __ RecordWriteField(edx,
    932                       HeapObject::kMapOffset,
    933                       ebx,
    934                       edi,
    935                       kDontSaveFPRegs,
    936                       OMIT_REMEMBERED_SET,
    937                       OMIT_SMI_CHECK);
    938   // Replace receiver's backing store with newly created and filled FixedArray.
    939   __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
    940   __ RecordWriteField(edx,
    941                       JSObject::kElementsOffset,
    942                       eax,
    943                       edi,
    944                       kDontSaveFPRegs,
    945                       EMIT_REMEMBERED_SET,
    946                       OMIT_SMI_CHECK);
    947 
    948   // Restore registers.
    949   __ pop(eax);
    950   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
    951 
    952   __ bind(&success);
    953 }
    954 
    955 
    956 void StringCharLoadGenerator::Generate(MacroAssembler* masm,
    957                                        Factory* factory,
    958                                        Register string,
    959                                        Register index,
    960                                        Register result,
    961                                        Label* call_runtime) {
    962   // Fetch the instance type of the receiver into result register.
    963   __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
    964   __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
    965 
    966   // We need special handling for indirect strings.
    967   Label check_sequential;
    968   __ test(result, Immediate(kIsIndirectStringMask));
    969   __ j(zero, &check_sequential, Label::kNear);
    970 
    971   // Dispatch on the indirect string shape: slice or cons.
    972   Label cons_string;
    973   __ test(result, Immediate(kSlicedNotConsMask));
    974   __ j(zero, &cons_string, Label::kNear);
    975 
    976   // Handle slices.
    977   Label indirect_string_loaded;
    978   __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset));
    979   __ SmiUntag(result);
    980   __ add(index, result);
    981   __ mov(string, FieldOperand(string, SlicedString::kParentOffset));
    982   __ jmp(&indirect_string_loaded, Label::kNear);
    983 
    984   // Handle cons strings.
    985   // Check whether the right hand side is the empty string (i.e. if
    986   // this is really a flat string in a cons string). If that is not
    987   // the case we would rather go to the runtime system now to flatten
    988   // the string.
    989   __ bind(&cons_string);
    990   __ cmp(FieldOperand(string, ConsString::kSecondOffset),
    991          Immediate(factory->empty_string()));
    992   __ j(not_equal, call_runtime);
    993   __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
    994 
    995   __ bind(&indirect_string_loaded);
    996   __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
    997   __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
    998 
    999   // Distinguish sequential and external strings. Only these two string
   1000   // representations can reach here (slices and flat cons strings have been
   1001   // reduced to the underlying sequential or external string).
   1002   Label seq_string;
   1003   __ bind(&check_sequential);
   1004   STATIC_ASSERT(kSeqStringTag == 0);
   1005   __ test(result, Immediate(kStringRepresentationMask));
   1006   __ j(zero, &seq_string, Label::kNear);
   1007 
   1008   // Handle external strings.
   1009   Label ascii_external, done;
   1010   if (FLAG_debug_code) {
   1011     // Assert that we do not have a cons or slice (indirect strings) here.
   1012     // Sequential strings have already been ruled out.
   1013     __ test(result, Immediate(kIsIndirectStringMask));
   1014     __ Assert(zero, kExternalStringExpectedButNotFound);
   1015   }
   1016   // Rule out short external strings.
   1017   STATIC_CHECK(kShortExternalStringTag != 0);
   1018   __ test_b(result, kShortExternalStringMask);
   1019   __ j(not_zero, call_runtime);
   1020   // Check encoding.
   1021   STATIC_ASSERT(kTwoByteStringTag == 0);
   1022   __ test_b(result, kStringEncodingMask);
   1023   __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset));
   1024   __ j(not_equal, &ascii_external, Label::kNear);
   1025   // Two-byte string.
   1026   __ movzx_w(result, Operand(result, index, times_2, 0));
   1027   __ jmp(&done, Label::kNear);
   1028   __ bind(&ascii_external);
   1029   // Ascii string.
   1030   __ movzx_b(result, Operand(result, index, times_1, 0));
   1031   __ jmp(&done, Label::kNear);
   1032 
   1033   // Dispatch on the encoding: ASCII or two-byte.
   1034   Label ascii;
   1035   __ bind(&seq_string);
   1036   STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
   1037   STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
   1038   __ test(result, Immediate(kStringEncodingMask));
   1039   __ j(not_zero, &ascii, Label::kNear);
   1040 
   1041   // Two-byte string.
   1042   // Load the two-byte character code into the result register.
   1043   __ movzx_w(result, FieldOperand(string,
   1044                                   index,
   1045                                   times_2,
   1046                                   SeqTwoByteString::kHeaderSize));
   1047   __ jmp(&done, Label::kNear);
   1048 
   1049   // Ascii string.
   1050   // Load the byte into the result register.
   1051   __ bind(&ascii);
   1052   __ movzx_b(result, FieldOperand(string,
   1053                                   index,
   1054                                   times_1,
   1055                                   SeqOneByteString::kHeaderSize));
   1056   __ bind(&done);
   1057 }
   1058 
   1059 
   1060 static Operand ExpConstant(int index) {
   1061   return Operand::StaticVariable(ExternalReference::math_exp_constants(index));
   1062 }
   1063 
   1064 
   1065 void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
   1066                                    XMMRegister input,
   1067                                    XMMRegister result,
   1068                                    XMMRegister double_scratch,
   1069                                    Register temp1,
   1070                                    Register temp2) {
   1071   ASSERT(!input.is(double_scratch));
   1072   ASSERT(!input.is(result));
   1073   ASSERT(!result.is(double_scratch));
   1074   ASSERT(!temp1.is(temp2));
   1075   ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
   1076 
   1077   Label done;
   1078 
   1079   __ movdbl(double_scratch, ExpConstant(0));
   1080   __ xorpd(result, result);
   1081   __ ucomisd(double_scratch, input);
   1082   __ j(above_equal, &done);
   1083   __ ucomisd(input, ExpConstant(1));
   1084   __ movdbl(result, ExpConstant(2));
   1085   __ j(above_equal, &done);
   1086   __ movdbl(double_scratch, ExpConstant(3));
   1087   __ movdbl(result, ExpConstant(4));
   1088   __ mulsd(double_scratch, input);
   1089   __ addsd(double_scratch, result);
   1090   __ movd(temp2, double_scratch);
   1091   __ subsd(double_scratch, result);
   1092   __ movdbl(result, ExpConstant(6));
   1093   __ mulsd(double_scratch, ExpConstant(5));
   1094   __ subsd(double_scratch, input);
   1095   __ subsd(result, double_scratch);
   1096   __ movsd(input, double_scratch);
   1097   __ mulsd(input, double_scratch);
   1098   __ mulsd(result, input);
   1099   __ mov(temp1, temp2);
   1100   __ mulsd(result, ExpConstant(7));
   1101   __ subsd(result, double_scratch);
   1102   __ add(temp1, Immediate(0x1ff800));
   1103   __ addsd(result, ExpConstant(8));
   1104   __ and_(temp2, Immediate(0x7ff));
   1105   __ shr(temp1, 11);
   1106   __ shl(temp1, 20);
   1107   __ movd(input, temp1);
   1108   __ pshufd(input, input, static_cast<uint8_t>(0xe1));  // Order: 11 10 00 01
   1109   __ movdbl(double_scratch, Operand::StaticArray(
   1110       temp2, times_8, ExternalReference::math_exp_log_table()));
   1111   __ por(input, double_scratch);
   1112   __ mulsd(result, input);
   1113   __ bind(&done);
   1114 }
   1115 
   1116 #undef __
   1117 
   1118 static const int kNoCodeAgeSequenceLength = 5;
   1119 
   1120 static byte* GetNoCodeAgeSequence(uint32_t* length) {
   1121   static bool initialized = false;
   1122   static byte sequence[kNoCodeAgeSequenceLength];
   1123   *length = kNoCodeAgeSequenceLength;
   1124   if (!initialized) {
   1125     // The sequence of instructions that is patched out for aging code is the
   1126     // following boilerplate stack-building prologue that is found both in
   1127     // FUNCTION and OPTIMIZED_FUNCTION code:
   1128     CodePatcher patcher(sequence, kNoCodeAgeSequenceLength);
   1129     patcher.masm()->push(ebp);
   1130     patcher.masm()->mov(ebp, esp);
   1131     patcher.masm()->push(esi);
   1132     patcher.masm()->push(edi);
   1133     initialized = true;
   1134   }
   1135   return sequence;
   1136 }
   1137 
   1138 
   1139 bool Code::IsYoungSequence(byte* sequence) {
   1140   uint32_t young_length;
   1141   byte* young_sequence = GetNoCodeAgeSequence(&young_length);
   1142   bool result = (!memcmp(sequence, young_sequence, young_length));
   1143   ASSERT(result || *sequence == kCallOpcode);
   1144   return result;
   1145 }
   1146 
   1147 
   1148 void Code::GetCodeAgeAndParity(byte* sequence, Age* age,
   1149                                MarkingParity* parity) {
   1150   if (IsYoungSequence(sequence)) {
   1151     *age = kNoAge;
   1152     *parity = NO_MARKING_PARITY;
   1153   } else {
   1154     sequence++;  // Skip the kCallOpcode byte
   1155     Address target_address = sequence + *reinterpret_cast<int*>(sequence) +
   1156         Assembler::kCallTargetAddressOffset;
   1157     Code* stub = GetCodeFromTargetAddress(target_address);
   1158     GetCodeAgeAndParity(stub, age, parity);
   1159   }
   1160 }
   1161 
   1162 
   1163 void Code::PatchPlatformCodeAge(byte* sequence,
   1164                                 Code::Age age,
   1165                                 MarkingParity parity) {
   1166   uint32_t young_length;
   1167   byte* young_sequence = GetNoCodeAgeSequence(&young_length);
   1168   if (age == kNoAge) {
   1169     CopyBytes(sequence, young_sequence, young_length);
   1170     CPU::FlushICache(sequence, young_length);
   1171   } else {
   1172     Code* stub = GetCodeAgeStub(age, parity);
   1173     CodePatcher patcher(sequence, young_length);
   1174     patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32);
   1175   }
   1176 }
   1177 
   1178 
   1179 } }  // namespace v8::internal
   1180 
   1181 #endif  // V8_TARGET_ARCH_IA32
   1182