V8 Project
codegen-arm.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_ARM
8 
10 #include "src/codegen.h"
11 #include "src/macro-assembler.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 
17 #define __ masm.
18 
19 
20 #if defined(USE_SIMULATOR)
21 byte* fast_exp_arm_machine_code = NULL;
22 double fast_exp_simulator(double x) {
23  return Simulator::current(Isolate::Current())->CallFPReturnsDouble(
24  fast_exp_arm_machine_code, x, 0);
25 }
26 #endif
27 
28 
30  if (!FLAG_fast_math) return &std::exp;
31  size_t actual_size;
32  byte* buffer =
33  static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
34  if (buffer == NULL) return &std::exp;
35  ExternalReference::InitializeMathExpData();
36 
37  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
38 
39  {
40  DwVfpRegister input = d0;
41  DwVfpRegister result = d1;
42  DwVfpRegister double_scratch1 = d2;
43  DwVfpRegister double_scratch2 = d3;
44  Register temp1 = r4;
45  Register temp2 = r5;
46  Register temp3 = r6;
47 
48  if (masm.use_eabi_hardfloat()) {
49  // Input value is in d0 anyway, nothing to do.
50  } else {
51  __ vmov(input, r0, r1);
52  }
53  __ Push(temp3, temp2, temp1);
55  &masm, input, result, double_scratch1, double_scratch2,
56  temp1, temp2, temp3);
57  __ Pop(temp3, temp2, temp1);
58  if (masm.use_eabi_hardfloat()) {
59  __ vmov(d0, result);
60  } else {
61  __ vmov(r0, r1, result);
62  }
63  __ Ret();
64  }
65 
66  CodeDesc desc;
67  masm.GetCode(&desc);
68  DCHECK(!RelocInfo::RequiresRelocation(desc));
69 
70  CpuFeatures::FlushICache(buffer, actual_size);
71  base::OS::ProtectCode(buffer, actual_size);
72 
73 #if !defined(USE_SIMULATOR)
74  return FUNCTION_CAST<UnaryMathFunction>(buffer);
75 #else
76  fast_exp_arm_machine_code = buffer;
77  return &fast_exp_simulator;
78 #endif
79 }
80 
81 #if defined(V8_HOST_ARCH_ARM)
82 MemCopyUint8Function CreateMemCopyUint8Function(MemCopyUint8Function stub) {
83 #if defined(USE_SIMULATOR)
84  return stub;
85 #else
87  size_t actual_size;
88  byte* buffer =
89  static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
90  if (buffer == NULL) return stub;
91 
92  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
93 
94  Register dest = r0;
95  Register src = r1;
96  Register chars = r2;
97  Register temp1 = r3;
98  Label less_4;
99 
101  Label loop, less_256, less_128, less_64, less_32, _16_or_less, _8_or_less;
102  Label size_less_than_8;
103  __ pld(MemOperand(src, 0));
104 
105  __ cmp(chars, Operand(8));
106  __ b(lt, &size_less_than_8);
107  __ cmp(chars, Operand(32));
108  __ b(lt, &less_32);
109  if (CpuFeatures::cache_line_size() == 32) {
110  __ pld(MemOperand(src, 32));
111  }
112  __ cmp(chars, Operand(64));
113  __ b(lt, &less_64);
114  __ pld(MemOperand(src, 64));
115  if (CpuFeatures::cache_line_size() == 32) {
116  __ pld(MemOperand(src, 96));
117  }
118  __ cmp(chars, Operand(128));
119  __ b(lt, &less_128);
120  __ pld(MemOperand(src, 128));
121  if (CpuFeatures::cache_line_size() == 32) {
122  __ pld(MemOperand(src, 160));
123  }
124  __ pld(MemOperand(src, 192));
125  if (CpuFeatures::cache_line_size() == 32) {
126  __ pld(MemOperand(src, 224));
127  }
128  __ cmp(chars, Operand(256));
129  __ b(lt, &less_256);
130  __ sub(chars, chars, Operand(256));
131 
132  __ bind(&loop);
133  __ pld(MemOperand(src, 256));
134  __ vld1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(src, PostIndex));
135  if (CpuFeatures::cache_line_size() == 32) {
136  __ pld(MemOperand(src, 256));
137  }
138  __ vld1(Neon8, NeonListOperand(d4, 4), NeonMemOperand(src, PostIndex));
139  __ sub(chars, chars, Operand(64), SetCC);
140  __ vst1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(dest, PostIndex));
141  __ vst1(Neon8, NeonListOperand(d4, 4), NeonMemOperand(dest, PostIndex));
142  __ b(ge, &loop);
143  __ add(chars, chars, Operand(256));
144 
145  __ bind(&less_256);
146  __ vld1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(src, PostIndex));
147  __ vld1(Neon8, NeonListOperand(d4, 4), NeonMemOperand(src, PostIndex));
148  __ sub(chars, chars, Operand(128));
149  __ vst1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(dest, PostIndex));
150  __ vst1(Neon8, NeonListOperand(d4, 4), NeonMemOperand(dest, PostIndex));
151  __ vld1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(src, PostIndex));
152  __ vld1(Neon8, NeonListOperand(d4, 4), NeonMemOperand(src, PostIndex));
153  __ vst1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(dest, PostIndex));
154  __ vst1(Neon8, NeonListOperand(d4, 4), NeonMemOperand(dest, PostIndex));
155  __ cmp(chars, Operand(64));
156  __ b(lt, &less_64);
157 
158  __ bind(&less_128);
159  __ vld1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(src, PostIndex));
160  __ vld1(Neon8, NeonListOperand(d4, 4), NeonMemOperand(src, PostIndex));
161  __ sub(chars, chars, Operand(64));
162  __ vst1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(dest, PostIndex));
163  __ vst1(Neon8, NeonListOperand(d4, 4), NeonMemOperand(dest, PostIndex));
164 
165  __ bind(&less_64);
166  __ cmp(chars, Operand(32));
167  __ b(lt, &less_32);
168  __ vld1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(src, PostIndex));
169  __ vst1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(dest, PostIndex));
170  __ sub(chars, chars, Operand(32));
171 
172  __ bind(&less_32);
173  __ cmp(chars, Operand(16));
174  __ b(le, &_16_or_less);
175  __ vld1(Neon8, NeonListOperand(d0, 2), NeonMemOperand(src, PostIndex));
176  __ vst1(Neon8, NeonListOperand(d0, 2), NeonMemOperand(dest, PostIndex));
177  __ sub(chars, chars, Operand(16));
178 
179  __ bind(&_16_or_less);
180  __ cmp(chars, Operand(8));
181  __ b(le, &_8_or_less);
182  __ vld1(Neon8, NeonListOperand(d0), NeonMemOperand(src, PostIndex));
183  __ vst1(Neon8, NeonListOperand(d0), NeonMemOperand(dest, PostIndex));
184  __ sub(chars, chars, Operand(8));
185 
186  // Do a last copy which may overlap with the previous copy (up to 8 bytes).
187  __ bind(&_8_or_less);
188  __ rsb(chars, chars, Operand(8));
189  __ sub(src, src, Operand(chars));
190  __ sub(dest, dest, Operand(chars));
191  __ vld1(Neon8, NeonListOperand(d0), NeonMemOperand(src));
192  __ vst1(Neon8, NeonListOperand(d0), NeonMemOperand(dest));
193 
194  __ Ret();
195 
196  __ bind(&size_less_than_8);
197 
198  __ bic(temp1, chars, Operand(0x3), SetCC);
199  __ b(&less_4, eq);
200  __ ldr(temp1, MemOperand(src, 4, PostIndex));
201  __ str(temp1, MemOperand(dest, 4, PostIndex));
202  } else {
203  Register temp2 = ip;
204  Label loop;
205 
206  __ bic(temp2, chars, Operand(0x3), SetCC);
207  __ b(&less_4, eq);
208  __ add(temp2, dest, temp2);
209 
210  __ bind(&loop);
211  __ ldr(temp1, MemOperand(src, 4, PostIndex));
212  __ str(temp1, MemOperand(dest, 4, PostIndex));
213  __ cmp(dest, temp2);
214  __ b(&loop, ne);
215  }
216 
217  __ bind(&less_4);
218  __ mov(chars, Operand(chars, LSL, 31), SetCC);
219  // bit0 => Z (ne), bit1 => C (cs)
220  __ ldrh(temp1, MemOperand(src, 2, PostIndex), cs);
221  __ strh(temp1, MemOperand(dest, 2, PostIndex), cs);
222  __ ldrb(temp1, MemOperand(src), ne);
223  __ strb(temp1, MemOperand(dest), ne);
224  __ Ret();
225 
226  CodeDesc desc;
227  masm.GetCode(&desc);
228  DCHECK(!RelocInfo::RequiresRelocation(desc));
229 
230  CpuFeatures::FlushICache(buffer, actual_size);
231  base::OS::ProtectCode(buffer, actual_size);
232  return FUNCTION_CAST<MemCopyUint8Function>(buffer);
233 #endif
234 }
235 
236 
237 // Convert 8 to 16. The number of character to copy must be at least 8.
238 MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
239  MemCopyUint16Uint8Function stub) {
240 #if defined(USE_SIMULATOR)
241  return stub;
242 #else
243  if (!CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) return stub;
244  size_t actual_size;
245  byte* buffer =
246  static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
247  if (buffer == NULL) return stub;
248 
249  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
250 
251  Register dest = r0;
252  Register src = r1;
253  Register chars = r2;
255  Register temp = r3;
256  Label loop;
257 
258  __ bic(temp, chars, Operand(0x7));
259  __ sub(chars, chars, Operand(temp));
260  __ add(temp, dest, Operand(temp, LSL, 1));
261 
262  __ bind(&loop);
263  __ vld1(Neon8, NeonListOperand(d0), NeonMemOperand(src, PostIndex));
264  __ vmovl(NeonU8, q0, d0);
265  __ vst1(Neon16, NeonListOperand(d0, 2), NeonMemOperand(dest, PostIndex));
266  __ cmp(dest, temp);
267  __ b(&loop, ne);
268 
269  // Do a last copy which will overlap with the previous copy (1 to 8 bytes).
270  __ rsb(chars, chars, Operand(8));
271  __ sub(src, src, Operand(chars));
272  __ sub(dest, dest, Operand(chars, LSL, 1));
273  __ vld1(Neon8, NeonListOperand(d0), NeonMemOperand(src));
274  __ vmovl(NeonU8, q0, d0);
275  __ vst1(Neon16, NeonListOperand(d0, 2), NeonMemOperand(dest));
276  __ Ret();
277  } else {
278  Register temp1 = r3;
279  Register temp2 = ip;
280  Register temp3 = lr;
281  Register temp4 = r4;
282  Label loop;
283  Label not_two;
284 
285  __ Push(lr, r4);
286  __ bic(temp2, chars, Operand(0x3));
287  __ add(temp2, dest, Operand(temp2, LSL, 1));
288 
289  __ bind(&loop);
290  __ ldr(temp1, MemOperand(src, 4, PostIndex));
291  __ uxtb16(temp3, Operand(temp1, ROR, 0));
292  __ uxtb16(temp4, Operand(temp1, ROR, 8));
293  __ pkhbt(temp1, temp3, Operand(temp4, LSL, 16));
294  __ str(temp1, MemOperand(dest));
295  __ pkhtb(temp1, temp4, Operand(temp3, ASR, 16));
296  __ str(temp1, MemOperand(dest, 4));
297  __ add(dest, dest, Operand(8));
298  __ cmp(dest, temp2);
299  __ b(&loop, ne);
300 
301  __ mov(chars, Operand(chars, LSL, 31), SetCC); // bit0 => ne, bit1 => cs
302  __ b(&not_two, cc);
303  __ ldrh(temp1, MemOperand(src, 2, PostIndex));
304  __ uxtb(temp3, Operand(temp1, ROR, 8));
305  __ mov(temp3, Operand(temp3, LSL, 16));
306  __ uxtab(temp3, temp3, Operand(temp1, ROR, 0));
307  __ str(temp3, MemOperand(dest, 4, PostIndex));
308  __ bind(&not_two);
309  __ ldrb(temp1, MemOperand(src), ne);
310  __ strh(temp1, MemOperand(dest), ne);
311  __ Pop(pc, r4);
312  }
313 
314  CodeDesc desc;
315  masm.GetCode(&desc);
316 
317  CpuFeatures::FlushICache(buffer, actual_size);
318  base::OS::ProtectCode(buffer, actual_size);
319 
320  return FUNCTION_CAST<MemCopyUint16Uint8Function>(buffer);
321 #endif
322 }
323 #endif
324 
326 #if defined(USE_SIMULATOR)
327  return &std::sqrt;
328 #else
329  size_t actual_size;
330  byte* buffer =
331  static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
332  if (buffer == NULL) return &std::sqrt;
333 
334  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
335 
336  __ MovFromFloatParameter(d0);
337  __ vsqrt(d0, d0);
338  __ MovToFloatResult(d0);
339  __ Ret();
340 
341  CodeDesc desc;
342  masm.GetCode(&desc);
343  DCHECK(!RelocInfo::RequiresRelocation(desc));
344 
345  CpuFeatures::FlushICache(buffer, actual_size);
346  base::OS::ProtectCode(buffer, actual_size);
347  return FUNCTION_CAST<UnaryMathFunction>(buffer);
348 #endif
349 }
350 
351 #undef __
352 
353 
354 // -------------------------------------------------------------------------
355 // Platform-specific RuntimeCallHelper functions.
356 
357 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
358  masm->EnterFrame(StackFrame::INTERNAL);
359  DCHECK(!masm->has_frame());
360  masm->set_has_frame(true);
361 }
362 
363 
364 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
365  masm->LeaveFrame(StackFrame::INTERNAL);
366  DCHECK(masm->has_frame());
367  masm->set_has_frame(false);
368 }
369 
370 
371 // -------------------------------------------------------------------------
372 // Code generators
373 
374 #define __ ACCESS_MASM(masm)
375 
377  MacroAssembler* masm,
378  Register receiver,
379  Register key,
380  Register value,
381  Register target_map,
383  Label* allocation_memento_found) {
384  Register scratch_elements = r4;
385  DCHECK(!AreAliased(receiver, key, value, target_map,
386  scratch_elements));
387 
388  if (mode == TRACK_ALLOCATION_SITE) {
389  DCHECK(allocation_memento_found != NULL);
390  __ JumpIfJSArrayHasAllocationMemento(
391  receiver, scratch_elements, allocation_memento_found);
392  }
393 
394  // Set transitioned map.
395  __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
396  __ RecordWriteField(receiver,
398  target_map,
399  r9,
404 }
405 
406 
408  MacroAssembler* masm,
409  Register receiver,
410  Register key,
411  Register value,
412  Register target_map,
414  Label* fail) {
415  // Register lr contains the return address.
416  Label loop, entry, convert_hole, gc_required, only_change_map, done;
417  Register elements = r4;
418  Register length = r5;
419  Register array = r6;
420  Register array_end = array;
421 
422  // target_map parameter can be clobbered.
423  Register scratch1 = target_map;
424  Register scratch2 = r9;
425 
426  // Verify input registers don't conflict with locals.
427  DCHECK(!AreAliased(receiver, key, value, target_map,
428  elements, length, array, scratch2));
429 
430  if (mode == TRACK_ALLOCATION_SITE) {
431  __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail);
432  }
433 
434  // Check for empty arrays, which only require a map transition and no changes
435  // to the backing store.
436  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
437  __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex);
438  __ b(eq, &only_change_map);
439 
440  __ push(lr);
441  __ ldr(length, FieldMemOperand(elements, FixedArray::kLengthOffset));
442  // length: number of elements (smi-tagged)
443 
444  // Allocate new FixedDoubleArray.
445  // Use lr as a temporary register.
446  __ mov(lr, Operand(length, LSL, 2));
447  __ add(lr, lr, Operand(FixedDoubleArray::kHeaderSize));
448  __ Allocate(lr, array, elements, scratch2, &gc_required, DOUBLE_ALIGNMENT);
449  // array: destination FixedDoubleArray, not tagged as heap object.
450  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
451  // r4: source FixedArray.
452 
453  // Set destination FixedDoubleArray's length and map.
454  __ LoadRoot(scratch2, Heap::kFixedDoubleArrayMapRootIndex);
455  __ str(length, MemOperand(array, FixedDoubleArray::kLengthOffset));
456  // Update receiver's map.
457  __ str(scratch2, MemOperand(array, HeapObject::kMapOffset));
458 
459  __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
460  __ RecordWriteField(receiver,
462  target_map,
463  scratch2,
468  // Replace receiver's backing store with newly created FixedDoubleArray.
469  __ add(scratch1, array, Operand(kHeapObjectTag));
470  __ str(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset));
471  __ RecordWriteField(receiver,
473  scratch1,
474  scratch2,
479 
480  // Prepare for conversion loop.
481  __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
482  __ add(scratch2, array, Operand(FixedDoubleArray::kHeaderSize));
483  __ add(array_end, scratch2, Operand(length, LSL, 2));
484 
485  // Repurpose registers no longer in use.
486  Register hole_lower = elements;
487  Register hole_upper = length;
488 
489  __ mov(hole_lower, Operand(kHoleNanLower32));
490  __ mov(hole_upper, Operand(kHoleNanUpper32));
491  // scratch1: begin of source FixedArray element fields, not tagged
492  // hole_lower: kHoleNanLower32
493  // hole_upper: kHoleNanUpper32
494  // array_end: end of destination FixedDoubleArray, not tagged
495  // scratch2: begin of FixedDoubleArray element fields, not tagged
496 
497  __ b(&entry);
498 
499  __ bind(&only_change_map);
500  __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
501  __ RecordWriteField(receiver,
503  target_map,
504  scratch2,
509  __ b(&done);
510 
511  // Call into runtime if GC is required.
512  __ bind(&gc_required);
513  __ pop(lr);
514  __ b(fail);
515 
516  // Convert and copy elements.
517  __ bind(&loop);
518  __ ldr(lr, MemOperand(scratch1, 4, PostIndex));
519  // lr: current element
520  __ UntagAndJumpIfNotSmi(lr, lr, &convert_hole);
521 
522  // Normal smi, convert to double and store.
523  __ vmov(s0, lr);
524  __ vcvt_f64_s32(d0, s0);
525  __ vstr(d0, scratch2, 0);
526  __ add(scratch2, scratch2, Operand(8));
527  __ b(&entry);
528 
529  // Hole found, store the-hole NaN.
530  __ bind(&convert_hole);
531  if (FLAG_debug_code) {
532  // Restore a "smi-untagged" heap object.
533  __ SmiTag(lr);
534  __ orr(lr, lr, Operand(1));
535  __ CompareRoot(lr, Heap::kTheHoleValueRootIndex);
536  __ Assert(eq, kObjectFoundInSmiOnlyArray);
537  }
538  __ Strd(hole_lower, hole_upper, MemOperand(scratch2, 8, PostIndex));
539 
540  __ bind(&entry);
541  __ cmp(scratch2, array_end);
542  __ b(lt, &loop);
543 
544  __ pop(lr);
545  __ bind(&done);
546 }
547 
548 
550  MacroAssembler* masm,
551  Register receiver,
552  Register key,
553  Register value,
554  Register target_map,
556  Label* fail) {
557  // Register lr contains the return address.
558  Label entry, loop, convert_hole, gc_required, only_change_map;
559  Register elements = r4;
560  Register array = r6;
561  Register length = r5;
562  Register scratch = r9;
563 
564  // Verify input registers don't conflict with locals.
565  DCHECK(!AreAliased(receiver, key, value, target_map,
566  elements, array, length, scratch));
567 
568  if (mode == TRACK_ALLOCATION_SITE) {
569  __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail);
570  }
571 
572  // Check for empty arrays, which only require a map transition and no changes
573  // to the backing store.
574  __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
575  __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex);
576  __ b(eq, &only_change_map);
577 
578  __ push(lr);
579  __ Push(target_map, receiver, key, value);
580  __ ldr(length, FieldMemOperand(elements, FixedArray::kLengthOffset));
581  // elements: source FixedDoubleArray
582  // length: number of elements (smi-tagged)
583 
584  // Allocate new FixedArray.
585  // Re-use value and target_map registers, as they have been saved on the
586  // stack.
587  Register array_size = value;
588  Register allocate_scratch = target_map;
589  __ mov(array_size, Operand(FixedDoubleArray::kHeaderSize));
590  __ add(array_size, array_size, Operand(length, LSL, 1));
591  __ Allocate(array_size, array, allocate_scratch, scratch, &gc_required,
593  // array: destination FixedArray, not tagged as heap object
594  // Set destination FixedDoubleArray's length and map.
595  __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
596  __ str(length, MemOperand(array, FixedDoubleArray::kLengthOffset));
597  __ str(scratch, MemOperand(array, HeapObject::kMapOffset));
598 
599  // Prepare for conversion loop.
600  Register src_elements = elements;
601  Register dst_elements = target_map;
602  Register dst_end = length;
603  Register heap_number_map = scratch;
604  __ add(src_elements, elements,
606  __ add(dst_elements, array, Operand(FixedArray::kHeaderSize));
607  __ add(array, array, Operand(kHeapObjectTag));
608  __ add(dst_end, dst_elements, Operand(length, LSL, 1));
609  __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
610  // Using offsetted addresses in src_elements to fully take advantage of
611  // post-indexing.
612  // dst_elements: begin of destination FixedArray element fields, not tagged
613  // src_elements: begin of source FixedDoubleArray element fields,
614  // not tagged, +4
615  // dst_end: end of destination FixedArray, not tagged
616  // array: destination FixedArray
617  // heap_number_map: heap number map
618  __ b(&entry);
619 
620  // Call into runtime if GC is required.
621  __ bind(&gc_required);
622  __ Pop(target_map, receiver, key, value);
623  __ pop(lr);
624  __ b(fail);
625 
626  __ bind(&loop);
627  Register upper_bits = key;
628  __ ldr(upper_bits, MemOperand(src_elements, 8, PostIndex));
629  // upper_bits: current element's upper 32 bit
630  // src_elements: address of next element's upper 32 bit
631  __ cmp(upper_bits, Operand(kHoleNanUpper32));
632  __ b(eq, &convert_hole);
633 
634  // Non-hole double, copy value into a heap number.
635  Register heap_number = receiver;
636  Register scratch2 = value;
637  __ AllocateHeapNumber(heap_number, scratch2, lr, heap_number_map,
638  &gc_required);
639  // heap_number: new heap number
640  __ ldr(scratch2, MemOperand(src_elements, 12, NegOffset));
641  __ Strd(scratch2, upper_bits,
643  __ mov(scratch2, dst_elements);
644  __ str(heap_number, MemOperand(dst_elements, 4, PostIndex));
645  __ RecordWrite(array,
646  scratch2,
647  heap_number,
652  __ b(&entry);
653 
654  // Replace the-hole NaN with the-hole pointer.
655  __ bind(&convert_hole);
656  __ LoadRoot(scratch2, Heap::kTheHoleValueRootIndex);
657  __ str(scratch2, MemOperand(dst_elements, 4, PostIndex));
658 
659  __ bind(&entry);
660  __ cmp(dst_elements, dst_end);
661  __ b(lt, &loop);
662 
663  __ Pop(target_map, receiver, key, value);
664  // Replace receiver's backing store with newly created and filled FixedArray.
665  __ str(array, FieldMemOperand(receiver, JSObject::kElementsOffset));
666  __ RecordWriteField(receiver,
668  array,
669  scratch,
674  __ pop(lr);
675 
676  __ bind(&only_change_map);
677  // Update receiver's map.
678  __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
679  __ RecordWriteField(receiver,
681  target_map,
682  scratch,
687 }
688 
689 
690 void StringCharLoadGenerator::Generate(MacroAssembler* masm,
691  Register string,
692  Register index,
693  Register result,
694  Label* call_runtime) {
695  // Fetch the instance type of the receiver into result register.
696  __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
697  __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
698 
699  // We need special handling for indirect strings.
700  Label check_sequential;
701  __ tst(result, Operand(kIsIndirectStringMask));
702  __ b(eq, &check_sequential);
703 
704  // Dispatch on the indirect string shape: slice or cons.
705  Label cons_string;
706  __ tst(result, Operand(kSlicedNotConsMask));
707  __ b(eq, &cons_string);
708 
709  // Handle slices.
710  Label indirect_string_loaded;
711  __ ldr(result, FieldMemOperand(string, SlicedString::kOffsetOffset));
712  __ ldr(string, FieldMemOperand(string, SlicedString::kParentOffset));
713  __ add(index, index, Operand::SmiUntag(result));
714  __ jmp(&indirect_string_loaded);
715 
716  // Handle cons strings.
717  // Check whether the right hand side is the empty string (i.e. if
718  // this is really a flat string in a cons string). If that is not
719  // the case we would rather go to the runtime system now to flatten
720  // the string.
721  __ bind(&cons_string);
722  __ ldr(result, FieldMemOperand(string, ConsString::kSecondOffset));
723  __ CompareRoot(result, Heap::kempty_stringRootIndex);
724  __ b(ne, call_runtime);
725  // Get the first of the two strings and load its instance type.
726  __ ldr(string, FieldMemOperand(string, ConsString::kFirstOffset));
727 
728  __ bind(&indirect_string_loaded);
729  __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
730  __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
731 
732  // Distinguish sequential and external strings. Only these two string
733  // representations can reach here (slices and flat cons strings have been
734  // reduced to the underlying sequential or external string).
735  Label external_string, check_encoding;
736  __ bind(&check_sequential);
738  __ tst(result, Operand(kStringRepresentationMask));
739  __ b(ne, &external_string);
740 
741  // Prepare sequential strings
743  __ add(string,
744  string,
746  __ jmp(&check_encoding);
747 
748  // Handle external strings.
749  __ bind(&external_string);
750  if (FLAG_debug_code) {
751  // Assert that we do not have a cons or slice (indirect strings) here.
752  // Sequential strings have already been ruled out.
753  __ tst(result, Operand(kIsIndirectStringMask));
754  __ Assert(eq, kExternalStringExpectedButNotFound);
755  }
756  // Rule out short external strings.
758  __ tst(result, Operand(kShortExternalStringMask));
759  __ b(ne, call_runtime);
761 
762  Label one_byte, done;
763  __ bind(&check_encoding);
765  __ tst(result, Operand(kStringEncodingMask));
766  __ b(ne, &one_byte);
767  // Two-byte string.
768  __ ldrh(result, MemOperand(string, index, LSL, 1));
769  __ jmp(&done);
770  __ bind(&one_byte);
771  // One-byte string.
772  __ ldrb(result, MemOperand(string, index));
773  __ bind(&done);
774 }
775 
776 
777 static MemOperand ExpConstant(int index, Register base) {
778  return MemOperand(base, index * kDoubleSize);
779 }
780 
781 
782 void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
783  DwVfpRegister input,
784  DwVfpRegister result,
785  DwVfpRegister double_scratch1,
786  DwVfpRegister double_scratch2,
787  Register temp1,
788  Register temp2,
789  Register temp3) {
790  DCHECK(!input.is(result));
791  DCHECK(!input.is(double_scratch1));
792  DCHECK(!input.is(double_scratch2));
793  DCHECK(!result.is(double_scratch1));
794  DCHECK(!result.is(double_scratch2));
795  DCHECK(!double_scratch1.is(double_scratch2));
796  DCHECK(!temp1.is(temp2));
797  DCHECK(!temp1.is(temp3));
798  DCHECK(!temp2.is(temp3));
799  DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
800  DCHECK(!masm->serializer_enabled()); // External references not serializable.
801 
802  Label zero, infinity, done;
803 
804  __ mov(temp3, Operand(ExternalReference::math_exp_constants(0)));
805 
806  __ vldr(double_scratch1, ExpConstant(0, temp3));
807  __ VFPCompareAndSetFlags(double_scratch1, input);
808  __ b(ge, &zero);
809 
810  __ vldr(double_scratch2, ExpConstant(1, temp3));
811  __ VFPCompareAndSetFlags(input, double_scratch2);
812  __ b(ge, &infinity);
813 
814  __ vldr(double_scratch1, ExpConstant(3, temp3));
815  __ vldr(result, ExpConstant(4, temp3));
816  __ vmul(double_scratch1, double_scratch1, input);
817  __ vadd(double_scratch1, double_scratch1, result);
818  __ VmovLow(temp2, double_scratch1);
819  __ vsub(double_scratch1, double_scratch1, result);
820  __ vldr(result, ExpConstant(6, temp3));
821  __ vldr(double_scratch2, ExpConstant(5, temp3));
822  __ vmul(double_scratch1, double_scratch1, double_scratch2);
823  __ vsub(double_scratch1, double_scratch1, input);
824  __ vsub(result, result, double_scratch1);
825  __ vmul(double_scratch2, double_scratch1, double_scratch1);
826  __ vmul(result, result, double_scratch2);
827  __ vldr(double_scratch2, ExpConstant(7, temp3));
828  __ vmul(result, result, double_scratch2);
829  __ vsub(result, result, double_scratch1);
830  // Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
831  DCHECK(*reinterpret_cast<double*>
832  (ExternalReference::math_exp_constants(8).address()) == 1);
833  __ vmov(double_scratch2, 1);
834  __ vadd(result, result, double_scratch2);
835  __ mov(temp1, Operand(temp2, LSR, 11));
836  __ Ubfx(temp2, temp2, 0, 11);
837  __ add(temp1, temp1, Operand(0x3ff));
838 
839  // Must not call ExpConstant() after overwriting temp3!
840  __ mov(temp3, Operand(ExternalReference::math_exp_log_table()));
841  __ add(temp3, temp3, Operand(temp2, LSL, 3));
842  __ ldm(ia, temp3, temp2.bit() | temp3.bit());
843  // The first word is loaded is the lower number register.
844  if (temp2.code() < temp3.code()) {
845  __ orr(temp1, temp3, Operand(temp1, LSL, 20));
846  __ vmov(double_scratch1, temp2, temp1);
847  } else {
848  __ orr(temp1, temp2, Operand(temp1, LSL, 20));
849  __ vmov(double_scratch1, temp3, temp1);
850  }
851  __ vmul(result, result, double_scratch1);
852  __ b(&done);
853 
854  __ bind(&zero);
855  __ vmov(result, kDoubleRegZero);
856  __ b(&done);
857 
858  __ bind(&infinity);
859  __ vldr(result, ExpConstant(2, temp3));
860 
861  __ bind(&done);
862 }
863 
864 #undef __
865 
866 #ifdef DEBUG
867 // add(r0, pc, Operand(-8))
868 static const uint32_t kCodeAgePatchFirstInstruction = 0xe24f0008;
869 #endif
870 
873  // Since patcher is a large object, allocate it dynamically when needed,
874  // to avoid overloading the stack in stress conditions.
875  // DONT_FLUSH is used because the CodeAgingHelper is initialized early in
876  // the process, before ARM simulator ICache is setup.
877  SmartPointer<CodePatcher> patcher(
878  new CodePatcher(young_sequence_.start(),
881  PredictableCodeSizeScope scope(patcher->masm(), young_sequence_.length());
882  patcher->masm()->PushFixedFrame(r1);
883  patcher->masm()->nop(ip.code());
884  patcher->masm()->add(
886 }
887 
888 
889 #ifdef DEBUG
890 bool CodeAgingHelper::IsOld(byte* candidate) const {
891  return Memory::uint32_at(candidate) == kCodeAgePatchFirstInstruction;
892 }
893 #endif
894 
895 
896 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
897  bool result = isolate->code_aging_helper()->IsYoung(sequence);
898  DCHECK(result || isolate->code_aging_helper()->IsOld(sequence));
899  return result;
900 }
901 
902 
903 void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
904  MarkingParity* parity) {
905  if (IsYoungSequence(isolate, sequence)) {
906  *age = kNoAgeCodeAge;
907  *parity = NO_MARKING_PARITY;
908  } else {
909  Address target_address = Memory::Address_at(
911  Code* stub = GetCodeFromTargetAddress(target_address);
912  GetCodeAgeAndParity(stub, age, parity);
913  }
914 }
915 
916 
917 void Code::PatchPlatformCodeAge(Isolate* isolate,
918  byte* sequence,
919  Code::Age age,
920  MarkingParity parity) {
921  uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
922  if (age == kNoAgeCodeAge) {
923  isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
924  CpuFeatures::FlushICache(sequence, young_length);
925  } else {
926  Code* stub = GetCodeAgeStub(isolate, age, parity);
927  CodePatcher patcher(sequence, young_length / Assembler::kInstrSize);
928  patcher.masm()->add(r0, pc, Operand(-8));
929  patcher.masm()->ldr(pc, MemOperand(pc, -4));
930  patcher.masm()->emit_code_stub_address(stub);
931  }
932 }
933 
934 
935 } } // namespace v8::internal
936 
937 #endif // V8_TARGET_ARCH_ARM
#define kDoubleRegZero
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 kInstrSize
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 bool IsSupported(CpuFeature f)
Definition: assembler.h:184
static unsigned cache_line_size()
Definition: assembler.h:190
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 uint32_t & uint32_at(Address addr)
Definition: v8memory.h:24
static Address & Address_at(Address addr)
Definition: v8memory.h:56
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 const int kFixedFrameSizeFromFp
Definition: frames.h:157
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
@ DOUBLE_ALIGNMENT
@ NO_ALLOCATION_FLAGS
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Definition: scheduler.cc:773
const LowDwVfpRegister d2
const uint32_t kStringEncodingMask
Definition: objects.h:555
const Register r2
@ UNALIGNED_ACCESSES
Definition: globals.h:621
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 LowDwVfpRegister d1
const Register r6
const uint32_t kTwoByteStringTag
Definition: objects.h:556
const Register r0
const uint32_t kShortExternalStringTag
Definition: objects.h:590
const LowDwVfpRegister d0
const Register ip
const int kDoubleSize
Definition: globals.h:127
const SwVfpRegister s0
const Register r3
const Register fp
const Register sp
const Register r4
MemOperand FieldMemOperand(Register object, int offset)
UnaryMathFunction CreateExpFunction()
@ NO_MARKING_PARITY
Definition: objects.h:298
const Register r9
const Register pc
const uint32_t kShortExternalStringMask
Definition: objects.h:589
const Register r5
const uint32_t kStringRepresentationMask
Definition: objects.h:561
const Register lr
byte * Address
Definition: globals.h:101
const uint32_t kSlicedNotConsMask
Definition: objects.h:579
const Register r1
const int kHeapObjectTag
Definition: v8.h:5737
const QwNeonRegister q0
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
UnaryMathFunction CreateSqrtFunction()
double(* UnaryMathFunction)(double x)
Definition: codegen.h:98
const LowDwVfpRegister d3
static const int kNoCodeAgeSequenceLength
const uint32_t kHoleNanLower32
Definition: globals.h:657
const uint32_t kIsIndirectStringMask
Definition: objects.h:568
const uint32_t kHoleNanUpper32
Definition: globals.h:656
const LowDwVfpRegister d4
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20