| OLD | NEW | 
|---|
| 1 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a | 
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "vm/regexp_assembler_bytecode.h" | 5 #include "vm/regexp_assembler_bytecode.h" | 
| 6 | 6 | 
| 7 #include "vm/regexp_assembler_bytecode_inl.h" | 7 #include "vm/regexp_assembler_bytecode_inl.h" | 
| 8 #include "vm/exceptions.h" | 8 #include "vm/exceptions.h" | 
| 9 #include "vm/object_store.h" | 9 #include "vm/object_store.h" | 
| 10 #include "vm/regexp_bytecodes.h" | 10 #include "vm/regexp_bytecodes.h" | 
| 11 #include "vm/regexp_assembler.h" | 11 #include "vm/regexp_assembler.h" | 
| 12 #include "vm/regexp.h" | 12 #include "vm/regexp.h" | 
| 13 #include "vm/regexp_parser.h" | 13 #include "vm/regexp_parser.h" | 
| 14 #include "vm/regexp_interpreter.h" | 14 #include "vm/regexp_interpreter.h" | 
| 15 #include "vm/timeline.h" | 15 #include "vm/timeline.h" | 
| 16 | 16 | 
| 17 namespace dart { | 17 namespace dart { | 
| 18 | 18 | 
| 19 BytecodeRegExpMacroAssembler::BytecodeRegExpMacroAssembler( | 19 BytecodeRegExpMacroAssembler::BytecodeRegExpMacroAssembler( | 
| 20     ZoneGrowableArray<uint8_t>* buffer, | 20     ZoneGrowableArray<uint8_t>* buffer, | 
| 21     Zone* zone) | 21     Zone* zone) | 
| 22     : RegExpMacroAssembler(zone), | 22     : RegExpMacroAssembler(zone), | 
| 23       buffer_(buffer), | 23       buffer_(buffer), | 
| 24       pc_(0), | 24       pc_(0), | 
| 25       advance_current_end_(kInvalidPC) { } | 25       advance_current_end_(kInvalidPC) {} | 
| 26 | 26 | 
| 27 | 27 | 
| 28 BytecodeRegExpMacroAssembler::~BytecodeRegExpMacroAssembler() { | 28 BytecodeRegExpMacroAssembler::~BytecodeRegExpMacroAssembler() { | 
| 29   if (backtrack_.is_linked()) backtrack_.Unuse(); | 29   if (backtrack_.is_linked()) backtrack_.Unuse(); | 
| 30 } | 30 } | 
| 31 | 31 | 
| 32 | 32 | 
| 33 BytecodeRegExpMacroAssembler::IrregexpImplementation | 33 BytecodeRegExpMacroAssembler::IrregexpImplementation | 
| 34 BytecodeRegExpMacroAssembler::Implementation() { | 34 BytecodeRegExpMacroAssembler::Implementation() { | 
| 35   return kBytecodeImplementation; | 35   return kBytecodeImplementation; | 
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 74 | 74 | 
| 75 | 75 | 
| 76 void BytecodeRegExpMacroAssembler::PushRegister(intptr_t register_index) { | 76 void BytecodeRegExpMacroAssembler::PushRegister(intptr_t register_index) { | 
| 77   ASSERT(register_index >= 0); | 77   ASSERT(register_index >= 0); | 
| 78   ASSERT(register_index <= kMaxRegister); | 78   ASSERT(register_index <= kMaxRegister); | 
| 79   Emit(BC_PUSH_REGISTER, register_index); | 79   Emit(BC_PUSH_REGISTER, register_index); | 
| 80 } | 80 } | 
| 81 | 81 | 
| 82 | 82 | 
| 83 void BytecodeRegExpMacroAssembler::WriteCurrentPositionToRegister( | 83 void BytecodeRegExpMacroAssembler::WriteCurrentPositionToRegister( | 
| 84     intptr_t register_index, intptr_t cp_offset) { | 84     intptr_t register_index, | 
|  | 85     intptr_t cp_offset) { | 
| 85   ASSERT(register_index >= 0); | 86   ASSERT(register_index >= 0); | 
| 86   ASSERT(register_index <= kMaxRegister); | 87   ASSERT(register_index <= kMaxRegister); | 
| 87   Emit(BC_SET_REGISTER_TO_CP, register_index); | 88   Emit(BC_SET_REGISTER_TO_CP, register_index); | 
| 88   Emit32(cp_offset);  // Current position offset. | 89   Emit32(cp_offset);  // Current position offset. | 
| 89 } | 90 } | 
| 90 | 91 | 
| 91 | 92 | 
| 92 void BytecodeRegExpMacroAssembler::ClearRegisters(intptr_t reg_from, | 93 void BytecodeRegExpMacroAssembler::ClearRegisters(intptr_t reg_from, | 
| 93                                                   intptr_t reg_to) { | 94                                                   intptr_t reg_to) { | 
| 94   ASSERT(reg_from <= reg_to); | 95   ASSERT(reg_from <= reg_to); | 
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 197   ASSERT(by >= kMinCPOffset); | 198   ASSERT(by >= kMinCPOffset); | 
| 198   ASSERT(by <= kMaxCPOffset); | 199   ASSERT(by <= kMaxCPOffset); | 
| 199   advance_current_start_ = pc_; | 200   advance_current_start_ = pc_; | 
| 200   advance_current_offset_ = by; | 201   advance_current_offset_ = by; | 
| 201   Emit(BC_ADVANCE_CP, by); | 202   Emit(BC_ADVANCE_CP, by); | 
| 202   advance_current_end_ = pc_; | 203   advance_current_end_ = pc_; | 
| 203 } | 204 } | 
| 204 | 205 | 
| 205 | 206 | 
| 206 void BytecodeRegExpMacroAssembler::CheckGreedyLoop( | 207 void BytecodeRegExpMacroAssembler::CheckGreedyLoop( | 
| 207       BlockLabel* on_tos_equals_current_position) { | 208     BlockLabel* on_tos_equals_current_position) { | 
| 208   Emit(BC_CHECK_GREEDY, 0); | 209   Emit(BC_CHECK_GREEDY, 0); | 
| 209   EmitOrLink(on_tos_equals_current_position); | 210   EmitOrLink(on_tos_equals_current_position); | 
| 210 } | 211 } | 
| 211 | 212 | 
| 212 | 213 | 
| 213 void BytecodeRegExpMacroAssembler::LoadCurrentCharacter(intptr_t cp_offset, | 214 void BytecodeRegExpMacroAssembler::LoadCurrentCharacter(intptr_t cp_offset, | 
| 214                                                         BlockLabel* on_failure, | 215                                                         BlockLabel* on_failure, | 
| 215                                                         bool check_bounds, | 216                                                         bool check_bounds, | 
| 216                                                         intptr_t characters) { | 217                                                         intptr_t characters) { | 
| 217   ASSERT(cp_offset >= kMinCPOffset); | 218   ASSERT(cp_offset >= kMinCPOffset); | 
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 349     uint16_t from, | 350     uint16_t from, | 
| 350     uint16_t to, | 351     uint16_t to, | 
| 351     BlockLabel* on_not_in_range) { | 352     BlockLabel* on_not_in_range) { | 
| 352   Emit(BC_CHECK_CHAR_NOT_IN_RANGE, 0); | 353   Emit(BC_CHECK_CHAR_NOT_IN_RANGE, 0); | 
| 353   Emit16(from); | 354   Emit16(from); | 
| 354   Emit16(to); | 355   Emit16(to); | 
| 355   EmitOrLink(on_not_in_range); | 356   EmitOrLink(on_not_in_range); | 
| 356 } | 357 } | 
| 357 | 358 | 
| 358 | 359 | 
| 359 void BytecodeRegExpMacroAssembler::CheckBitInTable( | 360 void BytecodeRegExpMacroAssembler::CheckBitInTable(const TypedData& table, | 
| 360     const TypedData& table, BlockLabel* on_bit_set) { | 361                                                    BlockLabel* on_bit_set) { | 
| 361   Emit(BC_CHECK_BIT_IN_TABLE, 0); | 362   Emit(BC_CHECK_BIT_IN_TABLE, 0); | 
| 362   EmitOrLink(on_bit_set); | 363   EmitOrLink(on_bit_set); | 
| 363   for (int i = 0; i < kTableSize; i += kBitsPerByte) { | 364   for (int i = 0; i < kTableSize; i += kBitsPerByte) { | 
| 364     int byte = 0; | 365     int byte = 0; | 
| 365     for (int j = 0; j < kBitsPerByte; j++) { | 366     for (int j = 0; j < kBitsPerByte; j++) { | 
| 366       if (table.GetUint8(i + j) != 0) byte |= 1 << j; | 367       if (table.GetUint8(i + j) != 0) byte |= 1 << j; | 
| 367     } | 368     } | 
| 368     Emit8(byte); | 369     Emit8(byte); | 
| 369   } | 370   } | 
| 370 } | 371 } | 
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 442 } | 443 } | 
| 443 | 444 | 
| 444 | 445 | 
| 445 void BytecodeRegExpMacroAssembler::Expand() { | 446 void BytecodeRegExpMacroAssembler::Expand() { | 
| 446   // BOGUS | 447   // BOGUS | 
| 447   buffer_->Add(0); | 448   buffer_->Add(0); | 
| 448   buffer_->Add(0); | 449   buffer_->Add(0); | 
| 449   buffer_->Add(0); | 450   buffer_->Add(0); | 
| 450   buffer_->Add(0); | 451   buffer_->Add(0); | 
| 451   intptr_t x = buffer_->length(); | 452   intptr_t x = buffer_->length(); | 
| 452   for (intptr_t i = 0; i < x; i++) buffer_->Add(0); | 453   for (intptr_t i = 0; i < x; i++) | 
|  | 454     buffer_->Add(0); | 
| 453 } | 455 } | 
| 454 | 456 | 
| 455 | 457 | 
| 456 static intptr_t Prepare(const RegExp& regexp, | 458 static intptr_t Prepare(const RegExp& regexp, | 
| 457                         const String& subject, | 459                         const String& subject, | 
| 458                         Zone* zone) { | 460                         Zone* zone) { | 
| 459   bool is_one_byte = subject.IsOneByteString() || | 461   bool is_one_byte = | 
| 460                      subject.IsExternalOneByteString(); | 462       subject.IsOneByteString() || subject.IsExternalOneByteString(); | 
| 461 | 463 | 
| 462   if (regexp.bytecode(is_one_byte) == TypedData::null()) { | 464   if (regexp.bytecode(is_one_byte) == TypedData::null()) { | 
| 463     const String& pattern = String::Handle(zone, regexp.pattern()); | 465     const String& pattern = String::Handle(zone, regexp.pattern()); | 
| 464     NOT_IN_PRODUCT(TimelineDurationScope tds(Thread::Current(), | 466 #if !defined(PRODUCT) | 
| 465                                              Timeline::GetCompilerStream(), | 467     TimelineDurationScope tds(Thread::Current(), Timeline::GetCompilerStream(), | 
| 466                                              "CompileIrregexpBytecode"); | 468                               "CompileIrregexpBytecode"); | 
| 467     if (tds.enabled()) { | 469     if (tds.enabled()) { | 
| 468       tds.SetNumArguments(1); | 470       tds.SetNumArguments(1); | 
| 469       tds.CopyArgument(0, "pattern", pattern.ToCString()); | 471       tds.CopyArgument(0, "pattern", pattern.ToCString()); | 
| 470     });  // !PRODUCT | 472     } | 
|  | 473 #endif  // !defined(PRODUCT) | 
| 471 | 474 | 
| 472     const bool multiline = regexp.is_multi_line(); | 475     const bool multiline = regexp.is_multi_line(); | 
| 473     RegExpCompileData* compile_data = new(zone) RegExpCompileData(); | 476     RegExpCompileData* compile_data = new (zone) RegExpCompileData(); | 
| 474     if (!RegExpParser::ParseRegExp(pattern, multiline, compile_data)) { | 477     if (!RegExpParser::ParseRegExp(pattern, multiline, compile_data)) { | 
| 475       // Parsing failures are handled in the RegExp factory constructor. | 478       // Parsing failures are handled in the RegExp factory constructor. | 
| 476       UNREACHABLE(); | 479       UNREACHABLE(); | 
| 477     } | 480     } | 
| 478 | 481 | 
| 479     regexp.set_num_bracket_expressions(compile_data->capture_count); | 482     regexp.set_num_bracket_expressions(compile_data->capture_count); | 
| 480     if (compile_data->simple) { | 483     if (compile_data->simple) { | 
| 481       regexp.set_is_simple(); | 484       regexp.set_is_simple(); | 
| 482     } else { | 485     } else { | 
| 483       regexp.set_is_complex(); | 486       regexp.set_is_complex(); | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 498          (Smi::Value(regexp.num_bracket_expressions()) + 1) * 2; | 501          (Smi::Value(regexp.num_bracket_expressions()) + 1) * 2; | 
| 499 } | 502 } | 
| 500 | 503 | 
| 501 | 504 | 
| 502 static IrregexpInterpreter::IrregexpResult ExecRaw(const RegExp& regexp, | 505 static IrregexpInterpreter::IrregexpResult ExecRaw(const RegExp& regexp, | 
| 503                                                    const String& subject, | 506                                                    const String& subject, | 
| 504                                                    intptr_t index, | 507                                                    intptr_t index, | 
| 505                                                    int32_t* output, | 508                                                    int32_t* output, | 
| 506                                                    intptr_t output_size, | 509                                                    intptr_t output_size, | 
| 507                                                    Zone* zone) { | 510                                                    Zone* zone) { | 
| 508   bool is_one_byte = subject.IsOneByteString() || | 511   bool is_one_byte = | 
| 509                      subject.IsExternalOneByteString(); | 512       subject.IsOneByteString() || subject.IsExternalOneByteString(); | 
| 510 | 513 | 
| 511   ASSERT(regexp.num_bracket_expressions() != Smi::null()); | 514   ASSERT(regexp.num_bracket_expressions() != Smi::null()); | 
| 512 | 515 | 
| 513   // We must have done EnsureCompiledIrregexp, so we can get the number of | 516   // We must have done EnsureCompiledIrregexp, so we can get the number of | 
| 514   // registers. | 517   // registers. | 
| 515   int number_of_capture_registers = | 518   int number_of_capture_registers = | 
| 516      (Smi::Value(regexp.num_bracket_expressions()) + 1) * 2; | 519       (Smi::Value(regexp.num_bracket_expressions()) + 1) * 2; | 
| 517   int32_t* raw_output = &output[number_of_capture_registers]; | 520   int32_t* raw_output = &output[number_of_capture_registers]; | 
| 518 | 521 | 
| 519   // We do not touch the actual capture result registers until we know there | 522   // We do not touch the actual capture result registers until we know there | 
| 520   // has been a match so that we can use those capture results to set the | 523   // has been a match so that we can use those capture results to set the | 
| 521   // last match info. | 524   // last match info. | 
| 522   for (int i = number_of_capture_registers - 1; i >= 0; i--) { | 525   for (int i = number_of_capture_registers - 1; i >= 0; i--) { | 
| 523     raw_output[i] = -1; | 526     raw_output[i] = -1; | 
| 524   } | 527   } | 
| 525 | 528 | 
| 526   const TypedData& bytecode = | 529   const TypedData& bytecode = | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
| 551                                                      Zone* zone) { | 554                                                      Zone* zone) { | 
| 552   intptr_t required_registers = Prepare(regexp, subject, zone); | 555   intptr_t required_registers = Prepare(regexp, subject, zone); | 
| 553   if (required_registers < 0) { | 556   if (required_registers < 0) { | 
| 554     // Compiling failed with an exception. | 557     // Compiling failed with an exception. | 
| 555     UNREACHABLE(); | 558     UNREACHABLE(); | 
| 556   } | 559   } | 
| 557 | 560 | 
| 558   // V8 uses a shared copy on the isolate when smaller than some threshold. | 561   // V8 uses a shared copy on the isolate when smaller than some threshold. | 
| 559   int32_t* output_registers = zone->Alloc<int32_t>(required_registers); | 562   int32_t* output_registers = zone->Alloc<int32_t>(required_registers); | 
| 560 | 563 | 
| 561   IrregexpInterpreter::IrregexpResult result = ExecRaw(regexp, | 564   IrregexpInterpreter::IrregexpResult result = | 
| 562                                                        subject, | 565       ExecRaw(regexp, subject, start_index.Value(), output_registers, | 
| 563                                                        start_index.Value(), | 566               required_registers, zone); | 
| 564                                                        output_registers, |  | 
| 565                                                        required_registers, |  | 
| 566                                                        zone); |  | 
| 567 | 567 | 
| 568   if (result == IrregexpInterpreter::RE_SUCCESS) { | 568   if (result == IrregexpInterpreter::RE_SUCCESS) { | 
| 569     intptr_t capture_count = Smi::Value(regexp.num_bracket_expressions()); | 569     intptr_t capture_count = Smi::Value(regexp.num_bracket_expressions()); | 
| 570     intptr_t capture_register_count = (capture_count + 1) * 2; | 570     intptr_t capture_register_count = (capture_count + 1) * 2; | 
| 571     ASSERT(required_registers >= capture_register_count); | 571     ASSERT(required_registers >= capture_register_count); | 
| 572 | 572 | 
| 573     const TypedData& result = | 573     const TypedData& result = TypedData::Handle( | 
| 574         TypedData::Handle(TypedData::New(kTypedDataInt32ArrayCid, | 574         TypedData::New(kTypedDataInt32ArrayCid, capture_register_count)); | 
| 575                                          capture_register_count)); |  | 
| 576     { | 575     { | 
| 577 #ifdef DEBUG | 576 #ifdef DEBUG | 
| 578       // These indices will be used with substring operations that don't check | 577       // These indices will be used with substring operations that don't check | 
| 579       // bounds, so sanity check them here. | 578       // bounds, so sanity check them here. | 
| 580       for (intptr_t i = 0; i < capture_register_count; i++) { | 579       for (intptr_t i = 0; i < capture_register_count; i++) { | 
| 581         int32_t val = output_registers[i]; | 580         int32_t val = output_registers[i]; | 
| 582         ASSERT(val == -1 || (val >= 0 && val <= subject.Length())); | 581         ASSERT(val == -1 || (val >= 0 && val <= subject.Length())); | 
| 583       } | 582       } | 
| 584 #endif | 583 #endif | 
| 585 | 584 | 
| 586       NoSafepointScope no_safepoint; | 585       NoSafepointScope no_safepoint; | 
| 587       memmove(result.DataAddr(0), | 586       memmove(result.DataAddr(0), output_registers, | 
| 588               output_registers, |  | 
| 589               capture_register_count * sizeof(int32_t)); | 587               capture_register_count * sizeof(int32_t)); | 
| 590     } | 588     } | 
| 591 | 589 | 
| 592     return result.raw(); | 590     return result.raw(); | 
| 593   } | 591   } | 
| 594   if (result == IrregexpInterpreter::RE_EXCEPTION) { | 592   if (result == IrregexpInterpreter::RE_EXCEPTION) { | 
| 595     UNREACHABLE(); | 593     UNREACHABLE(); | 
| 596   } | 594   } | 
| 597   ASSERT(result == IrregexpInterpreter::RE_FAILURE); | 595   ASSERT(result == IrregexpInterpreter::RE_FAILURE); | 
| 598   return Instance::null(); | 596   return Instance::null(); | 
| 599 } | 597 } | 
| 600 | 598 | 
| 601 | 599 | 
| 602 }  // namespace dart | 600 }  // namespace dart | 
| OLD | NEW | 
|---|