The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / ia32 / codegen-ia32.cc @ f230a1cf

History | View | Annotate | Download (39.6 KB)

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
    __ movsd(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
    __ movsd(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
    __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
159
    __ sqrtsd(xmm0, xmm0);
160
    __ movsd(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
enum Direction { FORWARD, BACKWARD };
181
enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
182

    
183
// Expects registers:
184
// esi - source, aligned if alignment == ALIGNED
185
// edi - destination, always aligned
186
// ecx - count (copy size in bytes)
187
// edx - loop count (number of 64 byte chunks)
188
void MemMoveEmitMainLoop(MacroAssembler* masm,
189
                         Label* move_last_15,
190
                         Direction direction,
191
                         Alignment alignment) {
192
  Register src = esi;
193
  Register dst = edi;
194
  Register count = ecx;
195
  Register loop_count = edx;
196
  Label loop, move_last_31, move_last_63;
197
  __ cmp(loop_count, 0);
198
  __ j(equal, &move_last_63);
199
  __ bind(&loop);
200
  // Main loop. Copy in 64 byte chunks.
201
  if (direction == BACKWARD) __ sub(src, Immediate(0x40));
202
  __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
203
  __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
204
  __ movdq(alignment == MOVE_ALIGNED, xmm2, Operand(src, 0x20));
205
  __ movdq(alignment == MOVE_ALIGNED, xmm3, Operand(src, 0x30));
206
  if (direction == FORWARD) __ add(src, Immediate(0x40));
207
  if (direction == BACKWARD) __ sub(dst, Immediate(0x40));
208
  __ movdqa(Operand(dst, 0x00), xmm0);
209
  __ movdqa(Operand(dst, 0x10), xmm1);
210
  __ movdqa(Operand(dst, 0x20), xmm2);
211
  __ movdqa(Operand(dst, 0x30), xmm3);
212
  if (direction == FORWARD) __ add(dst, Immediate(0x40));
213
  __ dec(loop_count);
214
  __ j(not_zero, &loop);
215
  // At most 63 bytes left to copy.
216
  __ bind(&move_last_63);
217
  __ test(count, Immediate(0x20));
218
  __ j(zero, &move_last_31);
219
  if (direction == BACKWARD) __ sub(src, Immediate(0x20));
220
  __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
221
  __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
222
  if (direction == FORWARD) __ add(src, Immediate(0x20));
223
  if (direction == BACKWARD) __ sub(dst, Immediate(0x20));
224
  __ movdqa(Operand(dst, 0x00), xmm0);
225
  __ movdqa(Operand(dst, 0x10), xmm1);
226
  if (direction == FORWARD) __ add(dst, Immediate(0x20));
227
  // At most 31 bytes left to copy.
228
  __ bind(&move_last_31);
229
  __ test(count, Immediate(0x10));
230
  __ j(zero, move_last_15);
231
  if (direction == BACKWARD) __ sub(src, Immediate(0x10));
232
  __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0));
233
  if (direction == FORWARD) __ add(src, Immediate(0x10));
234
  if (direction == BACKWARD) __ sub(dst, Immediate(0x10));
235
  __ movdqa(Operand(dst, 0), xmm0);
236
  if (direction == FORWARD) __ add(dst, Immediate(0x10));
237
}
238

    
239

    
240
void MemMoveEmitPopAndReturn(MacroAssembler* masm) {
241
  __ pop(esi);
242
  __ pop(edi);
243
  __ ret(0);
244
}
245

    
246

    
247
#undef __
248
#define __ masm.
249

    
250

    
251
class LabelConverter {
252
 public:
253
  explicit LabelConverter(byte* buffer) : buffer_(buffer) {}
254
  int32_t address(Label* l) const {
255
    return reinterpret_cast<int32_t>(buffer_) + l->pos();
256
  }
257
 private:
258
  byte* buffer_;
259
};
260

    
261

    
262
OS::MemMoveFunction CreateMemMoveFunction() {
263
  size_t actual_size;
264
  // Allocate buffer in executable space.
265
  byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
266
  if (buffer == NULL) return NULL;
267
  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
268
  LabelConverter conv(buffer);
269

    
270
  // Generated code is put into a fixed, unmovable buffer, and not into
271
  // the V8 heap. We can't, and don't, refer to any relocatable addresses
272
  // (e.g. the JavaScript nan-object).
273

    
274
  // 32-bit C declaration function calls pass arguments on stack.
275

    
276
  // Stack layout:
277
  // esp[12]: Third argument, size.
278
  // esp[8]: Second argument, source pointer.
279
  // esp[4]: First argument, destination pointer.
280
  // esp[0]: return address
281

    
282
  const int kDestinationOffset = 1 * kPointerSize;
283
  const int kSourceOffset = 2 * kPointerSize;
284
  const int kSizeOffset = 3 * kPointerSize;
285

    
286
  // When copying up to this many bytes, use special "small" handlers.
287
  const size_t kSmallCopySize = 8;
288
  // When copying up to this many bytes, use special "medium" handlers.
289
  const size_t kMediumCopySize = 63;
290
  // When non-overlapping region of src and dst is less than this,
291
  // use a more careful implementation (slightly slower).
292
  const size_t kMinMoveDistance = 16;
293
  // Note that these values are dictated by the implementation below,
294
  // do not just change them and hope things will work!
295

    
296
  int stack_offset = 0;  // Update if we change the stack height.
297

    
298
  Label backward, backward_much_overlap;
299
  Label forward_much_overlap, small_size, medium_size, pop_and_return;
300
  __ push(edi);
301
  __ push(esi);
302
  stack_offset += 2 * kPointerSize;
303
  Register dst = edi;
304
  Register src = esi;
305
  Register count = ecx;
306
  Register loop_count = edx;
307
  __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
308
  __ mov(src, Operand(esp, stack_offset + kSourceOffset));
309
  __ mov(count, Operand(esp, stack_offset + kSizeOffset));
310

    
311
  __ cmp(dst, src);
312
  __ j(equal, &pop_and_return);
313

    
314
  if (CpuFeatures::IsSupported(SSE2)) {
315
    CpuFeatureScope sse2_scope(&masm, SSE2);
316
    __ prefetch(Operand(src, 0), 1);
317
    __ cmp(count, kSmallCopySize);
318
    __ j(below_equal, &small_size);
319
    __ cmp(count, kMediumCopySize);
320
    __ j(below_equal, &medium_size);
321
    __ cmp(dst, src);
322
    __ j(above, &backward);
323

    
324
    {
325
      // |dst| is a lower address than |src|. Copy front-to-back.
326
      Label unaligned_source, move_last_15, skip_last_move;
327
      __ mov(eax, src);
328
      __ sub(eax, dst);
329
      __ cmp(eax, kMinMoveDistance);
330
      __ j(below, &forward_much_overlap);
331
      // Copy first 16 bytes.
332
      __ movdqu(xmm0, Operand(src, 0));
333
      __ movdqu(Operand(dst, 0), xmm0);
334
      // Determine distance to alignment: 16 - (dst & 0xF).
335
      __ mov(edx, dst);
336
      __ and_(edx, 0xF);
337
      __ neg(edx);
338
      __ add(edx, Immediate(16));
339
      __ add(dst, edx);
340
      __ add(src, edx);
341
      __ sub(count, edx);
342
      // dst is now aligned. Main copy loop.
343
      __ mov(loop_count, count);
344
      __ shr(loop_count, 6);
345
      // Check if src is also aligned.
346
      __ test(src, Immediate(0xF));
347
      __ j(not_zero, &unaligned_source);
348
      // Copy loop for aligned source and destination.
349
      MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
350
      // At most 15 bytes to copy. Copy 16 bytes at end of string.
351
      __ bind(&move_last_15);
352
      __ and_(count, 0xF);
353
      __ j(zero, &skip_last_move, Label::kNear);
354
      __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
355
      __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
356
      __ bind(&skip_last_move);
357
      MemMoveEmitPopAndReturn(&masm);
358

    
359
      // Copy loop for unaligned source and aligned destination.
360
      __ bind(&unaligned_source);
361
      MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
362
      __ jmp(&move_last_15);
363

    
364
      // Less than kMinMoveDistance offset between dst and src.
365
      Label loop_until_aligned, last_15_much_overlap;
366
      __ bind(&loop_until_aligned);
367
      __ mov_b(eax, Operand(src, 0));
368
      __ inc(src);
369
      __ mov_b(Operand(dst, 0), eax);
370
      __ inc(dst);
371
      __ dec(count);
372
      __ bind(&forward_much_overlap);  // Entry point into this block.
373
      __ test(dst, Immediate(0xF));
374
      __ j(not_zero, &loop_until_aligned);
375
      // dst is now aligned, src can't be. Main copy loop.
376
      __ mov(loop_count, count);
377
      __ shr(loop_count, 6);
378
      MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
379
                          FORWARD, MOVE_UNALIGNED);
380
      __ bind(&last_15_much_overlap);
381
      __ and_(count, 0xF);
382
      __ j(zero, &pop_and_return);
383
      __ cmp(count, kSmallCopySize);
384
      __ j(below_equal, &small_size);
385
      __ jmp(&medium_size);
386
    }
387

    
388
    {
389
      // |dst| is a higher address than |src|. Copy backwards.
390
      Label unaligned_source, move_first_15, skip_last_move;
391
      __ bind(&backward);
392
      // |dst| and |src| always point to the end of what's left to copy.
393
      __ add(dst, count);
394
      __ add(src, count);
395
      __ mov(eax, dst);
396
      __ sub(eax, src);
397
      __ cmp(eax, kMinMoveDistance);
398
      __ j(below, &backward_much_overlap);
399
      // Copy last 16 bytes.
400
      __ movdqu(xmm0, Operand(src, -0x10));
401
      __ movdqu(Operand(dst, -0x10), xmm0);
402
      // Find distance to alignment: dst & 0xF
403
      __ mov(edx, dst);
404
      __ and_(edx, 0xF);
405
      __ sub(dst, edx);
406
      __ sub(src, edx);
407
      __ sub(count, edx);
408
      // dst is now aligned. Main copy loop.
409
      __ mov(loop_count, count);
410
      __ shr(loop_count, 6);
411
      // Check if src is also aligned.
412
      __ test(src, Immediate(0xF));
413
      __ j(not_zero, &unaligned_source);
414
      // Copy loop for aligned source and destination.
415
      MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
416
      // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
417
      __ bind(&move_first_15);
418
      __ and_(count, 0xF);
419
      __ j(zero, &skip_last_move, Label::kNear);
420
      __ sub(src, count);
421
      __ sub(dst, count);
422
      __ movdqu(xmm0, Operand(src, 0));
423
      __ movdqu(Operand(dst, 0), xmm0);
424
      __ bind(&skip_last_move);
425
      MemMoveEmitPopAndReturn(&masm);
426

    
427
      // Copy loop for unaligned source and aligned destination.
428
      __ bind(&unaligned_source);
429
      MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED);
430
      __ jmp(&move_first_15);
431

    
432
      // Less than kMinMoveDistance offset between dst and src.
433
      Label loop_until_aligned, first_15_much_overlap;
434
      __ bind(&loop_until_aligned);
435
      __ dec(src);
436
      __ dec(dst);
437
      __ mov_b(eax, Operand(src, 0));
438
      __ mov_b(Operand(dst, 0), eax);
439
      __ dec(count);
440
      __ bind(&backward_much_overlap);  // Entry point into this block.
441
      __ test(dst, Immediate(0xF));
442
      __ j(not_zero, &loop_until_aligned);
443
      // dst is now aligned, src can't be. Main copy loop.
444
      __ mov(loop_count, count);
445
      __ shr(loop_count, 6);
446
      MemMoveEmitMainLoop(&masm, &first_15_much_overlap,
447
                          BACKWARD, MOVE_UNALIGNED);
448
      __ bind(&first_15_much_overlap);
449
      __ and_(count, 0xF);
450
      __ j(zero, &pop_and_return);
451
      // Small/medium handlers expect dst/src to point to the beginning.
452
      __ sub(dst, count);
453
      __ sub(src, count);
454
      __ cmp(count, kSmallCopySize);
455
      __ j(below_equal, &small_size);
456
      __ jmp(&medium_size);
457
    }
458
    {
459
      // Special handlers for 9 <= copy_size < 64. No assumptions about
460
      // alignment or move distance, so all reads must be unaligned and
461
      // must happen before any writes.
462
      Label medium_handlers, f9_16, f17_32, f33_48, f49_63;
463

    
464
      __ bind(&f9_16);
465
      __ movsd(xmm0, Operand(src, 0));
466
      __ movsd(xmm1, Operand(src, count, times_1, -8));
467
      __ movsd(Operand(dst, 0), xmm0);
468
      __ movsd(Operand(dst, count, times_1, -8), xmm1);
469
      MemMoveEmitPopAndReturn(&masm);
470

    
471
      __ bind(&f17_32);
472
      __ movdqu(xmm0, Operand(src, 0));
473
      __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
474
      __ movdqu(Operand(dst, 0x00), xmm0);
475
      __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
476
      MemMoveEmitPopAndReturn(&masm);
477

    
478
      __ bind(&f33_48);
479
      __ movdqu(xmm0, Operand(src, 0x00));
480
      __ movdqu(xmm1, Operand(src, 0x10));
481
      __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
482
      __ movdqu(Operand(dst, 0x00), xmm0);
483
      __ movdqu(Operand(dst, 0x10), xmm1);
484
      __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
485
      MemMoveEmitPopAndReturn(&masm);
486

    
487
      __ bind(&f49_63);
488
      __ movdqu(xmm0, Operand(src, 0x00));
489
      __ movdqu(xmm1, Operand(src, 0x10));
490
      __ movdqu(xmm2, Operand(src, 0x20));
491
      __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
492
      __ movdqu(Operand(dst, 0x00), xmm0);
493
      __ movdqu(Operand(dst, 0x10), xmm1);
494
      __ movdqu(Operand(dst, 0x20), xmm2);
495
      __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
496
      MemMoveEmitPopAndReturn(&masm);
497

    
498
      __ bind(&medium_handlers);
499
      __ dd(conv.address(&f9_16));
500
      __ dd(conv.address(&f17_32));
501
      __ dd(conv.address(&f33_48));
502
      __ dd(conv.address(&f49_63));
503

    
504
      __ bind(&medium_size);  // Entry point into this block.
505
      __ mov(eax, count);
506
      __ dec(eax);
507
      __ shr(eax, 4);
508
      if (FLAG_debug_code) {
509
        Label ok;
510
        __ cmp(eax, 3);
511
        __ j(below_equal, &ok);
512
        __ int3();
513
        __ bind(&ok);
514
      }
515
      __ mov(eax, Operand(eax, times_4, conv.address(&medium_handlers)));
516
      __ jmp(eax);
517
    }
518
    {
519
      // Specialized copiers for copy_size <= 8 bytes.
520
      Label small_handlers, f0, f1, f2, f3, f4, f5_8;
521
      __ bind(&f0);
522
      MemMoveEmitPopAndReturn(&masm);
523

    
524
      __ bind(&f1);
525
      __ mov_b(eax, Operand(src, 0));
526
      __ mov_b(Operand(dst, 0), eax);
527
      MemMoveEmitPopAndReturn(&masm);
528

    
529
      __ bind(&f2);
530
      __ mov_w(eax, Operand(src, 0));
531
      __ mov_w(Operand(dst, 0), eax);
532
      MemMoveEmitPopAndReturn(&masm);
533

    
534
      __ bind(&f3);
535
      __ mov_w(eax, Operand(src, 0));
536
      __ mov_b(edx, Operand(src, 2));
537
      __ mov_w(Operand(dst, 0), eax);
538
      __ mov_b(Operand(dst, 2), edx);
539
      MemMoveEmitPopAndReturn(&masm);
540

    
541
      __ bind(&f4);
542
      __ mov(eax, Operand(src, 0));
543
      __ mov(Operand(dst, 0), eax);
544
      MemMoveEmitPopAndReturn(&masm);
545

    
546
      __ bind(&f5_8);
547
      __ mov(eax, Operand(src, 0));
548
      __ mov(edx, Operand(src, count, times_1, -4));
549
      __ mov(Operand(dst, 0), eax);
550
      __ mov(Operand(dst, count, times_1, -4), edx);
551
      MemMoveEmitPopAndReturn(&masm);
552

    
553
      __ bind(&small_handlers);
554
      __ dd(conv.address(&f0));
555
      __ dd(conv.address(&f1));
556
      __ dd(conv.address(&f2));
557
      __ dd(conv.address(&f3));
558
      __ dd(conv.address(&f4));
559
      __ dd(conv.address(&f5_8));
560
      __ dd(conv.address(&f5_8));
561
      __ dd(conv.address(&f5_8));
562
      __ dd(conv.address(&f5_8));
563

    
564
      __ bind(&small_size);  // Entry point into this block.
565
      if (FLAG_debug_code) {
566
        Label ok;
567
        __ cmp(count, 8);
568
        __ j(below_equal, &ok);
569
        __ int3();
570
        __ bind(&ok);
571
      }
572
      __ mov(eax, Operand(count, times_4, conv.address(&small_handlers)));
573
      __ jmp(eax);
574
    }
575
  } else {
576
    // No SSE2.
577
    Label forward;
578
    __ cmp(count, 0);
579
    __ j(equal, &pop_and_return);
580
    __ cmp(dst, src);
581
    __ j(above, &backward);
582
    __ jmp(&forward);
583
    {
584
      // Simple forward copier.
585
      Label forward_loop_1byte, forward_loop_4byte;
586
      __ bind(&forward_loop_4byte);
587
      __ mov(eax, Operand(src, 0));
588
      __ sub(count, Immediate(4));
589
      __ add(src, Immediate(4));
590
      __ mov(Operand(dst, 0), eax);
591
      __ add(dst, Immediate(4));
592
      __ bind(&forward);  // Entry point.
593
      __ cmp(count, 3);
594
      __ j(above, &forward_loop_4byte);
595
      __ bind(&forward_loop_1byte);
596
      __ cmp(count, 0);
597
      __ j(below_equal, &pop_and_return);
598
      __ mov_b(eax, Operand(src, 0));
599
      __ dec(count);
600
      __ inc(src);
601
      __ mov_b(Operand(dst, 0), eax);
602
      __ inc(dst);
603
      __ jmp(&forward_loop_1byte);
604
    }
605
    {
606
      // Simple backward copier.
607
      Label backward_loop_1byte, backward_loop_4byte, entry_shortcut;
608
      __ bind(&backward);
609
      __ add(src, count);
610
      __ add(dst, count);
611
      __ cmp(count, 3);
612
      __ j(below_equal, &entry_shortcut);
613

    
614
      __ bind(&backward_loop_4byte);
615
      __ sub(src, Immediate(4));
616
      __ sub(count, Immediate(4));
617
      __ mov(eax, Operand(src, 0));
618
      __ sub(dst, Immediate(4));
619
      __ mov(Operand(dst, 0), eax);
620
      __ cmp(count, 3);
621
      __ j(above, &backward_loop_4byte);
622
      __ bind(&backward_loop_1byte);
623
      __ cmp(count, 0);
624
      __ j(below_equal, &pop_and_return);
625
      __ bind(&entry_shortcut);
626
      __ dec(src);
627
      __ dec(count);
628
      __ mov_b(eax, Operand(src, 0));
629
      __ dec(dst);
630
      __ mov_b(Operand(dst, 0), eax);
631
      __ jmp(&backward_loop_1byte);
632
    }
633
  }
