| 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/code-stubs.h" | 9 #include "src/code-stubs.h" |
| 10 #include "src/cpu-profiler.h" | 10 #include "src/cpu-profiler.h" |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 masm_(new MacroAssembler(zone->isolate(), NULL, kRegExpCodeSize)), | 119 masm_(new MacroAssembler(zone->isolate(), NULL, kRegExpCodeSize)), |
| 120 mode_(mode), | 120 mode_(mode), |
| 121 num_registers_(registers_to_save), | 121 num_registers_(registers_to_save), |
| 122 num_saved_registers_(registers_to_save), | 122 num_saved_registers_(registers_to_save), |
| 123 entry_label_(), | 123 entry_label_(), |
| 124 start_label_(), | 124 start_label_(), |
| 125 success_label_(), | 125 success_label_(), |
| 126 backtrack_label_(), | 126 backtrack_label_(), |
| 127 exit_label_() { | 127 exit_label_() { |
| 128 __ SetStackPointer(csp); | 128 __ SetStackPointer(csp); |
| 129 ASSERT_EQ(0, registers_to_save % 2); | 129 DCHECK_EQ(0, registers_to_save % 2); |
| 130 // We can cache at most 16 W registers in x0-x7. | 130 // We can cache at most 16 W registers in x0-x7. |
| 131 STATIC_ASSERT(kNumCachedRegisters <= 16); | 131 STATIC_ASSERT(kNumCachedRegisters <= 16); |
| 132 STATIC_ASSERT((kNumCachedRegisters % 2) == 0); | 132 STATIC_ASSERT((kNumCachedRegisters % 2) == 0); |
| 133 __ B(&entry_label_); // We'll write the entry code later. | 133 __ B(&entry_label_); // We'll write the entry code later. |
| 134 __ Bind(&start_label_); // And then continue from here. | 134 __ Bind(&start_label_); // And then continue from here. |
| 135 } | 135 } |
| 136 | 136 |
| 137 | 137 |
| 138 RegExpMacroAssemblerARM64::~RegExpMacroAssemblerARM64() { | 138 RegExpMacroAssemblerARM64::~RegExpMacroAssemblerARM64() { |
| 139 delete masm_; | 139 delete masm_; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 154 | 154 |
| 155 void RegExpMacroAssemblerARM64::AdvanceCurrentPosition(int by) { | 155 void RegExpMacroAssemblerARM64::AdvanceCurrentPosition(int by) { |
| 156 if (by != 0) { | 156 if (by != 0) { |
| 157 __ Add(current_input_offset(), | 157 __ Add(current_input_offset(), |
| 158 current_input_offset(), by * char_size()); | 158 current_input_offset(), by * char_size()); |
| 159 } | 159 } |
| 160 } | 160 } |
| 161 | 161 |
| 162 | 162 |
| 163 void RegExpMacroAssemblerARM64::AdvanceRegister(int reg, int by) { | 163 void RegExpMacroAssemblerARM64::AdvanceRegister(int reg, int by) { |
| 164 ASSERT((reg >= 0) && (reg < num_registers_)); | 164 DCHECK((reg >= 0) && (reg < num_registers_)); |
| 165 if (by != 0) { | 165 if (by != 0) { |
| 166 Register to_advance; | 166 Register to_advance; |
| 167 RegisterState register_state = GetRegisterState(reg); | 167 RegisterState register_state = GetRegisterState(reg); |
| 168 switch (register_state) { | 168 switch (register_state) { |
| 169 case STACKED: | 169 case STACKED: |
| 170 __ Ldr(w10, register_location(reg)); | 170 __ Ldr(w10, register_location(reg)); |
| 171 __ Add(w10, w10, by); | 171 __ Add(w10, w10, by); |
| 172 __ Str(w10, register_location(reg)); | 172 __ Str(w10, register_location(reg)); |
| 173 break; | 173 break; |
| 174 case CACHED_LSW: | 174 case CACHED_LSW: |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 __ Add(characters_address, | 255 __ Add(characters_address, |
| 256 input_end(), | 256 input_end(), |
| 257 Operand(current_input_offset(), SXTW)); | 257 Operand(current_input_offset(), SXTW)); |
| 258 if (cp_offset != 0) { | 258 if (cp_offset != 0) { |
| 259 __ Add(characters_address, characters_address, cp_offset * char_size()); | 259 __ Add(characters_address, characters_address, cp_offset * char_size()); |
| 260 } | 260 } |
| 261 | 261 |
| 262 for (int i = 0; i < str.length(); i++) { | 262 for (int i = 0; i < str.length(); i++) { |
| 263 if (mode_ == ASCII) { | 263 if (mode_ == ASCII) { |
| 264 __ Ldrb(w10, MemOperand(characters_address, 1, PostIndex)); | 264 __ Ldrb(w10, MemOperand(characters_address, 1, PostIndex)); |
| 265 ASSERT(str[i] <= String::kMaxOneByteCharCode); | 265 DCHECK(str[i] <= String::kMaxOneByteCharCode); |
| 266 } else { | 266 } else { |
| 267 __ Ldrh(w10, MemOperand(characters_address, 2, PostIndex)); | 267 __ Ldrh(w10, MemOperand(characters_address, 2, PostIndex)); |
| 268 } | 268 } |
| 269 CompareAndBranchOrBacktrack(w10, str[i], ne, on_failure); | 269 CompareAndBranchOrBacktrack(w10, str[i], ne, on_failure); |
| 270 } | 270 } |
| 271 } | 271 } |
| 272 | 272 |
| 273 | 273 |
| 274 void RegExpMacroAssemblerARM64::CheckGreedyLoop(Label* on_equal) { | 274 void RegExpMacroAssemblerARM64::CheckGreedyLoop(Label* on_equal) { |
| 275 __ Ldr(w10, MemOperand(backtrack_stackpointer())); | 275 __ Ldr(w10, MemOperand(backtrack_stackpointer())); |
| 276 __ Cmp(current_input_offset(), w10); | 276 __ Cmp(current_input_offset(), w10); |
| 277 __ Cset(x11, eq); | 277 __ Cset(x11, eq); |
| 278 __ Add(backtrack_stackpointer(), | 278 __ Add(backtrack_stackpointer(), |
| 279 backtrack_stackpointer(), Operand(x11, LSL, kWRegSizeLog2)); | 279 backtrack_stackpointer(), Operand(x11, LSL, kWRegSizeLog2)); |
| 280 BranchOrBacktrack(eq, on_equal); | 280 BranchOrBacktrack(eq, on_equal); |
| 281 } | 281 } |
| 282 | 282 |
| 283 void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( | 283 void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( |
| 284 int start_reg, | 284 int start_reg, |
| 285 Label* on_no_match) { | 285 Label* on_no_match) { |
| 286 Label fallthrough; | 286 Label fallthrough; |
| 287 | 287 |
| 288 Register capture_start_offset = w10; | 288 Register capture_start_offset = w10; |
| 289 // Save the capture length in a callee-saved register so it will | 289 // Save the capture length in a callee-saved register so it will |
| 290 // be preserved if we call a C helper. | 290 // be preserved if we call a C helper. |
| 291 Register capture_length = w19; | 291 Register capture_length = w19; |
| 292 ASSERT(kCalleeSaved.IncludesAliasOf(capture_length)); | 292 DCHECK(kCalleeSaved.IncludesAliasOf(capture_length)); |
| 293 | 293 |
| 294 // Find length of back-referenced capture. | 294 // Find length of back-referenced capture. |
| 295 ASSERT((start_reg % 2) == 0); | 295 DCHECK((start_reg % 2) == 0); |
| 296 if (start_reg < kNumCachedRegisters) { | 296 if (start_reg < kNumCachedRegisters) { |
| 297 __ Mov(capture_start_offset.X(), GetCachedRegister(start_reg)); | 297 __ Mov(capture_start_offset.X(), GetCachedRegister(start_reg)); |
| 298 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits); | 298 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits); |
| 299 } else { | 299 } else { |
| 300 __ Ldp(w11, capture_start_offset, capture_location(start_reg, x10)); | 300 __ Ldp(w11, capture_start_offset, capture_location(start_reg, x10)); |
| 301 } | 301 } |
| 302 __ Sub(capture_length, w11, capture_start_offset); // Length to check. | 302 __ Sub(capture_length, w11, capture_start_offset); // Length to check. |
| 303 // Succeed on empty capture (including no capture). | 303 // Succeed on empty capture (including no capture). |
| 304 __ Cbz(capture_length, &fallthrough); | 304 __ Cbz(capture_length, &fallthrough); |
| 305 | 305 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 358 __ Bind(&success); | 358 __ Bind(&success); |
| 359 // Compute new value of character position after the matched part. | 359 // Compute new value of character position after the matched part. |
| 360 __ Sub(current_input_offset().X(), current_position_address, input_end()); | 360 __ Sub(current_input_offset().X(), current_position_address, input_end()); |
| 361 if (masm_->emit_debug_code()) { | 361 if (masm_->emit_debug_code()) { |
| 362 __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW)); | 362 __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW)); |
| 363 __ Ccmp(current_input_offset(), 0, NoFlag, eq); | 363 __ Ccmp(current_input_offset(), 0, NoFlag, eq); |
| 364 // The current input offset should be <= 0, and fit in a W register. | 364 // The current input offset should be <= 0, and fit in a W register. |
| 365 __ Check(le, kOffsetOutOfRange); | 365 __ Check(le, kOffsetOutOfRange); |
| 366 } | 366 } |
| 367 } else { | 367 } else { |
| 368 ASSERT(mode_ == UC16); | 368 DCHECK(mode_ == UC16); |
| 369 int argument_count = 4; | 369 int argument_count = 4; |
| 370 | 370 |
| 371 // The cached registers need to be retained. | 371 // The cached registers need to be retained. |
| 372 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7); | 372 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7); |
| 373 ASSERT((cached_registers.Count() * 2) == kNumCachedRegisters); | 373 DCHECK((cached_registers.Count() * 2) == kNumCachedRegisters); |
| 374 __ PushCPURegList(cached_registers); | 374 __ PushCPURegList(cached_registers); |
| 375 | 375 |
| 376 // Put arguments into arguments registers. | 376 // Put arguments into arguments registers. |
| 377 // Parameters are | 377 // Parameters are |
| 378 // x0: Address byte_offset1 - Address captured substring's start. | 378 // x0: Address byte_offset1 - Address captured substring's start. |
| 379 // x1: Address byte_offset2 - Address of current character position. | 379 // x1: Address byte_offset2 - Address of current character position. |
| 380 // w2: size_t byte_length - length of capture in bytes(!) | 380 // w2: size_t byte_length - length of capture in bytes(!) |
| 381 // x3: Isolate* isolate | 381 // x3: Isolate* isolate |
| 382 | 382 |
| 383 // Address of start of capture. | 383 // Address of start of capture. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 414 int start_reg, | 414 int start_reg, |
| 415 Label* on_no_match) { | 415 Label* on_no_match) { |
| 416 Label fallthrough; | 416 Label fallthrough; |
| 417 | 417 |
| 418 Register capture_start_address = x12; | 418 Register capture_start_address = x12; |
| 419 Register capture_end_address = x13; | 419 Register capture_end_address = x13; |
| 420 Register current_position_address = x14; | 420 Register current_position_address = x14; |
| 421 Register capture_length = w15; | 421 Register capture_length = w15; |
| 422 | 422 |
| 423 // Find length of back-referenced capture. | 423 // Find length of back-referenced capture. |
| 424 ASSERT((start_reg % 2) == 0); | 424 DCHECK((start_reg % 2) == 0); |
| 425 if (start_reg < kNumCachedRegisters) { | 425 if (start_reg < kNumCachedRegisters) { |
| 426 __ Mov(x10, GetCachedRegister(start_reg)); | 426 __ Mov(x10, GetCachedRegister(start_reg)); |
| 427 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits); | 427 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits); |
| 428 } else { | 428 } else { |
| 429 __ Ldp(w11, w10, capture_location(start_reg, x10)); | 429 __ Ldp(w11, w10, capture_location(start_reg, x10)); |
| 430 } | 430 } |
| 431 __ Sub(capture_length, w11, w10); // Length to check. | 431 __ Sub(capture_length, w11, w10); // Length to check. |
| 432 // Succeed on empty capture (including no capture). | 432 // Succeed on empty capture (including no capture). |
| 433 __ Cbz(capture_length, &fallthrough); | 433 __ Cbz(capture_length, &fallthrough); |
| 434 | 434 |
| 435 // Check that there are enough characters left in the input. | 435 // Check that there are enough characters left in the input. |
| 436 __ Cmn(capture_length, current_input_offset()); | 436 __ Cmn(capture_length, current_input_offset()); |
| 437 BranchOrBacktrack(gt, on_no_match); | 437 BranchOrBacktrack(gt, on_no_match); |
| 438 | 438 |
| 439 // Compute pointers to match string and capture string | 439 // Compute pointers to match string and capture string |
| 440 __ Add(capture_start_address, input_end(), Operand(w10, SXTW)); | 440 __ Add(capture_start_address, input_end(), Operand(w10, SXTW)); |
| 441 __ Add(capture_end_address, | 441 __ Add(capture_end_address, |
| 442 capture_start_address, | 442 capture_start_address, |
| 443 Operand(capture_length, SXTW)); | 443 Operand(capture_length, SXTW)); |
| 444 __ Add(current_position_address, | 444 __ Add(current_position_address, |
| 445 input_end(), | 445 input_end(), |
| 446 Operand(current_input_offset(), SXTW)); | 446 Operand(current_input_offset(), SXTW)); |
| 447 | 447 |
| 448 Label loop; | 448 Label loop; |
| 449 __ Bind(&loop); | 449 __ Bind(&loop); |
| 450 if (mode_ == ASCII) { | 450 if (mode_ == ASCII) { |
| 451 __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex)); | 451 __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex)); |
| 452 __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex)); | 452 __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex)); |
| 453 } else { | 453 } else { |
| 454 ASSERT(mode_ == UC16); | 454 DCHECK(mode_ == UC16); |
| 455 __ Ldrh(w10, MemOperand(capture_start_address, 2, PostIndex)); | 455 __ Ldrh(w10, MemOperand(capture_start_address, 2, PostIndex)); |
| 456 __ Ldrh(w11, MemOperand(current_position_address, 2, PostIndex)); | 456 __ Ldrh(w11, MemOperand(current_position_address, 2, PostIndex)); |
| 457 } | 457 } |
| 458 __ Cmp(w10, w11); | 458 __ Cmp(w10, w11); |
| 459 BranchOrBacktrack(ne, on_no_match); | 459 BranchOrBacktrack(ne, on_no_match); |
| 460 __ Cmp(capture_start_address, capture_end_address); | 460 __ Cmp(capture_start_address, capture_end_address); |
| 461 __ B(lt, &loop); | 461 __ B(lt, &loop); |
| 462 | 462 |
| 463 // Move current character position to position after match. | 463 // Move current character position to position after match. |
| 464 __ Sub(current_input_offset().X(), current_position_address, input_end()); | 464 __ Sub(current_input_offset().X(), current_position_address, input_end()); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 492 __ And(w10, current_character(), mask); | 492 __ And(w10, current_character(), mask); |
| 493 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal); | 493 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal); |
| 494 } | 494 } |
| 495 | 495 |
| 496 | 496 |
| 497 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterMinusAnd( | 497 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterMinusAnd( |
| 498 uc16 c, | 498 uc16 c, |
| 499 uc16 minus, | 499 uc16 minus, |
| 500 uc16 mask, | 500 uc16 mask, |
| 501 Label* on_not_equal) { | 501 Label* on_not_equal) { |
| 502 ASSERT(minus < String::kMaxUtf16CodeUnit); | 502 DCHECK(minus < String::kMaxUtf16CodeUnit); |
| 503 __ Sub(w10, current_character(), minus); | 503 __ Sub(w10, current_character(), minus); |
| 504 __ And(w10, w10, mask); | 504 __ And(w10, w10, mask); |
| 505 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal); | 505 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal); |
| 506 } | 506 } |
| 507 | 507 |
| 508 | 508 |
| 509 void RegExpMacroAssemblerARM64::CheckCharacterInRange( | 509 void RegExpMacroAssemblerARM64::CheckCharacterInRange( |
| 510 uc16 from, | 510 uc16 from, |
| 511 uc16 to, | 511 uc16 to, |
| 512 Label* on_in_range) { | 512 Label* on_in_range) { |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 674 // csp[0]: secondary link/return address used by native call | 674 // csp[0]: secondary link/return address used by native call |
| 675 | 675 |
| 676 // Tell the system that we have a stack frame. Because the type is MANUAL, no | 676 // Tell the system that we have a stack frame. Because the type is MANUAL, no |
| 677 // code is generated. | 677 // code is generated. |
| 678 FrameScope scope(masm_, StackFrame::MANUAL); | 678 FrameScope scope(masm_, StackFrame::MANUAL); |
| 679 | 679 |
| 680 // Push registers on the stack, only push the argument registers that we need. | 680 // Push registers on the stack, only push the argument registers that we need. |
| 681 CPURegList argument_registers(x0, x5, x6, x7); | 681 CPURegList argument_registers(x0, x5, x6, x7); |
| 682 | 682 |
| 683 CPURegList registers_to_retain = kCalleeSaved; | 683 CPURegList registers_to_retain = kCalleeSaved; |
| 684 ASSERT(kCalleeSaved.Count() == 11); | 684 DCHECK(kCalleeSaved.Count() == 11); |
| 685 registers_to_retain.Combine(lr); | 685 registers_to_retain.Combine(lr); |
| 686 | 686 |
| 687 ASSERT(csp.Is(__ StackPointer())); | 687 DCHECK(csp.Is(__ StackPointer())); |
| 688 __ PushCPURegList(registers_to_retain); | 688 __ PushCPURegList(registers_to_retain); |
| 689 __ PushCPURegList(argument_registers); | 689 __ PushCPURegList(argument_registers); |
| 690 | 690 |
| 691 // Set frame pointer in place. | 691 // Set frame pointer in place. |
| 692 __ Add(frame_pointer(), csp, argument_registers.Count() * kPointerSize); | 692 __ Add(frame_pointer(), csp, argument_registers.Count() * kPointerSize); |
| 693 | 693 |
| 694 // Initialize callee-saved registers. | 694 // Initialize callee-saved registers. |
| 695 __ Mov(start_offset(), w1); | 695 __ Mov(start_offset(), w1); |
| 696 __ Mov(input_start(), x2); | 696 __ Mov(input_start(), x2); |
| 697 __ Mov(input_end(), x3); | 697 __ Mov(input_end(), x3); |
| 698 __ Mov(output_array(), x4); | 698 __ Mov(output_array(), x4); |
| 699 | 699 |
| 700 // Set the number of registers we will need to allocate, that is: | 700 // Set the number of registers we will need to allocate, that is: |
| 701 // - success_counter (X register) | 701 // - success_counter (X register) |
| 702 // - (num_registers_ - kNumCachedRegisters) (W registers) | 702 // - (num_registers_ - kNumCachedRegisters) (W registers) |
| 703 int num_wreg_to_allocate = num_registers_ - kNumCachedRegisters; | 703 int num_wreg_to_allocate = num_registers_ - kNumCachedRegisters; |
| 704 // Do not allocate registers on the stack if they can all be cached. | 704 // Do not allocate registers on the stack if they can all be cached. |
| 705 if (num_wreg_to_allocate < 0) { num_wreg_to_allocate = 0; } | 705 if (num_wreg_to_allocate < 0) { num_wreg_to_allocate = 0; } |
| 706 // Make room for the success_counter. | 706 // Make room for the success_counter. |
| 707 num_wreg_to_allocate += 2; | 707 num_wreg_to_allocate += 2; |
| 708 | 708 |
| 709 // Make sure the stack alignment will be respected. | 709 // Make sure the stack alignment will be respected. |
| 710 int alignment = masm_->ActivationFrameAlignment(); | 710 int alignment = masm_->ActivationFrameAlignment(); |
| 711 ASSERT_EQ(alignment % 16, 0); | 711 DCHECK_EQ(alignment % 16, 0); |
| 712 int align_mask = (alignment / kWRegSize) - 1; | 712 int align_mask = (alignment / kWRegSize) - 1; |
| 713 num_wreg_to_allocate = (num_wreg_to_allocate + align_mask) & ~align_mask; | 713 num_wreg_to_allocate = (num_wreg_to_allocate + align_mask) & ~align_mask; |
| 714 | 714 |
| 715 // Check if we have space on the stack. | 715 // Check if we have space on the stack. |
| 716 Label stack_limit_hit; | 716 Label stack_limit_hit; |
| 717 Label stack_ok; | 717 Label stack_ok; |
| 718 | 718 |
| 719 ExternalReference stack_limit = | 719 ExternalReference stack_limit = |
| 720 ExternalReference::address_of_stack_limit(isolate()); | 720 ExternalReference::address_of_stack_limit(isolate()); |
| 721 __ Mov(x10, stack_limit); | 721 __ Mov(x10, stack_limit); |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 854 } | 854 } |
| 855 | 855 |
| 856 // Only carry on if there are more than kNumCachedRegisters capture | 856 // Only carry on if there are more than kNumCachedRegisters capture |
| 857 // registers. | 857 // registers. |
| 858 int num_registers_left_on_stack = | 858 int num_registers_left_on_stack = |
| 859 num_saved_registers_ - kNumCachedRegisters; | 859 num_saved_registers_ - kNumCachedRegisters; |
| 860 if (num_registers_left_on_stack > 0) { | 860 if (num_registers_left_on_stack > 0) { |
| 861 Register base = x10; | 861 Register base = x10; |
| 862 // There are always an even number of capture registers. A couple of | 862 // There are always an even number of capture registers. A couple of |
| 863 // registers determine one match with two offsets. | 863 // registers determine one match with two offsets. |
| 864 ASSERT_EQ(0, num_registers_left_on_stack % 2); | 864 DCHECK_EQ(0, num_registers_left_on_stack % 2); |
| 865 __ Add(base, frame_pointer(), kFirstCaptureOnStack); | 865 __ Add(base, frame_pointer(), kFirstCaptureOnStack); |
| 866 | 866 |
| 867 // We can unroll the loop here, we should not unroll for less than 2 | 867 // We can unroll the loop here, we should not unroll for less than 2 |
| 868 // registers. | 868 // registers. |
| 869 STATIC_ASSERT(kNumRegistersToUnroll > 2); | 869 STATIC_ASSERT(kNumRegistersToUnroll > 2); |
| 870 if (num_registers_left_on_stack <= kNumRegistersToUnroll) { | 870 if (num_registers_left_on_stack <= kNumRegistersToUnroll) { |
| 871 for (int i = 0; i < num_registers_left_on_stack / 2; i++) { | 871 for (int i = 0; i < num_registers_left_on_stack / 2; i++) { |
| 872 __ Ldp(capture_end, | 872 __ Ldp(capture_end, |
| 873 capture_start, | 873 capture_start, |
| 874 MemOperand(base, -kPointerSize, PostIndex)); | 874 MemOperand(base, -kPointerSize, PostIndex)); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 971 // Exit and return w0 | 971 // Exit and return w0 |
| 972 __ Bind(&exit_label_); | 972 __ Bind(&exit_label_); |
| 973 if (global()) { | 973 if (global()) { |
| 974 __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter)); | 974 __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter)); |
| 975 } | 975 } |
| 976 } | 976 } |
| 977 | 977 |
| 978 __ Bind(&return_w0); | 978 __ Bind(&return_w0); |
| 979 | 979 |
| 980 // Set stack pointer back to first register to retain | 980 // Set stack pointer back to first register to retain |
| 981 ASSERT(csp.Is(__ StackPointer())); | 981 DCHECK(csp.Is(__ StackPointer())); |
| 982 __ Mov(csp, fp); | 982 __ Mov(csp, fp); |
| 983 __ AssertStackConsistency(); | 983 __ AssertStackConsistency(); |
| 984 | 984 |
| 985 // Restore registers. | 985 // Restore registers. |
| 986 __ PopCPURegList(registers_to_retain); | 986 __ PopCPURegList(registers_to_retain); |
| 987 | 987 |
| 988 __ Ret(); | 988 __ Ret(); |
| 989 | 989 |
| 990 Label exit_with_exception; | 990 Label exit_with_exception; |
| 991 // Registers x0 to x7 are used to store the first captures, they need to be | 991 // Registers x0 to x7 are used to store the first captures, they need to be |
| 992 // retained over calls to C++ code. | 992 // retained over calls to C++ code. |
| 993 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7); | 993 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7); |
| 994 ASSERT((cached_registers.Count() * 2) == kNumCachedRegisters); | 994 DCHECK((cached_registers.Count() * 2) == kNumCachedRegisters); |
| 995 | 995 |
| 996 if (check_preempt_label_.is_linked()) { | 996 if (check_preempt_label_.is_linked()) { |
| 997 __ Bind(&check_preempt_label_); | 997 __ Bind(&check_preempt_label_); |
| 998 SaveLinkRegister(); | 998 SaveLinkRegister(); |
| 999 // The cached registers need to be retained. | 999 // The cached registers need to be retained. |
| 1000 __ PushCPURegList(cached_registers); | 1000 __ PushCPURegList(cached_registers); |
| 1001 CallCheckStackGuardState(x10); | 1001 CallCheckStackGuardState(x10); |
| 1002 // Returning from the regexp code restores the stack (csp <- fp) | 1002 // Returning from the regexp code restores the stack (csp <- fp) |
| 1003 // so we don't need to drop the link register from it before exiting. | 1003 // so we don't need to drop the link register from it before exiting. |
| 1004 __ Cbnz(w0, &return_w0); | 1004 __ Cbnz(w0, &return_w0); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1077 return kARM64Implementation; | 1077 return kARM64Implementation; |
| 1078 } | 1078 } |
| 1079 | 1079 |
| 1080 | 1080 |
| 1081 void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset, | 1081 void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset, |
| 1082 Label* on_end_of_input, | 1082 Label* on_end_of_input, |
| 1083 bool check_bounds, | 1083 bool check_bounds, |
| 1084 int characters) { | 1084 int characters) { |
| 1085 // TODO(pielan): Make sure long strings are caught before this, and not | 1085 // TODO(pielan): Make sure long strings are caught before this, and not |
| 1086 // just asserted in debug mode. | 1086 // just asserted in debug mode. |
| 1087 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. | 1087 DCHECK(cp_offset >= -1); // ^ and \b can look behind one character. |
| 1088 // Be sane! (And ensure that an int32_t can be used to index the string) | 1088 // Be sane! (And ensure that an int32_t can be used to index the string) |
| 1089 ASSERT(cp_offset < (1<<30)); | 1089 DCHECK(cp_offset < (1<<30)); |
| 1090 if (check_bounds) { | 1090 if (check_bounds) { |
| 1091 CheckPosition(cp_offset + characters - 1, on_end_of_input); | 1091 CheckPosition(cp_offset + characters - 1, on_end_of_input); |
| 1092 } | 1092 } |
| 1093 LoadCurrentCharacterUnchecked(cp_offset, characters); | 1093 LoadCurrentCharacterUnchecked(cp_offset, characters); |
| 1094 } | 1094 } |
| 1095 | 1095 |
| 1096 | 1096 |
| 1097 void RegExpMacroAssemblerARM64::PopCurrentPosition() { | 1097 void RegExpMacroAssemblerARM64::PopCurrentPosition() { |
| 1098 Pop(current_input_offset()); | 1098 Pop(current_input_offset()); |
| 1099 } | 1099 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1172 __ Mov(current_input_offset(), -by * char_size()); | 1172 __ Mov(current_input_offset(), -by * char_size()); |
| 1173 // On RegExp code entry (where this operation is used), the character before | 1173 // On RegExp code entry (where this operation is used), the character before |
| 1174 // the current position is expected to be already loaded. | 1174 // the current position is expected to be already loaded. |
| 1175 // We have advanced the position, so it's safe to read backwards. | 1175 // We have advanced the position, so it's safe to read backwards. |
| 1176 LoadCurrentCharacterUnchecked(-1, 1); | 1176 LoadCurrentCharacterUnchecked(-1, 1); |
| 1177 __ Bind(&after_position); | 1177 __ Bind(&after_position); |
| 1178 } | 1178 } |
| 1179 | 1179 |
| 1180 | 1180 |
| 1181 void RegExpMacroAssemblerARM64::SetRegister(int register_index, int to) { | 1181 void RegExpMacroAssemblerARM64::SetRegister(int register_index, int to) { |
| 1182 ASSERT(register_index >= num_saved_registers_); // Reserved for positions! | 1182 DCHECK(register_index >= num_saved_registers_); // Reserved for positions! |
| 1183 Register set_to = wzr; | 1183 Register set_to = wzr; |
| 1184 if (to != 0) { | 1184 if (to != 0) { |
| 1185 set_to = w10; | 1185 set_to = w10; |
| 1186 __ Mov(set_to, to); | 1186 __ Mov(set_to, to); |
| 1187 } | 1187 } |
| 1188 StoreRegister(register_index, set_to); | 1188 StoreRegister(register_index, set_to); |
| 1189 } | 1189 } |
| 1190 | 1190 |
| 1191 | 1191 |
| 1192 bool RegExpMacroAssemblerARM64::Succeed() { | 1192 bool RegExpMacroAssemblerARM64::Succeed() { |
| 1193 __ B(&success_label_); | 1193 __ B(&success_label_); |
| 1194 return global(); | 1194 return global(); |
| 1195 } | 1195 } |
| 1196 | 1196 |
| 1197 | 1197 |
| 1198 void RegExpMacroAssemblerARM64::WriteCurrentPositionToRegister(int reg, | 1198 void RegExpMacroAssemblerARM64::WriteCurrentPositionToRegister(int reg, |
| 1199 int cp_offset) { | 1199 int cp_offset) { |
| 1200 Register position = current_input_offset(); | 1200 Register position = current_input_offset(); |
| 1201 if (cp_offset != 0) { | 1201 if (cp_offset != 0) { |
| 1202 position = w10; | 1202 position = w10; |
| 1203 __ Add(position, current_input_offset(), cp_offset * char_size()); | 1203 __ Add(position, current_input_offset(), cp_offset * char_size()); |
| 1204 } | 1204 } |
| 1205 StoreRegister(reg, position); | 1205 StoreRegister(reg, position); |
| 1206 } | 1206 } |
| 1207 | 1207 |
| 1208 | 1208 |
| 1209 void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) { | 1209 void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) { |
| 1210 ASSERT(reg_from <= reg_to); | 1210 DCHECK(reg_from <= reg_to); |
| 1211 int num_registers = reg_to - reg_from + 1; | 1211 int num_registers = reg_to - reg_from + 1; |
| 1212 | 1212 |
| 1213 // If the first capture register is cached in a hardware register but not | 1213 // If the first capture register is cached in a hardware register but not |
| 1214 // aligned on a 64-bit one, we need to clear the first one specifically. | 1214 // aligned on a 64-bit one, we need to clear the first one specifically. |
| 1215 if ((reg_from < kNumCachedRegisters) && ((reg_from % 2) != 0)) { | 1215 if ((reg_from < kNumCachedRegisters) && ((reg_from % 2) != 0)) { |
| 1216 StoreRegister(reg_from, non_position_value()); | 1216 StoreRegister(reg_from, non_position_value()); |
| 1217 num_registers--; | 1217 num_registers--; |
| 1218 reg_from++; | 1218 reg_from++; |
| 1219 } | 1219 } |
| 1220 | 1220 |
| 1221 // Clear cached registers in pairs as far as possible. | 1221 // Clear cached registers in pairs as far as possible. |
| 1222 while ((num_registers >= 2) && (reg_from < kNumCachedRegisters)) { | 1222 while ((num_registers >= 2) && (reg_from < kNumCachedRegisters)) { |
| 1223 ASSERT(GetRegisterState(reg_from) == CACHED_LSW); | 1223 DCHECK(GetRegisterState(reg_from) == CACHED_LSW); |
| 1224 __ Mov(GetCachedRegister(reg_from), twice_non_position_value()); | 1224 __ Mov(GetCachedRegister(reg_from), twice_non_position_value()); |
| 1225 reg_from += 2; | 1225 reg_from += 2; |
| 1226 num_registers -= 2; | 1226 num_registers -= 2; |
| 1227 } | 1227 } |
| 1228 | 1228 |
| 1229 if ((num_registers % 2) == 1) { | 1229 if ((num_registers % 2) == 1) { |
| 1230 StoreRegister(reg_from, non_position_value()); | 1230 StoreRegister(reg_from, non_position_value()); |
| 1231 num_registers--; | 1231 num_registers--; |
| 1232 reg_from++; | 1232 reg_from++; |
| 1233 } | 1233 } |
| 1234 | 1234 |
| 1235 if (num_registers > 0) { | 1235 if (num_registers > 0) { |
| 1236 // If there are some remaining registers, they are stored on the stack. | 1236 // If there are some remaining registers, they are stored on the stack. |
| 1237 ASSERT(reg_from >= kNumCachedRegisters); | 1237 DCHECK(reg_from >= kNumCachedRegisters); |
| 1238 | 1238 |
| 1239 // Move down the indexes of the registers on stack to get the correct offset | 1239 // Move down the indexes of the registers on stack to get the correct offset |
| 1240 // in memory. | 1240 // in memory. |
| 1241 reg_from -= kNumCachedRegisters; | 1241 reg_from -= kNumCachedRegisters; |
| 1242 reg_to -= kNumCachedRegisters; | 1242 reg_to -= kNumCachedRegisters; |
| 1243 // We should not unroll the loop for less than 2 registers. | 1243 // We should not unroll the loop for less than 2 registers. |
| 1244 STATIC_ASSERT(kNumRegistersToUnroll > 2); | 1244 STATIC_ASSERT(kNumRegistersToUnroll > 2); |
| 1245 // We position the base pointer to (reg_from + 1). | 1245 // We position the base pointer to (reg_from + 1). |
| 1246 int base_offset = kFirstRegisterOnStack - | 1246 int base_offset = kFirstRegisterOnStack - |
| 1247 kWRegSize - (kWRegSize * reg_from); | 1247 kWRegSize - (kWRegSize * reg_from); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1310 | 1310 |
| 1311 // Prepare for possible GC. | 1311 // Prepare for possible GC. |
| 1312 HandleScope handles(isolate); | 1312 HandleScope handles(isolate); |
| 1313 Handle<Code> code_handle(re_code); | 1313 Handle<Code> code_handle(re_code); |
| 1314 | 1314 |
| 1315 Handle<String> subject(frame_entry<String*>(re_frame, kInput)); | 1315 Handle<String> subject(frame_entry<String*>(re_frame, kInput)); |
| 1316 | 1316 |
| 1317 // Current string. | 1317 // Current string. |
| 1318 bool is_ascii = subject->IsOneByteRepresentationUnderneath(); | 1318 bool is_ascii = subject->IsOneByteRepresentationUnderneath(); |
| 1319 | 1319 |
| 1320 ASSERT(re_code->instruction_start() <= *return_address); | 1320 DCHECK(re_code->instruction_start() <= *return_address); |
| 1321 ASSERT(*return_address <= | 1321 DCHECK(*return_address <= |
| 1322 re_code->instruction_start() + re_code->instruction_size()); | 1322 re_code->instruction_start() + re_code->instruction_size()); |
| 1323 | 1323 |
| 1324 Object* result = isolate->stack_guard()->HandleInterrupts(); | 1324 Object* result = isolate->stack_guard()->HandleInterrupts(); |
| 1325 | 1325 |
| 1326 if (*code_handle != re_code) { // Return address no longer valid | 1326 if (*code_handle != re_code) { // Return address no longer valid |
| 1327 int delta = code_handle->address() - re_code->address(); | 1327 int delta = code_handle->address() - re_code->address(); |
| 1328 // Overwrite the return address on the stack. | 1328 // Overwrite the return address on the stack. |
| 1329 *return_address += delta; | 1329 *return_address += delta; |
| 1330 } | 1330 } |
| 1331 | 1331 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1350 // If we changed between an ASCII and an UC16 string, the specialized | 1350 // If we changed between an ASCII and an UC16 string, the specialized |
| 1351 // code cannot be used, and we need to restart regexp matching from | 1351 // code cannot be used, and we need to restart regexp matching from |
| 1352 // scratch (including, potentially, compiling a new version of the code). | 1352 // scratch (including, potentially, compiling a new version of the code). |
| 1353 return RETRY; | 1353 return RETRY; |
| 1354 } | 1354 } |
| 1355 | 1355 |
| 1356 // Otherwise, the content of the string might have moved. It must still | 1356 // Otherwise, the content of the string might have moved. It must still |
| 1357 // be a sequential or external string with the same content. | 1357 // be a sequential or external string with the same content. |
| 1358 // Update the start and end pointers in the stack frame to the current | 1358 // Update the start and end pointers in the stack frame to the current |
| 1359 // location (whether it has actually moved or not). | 1359 // location (whether it has actually moved or not). |
| 1360 ASSERT(StringShape(*subject_tmp).IsSequential() || | 1360 DCHECK(StringShape(*subject_tmp).IsSequential() || |
| 1361 StringShape(*subject_tmp).IsExternal()); | 1361 StringShape(*subject_tmp).IsExternal()); |
| 1362 | 1362 |
| 1363 // The original start address of the characters to match. | 1363 // The original start address of the characters to match. |
| 1364 const byte* start_address = *input_start; | 1364 const byte* start_address = *input_start; |
| 1365 | 1365 |
| 1366 // Find the current start address of the same character at the current string | 1366 // Find the current start address of the same character at the current string |
| 1367 // position. | 1367 // position. |
| 1368 const byte* new_address = StringCharacterPosition(*subject_tmp, | 1368 const byte* new_address = StringCharacterPosition(*subject_tmp, |
| 1369 start_offset + slice_offset); | 1369 start_offset + slice_offset); |
| 1370 | 1370 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1403 | 1403 |
| 1404 | 1404 |
| 1405 // Private methods: | 1405 // Private methods: |
| 1406 | 1406 |
| 1407 void RegExpMacroAssemblerARM64::CallCheckStackGuardState(Register scratch) { | 1407 void RegExpMacroAssemblerARM64::CallCheckStackGuardState(Register scratch) { |
| 1408 // Allocate space on the stack to store the return address. The | 1408 // Allocate space on the stack to store the return address. The |
| 1409 // CheckStackGuardState C++ function will override it if the code | 1409 // CheckStackGuardState C++ function will override it if the code |
| 1410 // moved. Allocate extra space for 2 arguments passed by pointers. | 1410 // moved. Allocate extra space for 2 arguments passed by pointers. |
| 1411 // AAPCS64 requires the stack to be 16 byte aligned. | 1411 // AAPCS64 requires the stack to be 16 byte aligned. |
| 1412 int alignment = masm_->ActivationFrameAlignment(); | 1412 int alignment = masm_->ActivationFrameAlignment(); |
| 1413 ASSERT_EQ(alignment % 16, 0); | 1413 DCHECK_EQ(alignment % 16, 0); |
| 1414 int align_mask = (alignment / kXRegSize) - 1; | 1414 int align_mask = (alignment / kXRegSize) - 1; |
| 1415 int xreg_to_claim = (3 + align_mask) & ~align_mask; | 1415 int xreg_to_claim = (3 + align_mask) & ~align_mask; |
| 1416 | 1416 |
| 1417 ASSERT(csp.Is(__ StackPointer())); | 1417 DCHECK(csp.Is(__ StackPointer())); |
| 1418 __ Claim(xreg_to_claim); | 1418 __ Claim(xreg_to_claim); |
| 1419 | 1419 |
| 1420 // CheckStackGuardState needs the end and start addresses of the input string. | 1420 // CheckStackGuardState needs the end and start addresses of the input string. |
| 1421 __ Poke(input_end(), 2 * kPointerSize); | 1421 __ Poke(input_end(), 2 * kPointerSize); |
| 1422 __ Add(x5, csp, 2 * kPointerSize); | 1422 __ Add(x5, csp, 2 * kPointerSize); |
| 1423 __ Poke(input_start(), kPointerSize); | 1423 __ Poke(input_start(), kPointerSize); |
| 1424 __ Add(x4, csp, kPointerSize); | 1424 __ Add(x4, csp, kPointerSize); |
| 1425 | 1425 |
| 1426 __ Mov(w3, start_offset()); | 1426 __ Mov(w3, start_offset()); |
| 1427 // RegExp code frame pointer. | 1427 // RegExp code frame pointer. |
| 1428 __ Mov(x2, frame_pointer()); | 1428 __ Mov(x2, frame_pointer()); |
| 1429 // Code* of self. | 1429 // Code* of self. |
| 1430 __ Mov(x1, Operand(masm_->CodeObject())); | 1430 __ Mov(x1, Operand(masm_->CodeObject())); |
| 1431 | 1431 |
| 1432 // We need to pass a pointer to the return address as first argument. | 1432 // We need to pass a pointer to the return address as first argument. |
| 1433 // The DirectCEntry stub will place the return address on the stack before | 1433 // The DirectCEntry stub will place the return address on the stack before |
| 1434 // calling so the stack pointer will point to it. | 1434 // calling so the stack pointer will point to it. |
| 1435 __ Mov(x0, csp); | 1435 __ Mov(x0, csp); |
| 1436 | 1436 |
| 1437 ExternalReference check_stack_guard_state = | 1437 ExternalReference check_stack_guard_state = |
| 1438 ExternalReference::re_check_stack_guard_state(isolate()); | 1438 ExternalReference::re_check_stack_guard_state(isolate()); |
| 1439 __ Mov(scratch, check_stack_guard_state); | 1439 __ Mov(scratch, check_stack_guard_state); |
| 1440 DirectCEntryStub stub(isolate()); | 1440 DirectCEntryStub stub(isolate()); |
| 1441 stub.GenerateCall(masm_, scratch); | 1441 stub.GenerateCall(masm_, scratch); |
| 1442 | 1442 |
| 1443 // The input string may have been moved in memory, we need to reload it. | 1443 // The input string may have been moved in memory, we need to reload it. |
| 1444 __ Peek(input_start(), kPointerSize); | 1444 __ Peek(input_start(), kPointerSize); |
| 1445 __ Peek(input_end(), 2 * kPointerSize); | 1445 __ Peek(input_end(), 2 * kPointerSize); |
| 1446 | 1446 |
| 1447 ASSERT(csp.Is(__ StackPointer())); | 1447 DCHECK(csp.Is(__ StackPointer())); |
| 1448 __ Drop(xreg_to_claim); | 1448 __ Drop(xreg_to_claim); |
| 1449 | 1449 |
| 1450 // Reload the Code pointer. | 1450 // Reload the Code pointer. |
| 1451 __ Mov(code_pointer(), Operand(masm_->CodeObject())); | 1451 __ Mov(code_pointer(), Operand(masm_->CodeObject())); |
| 1452 } | 1452 } |
| 1453 | 1453 |
| 1454 void RegExpMacroAssemblerARM64::BranchOrBacktrack(Condition condition, | 1454 void RegExpMacroAssemblerARM64::BranchOrBacktrack(Condition condition, |
| 1455 Label* to) { | 1455 Label* to) { |
| 1456 if (condition == al) { // Unconditional. | 1456 if (condition == al) { // Unconditional. |
| 1457 if (to == NULL) { | 1457 if (to == NULL) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1486 } | 1486 } |
| 1487 } | 1487 } |
| 1488 | 1488 |
| 1489 | 1489 |
| 1490 void RegExpMacroAssemblerARM64::CheckPreemption() { | 1490 void RegExpMacroAssemblerARM64::CheckPreemption() { |
| 1491 // Check for preemption. | 1491 // Check for preemption. |
| 1492 ExternalReference stack_limit = | 1492 ExternalReference stack_limit = |
| 1493 ExternalReference::address_of_stack_limit(isolate()); | 1493 ExternalReference::address_of_stack_limit(isolate()); |
| 1494 __ Mov(x10, stack_limit); | 1494 __ Mov(x10, stack_limit); |
| 1495 __ Ldr(x10, MemOperand(x10)); | 1495 __ Ldr(x10, MemOperand(x10)); |
| 1496 ASSERT(csp.Is(__ StackPointer())); | 1496 DCHECK(csp.Is(__ StackPointer())); |
| 1497 __ Cmp(csp, x10); | 1497 __ Cmp(csp, x10); |
| 1498 CallIf(&check_preempt_label_, ls); | 1498 CallIf(&check_preempt_label_, ls); |
| 1499 } | 1499 } |
| 1500 | 1500 |
| 1501 | 1501 |
| 1502 void RegExpMacroAssemblerARM64::CheckStackLimit() { | 1502 void RegExpMacroAssemblerARM64::CheckStackLimit() { |
| 1503 ExternalReference stack_limit = | 1503 ExternalReference stack_limit = |
| 1504 ExternalReference::address_of_regexp_stack_limit(isolate()); | 1504 ExternalReference::address_of_regexp_stack_limit(isolate()); |
| 1505 __ Mov(x10, stack_limit); | 1505 __ Mov(x10, stack_limit); |
| 1506 __ Ldr(x10, MemOperand(x10)); | 1506 __ Ldr(x10, MemOperand(x10)); |
| 1507 __ Cmp(backtrack_stackpointer(), x10); | 1507 __ Cmp(backtrack_stackpointer(), x10); |
| 1508 CallIf(&stack_overflow_label_, ls); | 1508 CallIf(&stack_overflow_label_, ls); |
| 1509 } | 1509 } |
| 1510 | 1510 |
| 1511 | 1511 |
| 1512 void RegExpMacroAssemblerARM64::Push(Register source) { | 1512 void RegExpMacroAssemblerARM64::Push(Register source) { |
| 1513 ASSERT(source.Is32Bits()); | 1513 DCHECK(source.Is32Bits()); |
| 1514 ASSERT(!source.is(backtrack_stackpointer())); | 1514 DCHECK(!source.is(backtrack_stackpointer())); |
| 1515 __ Str(source, | 1515 __ Str(source, |
| 1516 MemOperand(backtrack_stackpointer(), | 1516 MemOperand(backtrack_stackpointer(), |
| 1517 -static_cast<int>(kWRegSize), | 1517 -static_cast<int>(kWRegSize), |
| 1518 PreIndex)); | 1518 PreIndex)); |
| 1519 } | 1519 } |
| 1520 | 1520 |
| 1521 | 1521 |
| 1522 void RegExpMacroAssemblerARM64::Pop(Register target) { | 1522 void RegExpMacroAssemblerARM64::Pop(Register target) { |
| 1523 ASSERT(target.Is32Bits()); | 1523 DCHECK(target.Is32Bits()); |
| 1524 ASSERT(!target.is(backtrack_stackpointer())); | 1524 DCHECK(!target.is(backtrack_stackpointer())); |
| 1525 __ Ldr(target, | 1525 __ Ldr(target, |
| 1526 MemOperand(backtrack_stackpointer(), kWRegSize, PostIndex)); | 1526 MemOperand(backtrack_stackpointer(), kWRegSize, PostIndex)); |
| 1527 } | 1527 } |
| 1528 | 1528 |
| 1529 | 1529 |
| 1530 Register RegExpMacroAssemblerARM64::GetCachedRegister(int register_index) { | 1530 Register RegExpMacroAssemblerARM64::GetCachedRegister(int register_index) { |
| 1531 ASSERT(register_index < kNumCachedRegisters); | 1531 DCHECK(register_index < kNumCachedRegisters); |
| 1532 return Register::Create(register_index / 2, kXRegSizeInBits); | 1532 return Register::Create(register_index / 2, kXRegSizeInBits); |
| 1533 } | 1533 } |
| 1534 | 1534 |
| 1535 | 1535 |
| 1536 Register RegExpMacroAssemblerARM64::GetRegister(int register_index, | 1536 Register RegExpMacroAssemblerARM64::GetRegister(int register_index, |
| 1537 Register maybe_result) { | 1537 Register maybe_result) { |
| 1538 ASSERT(maybe_result.Is32Bits()); | 1538 DCHECK(maybe_result.Is32Bits()); |
| 1539 ASSERT(register_index >= 0); | 1539 DCHECK(register_index >= 0); |
| 1540 if (num_registers_ <= register_index) { | 1540 if (num_registers_ <= register_index) { |
| 1541 num_registers_ = register_index + 1; | 1541 num_registers_ = register_index + 1; |
| 1542 } | 1542 } |
| 1543 Register result; | 1543 Register result; |
| 1544 RegisterState register_state = GetRegisterState(register_index); | 1544 RegisterState register_state = GetRegisterState(register_index); |
| 1545 switch (register_state) { | 1545 switch (register_state) { |
| 1546 case STACKED: | 1546 case STACKED: |
| 1547 __ Ldr(maybe_result, register_location(register_index)); | 1547 __ Ldr(maybe_result, register_location(register_index)); |
| 1548 result = maybe_result; | 1548 result = maybe_result; |
| 1549 break; | 1549 break; |
| 1550 case CACHED_LSW: | 1550 case CACHED_LSW: |
| 1551 result = GetCachedRegister(register_index).W(); | 1551 result = GetCachedRegister(register_index).W(); |
| 1552 break; | 1552 break; |
| 1553 case CACHED_MSW: | 1553 case CACHED_MSW: |
| 1554 __ Lsr(maybe_result.X(), GetCachedRegister(register_index), | 1554 __ Lsr(maybe_result.X(), GetCachedRegister(register_index), |
| 1555 kWRegSizeInBits); | 1555 kWRegSizeInBits); |
| 1556 result = maybe_result; | 1556 result = maybe_result; |
| 1557 break; | 1557 break; |
| 1558 default: | 1558 default: |
| 1559 UNREACHABLE(); | 1559 UNREACHABLE(); |
| 1560 break; | 1560 break; |
| 1561 } | 1561 } |
| 1562 ASSERT(result.Is32Bits()); | 1562 DCHECK(result.Is32Bits()); |
| 1563 return result; | 1563 return result; |
| 1564 } | 1564 } |
| 1565 | 1565 |
| 1566 | 1566 |
| 1567 void RegExpMacroAssemblerARM64::StoreRegister(int register_index, | 1567 void RegExpMacroAssemblerARM64::StoreRegister(int register_index, |
| 1568 Register source) { | 1568 Register source) { |
| 1569 ASSERT(source.Is32Bits()); | 1569 DCHECK(source.Is32Bits()); |
| 1570 ASSERT(register_index >= 0); | 1570 DCHECK(register_index >= 0); |
| 1571 if (num_registers_ <= register_index) { | 1571 if (num_registers_ <= register_index) { |
| 1572 num_registers_ = register_index + 1; | 1572 num_registers_ = register_index + 1; |
| 1573 } | 1573 } |
| 1574 | 1574 |
| 1575 Register cached_register; | 1575 Register cached_register; |
| 1576 RegisterState register_state = GetRegisterState(register_index); | 1576 RegisterState register_state = GetRegisterState(register_index); |
| 1577 switch (register_state) { | 1577 switch (register_state) { |
| 1578 case STACKED: | 1578 case STACKED: |
| 1579 __ Str(source, register_location(register_index)); | 1579 __ Str(source, register_location(register_index)); |
| 1580 break; | 1580 break; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1597 | 1597 |
| 1598 void RegExpMacroAssemblerARM64::CallIf(Label* to, Condition condition) { | 1598 void RegExpMacroAssemblerARM64::CallIf(Label* to, Condition condition) { |
| 1599 Label skip_call; | 1599 Label skip_call; |
| 1600 if (condition != al) __ B(&skip_call, NegateCondition(condition)); | 1600 if (condition != al) __ B(&skip_call, NegateCondition(condition)); |
| 1601 __ Bl(to); | 1601 __ Bl(to); |
| 1602 __ Bind(&skip_call); | 1602 __ Bind(&skip_call); |
| 1603 } | 1603 } |
| 1604 | 1604 |
| 1605 | 1605 |
| 1606 void RegExpMacroAssemblerARM64::RestoreLinkRegister() { | 1606 void RegExpMacroAssemblerARM64::RestoreLinkRegister() { |
| 1607 ASSERT(csp.Is(__ StackPointer())); | 1607 DCHECK(csp.Is(__ StackPointer())); |
| 1608 __ Pop(lr, xzr); | 1608 __ Pop(lr, xzr); |
| 1609 __ Add(lr, lr, Operand(masm_->CodeObject())); | 1609 __ Add(lr, lr, Operand(masm_->CodeObject())); |
| 1610 } | 1610 } |
| 1611 | 1611 |
| 1612 | 1612 |
| 1613 void RegExpMacroAssemblerARM64::SaveLinkRegister() { | 1613 void RegExpMacroAssemblerARM64::SaveLinkRegister() { |
| 1614 ASSERT(csp.Is(__ StackPointer())); | 1614 DCHECK(csp.Is(__ StackPointer())); |
| 1615 __ Sub(lr, lr, Operand(masm_->CodeObject())); | 1615 __ Sub(lr, lr, Operand(masm_->CodeObject())); |
| 1616 __ Push(xzr, lr); | 1616 __ Push(xzr, lr); |
| 1617 } | 1617 } |
| 1618 | 1618 |
| 1619 | 1619 |
| 1620 MemOperand RegExpMacroAssemblerARM64::register_location(int register_index) { | 1620 MemOperand RegExpMacroAssemblerARM64::register_location(int register_index) { |
| 1621 ASSERT(register_index < (1<<30)); | 1621 DCHECK(register_index < (1<<30)); |
| 1622 ASSERT(register_index >= kNumCachedRegisters); | 1622 DCHECK(register_index >= kNumCachedRegisters); |
| 1623 if (num_registers_ <= register_index) { | 1623 if (num_registers_ <= register_index) { |
| 1624 num_registers_ = register_index + 1; | 1624 num_registers_ = register_index + 1; |
| 1625 } | 1625 } |
| 1626 register_index -= kNumCachedRegisters; | 1626 register_index -= kNumCachedRegisters; |
| 1627 int offset = kFirstRegisterOnStack - register_index * kWRegSize; | 1627 int offset = kFirstRegisterOnStack - register_index * kWRegSize; |
| 1628 return MemOperand(frame_pointer(), offset); | 1628 return MemOperand(frame_pointer(), offset); |
| 1629 } | 1629 } |
| 1630 | 1630 |
| 1631 MemOperand RegExpMacroAssemblerARM64::capture_location(int register_index, | 1631 MemOperand RegExpMacroAssemblerARM64::capture_location(int register_index, |
| 1632 Register scratch) { | 1632 Register scratch) { |
| 1633 ASSERT(register_index < (1<<30)); | 1633 DCHECK(register_index < (1<<30)); |
| 1634 ASSERT(register_index < num_saved_registers_); | 1634 DCHECK(register_index < num_saved_registers_); |
| 1635 ASSERT(register_index >= kNumCachedRegisters); | 1635 DCHECK(register_index >= kNumCachedRegisters); |
| 1636 ASSERT_EQ(register_index % 2, 0); | 1636 DCHECK_EQ(register_index % 2, 0); |
| 1637 register_index -= kNumCachedRegisters; | 1637 register_index -= kNumCachedRegisters; |
| 1638 int offset = kFirstCaptureOnStack - register_index * kWRegSize; | 1638 int offset = kFirstCaptureOnStack - register_index * kWRegSize; |
| 1639 // capture_location is used with Stp instructions to load/store 2 registers. | 1639 // capture_location is used with Stp instructions to load/store 2 registers. |
| 1640 // The immediate field in the encoding is limited to 7 bits (signed). | 1640 // The immediate field in the encoding is limited to 7 bits (signed). |
| 1641 if (is_int7(offset)) { | 1641 if (is_int7(offset)) { |
| 1642 return MemOperand(frame_pointer(), offset); | 1642 return MemOperand(frame_pointer(), offset); |
| 1643 } else { | 1643 } else { |
| 1644 __ Add(scratch, frame_pointer(), offset); | 1644 __ Add(scratch, frame_pointer(), offset); |
| 1645 return MemOperand(scratch); | 1645 return MemOperand(scratch); |
| 1646 } | 1646 } |
| 1647 } | 1647 } |
| 1648 | 1648 |
| 1649 void RegExpMacroAssemblerARM64::LoadCurrentCharacterUnchecked(int cp_offset, | 1649 void RegExpMacroAssemblerARM64::LoadCurrentCharacterUnchecked(int cp_offset, |
| 1650 int characters) { | 1650 int characters) { |
| 1651 Register offset = current_input_offset(); | 1651 Register offset = current_input_offset(); |
| 1652 | 1652 |
| 1653 // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU | 1653 // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU |
| 1654 // and the operating system running on the target allow it. | 1654 // and the operating system running on the target allow it. |
| 1655 // If unaligned load/stores are not supported then this function must only | 1655 // If unaligned load/stores are not supported then this function must only |
| 1656 // be used to load a single character at a time. | 1656 // be used to load a single character at a time. |
| 1657 | 1657 |
| 1658 // ARMv8 supports unaligned accesses but V8 or the kernel can decide to | 1658 // ARMv8 supports unaligned accesses but V8 or the kernel can decide to |
| 1659 // disable it. | 1659 // disable it. |
| 1660 // TODO(pielan): See whether or not we should disable unaligned accesses. | 1660 // TODO(pielan): See whether or not we should disable unaligned accesses. |
| 1661 if (!CanReadUnaligned()) { | 1661 if (!CanReadUnaligned()) { |
| 1662 ASSERT(characters == 1); | 1662 DCHECK(characters == 1); |
| 1663 } | 1663 } |
| 1664 | 1664 |
| 1665 if (cp_offset != 0) { | 1665 if (cp_offset != 0) { |
| 1666 if (masm_->emit_debug_code()) { | 1666 if (masm_->emit_debug_code()) { |
| 1667 __ Mov(x10, cp_offset * char_size()); | 1667 __ Mov(x10, cp_offset * char_size()); |
| 1668 __ Add(x10, x10, Operand(current_input_offset(), SXTW)); | 1668 __ Add(x10, x10, Operand(current_input_offset(), SXTW)); |
| 1669 __ Cmp(x10, Operand(w10, SXTW)); | 1669 __ Cmp(x10, Operand(w10, SXTW)); |
| 1670 // The offset needs to fit in a W register. | 1670 // The offset needs to fit in a W register. |
| 1671 __ Check(eq, kOffsetOutOfRange); | 1671 __ Check(eq, kOffsetOutOfRange); |
| 1672 } else { | 1672 } else { |
| 1673 __ Add(w10, current_input_offset(), cp_offset * char_size()); | 1673 __ Add(w10, current_input_offset(), cp_offset * char_size()); |
| 1674 } | 1674 } |
| 1675 offset = w10; | 1675 offset = w10; |
| 1676 } | 1676 } |
| 1677 | 1677 |
| 1678 if (mode_ == ASCII) { | 1678 if (mode_ == ASCII) { |
| 1679 if (characters == 4) { | 1679 if (characters == 4) { |
| 1680 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW)); | 1680 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW)); |
| 1681 } else if (characters == 2) { | 1681 } else if (characters == 2) { |
| 1682 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW)); | 1682 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW)); |
| 1683 } else { | 1683 } else { |
| 1684 ASSERT(characters == 1); | 1684 DCHECK(characters == 1); |
| 1685 __ Ldrb(current_character(), MemOperand(input_end(), offset, SXTW)); | 1685 __ Ldrb(current_character(), MemOperand(input_end(), offset, SXTW)); |
| 1686 } | 1686 } |
| 1687 } else { | 1687 } else { |
| 1688 ASSERT(mode_ == UC16); | 1688 DCHECK(mode_ == UC16); |
| 1689 if (characters == 2) { | 1689 if (characters == 2) { |
| 1690 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW)); | 1690 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW)); |
| 1691 } else { | 1691 } else { |
| 1692 ASSERT(characters == 1); | 1692 DCHECK(characters == 1); |
| 1693 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW)); | 1693 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW)); |
| 1694 } | 1694 } |
| 1695 } | 1695 } |
| 1696 } | 1696 } |
| 1697 | 1697 |
| 1698 #endif // V8_INTERPRETED_REGEXP | 1698 #endif // V8_INTERPRETED_REGEXP |
| 1699 | 1699 |
| 1700 }} // namespace v8::internal | 1700 }} // namespace v8::internal |
| 1701 | 1701 |
| 1702 #endif // V8_TARGET_ARCH_ARM64 | 1702 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |