• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/v8.h"
6 
7 #if V8_TARGET_ARCH_IA32
8 
9 #include "src/codegen.h"
10 #include "src/heap.h"
11 #include "src/macro-assembler.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 
17 // -------------------------------------------------------------------------
18 // Platform-specific RuntimeCallHelper functions.
19 
BeforeCall(MacroAssembler * masm) const20 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
21   masm->EnterFrame(StackFrame::INTERNAL);
22   ASSERT(!masm->has_frame());
23   masm->set_has_frame(true);
24 }
25 
26 
AfterCall(MacroAssembler * masm) const27 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
28   masm->LeaveFrame(StackFrame::INTERNAL);
29   ASSERT(masm->has_frame());
30   masm->set_has_frame(false);
31 }
32 
33 
34 #define __ masm.
35 
36 
CreateExpFunction()37 UnaryMathFunction CreateExpFunction() {
38   if (!FLAG_fast_math) return &std::exp;
39   size_t actual_size;
40   byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
41   if (buffer == NULL) return &std::exp;
42   ExternalReference::InitializeMathExpData();
43 
44   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
45   // esp[1 * kPointerSize]: raw double input
46   // esp[0 * kPointerSize]: return address
47   {
48     XMMRegister input = xmm1;
49     XMMRegister result = xmm2;
50     __ movsd(input, Operand(esp, 1 * kPointerSize));
51     __ push(eax);
52     __ push(ebx);
53 
54     MathExpGenerator::EmitMathExp(&masm, input, result, xmm0, eax, ebx);
55 
56     __ pop(ebx);
57     __ pop(eax);
58     __ movsd(Operand(esp, 1 * kPointerSize), result);
59     __ fld_d(Operand(esp, 1 * kPointerSize));
60     __ Ret();
61   }
62 
63   CodeDesc desc;
64   masm.GetCode(&desc);
65   ASSERT(!RelocInfo::RequiresRelocation(desc));
66 
67   CPU::FlushICache(buffer, actual_size);
68   OS::ProtectCode(buffer, actual_size);
69   return FUNCTION_CAST<UnaryMathFunction>(buffer);
70 }
71 
72 
CreateSqrtFunction()73 UnaryMathFunction CreateSqrtFunction() {
74   size_t actual_size;
75   // Allocate buffer in executable space.
76   byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
77                                                  &actual_size,
78                                                  true));
79   if (buffer == NULL) return &std::sqrt;
80   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
81   // esp[1 * kPointerSize]: raw double input
82   // esp[0 * kPointerSize]: return address
83   // Move double input into registers.
84   {
85     __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
86     __ sqrtsd(xmm0, xmm0);
87     __ movsd(Operand(esp, 1 * kPointerSize), xmm0);
88     // Load result into floating point register as return value.
89     __ fld_d(Operand(esp, 1 * kPointerSize));
90     __ Ret();
91   }
92 
93   CodeDesc desc;
94   masm.GetCode(&desc);
95   ASSERT(!RelocInfo::RequiresRelocation(desc));
96 
97   CPU::FlushICache(buffer, actual_size);
98   OS::ProtectCode(buffer, actual_size);
99   return FUNCTION_CAST<UnaryMathFunction>(buffer);
100 }
101 
102 
103 // Helper functions for CreateMemMoveFunction.
104 #undef __
105 #define __ ACCESS_MASM(masm)
106 
107 enum Direction { FORWARD, BACKWARD };
108 enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED };
109 
110 // Expects registers:
111 // esi - source, aligned if alignment == ALIGNED
112 // edi - destination, always aligned
113 // ecx - count (copy size in bytes)
114 // edx - loop count (number of 64 byte chunks)
MemMoveEmitMainLoop(MacroAssembler * masm,Label * move_last_15,Direction direction,Alignment alignment)115 void MemMoveEmitMainLoop(MacroAssembler* masm,
116                          Label* move_last_15,
117                          Direction direction,
118                          Alignment alignment) {
119   Register src = esi;
120   Register dst = edi;
121   Register count = ecx;
122   Register loop_count = edx;
123   Label loop, move_last_31, move_last_63;
124   __ cmp(loop_count, 0);
125   __ j(equal, &move_last_63);
126   __ bind(&loop);
127   // Main loop. Copy in 64 byte chunks.
128   if (direction == BACKWARD) __ sub(src, Immediate(0x40));
129   __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
130   __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
131   __ movdq(alignment == MOVE_ALIGNED, xmm2, Operand(src, 0x20));
132   __ movdq(alignment == MOVE_ALIGNED, xmm3, Operand(src, 0x30));
133   if (direction == FORWARD) __ add(src, Immediate(0x40));
134   if (direction == BACKWARD) __ sub(dst, Immediate(0x40));
135   __ movdqa(Operand(dst, 0x00), xmm0);
136   __ movdqa(Operand(dst, 0x10), xmm1);
137   __ movdqa(Operand(dst, 0x20), xmm2);
138   __ movdqa(Operand(dst, 0x30), xmm3);
139   if (direction == FORWARD) __ add(dst, Immediate(0x40));
140   __ dec(loop_count);
141   __ j(not_zero, &loop);
142   // At most 63 bytes left to copy.
143   __ bind(&move_last_63);
144   __ test(count, Immediate(0x20));
145   __ j(zero, &move_last_31);
146   if (direction == BACKWARD) __ sub(src, Immediate(0x20));
147   __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00));
148   __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10));
149   if (direction == FORWARD) __ add(src, Immediate(0x20));
150   if (direction == BACKWARD) __ sub(dst, Immediate(0x20));
151   __ movdqa(Operand(dst, 0x00), xmm0);
152   __ movdqa(Operand(dst, 0x10), xmm1);
153   if (direction == FORWARD) __ add(dst, Immediate(0x20));
154   // At most 31 bytes left to copy.
155   __ bind(&move_last_31);
156   __ test(count, Immediate(0x10));
157   __ j(zero, move_last_15);
158   if (direction == BACKWARD) __ sub(src, Immediate(0x10));
159   __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0));
160   if (direction == FORWARD) __ add(src, Immediate(0x10));
161   if (direction == BACKWARD) __ sub(dst, Immediate(0x10));
162   __ movdqa(Operand(dst, 0), xmm0);
163   if (direction == FORWARD) __ add(dst, Immediate(0x10));
164 }
165 
166 
MemMoveEmitPopAndReturn(MacroAssembler * masm)167 void MemMoveEmitPopAndReturn(MacroAssembler* masm) {
168   __ pop(esi);
169   __ pop(edi);
170   __ ret(0);
171 }
172 
173 
174 #undef __
175 #define __ masm.
176 
177 
178 class LabelConverter {
179  public:
LabelConverter(byte * buffer)180   explicit LabelConverter(byte* buffer) : buffer_(buffer) {}
address(Label * l) const181   int32_t address(Label* l) const {
182     return reinterpret_cast<int32_t>(buffer_) + l->pos();
183   }
184  private:
185   byte* buffer_;
186 };
187 
188 
CreateMemMoveFunction()189 MemMoveFunction CreateMemMoveFunction() {
190   size_t actual_size;
191   // Allocate buffer in executable space.
192   byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
193   if (buffer == NULL) return NULL;
194   MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
195   LabelConverter conv(buffer);
196 
197   // Generated code is put into a fixed, unmovable buffer, and not into
198   // the V8 heap. We can't, and don't, refer to any relocatable addresses
199   // (e.g. the JavaScript nan-object).
200 
201   // 32-bit C declaration function calls pass arguments on stack.
202 
203   // Stack layout:
204   // esp[12]: Third argument, size.
205   // esp[8]: Second argument, source pointer.
206   // esp[4]: First argument, destination pointer.
207   // esp[0]: return address
208 
209   const int kDestinationOffset = 1 * kPointerSize;
210   const int kSourceOffset = 2 * kPointerSize;
211   const int kSizeOffset = 3 * kPointerSize;
212 
213   // When copying up to this many bytes, use special "small" handlers.
214   const size_t kSmallCopySize = 8;
215   // When copying up to this many bytes, use special "medium" handlers.
216   const size_t kMediumCopySize = 63;
217   // When non-overlapping region of src and dst is less than this,
218   // use a more careful implementation (slightly slower).
219   const size_t kMinMoveDistance = 16;
220   // Note that these values are dictated by the implementation below,
221   // do not just change them and hope things will work!
222 
223   int stack_offset = 0;  // Update if we change the stack height.
224 
225   Label backward, backward_much_overlap;
226   Label forward_much_overlap, small_size, medium_size, pop_and_return;
227   __ push(edi);
228   __ push(esi);
229   stack_offset += 2 * kPointerSize;
230   Register dst = edi;
231   Register src = esi;
232   Register count = ecx;
233   Register loop_count = edx;
234   __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
235   __ mov(src, Operand(esp, stack_offset + kSourceOffset));
236   __ mov(count, Operand(esp, stack_offset + kSizeOffset));
237 
238   __ cmp(dst, src);
239   __ j(equal, &pop_and_return);
240 
241   __ prefetch(Operand(src, 0), 1);
242   __ cmp(count, kSmallCopySize);
243   __ j(below_equal, &small_size);
244   __ cmp(count, kMediumCopySize);
245   __ j(below_equal, &medium_size);
246   __ cmp(dst, src);
247   __ j(above, &backward);
248 
249   {
250     // |dst| is a lower address than |src|. Copy front-to-back.
251     Label unaligned_source, move_last_15, skip_last_move;
252     __ mov(eax, src);
253     __ sub(eax, dst);
254     __ cmp(eax, kMinMoveDistance);
255     __ j(below, &forward_much_overlap);
256     // Copy first 16 bytes.
257     __ movdqu(xmm0, Operand(src, 0));
258     __ movdqu(Operand(dst, 0), xmm0);
259     // Determine distance to alignment: 16 - (dst & 0xF).
260     __ mov(edx, dst);
261     __ and_(edx, 0xF);
262     __ neg(edx);
263     __ add(edx, Immediate(16));
264     __ add(dst, edx);
265     __ add(src, edx);
266     __ sub(count, edx);
267     // dst is now aligned. Main copy loop.
268     __ mov(loop_count, count);
269     __ shr(loop_count, 6);
270     // Check if src is also aligned.
271     __ test(src, Immediate(0xF));
272     __ j(not_zero, &unaligned_source);
273     // Copy loop for aligned source and destination.
274     MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
275     // At most 15 bytes to copy. Copy 16 bytes at end of string.
276     __ bind(&move_last_15);
277     __ and_(count, 0xF);
278     __ j(zero, &skip_last_move, Label::kNear);
279     __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
280     __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
281     __ bind(&skip_last_move);
282     MemMoveEmitPopAndReturn(&masm);
283 
284     // Copy loop for unaligned source and aligned destination.
285     __ bind(&unaligned_source);
286     MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
287     __ jmp(&move_last_15);
288 
289     // Less than kMinMoveDistance offset between dst and src.
290     Label loop_until_aligned, last_15_much_overlap;
291     __ bind(&loop_until_aligned);
292     __ mov_b(eax, Operand(src, 0));
293     __ inc(src);
294     __ mov_b(Operand(dst, 0), eax);
295     __ inc(dst);
296     __ dec(count);
297     __ bind(&forward_much_overlap);  // Entry point into this block.
298     __ test(dst, Immediate(0xF));
299     __ j(not_zero, &loop_until_aligned);
300     // dst is now aligned, src can't be. Main copy loop.
301     __ mov(loop_count, count);
302     __ shr(loop_count, 6);
303     MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
304                         FORWARD, MOVE_UNALIGNED);
305     __ bind(&last_15_much_overlap);
306     __ and_(count, 0xF);
307     __ j(zero, &pop_and_return);
308     __ cmp(count, kSmallCopySize);
309     __ j(below_equal, &small_size);
310     __ jmp(&medium_size);
311   }
312 
313   {
314     // |dst| is a higher address than |src|. Copy backwards.
315     Label unaligned_source, move_first_15, skip_last_move;
316     __ bind(&backward);
317     // |dst| and |src| always point to the end of what's left to copy.
318     __ add(dst, count);
319     __ add(src, count);
320     __ mov(eax, dst);
321     __ sub(eax, src);
322     __ cmp(eax, kMinMoveDistance);
323     __ j(below, &backward_much_overlap);
324     // Copy last 16 bytes.
325     __ movdqu(xmm0, Operand(src, -0x10));
326     __ movdqu(Operand(dst, -0x10), xmm0);
327     // Find distance to alignment: dst & 0xF
328     __ mov(edx, dst);
329     __ and_(edx, 0xF);
330     __ sub(dst, edx);
331     __ sub(src, edx);
332     __ sub(count, edx);
333     // dst is now aligned. Main copy loop.
334     __ mov(loop_count, count);
335     __ shr(loop_count, 6);
336     // Check if src is also aligned.
337     __ test(src, Immediate(0xF));
338     __ j(not_zero, &unaligned_source);
339     // Copy loop for aligned source and destination.
340     MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
341     // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
342     __ bind(&move_first_15);
343     __ and_(count, 0xF);
344     __ j(zero, &skip_last_move, Label::kNear);
345     __ sub(src, count);
346     __ sub(dst, count);
347     __ movdqu(xmm0, Operand(src, 0));
348     __ movdqu(Operand(dst, 0), 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_first_15, BACKWARD, MOVE_UNALIGNED);
355     __ jmp(&move_first_15);
356 
357     // Less than kMinMoveDistance offset between dst and src.
358     Label loop_until_aligned, first_15_much_overlap;
359     __ bind(&loop_until_aligned);
360     __ dec(src);
361     __ dec(dst);
362     __ mov_b(eax, Operand(src, 0));
363     __ mov_b(Operand(dst, 0), eax);
364     __ dec(count);
365     __ bind(&backward_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, &first_15_much_overlap,
372                         BACKWARD, MOVE_UNALIGNED);
373     __ bind(&first_15_much_overlap);
374     __ and_(count, 0xF);
375     __ j(zero, &pop_and_return);
376     // Small/medium handlers expect dst/src to point to the beginning.
377     __ sub(dst, count);
378     __ sub(src, count);
379     __ cmp(count, kSmallCopySize);
380     __ j(below_equal, &small_size);
381     __ jmp(&medium_size);
382   }
383   {
384     // Special handlers for 9 <= copy_size < 64. No assumptions about
385     // alignment or move distance, so all reads must be unaligned and
386     // must happen before any writes.
387     Label medium_handlers, f9_16, f17_32, f33_48, f49_63;
388 
389     __ bind(&f9_16);
390     __ movsd(xmm0, Operand(src, 0));
391     __ movsd(xmm1, Operand(src, count, times_1, -8));
392     __ movsd(Operand(dst, 0), xmm0);
393     __ movsd(Operand(dst, count, times_1, -8), xmm1);
394     MemMoveEmitPopAndReturn(&masm);
395 
396     __ bind(&f17_32);
397     __ movdqu(xmm0, Operand(src, 0));
398     __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
399     __ movdqu(Operand(dst, 0x00), xmm0);
400     __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
401     MemMoveEmitPopAndReturn(&masm);
402 
403     __ bind(&f33_48);
404     __ movdqu(xmm0, Operand(src, 0x00));
405     __ movdqu(xmm1, Operand(src, 0x10));
406     __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
407     __ movdqu(Operand(dst, 0x00), xmm0);
408     __ movdqu(Operand(dst, 0x10), xmm1);
409     __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
410     MemMoveEmitPopAndReturn(&masm);
411 
412     __ bind(&f49_63);
413     __ movdqu(xmm0, Operand(src, 0x00));
414     __ movdqu(xmm1, Operand(src, 0x10));
415     __ movdqu(xmm2, Operand(src, 0x20));
416     __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
417     __ movdqu(Operand(dst, 0x00), xmm0);
418     __ movdqu(Operand(dst, 0x10), xmm1);
419     __ movdqu(Operand(dst, 0x20), xmm2);
420     __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
421     MemMoveEmitPopAndReturn(&masm);
422 
423     __ bind(&medium_handlers);
424     __ dd(conv.address(&f9_16));
425     __ dd(conv.address(&f17_32));
426     __ dd(conv.address(&f33_48));
427     __ dd(conv.address(&f49_63));
428 
429     __ bind(&medium_size);  // Entry point into this block.
430     __ mov(eax, count);
431     __ dec(eax);
432     __ shr(eax, 4);
433     if (FLAG_debug_code) {
434       Label ok;
435       __ cmp(eax, 3);
436       __ j(below_equal, &ok);
437       __ int3();
438       __ bind(&ok);
439     }
440     __ mov(eax, Operand(eax, times_4, conv.address(&medium_handlers)));
441     __ jmp(eax);
442   }
443   {
444     // Specialized copiers for copy_size <= 8 bytes.
445     Label small_handlers, f0, f1, f2, f3, f4, f5_8;
446     __ bind(&f0);
447     MemMoveEmitPopAndReturn(&masm);
448 
449     __ bind(&f1);
450     __ mov_b(eax, Operand(src, 0));
451     __ mov_b(Operand(dst, 0), eax);
452     MemMoveEmitPopAndReturn(&masm);
453 
454     __ bind(&f2);
455     __ mov_w(eax, Operand(src, 0));
456     __ mov_w(Operand(dst, 0), eax);
457     MemMoveEmitPopAndReturn(&masm);
458 
459     __ bind(&f3);
460     __ mov_w(eax, Operand(src, 0));
461     __ mov_b(edx, Operand(src, 2));
462     __ mov_w(Operand(dst, 0), eax);
463     __ mov_b(Operand(dst, 2), edx);
464     MemMoveEmitPopAndReturn(&masm);
465 
466     __ bind(&f4);
467     __ mov(eax, Operand(src, 0));
468     __ mov(Operand(dst, 0), eax);
469     MemMoveEmitPopAndReturn(&masm);
470 
471     __ bind(&f5_8);
472     __ mov(eax, Operand(src, 0));
473     __ mov(edx, Operand(src, count, times_1, -4));
474     __ mov(Operand(dst, 0), eax);
475     __ mov(Operand(dst, count, times_1, -4), edx);
476     MemMoveEmitPopAndReturn(&masm);
477 
478     __ bind(&small_handlers);
479     __ dd(conv.address(&f0));
480     __ dd(conv.address(&f1));
481     __ dd(conv.address(&f2));
482     __ dd(conv.address(&f3));
483     __ dd(conv.address(&f4));
484     __ dd(conv.address(&f5_8));
485     __ dd(conv.address(&f5_8));
486     __ dd(conv.address(&f5_8));
487     __ dd(conv.address(&f5_8));
488 
489     __ bind(&small_size);  // Entry point into this block.
490     if (FLAG_debug_code) {
491       Label ok;
492       __ cmp(count, 8);
493       __ j(below_equal, &ok);
494       __ int3();
495       __ bind(&ok);
496     }
497     __ mov(eax, Operand(count, times_4, conv.address(&small_handlers)));
498     __ jmp(eax);
499   }
500 
501   __ bind(&pop_and_return);
502   MemMoveEmitPopAndReturn(&masm);
503 
504   CodeDesc desc;
505   masm.GetCode(&desc);
506   ASSERT(!RelocInfo::RequiresRelocation(desc));
507   CPU::FlushICache(buffer, actual_size);
508   OS::ProtectCode(buffer, actual_size);
509   // TODO(jkummerow): It would be nice to register this code creation event
510   // with the PROFILE / GDBJIT system.
511   return FUNCTION_CAST<MemMoveFunction>(buffer);
512 }
513 
514 
515 #undef __
516 
517 // -------------------------------------------------------------------------
518 // Code generators
519 
520 #define __ ACCESS_MASM(masm)
521 
522 
GenerateMapChangeElementsTransition(MacroAssembler * masm,AllocationSiteMode mode,Label * allocation_memento_found)523 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
524     MacroAssembler* masm, AllocationSiteMode mode,
525     Label* allocation_memento_found) {
526   // ----------- S t a t e -------------
527   //  -- eax    : value
528   //  -- ebx    : target map
529   //  -- ecx    : key
530   //  -- edx    : receiver
531   //  -- esp[0] : return address
532   // -----------------------------------
533   if (mode == TRACK_ALLOCATION_SITE) {
534     ASSERT(allocation_memento_found != NULL);
535     __ JumpIfJSArrayHasAllocationMemento(edx, edi, allocation_memento_found);
536   }
537 
538   // Set transitioned map.
539   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
540   __ RecordWriteField(edx,
541                       HeapObject::kMapOffset,
542                       ebx,
543                       edi,
544                       kDontSaveFPRegs,
545                       EMIT_REMEMBERED_SET,
546                       OMIT_SMI_CHECK);
547 }
548 
549 
GenerateSmiToDouble(MacroAssembler * masm,AllocationSiteMode mode,Label * fail)550 void ElementsTransitionGenerator::GenerateSmiToDouble(
551     MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
552   // ----------- S t a t e -------------
553   //  -- eax    : value
554   //  -- ebx    : target map
555   //  -- ecx    : key
556   //  -- edx    : receiver
557   //  -- esp[0] : return address
558   // -----------------------------------
559   Label loop, entry, convert_hole, gc_required, only_change_map;
560 
561   if (mode == TRACK_ALLOCATION_SITE) {
562     __ JumpIfJSArrayHasAllocationMemento(edx, edi, fail);
563   }
564 
565   // Check for empty arrays, which only require a map transition and no changes
566   // to the backing store.
567   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
568   __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
569   __ j(equal, &only_change_map);
570 
571   __ push(eax);
572   __ push(ebx);
573 
574   __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
575 
576   // Allocate new FixedDoubleArray.
577   // edx: receiver
578   // edi: length of source FixedArray (smi-tagged)
579   AllocationFlags flags =
580       static_cast<AllocationFlags>(TAG_OBJECT | DOUBLE_ALIGNMENT);
581   __ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi,
582               REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags);
583 
584   // eax: destination FixedDoubleArray
585   // edi: number of elements
586   // edx: receiver
587   __ mov(FieldOperand(eax, HeapObject::kMapOffset),
588          Immediate(masm->isolate()->factory()->fixed_double_array_map()));
589   __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
590   __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
591   // Replace receiver's backing store with newly created FixedDoubleArray.
592   __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
593   __ mov(ebx, eax);
594   __ RecordWriteField(edx,
595                       JSObject::kElementsOffset,
596                       ebx,
597                       edi,
598                       kDontSaveFPRegs,
599                       EMIT_REMEMBERED_SET,
600                       OMIT_SMI_CHECK);
601 
602   __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
603 
604   // Prepare for conversion loop.
605   ExternalReference canonical_the_hole_nan_reference =
606       ExternalReference::address_of_the_hole_nan();
607   XMMRegister the_hole_nan = xmm1;
608   __ movsd(the_hole_nan,
609            Operand::StaticVariable(canonical_the_hole_nan_reference));
610   __ jmp(&entry);
611 
612   // Call into runtime if GC is required.
613   __ bind(&gc_required);
614   // Restore registers before jumping into runtime.
615   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
616   __ pop(ebx);
617   __ pop(eax);
618   __ jmp(fail);
619 
620   // Convert and copy elements
621   // esi: source FixedArray
622   __ bind(&loop);
623   __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
624   // ebx: current element from source
625   // edi: index of current element
626   __ JumpIfNotSmi(ebx, &convert_hole);
627 
628   // Normal smi, convert it to double and store.
629   __ SmiUntag(ebx);
630   __ Cvtsi2sd(xmm0, ebx);
631   __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
632            xmm0);
633   __ jmp(&entry);
634 
635   // Found hole, store hole_nan_as_double instead.
636   __ bind(&convert_hole);
637 
638   if (FLAG_debug_code) {
639     __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
640     __ Assert(equal, kObjectFoundInSmiOnlyArray);
641   }
642 
643   __ movsd(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
644            the_hole_nan);
645 
646   __ bind(&entry);
647   __ sub(edi, Immediate(Smi::FromInt(1)));
648   __ j(not_sign, &loop);
649 
650   __ pop(ebx);
651   __ pop(eax);
652 
653   // Restore esi.
654   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
655 
656   __ bind(&only_change_map);
657   // eax: value
658   // ebx: target map
659   // Set transitioned map.
660   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
661   __ RecordWriteField(edx,
662                       HeapObject::kMapOffset,
663                       ebx,
664                       edi,
665                       kDontSaveFPRegs,
666                       OMIT_REMEMBERED_SET,
667                       OMIT_SMI_CHECK);
668 }
669 
670 
GenerateDoubleToObject(MacroAssembler * masm,AllocationSiteMode mode,Label * fail)671 void ElementsTransitionGenerator::GenerateDoubleToObject(
672     MacroAssembler* masm, AllocationSiteMode mode, Label* fail) {
673   // ----------- S t a t e -------------
674   //  -- eax    : value
675   //  -- ebx    : target map
676   //  -- ecx    : key
677   //  -- edx    : receiver
678   //  -- esp[0] : return address
679   // -----------------------------------
680   Label loop, entry, convert_hole, gc_required, only_change_map, success;
681 
682   if (mode == TRACK_ALLOCATION_SITE) {
683     __ JumpIfJSArrayHasAllocationMemento(edx, edi, fail);
684   }
685 
686   // Check for empty arrays, which only require a map transition and no changes
687   // to the backing store.
688   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
689   __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
690   __ j(equal, &only_change_map);
691 
692   __ push(eax);
693   __ push(edx);
694   __ push(ebx);
695 
696   __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
697 
698   // Allocate new FixedArray.
699   // ebx: length of source FixedDoubleArray (smi-tagged)
700   __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
701   __ Allocate(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
702 
703   // eax: destination FixedArray
704   // ebx: number of elements
705   __ mov(FieldOperand(eax, HeapObject::kMapOffset),
706          Immediate(masm->isolate()->factory()->fixed_array_map()));
707   __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
708   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
709 
710   __ jmp(&entry);
711 
712   // ebx: target map
713   // edx: receiver
714   // Set transitioned map.
715   __ bind(&only_change_map);
716   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
717   __ RecordWriteField(edx,
718                       HeapObject::kMapOffset,
719                       ebx,
720                       edi,
721                       kDontSaveFPRegs,
722                       OMIT_REMEMBERED_SET,
723                       OMIT_SMI_CHECK);
724   __ jmp(&success);
725 
726   // Call into runtime if GC is required.
727   __ bind(&gc_required);
728   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
729   __ pop(ebx);
730   __ pop(edx);
731   __ pop(eax);
732   __ jmp(fail);
733 
734   // Box doubles into heap numbers.
735   // edi: source FixedDoubleArray
736   // eax: destination FixedArray
737   __ bind(&loop);
738   // ebx: index of current element (smi-tagged)
739   uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
740   __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
741   __ j(equal, &convert_hole);
742 
743   // Non-hole double, copy value into a heap number.
744   __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
745   // edx: new heap number
746   __ movsd(xmm0,
747            FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
748   __ movsd(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
749   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
750   __ mov(esi, ebx);
751   __ RecordWriteArray(eax,
752                       edx,
753                       esi,
754                       kDontSaveFPRegs,
755                       EMIT_REMEMBERED_SET,
756                       OMIT_SMI_CHECK);
757   __ jmp(&entry, Label::kNear);
758 
759   // Replace the-hole NaN with the-hole pointer.
760   __ bind(&convert_hole);
761   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
762          masm->isolate()->factory()->the_hole_value());
763 
764   __ bind(&entry);
765   __ sub(ebx, Immediate(Smi::FromInt(1)));
766   __ j(not_sign, &loop);
767 
768   __ pop(ebx);
769   __ pop(edx);
770   // ebx: target map
771   // edx: receiver
772   // Set transitioned map.
773   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
774   __ RecordWriteField(edx,
775                       HeapObject::kMapOffset,
776                       ebx,
777                       edi,
778                       kDontSaveFPRegs,
779                       OMIT_REMEMBERED_SET,
780                       OMIT_SMI_CHECK);
781   // Replace receiver's backing store with newly created and filled FixedArray.
782   __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
783   __ RecordWriteField(edx,
784                       JSObject::kElementsOffset,
785                       eax,
786                       edi,
787                       kDontSaveFPRegs,
788                       EMIT_REMEMBERED_SET,
789                       OMIT_SMI_CHECK);
790 
791   // Restore registers.
792   __ pop(eax);
793   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
794 
795   __ bind(&success);
796 }
797 
798 
Generate(MacroAssembler * masm,Factory * factory,Register string,Register index,Register result,Label * call_runtime)799 void StringCharLoadGenerator::Generate(MacroAssembler* masm,
800                                        Factory* factory,
801                                        Register string,
802                                        Register index,
803                                        Register result,
804                                        Label* call_runtime) {
805   // Fetch the instance type of the receiver into result register.
806   __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
807   __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
808 
809   // We need special handling for indirect strings.
810   Label check_sequential;
811   __ test(result, Immediate(kIsIndirectStringMask));
812   __ j(zero, &check_sequential, Label::kNear);
813 
814   // Dispatch on the indirect string shape: slice or cons.
815   Label cons_string;
816   __ test(result, Immediate(kSlicedNotConsMask));
817   __ j(zero, &cons_string, Label::kNear);
818 
819   // Handle slices.
820   Label indirect_string_loaded;
821   __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset));
822   __ SmiUntag(result);
823   __ add(index, result);
824   __ mov(string, FieldOperand(string, SlicedString::kParentOffset));
825   __ jmp(&indirect_string_loaded, Label::kNear);
826 
827   // Handle cons strings.
828   // Check whether the right hand side is the empty string (i.e. if
829   // this is really a flat string in a cons string). If that is not
830   // the case we would rather go to the runtime system now to flatten
831   // the string.
832   __ bind(&cons_string);
833   __ cmp(FieldOperand(string, ConsString::kSecondOffset),
834          Immediate(factory->empty_string()));
835   __ j(not_equal, call_runtime);
836   __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
837 
838   __ bind(&indirect_string_loaded);
839   __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
840   __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
841 
842   // Distinguish sequential and external strings. Only these two string
843   // representations can reach here (slices and flat cons strings have been
844   // reduced to the underlying sequential or external string).
845   Label seq_string;
846   __ bind(&check_sequential);
847   STATIC_ASSERT(kSeqStringTag == 0);
848   __ test(result, Immediate(kStringRepresentationMask));
849   __ j(zero, &seq_string, Label::kNear);
850 
851   // Handle external strings.
852   Label ascii_external, done;
853   if (FLAG_debug_code) {
854     // Assert that we do not have a cons or slice (indirect strings) here.
855     // Sequential strings have already been ruled out.
856     __ test(result, Immediate(kIsIndirectStringMask));
857     __ Assert(zero, kExternalStringExpectedButNotFound);
858   }
859   // Rule out short external strings.
860   STATIC_ASSERT(kShortExternalStringTag != 0);
861   __ test_b(result, kShortExternalStringMask);
862   __ j(not_zero, call_runtime);
863   // Check encoding.
864   STATIC_ASSERT(kTwoByteStringTag == 0);
865   __ test_b(result, kStringEncodingMask);
866   __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset));
867   __ j(not_equal, &ascii_external, Label::kNear);
868   // Two-byte string.
869   __ movzx_w(result, Operand(result, index, times_2, 0));
870   __ jmp(&done, Label::kNear);
871   __ bind(&ascii_external);
872   // Ascii string.
873   __ movzx_b(result, Operand(result, index, times_1, 0));
874   __ jmp(&done, Label::kNear);
875 
876   // Dispatch on the encoding: ASCII or two-byte.
877   Label ascii;
878   __ bind(&seq_string);
879   STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
880   STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
881   __ test(result, Immediate(kStringEncodingMask));
882   __ j(not_zero, &ascii, Label::kNear);
883 
884   // Two-byte string.
885   // Load the two-byte character code into the result register.
886   __ movzx_w(result, FieldOperand(string,
887                                   index,
888                                   times_2,
889                                   SeqTwoByteString::kHeaderSize));
890   __ jmp(&done, Label::kNear);
891 
892   // Ascii string.
893   // Load the byte into the result register.
894   __ bind(&ascii);
895   __ movzx_b(result, FieldOperand(string,
896                                   index,
897                                   times_1,
898                                   SeqOneByteString::kHeaderSize));
899   __ bind(&done);
900 }
901 
902 
ExpConstant(int index)903 static Operand ExpConstant(int index) {
904   return Operand::StaticVariable(ExternalReference::math_exp_constants(index));
905 }
906 
907 
EmitMathExp(MacroAssembler * masm,XMMRegister input,XMMRegister result,XMMRegister double_scratch,Register temp1,Register temp2)908 void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
909                                    XMMRegister input,
910                                    XMMRegister result,
911                                    XMMRegister double_scratch,
912                                    Register temp1,
913                                    Register temp2) {
914   ASSERT(!input.is(double_scratch));
915   ASSERT(!input.is(result));
916   ASSERT(!result.is(double_scratch));
917   ASSERT(!temp1.is(temp2));
918   ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
919 
920   Label done;
921 
922   __ movsd(double_scratch, ExpConstant(0));
923   __ xorpd(result, result);
924   __ ucomisd(double_scratch, input);
925   __ j(above_equal, &done);
926   __ ucomisd(input, ExpConstant(1));
927   __ movsd(result, ExpConstant(2));
928   __ j(above_equal, &done);
929   __ movsd(double_scratch, ExpConstant(3));
930   __ movsd(result, ExpConstant(4));
931   __ mulsd(double_scratch, input);
932   __ addsd(double_scratch, result);
933   __ movd(temp2, double_scratch);
934   __ subsd(double_scratch, result);
935   __ movsd(result, ExpConstant(6));
936   __ mulsd(double_scratch, ExpConstant(5));
937   __ subsd(double_scratch, input);
938   __ subsd(result, double_scratch);
939   __ movsd(input, double_scratch);
940   __ mulsd(input, double_scratch);
941   __ mulsd(result, input);
942   __ mov(temp1, temp2);
943   __ mulsd(result, ExpConstant(7));
944   __ subsd(result, double_scratch);
945   __ add(temp1, Immediate(0x1ff800));
946   __ addsd(result, ExpConstant(8));
947   __ and_(temp2, Immediate(0x7ff));
948   __ shr(temp1, 11);
949   __ shl(temp1, 20);
950   __ movd(input, temp1);
951   __ pshufd(input, input, static_cast<uint8_t>(0xe1));  // Order: 11 10 00 01
952   __ movsd(double_scratch, Operand::StaticArray(
953       temp2, times_8, ExternalReference::math_exp_log_table()));
954   __ orps(input, double_scratch);
955   __ mulsd(result, input);
956   __ bind(&done);
957 }
958 
959 #undef __
960 
961 
CodeAgingHelper()962 CodeAgingHelper::CodeAgingHelper() {
963   ASSERT(young_sequence_.length() == kNoCodeAgeSequenceLength);
964   CodePatcher patcher(young_sequence_.start(), young_sequence_.length());
965   patcher.masm()->push(ebp);
966   patcher.masm()->mov(ebp, esp);
967   patcher.masm()->push(esi);
968   patcher.masm()->push(edi);
969 }
970 
971 
972 #ifdef DEBUG
IsOld(byte * candidate) const973 bool CodeAgingHelper::IsOld(byte* candidate) const {
974   return *candidate == kCallOpcode;
975 }
976 #endif
977 
978 
IsYoungSequence(Isolate * isolate,byte * sequence)979 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
980   bool result = isolate->code_aging_helper()->IsYoung(sequence);
981   ASSERT(result || isolate->code_aging_helper()->IsOld(sequence));
982   return result;
983 }
984 
985 
GetCodeAgeAndParity(Isolate * isolate,byte * sequence,Age * age,MarkingParity * parity)986 void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
987                                MarkingParity* parity) {
988   if (IsYoungSequence(isolate, sequence)) {
989     *age = kNoAgeCodeAge;
990     *parity = NO_MARKING_PARITY;
991   } else {
992     sequence++;  // Skip the kCallOpcode byte
993     Address target_address = sequence + *reinterpret_cast<int*>(sequence) +
994         Assembler::kCallTargetAddressOffset;
995     Code* stub = GetCodeFromTargetAddress(target_address);
996     GetCodeAgeAndParity(stub, age, parity);
997   }
998 }
999 
1000 
PatchPlatformCodeAge(Isolate * isolate,byte * sequence,Code::Age age,MarkingParity parity)1001 void Code::PatchPlatformCodeAge(Isolate* isolate,
1002                                 byte* sequence,
1003                                 Code::Age age,
1004                                 MarkingParity parity) {
1005   uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
1006   if (age == kNoAgeCodeAge) {
1007     isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
1008     CPU::FlushICache(sequence, young_length);
1009   } else {
1010     Code* stub = GetCodeAgeStub(isolate, age, parity);
1011     CodePatcher patcher(sequence, young_length);
1012     patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32);
1013   }
1014 }
1015 
1016 
1017 } }  // namespace v8::internal
1018 
1019 #endif  // V8_TARGET_ARCH_IA32
1020