634

    
635
  __ bind(&pop_and_return);
636
  MemMoveEmitPopAndReturn(&masm);
637

    
638
  CodeDesc desc;
639
  masm.GetCode(&desc);
640
  ASSERT(!RelocInfo::RequiresRelocation(desc));
641
  CPU::FlushICache(buffer, actual_size);
642
  OS::ProtectCode(buffer, actual_size);
643
  // TODO(jkummerow): It would be nice to register this code creation event
644
  // with the PROFILE / GDBJIT system.
645
  return FUNCTION_CAST<OS::MemMoveFunction>(buffer);
646
}
647

    
648

    
649
#undef __
650

    
651
// -------------------------------------------------------------------------
652
// Code generators
653

    
654
#define __ ACCESS_MASM(masm)
655

    
656

    
657
void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
658
    MacroAssembler* masm, AllocationSiteMode mode,
659
    Label* allocation_memento_found) {
660
  // ----------- S t a t e -------------
661
  //  -- eax    : value
662
  //  -- ebx    : target map
663
  //  -- ecx    : key
664
  //  -- edx    : receiver
665
  //  -- esp[0] : return address
666
  // -----------------------------------
667
  if (mode == TRACK_ALLOCATION_SITE) {
668
    ASSERT(allocation_memento_found != NULL);
669
    __ JumpIfJSArrayHasAllocationMemento(edx, edi, allocation_memento_found);
670
  }
671

    
672
  // Set transitioned map.
673
  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
674
  __ RecordWriteField(edx,
675
                      HeapObject::kMapOffset,
676
                      ebx,
677
                      edi,
678
                      kDontSaveFPRegs,
679
                      EMIT_REMEMBERED_SET,
680
                      OMIT_SMI_CHECK);
681
}
682

    
683

    
684
void ElementsTransitionGenerator::GenerateSmiToDouble(
685
    MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
686
  // ----------- S t a t e -------------
687
  //  -- eax    : value
688
  //  -- ebx    : target map
689
  //  -- ecx    : key
690
  //  -- edx    : receiver
691
  //  -- esp[0] : return address
692
  // -----------------------------------
693
  Label loop, entry, convert_hole, gc_required, only_change_map;
694

    
695
  if (mode == TRACK_ALLOCATION_SITE) {
696
    __ JumpIfJSArrayHasAllocationMemento(edx, edi, fail);
697
  }
698

    
699
  // Check for empty arrays, which only require a map transition and no changes
700
  // to the backing store.
701
  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
702
  __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
703
  __ j(equal, &only_change_map);
704

    
705
  __ push(eax);
706
  __ push(ebx);
707

    
708
  __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
709

    
710
  // Allocate new FixedDoubleArray.
711
  // edx: receiver
712
  // edi: length of source FixedArray (smi-tagged)
713
  AllocationFlags flags =
714
      static_cast<AllocationFlags>(TAG_OBJECT | DOUBLE_ALIGNMENT);
715
  __ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi,
716
              REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags);
717

    
718
  // eax: destination FixedDoubleArray
719
  // edi: number of elements
720
  // edx: receiver
721
  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
722
         Immediate(masm->isolate()->factory()->fixed_double_array_map()));
723
  __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
724
  __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
725
  // Replace receiver's backing store with newly created FixedDoubleArray.
726
  __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
727
  __ mov(ebx, eax);
728
  __ RecordWriteField(edx,
729
                      JSObject::kElementsOffset,
730
                      ebx,
731
                      edi,
732
                      kDontSaveFPRegs,
733
                      EMIT_REMEMBERED_SET,
734
                      OMIT_SMI_CHECK);
735

    
736
  __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
737

    
738
  // Prepare for conversion loop.
739
  ExternalReference canonical_the_hole_nan_reference =
740
      ExternalReference::address_of_the_hole_nan();
741
  XMMRegister the_hole_nan = xmm1;
742
  if (CpuFeatures::IsSupported(SSE2)) {
743
    CpuFeatureScope use_sse2(masm, SSE2);
744
    __ movsd(the_hole_nan,
745
              Operand::StaticVariable(canonical_the_hole_nan_reference));
746
  }
747
  __ jmp(&entry);
748

    
749
  // Call into runtime if GC is required.
750
  __ bind(&gc_required);
751
  // Restore registers before jumping into runtime.
752
  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
753
  __ pop(ebx);
754
  __ pop(eax);
755
  __ jmp(fail);
756

    
757
  // Convert and copy elements
758
  // esi: source FixedArray
759
  __ bind(&loop);
760
  __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
761
  // ebx: current element from source
762
  // edi: index of current element
763
  __ JumpIfNotSmi(ebx, &convert_hole);
764

    
765
  // Normal smi, convert it to double and store.
766
  __ SmiUntag(ebx);
767
  if (CpuFeatures::IsSupported(SSE2)) {
768
    CpuFeatureScope fscope(masm, SSE2);
769
    __ Cvtsi2sd(xmm0, ebx);
770
    __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
771
              xmm0);
772
  } else {
773
    __ push(ebx);
774
    __ fild_s(Operand(esp, 0));
775
    __ pop(ebx);
776
    __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
777
  }
778
  __ jmp(&entry);
779

    
780
  // Found hole, store hole_nan_as_double instead.
781
  __ bind(&convert_hole);
782

    
783
  if (FLAG_debug_code) {
784
    __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
785
    __ Assert(equal, kObjectFoundInSmiOnlyArray);
786
  }
787

    
788
  if (CpuFeatures::IsSupported(SSE2)) {
789
    CpuFeatureScope use_sse2(masm, SSE2);
790
    __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
791
              the_hole_nan);
