OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
8 | 8 |
9 #include "src/arm64/simulator-arm64.h" | 9 #include "src/arm64/simulator-arm64.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 | 55 |
56 MathExpGenerator::EmitMathExp(&masm, input, result, | 56 MathExpGenerator::EmitMathExp(&masm, input, result, |
57 double_temp1, double_temp2, | 57 double_temp1, double_temp2, |
58 temp1, temp2, temp3); | 58 temp1, temp2, temp3); |
59 // Move the result to the return register. | 59 // Move the result to the return register. |
60 masm.Fmov(d0, result); | 60 masm.Fmov(d0, result); |
61 masm.Ret(); | 61 masm.Ret(); |
62 | 62 |
63 CodeDesc desc; | 63 CodeDesc desc; |
64 masm.GetCode(&desc); | 64 masm.GetCode(&desc); |
65 ASSERT(!RelocInfo::RequiresRelocation(desc)); | 65 DCHECK(!RelocInfo::RequiresRelocation(desc)); |
66 | 66 |
67 CpuFeatures::FlushICache(buffer, actual_size); | 67 CpuFeatures::FlushICache(buffer, actual_size); |
68 base::OS::ProtectCode(buffer, actual_size); | 68 base::OS::ProtectCode(buffer, actual_size); |
69 | 69 |
70 #if !defined(USE_SIMULATOR) | 70 #if !defined(USE_SIMULATOR) |
71 return FUNCTION_CAST<UnaryMathFunction>(buffer); | 71 return FUNCTION_CAST<UnaryMathFunction>(buffer); |
72 #else | 72 #else |
73 fast_exp_arm64_machine_code = buffer; | 73 fast_exp_arm64_machine_code = buffer; |
74 return &fast_exp_simulator; | 74 return &fast_exp_simulator; |
75 #endif | 75 #endif |
76 } | 76 } |
77 | 77 |
78 | 78 |
79 UnaryMathFunction CreateSqrtFunction() { | 79 UnaryMathFunction CreateSqrtFunction() { |
80 return &std::sqrt; | 80 return &std::sqrt; |
81 } | 81 } |
82 | 82 |
83 | 83 |
84 // ------------------------------------------------------------------------- | 84 // ------------------------------------------------------------------------- |
85 // Platform-specific RuntimeCallHelper functions. | 85 // Platform-specific RuntimeCallHelper functions. |
86 | 86 |
87 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { | 87 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { |
88 masm->EnterFrame(StackFrame::INTERNAL); | 88 masm->EnterFrame(StackFrame::INTERNAL); |
89 ASSERT(!masm->has_frame()); | 89 DCHECK(!masm->has_frame()); |
90 masm->set_has_frame(true); | 90 masm->set_has_frame(true); |
91 } | 91 } |
92 | 92 |
93 | 93 |
94 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { | 94 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { |
95 masm->LeaveFrame(StackFrame::INTERNAL); | 95 masm->LeaveFrame(StackFrame::INTERNAL); |
96 ASSERT(masm->has_frame()); | 96 DCHECK(masm->has_frame()); |
97 masm->set_has_frame(false); | 97 masm->set_has_frame(false); |
98 } | 98 } |
99 | 99 |
100 | 100 |
101 // ------------------------------------------------------------------------- | 101 // ------------------------------------------------------------------------- |
102 // Code generators | 102 // Code generators |
103 | 103 |
104 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( | 104 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( |
105 MacroAssembler* masm, | 105 MacroAssembler* masm, |
106 Register receiver, | 106 Register receiver, |
107 Register key, | 107 Register key, |
108 Register value, | 108 Register value, |
109 Register target_map, | 109 Register target_map, |
110 AllocationSiteMode mode, | 110 AllocationSiteMode mode, |
111 Label* allocation_memento_found) { | 111 Label* allocation_memento_found) { |
112 ASM_LOCATION( | 112 ASM_LOCATION( |
113 "ElementsTransitionGenerator::GenerateMapChangeElementsTransition"); | 113 "ElementsTransitionGenerator::GenerateMapChangeElementsTransition"); |
114 ASSERT(!AreAliased(receiver, key, value, target_map)); | 114 DCHECK(!AreAliased(receiver, key, value, target_map)); |
115 | 115 |
116 if (mode == TRACK_ALLOCATION_SITE) { | 116 if (mode == TRACK_ALLOCATION_SITE) { |
117 ASSERT(allocation_memento_found != NULL); | 117 DCHECK(allocation_memento_found != NULL); |
118 __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, | 118 __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, |
119 allocation_memento_found); | 119 allocation_memento_found); |
120 } | 120 } |
121 | 121 |
122 // Set transitioned map. | 122 // Set transitioned map. |
123 __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 123 __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
124 __ RecordWriteField(receiver, | 124 __ RecordWriteField(receiver, |
125 HeapObject::kMapOffset, | 125 HeapObject::kMapOffset, |
126 target_map, | 126 target_map, |
127 x10, | 127 x10, |
(...skipping 15 matching lines...) Expand all Loading... |
143 ASM_LOCATION("ElementsTransitionGenerator::GenerateSmiToDouble"); | 143 ASM_LOCATION("ElementsTransitionGenerator::GenerateSmiToDouble"); |
144 Label gc_required, only_change_map; | 144 Label gc_required, only_change_map; |
145 Register elements = x4; | 145 Register elements = x4; |
146 Register length = x5; | 146 Register length = x5; |
147 Register array_size = x6; | 147 Register array_size = x6; |
148 Register array = x7; | 148 Register array = x7; |
149 | 149 |
150 Register scratch = x6; | 150 Register scratch = x6; |
151 | 151 |
152 // Verify input registers don't conflict with locals. | 152 // Verify input registers don't conflict with locals. |
153 ASSERT(!AreAliased(receiver, key, value, target_map, | 153 DCHECK(!AreAliased(receiver, key, value, target_map, |
154 elements, length, array_size, array)); | 154 elements, length, array_size, array)); |
155 | 155 |
156 if (mode == TRACK_ALLOCATION_SITE) { | 156 if (mode == TRACK_ALLOCATION_SITE) { |
157 __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, fail); | 157 __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, fail); |
158 } | 158 } |
159 | 159 |
160 // Check for empty arrays, which only require a map transition and no changes | 160 // Check for empty arrays, which only require a map transition and no changes |
161 // to the backing store. | 161 // to the backing store. |
162 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 162 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
163 __ JumpIfRoot(elements, Heap::kEmptyFixedArrayRootIndex, &only_change_map); | 163 __ JumpIfRoot(elements, Heap::kEmptyFixedArrayRootIndex, &only_change_map); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 Register target_map, | 246 Register target_map, |
247 AllocationSiteMode mode, | 247 AllocationSiteMode mode, |
248 Label* fail) { | 248 Label* fail) { |
249 ASM_LOCATION("ElementsTransitionGenerator::GenerateDoubleToObject"); | 249 ASM_LOCATION("ElementsTransitionGenerator::GenerateDoubleToObject"); |
250 Register elements = x4; | 250 Register elements = x4; |
251 Register array_size = x6; | 251 Register array_size = x6; |
252 Register array = x7; | 252 Register array = x7; |
253 Register length = x5; | 253 Register length = x5; |
254 | 254 |
255 // Verify input registers don't conflict with locals. | 255 // Verify input registers don't conflict with locals. |
256 ASSERT(!AreAliased(receiver, key, value, target_map, | 256 DCHECK(!AreAliased(receiver, key, value, target_map, |
257 elements, array_size, array, length)); | 257 elements, array_size, array, length)); |
258 | 258 |
259 if (mode == TRACK_ALLOCATION_SITE) { | 259 if (mode == TRACK_ALLOCATION_SITE) { |
260 __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, fail); | 260 __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, fail); |
261 } | 261 } |
262 | 262 |
263 // Check for empty arrays, which only require a map transition and no changes | 263 // Check for empty arrays, which only require a map transition and no changes |
264 // to the backing store. | 264 // to the backing store. |
265 Label only_change_map; | 265 Label only_change_map; |
266 | 266 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 | 349 |
350 __ Bind(&only_change_map); | 350 __ Bind(&only_change_map); |
351 __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 351 __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
352 __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, x13, | 352 __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, x13, |
353 kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, | 353 kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, |
354 OMIT_SMI_CHECK); | 354 OMIT_SMI_CHECK); |
355 } | 355 } |
356 | 356 |
357 | 357 |
358 CodeAgingHelper::CodeAgingHelper() { | 358 CodeAgingHelper::CodeAgingHelper() { |
359 ASSERT(young_sequence_.length() == kNoCodeAgeSequenceLength); | 359 DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength); |
360 // The sequence of instructions that is patched out for aging code is the | 360 // The sequence of instructions that is patched out for aging code is the |
361 // following boilerplate stack-building prologue that is found both in | 361 // following boilerplate stack-building prologue that is found both in |
362 // FUNCTION and OPTIMIZED_FUNCTION code: | 362 // FUNCTION and OPTIMIZED_FUNCTION code: |
363 PatchingAssembler patcher(young_sequence_.start(), | 363 PatchingAssembler patcher(young_sequence_.start(), |
364 young_sequence_.length() / kInstructionSize); | 364 young_sequence_.length() / kInstructionSize); |
365 // The young sequence is the frame setup code for FUNCTION code types. It is | 365 // The young sequence is the frame setup code for FUNCTION code types. It is |
366 // generated by FullCodeGenerator::Generate. | 366 // generated by FullCodeGenerator::Generate. |
367 MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher); | 367 MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher); |
368 | 368 |
369 #ifdef DEBUG | 369 #ifdef DEBUG |
370 const int length = kCodeAgeStubEntryOffset / kInstructionSize; | 370 const int length = kCodeAgeStubEntryOffset / kInstructionSize; |
371 ASSERT(old_sequence_.length() >= kCodeAgeStubEntryOffset); | 371 DCHECK(old_sequence_.length() >= kCodeAgeStubEntryOffset); |
372 PatchingAssembler patcher_old(old_sequence_.start(), length); | 372 PatchingAssembler patcher_old(old_sequence_.start(), length); |
373 MacroAssembler::EmitCodeAgeSequence(&patcher_old, NULL); | 373 MacroAssembler::EmitCodeAgeSequence(&patcher_old, NULL); |
374 #endif | 374 #endif |
375 } | 375 } |
376 | 376 |
377 | 377 |
378 #ifdef DEBUG | 378 #ifdef DEBUG |
379 bool CodeAgingHelper::IsOld(byte* candidate) const { | 379 bool CodeAgingHelper::IsOld(byte* candidate) const { |
380 return memcmp(candidate, old_sequence_.start(), kCodeAgeStubEntryOffset) == 0; | 380 return memcmp(candidate, old_sequence_.start(), kCodeAgeStubEntryOffset) == 0; |
381 } | 381 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 MacroAssembler::EmitCodeAgeSequence(&patcher, stub); | 413 MacroAssembler::EmitCodeAgeSequence(&patcher, stub); |
414 } | 414 } |
415 } | 415 } |
416 | 416 |
417 | 417 |
418 void StringCharLoadGenerator::Generate(MacroAssembler* masm, | 418 void StringCharLoadGenerator::Generate(MacroAssembler* masm, |
419 Register string, | 419 Register string, |
420 Register index, | 420 Register index, |
421 Register result, | 421 Register result, |
422 Label* call_runtime) { | 422 Label* call_runtime) { |
423 ASSERT(string.Is64Bits() && index.Is32Bits() && result.Is64Bits()); | 423 DCHECK(string.Is64Bits() && index.Is32Bits() && result.Is64Bits()); |
424 // Fetch the instance type of the receiver into result register. | 424 // Fetch the instance type of the receiver into result register. |
425 __ Ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); | 425 __ Ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
426 __ Ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); | 426 __ Ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
427 | 427 |
428 // We need special handling for indirect strings. | 428 // We need special handling for indirect strings. |
429 Label check_sequential; | 429 Label check_sequential; |
430 __ TestAndBranchIfAllClear(result, kIsIndirectStringMask, &check_sequential); | 430 __ TestAndBranchIfAllClear(result, kIsIndirectStringMask, &check_sequential); |
431 | 431 |
432 // Dispatch on the indirect string shape: slice or cons. | 432 // Dispatch on the indirect string shape: slice or cons. |
433 Label cons_string; | 433 Label cons_string; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 DoubleRegister result, | 509 DoubleRegister result, |
510 DoubleRegister double_temp1, | 510 DoubleRegister double_temp1, |
511 DoubleRegister double_temp2, | 511 DoubleRegister double_temp2, |
512 Register temp1, | 512 Register temp1, |
513 Register temp2, | 513 Register temp2, |
514 Register temp3) { | 514 Register temp3) { |
515 // TODO(jbramley): There are several instances where fnmsub could be used | 515 // TODO(jbramley): There are several instances where fnmsub could be used |
516 // instead of fmul and fsub. Doing this changes the result, but since this is | 516 // instead of fmul and fsub. Doing this changes the result, but since this is |
517 // an estimation anyway, does it matter? | 517 // an estimation anyway, does it matter? |
518 | 518 |
519 ASSERT(!AreAliased(input, result, | 519 DCHECK(!AreAliased(input, result, |
520 double_temp1, double_temp2, | 520 double_temp1, double_temp2, |
521 temp1, temp2, temp3)); | 521 temp1, temp2, temp3)); |
522 ASSERT(ExternalReference::math_exp_constants(0).address() != NULL); | 522 DCHECK(ExternalReference::math_exp_constants(0).address() != NULL); |
523 | 523 |
524 Label done; | 524 Label done; |
525 DoubleRegister double_temp3 = result; | 525 DoubleRegister double_temp3 = result; |
526 Register constants = temp3; | 526 Register constants = temp3; |
527 | 527 |
528 // The algorithm used relies on some magic constants which are initialized in | 528 // The algorithm used relies on some magic constants which are initialized in |
529 // ExternalReference::InitializeMathExpData(). | 529 // ExternalReference::InitializeMathExpData(). |
530 | 530 |
531 // Load the address of the start of the array. | 531 // Load the address of the start of the array. |
532 __ Mov(constants, ExternalReference::math_exp_constants(0)); | 532 __ Mov(constants, ExternalReference::math_exp_constants(0)); |
533 | 533 |
534 // We have to do a four-way split here: | 534 // We have to do a four-way split here: |
535 // - If input <= about -708.4, the output always rounds to zero. | 535 // - If input <= about -708.4, the output always rounds to zero. |
536 // - If input >= about 709.8, the output always rounds to +infinity. | 536 // - If input >= about 709.8, the output always rounds to +infinity. |
537 // - If the input is NaN, the output is NaN. | 537 // - If the input is NaN, the output is NaN. |
538 // - Otherwise, the result needs to be calculated. | 538 // - Otherwise, the result needs to be calculated. |
539 Label result_is_finite_non_zero; | 539 Label result_is_finite_non_zero; |
540 // Assert that we can load offset 0 (the small input threshold) and offset 1 | 540 // Assert that we can load offset 0 (the small input threshold) and offset 1 |
541 // (the large input threshold) with a single ldp. | 541 // (the large input threshold) with a single ldp. |
542 ASSERT(kDRegSize == (ExpConstant(constants, 1).offset() - | 542 DCHECK(kDRegSize == (ExpConstant(constants, 1).offset() - |
543 ExpConstant(constants, 0).offset())); | 543 ExpConstant(constants, 0).offset())); |
544 __ Ldp(double_temp1, double_temp2, ExpConstant(constants, 0)); | 544 __ Ldp(double_temp1, double_temp2, ExpConstant(constants, 0)); |
545 | 545 |
546 __ Fcmp(input, double_temp1); | 546 __ Fcmp(input, double_temp1); |
547 __ Fccmp(input, double_temp2, NoFlag, hi); | 547 __ Fccmp(input, double_temp2, NoFlag, hi); |
548 // At this point, the condition flags can be in one of five states: | 548 // At this point, the condition flags can be in one of five states: |
549 // NZCV | 549 // NZCV |
550 // 1000 -708.4 < input < 709.8 result = exp(input) | 550 // 1000 -708.4 < input < 709.8 result = exp(input) |
551 // 0110 input == 709.8 result = +infinity | 551 // 0110 input == 709.8 result = +infinity |
552 // 0010 input > 709.8 result = +infinity | 552 // 0010 input > 709.8 result = +infinity |
553 // 0011 input is NaN result = input | 553 // 0011 input is NaN result = input |
554 // 0000 input <= -708.4 result = +0.0 | 554 // 0000 input <= -708.4 result = +0.0 |
555 | 555 |
556 // Continue the common case first. 'mi' tests N == 1. | 556 // Continue the common case first. 'mi' tests N == 1. |
557 __ B(&result_is_finite_non_zero, mi); | 557 __ B(&result_is_finite_non_zero, mi); |
558 | 558 |
559 // TODO(jbramley): Consider adding a +infinity register for ARM64. | 559 // TODO(jbramley): Consider adding a +infinity register for ARM64. |
560 __ Ldr(double_temp2, ExpConstant(constants, 2)); // Synthesize +infinity. | 560 __ Ldr(double_temp2, ExpConstant(constants, 2)); // Synthesize +infinity. |
561 | 561 |
562 // Select between +0.0 and +infinity. 'lo' tests C == 0. | 562 // Select between +0.0 and +infinity. 'lo' tests C == 0. |
563 __ Fcsel(result, fp_zero, double_temp2, lo); | 563 __ Fcsel(result, fp_zero, double_temp2, lo); |
564 // Select between {+0.0 or +infinity} and input. 'vc' tests V == 0. | 564 // Select between {+0.0 or +infinity} and input. 'vc' tests V == 0. |
565 __ Fcsel(result, result, input, vc); | 565 __ Fcsel(result, result, input, vc); |
566 __ B(&done); | 566 __ B(&done); |
567 | 567 |
568 // The rest is magic, as described in InitializeMathExpData(). | 568 // The rest is magic, as described in InitializeMathExpData(). |
569 __ Bind(&result_is_finite_non_zero); | 569 __ Bind(&result_is_finite_non_zero); |
570 | 570 |
571 // Assert that we can load offset 3 and offset 4 with a single ldp. | 571 // Assert that we can load offset 3 and offset 4 with a single ldp. |
572 ASSERT(kDRegSize == (ExpConstant(constants, 4).offset() - | 572 DCHECK(kDRegSize == (ExpConstant(constants, 4).offset() - |
573 ExpConstant(constants, 3).offset())); | 573 ExpConstant(constants, 3).offset())); |
574 __ Ldp(double_temp1, double_temp3, ExpConstant(constants, 3)); | 574 __ Ldp(double_temp1, double_temp3, ExpConstant(constants, 3)); |
575 __ Fmadd(double_temp1, double_temp1, input, double_temp3); | 575 __ Fmadd(double_temp1, double_temp1, input, double_temp3); |
576 __ Fmov(temp2.W(), double_temp1.S()); | 576 __ Fmov(temp2.W(), double_temp1.S()); |
577 __ Fsub(double_temp1, double_temp1, double_temp3); | 577 __ Fsub(double_temp1, double_temp1, double_temp3); |
578 | 578 |
579 // Assert that we can load offset 5 and offset 6 with a single ldp. | 579 // Assert that we can load offset 5 and offset 6 with a single ldp. |
580 ASSERT(kDRegSize == (ExpConstant(constants, 6).offset() - | 580 DCHECK(kDRegSize == (ExpConstant(constants, 6).offset() - |
581 ExpConstant(constants, 5).offset())); | 581 ExpConstant(constants, 5).offset())); |
582 __ Ldp(double_temp2, double_temp3, ExpConstant(constants, 5)); | 582 __ Ldp(double_temp2, double_temp3, ExpConstant(constants, 5)); |
583 // TODO(jbramley): Consider using Fnmsub here. | 583 // TODO(jbramley): Consider using Fnmsub here. |
584 __ Fmul(double_temp1, double_temp1, double_temp2); | 584 __ Fmul(double_temp1, double_temp1, double_temp2); |
585 __ Fsub(double_temp1, double_temp1, input); | 585 __ Fsub(double_temp1, double_temp1, input); |
586 | 586 |
587 __ Fmul(double_temp2, double_temp1, double_temp1); | 587 __ Fmul(double_temp2, double_temp1, double_temp1); |
588 __ Fsub(double_temp3, double_temp3, double_temp1); | 588 __ Fsub(double_temp3, double_temp3, double_temp1); |
589 __ Fmul(double_temp3, double_temp3, double_temp2); | 589 __ Fmul(double_temp3, double_temp3, double_temp2); |
590 | 590 |
(...skipping 25 matching lines...) Expand all Loading... |
616 __ Fmul(result, double_temp3, double_temp1); | 616 __ Fmul(result, double_temp3, double_temp1); |
617 | 617 |
618 __ Bind(&done); | 618 __ Bind(&done); |
619 } | 619 } |
620 | 620 |
621 #undef __ | 621 #undef __ |
622 | 622 |
623 } } // namespace v8::internal | 623 } } // namespace v8::internal |
624 | 624 |
625 #endif // V8_TARGET_ARCH_ARM64 | 625 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |