| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ir.h" | 5 #include "vm/regexp_assembler_ir.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/compiler.h" | 8 #include "vm/compiler.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 String::Handle(String::New(__FUNCTION__)), Heap::kOld)))))); | 29 String::Handle(String::New(__FUNCTION__)), Heap::kOld)))))); |
| 30 | 30 |
| 31 #define PRINT(arg) if (FLAG_trace_irregexp) { Print(arg); } | 31 #define PRINT(arg) if (FLAG_trace_irregexp) { Print(arg); } |
| 32 | 32 |
| 33 namespace dart { | 33 namespace dart { |
| 34 | 34 |
| 35 DEFINE_FLAG(bool, trace_irregexp, false, "Trace irregexps"); | 35 DEFINE_FLAG(bool, trace_irregexp, false, "Trace irregexps"); |
| 36 | 36 |
| 37 | 37 |
| 38 static const intptr_t kInvalidTryIndex = CatchClauseNode::kInvalidTryIndex; | 38 static const intptr_t kInvalidTryIndex = CatchClauseNode::kInvalidTryIndex; |
| 39 static const TokenPosition kNoSourcePos = TokenPosition::kNoSource; | |
| 40 static const intptr_t kMinStackSize = 512; | 39 static const intptr_t kMinStackSize = 512; |
| 41 | 40 |
| 42 | 41 |
| 43 void PrintUtf16(uint16_t c) { | 42 void PrintUtf16(uint16_t c) { |
| 44 const char* format = (0x20 <= c && c <= 0x7F) ? | 43 const char* format = (0x20 <= c && c <= 0x7F) ? |
| 45 "%c" : (c <= 0xff) ? "\\x%02x" : "\\u%04x"; | 44 "%c" : (c <= 0xff) ? "\\x%02x" : "\\u%04x"; |
| 46 OS::Print(format, c); | 45 OS::Print(format, c); |
| 47 } | 46 } |
| 48 | 47 |
| 49 | 48 |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 } | 238 } |
| 240 | 239 |
| 241 | 240 |
| 242 void IRRegExpMacroAssembler::GenerateSuccessBlock() { | 241 void IRRegExpMacroAssembler::GenerateSuccessBlock() { |
| 243 set_current_instruction(success_block_); | 242 set_current_instruction(success_block_); |
| 244 TAG(); | 243 TAG(); |
| 245 | 244 |
| 246 Value* type = Bind(new(Z) ConstantInstr( | 245 Value* type = Bind(new(Z) ConstantInstr( |
| 247 TypeArguments::ZoneHandle(Z, TypeArguments::null()))); | 246 TypeArguments::ZoneHandle(Z, TypeArguments::null()))); |
| 248 Value* length = Bind(Uint64Constant(saved_registers_count_)); | 247 Value* length = Bind(Uint64Constant(saved_registers_count_)); |
| 249 Value* array = Bind(new(Z) CreateArrayInstr(kNoSourcePos, type, length)); | 248 Value* array = Bind(new(Z) CreateArrayInstr( |
| 249 TokenPosition::kNoSource, type, length)); |
| 250 StoreLocal(result_, array); | 250 StoreLocal(result_, array); |
| 251 | 251 |
| 252 // Store captured offsets in the `matches` parameter. | 252 // Store captured offsets in the `matches` parameter. |
| 253 for (intptr_t i = 0; i < saved_registers_count_; i++) { | 253 for (intptr_t i = 0; i < saved_registers_count_; i++) { |
| 254 PushArgumentInstr* matches_push = PushLocal(result_); | 254 PushArgumentInstr* matches_push = PushLocal(result_); |
| 255 PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(i))); | 255 PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(i))); |
| 256 | 256 |
| 257 // Convert negative offsets from the end of the string to string indices. | 257 // Convert negative offsets from the end of the string to string indices. |
| 258 // TODO(zerny): use positive offsets from the get-go. | 258 // TODO(zerny): use positive offsets from the get-go. |
| 259 PushArgumentInstr* offset_push = PushArgument(LoadRegister(i)); | 259 PushArgumentInstr* offset_push = PushArgument(LoadRegister(i)); |
| 260 PushArgumentInstr* len_push = PushLocal(string_param_length_); | 260 PushArgumentInstr* len_push = PushLocal(string_param_length_); |
| 261 PushArgumentInstr* value_push = | 261 PushArgumentInstr* value_push = |
| 262 PushArgument(Bind(Add(offset_push, len_push))); | 262 PushArgument(Bind(Add(offset_push, len_push))); |
| 263 | 263 |
| 264 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), | 264 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), |
| 265 matches_push, | 265 matches_push, |
| 266 index_push, | 266 index_push, |
| 267 value_push)); | 267 value_push)); |
| 268 } | 268 } |
| 269 | 269 |
| 270 // Print the result if tracing. | 270 // Print the result if tracing. |
| 271 PRINT(PushLocal(result_)); | 271 PRINT(PushLocal(result_)); |
| 272 | 272 |
| 273 // Return true on success. | 273 // Return true on success. |
| 274 AppendInstruction(new(Z) ReturnInstr(kNoSourcePos, Bind(LoadLocal(result_)))); | 274 AppendInstruction(new(Z) ReturnInstr( |
| 275 TokenPosition::kNoSource, Bind(LoadLocal(result_)))); |
| 275 } | 276 } |
| 276 | 277 |
| 277 | 278 |
| 278 void IRRegExpMacroAssembler::GenerateExitBlock() { | 279 void IRRegExpMacroAssembler::GenerateExitBlock() { |
| 279 set_current_instruction(exit_block_); | 280 set_current_instruction(exit_block_); |
| 280 TAG(); | 281 TAG(); |
| 281 | 282 |
| 282 // Return false on failure. | 283 // Return false on failure. |
| 283 AppendInstruction(new(Z) ReturnInstr(kNoSourcePos, Bind(LoadLocal(result_)))); | 284 AppendInstruction(new(Z) ReturnInstr( |
| 285 TokenPosition::kNoSource, Bind(LoadLocal(result_)))); |
| 284 } | 286 } |
| 285 | 287 |
| 286 | 288 |
| 287 void IRRegExpMacroAssembler::FinalizeRegistersArray() { | 289 void IRRegExpMacroAssembler::FinalizeRegistersArray() { |
| 288 ASSERT(registers_count_ >= saved_registers_count_); | 290 ASSERT(registers_count_ >= saved_registers_count_); |
| 289 registers_array_ = | 291 registers_array_ = |
| 290 TypedData::New(kTypedDataInt32ArrayCid, registers_count_, Heap::kOld); | 292 TypedData::New(kTypedDataInt32ArrayCid, registers_count_, Heap::kOld); |
| 291 } | 293 } |
| 292 | 294 |
| 293 | 295 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 } | 377 } |
| 376 | 378 |
| 377 | 379 |
| 378 DEFINE_RAW_LEAF_RUNTIME_ENTRY( | 380 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 379 CaseInsensitiveCompareUC16, 4, false /* is_float */, | 381 CaseInsensitiveCompareUC16, 4, false /* is_float */, |
| 380 reinterpret_cast<RuntimeFunction>(&CaseInsensitiveCompareUC16)); | 382 reinterpret_cast<RuntimeFunction>(&CaseInsensitiveCompareUC16)); |
| 381 | 383 |
| 382 | 384 |
| 383 LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name, | 385 LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name, |
| 384 intptr_t index) const { | 386 intptr_t index) const { |
| 385 LocalVariable* local = | 387 LocalVariable* local = new(Z) LocalVariable( |
| 386 new(Z) LocalVariable(kNoSourcePos, name, Object::dynamic_type()); | 388 TokenPosition::kNoSource, name, Object::dynamic_type()); |
| 387 | 389 |
| 388 intptr_t param_frame_index = kParamEndSlotFromFp + kParamCount - index; | 390 intptr_t param_frame_index = kParamEndSlotFromFp + kParamCount - index; |
| 389 local->set_index(param_frame_index); | 391 local->set_index(param_frame_index); |
| 390 | 392 |
| 391 return local; | 393 return local; |
| 392 } | 394 } |
| 393 | 395 |
| 394 | 396 |
| 395 LocalVariable* IRRegExpMacroAssembler::Local(const String& name) { | 397 LocalVariable* IRRegExpMacroAssembler::Local(const String& name) { |
| 396 LocalVariable* local = | 398 LocalVariable* local = new(Z) LocalVariable( |
| 397 new(Z) LocalVariable(kNoSourcePos, name, Object::dynamic_type()); | 399 TokenPosition::kNoSource, name, Object::dynamic_type()); |
| 398 local->set_index(GetNextLocalIndex()); | 400 local->set_index(GetNextLocalIndex()); |
| 399 | 401 |
| 400 return local; | 402 return local; |
| 401 } | 403 } |
| 402 | 404 |
| 403 | 405 |
| 404 ConstantInstr* IRRegExpMacroAssembler::Int64Constant(int64_t value) const { | 406 ConstantInstr* IRRegExpMacroAssembler::Int64Constant(int64_t value) const { |
| 405 return new(Z) ConstantInstr( | 407 return new(Z) ConstantInstr( |
| 406 Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld))); | 408 Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld))); |
| 407 } | 409 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 ASSERT(intermediate_operator != Token::kILLEGAL); | 475 ASSERT(intermediate_operator != Token::kILLEGAL); |
| 474 | 476 |
| 475 Value* lhs_value = | 477 Value* lhs_value = |
| 476 Bind(InstanceCall( | 478 Bind(InstanceCall( |
| 477 InstanceCallDescriptor::FromToken(intermediate_operator), | 479 InstanceCallDescriptor::FromToken(intermediate_operator), |
| 478 lhs, | 480 lhs, |
| 479 rhs)); | 481 rhs)); |
| 480 Value* rhs_value = Bind(BoolConstant(true)); | 482 Value* rhs_value = Bind(BoolConstant(true)); |
| 481 | 483 |
| 482 return new(Z) StrictCompareInstr( | 484 return new(Z) StrictCompareInstr( |
| 483 kNoSourcePos, strict_comparison, lhs_value, rhs_value, true); | 485 TokenPosition::kNoSource, strict_comparison, lhs_value, rhs_value, true); |
| 484 } | 486 } |
| 485 | 487 |
| 486 ComparisonInstr* IRRegExpMacroAssembler::Comparison( | 488 ComparisonInstr* IRRegExpMacroAssembler::Comparison( |
| 487 ComparisonKind kind, Definition* lhs, Definition* rhs) { | 489 ComparisonKind kind, Definition* lhs, Definition* rhs) { |
| 488 PushArgumentInstr* lhs_push = PushArgument(Bind(lhs)); | 490 PushArgumentInstr* lhs_push = PushArgument(Bind(lhs)); |
| 489 PushArgumentInstr* rhs_push = PushArgument(Bind(rhs)); | 491 PushArgumentInstr* rhs_push = PushArgument(Bind(rhs)); |
| 490 return Comparison(kind, lhs_push, rhs_push); | 492 return Comparison(kind, lhs_push, rhs_push); |
| 491 } | 493 } |
| 492 | 494 |
| 493 | 495 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 519 arguments->Add(arg1); | 521 arguments->Add(arg1); |
| 520 arguments->Add(arg2); | 522 arguments->Add(arg2); |
| 521 | 523 |
| 522 return StaticCall(function, arguments); | 524 return StaticCall(function, arguments); |
| 523 } | 525 } |
| 524 | 526 |
| 525 | 527 |
| 526 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( | 528 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( |
| 527 const Function& function, | 529 const Function& function, |
| 528 ZoneGrowableArray<PushArgumentInstr*>* arguments) const { | 530 ZoneGrowableArray<PushArgumentInstr*>* arguments) const { |
| 529 return new(Z) StaticCallInstr(kNoSourcePos, | 531 return new(Z) StaticCallInstr(TokenPosition::kNoSource, |
| 530 function, | 532 function, |
| 531 Object::null_array(), | 533 Object::null_array(), |
| 532 arguments, | 534 arguments, |
| 533 ic_data_array_); | 535 ic_data_array_); |
| 534 } | 536 } |
| 535 | 537 |
| 536 | 538 |
| 537 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( | 539 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( |
| 538 const InstanceCallDescriptor& desc, | 540 const InstanceCallDescriptor& desc, |
| 539 PushArgumentInstr* arg1) const { | 541 PushArgumentInstr* arg1) const { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 570 arguments->Add(arg3); | 572 arguments->Add(arg3); |
| 571 | 573 |
| 572 return InstanceCall(desc, arguments); | 574 return InstanceCall(desc, arguments); |
| 573 } | 575 } |
| 574 | 576 |
| 575 | 577 |
| 576 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( | 578 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( |
| 577 const InstanceCallDescriptor& desc, | 579 const InstanceCallDescriptor& desc, |
| 578 ZoneGrowableArray<PushArgumentInstr*> *arguments) const { | 580 ZoneGrowableArray<PushArgumentInstr*> *arguments) const { |
| 579 return | 581 return |
| 580 new(Z) InstanceCallInstr(kNoSourcePos, | 582 new(Z) InstanceCallInstr(TokenPosition::kNoSource, |
| 581 desc.name, | 583 desc.name, |
| 582 desc.token_kind, | 584 desc.token_kind, |
| 583 arguments, | 585 arguments, |
| 584 Object::null_array(), | 586 Object::null_array(), |
| 585 desc.checked_argument_count, | 587 desc.checked_argument_count, |
| 586 ic_data_array_); | 588 ic_data_array_); |
| 587 } | 589 } |
| 588 | 590 |
| 589 | 591 |
| 590 LoadLocalInstr* IRRegExpMacroAssembler::LoadLocal(LocalVariable* local) const { | 592 LoadLocalInstr* IRRegExpMacroAssembler::LoadLocal(LocalVariable* local) const { |
| 591 return new(Z) LoadLocalInstr(*local, kNoSourcePos); | 593 return new(Z) LoadLocalInstr(*local, TokenPosition::kNoSource); |
| 592 } | 594 } |
| 593 | 595 |
| 594 | 596 |
| 595 void IRRegExpMacroAssembler::StoreLocal(LocalVariable* local, | 597 void IRRegExpMacroAssembler::StoreLocal(LocalVariable* local, |
| 596 Value* value) { | 598 Value* value) { |
| 597 Do(new(Z) StoreLocalInstr(*local, value, kNoSourcePos)); | 599 Do(new(Z) StoreLocalInstr(*local, value, TokenPosition::kNoSource)); |
| 598 } | 600 } |
| 599 | 601 |
| 600 | 602 |
| 601 void IRRegExpMacroAssembler::set_current_instruction(Instruction* instruction) { | 603 void IRRegExpMacroAssembler::set_current_instruction(Instruction* instruction) { |
| 602 current_instruction_ = instruction; | 604 current_instruction_ = instruction; |
| 603 } | 605 } |
| 604 | 606 |
| 605 | 607 |
| 606 Value* IRRegExpMacroAssembler::Bind(Definition* definition) { | 608 Value* IRRegExpMacroAssembler::Bind(Definition* definition) { |
| 607 AppendInstruction(definition); | 609 AppendInstruction(definition); |
| 608 definition->set_temp_index(temp_id_.Alloc()); | 610 definition->set_temp_index(temp_id_.Alloc()); |
| 609 | 611 |
| 610 return new(Z) Value(definition); | 612 return new(Z) Value(definition); |
| 611 } | 613 } |
| 612 | 614 |
| 613 | 615 |
| 614 void IRRegExpMacroAssembler::Do(Definition* definition) { | 616 void IRRegExpMacroAssembler::Do(Definition* definition) { |
| 615 AppendInstruction(definition); | 617 AppendInstruction(definition); |
| 616 } | 618 } |
| 617 | 619 |
| 618 | 620 |
| 619 Value* IRRegExpMacroAssembler::BindLoadLocal(const LocalVariable& local) { | 621 Value* IRRegExpMacroAssembler::BindLoadLocal(const LocalVariable& local) { |
| 620 if (local.IsConst()) { | 622 if (local.IsConst()) { |
| 621 return Bind(new(Z) ConstantInstr(*local.ConstValue())); | 623 return Bind(new(Z) ConstantInstr(*local.ConstValue())); |
| 622 } | 624 } |
| 623 ASSERT(!local.is_captured()); | 625 ASSERT(!local.is_captured()); |
| 624 return Bind(new(Z) LoadLocalInstr(local, kNoSourcePos)); | 626 return Bind(new(Z) LoadLocalInstr(local, TokenPosition::kNoSource)); |
| 625 } | 627 } |
| 626 | 628 |
| 627 | 629 |
| 628 // In some cases, the V8 irregexp engine generates unreachable code by emitting | 630 // In some cases, the V8 irregexp engine generates unreachable code by emitting |
| 629 // a jmp not followed by a bind. We cannot do the same, since it is impossible | 631 // a jmp not followed by a bind. We cannot do the same, since it is impossible |
| 630 // to append to a block following a jmp. In such cases, assume that we are doing | 632 // to append to a block following a jmp. In such cases, assume that we are doing |
| 631 // the correct thing, but output a warning when tracing. | 633 // the correct thing, but output a warning when tracing. |
| 632 #define HANDLE_DEAD_CODE_EMISSION() \ | 634 #define HANDLE_DEAD_CODE_EMISSION() \ |
| 633 if (current_instruction_ == NULL) { \ | 635 if (current_instruction_ == NULL) { \ |
| 634 if (FLAG_trace_irregexp) { \ | 636 if (FLAG_trace_irregexp) { \ |
| (...skipping 1192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1827 blocks_.Add(target); | 1829 blocks_.Add(target); |
| 1828 | 1830 |
| 1829 target->AppendInstruction(new(Z) GotoInstr(dst)); | 1831 target->AppendInstruction(new(Z) GotoInstr(dst)); |
| 1830 | 1832 |
| 1831 return target; | 1833 return target; |
| 1832 } | 1834 } |
| 1833 | 1835 |
| 1834 | 1836 |
| 1835 void IRRegExpMacroAssembler::CheckPreemption() { | 1837 void IRRegExpMacroAssembler::CheckPreemption() { |
| 1836 TAG(); | 1838 TAG(); |
| 1837 AppendInstruction(new(Z) CheckStackOverflowInstr(kNoSourcePos, 0)); | 1839 AppendInstruction(new(Z) CheckStackOverflowInstr( |
| 1840 TokenPosition::kNoSource, 0)); |
| 1838 } | 1841 } |
| 1839 | 1842 |
| 1840 | 1843 |
| 1841 Definition* IRRegExpMacroAssembler::Add( | 1844 Definition* IRRegExpMacroAssembler::Add( |
| 1842 PushArgumentInstr* lhs, | 1845 PushArgumentInstr* lhs, |
| 1843 PushArgumentInstr* rhs) { | 1846 PushArgumentInstr* rhs) { |
| 1844 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), lhs, rhs); | 1847 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), lhs, rhs); |
| 1845 } | 1848 } |
| 1846 | 1849 |
| 1847 | 1850 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1917 } | 1920 } |
| 1918 | 1921 |
| 1919 // Here pattern_val might be untagged so this must not trigger a GC. | 1922 // Here pattern_val might be untagged so this must not trigger a GC. |
| 1920 Value* index_val = BindLoadLocal(*index); | 1923 Value* index_val = BindLoadLocal(*index); |
| 1921 | 1924 |
| 1922 return Bind(new(Z) LoadCodeUnitsInstr( | 1925 return Bind(new(Z) LoadCodeUnitsInstr( |
| 1923 pattern_val, | 1926 pattern_val, |
| 1924 index_val, | 1927 index_val, |
| 1925 characters, | 1928 characters, |
| 1926 specialization_cid_, | 1929 specialization_cid_, |
| 1927 kNoSourcePos)); | 1930 TokenPosition::kNoSource)); |
| 1928 } | 1931 } |
| 1929 | 1932 |
| 1930 | 1933 |
| 1931 #undef __ | 1934 #undef __ |
| 1932 | 1935 |
| 1933 } // namespace dart | 1936 } // namespace dart |
| OLD | NEW |