792
  } else {
793
    __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
794
    __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
795
  }
796

    
797
  __ bind(&entry);
798
  __ sub(edi, Immediate(Smi::FromInt(1)));
799
  __ j(not_sign, &loop);
800

    
801
  __ pop(ebx);
802
  __ pop(eax);
803

    
804
  // Restore esi.
805
  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
806

    
807
  __ bind(&only_change_map);
808
  // eax: value
809
  // ebx: target map
810
  // Set transitioned map.
811
  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
812
  __ RecordWriteField(edx,
813
                      HeapObject::kMapOffset,
814
                      ebx,
815
                      edi,
816
                      kDontSaveFPRegs,
817
                      OMIT_REMEMBERED_SET,
818
                      OMIT_SMI_CHECK);
819
}
820

    
821

    
822
void ElementsTransitionGenerator::GenerateDoubleToObject(
823
    MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
824
  // ----------- S t a t e -------------
825
  //  -- eax    : value
826
  //  -- ebx    : target map
827
  //  -- ecx    : key
828
  //  -- edx    : receiver
829
  //  -- esp[0] : return address
830
  // -----------------------------------
831
  Label loop, entry, convert_hole, gc_required, only_change_map, success;
832

    
833
  if (mode == TRACK_ALLOCATION_SITE) {
834
    __ JumpIfJSArrayHasAllocationMemento(edx, edi, fail);
835
  }
836

    
837
  // Check for empty arrays, which only require a map transition and no changes
838
  // to the backing store.
839
  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
840
  __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
841
  __ j(equal, &only_change_map);
842

    
843
  __ push(eax);
844
  __ push(edx);
845
  __ push(ebx);
846

    
847
  __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
848

    
849
  // Allocate new FixedArray.
850
  // ebx: length of source FixedDoubleArray (smi-tagged)
851
  __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
852
  __ Allocate(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
853

    
854
  // eax: destination FixedArray
855
  // ebx: number of elements
856
  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
857
         Immediate(masm->isolate()->factory()->fixed_array_map()));
858
  __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
859
  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
860

    
861
  __ jmp(&entry);
862

    
863
  // ebx: target map
864
  // edx: receiver
865
  // Set transitioned map.
866
  __ bind(&only_change_map);
867
  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
868
  __ RecordWriteField(edx,
869
                      HeapObject::kMapOffset,
870
                      ebx,
871
                      edi,
872
                      kDontSaveFPRegs,
873
                      OMIT_REMEMBERED_SET,
874
                      OMIT_SMI_CHECK);
875
  __ jmp(&success);
876

    
877
  // Call into runtime if GC is required.
878
  __ bind(&gc_required);
879
  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
880
  __ pop(ebx);
881
  __ pop(edx);
882
  __ pop(eax);
883
  __ jmp(fail);
884

    
885
  // Box doubles into heap numbers.
886
  // edi: source FixedDoubleArray
887
  // eax: destination FixedArray
888
  __ bind(&loop);
889
  // ebx: index of current element (smi-tagged)
890
  uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
891
  __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
892
  __ j(equal, &convert_hole);
893

    
894
  // Non-hole double, copy value into a heap number.
895
  __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
896
  // edx: new heap number
897
  if (CpuFeatures::IsSupported(SSE2)) {
898
    CpuFeatureScope fscope(masm, SSE2);
899
    __ movsd(xmm0,
900
              FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
901
    __ movsd(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
902
  } else {
903
    __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
904
    __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
905
    __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
906
    __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
907
  }
908
  __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
909
  __ mov(esi, ebx);
910
  __ RecordWriteArray(eax,
911
                      edx,
912
                      esi,
913
                      kDontSaveFPRegs,
914
                      EMIT_REMEMBERED_SET,
915
                      OMIT_SMI_CHECK);
916
  __ jmp(&entry, Label::kNear);
917

    
918
  // Replace the-hole NaN with the-hole pointer.
919
  __ bind(&convert_hole);
920
  __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
921
         masm->isolate()->factory()->the_hole_value());
922

    
923
  __ bind(&entry);
924
  __ sub(ebx, Immediate(Smi::FromInt(1)));
925
  __ j(not_sign, &loop);
926

    
927
  __ pop(ebx);
928
  __ pop(edx);
929
  // ebx: target map
930
  // edx: receiver
931
  // Set transitioned map.
932
  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
933
  __ RecordWriteField(edx,
934
                      HeapObject::kMapOffset,
935
                      ebx,
936
                      edi,
937
                      kDontSaveFPRegs,
938
                      OMIT_REMEMBERED_SET,
939
                      OMIT_SMI_CHECK);
940
  // Replace receiver's backing store with newly created and filled FixedArray.
941
  __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
942
  __ RecordWriteField(edx,
943
                      JSObject::kElementsOffset,
944
                      eax,
945
                      edi,
946
                      kDontSaveFPRegs,
947
                      EMIT_REMEMBERED_SET,
948
                      OMIT_SMI_CHECK);
949

    
950
  // Restore registers.
951
  __ pop(eax);
952
  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
953

    
954
  __ bind(&success);
955
}
956

    
957

    
958
void StringCharLoadGenerator::Generate(MacroAssembler* masm,
959
                                       Factory* factory,
960
                                       Register string,
961
                                       Register index,
962
                                       Register result,
963
                                       Label* call_runtime) {
964
  // Fetch the instance type of the receiver into result register.
965
  __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
966
  __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
967

    
968
  // We need special handling for indirect strings.
969
  Label check_sequential;
970
  __ test(result, Immediate(kIsIndirectStringMask));
971
  __ j(zero, &check_sequential, Label::kNear);
972

    
973
  // Dispatch on the indirect string shape: slice or cons.
974
  Label cons_string;
975
  __ test(result, Immediate(kSlicedNotConsMask));
976
  __ j(zero, &cons_string, Label::kNear);
977

    
978
  // Handle slices.
979
  Label indirect_string_loaded;
980
  __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset));
981
  __ SmiUntag(result);
982
  __ add(index, result);
983
  __ mov(string, FieldOperand(string, SlicedString::kParentOffset));
984
  __ jmp(&indirect_string_loaded, Label::kNear);
985

    
986
  // Handle cons strings.
987
  // Check whether the right hand side is the empty string (i.e. if
988
  // this is really a flat string in a cons string). If that is not
989
  // the case we would rather go to the runtime system now to flatten
990
  // the string.
991
  __ bind(&cons_string);
992
  __ cmp(FieldOperand(string, ConsString::kSecondOffset),
993
         Immediate(factory->empty_string()));
994
  __ j(not_equal, call_runtime);
995
  __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
996

    
997
  __ bind(&indirect_string_loaded);
998
  __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
999
  __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
1000

    
1001
  // Distinguish sequential and external strings. Only these two string
1002
  // representations can reach here (slices and flat cons strings have been
1003
  // reduced to the underlying sequential or external string).
1004
  Label seq_string;
1005
  __ bind(&check_sequential);
1006
  STATIC_ASSERT(kSeqStringTag == 0);
1007
  __ test(result, Immediate(kStringRepresentationMask));
1008
  __ j(zero, &seq_string, Label::kNear);
1009

    
1010
  // Handle external strings.
1011
  Label ascii_external, done;
1012
  if (FLAG_debug_code) {
1013
    // Assert that we do not have a cons or slice (indirect strings) here.
1014
    // Sequential strings have already been ruled out.
1015
    __ test(result, Immediate(kIsIndirectStringMask));
1016
    __ Assert(zero, kExternalStringExpectedButNotFound);
1017
  }
1018
  // Rule out short external strings.
1019
  STATIC_CHECK(kShortExternalStringTag != 0);
1020
  __ test_b(result, kShortExternalStringMask);
1021
  __ j(not_zero, call_runtime);
1022
  // Check encoding.
1023
  STATIC_ASSERT(kTwoByteStringTag == 0);
1024
  __ test_b(result, kStringEncodingMask);
1025
  __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset));
1026
  __ j(not_equal, &ascii_external, Label::kNear);
1027
  // Two-byte string.
1028
  __ movzx_w(result, Operand(result, index, times_2, 0));
1029
  __ jmp(&done, Label::kNear);
1030
  __ bind(&ascii_external);
1031
  // Ascii string.
1032
  __ movzx_b(result, Operand(result, index, times_1, 0));
1033
  __ jmp(&done, Label::kNear);
1034

    
1035
  // Dispatch on the encoding: ASCII or two-byte.
1036
  Label ascii;
1037
  __ bind(&seq_string);
1038
  STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
1039
  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
1040
  __ test(result, Immediate(kStringEncodingMask));
1041
  __ j(not_zero, &ascii, Label::kNear);
1042

    
1043
  // Two-byte string.
1044
  // Load the two-byte character code into the result register.
1045
  __ movzx_w(result, FieldOperand(string,
1046
                                  index,
1047
                                  times_2,
1048
                                  SeqTwoByteString::kHeaderSize));
1049
  __ jmp(&done, Label::kNear);
1050

    
1051
  // Ascii string.
1052
  // Load the byte into the result register.
1053
  __ bind(&ascii);
1054
  __ movzx_b(result, FieldOperand(string,
1055
                                  index,
1056
                                  times_1,
1057
                                  SeqOneByteString::kHeaderSize));
1058
  __ bind(&done);
1059
}
1060

    
1061

    
1062
static Operand ExpConstant(int index) {
1063
  return Operand::StaticVariable(ExternalReference::math_exp_constants(index));
1064
}
1065

    
1066

    
1067
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
1068
                                   XMMRegister input,
1069
                                   XMMRegister result,
1070
                                   XMMRegister double_scratch,
