Index: src/ia32/codegen-ia32.cc |
=================================================================== |
--- src/ia32/codegen-ia32.cc (revision 3531) |
+++ src/ia32/codegen-ia32.cc (working copy) |
@@ -32,7 +32,10 @@ |
#include "compiler.h" |
#include "debug.h" |
#include "ic-inl.h" |
+#include "jsregexp.h" |
#include "parser.h" |
+#include "regexp-macro-assembler.h" |
+#include "regexp-stack.h" |
#include "register-allocator-inl.h" |
#include "runtime.h" |
#include "scopes.h" |
@@ -5282,6 +5285,20 @@ |
} |
+void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) { |
+ ASSERT_EQ(args->length(), 4); |
+ |
+ // Load the arguments on the stack and call the stub. |
+ Load(args->at(0)); |
+ Load(args->at(1)); |
+ Load(args->at(2)); |
+ Load(args->at(3)); |
+ RegExpExecStub stub; |
+ Result result = frame_->CallStub(&stub, 4); |
+ frame_->Push(&result); |
+} |
+ |
+ |
void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
if (CheckForInlineRuntimeCall(node)) { |
return; |
@@ -7909,6 +7926,277 @@ |
} |
+void RegExpExecStub::Generate(MacroAssembler* masm) { |
+ // Just jump directly to runtime if regexp entry in generated code is turned |
+ // off. |
+ if (!FLAG_regexp_entry_native) { |
+ __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); |
+ return; |
+ } |
+ |
+ // Stack frame on entry. |
+ // esp[0]: return address |
+ // esp[4]: last_match_info (expected JSArray) |
+ // esp[8]: previous index |
+ // esp[12]: subject string |
+ // esp[16]: JSRegExp object |
+ |
+ Label runtime; |
+ |
+ // Check that the first argument is a JSRegExp object. |
+ __ mov(eax, Operand(esp, 4 * kPointerSize)); |
+ ASSERT_EQ(0, kSmiTag); |
+ __ test(eax, Immediate(kSmiTagMask)); |
+ __ j(zero, &runtime); |
+ __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); |
+ __ j(not_equal, &runtime); |
+ // Check that the RegExp has been compiled (data contains a fixed array). |
+ __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |
+#ifdef DEBUG |
+ __ test(ecx, Immediate(kSmiTagMask)); |
+ __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); |
+ __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); |
+ __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); |
+#endif |
+ |
+ // ecx: RegExp data (FixedArray) |
+ // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
+ __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); |
+ __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); |
+ __ j(not_equal, &runtime); |
+ |
+ // ecx: RegExp data (FixedArray) |
+ // Check that the number of captures fit in the static offsets vector buffer. |
+ __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); |
+ // Calculate number of capture registers (number_of_captures + 1) * 2. This |
+ // uses the asumption that smis are 2 * their untagged value. |
+ ASSERT_EQ(0, kSmiTag); |
+ ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
+ __ add(Operand(edx), Immediate(2)); // edx was a smi. |
+ // Check that the static offsets vector buffer is large enough. |
+ __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); |
+ __ j(above, &runtime); |
+ |
+ // ecx: RegExp data (FixedArray) |
+ // edx: Number of capture registers |
+ // Check that the second argument is a string. |
+ __ mov(eax, Operand(esp, 3 * kPointerSize)); |
+ __ test(eax, Immediate(kSmiTagMask)); |
+ __ j(zero, &runtime); |
+ Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); |
+ __ j(NegateCondition(is_string), &runtime); |
+ // Get the length of the string to ebx. |
+ __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
+ |
+ // ebx: Length of subject string |
+ // ecx: RegExp data (FixedArray) |
+ // edx: Number of capture registers |
+ // Check that the third argument is a positive smi. |
+ __ mov(eax, Operand(esp, 2 * kPointerSize)); |
+ __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
+ __ j(not_zero, &runtime); |
+ // Check that it is not greater than the subject string length. |
+ __ SmiUntag(eax); |
+ __ cmp(eax, Operand(ebx)); |
+ __ j(greater, &runtime); |
+ |
+ // ecx: RegExp data (FixedArray) |
+ // edx: Number of capture registers |
+ // Check that the fourth object is a JSArray object. |
+ __ mov(eax, Operand(esp, 1 * kPointerSize)); |
+ __ test(eax, Immediate(kSmiTagMask)); |
+ __ j(zero, &runtime); |
+ __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); |
+ __ j(not_equal, &runtime); |
+ // Check that the JSArray is in fast case. |
+ __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); |
+ __ cmp(eax, Factory::fixed_array_map()); |
+ __ j(not_equal, &runtime); |
+ // Check that the last match info has space for the capture registers and the |
+ // additional information. |
+ __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); |
+ __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead)); |
+ __ cmp(edx, Operand(eax)); |
+ __ j(greater, &runtime); |
+ |
+ // ecx: RegExp data (FixedArray) |
+ // Check the representation and encoding of the subject string (only support |
+ // flat ascii strings). |
+ __ mov(eax, Operand(esp, 3 * kPointerSize)); |
+ __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
+ __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
+ __ and_(ebx, kStringRepresentationMask | kStringEncodingMask); |
+ __ cmp(ebx, kSeqStringTag | kAsciiStringTag); |
+ __ j(not_equal, &runtime); |
+ |
+ // ecx: RegExp data (FixedArray) |
+ // Ensure that a RegExp stack is allocated. |
+ ExternalReference address_of_regexp_stack_memory_address = |
+ ExternalReference::address_of_regexp_stack_memory_address(); |
+ ExternalReference address_of_regexp_stack_memory_size = |
+ ExternalReference::address_of_regexp_stack_memory_size(); |
+ __ mov(eax, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
+ __ test(eax, Operand(eax)); |
+ __ j(zero, &runtime, not_taken); |
+ |
+ // ecx: RegExp data (FixedArray) |
+ // Check that the irregexp code has been generated for an ascii string. If |
+ // it has the field contains a code object otherwise it contains the hole. |
+ __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset)); |
+ __ CmpObjectType(edx, CODE_TYPE, ebx); |
+ __ j(not_equal, &runtime); |
+ |
+ // Load used arguments before starting to push arguments for call to native |
+ // RegExp code to avoid handling changing stack height. |
+ __ mov(eax, Operand(esp, 3 * kPointerSize)); // Subject string. |
+ __ mov(ebx, Operand(esp, 2 * kPointerSize)); // Previous index. |
+ __ mov(ecx, Operand(esp, 4 * kPointerSize)); // JSRegExp object. |
+ __ SmiUntag(ebx); // Previous index from sim. |
+ |
+ // eax: subject string |
+ // ebx: previous index |
+ // edx: code |
+ // All checks done. Now push arguments for native regexp code. |
+ __ IncrementCounter(&Counters::regexp_entry_native, 1); |
+ |
+ // Argument 8: Indicate that this is a direct call from JavaScript. |
+ __ push(Immediate(1)); |
+ |
+ // Argument 7: Start (high end) of backtracking stack memory area. |
+ __ mov(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_address)); |
+ __ add(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
+ __ push(ecx); |
+ |
+ // Argument 6: At start of string? |
+ __ xor_(Operand(ecx), ecx); // setcc only operated on cl (lower byte of ecx). |
+ __ test(ebx, Operand(ebx)); |
+ __ setcc(zero, ecx); // 1 if 0 (start of string), 0 if positive. |
+ __ push(ecx); |
+ |
+ // Argument 5: static offsets vector buffer. |
+ __ push(Immediate(ExternalReference::address_of_static_offsets_vector())); |
+ |
+ // Argument 4: End of string data. |
+ __ mov(ecx, FieldOperand(eax, String::kLengthOffset)); |
+ __ add(ecx, Operand(eax)); |
+ __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ __ push(ecx); |
+ |
+ // Argument 3: Start of string data. |
+ __ mov(ecx, ebx); |
+ __ add(ebx, Operand(eax)); // String is ASCII. |
+ __ add(Operand(ebx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
+ __ push(ebx); |
+ |
+ // Argument 2: Previous index. |
+ __ push(ecx); |
+ |
+ // Argument 1: Subject string. |
+ __ push(eax); |
+ |
+ // Locate the code entry and call it. |
+ __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); |
+ __ call(Operand(edx)); |
+ // Remove arguments. |
+ __ add(Operand(esp), Immediate(8 * kPointerSize)); |
+ |
+ // Check the result. |
+ Label success; |
+ __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); |
+ __ j(equal, &success, taken); |
+ Label failure; |
+ __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); |
+ __ j(equal, &failure, taken); |
+ __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); |
+ // If not exception it can only be retry. Handle that in the runtime system. |
+ __ j(not_equal, &runtime); |
+ // Result must now be exception. If there is no pending exception already a |
+ // stack overflow (on the backtrack stack) was detected in RegExp code but |
+ // haven't created the exception yet. Handle that in the runtime system. |
+ ExternalReference pending_exception(Top::k_pending_exception_address); |
+ __ mov(eax, |
+ Operand::StaticVariable(ExternalReference::the_hole_value_location())); |
+ __ cmp(eax, Operand::StaticVariable(pending_exception)); |
+ __ j(equal, &runtime); |
+ __ bind(&failure); |
+ // For failure and exception return null. |
+ __ mov(Operand(eax), Factory::null_value()); |
+ __ ret(4 * kPointerSize); |
+ |
+ // Load RegExp data. |
+ __ bind(&success); |
+ __ mov(eax, Operand(esp, 4 * kPointerSize)); |
+ __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |
+ __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); |
+ // Calculate number of capture registers (number_of_captures + 1) * 2. |
+ __ add(Operand(edx), Immediate(2)); // edx was a smi. |
+ |
+ // edx: Number of capture registers |
+ // Load last_match_info which is still known to be a fast case JSArray. |
+ __ mov(eax, Operand(esp, 1 * kPointerSize)); |
+ __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); |
+ |
+ // ebx: last_match_info backing store (FixedArray) |
+ // edx: number of capture registers |
+ // Store the capture count. |
+ __ SmiTag(edx); // Number of capture registers to smi. |
+ __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx); |
+ __ SmiUntag(edx); // Number of capture registers back from smi. |
+ // Store last subject and last input. |
+ __ mov(eax, Operand(esp, 3 * kPointerSize)); |
+ __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax); |
+ __ mov(ecx, ebx); |
+ __ RecordWrite(ecx, RegExpImpl::kLastSubjectOffset, eax, edi); |
+ __ mov(eax, Operand(esp, 3 * kPointerSize)); |
+ __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax); |
+ __ mov(ecx, ebx); |
+ __ RecordWrite(ecx, RegExpImpl::kLastInputOffset, eax, edi); |
+ |
+ // Get the static offsets vector filled by the native regexp code. |
+ ExternalReference address_of_static_offsets_vector = |
+ ExternalReference::address_of_static_offsets_vector(); |
+ __ mov(ecx, Immediate(address_of_static_offsets_vector)); |
+ |
+ // ebx: last_match_info backing store (FixedArray) |
+ // ecx: offsets vector |
+ // edx: number of capture registers |
+ Label next_capture, done; |
+ __ mov(eax, Operand(esp, 2 * kPointerSize)); // Read previous index. |
+ // Capture register counter starts from number of capture registers and |
+ // counts down until wraping after zero. |
+ __ bind(&next_capture); |
+ __ sub(Operand(edx), Immediate(1)); |
+ __ j(negative, &done); |
+ // Read the value from the static offsets vector buffer. |
+ __ mov(edi, Operand(ecx, edx, times_pointer_size, 0)); |
+ // Perform explicit shift |
+ ASSERT_EQ(0, kSmiTag); |
+ __ shl(edi, kSmiTagSize); |
+ // Add previous index (from its stack slot) if value is not negative. |
+ Label capture_negative; |
+ // Carry flag set by shift above. |
+ __ j(negative, &capture_negative, not_taken); |
+ __ add(edi, Operand(eax)); // Add previous index (adding smi to smi). |
+ __ bind(&capture_negative); |
+ // Store the smi value in the last match info. |
+ __ mov(FieldOperand(ebx, |
+ edx, |
+ times_pointer_size, |
+ RegExpImpl::kFirstCaptureOffset), |
+ edi); |
+ __ jmp(&next_capture); |
+ __ bind(&done); |
+ |
+ // Return last match info. |
+ __ mov(eax, Operand(esp, 1 * kPointerSize)); |
+ __ ret(4 * kPointerSize); |
+ |
+ // Do the runtime call to execute the regexp. |
+ __ bind(&runtime); |
+ __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); |
+} |
+ |
+ |
void CompareStub::Generate(MacroAssembler* masm) { |
Label call_builtin, done; |