| Index: src/arm/codegen-arm.cc | 
| =================================================================== | 
| --- src/arm/codegen-arm.cc	(revision 4395) | 
| +++ src/arm/codegen-arm.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" | 
| @@ -4015,8 +4018,8 @@ | 
| Load(args->at(1)); | 
| Load(args->at(2)); | 
| Load(args->at(3)); | 
| - | 
| -  frame_->CallRuntime(Runtime::kRegExpExec, 4); | 
| +  RegExpExecStub stub; | 
| +  frame_->CallStub(&stub, 4); | 
| frame_->EmitPush(r0); | 
| } | 
|  | 
| @@ -7502,6 +7505,345 @@ | 
| } | 
|  | 
|  | 
| +void RegExpExecStub::Generate(MacroAssembler* masm) { | 
| +  // Just jump directly to runtime if native RegExp is not selected at compile | 
| +  // time or if regexp entry in generated code is turned off runtime switch or | 
| +  // at compilation. | 
| +#ifndef V8_NATIVE_REGEXP | 
| +  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 
| +#else  // V8_NATIVE_REGEXP | 
| +  if (!FLAG_regexp_entry_native) { | 
| +    __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 
| +    return; | 
| +  } | 
| + | 
| +  // Stack frame on entry. | 
| +  //  sp[0]: last_match_info (expected JSArray) | 
| +  //  sp[4]: previous index | 
| +  //  sp[8]: subject string | 
| +  //  sp[12]: JSRegExp object | 
| + | 
| +  static const int kLastMatchInfoOffset = 0 * kPointerSize; | 
| +  static const int kPreviousIndexOffset = 1 * kPointerSize; | 
| +  static const int kSubjectOffset = 2 * kPointerSize; | 
| +  static const int kJSRegExpOffset = 3 * kPointerSize; | 
| + | 
| +  Label runtime, invoke_regexp; | 
| + | 
| +  // Allocation of registers for this function. These are in callee save | 
| +  // registers and will be preserved by the call to the native RegExp code, as | 
| +  // this code is called using the normal C calling convention. When calling | 
| +  // directly from generated code the native RegExp code will not do a GC and | 
| +  // therefore the content of these registers are safe to use after the call. | 
| +  Register subject = r4; | 
| +  Register regexp_data = r5; | 
| +  Register last_match_info_elements = r6; | 
| + | 
| +  // 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(r0, Operand(address_of_regexp_stack_memory_size)); | 
| +  __ ldr(r0, MemOperand(r0, 0)); | 
| +  __ tst(r0, Operand(r0)); | 
| +  __ b(eq, &runtime); | 
| + | 
| +  // Check that the first argument is a JSRegExp object. | 
| +  __ ldr(r0, MemOperand(sp, kJSRegExpOffset)); | 
| +  ASSERT_EQ(0, kSmiTag); | 
| +  __ tst(r0, Operand(kSmiTagMask)); | 
| +  __ b(eq, &runtime); | 
| +  __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); | 
| +  __ b(ne, &runtime); | 
| + | 
| +  // Check that the RegExp has been compiled (data contains a fixed array). | 
| +  __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); | 
| +  if (FLAG_debug_code) { | 
| +    __ tst(regexp_data, Operand(kSmiTagMask)); | 
| +    __ Check(nz, "Unexpected type for RegExp data, FixedArray expected"); | 
| +    __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); | 
| +    __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); | 
| +  } | 
| + | 
| +  // regexp_data: RegExp data (FixedArray) | 
| +  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 
| +  __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); | 
| +  __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); | 
| +  __ b(ne, &runtime); | 
| + | 
| +  // regexp_data: RegExp data (FixedArray) | 
| +  // Check that the number of captures fit in the static offsets vector buffer. | 
| +  __ ldr(r2, | 
| +         FieldMemOperand(regexp_data, 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(r2, r2, Operand(2));  // r2 was a smi. | 
| +  // Check that the static offsets vector buffer is large enough. | 
| +  __ cmp(r2, Operand(OffsetsVector::kStaticOffsetsVectorSize)); | 
| +  __ b(hi, &runtime); | 
| + | 
| +  // r2: Number of capture registers | 
| +  // regexp_data: RegExp data (FixedArray) | 
| +  // Check that the second argument is a string. | 
| +  __ ldr(subject, MemOperand(sp, kSubjectOffset)); | 
| +  __ tst(subject, Operand(kSmiTagMask)); | 
| +  __ b(eq, &runtime); | 
| +  Condition is_string = masm->IsObjectStringType(subject, r0); | 
| +  __ b(NegateCondition(is_string), &runtime); | 
| +  // Get the length of the string to r3. | 
| +  __ ldr(r3, FieldMemOperand(subject, String::kLengthOffset)); | 
| + | 
| +  // r2: Number of capture registers | 
| +  // r3: Length of subject string | 
| +  // subject: Subject string | 
| +  // regexp_data: RegExp data (FixedArray) | 
| +  // Check that the third argument is a positive smi less than the subject | 
| +  // string length. A negative value will be greater (unsigned comparison). | 
| +  __ ldr(r0, MemOperand(sp, kPreviousIndexOffset)); | 
| +  __ cmp(r3, Operand(r0, ASR, kSmiTagSize + kSmiShiftSize)); | 
| +  __ b(ls, &runtime); | 
| + | 
| +  // r2: Number of capture registers | 
| +  // subject: Subject string | 
| +  // regexp_data: RegExp data (FixedArray) | 
| +  // Check that the fourth object is a JSArray object. | 
| +  __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset)); | 
| +  __ tst(r0, Operand(kSmiTagMask)); | 
| +  __ b(eq, &runtime); | 
| +  __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); | 
| +  __ b(ne, &runtime); | 
| +  // Check that the JSArray is in fast case. | 
| +  __ ldr(last_match_info_elements, | 
| +         FieldMemOperand(r0, JSArray::kElementsOffset)); | 
| +  __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); | 
| +  __ cmp(r0, Operand(Factory::fixed_array_map())); | 
| +  __ b(ne, &runtime); | 
| +  // Check that the last match info has space for the capture registers and the | 
| +  // additional information. | 
| +  __ ldr(r0, | 
| +         FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); | 
| +  __ add(r2, r2, Operand(RegExpImpl::kLastMatchOverhead)); | 
| +  __ cmp(r2, r0); | 
| +  __ b(gt, &runtime); | 
| + | 
| +  // subject: Subject string | 
| +  // regexp_data: RegExp data (FixedArray) | 
| +  // Check the representation and encoding of the subject string. | 
| +  Label seq_string; | 
| +  const int kStringRepresentationEncodingMask = | 
| +      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; | 
| +  __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 
| +  __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | 
| +  __ and_(r1, r0, Operand(kStringRepresentationEncodingMask)); | 
| +  // First check for sequential string. | 
| +  ASSERT_EQ(0, kStringTag); | 
| +  ASSERT_EQ(0, kSeqStringTag); | 
| +  __ tst(r1, Operand(kIsNotStringMask | kStringRepresentationMask)); | 
| +  __ b(eq, &seq_string); | 
| + | 
| +  // subject: Subject string | 
| +  // regexp_data: RegExp data (FixedArray) | 
| +  // Check for flat cons string. | 
| +  // A flat cons string is a cons string where the second part is the empty | 
| +  // string. In that case the subject string is just the first part of the cons | 
| +  // string. Also in this case the first part of the cons string is known to be | 
| +  // a sequential string or an external string. | 
| +  __ and_(r0, r0, Operand(kStringRepresentationMask)); | 
| +  __ cmp(r0, Operand(kConsStringTag)); | 
| +  __ b(ne, &runtime); | 
| +  __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); | 
| +  __ LoadRoot(r1, Heap::kEmptyStringRootIndex); | 
| +  __ cmp(r0, r1); | 
| +  __ b(ne, &runtime); | 
| +  __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); | 
| +  __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 
| +  __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | 
| +  ASSERT_EQ(0, kSeqStringTag); | 
| +  __ tst(r0, Operand(kStringRepresentationMask)); | 
| +  __ b(nz, &runtime); | 
| +  __ and_(r1, r0, Operand(kStringRepresentationEncodingMask)); | 
| + | 
| +  __ bind(&seq_string); | 
| +  // r1: suject string type & kStringRepresentationEncodingMask | 
| +  // subject: Subject string | 
| +  // regexp_data: 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. | 
| +#ifdef DEBUG | 
| +  const int kSeqAsciiString = kStringTag | kSeqStringTag | kAsciiStringTag; | 
| +  const int kSeqTwoByteString = kStringTag | kSeqStringTag | kTwoByteStringTag; | 
| +  CHECK_EQ(4, kSeqAsciiString); | 
| +  CHECK_EQ(0, kSeqTwoByteString); | 
| +#endif | 
| +  // Find the code object based on the assumptions above. | 
| +  __ mov(r3, Operand(r1, ASR, 2), SetCC); | 
| +  __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); | 
| +  __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); | 
| + | 
| +  // Check that the irregexp code has been generated for the actual string | 
| +  // encoding. If it has, the field contains a code object otherwise it contains | 
| +  // the hole. | 
| +  __ CompareObjectType(r7, r0, r0, CODE_TYPE); | 
| +  __ b(ne, &runtime); | 
| + | 
| +  // r3: encoding of subject string (1 if ascii, 0 if two_byte); | 
| +  // r7: code | 
| +  // subject: Subject string | 
| +  // regexp_data: RegExp data (FixedArray) | 
| +  // Load used arguments before starting to push arguments for call to native | 
| +  // RegExp code to avoid handling changing stack height. | 
| +  __ ldr(r1, MemOperand(sp, kPreviousIndexOffset)); | 
| +  __ mov(r1, Operand(r1, ASR, kSmiTagSize)); | 
| + | 
| +  // r1: previous index | 
| +  // r3: encoding of subject string (1 if ascii, 0 if two_byte); | 
| +  // r7: code | 
| +  // subject: Subject string | 
| +  // regexp_data: RegExp data (FixedArray) | 
| +  // All checks done. Now push arguments for native regexp code. | 
| +  __ IncrementCounter(&Counters::regexp_entry_native, 1, r0, r2); | 
| + | 
| +  static const int kRegExpExecuteArguments = 7; | 
| +  __ push(lr); | 
| +  __ PrepareCallCFunction(kRegExpExecuteArguments, r0); | 
| + | 
| +  // Argument 7 (sp[8]): Indicate that this is a direct call from JavaScript. | 
| +  __ mov(r0, Operand(1)); | 
| +  __ str(r0, MemOperand(sp, 2 * kPointerSize)); | 
| + | 
| +  // Argument 6 (sp[4]): Start (high end) of backtracking stack memory area. | 
| +  __ mov(r0, Operand(address_of_regexp_stack_memory_address)); | 
| +  __ ldr(r0, MemOperand(r0, 0)); | 
| +  __ mov(r2, Operand(address_of_regexp_stack_memory_size)); | 
| +  __ ldr(r2, MemOperand(r2, 0)); | 
| +  __ add(r0, r0, Operand(r2)); | 
| +  __ str(r0, MemOperand(sp, 1 * kPointerSize)); | 
| + | 
| +  // Argument 5 (sp[0]): static offsets vector buffer. | 
| +  __ mov(r0, Operand(ExternalReference::address_of_static_offsets_vector())); | 
| +  __ str(r0, MemOperand(sp, 0 * kPointerSize)); | 
| + | 
| +  // For arguments 4 and 3 get string length, calculate start of string data and | 
| +  // calculate the shift of the index (0 for ASCII and 1 for two byte). | 
| +  __ ldr(r0, FieldMemOperand(subject, String::kLengthOffset)); | 
| +  ASSERT_EQ(SeqAsciiString::kHeaderSize, SeqTwoByteString::kHeaderSize); | 
| +  __ add(r9, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 
| +  __ eor(r3, r3, Operand(1)); | 
| +  // Argument 4 (r3): End of string data | 
| +  // Argument 3 (r2): Start of string data | 
| +  __ add(r2, r9, Operand(r1, LSL, r3)); | 
| +  __ add(r3, r9, Operand(r0, LSL, r3)); | 
| + | 
| +  // Argument 2 (r1): Previous index. | 
| +  // Already there | 
| + | 
| +  // Argument 1 (r0): Subject string. | 
| +  __ mov(r0, subject); | 
| + | 
| +  // Locate the code entry and call it. | 
| +  __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); | 
| +  __ CallCFunction(r7, kRegExpExecuteArguments); | 
| +  __ pop(lr); | 
| + | 
| +  // r0: result | 
| +  // subject: subject string (callee saved) | 
| +  // regexp_data: RegExp data (callee saved) | 
| +  // last_match_info_elements: Last match info elements (callee saved) | 
| + | 
| +  // Check the result. | 
| +  Label success; | 
| +  __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS)); | 
| +  __ b(eq, &success); | 
| +  Label failure; | 
| +  __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE)); | 
| +  __ b(eq, &failure); | 
| +  __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); | 
| +  // If not exception it can only be retry. Handle that in the runtime system. | 
| +  __ b(ne, &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. | 
| +  // TODO(592): Rerunning the RegExp to get the stack overflow exception. | 
| +  __ mov(r0, Operand(ExternalReference::the_hole_value_location())); | 
| +  __ ldr(r0, MemOperand(r0, 0)); | 
| +  __ mov(r1, Operand(ExternalReference(Top::k_pending_exception_address))); | 
| +  __ ldr(r1, MemOperand(r1, 0)); | 
| +  __ cmp(r0, r1); | 
| +  __ b(eq, &runtime); | 
| +  __ bind(&failure); | 
| +  // For failure and exception return null. | 
| +  __ mov(r0, Operand(Factory::null_value())); | 
| +  __ add(sp, sp, Operand(4 * kPointerSize)); | 
| +  __ Ret(); | 
| + | 
| +  // Process the result from the native regexp code. | 
| +  __ bind(&success); | 
| +  __ ldr(r1, | 
| +         FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | 
| +  // Calculate number of capture registers (number_of_captures + 1) * 2. | 
| +  ASSERT_EQ(0, kSmiTag); | 
| +  ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 
| +  __ add(r1, r1, Operand(2));  // r1 was a smi. | 
| + | 
| +  // r1: number of capture registers | 
| +  // r4: subject string | 
| +  // Store the capture count. | 
| +  __ mov(r2, Operand(r1, LSL, kSmiTagSize + kSmiShiftSize));  // To smi. | 
| +  __ str(r2, FieldMemOperand(last_match_info_elements, | 
| +                             RegExpImpl::kLastCaptureCountOffset)); | 
| +  // Store last subject and last input. | 
| +  __ mov(r3, last_match_info_elements);  // Moved up to reduce latency. | 
| +  __ mov(r2, Operand(RegExpImpl::kLastSubjectOffset));  // Ditto. | 
| +  __ str(subject, | 
| +         FieldMemOperand(last_match_info_elements, | 
| +                         RegExpImpl::kLastSubjectOffset)); | 
| +  __ RecordWrite(r3, r2, r7); | 
| +  __ str(subject, | 
| +         FieldMemOperand(last_match_info_elements, | 
| +                         RegExpImpl::kLastInputOffset)); | 
| +  __ mov(r3, last_match_info_elements); | 
| +  __ mov(r2, Operand(RegExpImpl::kLastInputOffset)); | 
| +  __ RecordWrite(r3, r2, r7); | 
| + | 
| +  // Get the static offsets vector filled by the native regexp code. | 
| +  ExternalReference address_of_static_offsets_vector = | 
| +      ExternalReference::address_of_static_offsets_vector(); | 
| +  __ mov(r2, Operand(address_of_static_offsets_vector)); | 
| + | 
| +  // r1: number of capture registers | 
| +  // r2: offsets vector | 
| +  Label next_capture, done; | 
| +  // Capture register counter starts from number of capture registers and | 
| +  // counts down until wraping after zero. | 
| +  __ add(r0, | 
| +         last_match_info_elements, | 
| +         Operand(RegExpImpl::kFirstCaptureOffset - kHeapObjectTag)); | 
| +  __ bind(&next_capture); | 
| +  __ sub(r1, r1, Operand(1), SetCC); | 
| +  __ b(mi, &done); | 
| +  // Read the value from the static offsets vector buffer. | 
| +  __ ldr(r3, MemOperand(r2, kPointerSize, PostIndex)); | 
| +  // Store the smi value in the last match info. | 
| +  __ mov(r3, Operand(r3, LSL, kSmiTagSize)); | 
| +  __ str(r3, MemOperand(r0, kPointerSize, PostIndex)); | 
| +  __ jmp(&next_capture); | 
| +  __ bind(&done); | 
| + | 
| +  // Return last match info. | 
| +  __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset)); | 
| +  __ add(sp, sp, Operand(4 * kPointerSize)); | 
| +  __ Ret(); | 
| + | 
| +  // Do the runtime call to execute the regexp. | 
| +  __ bind(&runtime); | 
| +  __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 
| +#endif  // V8_NATIVE_REGEXP | 
| +} | 
| + | 
| + | 
| void CallFunctionStub::Generate(MacroAssembler* masm) { | 
| Label slow; | 
|  | 
|  |