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#if V8_TARGET_ARCH_IA32 6 7#include "src/regexp/ia32/regexp-macro-assembler-ia32.h" 8 9#include "src/codegen/assembler-inl.h" 10#include "src/codegen/macro-assembler.h" 11#include "src/logging/log.h" 12#include "src/objects/objects-inl.h" 13#include "src/regexp/regexp-macro-assembler.h" 14#include "src/regexp/regexp-stack.h" 15#include "src/strings/unicode.h" 16 17namespace v8 { 18namespace internal { 19 20/* 21 * This assembler uses the following register assignment convention 22 * - edx : Current character. Must be loaded using LoadCurrentCharacter 23 * before using any of the dispatch methods. Temporarily stores the 24 * index of capture start after a matching pass for a global regexp. 25 * - edi : Current position in input, as negative offset from end of string. 26 * Please notice that this is the byte offset, not the character offset! 27 * - esi : end of input (points to byte after last character in input). 28 * - ebp : Frame pointer. Used to access arguments, local variables and 29 * RegExp registers. 30 * - esp : Points to tip of C stack. 31 * - ecx : Points to tip of backtrack stack 32 * 33 * The registers eax and ebx are free to use for computations. 34 * 35 * Each call to a public method should retain this convention. 36 * The stack will have the following structure: 37 * - Address regexp (address of the JSRegExp object; unused in 38 * native code, passed to match signature of 39 * the interpreter) 40 * - Isolate* isolate (address of the current isolate) 41 * - direct_call (if 1, direct call from JavaScript code, if 0 42 * call through the runtime system) 43 * - capture array size (may fit multiple sets of matches) 44 * - int* capture_array (int[num_saved_registers_], for output). 45 * - end of input (address of end of string) 46 * - start of input (address of first character in string) 47 * - start index (character index of start) 48 * - String input_string (location of a handle containing the string) 49 * --- frame alignment (if applicable) --- 50 * - return address 51 * ebp-> - old ebp 52 * - backup of caller esi 53 * - backup of caller edi 54 * - backup of caller ebx 55 * - success counter (only for global regexps to count matches). 56 * - Offset of location before start of input (effectively character 57 * string start - 1). Used to initialize capture registers to a 58 * non-position. 59 * - register 0 ebp[-4] (only positions must be stored in the first 60 * - register 1 ebp[-8] num_saved_registers_ registers) 61 * - ... 62 * 63 * The first num_saved_registers_ registers are initialized to point to 64 * "character -1" in the string (i.e., char_size() bytes before the first 65 * character of the string). The remaining registers starts out as garbage. 66 * 67 * The data up to the return address must be placed there by the calling 68 * code, by calling the code entry as cast to a function with the signature: 69 * int (*match)(String input_string, 70 * int start_index, 71 * Address start, 72 * Address end, 73 * int* capture_output_array, 74 * int num_capture_registers, 75 * bool direct_call = false, 76 * Isolate* isolate 77 * Address regexp); 78 */ 79 80#define __ ACCESS_MASM(masm_) 81 82const int RegExpMacroAssemblerIA32::kRegExpCodeSize; 83 84RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone, 85 Mode mode, 86 int registers_to_save) 87 : NativeRegExpMacroAssembler(isolate, zone), 88 masm_(std::make_unique<MacroAssembler>( 89 isolate, CodeObjectRequired::kYes, 90 NewAssemblerBuffer(kRegExpCodeSize))), 91 no_root_array_scope_(masm_.get()), 92 mode_(mode), 93 num_registers_(registers_to_save), 94 num_saved_registers_(registers_to_save), 95 entry_label_(), 96 start_label_(), 97 success_label_(), 98 backtrack_label_(), 99 exit_label_() { 100 DCHECK_EQ(0, registers_to_save % 2); 101 __ jmp(&entry_label_); // We'll write the entry code later. 102 __ bind(&start_label_); // And then continue from here. 103} 104 105RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() { 106 // Unuse labels in case we throw away the assembler without calling GetCode. 107 entry_label_.Unuse(); 108 start_label_.Unuse(); 109 success_label_.Unuse(); 110 backtrack_label_.Unuse(); 111 exit_label_.Unuse(); 112 check_preempt_label_.Unuse(); 113 stack_overflow_label_.Unuse(); 114 fallback_label_.Unuse(); 115} 116 117 118int RegExpMacroAssemblerIA32::stack_limit_slack() { 119 return RegExpStack::kStackLimitSlack; 120} 121 122 123void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) { 124 if (by != 0) { 125 __ add(edi, Immediate(by * char_size())); 126 } 127} 128 129 130void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) { 131 DCHECK_LE(0, reg); 132 DCHECK_GT(num_registers_, reg); 133 if (by != 0) { 134 __ add(register_location(reg), Immediate(by)); 135 } 136} 137 138 139void RegExpMacroAssemblerIA32::Backtrack() { 140 CheckPreemption(); 141 if (has_backtrack_limit()) { 142 Label next; 143 __ inc(Operand(ebp, kBacktrackCount)); 144 __ cmp(Operand(ebp, kBacktrackCount), Immediate(backtrack_limit())); 145 __ j(not_equal, &next); 146 147 // Backtrack limit exceeded. 148 if (can_fallback()) { 149 __ jmp(&fallback_label_); 150 } else { 151 // Can't fallback, so we treat it as a failed match. 152 Fail(); 153 } 154 155 __ bind(&next); 156 } 157 // Pop Code offset from backtrack stack, add Code and jump to location. 158 Pop(ebx); 159 __ add(ebx, Immediate(masm_->CodeObject())); 160 __ jmp(ebx); 161} 162 163 164void RegExpMacroAssemblerIA32::Bind(Label* label) { 165 __ bind(label); 166} 167 168 169void RegExpMacroAssemblerIA32::CheckCharacter(uint32_t c, Label* on_equal) { 170 __ cmp(current_character(), c); 171 BranchOrBacktrack(equal, on_equal); 172} 173 174void RegExpMacroAssemblerIA32::CheckCharacterGT(base::uc16 limit, 175 Label* on_greater) { 176 __ cmp(current_character(), limit); 177 BranchOrBacktrack(greater, on_greater); 178} 179 180void RegExpMacroAssemblerIA32::CheckAtStart(int cp_offset, Label* on_at_start) { 181 __ lea(eax, Operand(edi, -char_size() + cp_offset * char_size())); 182 __ cmp(eax, Operand(ebp, kStringStartMinusOne)); 183 BranchOrBacktrack(equal, on_at_start); 184} 185 186void RegExpMacroAssemblerIA32::CheckNotAtStart(int cp_offset, 187 Label* on_not_at_start) { 188 __ lea(eax, Operand(edi, -char_size() + cp_offset * char_size())); 189 __ cmp(eax, Operand(ebp, kStringStartMinusOne)); 190 BranchOrBacktrack(not_equal, on_not_at_start); 191} 192 193void RegExpMacroAssemblerIA32::CheckCharacterLT(base::uc16 limit, 194 Label* on_less) { 195 __ cmp(current_character(), limit); 196 BranchOrBacktrack(less, on_less); 197} 198 199void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) { 200 Label fallthrough; 201 __ cmp(edi, Operand(backtrack_stackpointer(), 0)); 202 __ j(not_equal, &fallthrough); 203 __ add(backtrack_stackpointer(), Immediate(kSystemPointerSize)); // Pop. 204 BranchOrBacktrack(no_condition, on_equal); 205 __ bind(&fallthrough); 206} 207 208void RegExpMacroAssemblerIA32::PushCallerSavedRegisters() { 209 STATIC_ASSERT(backtrack_stackpointer() == ecx); 210 STATIC_ASSERT(current_character() == edx); 211 __ push(ecx); 212 __ push(edx); 213} 214 215void RegExpMacroAssemblerIA32::PopCallerSavedRegisters() { 216 __ pop(edx); 217 __ pop(ecx); 218} 219 220void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase( 221 int start_reg, bool read_backward, bool unicode, Label* on_no_match) { 222 Label fallthrough; 223 __ mov(edx, register_location(start_reg)); // Index of start of capture 224 __ mov(ebx, register_location(start_reg + 1)); // Index of end of capture 225 __ sub(ebx, edx); // Length of capture. 226 227 // At this point, the capture registers are either both set or both cleared. 228 // If the capture length is zero, then the capture is either empty or cleared. 229 // Fall through in both cases. 230 __ j(equal, &fallthrough); 231 232 // Check that there are sufficient characters left in the input. 233 if (read_backward) { 234 __ mov(eax, Operand(ebp, kStringStartMinusOne)); 235 __ add(eax, ebx); 236 __ cmp(edi, eax); 237 BranchOrBacktrack(less_equal, on_no_match); 238 } else { 239 __ mov(eax, edi); 240 __ add(eax, ebx); 241 BranchOrBacktrack(greater, on_no_match); 242 } 243 244 if (mode_ == LATIN1) { 245 Label success; 246 Label fail; 247 Label loop_increment; 248 // Save register contents to make the registers available below. 249 __ push(edi); 250 __ push(backtrack_stackpointer()); 251 // After this, the eax, ecx, and edi registers are available. 252 253 __ add(edx, esi); // Start of capture 254 __ add(edi, esi); // Start of text to match against capture. 255 if (read_backward) { 256 __ sub(edi, ebx); // Offset by length when matching backwards. 257 } 258 __ add(ebx, edi); // End of text to match against capture. 259 260 Label loop; 261 __ bind(&loop); 262 __ movzx_b(eax, Operand(edi, 0)); 263 __ cmpb_al(Operand(edx, 0)); 264 __ j(equal, &loop_increment); 265 266 // Mismatch, try case-insensitive match (converting letters to lower-case). 267 __ or_(eax, 0x20); // Convert match character to lower-case. 268 __ lea(ecx, Operand(eax, -'a')); 269 __ cmp(ecx, static_cast<int32_t>('z' - 'a')); // Is eax a lowercase letter? 270 Label convert_capture; 271 __ j(below_equal, &convert_capture); // In range 'a'-'z'. 272 // Latin-1: Check for values in range [224,254] but not 247. 273 __ sub(ecx, Immediate(224 - 'a')); 274 __ cmp(ecx, Immediate(254 - 224)); 275 __ j(above, &fail); // Weren't Latin-1 letters. 276 __ cmp(ecx, Immediate(247 - 224)); // Check for 247. 277 __ j(equal, &fail); 278 __ bind(&convert_capture); 279 // Also convert capture character. 280 __ movzx_b(ecx, Operand(edx, 0)); 281 __ or_(ecx, 0x20); 282 283 __ cmp(eax, ecx); 284 __ j(not_equal, &fail); 285 286 __ bind(&loop_increment); 287 // Increment pointers into match and capture strings. 288 __ add(edx, Immediate(1)); 289 __ add(edi, Immediate(1)); 290 // Compare to end of match, and loop if not done. 291 __ cmp(edi, ebx); 292 __ j(below, &loop); 293 __ jmp(&success); 294 295 __ bind(&fail); 296 // Restore original values before failing. 297 __ pop(backtrack_stackpointer()); 298 __ pop(edi); 299 BranchOrBacktrack(no_condition, on_no_match); 300 301 __ bind(&success); 302 // Restore original value before continuing. 303 __ pop(backtrack_stackpointer()); 304 // Drop original value of character position. 305 __ add(esp, Immediate(kSystemPointerSize)); 306 // Compute new value of character position after the matched part. 307 __ sub(edi, esi); 308 if (read_backward) { 309 // Subtract match length if we matched backward. 310 __ add(edi, register_location(start_reg)); 311 __ sub(edi, register_location(start_reg + 1)); 312 } 313 } else { 314 DCHECK(mode_ == UC16); 315 // Save registers before calling C function. 316 __ push(esi); 317 __ push(edi); 318 __ push(backtrack_stackpointer()); 319 __ push(ebx); 320 321 static const int argument_count = 4; 322 __ PrepareCallCFunction(argument_count, ecx); 323 // Put arguments into allocated stack area, last argument highest on stack. 324 // Parameters are 325 // Address byte_offset1 - Address captured substring's start. 326 // Address byte_offset2 - Address of current character position. 327 // size_t byte_length - length of capture in bytes(!) 328 // Isolate* isolate. 329 330 // Set isolate. 331 __ mov(Operand(esp, 3 * kSystemPointerSize), 332 Immediate(ExternalReference::isolate_address(isolate()))); 333 // Set byte_length. 334 __ mov(Operand(esp, 2 * kSystemPointerSize), ebx); 335 // Set byte_offset2. 336 // Found by adding negative string-end offset of current position (edi) 337 // to end of string. 338 __ add(edi, esi); 339 if (read_backward) { 340 __ sub(edi, ebx); // Offset by length when matching backwards. 341 } 342 __ mov(Operand(esp, 1 * kSystemPointerSize), edi); 343 // Set byte_offset1. 344 // Start of capture, where edx already holds string-end negative offset. 345 __ add(edx, esi); 346 __ mov(Operand(esp, 0 * kSystemPointerSize), edx); 347 348 { 349 AllowExternalCallThatCantCauseGC scope(masm_.get()); 350 ExternalReference compare = 351 unicode 352 ? ExternalReference::re_case_insensitive_compare_unicode() 353 : ExternalReference::re_case_insensitive_compare_non_unicode(); 354 __ CallCFunction(compare, argument_count); 355 } 356 // Pop original values before reacting on result value. 357 __ pop(ebx); 358 __ pop(backtrack_stackpointer()); 359 __ pop(edi); 360 __ pop(esi); 361 362 // Check if function returned non-zero for success or zero for failure. 363 __ or_(eax, eax); 364 BranchOrBacktrack(zero, on_no_match); 365 // On success, advance position by length of capture. 366 if (read_backward) { 367 __ sub(edi, ebx); 368 } else { 369 __ add(edi, ebx); 370 } 371 } 372 __ bind(&fallthrough); 373} 374 375void RegExpMacroAssemblerIA32::CheckNotBackReference(int start_reg, 376 bool read_backward, 377 Label* on_no_match) { 378 Label fallthrough; 379 Label success; 380 Label fail; 381 382 // Find length of back-referenced capture. 383 __ mov(edx, register_location(start_reg)); 384 __ mov(eax, register_location(start_reg + 1)); 385 __ sub(eax, edx); // Length to check. 386 387 // At this point, the capture registers are either both set or both cleared. 388 // If the capture length is zero, then the capture is either empty or cleared. 389 // Fall through in both cases. 390 __ j(equal, &fallthrough); 391 392 // Check that there are sufficient characters left in the input. 393 if (read_backward) { 394 __ mov(ebx, Operand(ebp, kStringStartMinusOne)); 395 __ add(ebx, eax); 396 __ cmp(edi, ebx); 397 BranchOrBacktrack(less_equal, on_no_match); 398 } else { 399 __ mov(ebx, edi); 400 __ add(ebx, eax); 401 BranchOrBacktrack(greater, on_no_match); 402 } 403 404 // Save register to make it available below. 405 __ push(backtrack_stackpointer()); 406 407 // Compute pointers to match string and capture string 408 __ add(edx, esi); // Start of capture. 409 __ lea(ebx, Operand(esi, edi, times_1, 0)); // Start of match. 410 if (read_backward) { 411 __ sub(ebx, eax); // Offset by length when matching backwards. 412 } 413 __ lea(ecx, Operand(eax, ebx, times_1, 0)); // End of match 414 415 Label loop; 416 __ bind(&loop); 417 if (mode_ == LATIN1) { 418 __ movzx_b(eax, Operand(edx, 0)); 419 __ cmpb_al(Operand(ebx, 0)); 420 } else { 421 DCHECK(mode_ == UC16); 422 __ movzx_w(eax, Operand(edx, 0)); 423 __ cmpw_ax(Operand(ebx, 0)); 424 } 425 __ j(not_equal, &fail); 426 // Increment pointers into capture and match string. 427 __ add(edx, Immediate(char_size())); 428 __ add(ebx, Immediate(char_size())); 429 // Check if we have reached end of match area. 430 __ cmp(ebx, ecx); 431 __ j(below, &loop); 432 __ jmp(&success); 433 434 __ bind(&fail); 435 // Restore backtrack stackpointer. 436 __ pop(backtrack_stackpointer()); 437 BranchOrBacktrack(no_condition, on_no_match); 438 439 __ bind(&success); 440 // Move current character position to position after match. 441 __ mov(edi, ecx); 442 __ sub(edi, esi); 443 if (read_backward) { 444 // Subtract match length if we matched backward. 445 __ add(edi, register_location(start_reg)); 446 __ sub(edi, register_location(start_reg + 1)); 447 } 448 // Restore backtrack stackpointer. 449 __ pop(backtrack_stackpointer()); 450 451 __ bind(&fallthrough); 452} 453 454 455void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c, 456 Label* on_not_equal) { 457 __ cmp(current_character(), c); 458 BranchOrBacktrack(not_equal, on_not_equal); 459} 460 461 462void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c, 463 uint32_t mask, 464 Label* on_equal) { 465 if (c == 0) { 466 __ test(current_character(), Immediate(mask)); 467 } else { 468 __ mov(eax, mask); 469 __ and_(eax, current_character()); 470 __ cmp(eax, c); 471 } 472 BranchOrBacktrack(equal, on_equal); 473} 474 475 476void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c, 477 uint32_t mask, 478 Label* on_not_equal) { 479 if (c == 0) { 480 __ test(current_character(), Immediate(mask)); 481 } else { 482 __ mov(eax, mask); 483 __ and_(eax, current_character()); 484 __ cmp(eax, c); 485 } 486 BranchOrBacktrack(not_equal, on_not_equal); 487} 488 489void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd( 490 base::uc16 c, base::uc16 minus, base::uc16 mask, Label* on_not_equal) { 491 DCHECK_GT(String::kMaxUtf16CodeUnit, minus); 492 __ lea(eax, Operand(current_character(), -minus)); 493 if (c == 0) { 494 __ test(eax, Immediate(mask)); 495 } else { 496 __ and_(eax, mask); 497 __ cmp(eax, c); 498 } 499 BranchOrBacktrack(not_equal, on_not_equal); 500} 501 502void RegExpMacroAssemblerIA32::CheckCharacterInRange(base::uc16 from, 503 base::uc16 to, 504 Label* on_in_range) { 505 __ lea(eax, Operand(current_character(), -from)); 506 __ cmp(eax, to - from); 507 BranchOrBacktrack(below_equal, on_in_range); 508} 509 510void RegExpMacroAssemblerIA32::CheckCharacterNotInRange( 511 base::uc16 from, base::uc16 to, Label* on_not_in_range) { 512 __ lea(eax, Operand(current_character(), -from)); 513 __ cmp(eax, to - from); 514 BranchOrBacktrack(above, on_not_in_range); 515} 516 517void RegExpMacroAssemblerIA32::CallIsCharacterInRangeArray( 518 const ZoneList<CharacterRange>* ranges) { 519 PushCallerSavedRegisters(); 520 521 static const int kNumArguments = 3; 522 __ PrepareCallCFunction(kNumArguments, ecx); 523 524 __ mov(Operand(esp, 0 * kSystemPointerSize), current_character()); 525 __ mov(Operand(esp, 1 * kSystemPointerSize), GetOrAddRangeArray(ranges)); 526 __ mov(Operand(esp, 2 * kSystemPointerSize), 527 Immediate(ExternalReference::isolate_address(isolate()))); 528 529 { 530 // We have a frame (set up in GetCode), but the assembler doesn't know. 531 FrameScope scope(masm_.get(), StackFrame::MANUAL); 532 __ CallCFunction(ExternalReference::re_is_character_in_range_array(), 533 kNumArguments); 534 } 535 536 PopCallerSavedRegisters(); 537} 538 539bool RegExpMacroAssemblerIA32::CheckCharacterInRangeArray( 540 const ZoneList<CharacterRange>* ranges, Label* on_in_range) { 541 CallIsCharacterInRangeArray(ranges); 542 __ or_(eax, eax); 543 BranchOrBacktrack(not_zero, on_in_range); 544 return true; 545} 546 547bool RegExpMacroAssemblerIA32::CheckCharacterNotInRangeArray( 548 const ZoneList<CharacterRange>* ranges, Label* on_not_in_range) { 549 CallIsCharacterInRangeArray(ranges); 550 __ or_(eax, eax); 551 BranchOrBacktrack(zero, on_not_in_range); 552 return true; 553} 554 555void RegExpMacroAssemblerIA32::CheckBitInTable( 556 Handle<ByteArray> table, 557 Label* on_bit_set) { 558 __ mov(eax, Immediate(table)); 559 Register index = current_character(); 560 if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) { 561 __ mov(ebx, kTableSize - 1); 562 __ and_(ebx, current_character()); 563 index = ebx; 564 } 565 __ cmpb(FieldOperand(eax, index, times_1, ByteArray::kHeaderSize), 566 Immediate(0)); 567 BranchOrBacktrack(not_equal, on_bit_set); 568} 569 570bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass( 571 StandardCharacterSet type, Label* on_no_match) { 572 // Range checks (c in min..max) are generally implemented by an unsigned 573 // (c - min) <= (max - min) check 574 // TODO(jgruber): No custom implementation (yet): s(UC16), S(UC16). 575 switch (type) { 576 case StandardCharacterSet::kWhitespace: 577 // Match space-characters. 578 if (mode_ == LATIN1) { 579 // One byte space characters are '\t'..'\r', ' ' and \u00a0. 580 Label success; 581 __ cmp(current_character(), ' '); 582 __ j(equal, &success, Label::kNear); 583 // Check range 0x09..0x0D. 584 __ lea(eax, Operand(current_character(), -'\t')); 585 __ cmp(eax, '\r' - '\t'); 586 __ j(below_equal, &success, Label::kNear); 587 // \u00a0 (NBSP). 588 __ cmp(eax, 0x00A0 - '\t'); 589 BranchOrBacktrack(not_equal, on_no_match); 590 __ bind(&success); 591 return true; 592 } 593 return false; 594 case StandardCharacterSet::kNotWhitespace: 595 // The emitted code for generic character classes is good enough. 596 return false; 597 case StandardCharacterSet::kDigit: 598 // Match ASCII digits ('0'..'9'). 599 __ lea(eax, Operand(current_character(), -'0')); 600 __ cmp(eax, '9' - '0'); 601 BranchOrBacktrack(above, on_no_match); 602 return true; 603 case StandardCharacterSet::kNotDigit: 604 // Match non ASCII-digits. 605 __ lea(eax, Operand(current_character(), -'0')); 606 __ cmp(eax, '9' - '0'); 607 BranchOrBacktrack(below_equal, on_no_match); 608 return true; 609 case StandardCharacterSet::kLineTerminator: 610 // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 or 0x2029). 611 // The opposite of '.'. 612 __ mov(eax, current_character()); 613 __ xor_(eax, Immediate(0x01)); 614 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C. 615 __ sub(eax, Immediate(0x0B)); 616 __ cmp(eax, 0x0C - 0x0B); 617 if (mode_ == LATIN1) { 618 BranchOrBacktrack(above, on_no_match); 619 } else { 620 Label done; 621 BranchOrBacktrack(below_equal, &done); 622 DCHECK_EQ(UC16, mode_); 623 // Compare original value to 0x2028 and 0x2029, using the already 624 // computed (current_char ^ 0x01 - 0x0B). I.e., check for 625 // 0x201D (0x2028 - 0x0B) or 0x201E. 626 __ sub(eax, Immediate(0x2028 - 0x0B)); 627 __ cmp(eax, 1); 628 BranchOrBacktrack(above, on_no_match); 629 __ bind(&done); 630 } 631 return true; 632 case StandardCharacterSet::kNotLineTerminator: { 633 // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029). 634 __ mov(eax, current_character()); 635 __ xor_(eax, Immediate(0x01)); 636 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C. 637 __ sub(eax, Immediate(0x0B)); 638 __ cmp(eax, 0x0C - 0x0B); 639 BranchOrBacktrack(below_equal, on_no_match); 640 if (mode_ == UC16) { 641 // Compare original value to 0x2028 and 0x2029, using the already 642 // computed (current_char ^ 0x01 - 0x0B). I.e., check for 643 // 0x201D (0x2028 - 0x0B) or 0x201E. 644 __ sub(eax, Immediate(0x2028 - 0x0B)); 645 __ cmp(eax, 0x2029 - 0x2028); 646 BranchOrBacktrack(below_equal, on_no_match); 647 } 648 return true; 649 } 650 case StandardCharacterSet::kWord: { 651 if (mode_ != LATIN1) { 652 // Table is 256 entries, so all Latin1 characters can be tested. 653 __ cmp(current_character(), Immediate('z')); 654 BranchOrBacktrack(above, on_no_match); 655 } 656 DCHECK_EQ(0, 657 word_character_map[0]); // Character '\0' is not a word char. 658 ExternalReference word_map = ExternalReference::re_word_character_map(); 659 __ test_b(current_character(), 660 Operand(current_character(), times_1, word_map.address(), 661 RelocInfo::EXTERNAL_REFERENCE)); 662 BranchOrBacktrack(zero, on_no_match); 663 return true; 664 } 665 case StandardCharacterSet::kNotWord: { 666 Label done; 667 if (mode_ != LATIN1) { 668 // Table is 256 entries, so all Latin1 characters can be tested. 669 __ cmp(current_character(), Immediate('z')); 670 __ j(above, &done); 671 } 672 DCHECK_EQ(0, 673 word_character_map[0]); // Character '\0' is not a word char. 674 ExternalReference word_map = ExternalReference::re_word_character_map(); 675 __ test_b(current_character(), 676 Operand(current_character(), times_1, word_map.address(), 677 RelocInfo::EXTERNAL_REFERENCE)); 678 BranchOrBacktrack(not_zero, on_no_match); 679 if (mode_ != LATIN1) { 680 __ bind(&done); 681 } 682 return true; 683 } 684 // Non-standard classes (with no syntactic shorthand) used internally. 685 case StandardCharacterSet::kEverything: 686 // Match any character. 687 return true; 688 } 689} 690 691void RegExpMacroAssemblerIA32::Fail() { 692 STATIC_ASSERT(FAILURE == 0); // Return value for failure is zero. 693 if (!global()) { 694 __ Move(eax, Immediate(FAILURE)); 695 } 696 __ jmp(&exit_label_); 697} 698 699void RegExpMacroAssemblerIA32::LoadRegExpStackPointerFromMemory(Register dst) { 700 ExternalReference ref = 701 ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); 702 __ mov(dst, __ ExternalReferenceAsOperand(ref, dst)); 703} 704 705void RegExpMacroAssemblerIA32::StoreRegExpStackPointerToMemory( 706 Register src, Register scratch) { 707 ExternalReference ref = 708 ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); 709 __ mov(__ ExternalReferenceAsOperand(ref, scratch), src); 710} 711 712void RegExpMacroAssemblerIA32::PushRegExpBasePointer(Register stack_pointer, 713 Register scratch) { 714 ExternalReference ref = 715 ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); 716 __ mov(scratch, __ ExternalReferenceAsOperand(ref, scratch)); 717 __ sub(scratch, stack_pointer); 718 __ mov(Operand(ebp, kRegExpStackBasePointer), scratch); 719} 720 721void RegExpMacroAssemblerIA32::PopRegExpBasePointer(Register stack_pointer_out, 722 Register scratch) { 723 ExternalReference ref = 724 ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); 725 __ mov(scratch, Operand(ebp, kRegExpStackBasePointer)); 726 __ mov(stack_pointer_out, 727 __ ExternalReferenceAsOperand(ref, stack_pointer_out)); 728 __ sub(stack_pointer_out, scratch); 729 StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); 730} 731 732Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { 733 Label return_eax; 734 // Finalize code - write the entry point code now we know how many 735 // registers we need. 736 737 // Entry code: 738 __ bind(&entry_label_); 739 740 // Tell the system that we have a stack frame. Because the type is MANUAL, no 741 // code is generated. 742 FrameScope scope(masm_.get(), StackFrame::MANUAL); 743 744 // Actually emit code to start a new stack frame. 745 __ push(ebp); 746 __ mov(ebp, esp); 747 // Save callee-save registers. Order here should correspond to order of 748 // kBackup_ebx etc. 749 __ push(esi); 750 __ push(edi); 751 __ push(ebx); // Callee-save on MacOS. 752 STATIC_ASSERT(kLastCalleeSaveRegister == kBackup_ebx); 753 754 STATIC_ASSERT(kSuccessfulCaptures == 755 kLastCalleeSaveRegister - kSystemPointerSize); 756 __ push(Immediate(0)); // Number of successful matches in a global regexp. 757 STATIC_ASSERT(kStringStartMinusOne == 758 kSuccessfulCaptures - kSystemPointerSize); 759 __ push(Immediate(0)); // Make room for "string start - 1" constant. 760 STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); 761 __ push(Immediate(0)); // The backtrack counter. 762 STATIC_ASSERT(kRegExpStackBasePointer == 763 kBacktrackCount - kSystemPointerSize); 764 __ push(Immediate(0)); // The regexp stack base ptr. 765 766 // Initialize backtrack stack pointer. It must not be clobbered from here on. 767 // Note the backtrack_stackpointer is *not* callee-saved. 768 STATIC_ASSERT(backtrack_stackpointer() == ecx); 769 LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); 770 771 // Store the regexp base pointer - we'll later restore it / write it to 772 // memory when returning from this irregexp code object. 773 PushRegExpBasePointer(backtrack_stackpointer(), eax); 774 775 { 776 // Check if we have space on the stack for registers. 777 Label stack_limit_hit, stack_ok; 778 779 ExternalReference stack_limit = 780 ExternalReference::address_of_jslimit(isolate()); 781 __ mov(eax, esp); 782 __ sub(eax, StaticVariable(stack_limit)); 783 // Handle it if the stack pointer is already below the stack limit. 784 __ j(below_equal, &stack_limit_hit); 785 // Check if there is room for the variable number of registers above 786 // the stack limit. 787 __ cmp(eax, num_registers_ * kSystemPointerSize); 788 __ j(above_equal, &stack_ok); 789 // Exit with OutOfMemory exception. There is not enough space on the stack 790 // for our working registers. 791 __ mov(eax, EXCEPTION); 792 __ jmp(&return_eax); 793 794 __ bind(&stack_limit_hit); 795 __ push(backtrack_stackpointer()); 796 CallCheckStackGuardState(ebx); 797 __ pop(backtrack_stackpointer()); 798 __ or_(eax, eax); 799 // If returned value is non-zero, we exit with the returned value as result. 800 __ j(not_zero, &return_eax); 801 802 __ bind(&stack_ok); 803 } 804 805 // Load start index for later use. 806 __ mov(ebx, Operand(ebp, kStartIndex)); 807 808 // Allocate space on stack for registers. 809 __ AllocateStackSpace(num_registers_ * kSystemPointerSize); 810 // Load string length. 811 __ mov(esi, Operand(ebp, kInputEnd)); 812 // Load input position. 813 __ mov(edi, Operand(ebp, kInputStart)); 814 // Set up edi to be negative offset from string end. 815 __ sub(edi, esi); 816 817 // Set eax to address of char before start of the string. 818 // (effectively string position -1). 819 __ neg(ebx); 820 if (mode_ == UC16) { 821 __ lea(eax, Operand(edi, ebx, times_2, -char_size())); 822 } else { 823 __ lea(eax, Operand(edi, ebx, times_1, -char_size())); 824 } 825 // Store this value in a local variable, for use when clearing 826 // position registers. 827 __ mov(Operand(ebp, kStringStartMinusOne), eax); 828 829 Label load_char_start_regexp; 830 { 831 Label start_regexp; 832 833 // Load newline if index is at start, previous character otherwise. 834 __ cmp(Operand(ebp, kStartIndex), Immediate(0)); 835 __ j(not_equal, &load_char_start_regexp, Label::kNear); 836 __ mov(current_character(), '\n'); 837 __ jmp(&start_regexp, Label::kNear); 838 839 // Global regexp restarts matching here. 840 __ bind(&load_char_start_regexp); 841 // Load previous char as initial value of current character register. 842 LoadCurrentCharacterUnchecked(-1, 1); 843 __ bind(&start_regexp); 844 } 845 846 // Initialize on-stack registers. 847 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. 848 // Fill saved registers with initial value = start offset - 1 849 // Fill in stack push order, to avoid accessing across an unwritten 850 // page (a problem on Windows). 851 if (num_saved_registers_ > 8) { 852 DCHECK_EQ(ecx, backtrack_stackpointer()); 853 __ push(ecx); 854 __ mov(ecx, kRegisterZero); 855 Label init_loop; 856 __ bind(&init_loop); 857 __ mov(Operand(ebp, ecx, times_1, 0), eax); 858 __ sub(ecx, Immediate(kSystemPointerSize)); 859 __ cmp(ecx, kRegisterZero - num_saved_registers_ * kSystemPointerSize); 860 __ j(greater, &init_loop); 861 __ pop(ecx); 862 } else { // Unroll the loop. 863 for (int i = 0; i < num_saved_registers_; i++) { 864 __ mov(register_location(i), eax); 865 } 866 } 867 } 868 869 __ jmp(&start_label_); 870 871 // Exit code: 872 if (success_label_.is_linked()) { 873 // Save captures when successful. 874 __ bind(&success_label_); 875 if (num_saved_registers_ > 0) { 876 // copy captures to output 877 __ mov(ebx, Operand(ebp, kRegisterOutput)); 878 __ mov(ecx, Operand(ebp, kInputEnd)); 879 __ mov(edx, Operand(ebp, kStartIndex)); 880 __ sub(ecx, Operand(ebp, kInputStart)); 881 if (mode_ == UC16) { 882 __ lea(ecx, Operand(ecx, edx, times_2, 0)); 883 } else { 884 __ add(ecx, edx); 885 } 886 for (int i = 0; i < num_saved_registers_; i++) { 887 __ mov(eax, register_location(i)); 888 if (i == 0 && global_with_zero_length_check()) { 889 // Keep capture start in edx for the zero-length check later. 890 __ mov(edx, eax); 891 } 892 // Convert to index from start of string, not end. 893 __ add(eax, ecx); 894 if (mode_ == UC16) { 895 __ sar(eax, 1); // Convert byte index to character index. 896 } 897 __ mov(Operand(ebx, i * kSystemPointerSize), eax); 898 } 899 } 900 901 if (global()) { 902 // Restart matching if the regular expression is flagged as global. 903 // Increment success counter. 904 __ inc(Operand(ebp, kSuccessfulCaptures)); 905 // Capture results have been stored, so the number of remaining global 906 // output registers is reduced by the number of stored captures. 907 __ mov(ecx, Operand(ebp, kNumOutputRegisters)); 908 __ sub(ecx, Immediate(num_saved_registers_)); 909 // Check whether we have enough room for another set of capture results. 910 __ cmp(ecx, Immediate(num_saved_registers_)); 911 __ j(less, &exit_label_); 912 913 __ mov(Operand(ebp, kNumOutputRegisters), ecx); 914 // Advance the location for output. 915 __ add(Operand(ebp, kRegisterOutput), 916 Immediate(num_saved_registers_ * kSystemPointerSize)); 917 918 // Prepare eax to initialize registers with its value in the next run. 919 __ mov(eax, Operand(ebp, kStringStartMinusOne)); 920 921 // Restore the original regexp stack pointer value (effectively, pop the 922 // stored base pointer). 923 PopRegExpBasePointer(backtrack_stackpointer(), ebx); 924 925 if (global_with_zero_length_check()) { 926 // Special case for zero-length matches. 927 // edx: capture start index 928 __ cmp(edi, edx); 929 // Not a zero-length match, restart. 930 __ j(not_equal, &load_char_start_regexp); 931 // edi (offset from the end) is zero if we already reached the end. 932 __ test(edi, edi); 933 __ j(zero, &exit_label_, Label::kNear); 934 // Advance current position after a zero-length match. 935 Label advance; 936 __ bind(&advance); 937 if (mode_ == UC16) { 938 __ add(edi, Immediate(2)); 939 } else { 940 __ inc(edi); 941 } 942 if (global_unicode()) CheckNotInSurrogatePair(0, &advance); 943 } 944 __ jmp(&load_char_start_regexp); 945 } else { 946 __ mov(eax, Immediate(SUCCESS)); 947 } 948 } 949 950 __ bind(&exit_label_); 951 if (global()) { 952 // Return the number of successful captures. 953 __ mov(eax, Operand(ebp, kSuccessfulCaptures)); 954 } 955 956 __ bind(&return_eax); 957 // Restore the original regexp stack pointer value (effectively, pop the 958 // stored base pointer). 959 PopRegExpBasePointer(backtrack_stackpointer(), ebx); 960 961 // Skip esp past regexp registers. 962 __ lea(esp, Operand(ebp, kLastCalleeSaveRegister)); 963 // Restore callee-save registers. 964 __ pop(ebx); 965 __ pop(edi); 966 __ pop(esi); 967 // Exit function frame, restore previous one. 968 __ pop(ebp); 969 __ ret(0); 970 971 // Backtrack code (branch target for conditional backtracks). 972 if (backtrack_label_.is_linked()) { 973 __ bind(&backtrack_label_); 974 Backtrack(); 975 } 976 977 Label exit_with_exception; 978 979 // Preempt-code 980 if (check_preempt_label_.is_linked()) { 981 SafeCallTarget(&check_preempt_label_); 982 983 StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi); 984 985 __ push(edi); 986 987 CallCheckStackGuardState(ebx); 988 __ or_(eax, eax); 989 // If returning non-zero, we should end execution with the given 990 // result as return value. 991 __ j(not_zero, &return_eax); 992 993 __ pop(edi); 994 995 LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); 996 997 // String might have moved: Reload esi from frame. 998 __ mov(esi, Operand(ebp, kInputEnd)); 999 SafeReturn(); 1000 } 1001 1002 // Backtrack stack overflow code. 1003 if (stack_overflow_label_.is_linked()) { 1004 SafeCallTarget(&stack_overflow_label_); 1005 // Reached if the backtrack-stack limit has been hit. 1006 1007 // Save registers before calling C function. 1008 __ push(esi); 1009 __ push(edi); 1010 1011 StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi); 1012 1013 // Call GrowStack(isolate). 1014 static const int kNumArguments = 1; 1015 __ PrepareCallCFunction(kNumArguments, ebx); 1016 __ mov(Operand(esp, 0 * kSystemPointerSize), 1017 Immediate(ExternalReference::isolate_address(isolate()))); 1018 __ CallCFunction(ExternalReference::re_grow_stack(), kNumArguments); 1019 // If return nullptr, we have failed to grow the stack, and 1020 // must exit with a stack-overflow exception. 1021 __ or_(eax, eax); 1022 __ j(equal, &exit_with_exception); 1023 // Otherwise use return value as new stack pointer. 1024 __ mov(backtrack_stackpointer(), eax); 1025 // Restore saved registers and continue. 1026 __ pop(edi); 1027 __ pop(esi); 1028 SafeReturn(); 1029 } 1030 1031 if (exit_with_exception.is_linked()) { 1032 // If any of the code above needed to exit with an exception. 1033 __ bind(&exit_with_exception); 1034 // Exit with Result EXCEPTION(-1) to signal thrown exception. 1035 __ mov(eax, EXCEPTION); 1036 __ jmp(&return_eax); 1037 } 1038 1039 if (fallback_label_.is_linked()) { 1040 __ bind(&fallback_label_); 1041 __ mov(eax, FALLBACK_TO_EXPERIMENTAL); 1042 __ jmp(&return_eax); 1043 } 1044 1045 CodeDesc code_desc; 1046 masm_->GetCode(masm_->isolate(), &code_desc); 1047 Handle<Code> code = 1048 Factory::CodeBuilder(isolate(), code_desc, CodeKind::REGEXP) 1049 .set_self_reference(masm_->CodeObject()) 1050 .Build(); 1051 PROFILE(masm_->isolate(), 1052 RegExpCodeCreateEvent(Handle<AbstractCode>::cast(code), source)); 1053 return Handle<HeapObject>::cast(code); 1054} 1055 1056 1057void RegExpMacroAssemblerIA32::GoTo(Label* to) { 1058 BranchOrBacktrack(no_condition, to); 1059} 1060 1061 1062void RegExpMacroAssemblerIA32::IfRegisterGE(int reg, 1063 int comparand, 1064 Label* if_ge) { 1065 __ cmp(register_location(reg), Immediate(comparand)); 1066 BranchOrBacktrack(greater_equal, if_ge); 1067} 1068 1069 1070void RegExpMacroAssemblerIA32::IfRegisterLT(int reg, 1071 int comparand, 1072 Label* if_lt) { 1073 __ cmp(register_location(reg), Immediate(comparand)); 1074 BranchOrBacktrack(less, if_lt); 1075} 1076 1077 1078void RegExpMacroAssemblerIA32::IfRegisterEqPos(int reg, 1079 Label* if_eq) { 1080 __ cmp(edi, register_location(reg)); 1081 BranchOrBacktrack(equal, if_eq); 1082} 1083 1084 1085RegExpMacroAssembler::IrregexpImplementation 1086 RegExpMacroAssemblerIA32::Implementation() { 1087 return kIA32Implementation; 1088} 1089 1090 1091void RegExpMacroAssemblerIA32::PopCurrentPosition() { 1092 Pop(edi); 1093} 1094 1095 1096void RegExpMacroAssemblerIA32::PopRegister(int register_index) { 1097 Pop(eax); 1098 __ mov(register_location(register_index), eax); 1099} 1100 1101 1102void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) { 1103 Push(Immediate::CodeRelativeOffset(label)); 1104 CheckStackLimit(); 1105} 1106 1107 1108void RegExpMacroAssemblerIA32::PushCurrentPosition() { 1109 Push(edi); 1110} 1111 1112 1113void RegExpMacroAssemblerIA32::PushRegister(int register_index, 1114 StackCheckFlag check_stack_limit) { 1115 __ mov(eax, register_location(register_index)); 1116 Push(eax); 1117 if (check_stack_limit) CheckStackLimit(); 1118} 1119 1120 1121void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) { 1122 __ mov(edi, register_location(reg)); 1123} 1124 1125void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) { 1126 ExternalReference stack_top_address = 1127 ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); 1128 __ mov(eax, __ ExternalReferenceAsOperand(stack_top_address, eax)); 1129 __ sub(eax, backtrack_stackpointer()); 1130 __ mov(register_location(reg), eax); 1131} 1132 1133void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) { 1134 ExternalReference stack_top_address = 1135 ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); 1136 __ mov(backtrack_stackpointer(), 1137 __ ExternalReferenceAsOperand(stack_top_address, 1138 backtrack_stackpointer())); 1139 __ sub(backtrack_stackpointer(), register_location(reg)); 1140} 1141 1142void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by) { 1143 Label after_position; 1144 __ cmp(edi, -by * char_size()); 1145 __ j(greater_equal, &after_position, Label::kNear); 1146 __ mov(edi, -by * char_size()); 1147 // On RegExp code entry (where this operation is used), the character before 1148 // the current position is expected to be already loaded. 1149 // We have advanced the position, so it's safe to read backwards. 1150 LoadCurrentCharacterUnchecked(-1, 1); 1151 __ bind(&after_position); 1152} 1153 1154 1155void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) { 1156 DCHECK(register_index >= num_saved_registers_); // Reserved for positions! 1157 __ mov(register_location(register_index), Immediate(to)); 1158} 1159 1160 1161bool RegExpMacroAssemblerIA32::Succeed() { 1162 __ jmp(&success_label_); 1163 return global(); 1164} 1165 1166 1167void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg, 1168 int cp_offset) { 1169 if (cp_offset == 0) { 1170 __ mov(register_location(reg), edi); 1171 } else { 1172 __ lea(eax, Operand(edi, cp_offset * char_size())); 1173 __ mov(register_location(reg), eax); 1174 } 1175} 1176 1177 1178void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) { 1179 DCHECK(reg_from <= reg_to); 1180 __ mov(eax, Operand(ebp, kStringStartMinusOne)); 1181 for (int reg = reg_from; reg <= reg_to; reg++) { 1182 __ mov(register_location(reg), eax); 1183 } 1184} 1185 1186// Private methods: 1187 1188void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) { 1189 static const int num_arguments = 3; 1190 __ PrepareCallCFunction(num_arguments, scratch); 1191 // RegExp code frame pointer. 1192 __ mov(Operand(esp, 2 * kSystemPointerSize), ebp); 1193 // Code of self. 1194 __ mov(Operand(esp, 1 * kSystemPointerSize), Immediate(masm_->CodeObject())); 1195 // Next address on the stack (will be address of return address). 1196 __ lea(eax, Operand(esp, -kSystemPointerSize)); 1197 __ mov(Operand(esp, 0 * kSystemPointerSize), eax); 1198 ExternalReference check_stack_guard = 1199 ExternalReference::re_check_stack_guard_state(); 1200 __ CallCFunction(check_stack_guard, num_arguments); 1201} 1202 1203Operand RegExpMacroAssemblerIA32::StaticVariable(const ExternalReference& ext) { 1204 return Operand(ext.address(), RelocInfo::EXTERNAL_REFERENCE); 1205} 1206 1207// Helper function for reading a value out of a stack frame. 1208template <typename T> 1209static T& frame_entry(Address re_frame, int frame_offset) { 1210 return reinterpret_cast<T&>(Memory<int32_t>(re_frame + frame_offset)); 1211} 1212 1213 1214template <typename T> 1215static T* frame_entry_address(Address re_frame, int frame_offset) { 1216 return reinterpret_cast<T*>(re_frame + frame_offset); 1217} 1218 1219int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, 1220 Address raw_code, 1221 Address re_frame) { 1222 Code re_code = Code::cast(Object(raw_code)); 1223 return NativeRegExpMacroAssembler::CheckStackGuardState( 1224 frame_entry<Isolate*>(re_frame, kIsolate), 1225 frame_entry<int>(re_frame, kStartIndex), 1226 static_cast<RegExp::CallOrigin>(frame_entry<int>(re_frame, kDirectCall)), 1227 return_address, re_code, 1228 frame_entry_address<Address>(re_frame, kInputString), 1229 frame_entry_address<const byte*>(re_frame, kInputStart), 1230 frame_entry_address<const byte*>(re_frame, kInputEnd)); 1231} 1232 1233 1234Operand RegExpMacroAssemblerIA32::register_location(int register_index) { 1235 DCHECK(register_index < (1<<30)); 1236 if (num_registers_ <= register_index) { 1237 num_registers_ = register_index + 1; 1238 } 1239 return Operand(ebp, kRegisterZero - register_index * kSystemPointerSize); 1240} 1241 1242 1243void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset, 1244 Label* on_outside_input) { 1245 if (cp_offset >= 0) { 1246 __ cmp(edi, -cp_offset * char_size()); 1247 BranchOrBacktrack(greater_equal, on_outside_input); 1248 } else { 1249 __ lea(eax, Operand(edi, cp_offset * char_size())); 1250 __ cmp(eax, Operand(ebp, kStringStartMinusOne)); 1251 BranchOrBacktrack(less_equal, on_outside_input); 1252 } 1253} 1254 1255 1256void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition, 1257 Label* to) { 1258 if (condition < 0) { // No condition 1259 if (to == nullptr) { 1260 Backtrack(); 1261 return; 1262 } 1263 __ jmp(to); 1264 return; 1265 } 1266 if (to == nullptr) { 1267 __ j(condition, &backtrack_label_); 1268 return; 1269 } 1270 __ j(condition, to); 1271} 1272 1273 1274void RegExpMacroAssemblerIA32::SafeCall(Label* to) { 1275 Label return_to; 1276 __ push(Immediate::CodeRelativeOffset(&return_to)); 1277 __ jmp(to); 1278 __ bind(&return_to); 1279} 1280 1281 1282void RegExpMacroAssemblerIA32::SafeReturn() { 1283 __ pop(ebx); 1284 __ add(ebx, Immediate(masm_->CodeObject())); 1285 __ jmp(ebx); 1286} 1287 1288 1289void RegExpMacroAssemblerIA32::SafeCallTarget(Label* name) { 1290 __ bind(name); 1291} 1292 1293 1294void RegExpMacroAssemblerIA32::Push(Register source) { 1295 DCHECK(source != backtrack_stackpointer()); 1296 // Notice: This updates flags, unlike normal Push. 1297 __ sub(backtrack_stackpointer(), Immediate(kSystemPointerSize)); 1298 __ mov(Operand(backtrack_stackpointer(), 0), source); 1299} 1300 1301 1302void RegExpMacroAssemblerIA32::Push(Immediate value) { 1303 // Notice: This updates flags, unlike normal Push. 1304 __ sub(backtrack_stackpointer(), Immediate(kSystemPointerSize)); 1305 __ mov(Operand(backtrack_stackpointer(), 0), value); 1306} 1307 1308 1309void RegExpMacroAssemblerIA32::Pop(Register target) { 1310 DCHECK(target != backtrack_stackpointer()); 1311 __ mov(target, Operand(backtrack_stackpointer(), 0)); 1312 // Notice: This updates flags, unlike normal Pop. 1313 __ add(backtrack_stackpointer(), Immediate(kSystemPointerSize)); 1314} 1315 1316 1317void RegExpMacroAssemblerIA32::CheckPreemption() { 1318 // Check for preemption. 1319 Label no_preempt; 1320 ExternalReference stack_limit = 1321 ExternalReference::address_of_jslimit(isolate()); 1322 __ cmp(esp, StaticVariable(stack_limit)); 1323 __ j(above, &no_preempt); 1324 1325 SafeCall(&check_preempt_label_); 1326 1327 __ bind(&no_preempt); 1328} 1329 1330 1331void RegExpMacroAssemblerIA32::CheckStackLimit() { 1332 Label no_stack_overflow; 1333 ExternalReference stack_limit = 1334 ExternalReference::address_of_regexp_stack_limit_address(isolate()); 1335 __ cmp(backtrack_stackpointer(), StaticVariable(stack_limit)); 1336 __ j(above, &no_stack_overflow); 1337 1338 SafeCall(&stack_overflow_label_); 1339 1340 __ bind(&no_stack_overflow); 1341} 1342 1343 1344void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset, 1345 int characters) { 1346 if (mode_ == LATIN1) { 1347 if (characters == 4) { 1348 __ mov(current_character(), Operand(esi, edi, times_1, cp_offset)); 1349 } else if (characters == 2) { 1350 __ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset)); 1351 } else { 1352 DCHECK_EQ(1, characters); 1353 __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset)); 1354 } 1355 } else { 1356 DCHECK(mode_ == UC16); 1357 if (characters == 2) { 1358 __ mov(current_character(), 1359 Operand(esi, edi, times_1, cp_offset * sizeof(base::uc16))); 1360 } else { 1361 DCHECK_EQ(1, characters); 1362 __ movzx_w(current_character(), 1363 Operand(esi, edi, times_1, cp_offset * sizeof(base::uc16))); 1364 } 1365 } 1366} 1367 1368 1369#undef __ 1370 1371} // namespace internal 1372} // namespace v8 1373 1374#endif // V8_TARGET_ARCH_IA32 1375