OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/arm/codegen-arm.h" | 5 #include "src/arm/codegen-arm.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 | 10 |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 DCHECK(masm->has_frame()); | 310 DCHECK(masm->has_frame()); |
311 masm->set_has_frame(false); | 311 masm->set_has_frame(false); |
312 } | 312 } |
313 | 313 |
314 | 314 |
315 // ------------------------------------------------------------------------- | 315 // ------------------------------------------------------------------------- |
316 // Code generators | 316 // Code generators |
317 | 317 |
318 #define __ ACCESS_MASM(masm) | 318 #define __ ACCESS_MASM(masm) |
319 | 319 |
320 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( | |
321 MacroAssembler* masm, | |
322 Register receiver, | |
323 Register key, | |
324 Register value, | |
325 Register target_map, | |
326 AllocationSiteMode mode, | |
327 Label* allocation_memento_found) { | |
328 Register scratch_elements = r4; | |
329 DCHECK(!AreAliased(receiver, key, value, target_map, | |
330 scratch_elements)); | |
331 | |
332 if (mode == TRACK_ALLOCATION_SITE) { | |
333 DCHECK(allocation_memento_found != NULL); | |
334 __ JumpIfJSArrayHasAllocationMemento( | |
335 receiver, scratch_elements, allocation_memento_found); | |
336 } | |
337 | |
338 // Set transitioned map. | |
339 __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
340 __ RecordWriteField(receiver, | |
341 HeapObject::kMapOffset, | |
342 target_map, | |
343 r9, | |
344 kLRHasNotBeenSaved, | |
345 kDontSaveFPRegs, | |
346 EMIT_REMEMBERED_SET, | |
347 OMIT_SMI_CHECK); | |
348 } | |
349 | |
350 | |
351 void ElementsTransitionGenerator::GenerateSmiToDouble( | |
352 MacroAssembler* masm, | |
353 Register receiver, | |
354 Register key, | |
355 Register value, | |
356 Register target_map, | |
357 AllocationSiteMode mode, | |
358 Label* fail) { | |
359 // Register lr contains the return address. | |
360 Label loop, entry, convert_hole, gc_required, only_change_map, done; | |
361 Register elements = r4; | |
362 Register length = r5; | |
363 Register array = r6; | |
364 Register array_end = array; | |
365 | |
366 // target_map parameter can be clobbered. | |
367 Register scratch1 = target_map; | |
368 Register scratch2 = r9; | |
369 | |
370 // Verify input registers don't conflict with locals. | |
371 DCHECK(!AreAliased(receiver, key, value, target_map, | |
372 elements, length, array, scratch2)); | |
373 | |
374 if (mode == TRACK_ALLOCATION_SITE) { | |
375 __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail); | |
376 } | |
377 | |
378 // Check for empty arrays, which only require a map transition and no changes | |
379 // to the backing store. | |
380 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
381 __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex); | |
382 __ b(eq, &only_change_map); | |
383 | |
384 __ push(lr); | |
385 __ ldr(length, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
386 // length: number of elements (smi-tagged) | |
387 | |
388 // Allocate new FixedDoubleArray. | |
389 // Use lr as a temporary register. | |
390 __ mov(lr, Operand(length, LSL, 2)); | |
391 __ add(lr, lr, Operand(FixedDoubleArray::kHeaderSize)); | |
392 __ Allocate(lr, array, elements, scratch2, &gc_required, DOUBLE_ALIGNMENT); | |
393 __ sub(array, array, Operand(kHeapObjectTag)); | |
394 // array: destination FixedDoubleArray, not tagged as heap object. | |
395 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
396 // r4: source FixedArray. | |
397 | |
398 // Set destination FixedDoubleArray's length and map. | |
399 __ LoadRoot(scratch2, Heap::kFixedDoubleArrayMapRootIndex); | |
400 __ str(length, MemOperand(array, FixedDoubleArray::kLengthOffset)); | |
401 // Update receiver's map. | |
402 __ str(scratch2, MemOperand(array, HeapObject::kMapOffset)); | |
403 | |
404 __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
405 __ RecordWriteField(receiver, | |
406 HeapObject::kMapOffset, | |
407 target_map, | |
408 scratch2, | |
409 kLRHasBeenSaved, | |
410 kDontSaveFPRegs, | |
411 OMIT_REMEMBERED_SET, | |
412 OMIT_SMI_CHECK); | |
413 // Replace receiver's backing store with newly created FixedDoubleArray. | |
414 __ add(scratch1, array, Operand(kHeapObjectTag)); | |
415 __ str(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
416 __ RecordWriteField(receiver, | |
417 JSObject::kElementsOffset, | |
418 scratch1, | |
419 scratch2, | |
420 kLRHasBeenSaved, | |
421 kDontSaveFPRegs, | |
422 EMIT_REMEMBERED_SET, | |
423 OMIT_SMI_CHECK); | |
424 | |
425 // Prepare for conversion loop. | |
426 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
427 __ add(scratch2, array, Operand(FixedDoubleArray::kHeaderSize)); | |
428 __ add(array_end, scratch2, Operand(length, LSL, 2)); | |
429 | |
430 // Repurpose registers no longer in use. | |
431 Register hole_lower = elements; | |
432 Register hole_upper = length; | |
433 | |
434 __ mov(hole_lower, Operand(kHoleNanLower32)); | |
435 __ mov(hole_upper, Operand(kHoleNanUpper32)); | |
436 // scratch1: begin of source FixedArray element fields, not tagged | |
437 // hole_lower: kHoleNanLower32 | |
438 // hole_upper: kHoleNanUpper32 | |
439 // array_end: end of destination FixedDoubleArray, not tagged | |
440 // scratch2: begin of FixedDoubleArray element fields, not tagged | |
441 | |
442 __ b(&entry); | |
443 | |
444 __ bind(&only_change_map); | |
445 __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
446 __ RecordWriteField(receiver, | |
447 HeapObject::kMapOffset, | |
448 target_map, | |
449 scratch2, | |
450 kLRHasNotBeenSaved, | |
451 kDontSaveFPRegs, | |
452 OMIT_REMEMBERED_SET, | |
453 OMIT_SMI_CHECK); | |
454 __ b(&done); | |
455 | |
456 // Call into runtime if GC is required. | |
457 __ bind(&gc_required); | |
458 __ pop(lr); | |
459 __ b(fail); | |
460 | |
461 // Convert and copy elements. | |
462 __ bind(&loop); | |
463 __ ldr(lr, MemOperand(scratch1, 4, PostIndex)); | |
464 // lr: current element | |
465 __ UntagAndJumpIfNotSmi(lr, lr, &convert_hole); | |
466 | |
467 // Normal smi, convert to double and store. | |
468 __ vmov(s0, lr); | |
469 __ vcvt_f64_s32(d0, s0); | |
470 __ vstr(d0, scratch2, 0); | |
471 __ add(scratch2, scratch2, Operand(8)); | |
472 __ b(&entry); | |
473 | |
474 // Hole found, store the-hole NaN. | |
475 __ bind(&convert_hole); | |
476 if (FLAG_debug_code) { | |
477 // Restore a "smi-untagged" heap object. | |
478 __ SmiTag(lr); | |
479 __ orr(lr, lr, Operand(1)); | |
480 __ CompareRoot(lr, Heap::kTheHoleValueRootIndex); | |
481 __ Assert(eq, kObjectFoundInSmiOnlyArray); | |
482 } | |
483 __ Strd(hole_lower, hole_upper, MemOperand(scratch2, 8, PostIndex)); | |
484 | |
485 __ bind(&entry); | |
486 __ cmp(scratch2, array_end); | |
487 __ b(lt, &loop); | |
488 | |
489 __ pop(lr); | |
490 __ bind(&done); | |
491 } | |
492 | |
493 | |
494 void ElementsTransitionGenerator::GenerateDoubleToObject( | |
495 MacroAssembler* masm, | |
496 Register receiver, | |
497 Register key, | |
498 Register value, | |
499 Register target_map, | |
500 AllocationSiteMode mode, | |
501 Label* fail) { | |
502 // Register lr contains the return address. | |
503 Label entry, loop, convert_hole, gc_required, only_change_map; | |
504 Register elements = r4; | |
505 Register array = r6; | |
506 Register length = r5; | |
507 Register scratch = r9; | |
508 | |
509 // Verify input registers don't conflict with locals. | |
510 DCHECK(!AreAliased(receiver, key, value, target_map, | |
511 elements, array, length, scratch)); | |
512 | |
513 if (mode == TRACK_ALLOCATION_SITE) { | |
514 __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail); | |
515 } | |
516 | |
517 // Check for empty arrays, which only require a map transition and no changes | |
518 // to the backing store. | |
519 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
520 __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex); | |
521 __ b(eq, &only_change_map); | |
522 | |
523 __ push(lr); | |
524 __ Push(target_map, receiver, key, value); | |
525 __ ldr(length, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
526 // elements: source FixedDoubleArray | |
527 // length: number of elements (smi-tagged) | |
528 | |
529 // Allocate new FixedArray. | |
530 // Re-use value and target_map registers, as they have been saved on the | |
531 // stack. | |
532 Register array_size = value; | |
533 Register allocate_scratch = target_map; | |
534 __ mov(array_size, Operand(FixedDoubleArray::kHeaderSize)); | |
535 __ add(array_size, array_size, Operand(length, LSL, 1)); | |
536 __ Allocate(array_size, array, allocate_scratch, scratch, &gc_required, | |
537 NO_ALLOCATION_FLAGS); | |
538 // array: destination FixedArray, tagged as heap object | |
539 // Set destination FixedDoubleArray's length and map. | |
540 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex); | |
541 __ str(length, FieldMemOperand(array, FixedDoubleArray::kLengthOffset)); | |
542 __ str(scratch, FieldMemOperand(array, HeapObject::kMapOffset)); | |
543 | |
544 __ sub(array, array, Operand(kHeapObjectTag)); | |
545 | |
546 // Prepare for conversion loop. | |
547 Register src_elements = elements; | |
548 Register dst_elements = target_map; | |
549 Register dst_end = length; | |
550 Register heap_number_map = scratch; | |
551 __ add(src_elements, elements, | |
552 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag + 4)); | |
553 __ add(dst_elements, array, Operand(FixedArray::kHeaderSize)); | |
554 __ add(dst_end, dst_elements, Operand(length, LSL, 1)); | |
555 | |
556 // Allocating heap numbers in the loop below can fail and cause a jump to | |
557 // gc_required. We can't leave a partly initialized FixedArray behind, | |
558 // so pessimistically fill it with holes now. | |
559 Label initialization_loop, initialization_loop_entry; | |
560 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); | |
561 __ b(&initialization_loop_entry); | |
562 __ bind(&initialization_loop); | |
563 __ str(scratch, MemOperand(dst_elements, kPointerSize, PostIndex)); | |
564 __ bind(&initialization_loop_entry); | |
565 __ cmp(dst_elements, dst_end); | |
566 __ b(lt, &initialization_loop); | |
567 | |
568 __ add(dst_elements, array, Operand(FixedArray::kHeaderSize)); | |
569 __ add(array, array, Operand(kHeapObjectTag)); | |
570 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
571 // Using offsetted addresses in src_elements to fully take advantage of | |
572 // post-indexing. | |
573 // dst_elements: begin of destination FixedArray element fields, not tagged | |
574 // src_elements: begin of source FixedDoubleArray element fields, | |
575 // not tagged, +4 | |
576 // dst_end: end of destination FixedArray, not tagged | |
577 // array: destination FixedArray | |
578 // heap_number_map: heap number map | |
579 __ b(&entry); | |
580 | |
581 // Call into runtime if GC is required. | |
582 __ bind(&gc_required); | |
583 __ Pop(target_map, receiver, key, value); | |
584 __ pop(lr); | |
585 __ b(fail); | |
586 | |
587 __ bind(&loop); | |
588 Register upper_bits = key; | |
589 __ ldr(upper_bits, MemOperand(src_elements, 8, PostIndex)); | |
590 // upper_bits: current element's upper 32 bit | |
591 // src_elements: address of next element's upper 32 bit | |
592 __ cmp(upper_bits, Operand(kHoleNanUpper32)); | |
593 __ b(eq, &convert_hole); | |
594 | |
595 // Non-hole double, copy value into a heap number. | |
596 Register heap_number = receiver; | |
597 Register scratch2 = value; | |
598 __ AllocateHeapNumber(heap_number, scratch2, lr, heap_number_map, | |
599 &gc_required); | |
600 // heap_number: new heap number | |
601 __ ldr(scratch2, MemOperand(src_elements, 12, NegOffset)); | |
602 __ Strd(scratch2, upper_bits, | |
603 FieldMemOperand(heap_number, HeapNumber::kValueOffset)); | |
604 __ mov(scratch2, dst_elements); | |
605 __ str(heap_number, MemOperand(dst_elements, 4, PostIndex)); | |
606 __ RecordWrite(array, | |
607 scratch2, | |
608 heap_number, | |
609 kLRHasBeenSaved, | |
610 kDontSaveFPRegs, | |
611 EMIT_REMEMBERED_SET, | |
612 OMIT_SMI_CHECK); | |
613 __ b(&entry); | |
614 | |
615 // Replace the-hole NaN with the-hole pointer. | |
616 __ bind(&convert_hole); | |
617 __ LoadRoot(scratch2, Heap::kTheHoleValueRootIndex); | |
618 __ str(scratch2, MemOperand(dst_elements, 4, PostIndex)); | |
619 | |
620 __ bind(&entry); | |
621 __ cmp(dst_elements, dst_end); | |
622 __ b(lt, &loop); | |
623 | |
624 __ Pop(target_map, receiver, key, value); | |
625 // Replace receiver's backing store with newly created and filled FixedArray. | |
626 __ str(array, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
627 __ RecordWriteField(receiver, | |
628 JSObject::kElementsOffset, | |
629 array, | |
630 scratch, | |
631 kLRHasBeenSaved, | |
632 kDontSaveFPRegs, | |
633 EMIT_REMEMBERED_SET, | |
634 OMIT_SMI_CHECK); | |
635 __ pop(lr); | |
636 | |
637 __ bind(&only_change_map); | |
638 // Update receiver's map. | |
639 __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
640 __ RecordWriteField(receiver, | |
641 HeapObject::kMapOffset, | |
642 target_map, | |
643 scratch, | |
644 kLRHasNotBeenSaved, | |
645 kDontSaveFPRegs, | |
646 OMIT_REMEMBERED_SET, | |
647 OMIT_SMI_CHECK); | |
648 } | |
649 | |
650 | |
651 void StringCharLoadGenerator::Generate(MacroAssembler* masm, | 320 void StringCharLoadGenerator::Generate(MacroAssembler* masm, |
652 Register string, | 321 Register string, |
653 Register index, | 322 Register index, |
654 Register result, | 323 Register result, |
655 Label* call_runtime) { | 324 Label* call_runtime) { |
656 // Fetch the instance type of the receiver into result register. | 325 // Fetch the instance type of the receiver into result register. |
657 __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); | 326 __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
658 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); | 327 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
659 | 328 |
660 // We need special handling for indirect strings. | 329 // We need special handling for indirect strings. |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 patcher.masm()->ldr(pc, MemOperand(pc, -4)); | 471 patcher.masm()->ldr(pc, MemOperand(pc, -4)); |
803 patcher.masm()->emit_code_stub_address(stub); | 472 patcher.masm()->emit_code_stub_address(stub); |
804 } | 473 } |
805 } | 474 } |
806 | 475 |
807 | 476 |
808 } // namespace internal | 477 } // namespace internal |
809 } // namespace v8 | 478 } // namespace v8 |
810 | 479 |
811 #endif // V8_TARGET_ARCH_ARM | 480 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |