| Index: src/jsregexp.cc
|
| diff --git a/src/jsregexp.cc b/src/jsregexp.cc
|
| index ae25432a587d19b9adb1c0d9f9bdc206ed161bda..e730e145a4e41627512b75fb68fefa68cfe5f189 100644
|
| --- a/src/jsregexp.cc
|
| +++ b/src/jsregexp.cc
|
| @@ -278,12 +278,11 @@ static void SetAtomLastCapture(FixedArray* array,
|
| }
|
|
|
|
|
| -int RegExpImpl::AtomExecRaw(Handle<JSRegExp> regexp,
|
| - Handle<String> subject,
|
| - int index,
|
| - int32_t* output,
|
| - int output_size) {
|
| - Isolate* isolate = regexp->GetIsolate();
|
| +Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
|
| + Handle<String> subject,
|
| + int index,
|
| + Handle<JSArray> last_match_info) {
|
| + Isolate* isolate = re->GetIsolate();
|
|
|
| ASSERT(0 <= index);
|
| ASSERT(index <= subject->length());
|
| @@ -291,16 +290,15 @@ int RegExpImpl::AtomExecRaw(Handle<JSRegExp> regexp,
|
| if (!subject->IsFlat()) FlattenString(subject);
|
| AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
|
|
|
| - String* needle = String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex));
|
| + String* needle = String::cast(re->DataAt(JSRegExp::kAtomPatternIndex));
|
| int needle_len = needle->length();
|
| ASSERT(needle->IsFlat());
|
| - ASSERT_LT(0, needle_len);
|
|
|
| - if (index + needle_len > subject->length()) {
|
| - return RegExpImpl::RE_FAILURE;
|
| - }
|
| + if (needle_len != 0) {
|
| + if (index + needle_len > subject->length()) {
|
| + return isolate->factory()->null_value();
|
| + }
|
|
|
| - for (int i = 0; i < output_size; i += 2) {
|
| String::FlatContent needle_content = needle->GetFlatContent();
|
| String::FlatContent subject_content = subject->GetFlatContent();
|
| ASSERT(needle_content.IsFlat());
|
| @@ -325,36 +323,15 @@ int RegExpImpl::AtomExecRaw(Handle<JSRegExp> regexp,
|
| subject_content.ToUC16Vector(),
|
| needle_content.ToUC16Vector(),
|
| index)));
|
| - if (index == -1) {
|
| - return i / 2; // Return number of matches.
|
| - } else {
|
| - output[i] = index;
|
| - output[i+1] = index + needle_len;
|
| - index += needle_len;
|
| - }
|
| + if (index == -1) return isolate->factory()->null_value();
|
| }
|
| - return output_size / 2;
|
| -}
|
| + ASSERT(last_match_info->HasFastObjectElements());
|
|
|
| -
|
| -Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
|
| - Handle<String> subject,
|
| - int index,
|
| - Handle<JSArray> last_match_info) {
|
| - Isolate* isolate = re->GetIsolate();
|
| -
|
| - static const int kNumRegisters = 2;
|
| - STATIC_ASSERT(kNumRegisters <= Isolate::kJSRegexpStaticOffsetsVectorSize);
|
| - int32_t* output_registers = isolate->jsregexp_static_offsets_vector();
|
| -
|
| - int res = AtomExecRaw(re, subject, index, output_registers, kNumRegisters);
|
| -
|
| - if (res == RegExpImpl::RE_FAILURE) return isolate->factory()->null_value();
|
| -
|
| - ASSERT_EQ(res, RegExpImpl::RE_SUCCESS);
|
| - NoHandleAllocation no_handles;
|
| - FixedArray* array = FixedArray::cast(last_match_info->elements());
|
| - SetAtomLastCapture(array, *subject, output_registers[0], output_registers[1]);
|
| + {
|
| + NoHandleAllocation no_handles;
|
| + FixedArray* array = FixedArray::cast(last_match_info->elements());
|
| + SetAtomLastCapture(array, *subject, index, index + needle_len);
|
| + }
|
| return last_match_info;
|
| }
|
|
|
| @@ -534,11 +511,7 @@ int RegExpImpl::IrregexpPrepare(Handle<JSRegExp> regexp,
|
|
|
| #ifdef V8_INTERPRETED_REGEXP
|
| // Byte-code regexp needs space allocated for all its registers.
|
| - // The result captures are copied to the start of the registers array
|
| - // if the match succeeds. This way those registers are not clobbered
|
| - // when we set the last match info from last successful match.
|
| - return IrregexpNumberOfRegisters(FixedArray::cast(regexp->data())) +
|
| - (IrregexpNumberOfCaptures(FixedArray::cast(regexp->data())) + 1) * 2;
|
| + return IrregexpNumberOfRegisters(FixedArray::cast(regexp->data()));
|
| #else // V8_INTERPRETED_REGEXP
|
| // Native regexp only needs room to output captures. Registers are handled
|
| // internally.
|
| @@ -547,11 +520,27 @@ int RegExpImpl::IrregexpPrepare(Handle<JSRegExp> regexp,
|
| }
|
|
|
|
|
| -int RegExpImpl::IrregexpExecRaw(Handle<JSRegExp> regexp,
|
| - Handle<String> subject,
|
| - int index,
|
| - int32_t* output,
|
| - int output_size) {
|
| +int RegExpImpl::GlobalOffsetsVectorSize(Handle<JSRegExp> regexp,
|
| + int registers_per_match,
|
| + int* max_matches) {
|
| +#ifdef V8_INTERPRETED_REGEXP
|
| + // Global loop in interpreted regexp is not implemented. Therefore we choose
|
| + // the size of the offsets vector so that it can only store one match.
|
| + *max_matches = 1;
|
| + return registers_per_match;
|
| +#else // V8_INTERPRETED_REGEXP
|
| + int size = Max(registers_per_match, OffsetsVector::kStaticOffsetsVectorSize);
|
| + *max_matches = size / registers_per_match;
|
| + return size;
|
| +#endif // V8_INTERPRETED_REGEXP
|
| +}
|
| +
|
| +
|
| +int RegExpImpl::IrregexpExecRaw(
|
| + Handle<JSRegExp> regexp,
|
| + Handle<String> subject,
|
| + int index,
|
| + Vector<int> output) {
|
| Isolate* isolate = regexp->GetIsolate();
|
|
|
| Handle<FixedArray> irregexp(FixedArray::cast(regexp->data()), isolate);
|
| @@ -563,19 +552,15 @@ int RegExpImpl::IrregexpExecRaw(Handle<JSRegExp> regexp,
|
| bool is_ascii = subject->IsAsciiRepresentationUnderneath();
|
|
|
| #ifndef V8_INTERPRETED_REGEXP
|
| - ASSERT(output_size >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2);
|
| + ASSERT(output.length() >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2);
|
| do {
|
| EnsureCompiledIrregexp(regexp, subject, is_ascii);
|
| Handle<Code> code(IrregexpNativeCode(*irregexp, is_ascii), isolate);
|
| - // The stack is used to allocate registers for the compiled regexp code.
|
| - // This means that in case of failure, the output registers array is left
|
| - // untouched and contains the capture results from the previous successful
|
| - // match. We can use that to set the last match info lazily.
|
| NativeRegExpMacroAssembler::Result res =
|
| NativeRegExpMacroAssembler::Match(code,
|
| subject,
|
| - output,
|
| - output_size,
|
| + output.start(),
|
| + output.length(),
|
| index,
|
| isolate);
|
| if (res != NativeRegExpMacroAssembler::RETRY) {
|
| @@ -602,29 +587,22 @@ int RegExpImpl::IrregexpExecRaw(Handle<JSRegExp> regexp,
|
| return RE_EXCEPTION;
|
| #else // V8_INTERPRETED_REGEXP
|
|
|
| - ASSERT(output_size >= IrregexpNumberOfRegisters(*irregexp));
|
| + ASSERT(output.length() >= IrregexpNumberOfRegisters(*irregexp));
|
| // We must have done EnsureCompiledIrregexp, so we can get the number of
|
| // registers.
|
| + int* register_vector = output.start();
|
| int number_of_capture_registers =
|
| (IrregexpNumberOfCaptures(*irregexp) + 1) * 2;
|
| - int32_t* raw_output = &output[number_of_capture_registers];
|
| - // We do not touch the actual capture result registers until we know there
|
| - // has been a match so that we can use those capture results to set the
|
| - // last match info.
|
| for (int i = number_of_capture_registers - 1; i >= 0; i--) {
|
| - raw_output[i] = -1;
|
| + register_vector[i] = -1;
|
| }
|
| Handle<ByteArray> byte_codes(IrregexpByteCode(*irregexp, is_ascii), isolate);
|
|
|
| IrregexpResult result = IrregexpInterpreter::Match(isolate,
|
| byte_codes,
|
| subject,
|
| - raw_output,
|
| + register_vector,
|
| index);
|
| - if (result == RE_SUCCESS) {
|
| - // Copy capture results to the start of the registers array.
|
| - memcpy(output, raw_output, number_of_capture_registers * sizeof(int32_t));
|
| - }
|
| if (result == RE_EXCEPTION) {
|
| ASSERT(!isolate->has_pending_exception());
|
| isolate->StackOverflow();
|
| @@ -634,44 +612,50 @@ int RegExpImpl::IrregexpExecRaw(Handle<JSRegExp> regexp,
|
| }
|
|
|
|
|
| -Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> regexp,
|
| +Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
|
| Handle<String> subject,
|
| int previous_index,
|
| Handle<JSArray> last_match_info) {
|
| - Isolate* isolate = regexp->GetIsolate();
|
| - ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
|
| + Isolate* isolate = jsregexp->GetIsolate();
|
| + ASSERT_EQ(jsregexp->TypeTag(), JSRegExp::IRREGEXP);
|
|
|
| // Prepare space for the return values.
|
| -#if defined(V8_INTERPRETED_REGEXP) && defined(DEBUG)
|
| +#ifdef V8_INTERPRETED_REGEXP
|
| +#ifdef DEBUG
|
| if (FLAG_trace_regexp_bytecodes) {
|
| - String* pattern = regexp->Pattern();
|
| + String* pattern = jsregexp->Pattern();
|
| PrintF("\n\nRegexp match: /%s/\n\n", *(pattern->ToCString()));
|
| PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString()));
|
| }
|
| #endif
|
| - int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
|
| +#endif
|
| + int required_registers = RegExpImpl::IrregexpPrepare(jsregexp, subject);
|
| if (required_registers < 0) {
|
| // Compiling failed with an exception.
|
| ASSERT(isolate->has_pending_exception());
|
| return Handle<Object>::null();
|
| }
|
|
|
| - int32_t* output_registers = NULL;
|
| - if (required_registers > Isolate::kJSRegexpStaticOffsetsVectorSize) {
|
| - output_registers = NewArray<int32_t>(required_registers);
|
| - }
|
| - SmartArrayPointer<int32_t> auto_release(output_registers);
|
| - if (output_registers == NULL) {
|
| - output_registers = isolate->jsregexp_static_offsets_vector();
|
| - }
|
| + OffsetsVector registers(required_registers, isolate);
|
|
|
| - int res = RegExpImpl::IrregexpExecRaw(
|
| - regexp, subject, previous_index, output_registers, required_registers);
|
| + int res = RegExpImpl::IrregexpExecRaw(jsregexp, subject, previous_index,
|
| + Vector<int>(registers.vector(),
|
| + registers.length()));
|
| if (res == RE_SUCCESS) {
|
| - int capture_count =
|
| - IrregexpNumberOfCaptures(FixedArray::cast(regexp->data()));
|
| - return SetLastMatchInfo(
|
| - last_match_info, subject, capture_count, output_registers);
|
| + int capture_register_count =
|
| + (IrregexpNumberOfCaptures(FixedArray::cast(jsregexp->data())) + 1) * 2;
|
| + last_match_info->EnsureSize(capture_register_count + kLastMatchOverhead);
|
| + AssertNoAllocation no_gc;
|
| + int* register_vector = registers.vector();
|
| + FixedArray* array = FixedArray::cast(last_match_info->elements());
|
| + for (int i = 0; i < capture_register_count; i += 2) {
|
| + SetCapture(array, i, register_vector[i]);
|
| + SetCapture(array, i + 1, register_vector[i + 1]);
|
| + }
|
| + SetLastCaptureCount(array, capture_register_count);
|
| + SetLastSubject(array, *subject);
|
| + SetLastInput(array, *subject);
|
| + return last_match_info;
|
| }
|
| if (res == RE_EXCEPTION) {
|
| ASSERT(isolate->has_pending_exception());
|
| @@ -682,145 +666,6 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> regexp,
|
| }
|
|
|
|
|
| -Handle<JSArray> RegExpImpl::SetLastMatchInfo(Handle<JSArray> last_match_info,
|
| - Handle<String> subject,
|
| - int capture_count,
|
| - int32_t* match) {
|
| - int capture_register_count = (capture_count + 1) * 2;
|
| - last_match_info->EnsureSize(capture_register_count + kLastMatchOverhead);
|
| - AssertNoAllocation no_gc;
|
| - FixedArray* array = FixedArray::cast(last_match_info->elements());
|
| - if (match != NULL) {
|
| - for (int i = 0; i < capture_register_count; i += 2) {
|
| - SetCapture(array, i, match[i]);
|
| - SetCapture(array, i + 1, match[i + 1]);
|
| - }
|
| - }
|
| - SetLastCaptureCount(array, capture_register_count);
|
| - SetLastSubject(array, *subject);
|
| - SetLastInput(array, *subject);
|
| - return last_match_info;
|
| -}
|
| -
|
| -
|
| -RegExpImpl::GlobalCache::GlobalCache(Handle<JSRegExp> regexp,
|
| - Handle<String> subject,
|
| - bool is_global,
|
| - Isolate* isolate) {
|
| -#ifdef V8_INTERPRETED_REGEXP
|
| - bool interpreted = true;
|
| -#else
|
| - bool interpreted = false;
|
| -#endif // V8_INTERPRETED_REGEXP
|
| -
|
| - regexp_ = regexp;
|
| - subject_ = subject;
|
| -
|
| - if (regexp_->TypeTag() == JSRegExp::ATOM) {
|
| - static const int kAtomRegistersPerMatch = 2;
|
| - registers_per_match_ = kAtomRegistersPerMatch;
|
| - // There is no distinction between interpreted and native for atom regexps.
|
| - interpreted = false;
|
| - } else {
|
| - registers_per_match_ = RegExpImpl::IrregexpPrepare(regexp_, subject_);
|
| - if (registers_per_match_ < 0) {
|
| - num_matches_ = -1; // Signal exception.
|
| - return;
|
| - }
|
| - }
|
| -
|
| - if (is_global && !interpreted) {
|
| - register_array_size_ =
|
| - Max(registers_per_match_, Isolate::kJSRegexpStaticOffsetsVectorSize);
|
| - max_matches_ = register_array_size_ / registers_per_match_;
|
| - } else {
|
| - // Global loop in interpreted regexp is not implemented. We choose
|
| - // the size of the offsets vector so that it can only store one match.
|
| - register_array_size_ = registers_per_match_;
|
| - max_matches_ = 1;
|
| - }
|
| -
|
| - if (register_array_size_ > Isolate::kJSRegexpStaticOffsetsVectorSize) {
|
| - register_array_ = NewArray<int32_t>(register_array_size_);
|
| - } else {
|
| - register_array_ = isolate->jsregexp_static_offsets_vector();
|
| - }
|
| -
|
| - // Set state so that fetching the results the first time triggers a call
|
| - // to the compiled regexp.
|
| - current_match_index_ = max_matches_ - 1;
|
| - num_matches_ = max_matches_;
|
| - ASSERT(registers_per_match_ >= 2); // Each match has at least one capture.
|
| - ASSERT_GE(register_array_size_, registers_per_match_);
|
| - int32_t* last_match =
|
| - ®ister_array_[current_match_index_ * registers_per_match_];
|
| - last_match[0] = -1;
|
| - last_match[1] = 0;
|
| -}
|
| -
|
| -
|
| -RegExpImpl::GlobalCache::~GlobalCache() {
|
| - // Deallocate the register array if we allocated it in the constructor
|
| - // (as opposed to using the existing jsregexp_static_offsets_vector).
|
| - if (register_array_size_ > Isolate::kJSRegexpStaticOffsetsVectorSize) {
|
| - DeleteArray(register_array_);
|
| - }
|
| -}
|
| -
|
| -
|
| -int32_t* RegExpImpl::GlobalCache::FetchNext() {
|
| - current_match_index_++;
|
| - if (current_match_index_ >= num_matches_) {
|
| - // Current batch of results exhausted.
|
| - // Fail if last batch was not even fully filled.
|
| - if (num_matches_ < max_matches_) {
|
| - num_matches_ = 0; // Signal failed match.
|
| - return NULL;
|
| - }
|
| -
|
| - int32_t* last_match =
|
| - ®ister_array_[(current_match_index_ - 1) * registers_per_match_];
|
| - int last_end_index = last_match[1];
|
| -
|
| - if (regexp_->TypeTag() == JSRegExp::ATOM) {
|
| - num_matches_ = RegExpImpl::AtomExecRaw(regexp_,
|
| - subject_,
|
| - last_end_index,
|
| - register_array_,
|
| - register_array_size_);
|
| - } else {
|
| - int last_start_index = last_match[0];
|
| - if (last_start_index == last_end_index) last_end_index++;
|
| - if (last_end_index > subject_->length()) {
|
| - num_matches_ = 0; // Signal failed match.
|
| - return NULL;
|
| - }
|
| - num_matches_ = RegExpImpl::IrregexpExecRaw(regexp_,
|
| - subject_,
|
| - last_end_index,
|
| - register_array_,
|
| - register_array_size_);
|
| - }
|
| -
|
| - if (num_matches_ <= 0) return NULL;
|
| - current_match_index_ = 0;
|
| - return register_array_;
|
| - } else {
|
| - return ®ister_array_[current_match_index_ * registers_per_match_];
|
| - }
|
| -}
|
| -
|
| -
|
| -int32_t* RegExpImpl::GlobalCache::LastSuccessfulMatch() {
|
| - int index = current_match_index_ * registers_per_match_;
|
| - if (num_matches_ == 0) {
|
| - // After a failed match we shift back by one result.
|
| - index -= registers_per_match_;
|
| - }
|
| - return ®ister_array_[index];
|
| -}
|
| -
|
| -
|
| // -------------------------------------------------------------------
|
| // Implementation of the Irregexp regular expression engine.
|
| //
|
|
|