| 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 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/ast.h" | 7 #include "src/ast.h" |
| 8 #include "src/base/platform/platform.h" | 8 #include "src/base/platform/platform.h" |
| 9 #include "src/compilation-cache.h" | 9 #include "src/compilation-cache.h" |
| 10 #include "src/compiler.h" | 10 #include "src/compiler.h" |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 Handle<JSArray> array = factory->NewJSArrayWithElements(elements); | 90 Handle<JSArray> array = factory->NewJSArrayWithElements(elements); |
| 91 Handle<Object> regexp_err = factory->NewSyntaxError(message, array); | 91 Handle<Object> regexp_err = factory->NewSyntaxError(message, array); |
| 92 return isolate->Throw<Object>(regexp_err); | 92 return isolate->Throw<Object>(regexp_err); |
| 93 } | 93 } |
| 94 | 94 |
| 95 | 95 |
| 96 ContainedInLattice AddRange(ContainedInLattice containment, | 96 ContainedInLattice AddRange(ContainedInLattice containment, |
| 97 const int* ranges, | 97 const int* ranges, |
| 98 int ranges_length, | 98 int ranges_length, |
| 99 Interval new_range) { | 99 Interval new_range) { |
| 100 ASSERT((ranges_length & 1) == 1); | 100 DCHECK((ranges_length & 1) == 1); |
| 101 ASSERT(ranges[ranges_length - 1] == String::kMaxUtf16CodeUnit + 1); | 101 DCHECK(ranges[ranges_length - 1] == String::kMaxUtf16CodeUnit + 1); |
| 102 if (containment == kLatticeUnknown) return containment; | 102 if (containment == kLatticeUnknown) return containment; |
| 103 bool inside = false; | 103 bool inside = false; |
| 104 int last = 0; | 104 int last = 0; |
| 105 for (int i = 0; i < ranges_length; inside = !inside, last = ranges[i], i++) { | 105 for (int i = 0; i < ranges_length; inside = !inside, last = ranges[i], i++) { |
| 106 // Consider the range from last to ranges[i]. | 106 // Consider the range from last to ranges[i]. |
| 107 // We haven't got to the new range yet. | 107 // We haven't got to the new range yet. |
| 108 if (ranges[i] <= new_range.from()) continue; | 108 if (ranges[i] <= new_range.from()) continue; |
| 109 // New range is wholly inside last-ranges[i]. Note that new_range.to() is | 109 // New range is wholly inside last-ranges[i]. Note that new_range.to() is |
| 110 // inclusive, but the values in ranges are not. | 110 // inclusive, but the values in ranges are not. |
| 111 if (last <= new_range.from() && new_range.to() < ranges[i]) { | 111 if (last <= new_range.from() && new_range.to() < ranges[i]) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 isolate->factory()->NewStringFromTwoByte(atom_pattern), | 200 isolate->factory()->NewStringFromTwoByte(atom_pattern), |
| 201 Object); | 201 Object); |
| 202 if (!HasFewDifferentCharacters(atom_string)) { | 202 if (!HasFewDifferentCharacters(atom_string)) { |
| 203 AtomCompile(re, pattern, flags, atom_string); | 203 AtomCompile(re, pattern, flags, atom_string); |
| 204 has_been_compiled = true; | 204 has_been_compiled = true; |
| 205 } | 205 } |
| 206 } | 206 } |
| 207 if (!has_been_compiled) { | 207 if (!has_been_compiled) { |
| 208 IrregexpInitialize(re, pattern, flags, parse_result.capture_count); | 208 IrregexpInitialize(re, pattern, flags, parse_result.capture_count); |
| 209 } | 209 } |
| 210 ASSERT(re->data()->IsFixedArray()); | 210 DCHECK(re->data()->IsFixedArray()); |
| 211 // Compilation succeeded so the data is set on the regexp | 211 // Compilation succeeded so the data is set on the regexp |
| 212 // and we can store it in the cache. | 212 // and we can store it in the cache. |
| 213 Handle<FixedArray> data(FixedArray::cast(re->data())); | 213 Handle<FixedArray> data(FixedArray::cast(re->data())); |
| 214 compilation_cache->PutRegExp(pattern, flags, data); | 214 compilation_cache->PutRegExp(pattern, flags, data); |
| 215 | 215 |
| 216 return re; | 216 return re; |
| 217 } | 217 } |
| 218 | 218 |
| 219 | 219 |
| 220 MaybeHandle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, | 220 MaybeHandle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 } | 262 } |
| 263 | 263 |
| 264 | 264 |
| 265 int RegExpImpl::AtomExecRaw(Handle<JSRegExp> regexp, | 265 int RegExpImpl::AtomExecRaw(Handle<JSRegExp> regexp, |
| 266 Handle<String> subject, | 266 Handle<String> subject, |
| 267 int index, | 267 int index, |
| 268 int32_t* output, | 268 int32_t* output, |
| 269 int output_size) { | 269 int output_size) { |
| 270 Isolate* isolate = regexp->GetIsolate(); | 270 Isolate* isolate = regexp->GetIsolate(); |
| 271 | 271 |
| 272 ASSERT(0 <= index); | 272 DCHECK(0 <= index); |
| 273 ASSERT(index <= subject->length()); | 273 DCHECK(index <= subject->length()); |
| 274 | 274 |
| 275 subject = String::Flatten(subject); | 275 subject = String::Flatten(subject); |
| 276 DisallowHeapAllocation no_gc; // ensure vectors stay valid | 276 DisallowHeapAllocation no_gc; // ensure vectors stay valid |
| 277 | 277 |
| 278 String* needle = String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)); | 278 String* needle = String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)); |
| 279 int needle_len = needle->length(); | 279 int needle_len = needle->length(); |
| 280 ASSERT(needle->IsFlat()); | 280 DCHECK(needle->IsFlat()); |
| 281 ASSERT_LT(0, needle_len); | 281 DCHECK_LT(0, needle_len); |
| 282 | 282 |
| 283 if (index + needle_len > subject->length()) { | 283 if (index + needle_len > subject->length()) { |
| 284 return RegExpImpl::RE_FAILURE; | 284 return RegExpImpl::RE_FAILURE; |
| 285 } | 285 } |
| 286 | 286 |
| 287 for (int i = 0; i < output_size; i += 2) { | 287 for (int i = 0; i < output_size; i += 2) { |
| 288 String::FlatContent needle_content = needle->GetFlatContent(); | 288 String::FlatContent needle_content = needle->GetFlatContent(); |
| 289 String::FlatContent subject_content = subject->GetFlatContent(); | 289 String::FlatContent subject_content = subject->GetFlatContent(); |
| 290 ASSERT(needle_content.IsFlat()); | 290 DCHECK(needle_content.IsFlat()); |
| 291 ASSERT(subject_content.IsFlat()); | 291 DCHECK(subject_content.IsFlat()); |
| 292 // dispatch on type of strings | 292 // dispatch on type of strings |
| 293 index = (needle_content.IsAscii() | 293 index = (needle_content.IsAscii() |
| 294 ? (subject_content.IsAscii() | 294 ? (subject_content.IsAscii() |
| 295 ? SearchString(isolate, | 295 ? SearchString(isolate, |
| 296 subject_content.ToOneByteVector(), | 296 subject_content.ToOneByteVector(), |
| 297 needle_content.ToOneByteVector(), | 297 needle_content.ToOneByteVector(), |
| 298 index) | 298 index) |
| 299 : SearchString(isolate, | 299 : SearchString(isolate, |
| 300 subject_content.ToUC16Vector(), | 300 subject_content.ToUC16Vector(), |
| 301 needle_content.ToOneByteVector(), | 301 needle_content.ToOneByteVector(), |
| (...skipping 26 matching lines...) Expand all Loading... |
| 328 Isolate* isolate = re->GetIsolate(); | 328 Isolate* isolate = re->GetIsolate(); |
| 329 | 329 |
| 330 static const int kNumRegisters = 2; | 330 static const int kNumRegisters = 2; |
| 331 STATIC_ASSERT(kNumRegisters <= Isolate::kJSRegexpStaticOffsetsVectorSize); | 331 STATIC_ASSERT(kNumRegisters <= Isolate::kJSRegexpStaticOffsetsVectorSize); |
| 332 int32_t* output_registers = isolate->jsregexp_static_offsets_vector(); | 332 int32_t* output_registers = isolate->jsregexp_static_offsets_vector(); |
| 333 | 333 |
| 334 int res = AtomExecRaw(re, subject, index, output_registers, kNumRegisters); | 334 int res = AtomExecRaw(re, subject, index, output_registers, kNumRegisters); |
| 335 | 335 |
| 336 if (res == RegExpImpl::RE_FAILURE) return isolate->factory()->null_value(); | 336 if (res == RegExpImpl::RE_FAILURE) return isolate->factory()->null_value(); |
| 337 | 337 |
| 338 ASSERT_EQ(res, RegExpImpl::RE_SUCCESS); | 338 DCHECK_EQ(res, RegExpImpl::RE_SUCCESS); |
| 339 SealHandleScope shs(isolate); | 339 SealHandleScope shs(isolate); |
| 340 FixedArray* array = FixedArray::cast(last_match_info->elements()); | 340 FixedArray* array = FixedArray::cast(last_match_info->elements()); |
| 341 SetAtomLastCapture(array, *subject, output_registers[0], output_registers[1]); | 341 SetAtomLastCapture(array, *subject, output_registers[0], output_registers[1]); |
| 342 return last_match_info; | 342 return last_match_info; |
| 343 } | 343 } |
| 344 | 344 |
| 345 | 345 |
| 346 // Irregexp implementation. | 346 // Irregexp implementation. |
| 347 | 347 |
| 348 // Ensures that the regexp object contains a compiled version of the | 348 // Ensures that the regexp object contains a compiled version of the |
| 349 // source for either ASCII or non-ASCII strings. | 349 // source for either ASCII or non-ASCII strings. |
| 350 // If the compiled version doesn't already exist, it is compiled | 350 // If the compiled version doesn't already exist, it is compiled |
| 351 // from the source pattern. | 351 // from the source pattern. |
| 352 // If compilation fails, an exception is thrown and this function | 352 // If compilation fails, an exception is thrown and this function |
| 353 // returns false. | 353 // returns false. |
| 354 bool RegExpImpl::EnsureCompiledIrregexp( | 354 bool RegExpImpl::EnsureCompiledIrregexp( |
| 355 Handle<JSRegExp> re, Handle<String> sample_subject, bool is_ascii) { | 355 Handle<JSRegExp> re, Handle<String> sample_subject, bool is_ascii) { |
| 356 Object* compiled_code = re->DataAt(JSRegExp::code_index(is_ascii)); | 356 Object* compiled_code = re->DataAt(JSRegExp::code_index(is_ascii)); |
| 357 #ifdef V8_INTERPRETED_REGEXP | 357 #ifdef V8_INTERPRETED_REGEXP |
| 358 if (compiled_code->IsByteArray()) return true; | 358 if (compiled_code->IsByteArray()) return true; |
| 359 #else // V8_INTERPRETED_REGEXP (RegExp native code) | 359 #else // V8_INTERPRETED_REGEXP (RegExp native code) |
| 360 if (compiled_code->IsCode()) return true; | 360 if (compiled_code->IsCode()) return true; |
| 361 #endif | 361 #endif |
| 362 // We could potentially have marked this as flushable, but have kept | 362 // We could potentially have marked this as flushable, but have kept |
| 363 // a saved version if we did not flush it yet. | 363 // a saved version if we did not flush it yet. |
| 364 Object* saved_code = re->DataAt(JSRegExp::saved_code_index(is_ascii)); | 364 Object* saved_code = re->DataAt(JSRegExp::saved_code_index(is_ascii)); |
| 365 if (saved_code->IsCode()) { | 365 if (saved_code->IsCode()) { |
| 366 // Reinstate the code in the original place. | 366 // Reinstate the code in the original place. |
| 367 re->SetDataAt(JSRegExp::code_index(is_ascii), saved_code); | 367 re->SetDataAt(JSRegExp::code_index(is_ascii), saved_code); |
| 368 ASSERT(compiled_code->IsSmi()); | 368 DCHECK(compiled_code->IsSmi()); |
| 369 return true; | 369 return true; |
| 370 } | 370 } |
| 371 return CompileIrregexp(re, sample_subject, is_ascii); | 371 return CompileIrregexp(re, sample_subject, is_ascii); |
| 372 } | 372 } |
| 373 | 373 |
| 374 | 374 |
| 375 static bool CreateRegExpErrorObjectAndThrow(Handle<JSRegExp> re, | 375 static bool CreateRegExpErrorObjectAndThrow(Handle<JSRegExp> re, |
| 376 bool is_ascii, | 376 bool is_ascii, |
| 377 Handle<String> error_message, | 377 Handle<String> error_message, |
| 378 Isolate* isolate) { | 378 Isolate* isolate) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 394 // Compile the RegExp. | 394 // Compile the RegExp. |
| 395 Isolate* isolate = re->GetIsolate(); | 395 Isolate* isolate = re->GetIsolate(); |
| 396 Zone zone(isolate); | 396 Zone zone(isolate); |
| 397 PostponeInterruptsScope postpone(isolate); | 397 PostponeInterruptsScope postpone(isolate); |
| 398 // If we had a compilation error the last time this is saved at the | 398 // If we had a compilation error the last time this is saved at the |
| 399 // saved code index. | 399 // saved code index. |
| 400 Object* entry = re->DataAt(JSRegExp::code_index(is_ascii)); | 400 Object* entry = re->DataAt(JSRegExp::code_index(is_ascii)); |
| 401 // When arriving here entry can only be a smi, either representing an | 401 // When arriving here entry can only be a smi, either representing an |
| 402 // uncompiled regexp, a previous compilation error, or code that has | 402 // uncompiled regexp, a previous compilation error, or code that has |
| 403 // been flushed. | 403 // been flushed. |
| 404 ASSERT(entry->IsSmi()); | 404 DCHECK(entry->IsSmi()); |
| 405 int entry_value = Smi::cast(entry)->value(); | 405 int entry_value = Smi::cast(entry)->value(); |
| 406 ASSERT(entry_value == JSRegExp::kUninitializedValue || | 406 DCHECK(entry_value == JSRegExp::kUninitializedValue || |
| 407 entry_value == JSRegExp::kCompilationErrorValue || | 407 entry_value == JSRegExp::kCompilationErrorValue || |
| 408 (entry_value < JSRegExp::kCodeAgeMask && entry_value >= 0)); | 408 (entry_value < JSRegExp::kCodeAgeMask && entry_value >= 0)); |
| 409 | 409 |
| 410 if (entry_value == JSRegExp::kCompilationErrorValue) { | 410 if (entry_value == JSRegExp::kCompilationErrorValue) { |
| 411 // A previous compilation failed and threw an error which we store in | 411 // A previous compilation failed and threw an error which we store in |
| 412 // the saved code index (we store the error message, not the actual | 412 // the saved code index (we store the error message, not the actual |
| 413 // error). Recreate the error object and throw it. | 413 // error). Recreate the error object and throw it. |
| 414 Object* error_string = re->DataAt(JSRegExp::saved_code_index(is_ascii)); | 414 Object* error_string = re->DataAt(JSRegExp::saved_code_index(is_ascii)); |
| 415 ASSERT(error_string->IsString()); | 415 DCHECK(error_string->IsString()); |
| 416 Handle<String> error_message(String::cast(error_string)); | 416 Handle<String> error_message(String::cast(error_string)); |
| 417 CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate); | 417 CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate); |
| 418 return false; | 418 return false; |
| 419 } | 419 } |
| 420 | 420 |
| 421 JSRegExp::Flags flags = re->GetFlags(); | 421 JSRegExp::Flags flags = re->GetFlags(); |
| 422 | 422 |
| 423 Handle<String> pattern(re->Pattern()); | 423 Handle<String> pattern(re->Pattern()); |
| 424 pattern = String::Flatten(pattern); | 424 pattern = String::Flatten(pattern); |
| 425 RegExpCompileData compile_data; | 425 RegExpCompileData compile_data; |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 | 532 |
| 533 int RegExpImpl::IrregexpExecRaw(Handle<JSRegExp> regexp, | 533 int RegExpImpl::IrregexpExecRaw(Handle<JSRegExp> regexp, |
| 534 Handle<String> subject, | 534 Handle<String> subject, |
| 535 int index, | 535 int index, |
| 536 int32_t* output, | 536 int32_t* output, |
| 537 int output_size) { | 537 int output_size) { |
| 538 Isolate* isolate = regexp->GetIsolate(); | 538 Isolate* isolate = regexp->GetIsolate(); |
| 539 | 539 |
| 540 Handle<FixedArray> irregexp(FixedArray::cast(regexp->data()), isolate); | 540 Handle<FixedArray> irregexp(FixedArray::cast(regexp->data()), isolate); |
| 541 | 541 |
| 542 ASSERT(index >= 0); | 542 DCHECK(index >= 0); |
| 543 ASSERT(index <= subject->length()); | 543 DCHECK(index <= subject->length()); |
| 544 ASSERT(subject->IsFlat()); | 544 DCHECK(subject->IsFlat()); |
| 545 | 545 |
| 546 bool is_ascii = subject->IsOneByteRepresentationUnderneath(); | 546 bool is_ascii = subject->IsOneByteRepresentationUnderneath(); |
| 547 | 547 |
| 548 #ifndef V8_INTERPRETED_REGEXP | 548 #ifndef V8_INTERPRETED_REGEXP |
| 549 ASSERT(output_size >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2); | 549 DCHECK(output_size >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2); |
| 550 do { | 550 do { |
| 551 EnsureCompiledIrregexp(regexp, subject, is_ascii); | 551 EnsureCompiledIrregexp(regexp, subject, is_ascii); |
| 552 Handle<Code> code(IrregexpNativeCode(*irregexp, is_ascii), isolate); | 552 Handle<Code> code(IrregexpNativeCode(*irregexp, is_ascii), isolate); |
| 553 // The stack is used to allocate registers for the compiled regexp code. | 553 // The stack is used to allocate registers for the compiled regexp code. |
| 554 // This means that in case of failure, the output registers array is left | 554 // This means that in case of failure, the output registers array is left |
| 555 // untouched and contains the capture results from the previous successful | 555 // untouched and contains the capture results from the previous successful |
| 556 // match. We can use that to set the last match info lazily. | 556 // match. We can use that to set the last match info lazily. |
| 557 NativeRegExpMacroAssembler::Result res = | 557 NativeRegExpMacroAssembler::Result res = |
| 558 NativeRegExpMacroAssembler::Match(code, | 558 NativeRegExpMacroAssembler::Match(code, |
| 559 subject, | 559 subject, |
| 560 output, | 560 output, |
| 561 output_size, | 561 output_size, |
| 562 index, | 562 index, |
| 563 isolate); | 563 isolate); |
| 564 if (res != NativeRegExpMacroAssembler::RETRY) { | 564 if (res != NativeRegExpMacroAssembler::RETRY) { |
| 565 ASSERT(res != NativeRegExpMacroAssembler::EXCEPTION || | 565 DCHECK(res != NativeRegExpMacroAssembler::EXCEPTION || |
| 566 isolate->has_pending_exception()); | 566 isolate->has_pending_exception()); |
| 567 STATIC_ASSERT( | 567 STATIC_ASSERT( |
| 568 static_cast<int>(NativeRegExpMacroAssembler::SUCCESS) == RE_SUCCESS); | 568 static_cast<int>(NativeRegExpMacroAssembler::SUCCESS) == RE_SUCCESS); |
| 569 STATIC_ASSERT( | 569 STATIC_ASSERT( |
| 570 static_cast<int>(NativeRegExpMacroAssembler::FAILURE) == RE_FAILURE); | 570 static_cast<int>(NativeRegExpMacroAssembler::FAILURE) == RE_FAILURE); |
| 571 STATIC_ASSERT(static_cast<int>(NativeRegExpMacroAssembler::EXCEPTION) | 571 STATIC_ASSERT(static_cast<int>(NativeRegExpMacroAssembler::EXCEPTION) |
| 572 == RE_EXCEPTION); | 572 == RE_EXCEPTION); |
| 573 return static_cast<IrregexpResult>(res); | 573 return static_cast<IrregexpResult>(res); |
| 574 } | 574 } |
| 575 // If result is RETRY, the string has changed representation, and we | 575 // If result is RETRY, the string has changed representation, and we |
| 576 // must restart from scratch. | 576 // must restart from scratch. |
| 577 // In this case, it means we must make sure we are prepared to handle | 577 // In this case, it means we must make sure we are prepared to handle |
| 578 // the, potentially, different subject (the string can switch between | 578 // the, potentially, different subject (the string can switch between |
| 579 // being internal and external, and even between being ASCII and UC16, | 579 // being internal and external, and even between being ASCII and UC16, |
| 580 // but the characters are always the same). | 580 // but the characters are always the same). |
| 581 IrregexpPrepare(regexp, subject); | 581 IrregexpPrepare(regexp, subject); |
| 582 is_ascii = subject->IsOneByteRepresentationUnderneath(); | 582 is_ascii = subject->IsOneByteRepresentationUnderneath(); |
| 583 } while (true); | 583 } while (true); |
| 584 UNREACHABLE(); | 584 UNREACHABLE(); |
| 585 return RE_EXCEPTION; | 585 return RE_EXCEPTION; |
| 586 #else // V8_INTERPRETED_REGEXP | 586 #else // V8_INTERPRETED_REGEXP |
| 587 | 587 |
| 588 ASSERT(output_size >= IrregexpNumberOfRegisters(*irregexp)); | 588 DCHECK(output_size >= IrregexpNumberOfRegisters(*irregexp)); |
| 589 // We must have done EnsureCompiledIrregexp, so we can get the number of | 589 // We must have done EnsureCompiledIrregexp, so we can get the number of |
| 590 // registers. | 590 // registers. |
| 591 int number_of_capture_registers = | 591 int number_of_capture_registers = |
| 592 (IrregexpNumberOfCaptures(*irregexp) + 1) * 2; | 592 (IrregexpNumberOfCaptures(*irregexp) + 1) * 2; |
| 593 int32_t* raw_output = &output[number_of_capture_registers]; | 593 int32_t* raw_output = &output[number_of_capture_registers]; |
| 594 // We do not touch the actual capture result registers until we know there | 594 // We do not touch the actual capture result registers until we know there |
| 595 // has been a match so that we can use those capture results to set the | 595 // has been a match so that we can use those capture results to set the |
| 596 // last match info. | 596 // last match info. |
| 597 for (int i = number_of_capture_registers - 1; i >= 0; i--) { | 597 for (int i = number_of_capture_registers - 1; i >= 0; i--) { |
| 598 raw_output[i] = -1; | 598 raw_output[i] = -1; |
| 599 } | 599 } |
| 600 Handle<ByteArray> byte_codes(IrregexpByteCode(*irregexp, is_ascii), isolate); | 600 Handle<ByteArray> byte_codes(IrregexpByteCode(*irregexp, is_ascii), isolate); |
| 601 | 601 |
| 602 IrregexpResult result = IrregexpInterpreter::Match(isolate, | 602 IrregexpResult result = IrregexpInterpreter::Match(isolate, |
| 603 byte_codes, | 603 byte_codes, |
| 604 subject, | 604 subject, |
| 605 raw_output, | 605 raw_output, |
| 606 index); | 606 index); |
| 607 if (result == RE_SUCCESS) { | 607 if (result == RE_SUCCESS) { |
| 608 // Copy capture results to the start of the registers array. | 608 // Copy capture results to the start of the registers array. |
| 609 MemCopy(output, raw_output, number_of_capture_registers * sizeof(int32_t)); | 609 MemCopy(output, raw_output, number_of_capture_registers * sizeof(int32_t)); |
| 610 } | 610 } |
| 611 if (result == RE_EXCEPTION) { | 611 if (result == RE_EXCEPTION) { |
| 612 ASSERT(!isolate->has_pending_exception()); | 612 DCHECK(!isolate->has_pending_exception()); |
| 613 isolate->StackOverflow(); | 613 isolate->StackOverflow(); |
| 614 } | 614 } |
| 615 return result; | 615 return result; |
| 616 #endif // V8_INTERPRETED_REGEXP | 616 #endif // V8_INTERPRETED_REGEXP |
| 617 } | 617 } |
| 618 | 618 |
| 619 | 619 |
| 620 MaybeHandle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> regexp, | 620 MaybeHandle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> regexp, |
| 621 Handle<String> subject, | 621 Handle<String> subject, |
| 622 int previous_index, | 622 int previous_index, |
| 623 Handle<JSArray> last_match_info) { | 623 Handle<JSArray> last_match_info) { |
| 624 Isolate* isolate = regexp->GetIsolate(); | 624 Isolate* isolate = regexp->GetIsolate(); |
| 625 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); | 625 DCHECK_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); |
| 626 | 626 |
| 627 // Prepare space for the return values. | 627 // Prepare space for the return values. |
| 628 #if defined(V8_INTERPRETED_REGEXP) && defined(DEBUG) | 628 #if defined(V8_INTERPRETED_REGEXP) && defined(DEBUG) |
| 629 if (FLAG_trace_regexp_bytecodes) { | 629 if (FLAG_trace_regexp_bytecodes) { |
| 630 String* pattern = regexp->Pattern(); | 630 String* pattern = regexp->Pattern(); |
| 631 PrintF("\n\nRegexp match: /%s/\n\n", pattern->ToCString().get()); | 631 PrintF("\n\nRegexp match: /%s/\n\n", pattern->ToCString().get()); |
| 632 PrintF("\n\nSubject string: '%s'\n\n", subject->ToCString().get()); | 632 PrintF("\n\nSubject string: '%s'\n\n", subject->ToCString().get()); |
| 633 } | 633 } |
| 634 #endif | 634 #endif |
| 635 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); | 635 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); |
| 636 if (required_registers < 0) { | 636 if (required_registers < 0) { |
| 637 // Compiling failed with an exception. | 637 // Compiling failed with an exception. |
| 638 ASSERT(isolate->has_pending_exception()); | 638 DCHECK(isolate->has_pending_exception()); |
| 639 return MaybeHandle<Object>(); | 639 return MaybeHandle<Object>(); |
| 640 } | 640 } |
| 641 | 641 |
| 642 int32_t* output_registers = NULL; | 642 int32_t* output_registers = NULL; |
| 643 if (required_registers > Isolate::kJSRegexpStaticOffsetsVectorSize) { | 643 if (required_registers > Isolate::kJSRegexpStaticOffsetsVectorSize) { |
| 644 output_registers = NewArray<int32_t>(required_registers); | 644 output_registers = NewArray<int32_t>(required_registers); |
| 645 } | 645 } |
| 646 SmartArrayPointer<int32_t> auto_release(output_registers); | 646 SmartArrayPointer<int32_t> auto_release(output_registers); |
| 647 if (output_registers == NULL) { | 647 if (output_registers == NULL) { |
| 648 output_registers = isolate->jsregexp_static_offsets_vector(); | 648 output_registers = isolate->jsregexp_static_offsets_vector(); |
| 649 } | 649 } |
| 650 | 650 |
| 651 int res = RegExpImpl::IrregexpExecRaw( | 651 int res = RegExpImpl::IrregexpExecRaw( |
| 652 regexp, subject, previous_index, output_registers, required_registers); | 652 regexp, subject, previous_index, output_registers, required_registers); |
| 653 if (res == RE_SUCCESS) { | 653 if (res == RE_SUCCESS) { |
| 654 int capture_count = | 654 int capture_count = |
| 655 IrregexpNumberOfCaptures(FixedArray::cast(regexp->data())); | 655 IrregexpNumberOfCaptures(FixedArray::cast(regexp->data())); |
| 656 return SetLastMatchInfo( | 656 return SetLastMatchInfo( |
| 657 last_match_info, subject, capture_count, output_registers); | 657 last_match_info, subject, capture_count, output_registers); |
| 658 } | 658 } |
| 659 if (res == RE_EXCEPTION) { | 659 if (res == RE_EXCEPTION) { |
| 660 ASSERT(isolate->has_pending_exception()); | 660 DCHECK(isolate->has_pending_exception()); |
| 661 return MaybeHandle<Object>(); | 661 return MaybeHandle<Object>(); |
| 662 } | 662 } |
| 663 ASSERT(res == RE_FAILURE); | 663 DCHECK(res == RE_FAILURE); |
| 664 return isolate->factory()->null_value(); | 664 return isolate->factory()->null_value(); |
| 665 } | 665 } |
| 666 | 666 |
| 667 | 667 |
| 668 Handle<JSArray> RegExpImpl::SetLastMatchInfo(Handle<JSArray> last_match_info, | 668 Handle<JSArray> RegExpImpl::SetLastMatchInfo(Handle<JSArray> last_match_info, |
| 669 Handle<String> subject, | 669 Handle<String> subject, |
| 670 int capture_count, | 670 int capture_count, |
| 671 int32_t* match) { | 671 int32_t* match) { |
| 672 ASSERT(last_match_info->HasFastObjectElements()); | 672 DCHECK(last_match_info->HasFastObjectElements()); |
| 673 int capture_register_count = (capture_count + 1) * 2; | 673 int capture_register_count = (capture_count + 1) * 2; |
| 674 JSArray::EnsureSize(last_match_info, | 674 JSArray::EnsureSize(last_match_info, |
| 675 capture_register_count + kLastMatchOverhead); | 675 capture_register_count + kLastMatchOverhead); |
| 676 DisallowHeapAllocation no_allocation; | 676 DisallowHeapAllocation no_allocation; |
| 677 FixedArray* array = FixedArray::cast(last_match_info->elements()); | 677 FixedArray* array = FixedArray::cast(last_match_info->elements()); |
| 678 if (match != NULL) { | 678 if (match != NULL) { |
| 679 for (int i = 0; i < capture_register_count; i += 2) { | 679 for (int i = 0; i < capture_register_count; i += 2) { |
| 680 SetCapture(array, i, match[i]); | 680 SetCapture(array, i, match[i]); |
| 681 SetCapture(array, i + 1, match[i + 1]); | 681 SetCapture(array, i + 1, match[i + 1]); |
| 682 } | 682 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 if (register_array_size_ > Isolate::kJSRegexpStaticOffsetsVectorSize) { | 729 if (register_array_size_ > Isolate::kJSRegexpStaticOffsetsVectorSize) { |
| 730 register_array_ = NewArray<int32_t>(register_array_size_); | 730 register_array_ = NewArray<int32_t>(register_array_size_); |
| 731 } else { | 731 } else { |
| 732 register_array_ = isolate->jsregexp_static_offsets_vector(); | 732 register_array_ = isolate->jsregexp_static_offsets_vector(); |
| 733 } | 733 } |
| 734 | 734 |
| 735 // Set state so that fetching the results the first time triggers a call | 735 // Set state so that fetching the results the first time triggers a call |
| 736 // to the compiled regexp. | 736 // to the compiled regexp. |
| 737 current_match_index_ = max_matches_ - 1; | 737 current_match_index_ = max_matches_ - 1; |
| 738 num_matches_ = max_matches_; | 738 num_matches_ = max_matches_; |
| 739 ASSERT(registers_per_match_ >= 2); // Each match has at least one capture. | 739 DCHECK(registers_per_match_ >= 2); // Each match has at least one capture. |
| 740 ASSERT_GE(register_array_size_, registers_per_match_); | 740 DCHECK_GE(register_array_size_, registers_per_match_); |
| 741 int32_t* last_match = | 741 int32_t* last_match = |
| 742 ®ister_array_[current_match_index_ * registers_per_match_]; | 742 ®ister_array_[current_match_index_ * registers_per_match_]; |
| 743 last_match[0] = -1; | 743 last_match[0] = -1; |
| 744 last_match[1] = 0; | 744 last_match[1] = 0; |
| 745 } | 745 } |
| 746 | 746 |
| 747 | 747 |
| 748 // ------------------------------------------------------------------- | 748 // ------------------------------------------------------------------- |
| 749 // Implementation of the Irregexp regular expression engine. | 749 // Implementation of the Irregexp regular expression engine. |
| 750 // | 750 // |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 959 | 959 |
| 960 void CountCharacter(int character) { | 960 void CountCharacter(int character) { |
| 961 int index = (character & RegExpMacroAssembler::kTableMask); | 961 int index = (character & RegExpMacroAssembler::kTableMask); |
| 962 frequencies_[index].Increment(); | 962 frequencies_[index].Increment(); |
| 963 total_samples_++; | 963 total_samples_++; |
| 964 } | 964 } |
| 965 | 965 |
| 966 // Does not measure in percent, but rather per-128 (the table size from the | 966 // Does not measure in percent, but rather per-128 (the table size from the |
| 967 // regexp macro assembler). | 967 // regexp macro assembler). |
| 968 int Frequency(int in_character) { | 968 int Frequency(int in_character) { |
| 969 ASSERT((in_character & RegExpMacroAssembler::kTableMask) == in_character); | 969 DCHECK((in_character & RegExpMacroAssembler::kTableMask) == in_character); |
| 970 if (total_samples_ < 1) return 1; // Division by zero. | 970 if (total_samples_ < 1) return 1; // Division by zero. |
| 971 int freq_in_per128 = | 971 int freq_in_per128 = |
| 972 (frequencies_[in_character].counter() * 128) / total_samples_; | 972 (frequencies_[in_character].counter() * 128) / total_samples_; |
| 973 return freq_in_per128; | 973 return freq_in_per128; |
| 974 } | 974 } |
| 975 | 975 |
| 976 private: | 976 private: |
| 977 class CharacterFrequency { | 977 class CharacterFrequency { |
| 978 public: | 978 public: |
| 979 CharacterFrequency() : counter_(0), character_(-1) { } | 979 CharacterFrequency() : counter_(0), character_(-1) { } |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1081 : next_register_(2 * (capture_count + 1)), | 1081 : next_register_(2 * (capture_count + 1)), |
| 1082 work_list_(NULL), | 1082 work_list_(NULL), |
| 1083 recursion_depth_(0), | 1083 recursion_depth_(0), |
| 1084 ignore_case_(ignore_case), | 1084 ignore_case_(ignore_case), |
| 1085 ascii_(ascii), | 1085 ascii_(ascii), |
| 1086 reg_exp_too_big_(false), | 1086 reg_exp_too_big_(false), |
| 1087 current_expansion_factor_(1), | 1087 current_expansion_factor_(1), |
| 1088 frequency_collator_(), | 1088 frequency_collator_(), |
| 1089 zone_(zone) { | 1089 zone_(zone) { |
| 1090 accept_ = new(zone) EndNode(EndNode::ACCEPT, zone); | 1090 accept_ = new(zone) EndNode(EndNode::ACCEPT, zone); |
| 1091 ASSERT(next_register_ - 1 <= RegExpMacroAssembler::kMaxRegister); | 1091 DCHECK(next_register_ - 1 <= RegExpMacroAssembler::kMaxRegister); |
| 1092 } | 1092 } |
| 1093 | 1093 |
| 1094 | 1094 |
| 1095 RegExpEngine::CompilationResult RegExpCompiler::Assemble( | 1095 RegExpEngine::CompilationResult RegExpCompiler::Assemble( |
| 1096 RegExpMacroAssembler* macro_assembler, | 1096 RegExpMacroAssembler* macro_assembler, |
| 1097 RegExpNode* start, | 1097 RegExpNode* start, |
| 1098 int capture_count, | 1098 int capture_count, |
| 1099 Handle<String> pattern) { | 1099 Handle<String> pattern) { |
| 1100 Heap* heap = pattern->GetHeap(); | 1100 Heap* heap = pattern->GetHeap(); |
| 1101 | 1101 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1161 action != NULL; | 1161 action != NULL; |
| 1162 action = action->next()) { | 1162 action = action->next()) { |
| 1163 if (action->Mentions(reg)) | 1163 if (action->Mentions(reg)) |
| 1164 return true; | 1164 return true; |
| 1165 } | 1165 } |
| 1166 return false; | 1166 return false; |
| 1167 } | 1167 } |
| 1168 | 1168 |
| 1169 | 1169 |
| 1170 bool Trace::GetStoredPosition(int reg, int* cp_offset) { | 1170 bool Trace::GetStoredPosition(int reg, int* cp_offset) { |
| 1171 ASSERT_EQ(0, *cp_offset); | 1171 DCHECK_EQ(0, *cp_offset); |
| 1172 for (DeferredAction* action = actions_; | 1172 for (DeferredAction* action = actions_; |
| 1173 action != NULL; | 1173 action != NULL; |
| 1174 action = action->next()) { | 1174 action = action->next()) { |
| 1175 if (action->Mentions(reg)) { | 1175 if (action->Mentions(reg)) { |
| 1176 if (action->action_type() == ActionNode::STORE_POSITION) { | 1176 if (action->action_type() == ActionNode::STORE_POSITION) { |
| 1177 *cp_offset = static_cast<DeferredCapture*>(action)->cp_offset(); | 1177 *cp_offset = static_cast<DeferredCapture*>(action)->cp_offset(); |
| 1178 return true; | 1178 return true; |
| 1179 } else { | 1179 } else { |
| 1180 return false; | 1180 return false; |
| 1181 } | 1181 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1263 if (!absolute) { | 1263 if (!absolute) { |
| 1264 value += psr->value(); | 1264 value += psr->value(); |
| 1265 absolute = true; | 1265 absolute = true; |
| 1266 } | 1266 } |
| 1267 // SET_REGISTER is currently only used for newly introduced loop | 1267 // SET_REGISTER is currently only used for newly introduced loop |
| 1268 // counters. They can have a significant previous value if they | 1268 // counters. They can have a significant previous value if they |
| 1269 // occour in a loop. TODO(lrn): Propagate this information, so | 1269 // occour in a loop. TODO(lrn): Propagate this information, so |
| 1270 // we can set undo_action to IGNORE if we know there is no value to | 1270 // we can set undo_action to IGNORE if we know there is no value to |
| 1271 // restore. | 1271 // restore. |
| 1272 undo_action = RESTORE; | 1272 undo_action = RESTORE; |
| 1273 ASSERT_EQ(store_position, -1); | 1273 DCHECK_EQ(store_position, -1); |
| 1274 ASSERT(!clear); | 1274 DCHECK(!clear); |
| 1275 break; | 1275 break; |
| 1276 } | 1276 } |
| 1277 case ActionNode::INCREMENT_REGISTER: | 1277 case ActionNode::INCREMENT_REGISTER: |
| 1278 if (!absolute) { | 1278 if (!absolute) { |
| 1279 value++; | 1279 value++; |
| 1280 } | 1280 } |
| 1281 ASSERT_EQ(store_position, -1); | 1281 DCHECK_EQ(store_position, -1); |
| 1282 ASSERT(!clear); | 1282 DCHECK(!clear); |
| 1283 undo_action = RESTORE; | 1283 undo_action = RESTORE; |
| 1284 break; | 1284 break; |
| 1285 case ActionNode::STORE_POSITION: { | 1285 case ActionNode::STORE_POSITION: { |
| 1286 Trace::DeferredCapture* pc = | 1286 Trace::DeferredCapture* pc = |
| 1287 static_cast<Trace::DeferredCapture*>(action); | 1287 static_cast<Trace::DeferredCapture*>(action); |
| 1288 if (!clear && store_position == -1) { | 1288 if (!clear && store_position == -1) { |
| 1289 store_position = pc->cp_offset(); | 1289 store_position = pc->cp_offset(); |
| 1290 } | 1290 } |
| 1291 | 1291 |
| 1292 // For captures we know that stores and clears alternate. | 1292 // For captures we know that stores and clears alternate. |
| 1293 // Other register, are never cleared, and if the occur | 1293 // Other register, are never cleared, and if the occur |
| 1294 // inside a loop, they might be assigned more than once. | 1294 // inside a loop, they might be assigned more than once. |
| 1295 if (reg <= 1) { | 1295 if (reg <= 1) { |
| 1296 // Registers zero and one, aka "capture zero", is | 1296 // Registers zero and one, aka "capture zero", is |
| 1297 // always set correctly if we succeed. There is no | 1297 // always set correctly if we succeed. There is no |
| 1298 // need to undo a setting on backtrack, because we | 1298 // need to undo a setting on backtrack, because we |
| 1299 // will set it again or fail. | 1299 // will set it again or fail. |
| 1300 undo_action = IGNORE; | 1300 undo_action = IGNORE; |
| 1301 } else { | 1301 } else { |
| 1302 undo_action = pc->is_capture() ? CLEAR : RESTORE; | 1302 undo_action = pc->is_capture() ? CLEAR : RESTORE; |
| 1303 } | 1303 } |
| 1304 ASSERT(!absolute); | 1304 DCHECK(!absolute); |
| 1305 ASSERT_EQ(value, 0); | 1305 DCHECK_EQ(value, 0); |
| 1306 break; | 1306 break; |
| 1307 } | 1307 } |
| 1308 case ActionNode::CLEAR_CAPTURES: { | 1308 case ActionNode::CLEAR_CAPTURES: { |
| 1309 // Since we're scanning in reverse order, if we've already | 1309 // Since we're scanning in reverse order, if we've already |
| 1310 // set the position we have to ignore historically earlier | 1310 // set the position we have to ignore historically earlier |
| 1311 // clearing operations. | 1311 // clearing operations. |
| 1312 if (store_position == -1) { | 1312 if (store_position == -1) { |
| 1313 clear = true; | 1313 clear = true; |
| 1314 } | 1314 } |
| 1315 undo_action = RESTORE; | 1315 undo_action = RESTORE; |
| 1316 ASSERT(!absolute); | 1316 DCHECK(!absolute); |
| 1317 ASSERT_EQ(value, 0); | 1317 DCHECK_EQ(value, 0); |
| 1318 break; | 1318 break; |
| 1319 } | 1319 } |
| 1320 default: | 1320 default: |
| 1321 UNREACHABLE(); | 1321 UNREACHABLE(); |
| 1322 break; | 1322 break; |
| 1323 } | 1323 } |
| 1324 } | 1324 } |
| 1325 } | 1325 } |
| 1326 // Prepare for the undo-action (e.g., push if it's going to be popped). | 1326 // Prepare for the undo-action (e.g., push if it's going to be popped). |
| 1327 if (undo_action == RESTORE) { | 1327 if (undo_action == RESTORE) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1352 } | 1352 } |
| 1353 } | 1353 } |
| 1354 | 1354 |
| 1355 | 1355 |
| 1356 // This is called as we come into a loop choice node and some other tricky | 1356 // This is called as we come into a loop choice node and some other tricky |
| 1357 // nodes. It normalizes the state of the code generator to ensure we can | 1357 // nodes. It normalizes the state of the code generator to ensure we can |
| 1358 // generate generic code. | 1358 // generate generic code. |
| 1359 void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) { | 1359 void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) { |
| 1360 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 1360 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 1361 | 1361 |
| 1362 ASSERT(!is_trivial()); | 1362 DCHECK(!is_trivial()); |
| 1363 | 1363 |
| 1364 if (actions_ == NULL && backtrack() == NULL) { | 1364 if (actions_ == NULL && backtrack() == NULL) { |
| 1365 // Here we just have some deferred cp advances to fix and we are back to | 1365 // Here we just have some deferred cp advances to fix and we are back to |
| 1366 // a normal situation. We may also have to forget some information gained | 1366 // a normal situation. We may also have to forget some information gained |
| 1367 // through a quick check that was already performed. | 1367 // through a quick check that was already performed. |
| 1368 if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_); | 1368 if (cp_offset_ != 0) assembler->AdvanceCurrentPosition(cp_offset_); |
| 1369 // Create a new trivial state and generate the node with that. | 1369 // Create a new trivial state and generate the node with that. |
| 1370 Trace new_state; | 1370 Trace new_state; |
| 1371 successor->Emit(compiler, &new_state); | 1371 successor->Emit(compiler, &new_state); |
| 1372 return; | 1372 return; |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1569 | 1569 |
| 1570 // ------------------------------------------------------------------- | 1570 // ------------------------------------------------------------------- |
| 1571 // Emit code. | 1571 // Emit code. |
| 1572 | 1572 |
| 1573 | 1573 |
| 1574 void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler, | 1574 void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler, |
| 1575 Guard* guard, | 1575 Guard* guard, |
| 1576 Trace* trace) { | 1576 Trace* trace) { |
| 1577 switch (guard->op()) { | 1577 switch (guard->op()) { |
| 1578 case Guard::LT: | 1578 case Guard::LT: |
| 1579 ASSERT(!trace->mentions_reg(guard->reg())); | 1579 DCHECK(!trace->mentions_reg(guard->reg())); |
| 1580 macro_assembler->IfRegisterGE(guard->reg(), | 1580 macro_assembler->IfRegisterGE(guard->reg(), |
| 1581 guard->value(), | 1581 guard->value(), |
| 1582 trace->backtrack()); | 1582 trace->backtrack()); |
| 1583 break; | 1583 break; |
| 1584 case Guard::GEQ: | 1584 case Guard::GEQ: |
| 1585 ASSERT(!trace->mentions_reg(guard->reg())); | 1585 DCHECK(!trace->mentions_reg(guard->reg())); |
| 1586 macro_assembler->IfRegisterLT(guard->reg(), | 1586 macro_assembler->IfRegisterLT(guard->reg(), |
| 1587 guard->value(), | 1587 guard->value(), |
| 1588 trace->backtrack()); | 1588 trace->backtrack()); |
| 1589 break; | 1589 break; |
| 1590 } | 1590 } |
| 1591 } | 1591 } |
| 1592 | 1592 |
| 1593 | 1593 |
| 1594 // Returns the number of characters in the equivalence class, omitting those | 1594 // Returns the number of characters in the equivalence class, omitting those |
| 1595 // that cannot occur in the source string because it is ASCII. | 1595 // that cannot occur in the source string because it is ASCII. |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1679 if (ascii) { | 1679 if (ascii) { |
| 1680 char_mask = String::kMaxOneByteCharCode; | 1680 char_mask = String::kMaxOneByteCharCode; |
| 1681 } else { | 1681 } else { |
| 1682 char_mask = String::kMaxUtf16CodeUnit; | 1682 char_mask = String::kMaxUtf16CodeUnit; |
| 1683 } | 1683 } |
| 1684 uc16 exor = c1 ^ c2; | 1684 uc16 exor = c1 ^ c2; |
| 1685 // Check whether exor has only one bit set. | 1685 // Check whether exor has only one bit set. |
| 1686 if (((exor - 1) & exor) == 0) { | 1686 if (((exor - 1) & exor) == 0) { |
| 1687 // If c1 and c2 differ only by one bit. | 1687 // If c1 and c2 differ only by one bit. |
| 1688 // Ecma262UnCanonicalize always gives the highest number last. | 1688 // Ecma262UnCanonicalize always gives the highest number last. |
| 1689 ASSERT(c2 > c1); | 1689 DCHECK(c2 > c1); |
| 1690 uc16 mask = char_mask ^ exor; | 1690 uc16 mask = char_mask ^ exor; |
| 1691 macro_assembler->CheckNotCharacterAfterAnd(c1, mask, on_failure); | 1691 macro_assembler->CheckNotCharacterAfterAnd(c1, mask, on_failure); |
| 1692 return true; | 1692 return true; |
| 1693 } | 1693 } |
| 1694 ASSERT(c2 > c1); | 1694 DCHECK(c2 > c1); |
| 1695 uc16 diff = c2 - c1; | 1695 uc16 diff = c2 - c1; |
| 1696 if (((diff - 1) & diff) == 0 && c1 >= diff) { | 1696 if (((diff - 1) & diff) == 0 && c1 >= diff) { |
| 1697 // If the characters differ by 2^n but don't differ by one bit then | 1697 // If the characters differ by 2^n but don't differ by one bit then |
| 1698 // subtract the difference from the found character, then do the or | 1698 // subtract the difference from the found character, then do the or |
| 1699 // trick. We avoid the theoretical case where negative numbers are | 1699 // trick. We avoid the theoretical case where negative numbers are |
| 1700 // involved in order to simplify code generation. | 1700 // involved in order to simplify code generation. |
| 1701 uc16 mask = char_mask ^ diff; | 1701 uc16 mask = char_mask ^ diff; |
| 1702 macro_assembler->CheckNotCharacterAfterMinusAnd(c1 - diff, | 1702 macro_assembler->CheckNotCharacterAfterMinusAnd(c1 - diff, |
| 1703 diff, | 1703 diff, |
| 1704 mask, | 1704 mask, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1730 bool ascii = compiler->ascii(); | 1730 bool ascii = compiler->ascii(); |
| 1731 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; | 1731 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; |
| 1732 int length = GetCaseIndependentLetters(isolate, c, ascii, chars); | 1732 int length = GetCaseIndependentLetters(isolate, c, ascii, chars); |
| 1733 if (length <= 1) return false; | 1733 if (length <= 1) return false; |
| 1734 // We may not need to check against the end of the input string | 1734 // We may not need to check against the end of the input string |
| 1735 // if this character lies before a character that matched. | 1735 // if this character lies before a character that matched. |
| 1736 if (!preloaded) { | 1736 if (!preloaded) { |
| 1737 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check); | 1737 macro_assembler->LoadCurrentCharacter(cp_offset, on_failure, check); |
| 1738 } | 1738 } |
| 1739 Label ok; | 1739 Label ok; |
| 1740 ASSERT(unibrow::Ecma262UnCanonicalize::kMaxWidth == 4); | 1740 DCHECK(unibrow::Ecma262UnCanonicalize::kMaxWidth == 4); |
| 1741 switch (length) { | 1741 switch (length) { |
| 1742 case 2: { | 1742 case 2: { |
| 1743 if (ShortCutEmitCharacterPair(macro_assembler, | 1743 if (ShortCutEmitCharacterPair(macro_assembler, |
| 1744 ascii, | 1744 ascii, |
| 1745 chars[0], | 1745 chars[0], |
| 1746 chars[1], | 1746 chars[1], |
| 1747 on_failure)) { | 1747 on_failure)) { |
| 1748 } else { | 1748 } else { |
| 1749 macro_assembler->CheckCharacter(chars[0], &ok); | 1749 macro_assembler->CheckCharacter(chars[0], &ok); |
| 1750 macro_assembler->CheckNotCharacter(chars[1], on_failure); | 1750 macro_assembler->CheckNotCharacter(chars[1], on_failure); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1818 Label* even_label, | 1818 Label* even_label, |
| 1819 Label* odd_label) { | 1819 Label* odd_label) { |
| 1820 static const int kSize = RegExpMacroAssembler::kTableSize; | 1820 static const int kSize = RegExpMacroAssembler::kTableSize; |
| 1821 static const int kMask = RegExpMacroAssembler::kTableMask; | 1821 static const int kMask = RegExpMacroAssembler::kTableMask; |
| 1822 | 1822 |
| 1823 int base = (min_char & ~kMask); | 1823 int base = (min_char & ~kMask); |
| 1824 USE(base); | 1824 USE(base); |
| 1825 | 1825 |
| 1826 // Assert that everything is on one kTableSize page. | 1826 // Assert that everything is on one kTableSize page. |
| 1827 for (int i = start_index; i <= end_index; i++) { | 1827 for (int i = start_index; i <= end_index; i++) { |
| 1828 ASSERT_EQ(ranges->at(i) & ~kMask, base); | 1828 DCHECK_EQ(ranges->at(i) & ~kMask, base); |
| 1829 } | 1829 } |
| 1830 ASSERT(start_index == 0 || (ranges->at(start_index - 1) & ~kMask) <= base); | 1830 DCHECK(start_index == 0 || (ranges->at(start_index - 1) & ~kMask) <= base); |
| 1831 | 1831 |
| 1832 char templ[kSize]; | 1832 char templ[kSize]; |
| 1833 Label* on_bit_set; | 1833 Label* on_bit_set; |
| 1834 Label* on_bit_clear; | 1834 Label* on_bit_clear; |
| 1835 int bit; | 1835 int bit; |
| 1836 if (even_label == fall_through) { | 1836 if (even_label == fall_through) { |
| 1837 on_bit_set = odd_label; | 1837 on_bit_set = odd_label; |
| 1838 on_bit_clear = even_label; | 1838 on_bit_clear = even_label; |
| 1839 bit = 1; | 1839 bit = 1; |
| 1840 } else { | 1840 } else { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1876 Label* odd_label) { | 1876 Label* odd_label) { |
| 1877 bool odd = (((cut_index - start_index) & 1) == 1); | 1877 bool odd = (((cut_index - start_index) & 1) == 1); |
| 1878 Label* in_range_label = odd ? odd_label : even_label; | 1878 Label* in_range_label = odd ? odd_label : even_label; |
| 1879 Label dummy; | 1879 Label dummy; |
| 1880 EmitDoubleBoundaryTest(masm, | 1880 EmitDoubleBoundaryTest(masm, |
| 1881 ranges->at(cut_index), | 1881 ranges->at(cut_index), |
| 1882 ranges->at(cut_index + 1) - 1, | 1882 ranges->at(cut_index + 1) - 1, |
| 1883 &dummy, | 1883 &dummy, |
| 1884 in_range_label, | 1884 in_range_label, |
| 1885 &dummy); | 1885 &dummy); |
| 1886 ASSERT(!dummy.is_linked()); | 1886 DCHECK(!dummy.is_linked()); |
| 1887 // Cut out the single range by rewriting the array. This creates a new | 1887 // Cut out the single range by rewriting the array. This creates a new |
| 1888 // range that is a merger of the two ranges on either side of the one we | 1888 // range that is a merger of the two ranges on either side of the one we |
| 1889 // are cutting out. The oddity of the labels is preserved. | 1889 // are cutting out. The oddity of the labels is preserved. |
| 1890 for (int j = cut_index; j > start_index; j--) { | 1890 for (int j = cut_index; j > start_index; j--) { |
| 1891 ranges->at(j) = ranges->at(j - 1); | 1891 ranges->at(j) = ranges->at(j - 1); |
| 1892 } | 1892 } |
| 1893 for (int j = cut_index + 1; j < end_index; j++) { | 1893 for (int j = cut_index + 1; j < end_index; j++) { |
| 1894 ranges->at(j) = ranges->at(j + 1); | 1894 ranges->at(j) = ranges->at(j + 1); |
| 1895 } | 1895 } |
| 1896 } | 1896 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1943 while (scan_forward_for_section_border < end_index) { | 1943 while (scan_forward_for_section_border < end_index) { |
| 1944 if (ranges->at(scan_forward_for_section_border) > new_border) { | 1944 if (ranges->at(scan_forward_for_section_border) > new_border) { |
| 1945 *new_start_index = scan_forward_for_section_border; | 1945 *new_start_index = scan_forward_for_section_border; |
| 1946 *border = new_border; | 1946 *border = new_border; |
| 1947 break; | 1947 break; |
| 1948 } | 1948 } |
| 1949 scan_forward_for_section_border++; | 1949 scan_forward_for_section_border++; |
| 1950 } | 1950 } |
| 1951 } | 1951 } |
| 1952 | 1952 |
| 1953 ASSERT(*new_start_index > start_index); | 1953 DCHECK(*new_start_index > start_index); |
| 1954 *new_end_index = *new_start_index - 1; | 1954 *new_end_index = *new_start_index - 1; |
| 1955 if (ranges->at(*new_end_index) == *border) { | 1955 if (ranges->at(*new_end_index) == *border) { |
| 1956 (*new_end_index)--; | 1956 (*new_end_index)--; |
| 1957 } | 1957 } |
| 1958 if (*border >= ranges->at(end_index)) { | 1958 if (*border >= ranges->at(end_index)) { |
| 1959 *border = ranges->at(end_index); | 1959 *border = ranges->at(end_index); |
| 1960 *new_start_index = end_index; // Won't be used. | 1960 *new_start_index = end_index; // Won't be used. |
| 1961 *new_end_index = end_index - 1; | 1961 *new_end_index = end_index - 1; |
| 1962 } | 1962 } |
| 1963 } | 1963 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1974 int start_index, | 1974 int start_index, |
| 1975 int end_index, | 1975 int end_index, |
| 1976 uc16 min_char, | 1976 uc16 min_char, |
| 1977 uc16 max_char, | 1977 uc16 max_char, |
| 1978 Label* fall_through, | 1978 Label* fall_through, |
| 1979 Label* even_label, | 1979 Label* even_label, |
| 1980 Label* odd_label) { | 1980 Label* odd_label) { |
| 1981 int first = ranges->at(start_index); | 1981 int first = ranges->at(start_index); |
| 1982 int last = ranges->at(end_index) - 1; | 1982 int last = ranges->at(end_index) - 1; |
| 1983 | 1983 |
| 1984 ASSERT_LT(min_char, first); | 1984 DCHECK_LT(min_char, first); |
| 1985 | 1985 |
| 1986 // Just need to test if the character is before or on-or-after | 1986 // Just need to test if the character is before or on-or-after |
| 1987 // a particular character. | 1987 // a particular character. |
| 1988 if (start_index == end_index) { | 1988 if (start_index == end_index) { |
| 1989 EmitBoundaryTest(masm, first, fall_through, even_label, odd_label); | 1989 EmitBoundaryTest(masm, first, fall_through, even_label, odd_label); |
| 1990 return; | 1990 return; |
| 1991 } | 1991 } |
| 1992 | 1992 |
| 1993 // Another almost trivial case: There is one interval in the middle that is | 1993 // Another almost trivial case: There is one interval in the middle that is |
| 1994 // different from the end intervals. | 1994 // different from the end intervals. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2007 int cut = kNoCutIndex; | 2007 int cut = kNoCutIndex; |
| 2008 for (int i = start_index; i < end_index; i++) { | 2008 for (int i = start_index; i < end_index; i++) { |
| 2009 if (ranges->at(i) == ranges->at(i + 1) - 1) { | 2009 if (ranges->at(i) == ranges->at(i + 1) - 1) { |
| 2010 cut = i; | 2010 cut = i; |
| 2011 break; | 2011 break; |
| 2012 } | 2012 } |
| 2013 } | 2013 } |
| 2014 if (cut == kNoCutIndex) cut = start_index; | 2014 if (cut == kNoCutIndex) cut = start_index; |
| 2015 CutOutRange( | 2015 CutOutRange( |
| 2016 masm, ranges, start_index, end_index, cut, even_label, odd_label); | 2016 masm, ranges, start_index, end_index, cut, even_label, odd_label); |
| 2017 ASSERT_GE(end_index - start_index, 2); | 2017 DCHECK_GE(end_index - start_index, 2); |
| 2018 GenerateBranches(masm, | 2018 GenerateBranches(masm, |
| 2019 ranges, | 2019 ranges, |
| 2020 start_index + 1, | 2020 start_index + 1, |
| 2021 end_index - 1, | 2021 end_index - 1, |
| 2022 min_char, | 2022 min_char, |
| 2023 max_char, | 2023 max_char, |
| 2024 fall_through, | 2024 fall_through, |
| 2025 even_label, | 2025 even_label, |
| 2026 odd_label); | 2026 odd_label); |
| 2027 return; | 2027 return; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2067 &new_start_index, | 2067 &new_start_index, |
| 2068 &new_end_index, | 2068 &new_end_index, |
| 2069 &border); | 2069 &border); |
| 2070 | 2070 |
| 2071 Label handle_rest; | 2071 Label handle_rest; |
| 2072 Label* above = &handle_rest; | 2072 Label* above = &handle_rest; |
| 2073 if (border == last + 1) { | 2073 if (border == last + 1) { |
| 2074 // We didn't find any section that started after the limit, so everything | 2074 // We didn't find any section that started after the limit, so everything |
| 2075 // above the border is one of the terminal labels. | 2075 // above the border is one of the terminal labels. |
| 2076 above = (end_index & 1) != (start_index & 1) ? odd_label : even_label; | 2076 above = (end_index & 1) != (start_index & 1) ? odd_label : even_label; |
| 2077 ASSERT(new_end_index == end_index - 1); | 2077 DCHECK(new_end_index == end_index - 1); |
| 2078 } | 2078 } |
| 2079 | 2079 |
| 2080 ASSERT_LE(start_index, new_end_index); | 2080 DCHECK_LE(start_index, new_end_index); |
| 2081 ASSERT_LE(new_start_index, end_index); | 2081 DCHECK_LE(new_start_index, end_index); |
| 2082 ASSERT_LT(start_index, new_start_index); | 2082 DCHECK_LT(start_index, new_start_index); |
| 2083 ASSERT_LT(new_end_index, end_index); | 2083 DCHECK_LT(new_end_index, end_index); |
| 2084 ASSERT(new_end_index + 1 == new_start_index || | 2084 DCHECK(new_end_index + 1 == new_start_index || |
| 2085 (new_end_index + 2 == new_start_index && | 2085 (new_end_index + 2 == new_start_index && |
| 2086 border == ranges->at(new_end_index + 1))); | 2086 border == ranges->at(new_end_index + 1))); |
| 2087 ASSERT_LT(min_char, border - 1); | 2087 DCHECK_LT(min_char, border - 1); |
| 2088 ASSERT_LT(border, max_char); | 2088 DCHECK_LT(border, max_char); |
| 2089 ASSERT_LT(ranges->at(new_end_index), border); | 2089 DCHECK_LT(ranges->at(new_end_index), border); |
| 2090 ASSERT(border < ranges->at(new_start_index) || | 2090 DCHECK(border < ranges->at(new_start_index) || |
| 2091 (border == ranges->at(new_start_index) && | 2091 (border == ranges->at(new_start_index) && |
| 2092 new_start_index == end_index && | 2092 new_start_index == end_index && |
| 2093 new_end_index == end_index - 1 && | 2093 new_end_index == end_index - 1 && |
| 2094 border == last + 1)); | 2094 border == last + 1)); |
| 2095 ASSERT(new_start_index == 0 || border >= ranges->at(new_start_index - 1)); | 2095 DCHECK(new_start_index == 0 || border >= ranges->at(new_start_index - 1)); |
| 2096 | 2096 |
| 2097 masm->CheckCharacterGT(border - 1, above); | 2097 masm->CheckCharacterGT(border - 1, above); |
| 2098 Label dummy; | 2098 Label dummy; |
| 2099 GenerateBranches(masm, | 2099 GenerateBranches(masm, |
| 2100 ranges, | 2100 ranges, |
| 2101 start_index, | 2101 start_index, |
| 2102 new_end_index, | 2102 new_end_index, |
| 2103 min_char, | 2103 min_char, |
| 2104 border - 1, | 2104 border - 1, |
| 2105 &dummy, | 2105 &dummy, |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2202 // was already one there we fall through for success on that entry. | 2202 // was already one there we fall through for success on that entry. |
| 2203 // Subsequent entries have alternating meaning (success/failure). | 2203 // Subsequent entries have alternating meaning (success/failure). |
| 2204 ZoneList<int>* range_boundaries = | 2204 ZoneList<int>* range_boundaries = |
| 2205 new(zone) ZoneList<int>(last_valid_range, zone); | 2205 new(zone) ZoneList<int>(last_valid_range, zone); |
| 2206 | 2206 |
| 2207 bool zeroth_entry_is_failure = !cc->is_negated(); | 2207 bool zeroth_entry_is_failure = !cc->is_negated(); |
| 2208 | 2208 |
| 2209 for (int i = 0; i <= last_valid_range; i++) { | 2209 for (int i = 0; i <= last_valid_range; i++) { |
| 2210 CharacterRange& range = ranges->at(i); | 2210 CharacterRange& range = ranges->at(i); |
| 2211 if (range.from() == 0) { | 2211 if (range.from() == 0) { |
| 2212 ASSERT_EQ(i, 0); | 2212 DCHECK_EQ(i, 0); |
| 2213 zeroth_entry_is_failure = !zeroth_entry_is_failure; | 2213 zeroth_entry_is_failure = !zeroth_entry_is_failure; |
| 2214 } else { | 2214 } else { |
| 2215 range_boundaries->Add(range.from(), zone); | 2215 range_boundaries->Add(range.from(), zone); |
| 2216 } | 2216 } |
| 2217 range_boundaries->Add(range.to() + 1, zone); | 2217 range_boundaries->Add(range.to() + 1, zone); |
| 2218 } | 2218 } |
| 2219 int end_index = range_boundaries->length() - 1; | 2219 int end_index = range_boundaries->length() - 1; |
| 2220 if (range_boundaries->at(end_index) > max_char) { | 2220 if (range_boundaries->at(end_index) > max_char) { |
| 2221 end_index--; | 2221 end_index--; |
| 2222 } | 2222 } |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2459 Trace* trace, | 2459 Trace* trace, |
| 2460 bool preload_has_checked_bounds, | 2460 bool preload_has_checked_bounds, |
| 2461 Label* on_possible_success, | 2461 Label* on_possible_success, |
| 2462 QuickCheckDetails* details, | 2462 QuickCheckDetails* details, |
| 2463 bool fall_through_on_failure) { | 2463 bool fall_through_on_failure) { |
| 2464 if (details->characters() == 0) return false; | 2464 if (details->characters() == 0) return false; |
| 2465 GetQuickCheckDetails( | 2465 GetQuickCheckDetails( |
| 2466 details, compiler, 0, trace->at_start() == Trace::FALSE_VALUE); | 2466 details, compiler, 0, trace->at_start() == Trace::FALSE_VALUE); |
| 2467 if (details->cannot_match()) return false; | 2467 if (details->cannot_match()) return false; |
| 2468 if (!details->Rationalize(compiler->ascii())) return false; | 2468 if (!details->Rationalize(compiler->ascii())) return false; |
| 2469 ASSERT(details->characters() == 1 || | 2469 DCHECK(details->characters() == 1 || |
| 2470 compiler->macro_assembler()->CanReadUnaligned()); | 2470 compiler->macro_assembler()->CanReadUnaligned()); |
| 2471 uint32_t mask = details->mask(); | 2471 uint32_t mask = details->mask(); |
| 2472 uint32_t value = details->value(); | 2472 uint32_t value = details->value(); |
| 2473 | 2473 |
| 2474 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 2474 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 2475 | 2475 |
| 2476 if (trace->characters_preloaded() != details->characters()) { | 2476 if (trace->characters_preloaded() != details->characters()) { |
| 2477 assembler->LoadCurrentCharacter(trace->cp_offset(), | 2477 assembler->LoadCurrentCharacter(trace->cp_offset(), |
| 2478 trace->backtrack(), | 2478 trace->backtrack(), |
| 2479 !preload_has_checked_bounds, | 2479 !preload_has_checked_bounds, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2529 // We iterate along the text object, building up for each character a | 2529 // We iterate along the text object, building up for each character a |
| 2530 // mask and value that can be used to test for a quick failure to match. | 2530 // mask and value that can be used to test for a quick failure to match. |
| 2531 // The masks and values for the positions will be combined into a single | 2531 // The masks and values for the positions will be combined into a single |
| 2532 // machine word for the current character width in order to be used in | 2532 // machine word for the current character width in order to be used in |
| 2533 // generating a quick check. | 2533 // generating a quick check. |
| 2534 void TextNode::GetQuickCheckDetails(QuickCheckDetails* details, | 2534 void TextNode::GetQuickCheckDetails(QuickCheckDetails* details, |
| 2535 RegExpCompiler* compiler, | 2535 RegExpCompiler* compiler, |
| 2536 int characters_filled_in, | 2536 int characters_filled_in, |
| 2537 bool not_at_start) { | 2537 bool not_at_start) { |
| 2538 Isolate* isolate = compiler->macro_assembler()->zone()->isolate(); | 2538 Isolate* isolate = compiler->macro_assembler()->zone()->isolate(); |
| 2539 ASSERT(characters_filled_in < details->characters()); | 2539 DCHECK(characters_filled_in < details->characters()); |
| 2540 int characters = details->characters(); | 2540 int characters = details->characters(); |
| 2541 int char_mask; | 2541 int char_mask; |
| 2542 if (compiler->ascii()) { | 2542 if (compiler->ascii()) { |
| 2543 char_mask = String::kMaxOneByteCharCode; | 2543 char_mask = String::kMaxOneByteCharCode; |
| 2544 } else { | 2544 } else { |
| 2545 char_mask = String::kMaxUtf16CodeUnit; | 2545 char_mask = String::kMaxUtf16CodeUnit; |
| 2546 } | 2546 } |
| 2547 for (int k = 0; k < elms_->length(); k++) { | 2547 for (int k = 0; k < elms_->length(); k++) { |
| 2548 TextElement elm = elms_->at(k); | 2548 TextElement elm = elms_->at(k); |
| 2549 if (elm.text_type() == TextElement::ATOM) { | 2549 if (elm.text_type() == TextElement::ATOM) { |
| 2550 Vector<const uc16> quarks = elm.atom()->data(); | 2550 Vector<const uc16> quarks = elm.atom()->data(); |
| 2551 for (int i = 0; i < characters && i < quarks.length(); i++) { | 2551 for (int i = 0; i < characters && i < quarks.length(); i++) { |
| 2552 QuickCheckDetails::Position* pos = | 2552 QuickCheckDetails::Position* pos = |
| 2553 details->positions(characters_filled_in); | 2553 details->positions(characters_filled_in); |
| 2554 uc16 c = quarks[i]; | 2554 uc16 c = quarks[i]; |
| 2555 if (c > char_mask) { | 2555 if (c > char_mask) { |
| 2556 // If we expect a non-ASCII character from an ASCII string, | 2556 // If we expect a non-ASCII character from an ASCII string, |
| 2557 // there is no way we can match. Not even case independent | 2557 // there is no way we can match. Not even case independent |
| 2558 // matching can turn an ASCII character into non-ASCII or | 2558 // matching can turn an ASCII character into non-ASCII or |
| 2559 // vice versa. | 2559 // vice versa. |
| 2560 details->set_cannot_match(); | 2560 details->set_cannot_match(); |
| 2561 pos->determines_perfectly = false; | 2561 pos->determines_perfectly = false; |
| 2562 return; | 2562 return; |
| 2563 } | 2563 } |
| 2564 if (compiler->ignore_case()) { | 2564 if (compiler->ignore_case()) { |
| 2565 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; | 2565 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; |
| 2566 int length = GetCaseIndependentLetters(isolate, c, compiler->ascii(), | 2566 int length = GetCaseIndependentLetters(isolate, c, compiler->ascii(), |
| 2567 chars); | 2567 chars); |
| 2568 ASSERT(length != 0); // Can only happen if c > char_mask (see above). | 2568 DCHECK(length != 0); // Can only happen if c > char_mask (see above). |
| 2569 if (length == 1) { | 2569 if (length == 1) { |
| 2570 // This letter has no case equivalents, so it's nice and simple | 2570 // This letter has no case equivalents, so it's nice and simple |
| 2571 // and the mask-compare will determine definitely whether we have | 2571 // and the mask-compare will determine definitely whether we have |
| 2572 // a match at this character position. | 2572 // a match at this character position. |
| 2573 pos->mask = char_mask; | 2573 pos->mask = char_mask; |
| 2574 pos->value = c; | 2574 pos->value = c; |
| 2575 pos->determines_perfectly = true; | 2575 pos->determines_perfectly = true; |
| 2576 } else { | 2576 } else { |
| 2577 uint32_t common_bits = char_mask; | 2577 uint32_t common_bits = char_mask; |
| 2578 uint32_t bits = chars[0]; | 2578 uint32_t bits = chars[0]; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2594 } | 2594 } |
| 2595 } else { | 2595 } else { |
| 2596 // Don't ignore case. Nice simple case where the mask-compare will | 2596 // Don't ignore case. Nice simple case where the mask-compare will |
| 2597 // determine definitely whether we have a match at this character | 2597 // determine definitely whether we have a match at this character |
| 2598 // position. | 2598 // position. |
| 2599 pos->mask = char_mask; | 2599 pos->mask = char_mask; |
| 2600 pos->value = c; | 2600 pos->value = c; |
| 2601 pos->determines_perfectly = true; | 2601 pos->determines_perfectly = true; |
| 2602 } | 2602 } |
| 2603 characters_filled_in++; | 2603 characters_filled_in++; |
| 2604 ASSERT(characters_filled_in <= details->characters()); | 2604 DCHECK(characters_filled_in <= details->characters()); |
| 2605 if (characters_filled_in == details->characters()) { | 2605 if (characters_filled_in == details->characters()) { |
| 2606 return; | 2606 return; |
| 2607 } | 2607 } |
| 2608 } | 2608 } |
| 2609 } else { | 2609 } else { |
| 2610 QuickCheckDetails::Position* pos = | 2610 QuickCheckDetails::Position* pos = |
| 2611 details->positions(characters_filled_in); | 2611 details->positions(characters_filled_in); |
| 2612 RegExpCharacterClass* tree = elm.char_class(); | 2612 RegExpCharacterClass* tree = elm.char_class(); |
| 2613 ZoneList<CharacterRange>* ranges = tree->ranges(zone()); | 2613 ZoneList<CharacterRange>* ranges = tree->ranges(zone()); |
| 2614 if (tree->is_negated()) { | 2614 if (tree->is_negated()) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2660 common_bits &= new_common_bits; | 2660 common_bits &= new_common_bits; |
| 2661 bits &= new_common_bits; | 2661 bits &= new_common_bits; |
| 2662 uint32_t differing_bits = (from & common_bits) ^ bits; | 2662 uint32_t differing_bits = (from & common_bits) ^ bits; |
| 2663 common_bits ^= differing_bits; | 2663 common_bits ^= differing_bits; |
| 2664 bits &= common_bits; | 2664 bits &= common_bits; |
| 2665 } | 2665 } |
| 2666 pos->mask = common_bits; | 2666 pos->mask = common_bits; |
| 2667 pos->value = bits; | 2667 pos->value = bits; |
| 2668 } | 2668 } |
| 2669 characters_filled_in++; | 2669 characters_filled_in++; |
| 2670 ASSERT(characters_filled_in <= details->characters()); | 2670 DCHECK(characters_filled_in <= details->characters()); |
| 2671 if (characters_filled_in == details->characters()) { | 2671 if (characters_filled_in == details->characters()) { |
| 2672 return; | 2672 return; |
| 2673 } | 2673 } |
| 2674 } | 2674 } |
| 2675 } | 2675 } |
| 2676 ASSERT(characters_filled_in != details->characters()); | 2676 DCHECK(characters_filled_in != details->characters()); |
| 2677 if (!details->cannot_match()) { | 2677 if (!details->cannot_match()) { |
| 2678 on_success()-> GetQuickCheckDetails(details, | 2678 on_success()-> GetQuickCheckDetails(details, |
| 2679 compiler, | 2679 compiler, |
| 2680 characters_filled_in, | 2680 characters_filled_in, |
| 2681 true); | 2681 true); |
| 2682 } | 2682 } |
| 2683 } | 2683 } |
| 2684 | 2684 |
| 2685 | 2685 |
| 2686 void QuickCheckDetails::Clear() { | 2686 void QuickCheckDetails::Clear() { |
| 2687 for (int i = 0; i < characters_; i++) { | 2687 for (int i = 0; i < characters_; i++) { |
| 2688 positions_[i].mask = 0; | 2688 positions_[i].mask = 0; |
| 2689 positions_[i].value = 0; | 2689 positions_[i].value = 0; |
| 2690 positions_[i].determines_perfectly = false; | 2690 positions_[i].determines_perfectly = false; |
| 2691 } | 2691 } |
| 2692 characters_ = 0; | 2692 characters_ = 0; |
| 2693 } | 2693 } |
| 2694 | 2694 |
| 2695 | 2695 |
| 2696 void QuickCheckDetails::Advance(int by, bool ascii) { | 2696 void QuickCheckDetails::Advance(int by, bool ascii) { |
| 2697 ASSERT(by >= 0); | 2697 DCHECK(by >= 0); |
| 2698 if (by >= characters_) { | 2698 if (by >= characters_) { |
| 2699 Clear(); | 2699 Clear(); |
| 2700 return; | 2700 return; |
| 2701 } | 2701 } |
| 2702 for (int i = 0; i < characters_ - by; i++) { | 2702 for (int i = 0; i < characters_ - by; i++) { |
| 2703 positions_[i] = positions_[by + i]; | 2703 positions_[i] = positions_[by + i]; |
| 2704 } | 2704 } |
| 2705 for (int i = characters_ - by; i < characters_; i++) { | 2705 for (int i = characters_ - by; i < characters_; i++) { |
| 2706 positions_[i].mask = 0; | 2706 positions_[i].mask = 0; |
| 2707 positions_[i].value = 0; | 2707 positions_[i].value = 0; |
| 2708 positions_[i].determines_perfectly = false; | 2708 positions_[i].determines_perfectly = false; |
| 2709 } | 2709 } |
| 2710 characters_ -= by; | 2710 characters_ -= by; |
| 2711 // We could change mask_ and value_ here but we would never advance unless | 2711 // We could change mask_ and value_ here but we would never advance unless |
| 2712 // they had already been used in a check and they won't be used again because | 2712 // they had already been used in a check and they won't be used again because |
| 2713 // it would gain us nothing. So there's no point. | 2713 // it would gain us nothing. So there's no point. |
| 2714 } | 2714 } |
| 2715 | 2715 |
| 2716 | 2716 |
| 2717 void QuickCheckDetails::Merge(QuickCheckDetails* other, int from_index) { | 2717 void QuickCheckDetails::Merge(QuickCheckDetails* other, int from_index) { |
| 2718 ASSERT(characters_ == other->characters_); | 2718 DCHECK(characters_ == other->characters_); |
| 2719 if (other->cannot_match_) { | 2719 if (other->cannot_match_) { |
| 2720 return; | 2720 return; |
| 2721 } | 2721 } |
| 2722 if (cannot_match_) { | 2722 if (cannot_match_) { |
| 2723 *this = *other; | 2723 *this = *other; |
| 2724 return; | 2724 return; |
| 2725 } | 2725 } |
| 2726 for (int i = from_index; i < characters_; i++) { | 2726 for (int i = from_index; i < characters_; i++) { |
| 2727 QuickCheckDetails::Position* pos = positions(i); | 2727 QuickCheckDetails::Position* pos = positions(i); |
| 2728 QuickCheckDetails::Position* other_pos = other->positions(i); | 2728 QuickCheckDetails::Position* other_pos = other->positions(i); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2739 uc16 differing_bits = (pos->value ^ other_pos->value); | 2739 uc16 differing_bits = (pos->value ^ other_pos->value); |
| 2740 pos->mask &= ~differing_bits; | 2740 pos->mask &= ~differing_bits; |
| 2741 pos->value &= pos->mask; | 2741 pos->value &= pos->mask; |
| 2742 } | 2742 } |
| 2743 } | 2743 } |
| 2744 | 2744 |
| 2745 | 2745 |
| 2746 class VisitMarker { | 2746 class VisitMarker { |
| 2747 public: | 2747 public: |
| 2748 explicit VisitMarker(NodeInfo* info) : info_(info) { | 2748 explicit VisitMarker(NodeInfo* info) : info_(info) { |
| 2749 ASSERT(!info->visited); | 2749 DCHECK(!info->visited); |
| 2750 info->visited = true; | 2750 info->visited = true; |
| 2751 } | 2751 } |
| 2752 ~VisitMarker() { | 2752 ~VisitMarker() { |
| 2753 info_->visited = false; | 2753 info_->visited = false; |
| 2754 } | 2754 } |
| 2755 private: | 2755 private: |
| 2756 NodeInfo* info_; | 2756 NodeInfo* info_; |
| 2757 }; | 2757 }; |
| 2758 | 2758 |
| 2759 | 2759 |
| 2760 RegExpNode* SeqRegExpNode::FilterASCII(int depth, bool ignore_case) { | 2760 RegExpNode* SeqRegExpNode::FilterASCII(int depth, bool ignore_case) { |
| 2761 if (info()->replacement_calculated) return replacement(); | 2761 if (info()->replacement_calculated) return replacement(); |
| 2762 if (depth < 0) return this; | 2762 if (depth < 0) return this; |
| 2763 ASSERT(!info()->visited); | 2763 DCHECK(!info()->visited); |
| 2764 VisitMarker marker(info()); | 2764 VisitMarker marker(info()); |
| 2765 return FilterSuccessor(depth - 1, ignore_case); | 2765 return FilterSuccessor(depth - 1, ignore_case); |
| 2766 } | 2766 } |
| 2767 | 2767 |
| 2768 | 2768 |
| 2769 RegExpNode* SeqRegExpNode::FilterSuccessor(int depth, bool ignore_case) { | 2769 RegExpNode* SeqRegExpNode::FilterSuccessor(int depth, bool ignore_case) { |
| 2770 RegExpNode* next = on_success_->FilterASCII(depth - 1, ignore_case); | 2770 RegExpNode* next = on_success_->FilterASCII(depth - 1, ignore_case); |
| 2771 if (next == NULL) return set_replacement(NULL); | 2771 if (next == NULL) return set_replacement(NULL); |
| 2772 on_success_ = next; | 2772 on_success_ = next; |
| 2773 return set_replacement(this); | 2773 return set_replacement(this); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2787 // TODO(dcarney): this could be a lot more efficient. | 2787 // TODO(dcarney): this could be a lot more efficient. |
| 2788 if (RangeContainsLatin1Equivalents(ranges->at(i))) return true; | 2788 if (RangeContainsLatin1Equivalents(ranges->at(i))) return true; |
| 2789 } | 2789 } |
| 2790 return false; | 2790 return false; |
| 2791 } | 2791 } |
| 2792 | 2792 |
| 2793 | 2793 |
| 2794 RegExpNode* TextNode::FilterASCII(int depth, bool ignore_case) { | 2794 RegExpNode* TextNode::FilterASCII(int depth, bool ignore_case) { |
| 2795 if (info()->replacement_calculated) return replacement(); | 2795 if (info()->replacement_calculated) return replacement(); |
| 2796 if (depth < 0) return this; | 2796 if (depth < 0) return this; |
| 2797 ASSERT(!info()->visited); | 2797 DCHECK(!info()->visited); |
| 2798 VisitMarker marker(info()); | 2798 VisitMarker marker(info()); |
| 2799 int element_count = elms_->length(); | 2799 int element_count = elms_->length(); |
| 2800 for (int i = 0; i < element_count; i++) { | 2800 for (int i = 0; i < element_count; i++) { |
| 2801 TextElement elm = elms_->at(i); | 2801 TextElement elm = elms_->at(i); |
| 2802 if (elm.text_type() == TextElement::ATOM) { | 2802 if (elm.text_type() == TextElement::ATOM) { |
| 2803 Vector<const uc16> quarks = elm.atom()->data(); | 2803 Vector<const uc16> quarks = elm.atom()->data(); |
| 2804 for (int j = 0; j < quarks.length(); j++) { | 2804 for (int j = 0; j < quarks.length(); j++) { |
| 2805 uint16_t c = quarks[j]; | 2805 uint16_t c = quarks[j]; |
| 2806 if (c <= String::kMaxOneByteCharCode) continue; | 2806 if (c <= String::kMaxOneByteCharCode) continue; |
| 2807 if (!ignore_case) return set_replacement(NULL); | 2807 if (!ignore_case) return set_replacement(NULL); |
| 2808 // Here, we need to check for characters whose upper and lower cases | 2808 // Here, we need to check for characters whose upper and lower cases |
| 2809 // are outside the Latin-1 range. | 2809 // are outside the Latin-1 range. |
| 2810 uint16_t converted = unibrow::Latin1::ConvertNonLatin1ToLatin1(c); | 2810 uint16_t converted = unibrow::Latin1::ConvertNonLatin1ToLatin1(c); |
| 2811 // Character is outside Latin-1 completely | 2811 // Character is outside Latin-1 completely |
| 2812 if (converted == 0) return set_replacement(NULL); | 2812 if (converted == 0) return set_replacement(NULL); |
| 2813 // Convert quark to Latin-1 in place. | 2813 // Convert quark to Latin-1 in place. |
| 2814 uint16_t* copy = const_cast<uint16_t*>(quarks.start()); | 2814 uint16_t* copy = const_cast<uint16_t*>(quarks.start()); |
| 2815 copy[j] = converted; | 2815 copy[j] = converted; |
| 2816 } | 2816 } |
| 2817 } else { | 2817 } else { |
| 2818 ASSERT(elm.text_type() == TextElement::CHAR_CLASS); | 2818 DCHECK(elm.text_type() == TextElement::CHAR_CLASS); |
| 2819 RegExpCharacterClass* cc = elm.char_class(); | 2819 RegExpCharacterClass* cc = elm.char_class(); |
| 2820 ZoneList<CharacterRange>* ranges = cc->ranges(zone()); | 2820 ZoneList<CharacterRange>* ranges = cc->ranges(zone()); |
| 2821 if (!CharacterRange::IsCanonical(ranges)) { | 2821 if (!CharacterRange::IsCanonical(ranges)) { |
| 2822 CharacterRange::Canonicalize(ranges); | 2822 CharacterRange::Canonicalize(ranges); |
| 2823 } | 2823 } |
| 2824 // Now they are in order so we only need to look at the first. | 2824 // Now they are in order so we only need to look at the first. |
| 2825 int range_count = ranges->length(); | 2825 int range_count = ranges->length(); |
| 2826 if (cc->is_negated()) { | 2826 if (cc->is_negated()) { |
| 2827 if (range_count != 0 && | 2827 if (range_count != 0 && |
| 2828 ranges->at(0).from() == 0 && | 2828 ranges->at(0).from() == 0 && |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2877 return this; | 2877 return this; |
| 2878 } | 2878 } |
| 2879 } | 2879 } |
| 2880 | 2880 |
| 2881 int surviving = 0; | 2881 int surviving = 0; |
| 2882 RegExpNode* survivor = NULL; | 2882 RegExpNode* survivor = NULL; |
| 2883 for (int i = 0; i < choice_count; i++) { | 2883 for (int i = 0; i < choice_count; i++) { |
| 2884 GuardedAlternative alternative = alternatives_->at(i); | 2884 GuardedAlternative alternative = alternatives_->at(i); |
| 2885 RegExpNode* replacement = | 2885 RegExpNode* replacement = |
| 2886 alternative.node()->FilterASCII(depth - 1, ignore_case); | 2886 alternative.node()->FilterASCII(depth - 1, ignore_case); |
| 2887 ASSERT(replacement != this); // No missing EMPTY_MATCH_CHECK. | 2887 DCHECK(replacement != this); // No missing EMPTY_MATCH_CHECK. |
| 2888 if (replacement != NULL) { | 2888 if (replacement != NULL) { |
| 2889 alternatives_->at(i).set_node(replacement); | 2889 alternatives_->at(i).set_node(replacement); |
| 2890 surviving++; | 2890 surviving++; |
| 2891 survivor = replacement; | 2891 survivor = replacement; |
| 2892 } | 2892 } |
| 2893 } | 2893 } |
| 2894 if (surviving < 2) return set_replacement(survivor); | 2894 if (surviving < 2) return set_replacement(survivor); |
| 2895 | 2895 |
| 2896 set_replacement(this); | 2896 set_replacement(this); |
| 2897 if (surviving == choice_count) { | 2897 if (surviving == choice_count) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2963 SaveBMInfo(bm, not_at_start, offset); | 2963 SaveBMInfo(bm, not_at_start, offset); |
| 2964 } | 2964 } |
| 2965 | 2965 |
| 2966 | 2966 |
| 2967 void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, | 2967 void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, |
| 2968 RegExpCompiler* compiler, | 2968 RegExpCompiler* compiler, |
| 2969 int characters_filled_in, | 2969 int characters_filled_in, |
| 2970 bool not_at_start) { | 2970 bool not_at_start) { |
| 2971 not_at_start = (not_at_start || not_at_start_); | 2971 not_at_start = (not_at_start || not_at_start_); |
| 2972 int choice_count = alternatives_->length(); | 2972 int choice_count = alternatives_->length(); |
| 2973 ASSERT(choice_count > 0); | 2973 DCHECK(choice_count > 0); |
| 2974 alternatives_->at(0).node()->GetQuickCheckDetails(details, | 2974 alternatives_->at(0).node()->GetQuickCheckDetails(details, |
| 2975 compiler, | 2975 compiler, |
| 2976 characters_filled_in, | 2976 characters_filled_in, |
| 2977 not_at_start); | 2977 not_at_start); |
| 2978 for (int i = 1; i < choice_count; i++) { | 2978 for (int i = 1; i < choice_count; i++) { |
| 2979 QuickCheckDetails new_details(details->characters()); | 2979 QuickCheckDetails new_details(details->characters()); |
| 2980 RegExpNode* node = alternatives_->at(i).node(); | 2980 RegExpNode* node = alternatives_->at(i).node(); |
| 2981 node->GetQuickCheckDetails(&new_details, compiler, | 2981 node->GetQuickCheckDetails(&new_details, compiler, |
| 2982 characters_filled_in, | 2982 characters_filled_in, |
| 2983 not_at_start); | 2983 not_at_start); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3087 Label ok; | 3087 Label ok; |
| 3088 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord); | 3088 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord); |
| 3089 assembler->GoTo(&ok); | 3089 assembler->GoTo(&ok); |
| 3090 | 3090 |
| 3091 assembler->Bind(&before_word); | 3091 assembler->Bind(&before_word); |
| 3092 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord); | 3092 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord); |
| 3093 assembler->Bind(&ok); | 3093 assembler->Bind(&ok); |
| 3094 } else if (next_is_word_character == Trace::TRUE_VALUE) { | 3094 } else if (next_is_word_character == Trace::TRUE_VALUE) { |
| 3095 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord); | 3095 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsWord : kIsNonWord); |
| 3096 } else { | 3096 } else { |
| 3097 ASSERT(next_is_word_character == Trace::FALSE_VALUE); | 3097 DCHECK(next_is_word_character == Trace::FALSE_VALUE); |
| 3098 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord); | 3098 BacktrackIfPrevious(compiler, trace, at_boundary ? kIsNonWord : kIsWord); |
| 3099 } | 3099 } |
| 3100 } | 3100 } |
| 3101 | 3101 |
| 3102 | 3102 |
| 3103 void AssertionNode::BacktrackIfPrevious( | 3103 void AssertionNode::BacktrackIfPrevious( |
| 3104 RegExpCompiler* compiler, | 3104 RegExpCompiler* compiler, |
| 3105 Trace* trace, | 3105 Trace* trace, |
| 3106 AssertionNode::IfPrevious backtrack_if_previous) { | 3106 AssertionNode::IfPrevious backtrack_if_previous) { |
| 3107 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 3107 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3243 TextElement elm = elms_->at(i); | 3243 TextElement elm = elms_->at(i); |
| 3244 int cp_offset = trace->cp_offset() + elm.cp_offset(); | 3244 int cp_offset = trace->cp_offset() + elm.cp_offset(); |
| 3245 if (elm.text_type() == TextElement::ATOM) { | 3245 if (elm.text_type() == TextElement::ATOM) { |
| 3246 Vector<const uc16> quarks = elm.atom()->data(); | 3246 Vector<const uc16> quarks = elm.atom()->data(); |
| 3247 for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) { | 3247 for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) { |
| 3248 if (first_element_checked && i == 0 && j == 0) continue; | 3248 if (first_element_checked && i == 0 && j == 0) continue; |
| 3249 if (DeterminedAlready(quick_check, elm.cp_offset() + j)) continue; | 3249 if (DeterminedAlready(quick_check, elm.cp_offset() + j)) continue; |
| 3250 EmitCharacterFunction* emit_function = NULL; | 3250 EmitCharacterFunction* emit_function = NULL; |
| 3251 switch (pass) { | 3251 switch (pass) { |
| 3252 case NON_ASCII_MATCH: | 3252 case NON_ASCII_MATCH: |
| 3253 ASSERT(ascii); | 3253 DCHECK(ascii); |
| 3254 if (quarks[j] > String::kMaxOneByteCharCode) { | 3254 if (quarks[j] > String::kMaxOneByteCharCode) { |
| 3255 assembler->GoTo(backtrack); | 3255 assembler->GoTo(backtrack); |
| 3256 return; | 3256 return; |
| 3257 } | 3257 } |
| 3258 break; | 3258 break; |
| 3259 case NON_LETTER_CHARACTER_MATCH: | 3259 case NON_LETTER_CHARACTER_MATCH: |
| 3260 emit_function = &EmitAtomNonLetter; | 3260 emit_function = &EmitAtomNonLetter; |
| 3261 break; | 3261 break; |
| 3262 case SIMPLE_CHARACTER_MATCH: | 3262 case SIMPLE_CHARACTER_MATCH: |
| 3263 emit_function = &EmitSimpleCharacter; | 3263 emit_function = &EmitSimpleCharacter; |
| 3264 break; | 3264 break; |
| 3265 case CASE_CHARACTER_MATCH: | 3265 case CASE_CHARACTER_MATCH: |
| 3266 emit_function = &EmitAtomLetter; | 3266 emit_function = &EmitAtomLetter; |
| 3267 break; | 3267 break; |
| 3268 default: | 3268 default: |
| 3269 break; | 3269 break; |
| 3270 } | 3270 } |
| 3271 if (emit_function != NULL) { | 3271 if (emit_function != NULL) { |
| 3272 bool bound_checked = emit_function(isolate, | 3272 bool bound_checked = emit_function(isolate, |
| 3273 compiler, | 3273 compiler, |
| 3274 quarks[j], | 3274 quarks[j], |
| 3275 backtrack, | 3275 backtrack, |
| 3276 cp_offset + j, | 3276 cp_offset + j, |
| 3277 *checked_up_to < cp_offset + j, | 3277 *checked_up_to < cp_offset + j, |
| 3278 preloaded); | 3278 preloaded); |
| 3279 if (bound_checked) UpdateBoundsCheck(cp_offset + j, checked_up_to); | 3279 if (bound_checked) UpdateBoundsCheck(cp_offset + j, checked_up_to); |
| 3280 } | 3280 } |
| 3281 } | 3281 } |
| 3282 } else { | 3282 } else { |
| 3283 ASSERT_EQ(TextElement::CHAR_CLASS, elm.text_type()); | 3283 DCHECK_EQ(TextElement::CHAR_CLASS, elm.text_type()); |
| 3284 if (pass == CHARACTER_CLASS_MATCH) { | 3284 if (pass == CHARACTER_CLASS_MATCH) { |
| 3285 if (first_element_checked && i == 0) continue; | 3285 if (first_element_checked && i == 0) continue; |
| 3286 if (DeterminedAlready(quick_check, elm.cp_offset())) continue; | 3286 if (DeterminedAlready(quick_check, elm.cp_offset())) continue; |
| 3287 RegExpCharacterClass* cc = elm.char_class(); | 3287 RegExpCharacterClass* cc = elm.char_class(); |
| 3288 EmitCharClass(assembler, | 3288 EmitCharClass(assembler, |
| 3289 cc, | 3289 cc, |
| 3290 ascii, | 3290 ascii, |
| 3291 backtrack, | 3291 backtrack, |
| 3292 cp_offset, | 3292 cp_offset, |
| 3293 *checked_up_to < cp_offset, | 3293 *checked_up_to < cp_offset, |
| 3294 preloaded, | 3294 preloaded, |
| 3295 zone()); | 3295 zone()); |
| 3296 UpdateBoundsCheck(cp_offset, checked_up_to); | 3296 UpdateBoundsCheck(cp_offset, checked_up_to); |
| 3297 } | 3297 } |
| 3298 } | 3298 } |
| 3299 } | 3299 } |
| 3300 } | 3300 } |
| 3301 | 3301 |
| 3302 | 3302 |
| 3303 int TextNode::Length() { | 3303 int TextNode::Length() { |
| 3304 TextElement elm = elms_->last(); | 3304 TextElement elm = elms_->last(); |
| 3305 ASSERT(elm.cp_offset() >= 0); | 3305 DCHECK(elm.cp_offset() >= 0); |
| 3306 return elm.cp_offset() + elm.length(); | 3306 return elm.cp_offset() + elm.length(); |
| 3307 } | 3307 } |
| 3308 | 3308 |
| 3309 | 3309 |
| 3310 bool TextNode::SkipPass(int int_pass, bool ignore_case) { | 3310 bool TextNode::SkipPass(int int_pass, bool ignore_case) { |
| 3311 TextEmitPassType pass = static_cast<TextEmitPassType>(int_pass); | 3311 TextEmitPassType pass = static_cast<TextEmitPassType>(int_pass); |
| 3312 if (ignore_case) { | 3312 if (ignore_case) { |
| 3313 return pass == SIMPLE_CHARACTER_MATCH; | 3313 return pass == SIMPLE_CHARACTER_MATCH; |
| 3314 } else { | 3314 } else { |
| 3315 return pass == NON_LETTER_CHARACTER_MATCH || pass == CASE_CHARACTER_MATCH; | 3315 return pass == NON_LETTER_CHARACTER_MATCH || pass == CASE_CHARACTER_MATCH; |
| 3316 } | 3316 } |
| 3317 } | 3317 } |
| 3318 | 3318 |
| 3319 | 3319 |
| 3320 // This generates the code to match a text node. A text node can contain | 3320 // This generates the code to match a text node. A text node can contain |
| 3321 // straight character sequences (possibly to be matched in a case-independent | 3321 // straight character sequences (possibly to be matched in a case-independent |
| 3322 // way) and character classes. For efficiency we do not do this in a single | 3322 // way) and character classes. For efficiency we do not do this in a single |
| 3323 // pass from left to right. Instead we pass over the text node several times, | 3323 // pass from left to right. Instead we pass over the text node several times, |
| 3324 // emitting code for some character positions every time. See the comment on | 3324 // emitting code for some character positions every time. See the comment on |
| 3325 // TextEmitPass for details. | 3325 // TextEmitPass for details. |
| 3326 void TextNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 3326 void TextNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 3327 LimitResult limit_result = LimitVersions(compiler, trace); | 3327 LimitResult limit_result = LimitVersions(compiler, trace); |
| 3328 if (limit_result == DONE) return; | 3328 if (limit_result == DONE) return; |
| 3329 ASSERT(limit_result == CONTINUE); | 3329 DCHECK(limit_result == CONTINUE); |
| 3330 | 3330 |
| 3331 if (trace->cp_offset() + Length() > RegExpMacroAssembler::kMaxCPOffset) { | 3331 if (trace->cp_offset() + Length() > RegExpMacroAssembler::kMaxCPOffset) { |
| 3332 compiler->SetRegExpTooBig(); | 3332 compiler->SetRegExpTooBig(); |
| 3333 return; | 3333 return; |
| 3334 } | 3334 } |
| 3335 | 3335 |
| 3336 if (compiler->ascii()) { | 3336 if (compiler->ascii()) { |
| 3337 int dummy = 0; | 3337 int dummy = 0; |
| 3338 TextEmitPass(compiler, NON_ASCII_MATCH, false, trace, false, &dummy); | 3338 TextEmitPass(compiler, NON_ASCII_MATCH, false, trace, false, &dummy); |
| 3339 } | 3339 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3376 on_success()->Emit(compiler, &successor_trace); | 3376 on_success()->Emit(compiler, &successor_trace); |
| 3377 } | 3377 } |
| 3378 | 3378 |
| 3379 | 3379 |
| 3380 void Trace::InvalidateCurrentCharacter() { | 3380 void Trace::InvalidateCurrentCharacter() { |
| 3381 characters_preloaded_ = 0; | 3381 characters_preloaded_ = 0; |
| 3382 } | 3382 } |
| 3383 | 3383 |
| 3384 | 3384 |
| 3385 void Trace::AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler) { | 3385 void Trace::AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler) { |
| 3386 ASSERT(by > 0); | 3386 DCHECK(by > 0); |
| 3387 // We don't have an instruction for shifting the current character register | 3387 // We don't have an instruction for shifting the current character register |
| 3388 // down or for using a shifted value for anything so lets just forget that | 3388 // down or for using a shifted value for anything so lets just forget that |
| 3389 // we preloaded any characters into it. | 3389 // we preloaded any characters into it. |
| 3390 characters_preloaded_ = 0; | 3390 characters_preloaded_ = 0; |
| 3391 // Adjust the offsets of the quick check performed information. This | 3391 // Adjust the offsets of the quick check performed information. This |
| 3392 // information is used to find out what we already determined about the | 3392 // information is used to find out what we already determined about the |
| 3393 // characters by means of mask and compare. | 3393 // characters by means of mask and compare. |
| 3394 quick_check_performed_.Advance(by, compiler->ascii()); | 3394 quick_check_performed_.Advance(by, compiler->ascii()); |
| 3395 cp_offset_ += by; | 3395 cp_offset_ += by; |
| 3396 if (cp_offset_ > RegExpMacroAssembler::kMaxCPOffset) { | 3396 if (cp_offset_ > RegExpMacroAssembler::kMaxCPOffset) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3471 } | 3471 } |
| 3472 length += node_length; | 3472 length += node_length; |
| 3473 SeqRegExpNode* seq_node = static_cast<SeqRegExpNode*>(node); | 3473 SeqRegExpNode* seq_node = static_cast<SeqRegExpNode*>(node); |
| 3474 node = seq_node->on_success(); | 3474 node = seq_node->on_success(); |
| 3475 } | 3475 } |
| 3476 return length; | 3476 return length; |
| 3477 } | 3477 } |
| 3478 | 3478 |
| 3479 | 3479 |
| 3480 void LoopChoiceNode::AddLoopAlternative(GuardedAlternative alt) { | 3480 void LoopChoiceNode::AddLoopAlternative(GuardedAlternative alt) { |
| 3481 ASSERT_EQ(loop_node_, NULL); | 3481 DCHECK_EQ(loop_node_, NULL); |
| 3482 AddAlternative(alt); | 3482 AddAlternative(alt); |
| 3483 loop_node_ = alt.node(); | 3483 loop_node_ = alt.node(); |
| 3484 } | 3484 } |
| 3485 | 3485 |
| 3486 | 3486 |
| 3487 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { | 3487 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { |
| 3488 ASSERT_EQ(continue_node_, NULL); | 3488 DCHECK_EQ(continue_node_, NULL); |
| 3489 AddAlternative(alt); | 3489 AddAlternative(alt); |
| 3490 continue_node_ = alt.node(); | 3490 continue_node_ = alt.node(); |
| 3491 } | 3491 } |
| 3492 | 3492 |
| 3493 | 3493 |
| 3494 void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 3494 void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 3495 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 3495 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 3496 if (trace->stop_node() == this) { | 3496 if (trace->stop_node() == this) { |
| 3497 int text_length = | 3497 int text_length = |
| 3498 GreedyLoopTextLengthForAlternative(&(alternatives_->at(0))); | 3498 GreedyLoopTextLengthForAlternative(&(alternatives_->at(0))); |
| 3499 ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); | 3499 DCHECK(text_length != kNodeIsTooComplexForGreedyLoops); |
| 3500 // Update the counter-based backtracking info on the stack. This is an | 3500 // Update the counter-based backtracking info on the stack. This is an |
| 3501 // optimization for greedy loops (see below). | 3501 // optimization for greedy loops (see below). |
| 3502 ASSERT(trace->cp_offset() == text_length); | 3502 DCHECK(trace->cp_offset() == text_length); |
| 3503 macro_assembler->AdvanceCurrentPosition(text_length); | 3503 macro_assembler->AdvanceCurrentPosition(text_length); |
| 3504 macro_assembler->GoTo(trace->loop_label()); | 3504 macro_assembler->GoTo(trace->loop_label()); |
| 3505 return; | 3505 return; |
| 3506 } | 3506 } |
| 3507 ASSERT(trace->stop_node() == NULL); | 3507 DCHECK(trace->stop_node() == NULL); |
| 3508 if (!trace->is_trivial()) { | 3508 if (!trace->is_trivial()) { |
| 3509 trace->Flush(compiler, this); | 3509 trace->Flush(compiler, this); |
| 3510 return; | 3510 return; |
| 3511 } | 3511 } |
| 3512 ChoiceNode::Emit(compiler, trace); | 3512 ChoiceNode::Emit(compiler, trace); |
| 3513 } | 3513 } |
| 3514 | 3514 |
| 3515 | 3515 |
| 3516 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler, | 3516 int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler, |
| 3517 int eats_at_least) { | 3517 int eats_at_least) { |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3807 masm->AdvanceCurrentPosition(lookahead_width); | 3807 masm->AdvanceCurrentPosition(lookahead_width); |
| 3808 masm->GoTo(&again); | 3808 masm->GoTo(&again); |
| 3809 masm->Bind(&cont); | 3809 masm->Bind(&cont); |
| 3810 return true; | 3810 return true; |
| 3811 } | 3811 } |
| 3812 | 3812 |
| 3813 Factory* factory = masm->zone()->isolate()->factory(); | 3813 Factory* factory = masm->zone()->isolate()->factory(); |
| 3814 Handle<ByteArray> boolean_skip_table = factory->NewByteArray(kSize, TENURED); | 3814 Handle<ByteArray> boolean_skip_table = factory->NewByteArray(kSize, TENURED); |
| 3815 int skip_distance = GetSkipTable( | 3815 int skip_distance = GetSkipTable( |
| 3816 min_lookahead, max_lookahead, boolean_skip_table); | 3816 min_lookahead, max_lookahead, boolean_skip_table); |
| 3817 ASSERT(skip_distance != 0); | 3817 DCHECK(skip_distance != 0); |
| 3818 | 3818 |
| 3819 Label cont, again; | 3819 Label cont, again; |
| 3820 masm->Bind(&again); | 3820 masm->Bind(&again); |
| 3821 masm->LoadCurrentCharacter(max_lookahead, &cont, true); | 3821 masm->LoadCurrentCharacter(max_lookahead, &cont, true); |
| 3822 masm->CheckBitInTable(boolean_skip_table, &cont); | 3822 masm->CheckBitInTable(boolean_skip_table, &cont); |
| 3823 masm->AdvanceCurrentPosition(skip_distance); | 3823 masm->AdvanceCurrentPosition(skip_distance); |
| 3824 masm->GoTo(&again); | 3824 masm->GoTo(&again); |
| 3825 masm->Bind(&cont); | 3825 masm->Bind(&cont); |
| 3826 | 3826 |
| 3827 return true; | 3827 return true; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3908 | 3908 |
| 3909 void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 3909 void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 3910 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 3910 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 3911 int choice_count = alternatives_->length(); | 3911 int choice_count = alternatives_->length(); |
| 3912 #ifdef DEBUG | 3912 #ifdef DEBUG |
| 3913 for (int i = 0; i < choice_count - 1; i++) { | 3913 for (int i = 0; i < choice_count - 1; i++) { |
| 3914 GuardedAlternative alternative = alternatives_->at(i); | 3914 GuardedAlternative alternative = alternatives_->at(i); |
| 3915 ZoneList<Guard*>* guards = alternative.guards(); | 3915 ZoneList<Guard*>* guards = alternative.guards(); |
| 3916 int guard_count = (guards == NULL) ? 0 : guards->length(); | 3916 int guard_count = (guards == NULL) ? 0 : guards->length(); |
| 3917 for (int j = 0; j < guard_count; j++) { | 3917 for (int j = 0; j < guard_count; j++) { |
| 3918 ASSERT(!trace->mentions_reg(guards->at(j)->reg())); | 3918 DCHECK(!trace->mentions_reg(guards->at(j)->reg())); |
| 3919 } | 3919 } |
| 3920 } | 3920 } |
| 3921 #endif | 3921 #endif |
| 3922 | 3922 |
| 3923 LimitResult limit_result = LimitVersions(compiler, trace); | 3923 LimitResult limit_result = LimitVersions(compiler, trace); |
| 3924 if (limit_result == DONE) return; | 3924 if (limit_result == DONE) return; |
| 3925 ASSERT(limit_result == CONTINUE); | 3925 DCHECK(limit_result == CONTINUE); |
| 3926 | 3926 |
| 3927 int new_flush_budget = trace->flush_budget() / choice_count; | 3927 int new_flush_budget = trace->flush_budget() / choice_count; |
| 3928 if (trace->flush_budget() == 0 && trace->actions() != NULL) { | 3928 if (trace->flush_budget() == 0 && trace->actions() != NULL) { |
| 3929 trace->Flush(compiler, this); | 3929 trace->Flush(compiler, this); |
| 3930 return; | 3930 return; |
| 3931 } | 3931 } |
| 3932 | 3932 |
| 3933 RecursionCheck rc(compiler); | 3933 RecursionCheck rc(compiler); |
| 3934 | 3934 |
| 3935 Trace* current_trace = trace; | 3935 Trace* current_trace = trace; |
| 3936 | 3936 |
| 3937 int text_length = GreedyLoopTextLengthForAlternative(&(alternatives_->at(0))); | 3937 int text_length = GreedyLoopTextLengthForAlternative(&(alternatives_->at(0))); |
| 3938 bool greedy_loop = false; | 3938 bool greedy_loop = false; |
| 3939 Label greedy_loop_label; | 3939 Label greedy_loop_label; |
| 3940 Trace counter_backtrack_trace; | 3940 Trace counter_backtrack_trace; |
| 3941 counter_backtrack_trace.set_backtrack(&greedy_loop_label); | 3941 counter_backtrack_trace.set_backtrack(&greedy_loop_label); |
| 3942 if (not_at_start()) counter_backtrack_trace.set_at_start(false); | 3942 if (not_at_start()) counter_backtrack_trace.set_at_start(false); |
| 3943 | 3943 |
| 3944 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { | 3944 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { |
| 3945 // Here we have special handling for greedy loops containing only text nodes | 3945 // Here we have special handling for greedy loops containing only text nodes |
| 3946 // and other simple nodes. These are handled by pushing the current | 3946 // and other simple nodes. These are handled by pushing the current |
| 3947 // position on the stack and then incrementing the current position each | 3947 // position on the stack and then incrementing the current position each |
| 3948 // time around the switch. On backtrack we decrement the current position | 3948 // time around the switch. On backtrack we decrement the current position |
| 3949 // and check it against the pushed value. This avoids pushing backtrack | 3949 // and check it against the pushed value. This avoids pushing backtrack |
| 3950 // information for each iteration of the loop, which could take up a lot of | 3950 // information for each iteration of the loop, which could take up a lot of |
| 3951 // space. | 3951 // space. |
| 3952 greedy_loop = true; | 3952 greedy_loop = true; |
| 3953 ASSERT(trace->stop_node() == NULL); | 3953 DCHECK(trace->stop_node() == NULL); |
| 3954 macro_assembler->PushCurrentPosition(); | 3954 macro_assembler->PushCurrentPosition(); |
| 3955 current_trace = &counter_backtrack_trace; | 3955 current_trace = &counter_backtrack_trace; |
| 3956 Label greedy_match_failed; | 3956 Label greedy_match_failed; |
| 3957 Trace greedy_match_trace; | 3957 Trace greedy_match_trace; |
| 3958 if (not_at_start()) greedy_match_trace.set_at_start(false); | 3958 if (not_at_start()) greedy_match_trace.set_at_start(false); |
| 3959 greedy_match_trace.set_backtrack(&greedy_match_failed); | 3959 greedy_match_trace.set_backtrack(&greedy_match_failed); |
| 3960 Label loop_label; | 3960 Label loop_label; |
| 3961 macro_assembler->Bind(&loop_label); | 3961 macro_assembler->Bind(&loop_label); |
| 3962 greedy_match_trace.set_stop_node(this); | 3962 greedy_match_trace.set_stop_node(this); |
| 3963 greedy_match_trace.set_loop_label(&loop_label); | 3963 greedy_match_trace.set_loop_label(&loop_label); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3982 RegExpNode* eats_anything_node = alt1.node(); | 3982 RegExpNode* eats_anything_node = alt1.node(); |
| 3983 if (eats_anything_node->GetSuccessorOfOmnivorousTextNode(compiler) == | 3983 if (eats_anything_node->GetSuccessorOfOmnivorousTextNode(compiler) == |
| 3984 this) { | 3984 this) { |
| 3985 // At this point we know that we are at a non-greedy loop that will eat | 3985 // At this point we know that we are at a non-greedy loop that will eat |
| 3986 // any character one at a time. Any non-anchored regexp has such a | 3986 // any character one at a time. Any non-anchored regexp has such a |
| 3987 // loop prepended to it in order to find where it starts. We look for | 3987 // loop prepended to it in order to find where it starts. We look for |
| 3988 // a pattern of the form ...abc... where we can look 6 characters ahead | 3988 // a pattern of the form ...abc... where we can look 6 characters ahead |
| 3989 // and step forwards 3 if the character is not one of abc. Abc need | 3989 // and step forwards 3 if the character is not one of abc. Abc need |
| 3990 // not be atoms, they can be any reasonably limited character class or | 3990 // not be atoms, they can be any reasonably limited character class or |
| 3991 // small alternation. | 3991 // small alternation. |
| 3992 ASSERT(trace->is_trivial()); // This is the case on LoopChoiceNodes. | 3992 DCHECK(trace->is_trivial()); // This is the case on LoopChoiceNodes. |
| 3993 BoyerMooreLookahead* lookahead = bm_info(not_at_start); | 3993 BoyerMooreLookahead* lookahead = bm_info(not_at_start); |
| 3994 if (lookahead == NULL) { | 3994 if (lookahead == NULL) { |
| 3995 eats_at_least = Min(kMaxLookaheadForBoyerMoore, | 3995 eats_at_least = Min(kMaxLookaheadForBoyerMoore, |
| 3996 EatsAtLeast(kMaxLookaheadForBoyerMoore, | 3996 EatsAtLeast(kMaxLookaheadForBoyerMoore, |
| 3997 kRecursionBudget, | 3997 kRecursionBudget, |
| 3998 not_at_start)); | 3998 not_at_start)); |
| 3999 if (eats_at_least >= 1) { | 3999 if (eats_at_least >= 1) { |
| 4000 BoyerMooreLookahead* bm = | 4000 BoyerMooreLookahead* bm = |
| 4001 new(zone()) BoyerMooreLookahead(eats_at_least, | 4001 new(zone()) BoyerMooreLookahead(eats_at_least, |
| 4002 compiler, | 4002 compiler, |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4167 } | 4167 } |
| 4168 alternative.node()->Emit(compiler, &out_of_line_trace); | 4168 alternative.node()->Emit(compiler, &out_of_line_trace); |
| 4169 } | 4169 } |
| 4170 } | 4170 } |
| 4171 | 4171 |
| 4172 | 4172 |
| 4173 void ActionNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 4173 void ActionNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 4174 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 4174 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 4175 LimitResult limit_result = LimitVersions(compiler, trace); | 4175 LimitResult limit_result = LimitVersions(compiler, trace); |
| 4176 if (limit_result == DONE) return; | 4176 if (limit_result == DONE) return; |
| 4177 ASSERT(limit_result == CONTINUE); | 4177 DCHECK(limit_result == CONTINUE); |
| 4178 | 4178 |
| 4179 RecursionCheck rc(compiler); | 4179 RecursionCheck rc(compiler); |
| 4180 | 4180 |
| 4181 switch (action_type_) { | 4181 switch (action_type_) { |
| 4182 case STORE_POSITION: { | 4182 case STORE_POSITION: { |
| 4183 Trace::DeferredCapture | 4183 Trace::DeferredCapture |
| 4184 new_capture(data_.u_position_register.reg, | 4184 new_capture(data_.u_position_register.reg, |
| 4185 data_.u_position_register.is_capture, | 4185 data_.u_position_register.is_capture, |
| 4186 trace); | 4186 trace); |
| 4187 Trace new_trace = *trace; | 4187 Trace new_trace = *trace; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4275 int clear_registers_from = data_.u_submatch.clear_register_from; | 4275 int clear_registers_from = data_.u_submatch.clear_register_from; |
| 4276 Label clear_registers_backtrack; | 4276 Label clear_registers_backtrack; |
| 4277 Trace new_trace = *trace; | 4277 Trace new_trace = *trace; |
| 4278 new_trace.set_backtrack(&clear_registers_backtrack); | 4278 new_trace.set_backtrack(&clear_registers_backtrack); |
| 4279 on_success()->Emit(compiler, &new_trace); | 4279 on_success()->Emit(compiler, &new_trace); |
| 4280 | 4280 |
| 4281 assembler->Bind(&clear_registers_backtrack); | 4281 assembler->Bind(&clear_registers_backtrack); |
| 4282 int clear_registers_to = clear_registers_from + clear_register_count - 1; | 4282 int clear_registers_to = clear_registers_from + clear_register_count - 1; |
| 4283 assembler->ClearRegisters(clear_registers_from, clear_registers_to); | 4283 assembler->ClearRegisters(clear_registers_from, clear_registers_to); |
| 4284 | 4284 |
| 4285 ASSERT(trace->backtrack() == NULL); | 4285 DCHECK(trace->backtrack() == NULL); |
| 4286 assembler->Backtrack(); | 4286 assembler->Backtrack(); |
| 4287 return; | 4287 return; |
| 4288 } | 4288 } |
| 4289 default: | 4289 default: |
| 4290 UNREACHABLE(); | 4290 UNREACHABLE(); |
| 4291 } | 4291 } |
| 4292 } | 4292 } |
| 4293 | 4293 |
| 4294 | 4294 |
| 4295 void BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) { | 4295 void BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) { |
| 4296 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 4296 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 4297 if (!trace->is_trivial()) { | 4297 if (!trace->is_trivial()) { |
| 4298 trace->Flush(compiler, this); | 4298 trace->Flush(compiler, this); |
| 4299 return; | 4299 return; |
| 4300 } | 4300 } |
| 4301 | 4301 |
| 4302 LimitResult limit_result = LimitVersions(compiler, trace); | 4302 LimitResult limit_result = LimitVersions(compiler, trace); |
| 4303 if (limit_result == DONE) return; | 4303 if (limit_result == DONE) return; |
| 4304 ASSERT(limit_result == CONTINUE); | 4304 DCHECK(limit_result == CONTINUE); |
| 4305 | 4305 |
| 4306 RecursionCheck rc(compiler); | 4306 RecursionCheck rc(compiler); |
| 4307 | 4307 |
| 4308 ASSERT_EQ(start_reg_ + 1, end_reg_); | 4308 DCHECK_EQ(start_reg_ + 1, end_reg_); |
| 4309 if (compiler->ignore_case()) { | 4309 if (compiler->ignore_case()) { |
| 4310 assembler->CheckNotBackReferenceIgnoreCase(start_reg_, | 4310 assembler->CheckNotBackReferenceIgnoreCase(start_reg_, |
| 4311 trace->backtrack()); | 4311 trace->backtrack()); |
| 4312 } else { | 4312 } else { |
| 4313 assembler->CheckNotBackReference(start_reg_, trace->backtrack()); | 4313 assembler->CheckNotBackReference(start_reg_, trace->backtrack()); |
| 4314 } | 4314 } |
| 4315 on_success()->Emit(compiler, trace); | 4315 on_success()->Emit(compiler, trace); |
| 4316 } | 4316 } |
| 4317 | 4317 |
| 4318 | 4318 |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4679 RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler, | 4679 RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler, |
| 4680 RegExpNode* on_success) { | 4680 RegExpNode* on_success) { |
| 4681 return new(compiler->zone()) TextNode(elements(), on_success); | 4681 return new(compiler->zone()) TextNode(elements(), on_success); |
| 4682 } | 4682 } |
| 4683 | 4683 |
| 4684 | 4684 |
| 4685 static bool CompareInverseRanges(ZoneList<CharacterRange>* ranges, | 4685 static bool CompareInverseRanges(ZoneList<CharacterRange>* ranges, |
| 4686 const int* special_class, | 4686 const int* special_class, |
| 4687 int length) { | 4687 int length) { |
| 4688 length--; // Remove final 0x10000. | 4688 length--; // Remove final 0x10000. |
| 4689 ASSERT(special_class[length] == 0x10000); | 4689 DCHECK(special_class[length] == 0x10000); |
| 4690 ASSERT(ranges->length() != 0); | 4690 DCHECK(ranges->length() != 0); |
| 4691 ASSERT(length != 0); | 4691 DCHECK(length != 0); |
| 4692 ASSERT(special_class[0] != 0); | 4692 DCHECK(special_class[0] != 0); |
| 4693 if (ranges->length() != (length >> 1) + 1) { | 4693 if (ranges->length() != (length >> 1) + 1) { |
| 4694 return false; | 4694 return false; |
| 4695 } | 4695 } |
| 4696 CharacterRange range = ranges->at(0); | 4696 CharacterRange range = ranges->at(0); |
| 4697 if (range.from() != 0) { | 4697 if (range.from() != 0) { |
| 4698 return false; | 4698 return false; |
| 4699 } | 4699 } |
| 4700 for (int i = 0; i < length; i += 2) { | 4700 for (int i = 0; i < length; i += 2) { |
| 4701 if (special_class[i] != (range.to() + 1)) { | 4701 if (special_class[i] != (range.to() + 1)) { |
| 4702 return false; | 4702 return false; |
| 4703 } | 4703 } |
| 4704 range = ranges->at((i >> 1) + 1); | 4704 range = ranges->at((i >> 1) + 1); |
| 4705 if (special_class[i+1] != range.from()) { | 4705 if (special_class[i+1] != range.from()) { |
| 4706 return false; | 4706 return false; |
| 4707 } | 4707 } |
| 4708 } | 4708 } |
| 4709 if (range.to() != 0xffff) { | 4709 if (range.to() != 0xffff) { |
| 4710 return false; | 4710 return false; |
| 4711 } | 4711 } |
| 4712 return true; | 4712 return true; |
| 4713 } | 4713 } |
| 4714 | 4714 |
| 4715 | 4715 |
| 4716 static bool CompareRanges(ZoneList<CharacterRange>* ranges, | 4716 static bool CompareRanges(ZoneList<CharacterRange>* ranges, |
| 4717 const int* special_class, | 4717 const int* special_class, |
| 4718 int length) { | 4718 int length) { |
| 4719 length--; // Remove final 0x10000. | 4719 length--; // Remove final 0x10000. |
| 4720 ASSERT(special_class[length] == 0x10000); | 4720 DCHECK(special_class[length] == 0x10000); |
| 4721 if (ranges->length() * 2 != length) { | 4721 if (ranges->length() * 2 != length) { |
| 4722 return false; | 4722 return false; |
| 4723 } | 4723 } |
| 4724 for (int i = 0; i < length; i += 2) { | 4724 for (int i = 0; i < length; i += 2) { |
| 4725 CharacterRange range = ranges->at(i >> 1); | 4725 CharacterRange range = ranges->at(i >> 1); |
| 4726 if (range.from() != special_class[i] || | 4726 if (range.from() != special_class[i] || |
| 4727 range.to() != special_class[i + 1] - 1) { | 4727 range.to() != special_class[i + 1] - 1) { |
| 4728 return false; | 4728 return false; |
| 4729 } | 4729 } |
| 4730 } | 4730 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4807 | 4807 |
| 4808 // Scoped object to keep track of how much we unroll quantifier loops in the | 4808 // Scoped object to keep track of how much we unroll quantifier loops in the |
| 4809 // regexp graph generator. | 4809 // regexp graph generator. |
| 4810 class RegExpExpansionLimiter { | 4810 class RegExpExpansionLimiter { |
| 4811 public: | 4811 public: |
| 4812 static const int kMaxExpansionFactor = 6; | 4812 static const int kMaxExpansionFactor = 6; |
| 4813 RegExpExpansionLimiter(RegExpCompiler* compiler, int factor) | 4813 RegExpExpansionLimiter(RegExpCompiler* compiler, int factor) |
| 4814 : compiler_(compiler), | 4814 : compiler_(compiler), |
| 4815 saved_expansion_factor_(compiler->current_expansion_factor()), | 4815 saved_expansion_factor_(compiler->current_expansion_factor()), |
| 4816 ok_to_expand_(saved_expansion_factor_ <= kMaxExpansionFactor) { | 4816 ok_to_expand_(saved_expansion_factor_ <= kMaxExpansionFactor) { |
| 4817 ASSERT(factor > 0); | 4817 DCHECK(factor > 0); |
| 4818 if (ok_to_expand_) { | 4818 if (ok_to_expand_) { |
| 4819 if (factor > kMaxExpansionFactor) { | 4819 if (factor > kMaxExpansionFactor) { |
| 4820 // Avoid integer overflow of the current expansion factor. | 4820 // Avoid integer overflow of the current expansion factor. |
| 4821 ok_to_expand_ = false; | 4821 ok_to_expand_ = false; |
| 4822 compiler->set_current_expansion_factor(kMaxExpansionFactor + 1); | 4822 compiler->set_current_expansion_factor(kMaxExpansionFactor + 1); |
| 4823 } else { | 4823 } else { |
| 4824 int new_factor = saved_expansion_factor_ * factor; | 4824 int new_factor = saved_expansion_factor_ * factor; |
| 4825 ok_to_expand_ = (new_factor <= kMaxExpansionFactor); | 4825 ok_to_expand_ = (new_factor <= kMaxExpansionFactor); |
| 4826 compiler->set_current_expansion_factor(new_factor); | 4826 compiler->set_current_expansion_factor(new_factor); |
| 4827 } | 4827 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4896 // Unroll the forced matches from 0 to min. This can cause chains of | 4896 // Unroll the forced matches from 0 to min. This can cause chains of |
| 4897 // TextNodes (which the parser does not generate). These should be | 4897 // TextNodes (which the parser does not generate). These should be |
| 4898 // combined if it turns out they hinder good code generation. | 4898 // combined if it turns out they hinder good code generation. |
| 4899 for (int i = 0; i < min; i++) { | 4899 for (int i = 0; i < min; i++) { |
| 4900 answer = body->ToNode(compiler, answer); | 4900 answer = body->ToNode(compiler, answer); |
| 4901 } | 4901 } |
| 4902 return answer; | 4902 return answer; |
| 4903 } | 4903 } |
| 4904 } | 4904 } |
| 4905 if (max <= kMaxUnrolledMaxMatches && min == 0) { | 4905 if (max <= kMaxUnrolledMaxMatches && min == 0) { |
| 4906 ASSERT(max > 0); // Due to the 'if' above. | 4906 DCHECK(max > 0); // Due to the 'if' above. |
| 4907 RegExpExpansionLimiter limiter(compiler, max); | 4907 RegExpExpansionLimiter limiter(compiler, max); |
| 4908 if (limiter.ok_to_expand()) { | 4908 if (limiter.ok_to_expand()) { |
| 4909 // Unroll the optional matches up to max. | 4909 // Unroll the optional matches up to max. |
| 4910 RegExpNode* answer = on_success; | 4910 RegExpNode* answer = on_success; |
| 4911 for (int i = 0; i < max; i++) { | 4911 for (int i = 0; i < max; i++) { |
| 4912 ChoiceNode* alternation = new(zone) ChoiceNode(2, zone); | 4912 ChoiceNode* alternation = new(zone) ChoiceNode(2, zone); |
| 4913 if (is_greedy) { | 4913 if (is_greedy) { |
| 4914 alternation->AddAlternative( | 4914 alternation->AddAlternative( |
| 4915 GuardedAlternative(body->ToNode(compiler, answer))); | 4915 GuardedAlternative(body->ToNode(compiler, answer))); |
| 4916 alternation->AddAlternative(GuardedAlternative(on_success)); | 4916 alternation->AddAlternative(GuardedAlternative(on_success)); |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5135 } | 5135 } |
| 5136 return current; | 5136 return current; |
| 5137 } | 5137 } |
| 5138 | 5138 |
| 5139 | 5139 |
| 5140 static void AddClass(const int* elmv, | 5140 static void AddClass(const int* elmv, |
| 5141 int elmc, | 5141 int elmc, |
| 5142 ZoneList<CharacterRange>* ranges, | 5142 ZoneList<CharacterRange>* ranges, |
| 5143 Zone* zone) { | 5143 Zone* zone) { |
| 5144 elmc--; | 5144 elmc--; |
| 5145 ASSERT(elmv[elmc] == 0x10000); | 5145 DCHECK(elmv[elmc] == 0x10000); |
| 5146 for (int i = 0; i < elmc; i += 2) { | 5146 for (int i = 0; i < elmc; i += 2) { |
| 5147 ASSERT(elmv[i] < elmv[i + 1]); | 5147 DCHECK(elmv[i] < elmv[i + 1]); |
| 5148 ranges->Add(CharacterRange(elmv[i], elmv[i + 1] - 1), zone); | 5148 ranges->Add(CharacterRange(elmv[i], elmv[i + 1] - 1), zone); |
| 5149 } | 5149 } |
| 5150 } | 5150 } |
| 5151 | 5151 |
| 5152 | 5152 |
| 5153 static void AddClassNegated(const int *elmv, | 5153 static void AddClassNegated(const int *elmv, |
| 5154 int elmc, | 5154 int elmc, |
| 5155 ZoneList<CharacterRange>* ranges, | 5155 ZoneList<CharacterRange>* ranges, |
| 5156 Zone* zone) { | 5156 Zone* zone) { |
| 5157 elmc--; | 5157 elmc--; |
| 5158 ASSERT(elmv[elmc] == 0x10000); | 5158 DCHECK(elmv[elmc] == 0x10000); |
| 5159 ASSERT(elmv[0] != 0x0000); | 5159 DCHECK(elmv[0] != 0x0000); |
| 5160 ASSERT(elmv[elmc-1] != String::kMaxUtf16CodeUnit); | 5160 DCHECK(elmv[elmc-1] != String::kMaxUtf16CodeUnit); |
| 5161 uc16 last = 0x0000; | 5161 uc16 last = 0x0000; |
| 5162 for (int i = 0; i < elmc; i += 2) { | 5162 for (int i = 0; i < elmc; i += 2) { |
| 5163 ASSERT(last <= elmv[i] - 1); | 5163 DCHECK(last <= elmv[i] - 1); |
| 5164 ASSERT(elmv[i] < elmv[i + 1]); | 5164 DCHECK(elmv[i] < elmv[i + 1]); |
| 5165 ranges->Add(CharacterRange(last, elmv[i] - 1), zone); | 5165 ranges->Add(CharacterRange(last, elmv[i] - 1), zone); |
| 5166 last = elmv[i + 1]; | 5166 last = elmv[i + 1]; |
| 5167 } | 5167 } |
| 5168 ranges->Add(CharacterRange(last, String::kMaxUtf16CodeUnit), zone); | 5168 ranges->Add(CharacterRange(last, String::kMaxUtf16CodeUnit), zone); |
| 5169 } | 5169 } |
| 5170 | 5170 |
| 5171 | 5171 |
| 5172 void CharacterRange::AddClassEscape(uc16 type, | 5172 void CharacterRange::AddClassEscape(uc16 type, |
| 5173 ZoneList<CharacterRange>* ranges, | 5173 ZoneList<CharacterRange>* ranges, |
| 5174 Zone* zone) { | 5174 Zone* zone) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5250 if (*target == NULL) *target = new(zone_) ZoneList<CharacterRange>(2, zone_); | 5250 if (*target == NULL) *target = new(zone_) ZoneList<CharacterRange>(2, zone_); |
| 5251 (*target)->Add(CharacterRange(entry.from(), entry.to()), zone_); | 5251 (*target)->Add(CharacterRange(entry.from(), entry.to()), zone_); |
| 5252 } | 5252 } |
| 5253 | 5253 |
| 5254 | 5254 |
| 5255 void CharacterRange::Split(ZoneList<CharacterRange>* base, | 5255 void CharacterRange::Split(ZoneList<CharacterRange>* base, |
| 5256 Vector<const int> overlay, | 5256 Vector<const int> overlay, |
| 5257 ZoneList<CharacterRange>** included, | 5257 ZoneList<CharacterRange>** included, |
| 5258 ZoneList<CharacterRange>** excluded, | 5258 ZoneList<CharacterRange>** excluded, |
| 5259 Zone* zone) { | 5259 Zone* zone) { |
| 5260 ASSERT_EQ(NULL, *included); | 5260 DCHECK_EQ(NULL, *included); |
| 5261 ASSERT_EQ(NULL, *excluded); | 5261 DCHECK_EQ(NULL, *excluded); |
| 5262 DispatchTable table(zone); | 5262 DispatchTable table(zone); |
| 5263 for (int i = 0; i < base->length(); i++) | 5263 for (int i = 0; i < base->length(); i++) |
| 5264 table.AddRange(base->at(i), CharacterRangeSplitter::kInBase, zone); | 5264 table.AddRange(base->at(i), CharacterRangeSplitter::kInBase, zone); |
| 5265 for (int i = 0; i < overlay.length(); i += 2) { | 5265 for (int i = 0; i < overlay.length(); i += 2) { |
| 5266 table.AddRange(CharacterRange(overlay[i], overlay[i + 1] - 1), | 5266 table.AddRange(CharacterRange(overlay[i], overlay[i + 1] - 1), |
| 5267 CharacterRangeSplitter::kInOverlay, zone); | 5267 CharacterRangeSplitter::kInOverlay, zone); |
| 5268 } | 5268 } |
| 5269 CharacterRangeSplitter callback(included, excluded, zone); | 5269 CharacterRangeSplitter callback(included, excluded, zone); |
| 5270 table.ForEach(&callback); | 5270 table.ForEach(&callback); |
| 5271 } | 5271 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5311 // covered by the range (handling characters that is not in a block | 5311 // covered by the range (handling characters that is not in a block |
| 5312 // as a "singleton block"). | 5312 // as a "singleton block"). |
| 5313 unibrow::uchar range[unibrow::Ecma262UnCanonicalize::kMaxWidth]; | 5313 unibrow::uchar range[unibrow::Ecma262UnCanonicalize::kMaxWidth]; |
| 5314 int pos = bottom; | 5314 int pos = bottom; |
| 5315 while (pos <= top) { | 5315 while (pos <= top) { |
| 5316 int length = isolate->jsregexp_canonrange()->get(pos, '\0', range); | 5316 int length = isolate->jsregexp_canonrange()->get(pos, '\0', range); |
| 5317 uc16 block_end; | 5317 uc16 block_end; |
| 5318 if (length == 0) { | 5318 if (length == 0) { |
| 5319 block_end = pos; | 5319 block_end = pos; |
| 5320 } else { | 5320 } else { |
| 5321 ASSERT_EQ(1, length); | 5321 DCHECK_EQ(1, length); |
| 5322 block_end = range[0]; | 5322 block_end = range[0]; |
| 5323 } | 5323 } |
| 5324 int end = (block_end > top) ? top : block_end; | 5324 int end = (block_end > top) ? top : block_end; |
| 5325 length = isolate->jsregexp_uncanonicalize()->get(block_end, '\0', range); | 5325 length = isolate->jsregexp_uncanonicalize()->get(block_end, '\0', range); |
| 5326 for (int i = 0; i < length; i++) { | 5326 for (int i = 0; i < length; i++) { |
| 5327 uc32 c = range[i]; | 5327 uc32 c = range[i]; |
| 5328 uc16 range_from = c - (block_end - pos); | 5328 uc16 range_from = c - (block_end - pos); |
| 5329 uc16 range_to = c - (block_end - end); | 5329 uc16 range_to = c - (block_end - end); |
| 5330 if (!(bottom <= range_from && range_to <= top)) { | 5330 if (!(bottom <= range_from && range_to <= top)) { |
| 5331 ranges->Add(CharacterRange(range_from, range_to), zone); | 5331 ranges->Add(CharacterRange(range_from, range_to), zone); |
| 5332 } | 5332 } |
| 5333 } | 5333 } |
| 5334 pos = end + 1; | 5334 pos = end + 1; |
| 5335 } | 5335 } |
| 5336 } | 5336 } |
| 5337 } | 5337 } |
| 5338 | 5338 |
| 5339 | 5339 |
| 5340 bool CharacterRange::IsCanonical(ZoneList<CharacterRange>* ranges) { | 5340 bool CharacterRange::IsCanonical(ZoneList<CharacterRange>* ranges) { |
| 5341 ASSERT_NOT_NULL(ranges); | 5341 DCHECK_NOT_NULL(ranges); |
| 5342 int n = ranges->length(); | 5342 int n = ranges->length(); |
| 5343 if (n <= 1) return true; | 5343 if (n <= 1) return true; |
| 5344 int max = ranges->at(0).to(); | 5344 int max = ranges->at(0).to(); |
| 5345 for (int i = 1; i < n; i++) { | 5345 for (int i = 1; i < n; i++) { |
| 5346 CharacterRange next_range = ranges->at(i); | 5346 CharacterRange next_range = ranges->at(i); |
| 5347 if (next_range.from() <= max + 1) return false; | 5347 if (next_range.from() <= max + 1) return false; |
| 5348 max = next_range.to(); | 5348 max = next_range.to(); |
| 5349 } | 5349 } |
| 5350 return true; | 5350 return true; |
| 5351 } | 5351 } |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5471 int read = i; // Range to insert. | 5471 int read = i; // Range to insert. |
| 5472 int num_canonical = i; // Length of canonicalized part of list. | 5472 int num_canonical = i; // Length of canonicalized part of list. |
| 5473 do { | 5473 do { |
| 5474 num_canonical = InsertRangeInCanonicalList(character_ranges, | 5474 num_canonical = InsertRangeInCanonicalList(character_ranges, |
| 5475 num_canonical, | 5475 num_canonical, |
| 5476 character_ranges->at(read)); | 5476 character_ranges->at(read)); |
| 5477 read++; | 5477 read++; |
| 5478 } while (read < n); | 5478 } while (read < n); |
| 5479 character_ranges->Rewind(num_canonical); | 5479 character_ranges->Rewind(num_canonical); |
| 5480 | 5480 |
| 5481 ASSERT(CharacterRange::IsCanonical(character_ranges)); | 5481 DCHECK(CharacterRange::IsCanonical(character_ranges)); |
| 5482 } | 5482 } |
| 5483 | 5483 |
| 5484 | 5484 |
| 5485 void CharacterRange::Negate(ZoneList<CharacterRange>* ranges, | 5485 void CharacterRange::Negate(ZoneList<CharacterRange>* ranges, |
| 5486 ZoneList<CharacterRange>* negated_ranges, | 5486 ZoneList<CharacterRange>* negated_ranges, |
| 5487 Zone* zone) { | 5487 Zone* zone) { |
| 5488 ASSERT(CharacterRange::IsCanonical(ranges)); | 5488 DCHECK(CharacterRange::IsCanonical(ranges)); |
| 5489 ASSERT_EQ(0, negated_ranges->length()); | 5489 DCHECK_EQ(0, negated_ranges->length()); |
| 5490 int range_count = ranges->length(); | 5490 int range_count = ranges->length(); |
| 5491 uc16 from = 0; | 5491 uc16 from = 0; |
| 5492 int i = 0; | 5492 int i = 0; |
| 5493 if (range_count > 0 && ranges->at(0).from() == 0) { | 5493 if (range_count > 0 && ranges->at(0).from() == 0) { |
| 5494 from = ranges->at(0).to(); | 5494 from = ranges->at(0).to(); |
| 5495 i = 1; | 5495 i = 1; |
| 5496 } | 5496 } |
| 5497 while (i < range_count) { | 5497 while (i < range_count) { |
| 5498 CharacterRange range = ranges->at(i); | 5498 CharacterRange range = ranges->at(i); |
| 5499 negated_ranges->Add(CharacterRange(from + 1, range.from() - 1), zone); | 5499 negated_ranges->Add(CharacterRange(from + 1, range.from() - 1), zone); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5555 | 5555 |
| 5556 const uc16 DispatchTable::Config::kNoKey = unibrow::Utf8::kBadChar; | 5556 const uc16 DispatchTable::Config::kNoKey = unibrow::Utf8::kBadChar; |
| 5557 | 5557 |
| 5558 | 5558 |
| 5559 void DispatchTable::AddRange(CharacterRange full_range, int value, | 5559 void DispatchTable::AddRange(CharacterRange full_range, int value, |
| 5560 Zone* zone) { | 5560 Zone* zone) { |
| 5561 CharacterRange current = full_range; | 5561 CharacterRange current = full_range; |
| 5562 if (tree()->is_empty()) { | 5562 if (tree()->is_empty()) { |
| 5563 // If this is the first range we just insert into the table. | 5563 // If this is the first range we just insert into the table. |
| 5564 ZoneSplayTree<Config>::Locator loc; | 5564 ZoneSplayTree<Config>::Locator loc; |
| 5565 ASSERT_RESULT(tree()->Insert(current.from(), &loc)); | 5565 DCHECK_RESULT(tree()->Insert(current.from(), &loc)); |
| 5566 loc.set_value(Entry(current.from(), current.to(), | 5566 loc.set_value(Entry(current.from(), current.to(), |
| 5567 empty()->Extend(value, zone))); | 5567 empty()->Extend(value, zone))); |
| 5568 return; | 5568 return; |
| 5569 } | 5569 } |
| 5570 // First see if there is a range to the left of this one that | 5570 // First see if there is a range to the left of this one that |
| 5571 // overlaps. | 5571 // overlaps. |
| 5572 ZoneSplayTree<Config>::Locator loc; | 5572 ZoneSplayTree<Config>::Locator loc; |
| 5573 if (tree()->FindGreatestLessThan(current.from(), &loc)) { | 5573 if (tree()->FindGreatestLessThan(current.from(), &loc)) { |
| 5574 Entry* entry = &loc.value(); | 5574 Entry* entry = &loc.value(); |
| 5575 // If we've found a range that overlaps with this one, and it | 5575 // If we've found a range that overlaps with this one, and it |
| 5576 // starts strictly to the left of this one, we have to fix it | 5576 // starts strictly to the left of this one, we have to fix it |
| 5577 // because the following code only handles ranges that start on | 5577 // because the following code only handles ranges that start on |
| 5578 // or after the start point of the range we're adding. | 5578 // or after the start point of the range we're adding. |
| 5579 if (entry->from() < current.from() && entry->to() >= current.from()) { | 5579 if (entry->from() < current.from() && entry->to() >= current.from()) { |
| 5580 // Snap the overlapping range in half around the start point of | 5580 // Snap the overlapping range in half around the start point of |
| 5581 // the range we're adding. | 5581 // the range we're adding. |
| 5582 CharacterRange left(entry->from(), current.from() - 1); | 5582 CharacterRange left(entry->from(), current.from() - 1); |
| 5583 CharacterRange right(current.from(), entry->to()); | 5583 CharacterRange right(current.from(), entry->to()); |
| 5584 // The left part of the overlapping range doesn't overlap. | 5584 // The left part of the overlapping range doesn't overlap. |
| 5585 // Truncate the whole entry to be just the left part. | 5585 // Truncate the whole entry to be just the left part. |
| 5586 entry->set_to(left.to()); | 5586 entry->set_to(left.to()); |
| 5587 // The right part is the one that overlaps. We add this part | 5587 // The right part is the one that overlaps. We add this part |
| 5588 // to the map and let the next step deal with merging it with | 5588 // to the map and let the next step deal with merging it with |
| 5589 // the range we're adding. | 5589 // the range we're adding. |
| 5590 ZoneSplayTree<Config>::Locator loc; | 5590 ZoneSplayTree<Config>::Locator loc; |
| 5591 ASSERT_RESULT(tree()->Insert(right.from(), &loc)); | 5591 DCHECK_RESULT(tree()->Insert(right.from(), &loc)); |
| 5592 loc.set_value(Entry(right.from(), | 5592 loc.set_value(Entry(right.from(), |
| 5593 right.to(), | 5593 right.to(), |
| 5594 entry->out_set())); | 5594 entry->out_set())); |
| 5595 } | 5595 } |
| 5596 } | 5596 } |
| 5597 while (current.is_valid()) { | 5597 while (current.is_valid()) { |
| 5598 if (tree()->FindLeastGreaterThan(current.from(), &loc) && | 5598 if (tree()->FindLeastGreaterThan(current.from(), &loc) && |
| 5599 (loc.value().from() <= current.to()) && | 5599 (loc.value().from() <= current.to()) && |
| 5600 (loc.value().to() >= current.from())) { | 5600 (loc.value().to() >= current.from())) { |
| 5601 Entry* entry = &loc.value(); | 5601 Entry* entry = &loc.value(); |
| 5602 // We have overlap. If there is space between the start point of | 5602 // We have overlap. If there is space between the start point of |
| 5603 // the range we're adding and where the overlapping range starts | 5603 // the range we're adding and where the overlapping range starts |
| 5604 // then we have to add a range covering just that space. | 5604 // then we have to add a range covering just that space. |
| 5605 if (current.from() < entry->from()) { | 5605 if (current.from() < entry->from()) { |
| 5606 ZoneSplayTree<Config>::Locator ins; | 5606 ZoneSplayTree<Config>::Locator ins; |
| 5607 ASSERT_RESULT(tree()->Insert(current.from(), &ins)); | 5607 DCHECK_RESULT(tree()->Insert(current.from(), &ins)); |
| 5608 ins.set_value(Entry(current.from(), | 5608 ins.set_value(Entry(current.from(), |
| 5609 entry->from() - 1, | 5609 entry->from() - 1, |
| 5610 empty()->Extend(value, zone))); | 5610 empty()->Extend(value, zone))); |
| 5611 current.set_from(entry->from()); | 5611 current.set_from(entry->from()); |
| 5612 } | 5612 } |
| 5613 ASSERT_EQ(current.from(), entry->from()); | 5613 DCHECK_EQ(current.from(), entry->from()); |
| 5614 // If the overlapping range extends beyond the one we want to add | 5614 // If the overlapping range extends beyond the one we want to add |
| 5615 // we have to snap the right part off and add it separately. | 5615 // we have to snap the right part off and add it separately. |
| 5616 if (entry->to() > current.to()) { | 5616 if (entry->to() > current.to()) { |
| 5617 ZoneSplayTree<Config>::Locator ins; | 5617 ZoneSplayTree<Config>::Locator ins; |
| 5618 ASSERT_RESULT(tree()->Insert(current.to() + 1, &ins)); | 5618 DCHECK_RESULT(tree()->Insert(current.to() + 1, &ins)); |
| 5619 ins.set_value(Entry(current.to() + 1, | 5619 ins.set_value(Entry(current.to() + 1, |
| 5620 entry->to(), | 5620 entry->to(), |
| 5621 entry->out_set())); | 5621 entry->out_set())); |
| 5622 entry->set_to(current.to()); | 5622 entry->set_to(current.to()); |
| 5623 } | 5623 } |
| 5624 ASSERT(entry->to() <= current.to()); | 5624 DCHECK(entry->to() <= current.to()); |
| 5625 // The overlapping range is now completely contained by the range | 5625 // The overlapping range is now completely contained by the range |
| 5626 // we're adding so we can just update it and move the start point | 5626 // we're adding so we can just update it and move the start point |
| 5627 // of the range we're adding just past it. | 5627 // of the range we're adding just past it. |
| 5628 entry->AddValue(value, zone); | 5628 entry->AddValue(value, zone); |
| 5629 // Bail out if the last interval ended at 0xFFFF since otherwise | 5629 // Bail out if the last interval ended at 0xFFFF since otherwise |
| 5630 // adding 1 will wrap around to 0. | 5630 // adding 1 will wrap around to 0. |
| 5631 if (entry->to() == String::kMaxUtf16CodeUnit) | 5631 if (entry->to() == String::kMaxUtf16CodeUnit) |
| 5632 break; | 5632 break; |
| 5633 ASSERT(entry->to() + 1 > current.from()); | 5633 DCHECK(entry->to() + 1 > current.from()); |
| 5634 current.set_from(entry->to() + 1); | 5634 current.set_from(entry->to() + 1); |
| 5635 } else { | 5635 } else { |
| 5636 // There is no overlap so we can just add the range | 5636 // There is no overlap so we can just add the range |
| 5637 ZoneSplayTree<Config>::Locator ins; | 5637 ZoneSplayTree<Config>::Locator ins; |
| 5638 ASSERT_RESULT(tree()->Insert(current.from(), &ins)); | 5638 DCHECK_RESULT(tree()->Insert(current.from(), &ins)); |
| 5639 ins.set_value(Entry(current.from(), | 5639 ins.set_value(Entry(current.from(), |
| 5640 current.to(), | 5640 current.to(), |
| 5641 empty()->Extend(value, zone))); | 5641 empty()->Extend(value, zone))); |
| 5642 break; | 5642 break; |
| 5643 } | 5643 } |
| 5644 } | 5644 } |
| 5645 } | 5645 } |
| 5646 | 5646 |
| 5647 | 5647 |
| 5648 OutSet* DispatchTable::Get(uc16 value) { | 5648 OutSet* DispatchTable::Get(uc16 value) { |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5821 bm->max_char() == String::kMaxOneByteCharCode, | 5821 bm->max_char() == String::kMaxOneByteCharCode, |
| 5822 chars); | 5822 chars); |
| 5823 for (int j = 0; j < length; j++) { | 5823 for (int j = 0; j < length; j++) { |
| 5824 bm->Set(offset, chars[j]); | 5824 bm->Set(offset, chars[j]); |
| 5825 } | 5825 } |
| 5826 } else { | 5826 } else { |
| 5827 if (character <= max_char) bm->Set(offset, character); | 5827 if (character <= max_char) bm->Set(offset, character); |
| 5828 } | 5828 } |
| 5829 } | 5829 } |
| 5830 } else { | 5830 } else { |
| 5831 ASSERT_EQ(TextElement::CHAR_CLASS, text.text_type()); | 5831 DCHECK_EQ(TextElement::CHAR_CLASS, text.text_type()); |
| 5832 RegExpCharacterClass* char_class = text.char_class(); | 5832 RegExpCharacterClass* char_class = text.char_class(); |
| 5833 ZoneList<CharacterRange>* ranges = char_class->ranges(zone()); | 5833 ZoneList<CharacterRange>* ranges = char_class->ranges(zone()); |
| 5834 if (char_class->is_negated()) { | 5834 if (char_class->is_negated()) { |
| 5835 bm->SetAll(offset); | 5835 bm->SetAll(offset); |
| 5836 } else { | 5836 } else { |
| 5837 for (int k = 0; k < ranges->length(); k++) { | 5837 for (int k = 0; k < ranges->length(); k++) { |
| 5838 CharacterRange& range = ranges->at(k); | 5838 CharacterRange& range = ranges->at(k); |
| 5839 if (range.from() > max_char) continue; | 5839 if (range.from() > max_char) continue; |
| 5840 int to = Min(max_char, static_cast<int>(range.to())); | 5840 int to = Min(max_char, static_cast<int>(range.to())); |
| 5841 bm->SetInterval(offset, Interval(range.from(), to)); | 5841 bm->SetInterval(offset, Interval(range.from(), to)); |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6104 } | 6104 } |
| 6105 | 6105 |
| 6106 return compiler.Assemble(¯o_assembler, | 6106 return compiler.Assemble(¯o_assembler, |
| 6107 node, | 6107 node, |
| 6108 data->capture_count, | 6108 data->capture_count, |
| 6109 pattern); | 6109 pattern); |
| 6110 } | 6110 } |
| 6111 | 6111 |
| 6112 | 6112 |
| 6113 }} // namespace v8::internal | 6113 }} // namespace v8::internal |
| OLD | NEW |