| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_X87 | 5 #if V8_TARGET_ARCH_X87 |
| 6 | 6 |
| 7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
| 8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 // Put the double_exponent parameter in call stack | 275 // Put the double_exponent parameter in call stack |
| 276 __ fstp_d(Operand(esp, 1 * kDoubleSize)); | 276 __ fstp_d(Operand(esp, 1 * kDoubleSize)); |
| 277 __ CallCFunction(ExternalReference::power_double_double_function(isolate()), | 277 __ CallCFunction(ExternalReference::power_double_double_function(isolate()), |
| 278 4); | 278 4); |
| 279 } | 279 } |
| 280 // Return value is in st(0) on ia32. | 280 // Return value is in st(0) on ia32. |
| 281 __ ret(0); | 281 __ ret(0); |
| 282 } | 282 } |
| 283 | 283 |
| 284 void RegExpExecStub::Generate(MacroAssembler* masm) { | 284 void RegExpExecStub::Generate(MacroAssembler* masm) { |
| 285 // Just jump directly to runtime if native RegExp is not selected at compile | |
| 286 // time or if regexp entry in generated code is turned off runtime switch or | |
| 287 // at compilation. | |
| 288 #ifdef V8_INTERPRETED_REGEXP | 285 #ifdef V8_INTERPRETED_REGEXP |
| 289 __ TailCallRuntime(Runtime::kRegExpExec); | 286 // This case is handled prior to the RegExpExecStub call. |
| 287 __ Abort(kUnexpectedRegExpExecCall); |
| 290 #else // V8_INTERPRETED_REGEXP | 288 #else // V8_INTERPRETED_REGEXP |
| 291 | |
| 292 // Stack frame on entry. | |
| 293 // esp[0]: return address | |
| 294 // esp[4]: last_match_info (expected JSArray) | |
| 295 // esp[8]: previous index | |
| 296 // esp[12]: subject string | |
| 297 // esp[16]: JSRegExp object | |
| 298 | |
| 299 static const int kLastMatchInfoOffset = 1 * kPointerSize; | |
| 300 static const int kPreviousIndexOffset = 2 * kPointerSize; | |
| 301 static const int kSubjectOffset = 3 * kPointerSize; | |
| 302 static const int kJSRegExpOffset = 4 * kPointerSize; | |
| 303 | |
| 304 Label runtime; | |
| 305 Factory* factory = isolate()->factory(); | |
| 306 | |
| 307 // Ensure that a RegExp stack is allocated. | |
| 308 ExternalReference address_of_regexp_stack_memory_address = | |
| 309 ExternalReference::address_of_regexp_stack_memory_address(isolate()); | |
| 310 ExternalReference address_of_regexp_stack_memory_size = | |
| 311 ExternalReference::address_of_regexp_stack_memory_size(isolate()); | |
| 312 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); | |
| 313 __ test(ebx, ebx); | |
| 314 __ j(zero, &runtime); | |
| 315 | |
| 316 // Check that the first argument is a JSRegExp object. | |
| 317 __ mov(eax, Operand(esp, kJSRegExpOffset)); | |
| 318 STATIC_ASSERT(kSmiTag == 0); | |
| 319 __ JumpIfSmi(eax, &runtime); | |
| 320 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); | |
| 321 __ j(not_equal, &runtime); | |
| 322 | |
| 323 // Check that the RegExp has been compiled (data contains a fixed array). | |
| 324 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | |
| 325 if (FLAG_debug_code) { | |
| 326 __ test(ecx, Immediate(kSmiTagMask)); | |
| 327 __ Check(not_zero, kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
| 328 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); | |
| 329 __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
| 330 } | |
| 331 | |
| 332 // ecx: RegExp data (FixedArray) | |
| 333 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | |
| 334 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); | |
| 335 __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); | |
| 336 __ j(not_equal, &runtime); | |
| 337 | |
| 338 // ecx: RegExp data (FixedArray) | |
| 339 // Check that the number of captures fit in the static offsets vector buffer. | |
| 340 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); | |
| 341 // Check (number_of_captures + 1) * 2 <= offsets vector size | |
| 342 // Or number_of_captures * 2 <= offsets vector size - 2 | |
| 343 // Multiplying by 2 comes for free since edx is smi-tagged. | |
| 344 STATIC_ASSERT(kSmiTag == 0); | |
| 345 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | |
| 346 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); | |
| 347 __ cmp(edx, Isolate::kJSRegexpStaticOffsetsVectorSize - 2); | |
| 348 __ j(above, &runtime); | |
| 349 | |
| 350 // Reset offset for possibly sliced string. | |
| 351 __ Move(edi, Immediate(0)); | |
| 352 __ mov(eax, Operand(esp, kSubjectOffset)); | |
| 353 __ JumpIfSmi(eax, &runtime); | |
| 354 __ mov(edx, eax); // Make a copy of the original subject string. | |
| 355 | |
| 356 // eax: subject string | |
| 357 // edx: subject string | |
| 358 // ecx: RegExp data (FixedArray) | |
| 359 // Handle subject string according to its encoding and representation: | |
| 360 // (1) Sequential two byte? If yes, go to (9). | |
| 361 // (2) Sequential one byte? If yes, go to (5). | |
| 362 // (3) Sequential or cons? If not, go to (6). | |
| 363 // (4) Cons string. If the string is flat, replace subject with first string | |
| 364 // and go to (1). Otherwise bail out to runtime. | |
| 365 // (5) One byte sequential. Load regexp code for one byte. | |
| 366 // (E) Carry on. | |
| 367 /// [...] | |
| 368 | |
| 369 // Deferred code at the end of the stub: | |
| 370 // (6) Long external string? If not, go to (10). | |
| 371 // (7) External string. Make it, offset-wise, look like a sequential string. | |
| 372 // (8) Is the external string one byte? If yes, go to (5). | |
| 373 // (9) Two byte sequential. Load regexp code for two byte. Go to (E). | |
| 374 // (10) Short external string or not a string? If yes, bail out to runtime. | |
| 375 // (11) Sliced or thin string. Replace subject with parent. Go to (1). | |
| 376 | |
| 377 Label seq_one_byte_string /* 5 */, seq_two_byte_string /* 9 */, | |
| 378 external_string /* 7 */, check_underlying /* 1 */, | |
| 379 not_seq_nor_cons /* 6 */, check_code /* E */, not_long_external /* 10 */; | |
| 380 | |
| 381 __ bind(&check_underlying); | |
| 382 // (1) Sequential two byte? If yes, go to (9). | |
| 383 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | |
| 384 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | |
| 385 | |
| 386 __ and_(ebx, kIsNotStringMask | | |
| 387 kStringRepresentationMask | | |
| 388 kStringEncodingMask | | |
| 389 kShortExternalStringMask); | |
| 390 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); | |
| 391 __ j(zero, &seq_two_byte_string); // Go to (9). | |
| 392 | |
| 393 // (2) Sequential one byte? If yes, go to (5). | |
| 394 // Any other sequential string must be one byte. | |
| 395 __ and_(ebx, Immediate(kIsNotStringMask | | |
| 396 kStringRepresentationMask | | |
| 397 kShortExternalStringMask)); | |
| 398 __ j(zero, &seq_one_byte_string, Label::kNear); // Go to (5). | |
| 399 | |
| 400 // (3) Sequential or cons? If not, go to (6). | |
| 401 // We check whether the subject string is a cons, since sequential strings | |
| 402 // have already been covered. | |
| 403 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | |
| 404 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | |
| 405 STATIC_ASSERT(kThinStringTag > kExternalStringTag); | |
| 406 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | |
| 407 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | |
| 408 __ cmp(ebx, Immediate(kExternalStringTag)); | |
| 409 __ j(greater_equal, ¬_seq_nor_cons); // Go to (6). | |
| 410 | |
| 411 // (4) Cons string. Check that it's flat. | |
| 412 // Replace subject with first string and reload instance type. | |
| 413 __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string()); | |
| 414 __ j(not_equal, &runtime); | |
| 415 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); | |
| 416 __ jmp(&check_underlying); | |
| 417 | |
| 418 // eax: sequential subject string (or look-alike, external string) | |
| 419 // edx: original subject string | |
| 420 // ecx: RegExp data (FixedArray) | |
| 421 // (5) One byte sequential. Load regexp code for one byte. | |
| 422 __ bind(&seq_one_byte_string); | |
| 423 // Load previous index and check range before edx is overwritten. We have | |
| 424 // to use edx instead of eax here because it might have been only made to | |
| 425 // look like a sequential string when it actually is an external string. | |
| 426 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); | |
| 427 __ JumpIfNotSmi(ebx, &runtime); | |
| 428 __ cmp(ebx, FieldOperand(edx, String::kLengthOffset)); | |
| 429 __ j(above_equal, &runtime); | |
| 430 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataOneByteCodeOffset)); | |
| 431 __ Move(ecx, Immediate(1)); // Type is one byte. | |
| 432 | |
| 433 // (E) Carry on. String handling is done. | |
| 434 __ bind(&check_code); | |
| 435 // edx: irregexp code | |
| 436 // Check that the irregexp code has been generated for the actual string | |
| 437 // encoding. If it has, the field contains a code object otherwise it contains | |
| 438 // a smi (code flushing support). | |
| 439 __ JumpIfSmi(edx, &runtime); | |
| 440 | |
| 441 // eax: subject string | |
| 442 // ebx: previous index (smi) | |
| 443 // edx: code | |
| 444 // ecx: encoding of subject string (1 if one_byte, 0 if two_byte); | |
| 445 // All checks done. Now push arguments for native regexp code. | |
| 446 Counters* counters = isolate()->counters(); | |
| 447 __ IncrementCounter(counters->regexp_entry_native(), 1); | |
| 448 | |
| 449 // Isolates: note we add an additional parameter here (isolate pointer). | 289 // Isolates: note we add an additional parameter here (isolate pointer). |
| 450 static const int kRegExpExecuteArguments = 9; | 290 static const int kRegExpExecuteArguments = 9; |
| 451 __ EnterApiExitFrame(kRegExpExecuteArguments); | 291 __ EnterApiExitFrame(kRegExpExecuteArguments); |
| 452 | 292 |
| 453 // Argument 9: Pass current isolate address. | 293 // Argument 9: Pass current isolate address. |
| 454 __ mov(Operand(esp, 8 * kPointerSize), | 294 __ mov(Operand(esp, 8 * kPointerSize), |
| 455 Immediate(ExternalReference::isolate_address(isolate()))); | 295 Immediate(ExternalReference::isolate_address(isolate()))); |
| 456 | 296 |
| 457 // Argument 8: Indicate that this is a direct call from JavaScript. | 297 // Argument 8: Indicate that this is a direct call from JavaScript. |
| 458 __ mov(Operand(esp, 7 * kPointerSize), Immediate(1)); | 298 __ mov(Operand(esp, 7 * kPointerSize), Immediate(1)); |
| 459 | 299 |
| 460 // Argument 7: Start (high end) of backtracking stack memory area. | 300 // Argument 7: Start (high end) of backtracking stack memory area. |
| 301 ExternalReference address_of_regexp_stack_memory_address = |
| 302 ExternalReference::address_of_regexp_stack_memory_address(isolate()); |
| 303 ExternalReference address_of_regexp_stack_memory_size = |
| 304 ExternalReference::address_of_regexp_stack_memory_size(isolate()); |
| 461 __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address)); | 305 __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address)); |
| 462 __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size)); | 306 __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
| 463 __ mov(Operand(esp, 6 * kPointerSize), esi); | 307 __ mov(Operand(esp, 6 * kPointerSize), esi); |
| 464 | 308 |
| 465 // Argument 6: Set the number of capture registers to zero to force global | 309 // Argument 6: Set the number of capture registers to zero to force global |
| 466 // regexps to behave as non-global. This does not affect non-global regexps. | 310 // regexps to behave as non-global. This does not affect non-global regexps. |
| 467 __ mov(Operand(esp, 5 * kPointerSize), Immediate(0)); | 311 __ mov(Operand(esp, 5 * kPointerSize), Immediate(0)); |
| 468 | 312 |
| 469 // Argument 5: static offsets vector buffer. | 313 // Argument 5: static offsets vector buffer. |
| 470 __ mov(Operand(esp, 4 * kPointerSize), | 314 __ mov(Operand(esp, 4 * kPointerSize), |
| 471 Immediate(ExternalReference::address_of_static_offsets_vector( | 315 Immediate(ExternalReference::address_of_static_offsets_vector( |
| 472 isolate()))); | 316 isolate()))); |
| 473 | 317 |
| 318 // Argument 4: End of string data |
| 319 // Argument 3: Start of string data |
| 320 __ mov(Operand(esp, 3 * kPointerSize), |
| 321 RegExpExecDescriptor::StringEndRegister()); |
| 322 __ mov(Operand(esp, 2 * kPointerSize), |
| 323 RegExpExecDescriptor::StringStartRegister()); |
| 324 |
| 474 // Argument 2: Previous index. | 325 // Argument 2: Previous index. |
| 475 __ SmiUntag(ebx); | 326 __ mov(Operand(esp, 1 * kPointerSize), |
| 476 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 327 RegExpExecDescriptor::LastIndexRegister()); |
| 477 | 328 |
| 478 // Argument 1: Original subject string. | 329 // Argument 1: Original subject string. |
| 479 // The original subject is in the previous stack frame. Therefore we have to | 330 __ mov(Operand(esp, 0 * kPointerSize), |
| 480 // use ebp, which points exactly to one pointer size below the previous esp. | 331 RegExpExecDescriptor::StringRegister()); |
| 481 // (Because creating a new stack frame pushes the previous ebp onto the stack | |
| 482 // and thereby moves up esp by one kPointerSize.) | |
| 483 __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize)); | |
| 484 __ mov(Operand(esp, 0 * kPointerSize), esi); | |
| 485 | |
| 486 // esi: original subject string | |
| 487 // eax: underlying subject string | |
| 488 // ebx: previous index | |
| 489 // ecx: encoding of subject string (1 if one_byte 0 if two_byte); | |
| 490 // edx: code | |
| 491 // Argument 4: End of string data | |
| 492 // Argument 3: Start of string data | |
| 493 // Prepare start and end index of the input. | |
| 494 // Load the length from the original sliced string if that is the case. | |
| 495 __ mov(esi, FieldOperand(esi, String::kLengthOffset)); | |
| 496 __ add(esi, edi); // Calculate input end wrt offset. | |
| 497 __ SmiUntag(edi); | |
| 498 __ add(ebx, edi); // Calculate input start wrt offset. | |
| 499 | |
| 500 // ebx: start index of the input string | |
| 501 // esi: end index of the input string | |
| 502 Label setup_two_byte, setup_rest; | |
| 503 __ test(ecx, ecx); | |
| 504 __ j(zero, &setup_two_byte, Label::kNear); | |
| 505 __ SmiUntag(esi); | |
| 506 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqOneByteString::kHeaderSize)); | |
| 507 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | |
| 508 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqOneByteString::kHeaderSize)); | |
| 509 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | |
| 510 __ jmp(&setup_rest, Label::kNear); | |
| 511 | |
| 512 __ bind(&setup_two_byte); | |
| 513 STATIC_ASSERT(kSmiTag == 0); | |
| 514 STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2). | |
| 515 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize)); | |
| 516 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. | |
| 517 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); | |
| 518 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. | |
| 519 | |
| 520 __ bind(&setup_rest); | |
| 521 | 332 |
| 522 // Locate the code entry and call it. | 333 // Locate the code entry and call it. |
| 523 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 334 __ add(RegExpExecDescriptor::CodeRegister(), |
| 524 __ call(edx); | 335 Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 336 __ call(RegExpExecDescriptor::CodeRegister()); |
| 525 | 337 |
| 526 // Drop arguments and come back to JS mode. | 338 // Drop arguments and come back to JS mode. |
| 527 __ LeaveApiExitFrame(true); | 339 __ LeaveApiExitFrame(true); |
| 528 | 340 |
| 529 // Check the result. | 341 // TODO(jgruber): Don't tag return value once this is supported by stubs. |
| 530 Label success; | 342 __ SmiTag(eax); |
| 531 __ cmp(eax, 1); | 343 __ ret(0 * kPointerSize); |
| 532 // We expect exactly one result since we force the called regexp to behave | |
| 533 // as non-global. | |
| 534 __ j(equal, &success); | |
| 535 Label failure; | |
| 536 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); | |
| 537 __ j(equal, &failure); | |
| 538 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); | |
| 539 // If not exception it can only be retry. Handle that in the runtime system. | |
| 540 __ j(not_equal, &runtime); | |
| 541 // Result must now be exception. If there is no pending exception already a | |
| 542 // stack overflow (on the backtrack stack) was detected in RegExp code but | |
| 543 // haven't created the exception yet. Handle that in the runtime system. | |
| 544 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | |
| 545 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, | |
| 546 isolate()); | |
| 547 __ mov(edx, Immediate(isolate()->factory()->the_hole_value())); | |
| 548 __ mov(eax, Operand::StaticVariable(pending_exception)); | |
| 549 __ cmp(edx, eax); | |
| 550 __ j(equal, &runtime); | |
| 551 | |
| 552 // For exception, throw the exception again. | |
| 553 __ TailCallRuntime(Runtime::kRegExpExecReThrow); | |
| 554 | |
| 555 __ bind(&failure); | |
| 556 // For failure to match, return null. | |
| 557 __ mov(eax, factory->null_value()); | |
| 558 __ ret(4 * kPointerSize); | |
| 559 | |
| 560 // Load RegExp data. | |
| 561 __ bind(&success); | |
| 562 __ mov(eax, Operand(esp, kJSRegExpOffset)); | |
| 563 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | |
| 564 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); | |
| 565 // Calculate number of capture registers (number_of_captures + 1) * 2. | |
| 566 STATIC_ASSERT(kSmiTag == 0); | |
| 567 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | |
| 568 __ add(edx, Immediate(2)); // edx was a smi. | |
| 569 | |
| 570 // edx: Number of capture registers | |
| 571 // Check that the last match info is a FixedArray. | |
| 572 __ mov(ebx, Operand(esp, kLastMatchInfoOffset)); | |
| 573 __ JumpIfSmi(ebx, &runtime); | |
| 574 // Check that the object has fast elements. | |
| 575 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); | |
| 576 __ cmp(eax, factory->fixed_array_map()); | |
| 577 __ j(not_equal, &runtime); | |
| 578 // Check that the last match info has space for the capture registers and the | |
| 579 // additional information. | |
| 580 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); | |
| 581 __ SmiUntag(eax); | |
| 582 __ sub(eax, Immediate(RegExpMatchInfo::kLastMatchOverhead)); | |
| 583 __ cmp(edx, eax); | |
| 584 __ j(greater, &runtime); | |
| 585 | |
| 586 // ebx: last_match_info backing store (FixedArray) | |
| 587 // edx: number of capture registers | |
| 588 // Store the capture count. | |
| 589 __ SmiTag(edx); // Number of capture registers to smi. | |
| 590 __ mov(FieldOperand(ebx, RegExpMatchInfo::kNumberOfCapturesOffset), edx); | |
| 591 __ SmiUntag(edx); // Number of capture registers back from smi. | |
| 592 // Store last subject and last input. | |
| 593 __ mov(eax, Operand(esp, kSubjectOffset)); | |
| 594 __ mov(ecx, eax); | |
| 595 __ mov(FieldOperand(ebx, RegExpMatchInfo::kLastSubjectOffset), eax); | |
| 596 __ RecordWriteField(ebx, RegExpMatchInfo::kLastSubjectOffset, eax, edi, | |
| 597 kDontSaveFPRegs); | |
| 598 __ mov(eax, ecx); | |
| 599 __ mov(FieldOperand(ebx, RegExpMatchInfo::kLastInputOffset), eax); | |
| 600 __ RecordWriteField(ebx, RegExpMatchInfo::kLastInputOffset, eax, edi, | |
| 601 kDontSaveFPRegs); | |
| 602 | |
| 603 // Get the static offsets vector filled by the native regexp code. | |
| 604 ExternalReference address_of_static_offsets_vector = | |
| 605 ExternalReference::address_of_static_offsets_vector(isolate()); | |
| 606 __ mov(ecx, Immediate(address_of_static_offsets_vector)); | |
| 607 | |
| 608 // ebx: last_match_info backing store (FixedArray) | |
| 609 // ecx: offsets vector | |
| 610 // edx: number of capture registers | |
| 611 Label next_capture, done; | |
| 612 // Capture register counter starts from number of capture registers and | |
| 613 // counts down until wrapping after zero. | |
| 614 __ bind(&next_capture); | |
| 615 __ sub(edx, Immediate(1)); | |
| 616 __ j(negative, &done, Label::kNear); | |
| 617 // Read the value from the static offsets vector buffer. | |
| 618 __ mov(edi, Operand(ecx, edx, times_int_size, 0)); | |
| 619 __ SmiTag(edi); | |
| 620 // Store the smi value in the last match info. | |
| 621 __ mov(FieldOperand(ebx, edx, times_pointer_size, | |
| 622 RegExpMatchInfo::kFirstCaptureOffset), | |
| 623 edi); | |
| 624 __ jmp(&next_capture); | |
| 625 __ bind(&done); | |
| 626 | |
| 627 // Return last match info. | |
| 628 __ mov(eax, ebx); | |
| 629 __ ret(4 * kPointerSize); | |
| 630 | |
| 631 // Do the runtime call to execute the regexp. | |
| 632 __ bind(&runtime); | |
| 633 __ TailCallRuntime(Runtime::kRegExpExec); | |
| 634 | |
| 635 // Deferred code for string handling. | |
| 636 // (6) Long external string? If not, go to (10). | |
| 637 __ bind(¬_seq_nor_cons); | |
| 638 // Compare flags are still set from (3). | |
| 639 __ j(greater, ¬_long_external, Label::kNear); // Go to (10). | |
| 640 | |
| 641 // (7) External string. Short external strings have been ruled out. | |
| 642 __ bind(&external_string); | |
| 643 // Reload instance type. | |
| 644 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | |
| 645 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | |
| 646 if (FLAG_debug_code) { | |
| 647 // Assert that we do not have a cons or slice (indirect strings) here. | |
| 648 // Sequential strings have already been ruled out. | |
| 649 __ test_b(ebx, Immediate(kIsIndirectStringMask)); | |
| 650 __ Assert(zero, kExternalStringExpectedButNotFound); | |
| 651 } | |
| 652 __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); | |
| 653 // Move the pointer so that offset-wise, it looks like a sequential string. | |
| 654 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | |
| 655 __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
| 656 STATIC_ASSERT(kTwoByteStringTag == 0); | |
| 657 // (8) Is the external string one byte? If yes, go to (5). | |
| 658 __ test_b(ebx, Immediate(kStringEncodingMask)); | |
| 659 __ j(not_zero, &seq_one_byte_string); // Go to (5). | |
| 660 | |
| 661 // eax: sequential subject string (or look-alike, external string) | |
| 662 // edx: original subject string | |
| 663 // ecx: RegExp data (FixedArray) | |
| 664 // (9) Two byte sequential. Load regexp code for two byte. Go to (E). | |
| 665 __ bind(&seq_two_byte_string); | |
| 666 // Load previous index and check range before edx is overwritten. We have | |
| 667 // to use edx instead of eax here because it might have been only made to | |
| 668 // look like a sequential string when it actually is an external string. | |
| 669 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); | |
| 670 __ JumpIfNotSmi(ebx, &runtime); | |
| 671 __ cmp(ebx, FieldOperand(edx, String::kLengthOffset)); | |
| 672 __ j(above_equal, &runtime); | |
| 673 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset)); | |
| 674 __ Move(ecx, Immediate(0)); // Type is two byte. | |
| 675 __ jmp(&check_code); // Go to (E). | |
| 676 | |
| 677 // (10) Not a string or a short external string? If yes, bail out to runtime. | |
| 678 __ bind(¬_long_external); | |
| 679 // Catch non-string subject or short external string. | |
| 680 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); | |
| 681 __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag)); | |
| 682 __ j(not_zero, &runtime); | |
| 683 | |
| 684 // (11) Sliced or thin string. Replace subject with parent. Go to (1). | |
| 685 Label thin_string; | |
| 686 __ cmp(ebx, Immediate(kThinStringTag)); | |
| 687 __ j(equal, &thin_string, Label::kNear); | |
| 688 // Load offset into edi and replace subject string with parent. | |
| 689 __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset)); | |
| 690 __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset)); | |
| 691 __ jmp(&check_underlying); // Go to (1). | |
| 692 | |
| 693 __ bind(&thin_string); | |
| 694 __ mov(eax, FieldOperand(eax, ThinString::kActualOffset)); | |
| 695 __ jmp(&check_underlying); // Go to (1). | |
| 696 #endif // V8_INTERPRETED_REGEXP | 344 #endif // V8_INTERPRETED_REGEXP |
| 697 } | 345 } |
| 698 | 346 |
| 699 | 347 |
| 700 static int NegativeComparisonResult(Condition cc) { | 348 static int NegativeComparisonResult(Condition cc) { |
| 701 DCHECK(cc != equal); | 349 DCHECK(cc != equal); |
| 702 DCHECK((cc == less) || (cc == less_equal) | 350 DCHECK((cc == less) || (cc == less_equal) |
| 703 || (cc == greater) || (cc == greater_equal)); | 351 || (cc == greater) || (cc == greater_equal)); |
| 704 return (cc == greater || cc == greater_equal) ? LESS : GREATER; | 352 return (cc == greater || cc == greater_equal) ? LESS : GREATER; |
| 705 } | 353 } |
| (...skipping 3190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3896 kStackUnwindSpace, nullptr, return_value_operand, | 3544 kStackUnwindSpace, nullptr, return_value_operand, |
| 3897 NULL); | 3545 NULL); |
| 3898 } | 3546 } |
| 3899 | 3547 |
| 3900 #undef __ | 3548 #undef __ |
| 3901 | 3549 |
| 3902 } // namespace internal | 3550 } // namespace internal |
| 3903 } // namespace v8 | 3551 } // namespace v8 |
| 3904 | 3552 |
| 3905 #endif // V8_TARGET_ARCH_X87 | 3553 #endif // V8_TARGET_ARCH_X87 |
| OLD | NEW |