1071
                                   Register temp1,
1072
                                   Register temp2) {
1073
  ASSERT(!input.is(double_scratch));
1074
  ASSERT(!input.is(result));
1075
  ASSERT(!result.is(double_scratch));
1076
  ASSERT(!temp1.is(temp2));
1077
  ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
1078

    
1079
  Label done;
1080

    
1081
  __ movsd(double_scratch, ExpConstant(0));
1082
  __ xorpd(result, result);
1083
  __ ucomisd(double_scratch, input);
1084
  __ j(above_equal, &done);
1085
  __ ucomisd(input, ExpConstant(1));
1086
  __ movsd(result, ExpConstant(2));
1087
  __ j(above_equal, &done);
1088
  __ movsd(double_scratch, ExpConstant(3));
1089
  __ movsd(result, ExpConstant(4));
1090
  __ mulsd(double_scratch, input);
1091
  __ addsd(double_scratch, result);
1092
  __ movd(temp2, double_scratch);
1093
  __ subsd(double_scratch, result);
1094
  __ movsd(result, ExpConstant(6));
1095
  __ mulsd(double_scratch, ExpConstant(5));
1096
  __ subsd(double_scratch, input);
1097
  __ subsd(result, double_scratch);
1098
  __ movsd(input, double_scratch);
1099
  __ mulsd(input, double_scratch);
1100
  __ mulsd(result, input);
1101
  __ mov(temp1, temp2);
1102
  __ mulsd(result, ExpConstant(7));
1103
  __ subsd(result, double_scratch);
1104
  __ add(temp1, Immediate(0x1ff800));
1105
  __ addsd(result, ExpConstant(8));
1106
  __ and_(temp2, Immediate(0x7ff));
1107
  __ shr(temp1, 11);
1108
  __ shl(temp1, 20);
1109
  __ movd(input, temp1);
1110
  __ pshufd(input, input, static_cast<uint8_t>(0xe1));  // Order: 11 10 00 01
1111
  __ movsd(double_scratch, Operand::StaticArray(
1112
      temp2, times_8, ExternalReference::math_exp_log_table()));
1113
  __ por(input, double_scratch);
1114
  __ mulsd(result, input);
1115
  __ bind(&done);
1116
}
1117

    
1118
#undef __
1119

    
1120

    
1121
static byte* GetNoCodeAgeSequence(uint32_t* length) {
1122
  static bool initialized = false;
1123
  static byte sequence[kNoCodeAgeSequenceLength];
1124
  *length = kNoCodeAgeSequenceLength;
1125
  if (!initialized) {
1126
    // The sequence of instructions that is patched out for aging code is the
1127
    // following boilerplate stack-building prologue that is found both in
1128
    // FUNCTION and OPTIMIZED_FUNCTION code:
1129
    CodePatcher patcher(sequence, kNoCodeAgeSequenceLength);
1130
    patcher.masm()->push(ebp);
1131
    patcher.masm()->mov(ebp, esp);
1132
    patcher.masm()->push(esi);
1133
    patcher.masm()->push(edi);
1134
    initialized = true;
1135
  }
1136
  return sequence;
1137
}
1138

    
1139

    
1140
bool Code::IsYoungSequence(byte* sequence) {
1141
  uint32_t young_length;
1142
  byte* young_sequence = GetNoCodeAgeSequence(&young_length);
1143
  bool result = (!memcmp(sequence, young_sequence, young_length));
1144
  ASSERT(result || *sequence == kCallOpcode);
1145
  return result;
1146
}
1147

    
1148

    
1149
void Code::GetCodeAgeAndParity(byte* sequence, Age* age,
1150
                               MarkingParity* parity) {
1151
  if (IsYoungSequence(sequence)) {
1152
    *age = kNoAgeCodeAge;
1153
    *parity = NO_MARKING_PARITY;
1154
  } else {
1155
    sequence++;  // Skip the kCallOpcode byte
1156
    Address target_address = sequence + *reinterpret_cast<int*>(sequence) +
1157
        Assembler::kCallTargetAddressOffset;
1158
    Code* stub = GetCodeFromTargetAddress(target_address);
1159
    GetCodeAgeAndParity(stub, age, parity);
1160
  }
1161
}
1162

    
1163

    
1164
void Code::PatchPlatformCodeAge(Isolate* isolate,
1165
                                byte* sequence,
1166
                                Code::Age age,
1167
                                MarkingParity parity) {
1168
  uint32_t young_length;
1169
  byte* young_sequence = GetNoCodeAgeSequence(&young_length);
1170
  if (age == kNoAgeCodeAge) {
1171
    CopyBytes(sequence, young_sequence, young_length);
1172
    CPU::FlushICache(sequence, young_length);
1173
  } else {
1174
    Code* stub = GetCodeAgeStub(isolate, age, parity);
1175
    CodePatcher patcher(sequence, young_length);
1176
    patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32);
1177
  }
1178
}
1179

    
1180

    
1181
} }  // namespace v8::internal
1182

    
1183
#endif  // V8_TARGET_ARCH_IA32