V8 Project
codegen-ia32.cc
Go to the documentation of this file.
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/heap.h"
11 #include "src/macro-assembler.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 
17 // -------------------------------------------------------------------------
18 // Platform-specific RuntimeCallHelper functions.
19 
20 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
21  masm->EnterFrame(StackFrame::INTERNAL);
22  DCHECK(!masm->has_frame());
23  masm->set_has_frame(true);
24 }
25 
26 
27 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
28  masm->LeaveFrame(StackFrame::INTERNAL);
29  DCHECK(masm->has_frame());
30  masm->set_has_frame(false);
31 }
32 
33 
34 #define __ masm.
35 
36 
38  if (!FLAG_fast_math) return &std::exp;
39  size_t actual_size;
40  byte* buffer =
41  static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
42  if (buffer == NULL) return &std::exp;
43  ExternalReference::InitializeMathExpData();
44 
45  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
46  // esp[1 * kPointerSize]: raw double input
47  // esp[0 * kPointerSize]: return address
48  {
49  XMMRegister input = xmm1;
50  XMMRegister result = xmm2;
51  __ movsd(input, Operand(esp, 1 * kPointerSize));
52  __ push(eax);
53  __ push(ebx);
54 
55  MathExpGenerator::EmitMathExp(&masm, input, result, xmm0, eax, ebx);
56 
57  __ pop(ebx);
58  __ pop(eax);
59  __ movsd(Operand(esp, 1 * kPointerSize), result);
60  __ fld_d(Operand(esp, 1 * kPointerSize));
61  __ Ret();
62  }
63 
64  CodeDesc desc;
65  masm.GetCode(&desc);
66  DCHECK(!RelocInfo::RequiresRelocation(desc));
67 
68  CpuFeatures::FlushICache(buffer, actual_size);
69  base::OS::ProtectCode(buffer, actual_size);
70  return FUNCTION_CAST<UnaryMathFunction>(buffer);
71 }
72 
73 
75  size_t actual_size;
76  // Allocate buffer in executable space.
77  byte* buffer =
78  static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, 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  DCHECK(!RelocInfo::RequiresRelocation(desc));
96 
97  CpuFeatures::FlushICache(buffer, actual_size);
98  base::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)
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 
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:
180  explicit LabelConverter(byte* buffer) : buffer_(buffer) {}
181  int32_t address(Label* l) const {
182  return reinterpret_cast<int32_t>(buffer_) + l->pos();
183  }
184  private:
185  byte* buffer_;
186 };
187 
188 
189 MemMoveFunction CreateMemMoveFunction() {
190  size_t actual_size;
191  // Allocate buffer in executable space.
192  byte* buffer =
193  static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
194  if (buffer == NULL) return NULL;
195  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
196  LabelConverter conv(buffer);
197 
198  // Generated code is put into a fixed, unmovable buffer, and not into
199  // the V8 heap. We can't, and don't, refer to any relocatable addresses
200  // (e.g. the JavaScript nan-object).
201 
202  // 32-bit C declaration function calls pass arguments on stack.
203 
204  // Stack layout:
205  // esp[12]: Third argument, size.
206  // esp[8]: Second argument, source pointer.
207  // esp[4]: First argument, destination pointer.
208  // esp[0]: return address
209 
210  const int kDestinationOffset = 1 * kPointerSize;
211  const int kSourceOffset = 2 * kPointerSize;
212  const int kSizeOffset = 3 * kPointerSize;
213 
214  // When copying up to this many bytes, use special "small" handlers.
215  const size_t kSmallCopySize = 8;
216  // When copying up to this many bytes, use special "medium" handlers.
217  const size_t kMediumCopySize = 63;
218  // When non-overlapping region of src and dst is less than this,
219  // use a more careful implementation (slightly slower).
220  const size_t kMinMoveDistance = 16;
221  // Note that these values are dictated by the implementation below,
222  // do not just change them and hope things will work!
223 
224  int stack_offset = 0; // Update if we change the stack height.
225 
226  Label backward, backward_much_overlap;
227  Label forward_much_overlap, small_size, medium_size, pop_and_return;
228  __ push(edi);
229  __ push(esi);
230  stack_offset += 2 * kPointerSize;
231  Register dst = edi;
232  Register src = esi;
233  Register count = ecx;
234  Register loop_count = edx;
235  __ mov(dst, Operand(esp, stack_offset + kDestinationOffset));
236  __ mov(src, Operand(esp, stack_offset + kSourceOffset));
237  __ mov(count, Operand(esp, stack_offset + kSizeOffset));
238 
239  __ cmp(dst, src);
240  __ j(equal, &pop_and_return);
241 
242  __ prefetch(Operand(src, 0), 1);
243  __ cmp(count, kSmallCopySize);
244  __ j(below_equal, &small_size);
245  __ cmp(count, kMediumCopySize);
246  __ j(below_equal, &medium_size);
247  __ cmp(dst, src);
248  __ j(above, &backward);
249 
250  {
251  // |dst| is a lower address than |src|. Copy front-to-back.
252  Label unaligned_source, move_last_15, skip_last_move;
253  __ mov(eax, src);
254  __ sub(eax, dst);
255  __ cmp(eax, kMinMoveDistance);
256  __ j(below, &forward_much_overlap);
257  // Copy first 16 bytes.
258  __ movdqu(xmm0, Operand(src, 0));
259  __ movdqu(Operand(dst, 0), xmm0);
260  // Determine distance to alignment: 16 - (dst & 0xF).
261  __ mov(edx, dst);
262  __ and_(edx, 0xF);
263  __ neg(edx);
264  __ add(edx, Immediate(16));
265  __ add(dst, edx);
266  __ add(src, edx);
267  __ sub(count, edx);
268  // dst is now aligned. Main copy loop.
269  __ mov(loop_count, count);
270  __ shr(loop_count, 6);
271  // Check if src is also aligned.
272  __ test(src, Immediate(0xF));
273  __ j(not_zero, &unaligned_source);
274  // Copy loop for aligned source and destination.
275  MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED);
276  // At most 15 bytes to copy. Copy 16 bytes at end of string.
277  __ bind(&move_last_15);
278  __ and_(count, 0xF);
279  __ j(zero, &skip_last_move, Label::kNear);
280  __ movdqu(xmm0, Operand(src, count, times_1, -0x10));
281  __ movdqu(Operand(dst, count, times_1, -0x10), xmm0);
282  __ bind(&skip_last_move);
283  MemMoveEmitPopAndReturn(&masm);
284 
285  // Copy loop for unaligned source and aligned destination.
286  __ bind(&unaligned_source);
287  MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED);
288  __ jmp(&move_last_15);
289 
290  // Less than kMinMoveDistance offset between dst and src.
291  Label loop_until_aligned, last_15_much_overlap;
292  __ bind(&loop_until_aligned);
293  __ mov_b(eax, Operand(src, 0));
294  __ inc(src);
295  __ mov_b(Operand(dst, 0), eax);
296  __ inc(dst);
297  __ dec(count);
298  __ bind(&forward_much_overlap); // Entry point into this block.
299  __ test(dst, Immediate(0xF));
300  __ j(not_zero, &loop_until_aligned);
301  // dst is now aligned, src can't be. Main copy loop.
302  __ mov(loop_count, count);
303  __ shr(loop_count, 6);
304  MemMoveEmitMainLoop(&masm, &last_15_much_overlap,
305  FORWARD, MOVE_UNALIGNED);
306  __ bind(&last_15_much_overlap);
307  __ and_(count, 0xF);
308  __ j(zero, &pop_and_return);
309  __ cmp(count, kSmallCopySize);
310  __ j(below_equal, &small_size);
311  __ jmp(&medium_size);
312  }
313 
314  {
315  // |dst| is a higher address than |src|. Copy backwards.
316  Label unaligned_source, move_first_15, skip_last_move;
317  __ bind(&backward);
318  // |dst| and |src| always point to the end of what's left to copy.
319  __ add(dst, count);
320  __ add(src, count);
321  __ mov(eax, dst);
322  __ sub(eax, src);
323  __ cmp(eax, kMinMoveDistance);
324  __ j(below, &backward_much_overlap);
325  // Copy last 16 bytes.
326  __ movdqu(xmm0, Operand(src, -0x10));
327  __ movdqu(Operand(dst, -0x10), xmm0);
328  // Find distance to alignment: dst & 0xF
329  __ mov(edx, dst);
330  __ and_(edx, 0xF);
331  __ sub(dst, edx);
332  __ sub(src, edx);
333  __ sub(count, edx);
334  // dst is now aligned. Main copy loop.
335  __ mov(loop_count, count);
336  __ shr(loop_count, 6);
337  // Check if src is also aligned.
338  __ test(src, Immediate(0xF));
339  __ j(not_zero, &unaligned_source);
340  // Copy loop for aligned source and destination.
341  MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED);
342  // At most 15 bytes to copy. Copy 16 bytes at beginning of string.
343  __ bind(&move_first_15);
344  __ and_(count, 0xF);
345  __ j(zero, &skip_last_move, Label::kNear);
346  __ sub(src, count);
347  __ sub(dst, count);
348  __ movdqu(xmm0, Operand(src, 0));
349  __ movdqu(Operand(dst, 0), xmm0);
350  __ bind(&skip_last_move);
351  MemMoveEmitPopAndReturn(&masm);
352 
353  // Copy loop for unaligned source and aligned destination.
354  __ bind(&unaligned_source);
355  MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED);
356  __ jmp(&move_first_15);
357 
358  // Less than kMinMoveDistance offset between dst and src.
359  Label loop_until_aligned, first_15_much_overlap;
360  __ bind(&loop_until_aligned);
361  __ dec(src);
362  __ dec(dst);
363  __ mov_b(eax, Operand(src, 0));
364  __ mov_b(Operand(dst, 0), eax);
365  __ dec(count);
366  __ bind(&backward_much_overlap); // Entry point into this block.
367  __ test(dst, Immediate(0xF));
368  __ j(not_zero, &loop_until_aligned);
369  // dst is now aligned, src can't be. Main copy loop.
370  __ mov(loop_count, count);
371  __ shr(loop_count, 6);
372  MemMoveEmitMainLoop(&masm, &first_15_much_overlap,
373  BACKWARD, MOVE_UNALIGNED);
374  __ bind(&first_15_much_overlap);
375  __ and_(count, 0xF);
376  __ j(zero, &pop_and_return);
377  // Small/medium handlers expect dst/src to point to the beginning.
378  __ sub(dst, count);
379  __ sub(src, count);
380  __ cmp(count, kSmallCopySize);
381  __ j(below_equal, &small_size);
382  __ jmp(&medium_size);
383  }
384  {
385  // Special handlers for 9 <= copy_size < 64. No assumptions about
386  // alignment or move distance, so all reads must be unaligned and
387  // must happen before any writes.
388  Label medium_handlers, f9_16, f17_32, f33_48, f49_63;
389 
390  __ bind(&f9_16);
391  __ movsd(xmm0, Operand(src, 0));
392  __ movsd(xmm1, Operand(src, count, times_1, -8));
393  __ movsd(Operand(dst, 0), xmm0);
394  __ movsd(Operand(dst, count, times_1, -8), xmm1);
395  MemMoveEmitPopAndReturn(&masm);
396 
397  __ bind(&f17_32);
398  __ movdqu(xmm0, Operand(src, 0));
399  __ movdqu(xmm1, Operand(src, count, times_1, -0x10));
400  __ movdqu(Operand(dst, 0x00), xmm0);
401  __ movdqu(Operand(dst, count, times_1, -0x10), xmm1);
402  MemMoveEmitPopAndReturn(&masm);
403 
404  __ bind(&f33_48);
405  __ movdqu(xmm0, Operand(src, 0x00));
406  __ movdqu(xmm1, Operand(src, 0x10));
407  __ movdqu(xmm2, Operand(src, count, times_1, -0x10));
408  __ movdqu(Operand(dst, 0x00), xmm0);
409  __ movdqu(Operand(dst, 0x10), xmm1);
410  __ movdqu(Operand(dst, count, times_1, -0x10), xmm2);
411  MemMoveEmitPopAndReturn(&masm);
412 
413  __ bind(&f49_63);
414  __ movdqu(xmm0, Operand(src, 0x00));
415  __ movdqu(xmm1, Operand(src, 0x10));
416  __ movdqu(xmm2, Operand(src, 0x20));
417  __ movdqu(xmm3, Operand(src, count, times_1, -0x10));
418  __ movdqu(Operand(dst, 0x00), xmm0);
419  __ movdqu(Operand(dst, 0x10), xmm1);
420  __ movdqu(Operand(dst, 0x20), xmm2);
421  __ movdqu(Operand(dst, count, times_1, -0x10), xmm3);
422  MemMoveEmitPopAndReturn(&masm);
423 
424  __ bind(&medium_handlers);
425  __ dd(conv.address(&f9_16));
426  __ dd(conv.address(&f17_32));
427  __ dd(conv.address(&f33_48));
428  __ dd(conv.address(&f49_63));
429 
430  __ bind(&medium_size); // Entry point into this block.
431  __ mov(eax, count);
432  __ dec(eax);
433  __ shr(eax, 4);
434  if (FLAG_debug_code) {
435  Label ok;
436  __ cmp(eax, 3);
437  __ j(below_equal, &ok);
438  __ int3();
439  __ bind(&ok);
440  }
441  __ mov(eax, Operand(eax, times_4, conv.address(&medium_handlers)));
442  __ jmp(eax);
443  }
444  {
445  // Specialized copiers for copy_size <= 8 bytes.
446  Label small_handlers, f0, f1, f2, f3, f4, f5_8;
447  __ bind(&f0);
448  MemMoveEmitPopAndReturn(&masm);
449 
450  __ bind(&f1);
451  __ mov_b(eax, Operand(src, 0));
452  __ mov_b(Operand(dst, 0), eax);
453  MemMoveEmitPopAndReturn(&masm);
454 
455  __ bind(&f2);
456  __ mov_w(eax, Operand(src, 0));
457  __ mov_w(Operand(dst, 0), eax);
458  MemMoveEmitPopAndReturn(&masm);
459 
460  __ bind(&f3);
461  __ mov_w(eax, Operand(src, 0));
462  __ mov_b(edx, Operand(src, 2));
463  __ mov_w(Operand(dst, 0), eax);
464  __ mov_b(Operand(dst, 2), edx);
465  MemMoveEmitPopAndReturn(&masm);
466 
467  __ bind(&f4);
468  __ mov(eax, Operand(src, 0));
469  __ mov(Operand(dst, 0), eax);
470  MemMoveEmitPopAndReturn(&masm);
471 
472  __ bind(&f5_8);
473  __ mov(eax, Operand(src, 0));
474  __ mov(edx, Operand(src, count, times_1, -4));
475  __ mov(Operand(dst, 0), eax);
476  __ mov(Operand(dst, count, times_1, -4), edx);
477  MemMoveEmitPopAndReturn(&masm);
478 
479  __ bind(&small_handlers);
480  __ dd(conv.address(&f0));
481  __ dd(conv.address(&f1));
482  __ dd(conv.address(&f2));
483  __ dd(conv.address(&f3));
484  __ dd(conv.address(&f4));
485  __ dd(conv.address(&f5_8));
486  __ dd(conv.address(&f5_8));
487  __ dd(conv.address(&f5_8));
488  __ dd(conv.address(&f5_8));
489 
490  __ bind(&small_size); // Entry point into this block.
491  if (FLAG_debug_code) {
492  Label ok;
493  __ cmp(count, 8);
494  __ j(below_equal, &ok);
495  __ int3();
496  __ bind(&ok);
497  }
498  __ mov(eax, Operand(count, times_4, conv.address(&small_handlers)));
499  __ jmp(eax);
500  }
501 
502  __ bind(&pop_and_return);
503  MemMoveEmitPopAndReturn(&masm);
504 
505  CodeDesc desc;
506  masm.GetCode(&desc);
507  DCHECK(!RelocInfo::RequiresRelocation(desc));
508  CpuFeatures::FlushICache(buffer, actual_size);
509  base::OS::ProtectCode(buffer, actual_size);
510  // TODO(jkummerow): It would be nice to register this code creation event
511  // with the PROFILE / GDBJIT system.
512  return FUNCTION_CAST<MemMoveFunction>(buffer);
513 }
514 
515 
516 #undef __
517 
518 // -------------------------------------------------------------------------
519 // Code generators
520 
521 #define __ ACCESS_MASM(masm)
522 
523 
525  MacroAssembler* masm,
526  Register receiver,
527  Register key,
528  Register value,
529  Register target_map,
531  Label* allocation_memento_found) {
532  Register scratch = edi;
533  DCHECK(!AreAliased(receiver, key, value, target_map, scratch));
534 
535  if (mode == TRACK_ALLOCATION_SITE) {
536  DCHECK(allocation_memento_found != NULL);
537  __ JumpIfJSArrayHasAllocationMemento(
538  receiver, scratch, allocation_memento_found);
539  }
540 
541  // Set transitioned map.
542  __ mov(FieldOperand(receiver, HeapObject::kMapOffset), target_map);
543  __ RecordWriteField(receiver,
545  target_map,
546  scratch,
550 }
551 
552 
554  MacroAssembler* masm,
555  Register receiver,
556  Register key,
557  Register value,
558  Register target_map,
560  Label* fail) {
561  // Return address is on the stack.
562  DCHECK(receiver.is(edx));
563  DCHECK(key.is(ecx));
564  DCHECK(value.is(eax));
565  DCHECK(target_map.is(ebx));
566 
567  Label loop, entry, convert_hole, gc_required, only_change_map;
568 
569  if (mode == TRACK_ALLOCATION_SITE) {
570  __ JumpIfJSArrayHasAllocationMemento(edx, edi, fail);
571  }
572 
573  // Check for empty arrays, which only require a map transition and no changes
574  // to the backing store.
576  __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
577  __ j(equal, &only_change_map);
578 
579  __ push(eax);
580  __ push(ebx);
581 
583 
584  // Allocate new FixedDoubleArray.
585  // edx: receiver
586  // edi: length of source FixedArray (smi-tagged)
590  REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags);
591 
592  // eax: destination FixedDoubleArray
593  // edi: number of elements
594  // edx: receiver
596  Immediate(masm->isolate()->factory()->fixed_double_array_map()));
599  // Replace receiver's backing store with newly created FixedDoubleArray.
601  __ mov(ebx, eax);
602  __ RecordWriteField(edx,
604  ebx,
605  edi,
609 
611 
612  // Prepare for conversion loop.
613  ExternalReference canonical_the_hole_nan_reference =
614  ExternalReference::address_of_the_hole_nan();
615  XMMRegister the_hole_nan = xmm1;
616  __ movsd(the_hole_nan,
617  Operand::StaticVariable(canonical_the_hole_nan_reference));
618  __ jmp(&entry);
619 
620  // Call into runtime if GC is required.
621  __ bind(&gc_required);
622  // Restore registers before jumping into runtime.
624  __ pop(ebx);
625  __ pop(eax);
626  __ jmp(fail);
627 
628  // Convert and copy elements
629  // esi: source FixedArray
630  __ bind(&loop);
632  // ebx: current element from source
633  // edi: index of current element
634  __ JumpIfNotSmi(ebx, &convert_hole);
635 
636  // Normal smi, convert it to double and store.
637  __ SmiUntag(ebx);
638  __ Cvtsi2sd(xmm0, ebx);
640  xmm0);
641  __ jmp(&entry);
642 
643  // Found hole, store hole_nan_as_double instead.
644  __ bind(&convert_hole);
645 
646  if (FLAG_debug_code) {
647  __ cmp(ebx, masm->isolate()->factory()->the_hole_value());
648  __ Assert(equal, kObjectFoundInSmiOnlyArray);
649  }
650 
652  the_hole_nan);
653 
654  __ bind(&entry);
655  __ sub(edi, Immediate(Smi::FromInt(1)));
656  __ j(not_sign, &loop);
657 
658  __ pop(ebx);
659  __ pop(eax);
660 
661  // Restore esi.
663 
664  __ bind(&only_change_map);
665  // eax: value
666  // ebx: target map
667  // Set transitioned map.
669  __ RecordWriteField(edx,
671  ebx,
672  edi,
676 }
677 
678 
680  MacroAssembler* masm,
681  Register receiver,
682  Register key,
683  Register value,
684  Register target_map,
686  Label* fail) {
687  // Return address is on the stack.
688  DCHECK(receiver.is(edx));
689  DCHECK(key.is(ecx));
690  DCHECK(value.is(eax));
691  DCHECK(target_map.is(ebx));
692 
693  Label loop, entry, convert_hole, gc_required, only_change_map, success;
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.
702  __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array()));
703  __ j(equal, &only_change_map);
704 
705  __ push(eax);
706  __ push(edx);
707  __ push(ebx);
708 
710 
711  // Allocate new FixedArray.
712  // ebx: length of source FixedDoubleArray (smi-tagged)
713  __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
714  __ Allocate(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
715 
716  // eax: destination FixedArray
717  // ebx: number of elements
719  Immediate(masm->isolate()->factory()->fixed_array_map()));
722 
723  __ jmp(&entry);
724 
725  // ebx: target map
726  // edx: receiver
727  // Set transitioned map.
728  __ bind(&only_change_map);
730  __ RecordWriteField(edx,
732  ebx,
733  edi,
737  __ jmp(&success);
738 
739  // Call into runtime if GC is required.
740  __ bind(&gc_required);
742  __ pop(ebx);
743  __ pop(edx);
744  __ pop(eax);
745  __ jmp(fail);
746 
747  // Box doubles into heap numbers.
748  // edi: source FixedDoubleArray
749  // eax: destination FixedArray
750  __ bind(&loop);
751  // ebx: index of current element (smi-tagged)
753  __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
754  __ j(equal, &convert_hole);
755 
756  // Non-hole double, copy value into a heap number.
757  __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
758  // edx: new heap number
759  __ movsd(xmm0,
763  __ mov(esi, ebx);
764  __ RecordWriteArray(eax,
765  edx,
766  esi,
770  __ jmp(&entry, Label::kNear);
771 
772  // Replace the-hole NaN with the-hole pointer.
773  __ bind(&convert_hole);
775  masm->isolate()->factory()->the_hole_value());
776 
777  __ bind(&entry);
778  __ sub(ebx, Immediate(Smi::FromInt(1)));
779  __ j(not_sign, &loop);
780 
781  __ pop(ebx);
782  __ pop(edx);
783  // ebx: target map
784  // edx: receiver
785  // Set transitioned map.
787  __ RecordWriteField(edx,
789  ebx,
790  edi,
794  // Replace receiver's backing store with newly created and filled FixedArray.
796  __ RecordWriteField(edx,
798  eax,
799  edi,
803 
804  // Restore registers.
805  __ pop(eax);
807 
808  __ bind(&success);
809 }
810 
811 
812 void StringCharLoadGenerator::Generate(MacroAssembler* masm,
813  Factory* factory,
814  Register string,
815  Register index,
816  Register result,
817  Label* call_runtime) {
818  // Fetch the instance type of the receiver into result register.
819  __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
820  __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
821 
822  // We need special handling for indirect strings.
823  Label check_sequential;
824  __ test(result, Immediate(kIsIndirectStringMask));
825  __ j(zero, &check_sequential, Label::kNear);
826 
827  // Dispatch on the indirect string shape: slice or cons.
828  Label cons_string;
829  __ test(result, Immediate(kSlicedNotConsMask));
830  __ j(zero, &cons_string, Label::kNear);
831 
832  // Handle slices.
833  Label indirect_string_loaded;
834  __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset));
835  __ SmiUntag(result);
836  __ add(index, result);
837  __ mov(string, FieldOperand(string, SlicedString::kParentOffset));
838  __ jmp(&indirect_string_loaded, Label::kNear);
839 
840  // Handle cons strings.
841  // Check whether the right hand side is the empty string (i.e. if
842  // this is really a flat string in a cons string). If that is not
843  // the case we would rather go to the runtime system now to flatten
844  // the string.
845  __ bind(&cons_string);
847  Immediate(factory->empty_string()));
848  __ j(not_equal, call_runtime);
849  __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
850 
851  __ bind(&indirect_string_loaded);
852  __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
853  __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
854 
855  // Distinguish sequential and external strings. Only these two string
856  // representations can reach here (slices and flat cons strings have been
857  // reduced to the underlying sequential or external string).
858  Label seq_string;
859  __ bind(&check_sequential);
861  __ test(result, Immediate(kStringRepresentationMask));
862  __ j(zero, &seq_string, Label::kNear);
863 
864  // Handle external strings.
865  Label one_byte_external, done;
866  if (FLAG_debug_code) {
867  // Assert that we do not have a cons or slice (indirect strings) here.
868  // Sequential strings have already been ruled out.
869  __ test(result, Immediate(kIsIndirectStringMask));
870  __ Assert(zero, kExternalStringExpectedButNotFound);
871  }
872  // Rule out short external strings.
874  __ test_b(result, kShortExternalStringMask);
875  __ j(not_zero, call_runtime);
876  // Check encoding.
878  __ test_b(result, kStringEncodingMask);
880  __ j(not_equal, &one_byte_external, Label::kNear);
881  // Two-byte string.
882  __ movzx_w(result, Operand(result, index, times_2, 0));
883  __ jmp(&done, Label::kNear);
884  __ bind(&one_byte_external);
885  // One-byte string.
886  __ movzx_b(result, Operand(result, index, times_1, 0));
887  __ jmp(&done, Label::kNear);
888 
889  // Dispatch on the encoding: one-byte or two-byte.
890  Label one_byte;
891  __ bind(&seq_string);
894  __ test(result, Immediate(kStringEncodingMask));
895  __ j(not_zero, &one_byte, Label::kNear);
896 
897  // Two-byte string.
898  // Load the two-byte character code into the result register.
899  __ movzx_w(result, FieldOperand(string,
900  index,
901  times_2,
903  __ jmp(&done, Label::kNear);
904 
905  // One-byte string.
906  // Load the byte into the result register.
907  __ bind(&one_byte);
908  __ movzx_b(result, FieldOperand(string,
909  index,
910  times_1,
912  __ bind(&done);
913 }
914 
915 
916 static Operand ExpConstant(int index) {
917  return Operand::StaticVariable(ExternalReference::math_exp_constants(index));
918 }
919 
920 
921 void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
922  XMMRegister input,
923  XMMRegister result,
924  XMMRegister double_scratch,
925  Register temp1,
926  Register temp2) {
927  DCHECK(!input.is(double_scratch));
928  DCHECK(!input.is(result));
929  DCHECK(!result.is(double_scratch));
930  DCHECK(!temp1.is(temp2));
931  DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
932  DCHECK(!masm->serializer_enabled()); // External references not serializable.
933 
934  Label done;
935 
936  __ movsd(double_scratch, ExpConstant(0));
937  __ xorpd(result, result);
938  __ ucomisd(double_scratch, input);
939  __ j(above_equal, &done);
940  __ ucomisd(input, ExpConstant(1));
941  __ movsd(result, ExpConstant(2));
942  __ j(above_equal, &done);
943  __ movsd(double_scratch, ExpConstant(3));
944  __ movsd(result, ExpConstant(4));
945  __ mulsd(double_scratch, input);
946  __ addsd(double_scratch, result);
947  __ movd(temp2, double_scratch);
948  __ subsd(double_scratch, result);
949  __ movsd(result, ExpConstant(6));
950  __ mulsd(double_scratch, ExpConstant(5));
951  __ subsd(double_scratch, input);
952  __ subsd(result, double_scratch);
953  __ movsd(input, double_scratch);
954  __ mulsd(input, double_scratch);
955  __ mulsd(result, input);
956  __ mov(temp1, temp2);
957  __ mulsd(result, ExpConstant(7));
958  __ subsd(result, double_scratch);
959  __ add(temp1, Immediate(0x1ff800));
960  __ addsd(result, ExpConstant(8));
961  __ and_(temp2, Immediate(0x7ff));
962  __ shr(temp1, 11);
963  __ shl(temp1, 20);
964  __ movd(input, temp1);
965  __ pshufd(input, input, static_cast<uint8_t>(0xe1)); // Order: 11 10 00 01
966  __ movsd(double_scratch, Operand::StaticArray(
967  temp2, times_8, ExternalReference::math_exp_log_table()));
968  __ orps(input, double_scratch);
969  __ mulsd(result, input);
970  __ bind(&done);
971 }
972 
973 #undef __
974 
975 
978  CodePatcher patcher(young_sequence_.start(), young_sequence_.length());
979  patcher.masm()->push(ebp);
980  patcher.masm()->mov(ebp, esp);
981  patcher.masm()->push(esi);
982  patcher.masm()->push(edi);
983 }
984 
985 
986 #ifdef DEBUG
987 bool CodeAgingHelper::IsOld(byte* candidate) const {
988  return *candidate == kCallOpcode;
989 }
990 #endif
991 
992 
993 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
994  bool result = isolate->code_aging_helper()->IsYoung(sequence);
995  DCHECK(result || isolate->code_aging_helper()->IsOld(sequence));
996  return result;
997 }
998 
999 
1000 void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
1001  MarkingParity* parity) {
1002  if (IsYoungSequence(isolate, sequence)) {
1003  *age = kNoAgeCodeAge;
1004  *parity = NO_MARKING_PARITY;
1005  } else {
1006  sequence++; // Skip the kCallOpcode byte
1007  Address target_address = sequence + *reinterpret_cast<int*>(sequence) +
1009  Code* stub = GetCodeFromTargetAddress(target_address);
1010  GetCodeAgeAndParity(stub, age, parity);
1011  }
1012 }
1013 
1014 
1015 void Code::PatchPlatformCodeAge(Isolate* isolate,
1016  byte* sequence,
1017  Code::Age age,
1018  MarkingParity parity) {
1019  uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
1020  if (age == kNoAgeCodeAge) {
1021  isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
1022  CpuFeatures::FlushICache(sequence, young_length);
1023  } else {
1024  Code* stub = GetCodeAgeStub(isolate, age, parity);
1025  CodePatcher patcher(sequence, young_length);
1026  patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32);
1027  }
1028 }
1029 
1030 
1031 } } // namespace v8::internal
1032 
1033 #endif // V8_TARGET_ARCH_IA32
static void * Allocate(const size_t requested, size_t *allocated, bool is_executable)
static void ProtectCode(void *address, const size_t size)
static const int kCallTargetAddressOffset
const EmbeddedVector< byte, kNoCodeAgeSequenceLength > young_sequence_
Definition: codegen.h:171
static Code * GetCodeAgeStub(Isolate *isolate, Age age, MarkingParity parity)
Definition: objects.cc:10561
static Code * GetCodeFromTargetAddress(Address address)
Definition: objects-inl.h:5018
static void PatchPlatformCodeAge(Isolate *isolate, byte *sequence, Age age, MarkingParity parity)
static bool IsYoungSequence(Isolate *isolate, byte *sequence)
static void GetCodeAgeAndParity(Code *code, Age *age, MarkingParity *parity)
Definition: objects.cc:10525
static const int kFirstOffset
Definition: objects.h:9061
static const int kSecondOffset
Definition: objects.h:9062
static void FlushICache(void *start, size_t size)
static void GenerateSmiToDouble(MacroAssembler *masm, Register receiver, Register key, Register value, Register target_map, AllocationSiteMode mode, Label *fail)
static void GenerateMapChangeElementsTransition(MacroAssembler *masm, Register receiver, Register key, Register value, Register target_map, AllocationSiteMode mode, Label *allocation_memento_found)
static void GenerateDoubleToObject(MacroAssembler *masm, Register receiver, Register key, Register value, Register target_map, AllocationSiteMode mode, Label *fail)
static const int kResourceDataOffset
Definition: objects.h:9138
static const int kLengthOffset
Definition: objects.h:2392
static const int kHeaderSize
Definition: objects.h:2393
static const int kValueOffset
Definition: objects.h:1506
static const int kMapOffset
Definition: objects.h:1427
static const int kElementsOffset
Definition: objects.h:2194
static const int kInstanceTypeOffset
Definition: objects.h:6229
static void EmitMathExp(MacroAssembler *masm, DwVfpRegister input, DwVfpRegister result, DwVfpRegister double_scratch1, DwVfpRegister double_scratch2, Register temp1, Register temp2, Register temp3)
static const int kHeaderSize
Definition: objects.h:8941
static const int kParentOffset
Definition: objects.h:9104
static const int kOffsetOffset
Definition: objects.h:9105
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static const int kContextOffset
Definition: frames.h:162
static void Generate(MacroAssembler *masm, Register string, Register index, Register result, Label *call_runtime)
virtual void AfterCall(MacroAssembler *masm) const
virtual void BeforeCall(MacroAssembler *masm) const
T * start() const
Definition: vector.h:47
int length() const
Definition: vector.h:41
#define __
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define DCHECK(condition)
Definition: logging.h:205
AllocationFlags
@ DOUBLE_ALIGNMENT
@ TAG_OBJECT
int int32_t
Definition: unicode.cc:24
const int kPointerSize
Definition: globals.h:129
const Register edx
const uint32_t kStringEncodingMask
Definition: objects.h:555
const Register edi
const int KB
Definition: globals.h:106
@ TRACK_ALLOCATION_SITE
Definition: objects.h:8085
@ kSeqStringTag
Definition: objects.h:563
bool AreAliased(const CPURegister &reg1, const CPURegister &reg2, const CPURegister &reg3=NoReg, const CPURegister &reg4=NoReg, const CPURegister &reg5=NoReg, const CPURegister &reg6=NoReg, const CPURegister &reg7=NoReg, const CPURegister &reg8=NoReg)
const XMMRegister xmm1
const Register esp
const uint32_t kTwoByteStringTag
Definition: objects.h:556
const uint32_t kShortExternalStringTag
Definition: objects.h:590
const XMMRegister xmm2
const FPURegister f1
const FPURegister f2
Operand FieldOperand(Register object, int offset)
const FPURegister f4
const XMMRegister xmm3
const uint32_t kOneByteStringTag
Definition: objects.h:557
const Register esi
const Register eax
UnaryMathFunction CreateExpFunction()
@ NO_MARKING_PARITY
Definition: objects.h:298
const Register ebx
const uint32_t kShortExternalStringMask
Definition: objects.h:589
const XMMRegister xmm0
const uint32_t kStringRepresentationMask
Definition: objects.h:561
byte * Address
Definition: globals.h:101
const uint32_t kSlicedNotConsMask
Definition: objects.h:579
OStream & dec(OStream &os)
Definition: ostreams.cc:122
const Register no_reg
static const byte kCallOpcode
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
const Register ebp
UnaryMathFunction CreateSqrtFunction()
double(* UnaryMathFunction)(double x)
Definition: codegen.h:98
static const int kNoCodeAgeSequenceLength
const uint32_t kHoleNanLower32
Definition: globals.h:657
const uint32_t kIsIndirectStringMask
Definition: objects.h:568
const FPURegister f0
const uint32_t kHoleNanUpper32
Definition: globals.h:656
const Register ecx
const FPURegister f3
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20