| 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 22 matching lines...) Expand all Loading... |
| 33 #define PRINT(arg) \ | 33 #define PRINT(arg) \ |
| 34 if (FLAG_trace_irregexp) { \ | 34 if (FLAG_trace_irregexp) { \ |
| 35 Print(arg); \ | 35 Print(arg); \ |
| 36 } | 36 } |
| 37 | 37 |
| 38 namespace dart { | 38 namespace dart { |
| 39 | 39 |
| 40 static const intptr_t kInvalidTryIndex = CatchClauseNode::kInvalidTryIndex; | 40 static const intptr_t kInvalidTryIndex = CatchClauseNode::kInvalidTryIndex; |
| 41 static const intptr_t kMinStackSize = 512; | 41 static const intptr_t kMinStackSize = 512; |
| 42 | 42 |
| 43 | |
| 44 /* | 43 /* |
| 45 * This assembler uses the following main local variables: | 44 * This assembler uses the following main local variables: |
| 46 * - stack_: A pointer to a growable list which we use as an all-purpose stack | 45 * - stack_: A pointer to a growable list which we use as an all-purpose stack |
| 47 * storing backtracking offsets, positions & stored register values. | 46 * storing backtracking offsets, positions & stored register values. |
| 48 * - current_character_: Stores the currently loaded characters (possibly more | 47 * - current_character_: Stores the currently loaded characters (possibly more |
| 49 * than one). | 48 * than one). |
| 50 * - current_position_: The current position within the string, stored as a | 49 * - current_position_: The current position within the string, stored as a |
| 51 * negative offset from the end of the string (i.e. the | 50 * negative offset from the end of the string (i.e. the |
| 52 * position corresponding to str[0] is -str.length). | 51 * position corresponding to str[0] is -str.length). |
| 53 * Note that current_position_ is *not* byte-based, unlike | 52 * Note that current_position_ is *not* byte-based, unlike |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 blocks_.Add(entry_block_->normal_entry()); | 134 blocks_.Add(entry_block_->normal_entry()); |
| 136 blocks_.Add(start_block_); | 135 blocks_.Add(start_block_); |
| 137 blocks_.Add(success_block_); | 136 blocks_.Add(success_block_); |
| 138 blocks_.Add(backtrack_block_); | 137 blocks_.Add(backtrack_block_); |
| 139 blocks_.Add(exit_block_); | 138 blocks_.Add(exit_block_); |
| 140 | 139 |
| 141 // Begin emission at the start_block_. | 140 // Begin emission at the start_block_. |
| 142 set_current_instruction(start_block_); | 141 set_current_instruction(start_block_); |
| 143 } | 142 } |
| 144 | 143 |
| 145 | |
| 146 IRRegExpMacroAssembler::~IRRegExpMacroAssembler() {} | 144 IRRegExpMacroAssembler::~IRRegExpMacroAssembler() {} |
| 147 | 145 |
| 148 | |
| 149 void IRRegExpMacroAssembler::InitializeLocals() { | 146 void IRRegExpMacroAssembler::InitializeLocals() { |
| 150 // All generated functions are expected to have a current-context variable. | 147 // All generated functions are expected to have a current-context variable. |
| 151 // This variable is unused in irregexp functions. | 148 // This variable is unused in irregexp functions. |
| 152 parsed_function_->current_context_var()->set_index(GetNextLocalIndex()); | 149 parsed_function_->current_context_var()->set_index(GetNextLocalIndex()); |
| 153 | 150 |
| 154 // Create local variables and parameters. | 151 // Create local variables and parameters. |
| 155 stack_ = Local(Symbols::stack()); | 152 stack_ = Local(Symbols::stack()); |
| 156 stack_pointer_ = Local(Symbols::stack_pointer()); | 153 stack_pointer_ = Local(Symbols::stack_pointer()); |
| 157 registers_ = Local(Symbols::position_registers()); | 154 registers_ = Local(Symbols::position_registers()); |
| 158 current_character_ = Local(Symbols::current_character()); | 155 current_character_ = Local(Symbols::current_character()); |
| 159 current_position_ = Local(Symbols::current_position()); | 156 current_position_ = Local(Symbols::current_position()); |
| 160 string_param_length_ = Local(Symbols::string_param_length()); | 157 string_param_length_ = Local(Symbols::string_param_length()); |
| 161 capture_length_ = Local(Symbols::capture_length()); | 158 capture_length_ = Local(Symbols::capture_length()); |
| 162 match_start_index_ = Local(Symbols::match_start_index()); | 159 match_start_index_ = Local(Symbols::match_start_index()); |
| 163 capture_start_index_ = Local(Symbols::capture_start_index()); | 160 capture_start_index_ = Local(Symbols::capture_start_index()); |
| 164 match_end_index_ = Local(Symbols::match_end_index()); | 161 match_end_index_ = Local(Symbols::match_end_index()); |
| 165 char_in_capture_ = Local(Symbols::char_in_capture()); | 162 char_in_capture_ = Local(Symbols::char_in_capture()); |
| 166 char_in_match_ = Local(Symbols::char_in_match()); | 163 char_in_match_ = Local(Symbols::char_in_match()); |
| 167 index_temp_ = Local(Symbols::index_temp()); | 164 index_temp_ = Local(Symbols::index_temp()); |
| 168 result_ = Local(Symbols::result()); | 165 result_ = Local(Symbols::result()); |
| 169 | 166 |
| 170 string_param_ = Parameter(Symbols::string_param(), | 167 string_param_ = Parameter(Symbols::string_param(), |
| 171 RegExpMacroAssembler::kParamStringIndex); | 168 RegExpMacroAssembler::kParamStringIndex); |
| 172 start_index_param_ = Parameter(Symbols::start_index_param(), | 169 start_index_param_ = Parameter(Symbols::start_index_param(), |
| 173 RegExpMacroAssembler::kParamStartOffsetIndex); | 170 RegExpMacroAssembler::kParamStartOffsetIndex); |
| 174 } | 171 } |
| 175 | 172 |
| 176 | |
| 177 void IRRegExpMacroAssembler::GenerateEntryBlock() { | 173 void IRRegExpMacroAssembler::GenerateEntryBlock() { |
| 178 set_current_instruction(entry_block_->normal_entry()); | 174 set_current_instruction(entry_block_->normal_entry()); |
| 179 TAG(); | 175 TAG(); |
| 180 | 176 |
| 181 // Store string.length. | 177 // Store string.length. |
| 182 PushArgumentInstr* string_push = PushLocal(string_param_); | 178 PushArgumentInstr* string_push = PushLocal(string_param_); |
| 183 | 179 |
| 184 StoreLocal(string_param_length_, | 180 StoreLocal(string_param_length_, |
| 185 Bind(InstanceCall(InstanceCallDescriptor(String::ZoneHandle( | 181 Bind(InstanceCall(InstanceCallDescriptor(String::ZoneHandle( |
| 186 Field::GetterSymbol(Symbols::Length()))), | 182 Field::GetterSymbol(Symbols::Length()))), |
| (...skipping 17 matching lines...) Expand all Loading... |
| 204 StoreLocal(stack_, | 200 StoreLocal(stack_, |
| 205 Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), | 201 Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), |
| 206 stack_cell_push, | 202 stack_cell_push, |
| 207 PushArgument(Bind(Uint64Constant(0)))))); | 203 PushArgument(Bind(Uint64Constant(0)))))); |
| 208 StoreLocal(stack_pointer_, Bind(Int64Constant(-1))); | 204 StoreLocal(stack_pointer_, Bind(Int64Constant(-1))); |
| 209 | 205 |
| 210 // Jump to the start block. | 206 // Jump to the start block. |
| 211 current_instruction_->Goto(start_block_); | 207 current_instruction_->Goto(start_block_); |
| 212 } | 208 } |
| 213 | 209 |
| 214 | |
| 215 void IRRegExpMacroAssembler::GenerateBacktrackBlock() { | 210 void IRRegExpMacroAssembler::GenerateBacktrackBlock() { |
| 216 set_current_instruction(backtrack_block_); | 211 set_current_instruction(backtrack_block_); |
| 217 TAG(); | 212 TAG(); |
| 218 CheckPreemption(/*is_backtrack=*/true); | 213 CheckPreemption(/*is_backtrack=*/true); |
| 219 | 214 |
| 220 const intptr_t entries_count = entry_block_->indirect_entries().length(); | 215 const intptr_t entries_count = entry_block_->indirect_entries().length(); |
| 221 | 216 |
| 222 TypedData& offsets = TypedData::ZoneHandle( | 217 TypedData& offsets = TypedData::ZoneHandle( |
| 223 Z, TypedData::New(kTypedDataInt32ArrayCid, entries_count, Heap::kOld)); | 218 Z, TypedData::New(kTypedDataInt32ArrayCid, entries_count, Heap::kOld)); |
| 224 | 219 |
| 225 PushArgumentInstr* block_offsets_push = | 220 PushArgumentInstr* block_offsets_push = |
| 226 PushArgument(Bind(new (Z) ConstantInstr(offsets))); | 221 PushArgument(Bind(new (Z) ConstantInstr(offsets))); |
| 227 PushArgumentInstr* block_id_push = PushArgument(Bind(PopStack())); | 222 PushArgumentInstr* block_id_push = PushArgument(Bind(PopStack())); |
| 228 | 223 |
| 229 Value* offset_value = | 224 Value* offset_value = |
| 230 Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), | 225 Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), |
| 231 block_offsets_push, block_id_push)); | 226 block_offsets_push, block_id_push)); |
| 232 | 227 |
| 233 backtrack_goto_ = new (Z) IndirectGotoInstr(&offsets, offset_value); | 228 backtrack_goto_ = new (Z) IndirectGotoInstr(&offsets, offset_value); |
| 234 CloseBlockWith(backtrack_goto_); | 229 CloseBlockWith(backtrack_goto_); |
| 235 | 230 |
| 236 // Add an edge from the "indirect" goto to each of the targets. | 231 // Add an edge from the "indirect" goto to each of the targets. |
| 237 for (intptr_t j = 0; j < entries_count; j++) { | 232 for (intptr_t j = 0; j < entries_count; j++) { |
| 238 backtrack_goto_->AddSuccessor( | 233 backtrack_goto_->AddSuccessor( |
| 239 TargetWithJoinGoto(entry_block_->indirect_entries().At(j))); | 234 TargetWithJoinGoto(entry_block_->indirect_entries().At(j))); |
| 240 } | 235 } |
| 241 } | 236 } |
| 242 | 237 |
| 243 | |
| 244 void IRRegExpMacroAssembler::GenerateSuccessBlock() { | 238 void IRRegExpMacroAssembler::GenerateSuccessBlock() { |
| 245 set_current_instruction(success_block_); | 239 set_current_instruction(success_block_); |
| 246 TAG(); | 240 TAG(); |
| 247 | 241 |
| 248 Value* type = Bind(new (Z) ConstantInstr( | 242 Value* type = Bind(new (Z) ConstantInstr( |
| 249 TypeArguments::ZoneHandle(Z, TypeArguments::null()))); | 243 TypeArguments::ZoneHandle(Z, TypeArguments::null()))); |
| 250 Value* length = Bind(Uint64Constant(saved_registers_count_)); | 244 Value* length = Bind(Uint64Constant(saved_registers_count_)); |
| 251 Value* array = Bind(new (Z) CreateArrayInstr(TokenPosition::kNoSource, type, | 245 Value* array = Bind(new (Z) CreateArrayInstr(TokenPosition::kNoSource, type, |
| 252 length, GetNextDeoptId())); | 246 length, GetNextDeoptId())); |
| 253 StoreLocal(result_, array); | 247 StoreLocal(result_, array); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 269 } | 263 } |
| 270 | 264 |
| 271 // Print the result if tracing. | 265 // Print the result if tracing. |
| 272 PRINT(PushLocal(result_)); | 266 PRINT(PushLocal(result_)); |
| 273 | 267 |
| 274 // Return true on success. | 268 // Return true on success. |
| 275 AppendInstruction(new (Z) ReturnInstr( | 269 AppendInstruction(new (Z) ReturnInstr( |
| 276 TokenPosition::kNoSource, Bind(LoadLocal(result_)), GetNextDeoptId())); | 270 TokenPosition::kNoSource, Bind(LoadLocal(result_)), GetNextDeoptId())); |
| 277 } | 271 } |
| 278 | 272 |
| 279 | |
| 280 void IRRegExpMacroAssembler::GenerateExitBlock() { | 273 void IRRegExpMacroAssembler::GenerateExitBlock() { |
| 281 set_current_instruction(exit_block_); | 274 set_current_instruction(exit_block_); |
| 282 TAG(); | 275 TAG(); |
| 283 | 276 |
| 284 // Return false on failure. | 277 // Return false on failure. |
| 285 AppendInstruction(new (Z) ReturnInstr( | 278 AppendInstruction(new (Z) ReturnInstr( |
| 286 TokenPosition::kNoSource, Bind(LoadLocal(result_)), GetNextDeoptId())); | 279 TokenPosition::kNoSource, Bind(LoadLocal(result_)), GetNextDeoptId())); |
| 287 } | 280 } |
| 288 | 281 |
| 289 | |
| 290 void IRRegExpMacroAssembler::FinalizeRegistersArray() { | 282 void IRRegExpMacroAssembler::FinalizeRegistersArray() { |
| 291 ASSERT(registers_count_ >= saved_registers_count_); | 283 ASSERT(registers_count_ >= saved_registers_count_); |
| 292 registers_array_ = | 284 registers_array_ = |
| 293 TypedData::New(kTypedDataInt32ArrayCid, registers_count_, Heap::kOld); | 285 TypedData::New(kTypedDataInt32ArrayCid, registers_count_, Heap::kOld); |
| 294 } | 286 } |
| 295 | 287 |
| 296 | |
| 297 #if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_ARM) | 288 #if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_ARM) |
| 298 // Disabling unaligned accesses forces the regexp engine to load characters one | 289 // Disabling unaligned accesses forces the regexp engine to load characters one |
| 299 // by one instead of up to 4 at once, along with the associated performance hit. | 290 // by one instead of up to 4 at once, along with the associated performance hit. |
| 300 // TODO(zerny): Be less conservative about disabling unaligned accesses. | 291 // TODO(zerny): Be less conservative about disabling unaligned accesses. |
| 301 // For instance, ARMv6 supports unaligned accesses. Once it is enabled here, | 292 // For instance, ARMv6 supports unaligned accesses. Once it is enabled here, |
| 302 // update LoadCodeUnitsInstr methods for the appropriate architectures. | 293 // update LoadCodeUnitsInstr methods for the appropriate architectures. |
| 303 static const bool kEnableUnalignedAccesses = false; | 294 static const bool kEnableUnalignedAccesses = false; |
| 304 #else | 295 #else |
| 305 static const bool kEnableUnalignedAccesses = true; | 296 static const bool kEnableUnalignedAccesses = true; |
| 306 #endif | 297 #endif |
| 307 bool IRRegExpMacroAssembler::CanReadUnaligned() { | 298 bool IRRegExpMacroAssembler::CanReadUnaligned() { |
| 308 return kEnableUnalignedAccesses && !slow_safe(); | 299 return kEnableUnalignedAccesses && !slow_safe(); |
| 309 } | 300 } |
| 310 | 301 |
| 311 | |
| 312 RawArray* IRRegExpMacroAssembler::Execute(const RegExp& regexp, | 302 RawArray* IRRegExpMacroAssembler::Execute(const RegExp& regexp, |
| 313 const String& input, | 303 const String& input, |
| 314 const Smi& start_offset, | 304 const Smi& start_offset, |
| 315 bool sticky, | 305 bool sticky, |
| 316 Zone* zone) { | 306 Zone* zone) { |
| 317 const intptr_t cid = input.GetClassId(); | 307 const intptr_t cid = input.GetClassId(); |
| 318 const Function& fun = Function::Handle(regexp.function(cid, sticky)); | 308 const Function& fun = Function::Handle(regexp.function(cid, sticky)); |
| 319 ASSERT(!fun.IsNull()); | 309 ASSERT(!fun.IsNull()); |
| 320 // Create the argument list. | 310 // Create the argument list. |
| 321 const Array& args = | 311 const Array& args = |
| (...skipping 14 matching lines...) Expand all Loading... |
| 336 } | 326 } |
| 337 | 327 |
| 338 if (retval.IsNull()) { | 328 if (retval.IsNull()) { |
| 339 return Array::null(); | 329 return Array::null(); |
| 340 } | 330 } |
| 341 | 331 |
| 342 ASSERT(retval.IsArray()); | 332 ASSERT(retval.IsArray()); |
| 343 return Array::Cast(retval).raw(); | 333 return Array::Cast(retval).raw(); |
| 344 } | 334 } |
| 345 | 335 |
| 346 | |
| 347 LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name, | 336 LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name, |
| 348 intptr_t index) const { | 337 intptr_t index) const { |
| 349 LocalVariable* local = | 338 LocalVariable* local = |
| 350 new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, | 339 new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, |
| 351 name, Object::dynamic_type()); | 340 name, Object::dynamic_type()); |
| 352 | 341 |
| 353 intptr_t param_frame_index = kParamEndSlotFromFp + kParamCount - index; | 342 intptr_t param_frame_index = kParamEndSlotFromFp + kParamCount - index; |
| 354 local->set_index(param_frame_index); | 343 local->set_index(param_frame_index); |
| 355 | 344 |
| 356 return local; | 345 return local; |
| 357 } | 346 } |
| 358 | 347 |
| 359 | |
| 360 LocalVariable* IRRegExpMacroAssembler::Local(const String& name) { | 348 LocalVariable* IRRegExpMacroAssembler::Local(const String& name) { |
| 361 LocalVariable* local = | 349 LocalVariable* local = |
| 362 new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, | 350 new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, |
| 363 name, Object::dynamic_type()); | 351 name, Object::dynamic_type()); |
| 364 local->set_index(GetNextLocalIndex()); | 352 local->set_index(GetNextLocalIndex()); |
| 365 | 353 |
| 366 return local; | 354 return local; |
| 367 } | 355 } |
| 368 | 356 |
| 369 | |
| 370 ConstantInstr* IRRegExpMacroAssembler::Int64Constant(int64_t value) const { | 357 ConstantInstr* IRRegExpMacroAssembler::Int64Constant(int64_t value) const { |
| 371 return new (Z) | 358 return new (Z) |
| 372 ConstantInstr(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld))); | 359 ConstantInstr(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld))); |
| 373 } | 360 } |
| 374 | 361 |
| 375 | |
| 376 ConstantInstr* IRRegExpMacroAssembler::Uint64Constant(uint64_t value) const { | 362 ConstantInstr* IRRegExpMacroAssembler::Uint64Constant(uint64_t value) const { |
| 377 return new (Z) ConstantInstr( | 363 return new (Z) ConstantInstr( |
| 378 Integer::ZoneHandle(Z, Integer::NewFromUint64(value, Heap::kOld))); | 364 Integer::ZoneHandle(Z, Integer::NewFromUint64(value, Heap::kOld))); |
| 379 } | 365 } |
| 380 | 366 |
| 381 | |
| 382 ConstantInstr* IRRegExpMacroAssembler::BoolConstant(bool value) const { | 367 ConstantInstr* IRRegExpMacroAssembler::BoolConstant(bool value) const { |
| 383 return new (Z) ConstantInstr(value ? Bool::True() : Bool::False()); | 368 return new (Z) ConstantInstr(value ? Bool::True() : Bool::False()); |
| 384 } | 369 } |
| 385 | 370 |
| 386 | |
| 387 ConstantInstr* IRRegExpMacroAssembler::StringConstant(const char* value) const { | 371 ConstantInstr* IRRegExpMacroAssembler::StringConstant(const char* value) const { |
| 388 return new (Z) | 372 return new (Z) |
| 389 ConstantInstr(String::ZoneHandle(Z, String::New(value, Heap::kOld))); | 373 ConstantInstr(String::ZoneHandle(Z, String::New(value, Heap::kOld))); |
| 390 } | 374 } |
| 391 | 375 |
| 392 | |
| 393 ConstantInstr* IRRegExpMacroAssembler::WordCharacterMapConstant() const { | 376 ConstantInstr* IRRegExpMacroAssembler::WordCharacterMapConstant() const { |
| 394 const Library& lib = Library::Handle(Z, Library::CoreLibrary()); | 377 const Library& lib = Library::Handle(Z, Library::CoreLibrary()); |
| 395 const Class& regexp_class = | 378 const Class& regexp_class = |
| 396 Class::Handle(Z, lib.LookupClassAllowPrivate(Symbols::_RegExp())); | 379 Class::Handle(Z, lib.LookupClassAllowPrivate(Symbols::_RegExp())); |
| 397 const Field& word_character_field = Field::ZoneHandle( | 380 const Field& word_character_field = Field::ZoneHandle( |
| 398 Z, | 381 Z, |
| 399 regexp_class.LookupStaticFieldAllowPrivate(Symbols::_wordCharacterMap())); | 382 regexp_class.LookupStaticFieldAllowPrivate(Symbols::_wordCharacterMap())); |
| 400 ASSERT(!word_character_field.IsNull()); | 383 ASSERT(!word_character_field.IsNull()); |
| 401 | 384 |
| 402 if (word_character_field.IsUninitialized()) { | 385 if (word_character_field.IsUninitialized()) { |
| 403 ASSERT(!Compiler::IsBackgroundCompilation()); | 386 ASSERT(!Compiler::IsBackgroundCompilation()); |
| 404 word_character_field.EvaluateInitializer(); | 387 word_character_field.EvaluateInitializer(); |
| 405 } | 388 } |
| 406 ASSERT(!word_character_field.IsUninitialized()); | 389 ASSERT(!word_character_field.IsUninitialized()); |
| 407 | 390 |
| 408 return new (Z) ConstantInstr( | 391 return new (Z) ConstantInstr( |
| 409 Instance::ZoneHandle(Z, word_character_field.StaticValue())); | 392 Instance::ZoneHandle(Z, word_character_field.StaticValue())); |
| 410 } | 393 } |
| 411 | 394 |
| 412 | |
| 413 ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind, | 395 ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind, |
| 414 PushArgumentInstr* lhs, | 396 PushArgumentInstr* lhs, |
| 415 PushArgumentInstr* rhs) { | 397 PushArgumentInstr* rhs) { |
| 416 Token::Kind strict_comparison = Token::kEQ_STRICT; | 398 Token::Kind strict_comparison = Token::kEQ_STRICT; |
| 417 Token::Kind intermediate_operator = Token::kILLEGAL; | 399 Token::Kind intermediate_operator = Token::kILLEGAL; |
| 418 switch (kind) { | 400 switch (kind) { |
| 419 case kEQ: | 401 case kEQ: |
| 420 intermediate_operator = Token::kEQ; | 402 intermediate_operator = Token::kEQ; |
| 421 break; | 403 break; |
| 422 case kNE: | 404 case kNE: |
| (...skipping 28 matching lines...) Expand all Loading... |
| 451 } | 433 } |
| 452 | 434 |
| 453 ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind, | 435 ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind, |
| 454 Definition* lhs, | 436 Definition* lhs, |
| 455 Definition* rhs) { | 437 Definition* rhs) { |
| 456 PushArgumentInstr* lhs_push = PushArgument(Bind(lhs)); | 438 PushArgumentInstr* lhs_push = PushArgument(Bind(lhs)); |
| 457 PushArgumentInstr* rhs_push = PushArgument(Bind(rhs)); | 439 PushArgumentInstr* rhs_push = PushArgument(Bind(rhs)); |
| 458 return Comparison(kind, lhs_push, rhs_push); | 440 return Comparison(kind, lhs_push, rhs_push); |
| 459 } | 441 } |
| 460 | 442 |
| 461 | |
| 462 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( | 443 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( |
| 463 const Function& function) const { | 444 const Function& function) const { |
| 464 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 445 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 465 new (Z) ZoneGrowableArray<PushArgumentInstr*>(0); | 446 new (Z) ZoneGrowableArray<PushArgumentInstr*>(0); |
| 466 return StaticCall(function, arguments); | 447 return StaticCall(function, arguments); |
| 467 } | 448 } |
| 468 | 449 |
| 469 | |
| 470 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( | 450 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( |
| 471 const Function& function, | 451 const Function& function, |
| 472 PushArgumentInstr* arg1) const { | 452 PushArgumentInstr* arg1) const { |
| 473 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 453 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 474 new (Z) ZoneGrowableArray<PushArgumentInstr*>(1); | 454 new (Z) ZoneGrowableArray<PushArgumentInstr*>(1); |
| 475 arguments->Add(arg1); | 455 arguments->Add(arg1); |
| 476 | 456 |
| 477 return StaticCall(function, arguments); | 457 return StaticCall(function, arguments); |
| 478 } | 458 } |
| 479 | 459 |
| 480 | |
| 481 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( | 460 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( |
| 482 const Function& function, | 461 const Function& function, |
| 483 PushArgumentInstr* arg1, | 462 PushArgumentInstr* arg1, |
| 484 PushArgumentInstr* arg2) const { | 463 PushArgumentInstr* arg2) const { |
| 485 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 464 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 486 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); | 465 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); |
| 487 arguments->Add(arg1); | 466 arguments->Add(arg1); |
| 488 arguments->Add(arg2); | 467 arguments->Add(arg2); |
| 489 | 468 |
| 490 return StaticCall(function, arguments); | 469 return StaticCall(function, arguments); |
| 491 } | 470 } |
| 492 | 471 |
| 493 | |
| 494 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( | 472 StaticCallInstr* IRRegExpMacroAssembler::StaticCall( |
| 495 const Function& function, | 473 const Function& function, |
| 496 ZoneGrowableArray<PushArgumentInstr*>* arguments) const { | 474 ZoneGrowableArray<PushArgumentInstr*>* arguments) const { |
| 497 const intptr_t kTypeArgsLen = 0; | 475 const intptr_t kTypeArgsLen = 0; |
| 498 return new (Z) StaticCallInstr(TokenPosition::kNoSource, function, | 476 return new (Z) StaticCallInstr(TokenPosition::kNoSource, function, |
| 499 kTypeArgsLen, Object::null_array(), arguments, | 477 kTypeArgsLen, Object::null_array(), arguments, |
| 500 ic_data_array_, GetNextDeoptId()); | 478 ic_data_array_, GetNextDeoptId()); |
| 501 } | 479 } |
| 502 | 480 |
| 503 | |
| 504 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( | 481 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( |
| 505 const InstanceCallDescriptor& desc, | 482 const InstanceCallDescriptor& desc, |
| 506 PushArgumentInstr* arg1) const { | 483 PushArgumentInstr* arg1) const { |
| 507 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 484 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 508 new (Z) ZoneGrowableArray<PushArgumentInstr*>(1); | 485 new (Z) ZoneGrowableArray<PushArgumentInstr*>(1); |
| 509 arguments->Add(arg1); | 486 arguments->Add(arg1); |
| 510 | 487 |
| 511 return InstanceCall(desc, arguments); | 488 return InstanceCall(desc, arguments); |
| 512 } | 489 } |
| 513 | 490 |
| 514 | |
| 515 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( | 491 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( |
| 516 const InstanceCallDescriptor& desc, | 492 const InstanceCallDescriptor& desc, |
| 517 PushArgumentInstr* arg1, | 493 PushArgumentInstr* arg1, |
| 518 PushArgumentInstr* arg2) const { | 494 PushArgumentInstr* arg2) const { |
| 519 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 495 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 520 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); | 496 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); |
| 521 arguments->Add(arg1); | 497 arguments->Add(arg1); |
| 522 arguments->Add(arg2); | 498 arguments->Add(arg2); |
| 523 | 499 |
| 524 return InstanceCall(desc, arguments); | 500 return InstanceCall(desc, arguments); |
| 525 } | 501 } |
| 526 | 502 |
| 527 | |
| 528 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( | 503 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( |
| 529 const InstanceCallDescriptor& desc, | 504 const InstanceCallDescriptor& desc, |
| 530 PushArgumentInstr* arg1, | 505 PushArgumentInstr* arg1, |
| 531 PushArgumentInstr* arg2, | 506 PushArgumentInstr* arg2, |
| 532 PushArgumentInstr* arg3) const { | 507 PushArgumentInstr* arg3) const { |
| 533 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 508 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 534 new (Z) ZoneGrowableArray<PushArgumentInstr*>(3); | 509 new (Z) ZoneGrowableArray<PushArgumentInstr*>(3); |
| 535 arguments->Add(arg1); | 510 arguments->Add(arg1); |
| 536 arguments->Add(arg2); | 511 arguments->Add(arg2); |
| 537 arguments->Add(arg3); | 512 arguments->Add(arg3); |
| 538 | 513 |
| 539 return InstanceCall(desc, arguments); | 514 return InstanceCall(desc, arguments); |
| 540 } | 515 } |
| 541 | 516 |
| 542 | |
| 543 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( | 517 InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( |
| 544 const InstanceCallDescriptor& desc, | 518 const InstanceCallDescriptor& desc, |
| 545 ZoneGrowableArray<PushArgumentInstr*>* arguments) const { | 519 ZoneGrowableArray<PushArgumentInstr*>* arguments) const { |
| 546 const intptr_t kTypeArgsLen = 0; | 520 const intptr_t kTypeArgsLen = 0; |
| 547 return new (Z) InstanceCallInstr( | 521 return new (Z) InstanceCallInstr( |
| 548 TokenPosition::kNoSource, desc.name, desc.token_kind, arguments, | 522 TokenPosition::kNoSource, desc.name, desc.token_kind, arguments, |
| 549 kTypeArgsLen, Object::null_array(), desc.checked_argument_count, | 523 kTypeArgsLen, Object::null_array(), desc.checked_argument_count, |
| 550 ic_data_array_, GetNextDeoptId()); | 524 ic_data_array_, GetNextDeoptId()); |
| 551 } | 525 } |
| 552 | 526 |
| 553 | |
| 554 LoadLocalInstr* IRRegExpMacroAssembler::LoadLocal(LocalVariable* local) const { | 527 LoadLocalInstr* IRRegExpMacroAssembler::LoadLocal(LocalVariable* local) const { |
| 555 return new (Z) LoadLocalInstr(*local, TokenPosition::kNoSource); | 528 return new (Z) LoadLocalInstr(*local, TokenPosition::kNoSource); |
| 556 } | 529 } |
| 557 | 530 |
| 558 | |
| 559 void IRRegExpMacroAssembler::StoreLocal(LocalVariable* local, Value* value) { | 531 void IRRegExpMacroAssembler::StoreLocal(LocalVariable* local, Value* value) { |
| 560 Do(new (Z) StoreLocalInstr(*local, value, TokenPosition::kNoSource)); | 532 Do(new (Z) StoreLocalInstr(*local, value, TokenPosition::kNoSource)); |
| 561 } | 533 } |
| 562 | 534 |
| 563 | |
| 564 void IRRegExpMacroAssembler::set_current_instruction(Instruction* instruction) { | 535 void IRRegExpMacroAssembler::set_current_instruction(Instruction* instruction) { |
| 565 current_instruction_ = instruction; | 536 current_instruction_ = instruction; |
| 566 } | 537 } |
| 567 | 538 |
| 568 | |
| 569 Value* IRRegExpMacroAssembler::Bind(Definition* definition) { | 539 Value* IRRegExpMacroAssembler::Bind(Definition* definition) { |
| 570 AppendInstruction(definition); | 540 AppendInstruction(definition); |
| 571 definition->set_temp_index(temp_id_.Alloc()); | 541 definition->set_temp_index(temp_id_.Alloc()); |
| 572 | 542 |
| 573 return new (Z) Value(definition); | 543 return new (Z) Value(definition); |
| 574 } | 544 } |
| 575 | 545 |
| 576 | |
| 577 void IRRegExpMacroAssembler::Do(Definition* definition) { | 546 void IRRegExpMacroAssembler::Do(Definition* definition) { |
| 578 AppendInstruction(definition); | 547 AppendInstruction(definition); |
| 579 } | 548 } |
| 580 | 549 |
| 581 | |
| 582 Value* IRRegExpMacroAssembler::BindLoadLocal(const LocalVariable& local) { | 550 Value* IRRegExpMacroAssembler::BindLoadLocal(const LocalVariable& local) { |
| 583 if (local.IsConst()) { | 551 if (local.IsConst()) { |
| 584 return Bind(new (Z) ConstantInstr(*local.ConstValue())); | 552 return Bind(new (Z) ConstantInstr(*local.ConstValue())); |
| 585 } | 553 } |
| 586 ASSERT(!local.is_captured()); | 554 ASSERT(!local.is_captured()); |
| 587 return Bind(new (Z) LoadLocalInstr(local, TokenPosition::kNoSource)); | 555 return Bind(new (Z) LoadLocalInstr(local, TokenPosition::kNoSource)); |
| 588 } | 556 } |
| 589 | 557 |
| 590 | |
| 591 // In some cases, the V8 irregexp engine generates unreachable code by emitting | 558 // In some cases, the V8 irregexp engine generates unreachable code by emitting |
| 592 // a jmp not followed by a bind. We cannot do the same, since it is impossible | 559 // a jmp not followed by a bind. We cannot do the same, since it is impossible |
| 593 // to append to a block following a jmp. In such cases, assume that we are doing | 560 // to append to a block following a jmp. In such cases, assume that we are doing |
| 594 // the correct thing, but output a warning when tracing. | 561 // the correct thing, but output a warning when tracing. |
| 595 #define HANDLE_DEAD_CODE_EMISSION() \ | 562 #define HANDLE_DEAD_CODE_EMISSION() \ |
| 596 if (current_instruction_ == NULL) { \ | 563 if (current_instruction_ == NULL) { \ |
| 597 if (FLAG_trace_irregexp) { \ | 564 if (FLAG_trace_irregexp) { \ |
| 598 OS::Print( \ | 565 OS::Print( \ |
| 599 "WARNING: Attempting to append to a closed assembler. " \ | 566 "WARNING: Attempting to append to a closed assembler. " \ |
| 600 "This could be either a bug or generation of dead code " \ | 567 "This could be either a bug or generation of dead code " \ |
| 601 "inherited from V8.\n"); \ | 568 "inherited from V8.\n"); \ |
| 602 } \ | 569 } \ |
| 603 BlockLabel dummy; \ | 570 BlockLabel dummy; \ |
| 604 BindBlock(&dummy); \ | 571 BindBlock(&dummy); \ |
| 605 } | 572 } |
| 606 | 573 |
| 607 void IRRegExpMacroAssembler::AppendInstruction(Instruction* instruction) { | 574 void IRRegExpMacroAssembler::AppendInstruction(Instruction* instruction) { |
| 608 HANDLE_DEAD_CODE_EMISSION(); | 575 HANDLE_DEAD_CODE_EMISSION(); |
| 609 | 576 |
| 610 ASSERT(current_instruction_ != NULL); | 577 ASSERT(current_instruction_ != NULL); |
| 611 ASSERT(current_instruction_->next() == NULL); | 578 ASSERT(current_instruction_->next() == NULL); |
| 612 | 579 |
| 613 temp_id_.Dealloc(instruction->InputCount()); | 580 temp_id_.Dealloc(instruction->InputCount()); |
| 614 arg_id_.Dealloc(instruction->ArgumentCount()); | 581 arg_id_.Dealloc(instruction->ArgumentCount()); |
| 615 | 582 |
| 616 current_instruction_->LinkTo(instruction); | 583 current_instruction_->LinkTo(instruction); |
| 617 set_current_instruction(instruction); | 584 set_current_instruction(instruction); |
| 618 } | 585 } |
| 619 | 586 |
| 620 | |
| 621 void IRRegExpMacroAssembler::CloseBlockWith(Instruction* instruction) { | 587 void IRRegExpMacroAssembler::CloseBlockWith(Instruction* instruction) { |
| 622 HANDLE_DEAD_CODE_EMISSION(); | 588 HANDLE_DEAD_CODE_EMISSION(); |
| 623 | 589 |
| 624 ASSERT(current_instruction_ != NULL); | 590 ASSERT(current_instruction_ != NULL); |
| 625 ASSERT(current_instruction_->next() == NULL); | 591 ASSERT(current_instruction_->next() == NULL); |
| 626 | 592 |
| 627 temp_id_.Dealloc(instruction->InputCount()); | 593 temp_id_.Dealloc(instruction->InputCount()); |
| 628 arg_id_.Dealloc(instruction->ArgumentCount()); | 594 arg_id_.Dealloc(instruction->ArgumentCount()); |
| 629 | 595 |
| 630 current_instruction_->LinkTo(instruction); | 596 current_instruction_->LinkTo(instruction); |
| 631 set_current_instruction(NULL); | 597 set_current_instruction(NULL); |
| 632 } | 598 } |
| 633 | 599 |
| 634 | |
| 635 void IRRegExpMacroAssembler::GoTo(BlockLabel* to) { | 600 void IRRegExpMacroAssembler::GoTo(BlockLabel* to) { |
| 636 if (to == NULL) { | 601 if (to == NULL) { |
| 637 Backtrack(); | 602 Backtrack(); |
| 638 } else { | 603 } else { |
| 639 to->SetLinked(); | 604 to->SetLinked(); |
| 640 GoTo(to->block()); | 605 GoTo(to->block()); |
| 641 } | 606 } |
| 642 } | 607 } |
| 643 | 608 |
| 644 | |
| 645 // Closes the current block with a goto, and unsets current_instruction_. | 609 // Closes the current block with a goto, and unsets current_instruction_. |
| 646 // BindBlock() must be called before emission can continue. | 610 // BindBlock() must be called before emission can continue. |
| 647 void IRRegExpMacroAssembler::GoTo(JoinEntryInstr* to) { | 611 void IRRegExpMacroAssembler::GoTo(JoinEntryInstr* to) { |
| 648 HANDLE_DEAD_CODE_EMISSION(); | 612 HANDLE_DEAD_CODE_EMISSION(); |
| 649 | 613 |
| 650 ASSERT(current_instruction_ != NULL); | 614 ASSERT(current_instruction_ != NULL); |
| 651 ASSERT(current_instruction_->next() == NULL); | 615 ASSERT(current_instruction_->next() == NULL); |
| 652 current_instruction_->Goto(to); | 616 current_instruction_->Goto(to); |
| 653 set_current_instruction(NULL); | 617 set_current_instruction(NULL); |
| 654 } | 618 } |
| 655 | 619 |
| 656 | |
| 657 PushArgumentInstr* IRRegExpMacroAssembler::PushArgument(Value* value) { | 620 PushArgumentInstr* IRRegExpMacroAssembler::PushArgument(Value* value) { |
| 658 arg_id_.Alloc(); | 621 arg_id_.Alloc(); |
| 659 PushArgumentInstr* push = new (Z) PushArgumentInstr(value); | 622 PushArgumentInstr* push = new (Z) PushArgumentInstr(value); |
| 660 // Do *not* use Do() for push argument instructions. | 623 // Do *not* use Do() for push argument instructions. |
| 661 AppendInstruction(push); | 624 AppendInstruction(push); |
| 662 return push; | 625 return push; |
| 663 } | 626 } |
| 664 | 627 |
| 665 | |
| 666 PushArgumentInstr* IRRegExpMacroAssembler::PushLocal(LocalVariable* local) { | 628 PushArgumentInstr* IRRegExpMacroAssembler::PushLocal(LocalVariable* local) { |
| 667 return PushArgument(Bind(LoadLocal(local))); | 629 return PushArgument(Bind(LoadLocal(local))); |
| 668 } | 630 } |
| 669 | 631 |
| 670 | |
| 671 void IRRegExpMacroAssembler::Print(const char* str) { | 632 void IRRegExpMacroAssembler::Print(const char* str) { |
| 672 Print(PushArgument(Bind(new (Z) ConstantInstr( | 633 Print(PushArgument(Bind(new (Z) ConstantInstr( |
| 673 String::ZoneHandle(Z, String::New(str, Heap::kOld)))))); | 634 String::ZoneHandle(Z, String::New(str, Heap::kOld)))))); |
| 674 } | 635 } |
| 675 | 636 |
| 676 | |
| 677 void IRRegExpMacroAssembler::Print(PushArgumentInstr* argument) { | 637 void IRRegExpMacroAssembler::Print(PushArgumentInstr* argument) { |
| 678 const Library& lib = Library::Handle(Library::CoreLibrary()); | 638 const Library& lib = Library::Handle(Library::CoreLibrary()); |
| 679 const Function& print_fn = | 639 const Function& print_fn = |
| 680 Function::ZoneHandle(Z, lib.LookupFunctionAllowPrivate(Symbols::print())); | 640 Function::ZoneHandle(Z, lib.LookupFunctionAllowPrivate(Symbols::print())); |
| 681 Do(StaticCall(print_fn, argument)); | 641 Do(StaticCall(print_fn, argument)); |
| 682 } | 642 } |
| 683 | 643 |
| 684 | |
| 685 void IRRegExpMacroAssembler::PrintBlocks() { | 644 void IRRegExpMacroAssembler::PrintBlocks() { |
| 686 for (intptr_t i = 0; i < blocks_.length(); i++) { | 645 for (intptr_t i = 0; i < blocks_.length(); i++) { |
| 687 FlowGraphPrinter::PrintBlock(blocks_[i], false); | 646 FlowGraphPrinter::PrintBlock(blocks_[i], false); |
| 688 } | 647 } |
| 689 } | 648 } |
| 690 | 649 |
| 691 | |
| 692 intptr_t IRRegExpMacroAssembler::stack_limit_slack() { | 650 intptr_t IRRegExpMacroAssembler::stack_limit_slack() { |
| 693 return 32; | 651 return 32; |
| 694 } | 652 } |
| 695 | 653 |
| 696 | |
| 697 void IRRegExpMacroAssembler::AdvanceCurrentPosition(intptr_t by) { | 654 void IRRegExpMacroAssembler::AdvanceCurrentPosition(intptr_t by) { |
| 698 TAG(); | 655 TAG(); |
| 699 if (by != 0) { | 656 if (by != 0) { |
| 700 PushArgumentInstr* cur_pos_push = PushLocal(current_position_); | 657 PushArgumentInstr* cur_pos_push = PushLocal(current_position_); |
| 701 PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by))); | 658 PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by))); |
| 702 | 659 |
| 703 Value* new_pos_value = Bind(Add(cur_pos_push, by_push)); | 660 Value* new_pos_value = Bind(Add(cur_pos_push, by_push)); |
| 704 StoreLocal(current_position_, new_pos_value); | 661 StoreLocal(current_position_, new_pos_value); |
| 705 } | 662 } |
| 706 } | 663 } |
| 707 | 664 |
| 708 | |
| 709 void IRRegExpMacroAssembler::AdvanceRegister(intptr_t reg, intptr_t by) { | 665 void IRRegExpMacroAssembler::AdvanceRegister(intptr_t reg, intptr_t by) { |
| 710 TAG(); | 666 TAG(); |
| 711 ASSERT(reg >= 0); | 667 ASSERT(reg >= 0); |
| 712 ASSERT(reg < registers_count_); | 668 ASSERT(reg < registers_count_); |
| 713 | 669 |
| 714 if (by != 0) { | 670 if (by != 0) { |
| 715 PushArgumentInstr* registers_push = PushLocal(registers_); | 671 PushArgumentInstr* registers_push = PushLocal(registers_); |
| 716 PushArgumentInstr* index_push = PushRegisterIndex(reg); | 672 PushArgumentInstr* index_push = PushRegisterIndex(reg); |
| 717 PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); | 673 PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); |
| 718 PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by))); | 674 PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by))); |
| 719 PushArgumentInstr* value_push = PushArgument(Bind(Add(reg_push, by_push))); | 675 PushArgumentInstr* value_push = PushArgument(Bind(Add(reg_push, by_push))); |
| 720 StoreRegister(registers_push, index_push, value_push); | 676 StoreRegister(registers_push, index_push, value_push); |
| 721 } | 677 } |
| 722 } | 678 } |
| 723 | 679 |
| 724 | |
| 725 void IRRegExpMacroAssembler::Backtrack() { | 680 void IRRegExpMacroAssembler::Backtrack() { |
| 726 TAG(); | 681 TAG(); |
| 727 GoTo(backtrack_block_); | 682 GoTo(backtrack_block_); |
| 728 } | 683 } |
| 729 | 684 |
| 730 | |
| 731 // A BindBlock is analogous to assigning a label to a basic block. | 685 // A BindBlock is analogous to assigning a label to a basic block. |
| 732 // If the BlockLabel does not yet contain a block, it is created. | 686 // If the BlockLabel does not yet contain a block, it is created. |
| 733 // If there is a current instruction, append a goto to the bound block. | 687 // If there is a current instruction, append a goto to the bound block. |
| 734 void IRRegExpMacroAssembler::BindBlock(BlockLabel* label) { | 688 void IRRegExpMacroAssembler::BindBlock(BlockLabel* label) { |
| 735 ASSERT(!label->IsBound()); | 689 ASSERT(!label->IsBound()); |
| 736 ASSERT(label->block()->next() == NULL); | 690 ASSERT(label->block()->next() == NULL); |
| 737 | 691 |
| 738 label->SetBound(block_id_.Alloc()); | 692 label->SetBound(block_id_.Alloc()); |
| 739 blocks_.Add(label->block()); | 693 blocks_.Add(label->block()); |
| 740 | 694 |
| 741 if (current_instruction_ != NULL) { | 695 if (current_instruction_ != NULL) { |
| 742 GoTo(label); | 696 GoTo(label); |
| 743 } | 697 } |
| 744 set_current_instruction(label->block()); | 698 set_current_instruction(label->block()); |
| 745 | 699 |
| 746 // Print the id of the current block if tracing. | 700 // Print the id of the current block if tracing. |
| 747 PRINT(PushArgument(Bind(Uint64Constant(label->block()->block_id())))); | 701 PRINT(PushArgument(Bind(Uint64Constant(label->block()->block_id())))); |
| 748 } | 702 } |
| 749 | 703 |
| 750 | |
| 751 intptr_t IRRegExpMacroAssembler::GetNextLocalIndex() { | 704 intptr_t IRRegExpMacroAssembler::GetNextLocalIndex() { |
| 752 intptr_t id = local_id_.Alloc(); | 705 intptr_t id = local_id_.Alloc(); |
| 753 return kFirstLocalSlotFromFp - id; | 706 return kFirstLocalSlotFromFp - id; |
| 754 } | 707 } |
| 755 | 708 |
| 756 | |
| 757 Value* IRRegExpMacroAssembler::LoadRegister(intptr_t index) { | 709 Value* IRRegExpMacroAssembler::LoadRegister(intptr_t index) { |
| 758 PushArgumentInstr* registers_push = PushLocal(registers_); | 710 PushArgumentInstr* registers_push = PushLocal(registers_); |
| 759 PushArgumentInstr* index_push = PushRegisterIndex(index); | 711 PushArgumentInstr* index_push = PushRegisterIndex(index); |
| 760 return Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), | 712 return Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), |
| 761 registers_push, index_push)); | 713 registers_push, index_push)); |
| 762 } | 714 } |
| 763 | 715 |
| 764 void IRRegExpMacroAssembler::StoreRegister(intptr_t index, intptr_t value) { | 716 void IRRegExpMacroAssembler::StoreRegister(intptr_t index, intptr_t value) { |
| 765 PushArgumentInstr* registers_push = PushLocal(registers_); | 717 PushArgumentInstr* registers_push = PushLocal(registers_); |
| 766 PushArgumentInstr* index_push = PushRegisterIndex(index); | 718 PushArgumentInstr* index_push = PushRegisterIndex(index); |
| 767 PushArgumentInstr* value_push = PushArgument(Bind(Uint64Constant(value))); | 719 PushArgumentInstr* value_push = PushArgument(Bind(Uint64Constant(value))); |
| 768 StoreRegister(registers_push, index_push, value_push); | 720 StoreRegister(registers_push, index_push, value_push); |
| 769 } | 721 } |
| 770 | 722 |
| 771 | |
| 772 void IRRegExpMacroAssembler::StoreRegister(PushArgumentInstr* registers, | 723 void IRRegExpMacroAssembler::StoreRegister(PushArgumentInstr* registers, |
| 773 PushArgumentInstr* index, | 724 PushArgumentInstr* index, |
| 774 PushArgumentInstr* value) { | 725 PushArgumentInstr* value) { |
| 775 TAG(); | 726 TAG(); |
| 776 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), | 727 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), |
| 777 registers, index, value)); | 728 registers, index, value)); |
| 778 } | 729 } |
| 779 | 730 |
| 780 PushArgumentInstr* IRRegExpMacroAssembler::PushRegisterIndex(intptr_t index) { | 731 PushArgumentInstr* IRRegExpMacroAssembler::PushRegisterIndex(intptr_t index) { |
| 781 if (registers_count_ <= index) { | 732 if (registers_count_ <= index) { |
| 782 registers_count_ = index + 1; | 733 registers_count_ = index + 1; |
| 783 } | 734 } |
| 784 return PushArgument(Bind(Uint64Constant(index))); | 735 return PushArgument(Bind(Uint64Constant(index))); |
| 785 } | 736 } |
| 786 | 737 |
| 787 | |
| 788 void IRRegExpMacroAssembler::CheckCharacter(uint32_t c, BlockLabel* on_equal) { | 738 void IRRegExpMacroAssembler::CheckCharacter(uint32_t c, BlockLabel* on_equal) { |
| 789 TAG(); | 739 TAG(); |
| 790 Definition* cur_char_def = LoadLocal(current_character_); | 740 Definition* cur_char_def = LoadLocal(current_character_); |
| 791 Definition* char_def = Uint64Constant(c); | 741 Definition* char_def = Uint64Constant(c); |
| 792 | 742 |
| 793 BranchOrBacktrack(Comparison(kEQ, cur_char_def, char_def), on_equal); | 743 BranchOrBacktrack(Comparison(kEQ, cur_char_def, char_def), on_equal); |
| 794 } | 744 } |
| 795 | 745 |
| 796 | |
| 797 void IRRegExpMacroAssembler::CheckCharacterGT(uint16_t limit, | 746 void IRRegExpMacroAssembler::CheckCharacterGT(uint16_t limit, |
| 798 BlockLabel* on_greater) { | 747 BlockLabel* on_greater) { |
| 799 TAG(); | 748 TAG(); |
| 800 BranchOrBacktrack( | 749 BranchOrBacktrack( |
| 801 Comparison(kGT, LoadLocal(current_character_), Uint64Constant(limit)), | 750 Comparison(kGT, LoadLocal(current_character_), Uint64Constant(limit)), |
| 802 on_greater); | 751 on_greater); |
| 803 } | 752 } |
| 804 | 753 |
| 805 | |
| 806 void IRRegExpMacroAssembler::CheckAtStart(BlockLabel* on_at_start) { | 754 void IRRegExpMacroAssembler::CheckAtStart(BlockLabel* on_at_start) { |
| 807 TAG(); | 755 TAG(); |
| 808 | 756 |
| 809 BlockLabel not_at_start; | 757 BlockLabel not_at_start; |
| 810 | 758 |
| 811 // Did we start the match at the start of the string at all? | 759 // Did we start the match at the start of the string at all? |
| 812 BranchOrBacktrack( | 760 BranchOrBacktrack( |
| 813 Comparison(kNE, LoadLocal(start_index_param_), Uint64Constant(0)), | 761 Comparison(kNE, LoadLocal(start_index_param_), Uint64Constant(0)), |
| 814 ¬_at_start); | 762 ¬_at_start); |
| 815 | 763 |
| 816 // If we did, are we still at the start of the input, i.e. is | 764 // If we did, are we still at the start of the input, i.e. is |
| 817 // (offset == string_length * -1)? | 765 // (offset == string_length * -1)? |
| 818 Definition* neg_len_def = | 766 Definition* neg_len_def = |
| 819 InstanceCall(InstanceCallDescriptor::FromToken(Token::kNEGATE), | 767 InstanceCall(InstanceCallDescriptor::FromToken(Token::kNEGATE), |
| 820 PushLocal(string_param_length_)); | 768 PushLocal(string_param_length_)); |
| 821 Definition* offset_def = LoadLocal(current_position_); | 769 Definition* offset_def = LoadLocal(current_position_); |
| 822 BranchOrBacktrack(Comparison(kEQ, neg_len_def, offset_def), on_at_start); | 770 BranchOrBacktrack(Comparison(kEQ, neg_len_def, offset_def), on_at_start); |
| 823 | 771 |
| 824 BindBlock(¬_at_start); | 772 BindBlock(¬_at_start); |
| 825 } | 773 } |
| 826 | 774 |
| 827 | |
| 828 void IRRegExpMacroAssembler::CheckNotAtStart(BlockLabel* on_not_at_start) { | 775 void IRRegExpMacroAssembler::CheckNotAtStart(BlockLabel* on_not_at_start) { |
| 829 TAG(); | 776 TAG(); |
| 830 | 777 |
| 831 // Did we start the match at the start of the string at all? | 778 // Did we start the match at the start of the string at all? |
| 832 BranchOrBacktrack( | 779 BranchOrBacktrack( |
| 833 Comparison(kNE, LoadLocal(start_index_param_), Uint64Constant(0)), | 780 Comparison(kNE, LoadLocal(start_index_param_), Uint64Constant(0)), |
| 834 on_not_at_start); | 781 on_not_at_start); |
| 835 | 782 |
| 836 // If we did, are we still at the start of the input, i.e. is | 783 // If we did, are we still at the start of the input, i.e. is |
| 837 // (offset == string_length * -1)? | 784 // (offset == string_length * -1)? |
| 838 Definition* neg_len_def = | 785 Definition* neg_len_def = |
| 839 InstanceCall(InstanceCallDescriptor::FromToken(Token::kNEGATE), | 786 InstanceCall(InstanceCallDescriptor::FromToken(Token::kNEGATE), |
| 840 PushLocal(string_param_length_)); | 787 PushLocal(string_param_length_)); |
| 841 Definition* offset_def = LoadLocal(current_position_); | 788 Definition* offset_def = LoadLocal(current_position_); |
| 842 BranchOrBacktrack(Comparison(kNE, neg_len_def, offset_def), on_not_at_start); | 789 BranchOrBacktrack(Comparison(kNE, neg_len_def, offset_def), on_not_at_start); |
| 843 } | 790 } |
| 844 | 791 |
| 845 | |
| 846 void IRRegExpMacroAssembler::CheckCharacterLT(uint16_t limit, | 792 void IRRegExpMacroAssembler::CheckCharacterLT(uint16_t limit, |
| 847 BlockLabel* on_less) { | 793 BlockLabel* on_less) { |
| 848 TAG(); | 794 TAG(); |
| 849 BranchOrBacktrack( | 795 BranchOrBacktrack( |
| 850 Comparison(kLT, LoadLocal(current_character_), Uint64Constant(limit)), | 796 Comparison(kLT, LoadLocal(current_character_), Uint64Constant(limit)), |
| 851 on_less); | 797 on_less); |
| 852 } | 798 } |
| 853 | 799 |
| 854 | |
| 855 void IRRegExpMacroAssembler::CheckGreedyLoop(BlockLabel* on_equal) { | 800 void IRRegExpMacroAssembler::CheckGreedyLoop(BlockLabel* on_equal) { |
| 856 TAG(); | 801 TAG(); |
| 857 | 802 |
| 858 BlockLabel fallthrough; | 803 BlockLabel fallthrough; |
| 859 | 804 |
| 860 Definition* head = PeekStack(); | 805 Definition* head = PeekStack(); |
| 861 Definition* cur_pos_def = LoadLocal(current_position_); | 806 Definition* cur_pos_def = LoadLocal(current_position_); |
| 862 BranchOrBacktrack(Comparison(kNE, head, cur_pos_def), &fallthrough); | 807 BranchOrBacktrack(Comparison(kNE, head, cur_pos_def), &fallthrough); |
| 863 | 808 |
| 864 // Pop, throwing away the value. | 809 // Pop, throwing away the value. |
| 865 Do(PopStack()); | 810 Do(PopStack()); |
| 866 | 811 |
| 867 BranchOrBacktrack(NULL, on_equal); | 812 BranchOrBacktrack(NULL, on_equal); |
| 868 | 813 |
| 869 BindBlock(&fallthrough); | 814 BindBlock(&fallthrough); |
| 870 } | 815 } |
| 871 | 816 |
| 872 | |
| 873 void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( | 817 void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( |
| 874 intptr_t start_reg, | 818 intptr_t start_reg, |
| 875 BlockLabel* on_no_match) { | 819 BlockLabel* on_no_match) { |
| 876 TAG(); | 820 TAG(); |
| 877 ASSERT(start_reg + 1 <= registers_count_); | 821 ASSERT(start_reg + 1 <= registers_count_); |
| 878 | 822 |
| 879 BlockLabel fallthrough; | 823 BlockLabel fallthrough; |
| 880 | 824 |
| 881 PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1)); | 825 PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1)); |
| 882 PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg)); | 826 PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg)); |
| 883 StoreLocal(capture_length_, Bind(Sub(end_push, start_push))); | 827 StoreLocal(capture_length_, Bind(Sub(end_push, start_push))); |
| 884 | 828 |
| 885 // The length of a capture should not be negative. This can only happen | 829 // The length of a capture should not be negative. This can only happen |
| 886 // if the end of the capture is unrecorded, or at a point earlier than | 830 // if the end of the capture is unrecorded, or at a point earlier than |
| 887 // the start of the capture. | 831 // the start of the capture. |
| 888 // BranchOrBacktrack(less, on_no_match); | 832 // BranchOrBacktrack(less, on_no_match); |
| 889 | 833 |
| 890 BranchOrBacktrack( | 834 BranchOrBacktrack( |
| 891 Comparison(kLT, LoadLocal(capture_length_), Uint64Constant(0)), | 835 Comparison(kLT, LoadLocal(capture_length_), Uint64Constant(0)), |
| 892 on_no_match); | 836 on_no_match); |
| 893 | 837 |
| 894 // If length is zero, either the capture is empty or it is completely | 838 // If length is zero, either the capture is empty or it is completely |
| 895 // uncaptured. In either case succeed immediately. | 839 // uncaptured. In either case succeed immediately. |
| 896 BranchOrBacktrack( | 840 BranchOrBacktrack( |
| 897 Comparison(kEQ, LoadLocal(capture_length_), Uint64Constant(0)), | 841 Comparison(kEQ, LoadLocal(capture_length_), Uint64Constant(0)), |
| 898 &fallthrough); | 842 &fallthrough); |
| 899 | 843 |
| 900 | |
| 901 // Check that there are sufficient characters left in the input. | 844 // Check that there are sufficient characters left in the input. |
| 902 PushArgumentInstr* pos_push = PushLocal(current_position_); | 845 PushArgumentInstr* pos_push = PushLocal(current_position_); |
| 903 PushArgumentInstr* len_push = PushLocal(capture_length_); | 846 PushArgumentInstr* len_push = PushLocal(capture_length_); |
| 904 BranchOrBacktrack( | 847 BranchOrBacktrack( |
| 905 Comparison(kGT, | 848 Comparison(kGT, |
| 906 InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), | 849 InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), |
| 907 pos_push, len_push), | 850 pos_push, len_push), |
| 908 Uint64Constant(0)), | 851 Uint64Constant(0)), |
| 909 on_no_match); | 852 on_no_match); |
| 910 | 853 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1012 BindBlock(&success); | 955 BindBlock(&success); |
| 1013 | 956 |
| 1014 // Move current character position to position after match. | 957 // Move current character position to position after match. |
| 1015 PushArgumentInstr* match_end_push = PushLocal(match_end_index_); | 958 PushArgumentInstr* match_end_push = PushLocal(match_end_index_); |
| 1016 len_push = PushLocal(string_param_length_); | 959 len_push = PushLocal(string_param_length_); |
| 1017 StoreLocal(current_position_, Bind(Sub(match_end_push, len_push))); | 960 StoreLocal(current_position_, Bind(Sub(match_end_push, len_push))); |
| 1018 | 961 |
| 1019 BindBlock(&fallthrough); | 962 BindBlock(&fallthrough); |
| 1020 } | 963 } |
| 1021 | 964 |
| 1022 | |
| 1023 void IRRegExpMacroAssembler::CheckNotBackReference(intptr_t start_reg, | 965 void IRRegExpMacroAssembler::CheckNotBackReference(intptr_t start_reg, |
| 1024 BlockLabel* on_no_match) { | 966 BlockLabel* on_no_match) { |
| 1025 TAG(); | 967 TAG(); |
| 1026 ASSERT(start_reg + 1 <= registers_count_); | 968 ASSERT(start_reg + 1 <= registers_count_); |
| 1027 | 969 |
| 1028 BlockLabel fallthrough; | 970 BlockLabel fallthrough; |
| 1029 BlockLabel success; | 971 BlockLabel success; |
| 1030 | 972 |
| 1031 // Find length of back-referenced capture. | 973 // Find length of back-referenced capture. |
| 1032 PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1)); | 974 PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1)); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1093 BindBlock(&success); | 1035 BindBlock(&success); |
| 1094 | 1036 |
| 1095 // Move current character position to position after match. | 1037 // Move current character position to position after match. |
| 1096 PushArgumentInstr* match_end_push = PushLocal(match_end_index_); | 1038 PushArgumentInstr* match_end_push = PushLocal(match_end_index_); |
| 1097 len_push = PushLocal(string_param_length_); | 1039 len_push = PushLocal(string_param_length_); |
| 1098 StoreLocal(current_position_, Bind(Sub(match_end_push, len_push))); | 1040 StoreLocal(current_position_, Bind(Sub(match_end_push, len_push))); |
| 1099 | 1041 |
| 1100 BindBlock(&fallthrough); | 1042 BindBlock(&fallthrough); |
| 1101 } | 1043 } |
| 1102 | 1044 |
| 1103 | |
| 1104 void IRRegExpMacroAssembler::CheckNotCharacter(uint32_t c, | 1045 void IRRegExpMacroAssembler::CheckNotCharacter(uint32_t c, |
| 1105 BlockLabel* on_not_equal) { | 1046 BlockLabel* on_not_equal) { |
| 1106 TAG(); | 1047 TAG(); |
| 1107 BranchOrBacktrack( | 1048 BranchOrBacktrack( |
| 1108 Comparison(kNE, LoadLocal(current_character_), Uint64Constant(c)), | 1049 Comparison(kNE, LoadLocal(current_character_), Uint64Constant(c)), |
| 1109 on_not_equal); | 1050 on_not_equal); |
| 1110 } | 1051 } |
| 1111 | 1052 |
| 1112 | |
| 1113 void IRRegExpMacroAssembler::CheckCharacterAfterAnd(uint32_t c, | 1053 void IRRegExpMacroAssembler::CheckCharacterAfterAnd(uint32_t c, |
| 1114 uint32_t mask, | 1054 uint32_t mask, |
| 1115 BlockLabel* on_equal) { | 1055 BlockLabel* on_equal) { |
| 1116 TAG(); | 1056 TAG(); |
| 1117 | 1057 |
| 1118 Definition* actual_def = LoadLocal(current_character_); | 1058 Definition* actual_def = LoadLocal(current_character_); |
| 1119 Definition* expected_def = Uint64Constant(c); | 1059 Definition* expected_def = Uint64Constant(c); |
| 1120 | 1060 |
| 1121 PushArgumentInstr* actual_push = PushArgument(Bind(actual_def)); | 1061 PushArgumentInstr* actual_push = PushArgument(Bind(actual_def)); |
| 1122 PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask))); | 1062 PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask))); |
| 1123 actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), | 1063 actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), |
| 1124 actual_push, mask_push); | 1064 actual_push, mask_push); |
| 1125 | 1065 |
| 1126 BranchOrBacktrack(Comparison(kEQ, actual_def, expected_def), on_equal); | 1066 BranchOrBacktrack(Comparison(kEQ, actual_def, expected_def), on_equal); |
| 1127 } | 1067 } |
| 1128 | 1068 |
| 1129 | |
| 1130 void IRRegExpMacroAssembler::CheckNotCharacterAfterAnd( | 1069 void IRRegExpMacroAssembler::CheckNotCharacterAfterAnd( |
| 1131 uint32_t c, | 1070 uint32_t c, |
| 1132 uint32_t mask, | 1071 uint32_t mask, |
| 1133 BlockLabel* on_not_equal) { | 1072 BlockLabel* on_not_equal) { |
| 1134 TAG(); | 1073 TAG(); |
| 1135 | 1074 |
| 1136 Definition* actual_def = LoadLocal(current_character_); | 1075 Definition* actual_def = LoadLocal(current_character_); |
| 1137 Definition* expected_def = Uint64Constant(c); | 1076 Definition* expected_def = Uint64Constant(c); |
| 1138 | 1077 |
| 1139 PushArgumentInstr* actual_push = PushArgument(Bind(actual_def)); | 1078 PushArgumentInstr* actual_push = PushArgument(Bind(actual_def)); |
| 1140 PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask))); | 1079 PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask))); |
| 1141 actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), | 1080 actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), |
| 1142 actual_push, mask_push); | 1081 actual_push, mask_push); |
| 1143 | 1082 |
| 1144 BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal); | 1083 BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal); |
| 1145 } | 1084 } |
| 1146 | 1085 |
| 1147 | |
| 1148 void IRRegExpMacroAssembler::CheckNotCharacterAfterMinusAnd( | 1086 void IRRegExpMacroAssembler::CheckNotCharacterAfterMinusAnd( |
| 1149 uint16_t c, | 1087 uint16_t c, |
| 1150 uint16_t minus, | 1088 uint16_t minus, |
| 1151 uint16_t mask, | 1089 uint16_t mask, |
| 1152 BlockLabel* on_not_equal) { | 1090 BlockLabel* on_not_equal) { |
| 1153 TAG(); | 1091 TAG(); |
| 1154 ASSERT(minus < Utf16::kMaxCodeUnit); // NOLINT | 1092 ASSERT(minus < Utf16::kMaxCodeUnit); // NOLINT |
| 1155 | 1093 |
| 1156 Definition* actual_def = LoadLocal(current_character_); | 1094 Definition* actual_def = LoadLocal(current_character_); |
| 1157 Definition* expected_def = Uint64Constant(c); | 1095 Definition* expected_def = Uint64Constant(c); |
| 1158 | 1096 |
| 1159 PushArgumentInstr* actual_push = PushArgument(Bind(actual_def)); | 1097 PushArgumentInstr* actual_push = PushArgument(Bind(actual_def)); |
| 1160 PushArgumentInstr* minus_push = PushArgument(Bind(Uint64Constant(minus))); | 1098 PushArgumentInstr* minus_push = PushArgument(Bind(Uint64Constant(minus))); |
| 1161 | 1099 |
| 1162 actual_push = PushArgument(Bind(Sub(actual_push, minus_push))); | 1100 actual_push = PushArgument(Bind(Sub(actual_push, minus_push))); |
| 1163 PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask))); | 1101 PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask))); |
| 1164 actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), | 1102 actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), |
| 1165 actual_push, mask_push); | 1103 actual_push, mask_push); |
| 1166 | 1104 |
| 1167 BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal); | 1105 BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal); |
| 1168 } | 1106 } |
| 1169 | 1107 |
| 1170 | |
| 1171 void IRRegExpMacroAssembler::CheckCharacterInRange(uint16_t from, | 1108 void IRRegExpMacroAssembler::CheckCharacterInRange(uint16_t from, |
| 1172 uint16_t to, | 1109 uint16_t to, |
| 1173 BlockLabel* on_in_range) { | 1110 BlockLabel* on_in_range) { |
| 1174 TAG(); | 1111 TAG(); |
| 1175 ASSERT(from <= to); | 1112 ASSERT(from <= to); |
| 1176 | 1113 |
| 1177 // TODO(zerny): All range comparisons could be done cheaper with unsigned | 1114 // TODO(zerny): All range comparisons could be done cheaper with unsigned |
| 1178 // compares. This pattern repeats in various places. | 1115 // compares. This pattern repeats in various places. |
| 1179 | 1116 |
| 1180 BlockLabel on_not_in_range; | 1117 BlockLabel on_not_in_range; |
| 1181 BranchOrBacktrack( | 1118 BranchOrBacktrack( |
| 1182 Comparison(kLT, LoadLocal(current_character_), Uint64Constant(from)), | 1119 Comparison(kLT, LoadLocal(current_character_), Uint64Constant(from)), |
| 1183 &on_not_in_range); | 1120 &on_not_in_range); |
| 1184 BranchOrBacktrack( | 1121 BranchOrBacktrack( |
| 1185 Comparison(kGT, LoadLocal(current_character_), Uint64Constant(to)), | 1122 Comparison(kGT, LoadLocal(current_character_), Uint64Constant(to)), |
| 1186 &on_not_in_range); | 1123 &on_not_in_range); |
| 1187 BranchOrBacktrack(NULL, on_in_range); | 1124 BranchOrBacktrack(NULL, on_in_range); |
| 1188 | 1125 |
| 1189 BindBlock(&on_not_in_range); | 1126 BindBlock(&on_not_in_range); |
| 1190 } | 1127 } |
| 1191 | 1128 |
| 1192 | |
| 1193 void IRRegExpMacroAssembler::CheckCharacterNotInRange( | 1129 void IRRegExpMacroAssembler::CheckCharacterNotInRange( |
| 1194 uint16_t from, | 1130 uint16_t from, |
| 1195 uint16_t to, | 1131 uint16_t to, |
| 1196 BlockLabel* on_not_in_range) { | 1132 BlockLabel* on_not_in_range) { |
| 1197 TAG(); | 1133 TAG(); |
| 1198 ASSERT(from <= to); | 1134 ASSERT(from <= to); |
| 1199 | 1135 |
| 1200 BranchOrBacktrack( | 1136 BranchOrBacktrack( |
| 1201 Comparison(kLT, LoadLocal(current_character_), Uint64Constant(from)), | 1137 Comparison(kLT, LoadLocal(current_character_), Uint64Constant(from)), |
| 1202 on_not_in_range); | 1138 on_not_in_range); |
| 1203 | 1139 |
| 1204 BranchOrBacktrack( | 1140 BranchOrBacktrack( |
| 1205 Comparison(kGT, LoadLocal(current_character_), Uint64Constant(to)), | 1141 Comparison(kGT, LoadLocal(current_character_), Uint64Constant(to)), |
| 1206 on_not_in_range); | 1142 on_not_in_range); |
| 1207 } | 1143 } |
| 1208 | 1144 |
| 1209 | |
| 1210 void IRRegExpMacroAssembler::CheckBitInTable(const TypedData& table, | 1145 void IRRegExpMacroAssembler::CheckBitInTable(const TypedData& table, |
| 1211 BlockLabel* on_bit_set) { | 1146 BlockLabel* on_bit_set) { |
| 1212 TAG(); | 1147 TAG(); |
| 1213 | 1148 |
| 1214 PushArgumentInstr* table_push = | 1149 PushArgumentInstr* table_push = |
| 1215 PushArgument(Bind(new (Z) ConstantInstr(table))); | 1150 PushArgument(Bind(new (Z) ConstantInstr(table))); |
| 1216 PushArgumentInstr* index_push = PushLocal(current_character_); | 1151 PushArgumentInstr* index_push = PushLocal(current_character_); |
| 1217 | 1152 |
| 1218 if (mode_ != ASCII || kTableMask != Symbols::kMaxOneCharCodeSymbol) { | 1153 if (mode_ != ASCII || kTableMask != Symbols::kMaxOneCharCodeSymbol) { |
| 1219 PushArgumentInstr* mask_push = | 1154 PushArgumentInstr* mask_push = |
| 1220 PushArgument(Bind(Uint64Constant(kTableSize - 1))); | 1155 PushArgument(Bind(Uint64Constant(kTableSize - 1))); |
| 1221 index_push = PushArgument( | 1156 index_push = PushArgument( |
| 1222 Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), | 1157 Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), |
| 1223 index_push, mask_push))); | 1158 index_push, mask_push))); |
| 1224 } | 1159 } |
| 1225 | 1160 |
| 1226 Definition* byte_def = InstanceCall( | 1161 Definition* byte_def = InstanceCall( |
| 1227 InstanceCallDescriptor::FromToken(Token::kINDEX), table_push, index_push); | 1162 InstanceCallDescriptor::FromToken(Token::kINDEX), table_push, index_push); |
| 1228 Definition* zero_def = Int64Constant(0); | 1163 Definition* zero_def = Int64Constant(0); |
| 1229 | 1164 |
| 1230 BranchOrBacktrack(Comparison(kNE, byte_def, zero_def), on_bit_set); | 1165 BranchOrBacktrack(Comparison(kNE, byte_def, zero_def), on_bit_set); |
| 1231 } | 1166 } |
| 1232 | 1167 |
| 1233 | |
| 1234 bool IRRegExpMacroAssembler::CheckSpecialCharacterClass( | 1168 bool IRRegExpMacroAssembler::CheckSpecialCharacterClass( |
| 1235 uint16_t type, | 1169 uint16_t type, |
| 1236 BlockLabel* on_no_match) { | 1170 BlockLabel* on_no_match) { |
| 1237 TAG(); | 1171 TAG(); |
| 1238 | 1172 |
| 1239 // Range checks (c in min..max) are generally implemented by an unsigned | 1173 // Range checks (c in min..max) are generally implemented by an unsigned |
| 1240 // (c - min) <= (max - min) check | 1174 // (c - min) <= (max - min) check |
| 1241 switch (type) { | 1175 switch (type) { |
| 1242 case 's': | 1176 case 's': |
| 1243 // Match space-characters | 1177 // Match space-characters |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1360 BranchOrBacktrack(NULL, on_no_match); | 1294 BranchOrBacktrack(NULL, on_no_match); |
| 1361 BindBlock(&success); | 1295 BindBlock(&success); |
| 1362 return true; | 1296 return true; |
| 1363 } | 1297 } |
| 1364 // No custom implementation (yet): s(uint16_t), S(uint16_t). | 1298 // No custom implementation (yet): s(uint16_t), S(uint16_t). |
| 1365 default: | 1299 default: |
| 1366 return false; | 1300 return false; |
| 1367 } | 1301 } |
| 1368 } | 1302 } |
| 1369 | 1303 |
| 1370 | |
| 1371 void IRRegExpMacroAssembler::Fail() { | 1304 void IRRegExpMacroAssembler::Fail() { |
| 1372 TAG(); | 1305 TAG(); |
| 1373 ASSERT(FAILURE == 0); // Return value for failure is zero. | 1306 ASSERT(FAILURE == 0); // Return value for failure is zero. |
| 1374 if (!global()) { | 1307 if (!global()) { |
| 1375 UNREACHABLE(); // Dart regexps are always global. | 1308 UNREACHABLE(); // Dart regexps are always global. |
| 1376 } | 1309 } |
| 1377 GoTo(exit_block_); | 1310 GoTo(exit_block_); |
| 1378 } | 1311 } |
| 1379 | 1312 |
| 1380 | |
| 1381 void IRRegExpMacroAssembler::IfRegisterGE(intptr_t reg, | 1313 void IRRegExpMacroAssembler::IfRegisterGE(intptr_t reg, |
| 1382 intptr_t comparand, | 1314 intptr_t comparand, |
| 1383 BlockLabel* if_ge) { | 1315 BlockLabel* if_ge) { |
| 1384 TAG(); | 1316 TAG(); |
| 1385 PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); | 1317 PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); |
| 1386 PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand))); | 1318 PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand))); |
| 1387 BranchOrBacktrack(Comparison(kGTE, reg_push, pos), if_ge); | 1319 BranchOrBacktrack(Comparison(kGTE, reg_push, pos), if_ge); |
| 1388 } | 1320 } |
| 1389 | 1321 |
| 1390 | |
| 1391 void IRRegExpMacroAssembler::IfRegisterLT(intptr_t reg, | 1322 void IRRegExpMacroAssembler::IfRegisterLT(intptr_t reg, |
| 1392 intptr_t comparand, | 1323 intptr_t comparand, |
| 1393 BlockLabel* if_lt) { | 1324 BlockLabel* if_lt) { |
| 1394 TAG(); | 1325 TAG(); |
| 1395 PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); | 1326 PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); |
| 1396 PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand))); | 1327 PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand))); |
| 1397 BranchOrBacktrack(Comparison(kLT, reg_push, pos), if_lt); | 1328 BranchOrBacktrack(Comparison(kLT, reg_push, pos), if_lt); |
| 1398 } | 1329 } |
| 1399 | 1330 |
| 1400 | |
| 1401 void IRRegExpMacroAssembler::IfRegisterEqPos(intptr_t reg, BlockLabel* if_eq) { | 1331 void IRRegExpMacroAssembler::IfRegisterEqPos(intptr_t reg, BlockLabel* if_eq) { |
| 1402 TAG(); | 1332 TAG(); |
| 1403 PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); | 1333 PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); |
| 1404 PushArgumentInstr* pos = PushArgument(Bind(LoadLocal(current_position_))); | 1334 PushArgumentInstr* pos = PushArgument(Bind(LoadLocal(current_position_))); |
| 1405 BranchOrBacktrack(Comparison(kEQ, reg_push, pos), if_eq); | 1335 BranchOrBacktrack(Comparison(kEQ, reg_push, pos), if_eq); |
| 1406 } | 1336 } |
| 1407 | 1337 |
| 1408 | |
| 1409 RegExpMacroAssembler::IrregexpImplementation | 1338 RegExpMacroAssembler::IrregexpImplementation |
| 1410 IRRegExpMacroAssembler::Implementation() { | 1339 IRRegExpMacroAssembler::Implementation() { |
| 1411 return kIRImplementation; | 1340 return kIRImplementation; |
| 1412 } | 1341 } |
| 1413 | 1342 |
| 1414 | |
| 1415 void IRRegExpMacroAssembler::LoadCurrentCharacter(intptr_t cp_offset, | 1343 void IRRegExpMacroAssembler::LoadCurrentCharacter(intptr_t cp_offset, |
| 1416 BlockLabel* on_end_of_input, | 1344 BlockLabel* on_end_of_input, |
| 1417 bool check_bounds, | 1345 bool check_bounds, |
| 1418 intptr_t characters) { | 1346 intptr_t characters) { |
| 1419 TAG(); | 1347 TAG(); |
| 1420 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. | 1348 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. |
| 1421 ASSERT(cp_offset < (1 << 30)); // Be sane! (And ensure negation works) | 1349 ASSERT(cp_offset < (1 << 30)); // Be sane! (And ensure negation works) |
| 1422 if (check_bounds) { | 1350 if (check_bounds) { |
| 1423 CheckPosition(cp_offset + characters - 1, on_end_of_input); | 1351 CheckPosition(cp_offset + characters - 1, on_end_of_input); |
| 1424 } | 1352 } |
| 1425 LoadCurrentCharacterUnchecked(cp_offset, characters); | 1353 LoadCurrentCharacterUnchecked(cp_offset, characters); |
| 1426 } | 1354 } |
| 1427 | 1355 |
| 1428 | |
| 1429 void IRRegExpMacroAssembler::PopCurrentPosition() { | 1356 void IRRegExpMacroAssembler::PopCurrentPosition() { |
| 1430 TAG(); | 1357 TAG(); |
| 1431 StoreLocal(current_position_, Bind(PopStack())); | 1358 StoreLocal(current_position_, Bind(PopStack())); |
| 1432 } | 1359 } |
| 1433 | 1360 |
| 1434 | |
| 1435 void IRRegExpMacroAssembler::PopRegister(intptr_t reg) { | 1361 void IRRegExpMacroAssembler::PopRegister(intptr_t reg) { |
| 1436 TAG(); | 1362 TAG(); |
| 1437 ASSERT(reg < registers_count_); | 1363 ASSERT(reg < registers_count_); |
| 1438 PushArgumentInstr* registers_push = PushLocal(registers_); | 1364 PushArgumentInstr* registers_push = PushLocal(registers_); |
| 1439 PushArgumentInstr* index_push = PushRegisterIndex(reg); | 1365 PushArgumentInstr* index_push = PushRegisterIndex(reg); |
| 1440 PushArgumentInstr* pop_push = PushArgument(Bind(PopStack())); | 1366 PushArgumentInstr* pop_push = PushArgument(Bind(PopStack())); |
| 1441 StoreRegister(registers_push, index_push, pop_push); | 1367 StoreRegister(registers_push, index_push, pop_push); |
| 1442 } | 1368 } |
| 1443 | 1369 |
| 1444 | |
| 1445 void IRRegExpMacroAssembler::PushStack(Definition* definition) { | 1370 void IRRegExpMacroAssembler::PushStack(Definition* definition) { |
| 1446 PushArgumentInstr* stack_push = PushLocal(stack_); | 1371 PushArgumentInstr* stack_push = PushLocal(stack_); |
| 1447 PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); | 1372 PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); |
| 1448 StoreLocal(stack_pointer_, Bind(Add(stack_pointer_push, | 1373 StoreLocal(stack_pointer_, Bind(Add(stack_pointer_push, |
| 1449 PushArgument(Bind(Uint64Constant(1)))))); | 1374 PushArgument(Bind(Uint64Constant(1)))))); |
| 1450 stack_pointer_push = PushLocal(stack_pointer_); | 1375 stack_pointer_push = PushLocal(stack_pointer_); |
| 1451 // TODO(zerny): bind value and push could break stack discipline. | 1376 // TODO(zerny): bind value and push could break stack discipline. |
| 1452 PushArgumentInstr* value_push = PushArgument(Bind(definition)); | 1377 PushArgumentInstr* value_push = PushArgument(Bind(definition)); |
| 1453 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), | 1378 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), |
| 1454 stack_push, stack_pointer_push, value_push)); | 1379 stack_push, stack_pointer_push, value_push)); |
| 1455 } | 1380 } |
| 1456 | 1381 |
| 1457 | |
| 1458 Definition* IRRegExpMacroAssembler::PopStack() { | 1382 Definition* IRRegExpMacroAssembler::PopStack() { |
| 1459 PushArgumentInstr* stack_push = PushLocal(stack_); | 1383 PushArgumentInstr* stack_push = PushLocal(stack_); |
| 1460 PushArgumentInstr* stack_pointer_push1 = PushLocal(stack_pointer_); | 1384 PushArgumentInstr* stack_pointer_push1 = PushLocal(stack_pointer_); |
| 1461 PushArgumentInstr* stack_pointer_push2 = PushLocal(stack_pointer_); | 1385 PushArgumentInstr* stack_pointer_push2 = PushLocal(stack_pointer_); |
| 1462 StoreLocal(stack_pointer_, Bind(Sub(stack_pointer_push2, | 1386 StoreLocal(stack_pointer_, Bind(Sub(stack_pointer_push2, |
| 1463 PushArgument(Bind(Uint64Constant(1)))))); | 1387 PushArgument(Bind(Uint64Constant(1)))))); |
| 1464 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), | 1388 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), |
| 1465 stack_push, stack_pointer_push1); | 1389 stack_push, stack_pointer_push1); |
| 1466 } | 1390 } |
| 1467 | 1391 |
| 1468 | |
| 1469 Definition* IRRegExpMacroAssembler::PeekStack() { | 1392 Definition* IRRegExpMacroAssembler::PeekStack() { |
| 1470 PushArgumentInstr* stack_push = PushLocal(stack_); | 1393 PushArgumentInstr* stack_push = PushLocal(stack_); |
| 1471 PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); | 1394 PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); |
| 1472 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), | 1395 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), |
| 1473 stack_push, stack_pointer_push); | 1396 stack_push, stack_pointer_push); |
| 1474 } | 1397 } |
| 1475 | 1398 |
| 1476 | |
| 1477 // Pushes the location corresponding to label to the backtracking stack. | 1399 // Pushes the location corresponding to label to the backtracking stack. |
| 1478 void IRRegExpMacroAssembler::PushBacktrack(BlockLabel* label) { | 1400 void IRRegExpMacroAssembler::PushBacktrack(BlockLabel* label) { |
| 1479 TAG(); | 1401 TAG(); |
| 1480 | 1402 |
| 1481 // Ensure that targets of indirect jumps are never accessed through a | 1403 // Ensure that targets of indirect jumps are never accessed through a |
| 1482 // normal control flow instructions by creating a new block for each backtrack | 1404 // normal control flow instructions by creating a new block for each backtrack |
| 1483 // target. | 1405 // target. |
| 1484 IndirectEntryInstr* indirect_target = IndirectWithJoinGoto(label->block()); | 1406 IndirectEntryInstr* indirect_target = IndirectWithJoinGoto(label->block()); |
| 1485 | 1407 |
| 1486 // Add a fake edge from the graph entry for data flow analysis. | 1408 // Add a fake edge from the graph entry for data flow analysis. |
| 1487 entry_block_->AddIndirectEntry(indirect_target); | 1409 entry_block_->AddIndirectEntry(indirect_target); |
| 1488 | 1410 |
| 1489 ConstantInstr* offset = Uint64Constant(indirect_target->indirect_id()); | 1411 ConstantInstr* offset = Uint64Constant(indirect_target->indirect_id()); |
| 1490 PushStack(offset); | 1412 PushStack(offset); |
| 1491 CheckStackLimit(); | 1413 CheckStackLimit(); |
| 1492 } | 1414 } |
| 1493 | 1415 |
| 1494 | |
| 1495 void IRRegExpMacroAssembler::PushCurrentPosition() { | 1416 void IRRegExpMacroAssembler::PushCurrentPosition() { |
| 1496 TAG(); | 1417 TAG(); |
| 1497 PushStack(LoadLocal(current_position_)); | 1418 PushStack(LoadLocal(current_position_)); |
| 1498 } | 1419 } |
| 1499 | 1420 |
| 1500 | |
| 1501 void IRRegExpMacroAssembler::PushRegister(intptr_t reg) { | 1421 void IRRegExpMacroAssembler::PushRegister(intptr_t reg) { |
| 1502 TAG(); | 1422 TAG(); |
| 1503 // TODO(zerny): Refactor PushStack so it can be reused here. | 1423 // TODO(zerny): Refactor PushStack so it can be reused here. |
| 1504 PushArgumentInstr* stack_push = PushLocal(stack_); | 1424 PushArgumentInstr* stack_push = PushLocal(stack_); |
| 1505 PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); | 1425 PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); |
| 1506 StoreLocal(stack_pointer_, Bind(Add(stack_pointer_push, | 1426 StoreLocal(stack_pointer_, Bind(Add(stack_pointer_push, |
| 1507 PushArgument(Bind(Uint64Constant(1)))))); | 1427 PushArgument(Bind(Uint64Constant(1)))))); |
| 1508 stack_pointer_push = PushLocal(stack_pointer_); | 1428 stack_pointer_push = PushLocal(stack_pointer_); |
| 1509 // TODO(zerny): bind value and push could break stack discipline. | 1429 // TODO(zerny): bind value and push could break stack discipline. |
| 1510 PushArgumentInstr* value_push = PushArgument(LoadRegister(reg)); | 1430 PushArgumentInstr* value_push = PushArgument(LoadRegister(reg)); |
| 1511 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), | 1431 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), |
| 1512 stack_push, stack_pointer_push, value_push)); | 1432 stack_push, stack_pointer_push, value_push)); |
| 1513 CheckStackLimit(); | 1433 CheckStackLimit(); |
| 1514 } | 1434 } |
| 1515 | 1435 |
| 1516 | |
| 1517 // Checks that (stack.capacity - stack_limit_slack) > stack_pointer. | 1436 // Checks that (stack.capacity - stack_limit_slack) > stack_pointer. |
| 1518 // This ensures that up to stack_limit_slack stack pushes can be | 1437 // This ensures that up to stack_limit_slack stack pushes can be |
| 1519 // done without exhausting the stack space. If the check fails the | 1438 // done without exhausting the stack space. If the check fails the |
| 1520 // stack will be grown. | 1439 // stack will be grown. |
| 1521 void IRRegExpMacroAssembler::CheckStackLimit() { | 1440 void IRRegExpMacroAssembler::CheckStackLimit() { |
| 1522 TAG(); | 1441 TAG(); |
| 1523 PushArgumentInstr* stack_push = PushLocal(stack_); | 1442 PushArgumentInstr* stack_push = PushLocal(stack_); |
| 1524 PushArgumentInstr* length_push = PushArgument( | 1443 PushArgumentInstr* length_push = PushArgument( |
| 1525 Bind(InstanceCall(InstanceCallDescriptor(String::ZoneHandle( | 1444 Bind(InstanceCall(InstanceCallDescriptor(String::ZoneHandle( |
| 1526 Field::GetterSymbol(Symbols::Length()))), | 1445 Field::GetterSymbol(Symbols::Length()))), |
| 1527 stack_push))); | 1446 stack_push))); |
| 1528 PushArgumentInstr* capacity_push = PushArgument(Bind(Sub( | 1447 PushArgumentInstr* capacity_push = PushArgument(Bind(Sub( |
| 1529 length_push, PushArgument(Bind(Uint64Constant(stack_limit_slack())))))); | 1448 length_push, PushArgument(Bind(Uint64Constant(stack_limit_slack())))))); |
| 1530 PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); | 1449 PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); |
| 1531 BranchInstr* branch = new (Z) BranchInstr( | 1450 BranchInstr* branch = new (Z) BranchInstr( |
| 1532 Comparison(kGT, capacity_push, stack_pointer_push), GetNextDeoptId()); | 1451 Comparison(kGT, capacity_push, stack_pointer_push), GetNextDeoptId()); |
| 1533 CloseBlockWith(branch); | 1452 CloseBlockWith(branch); |
| 1534 | 1453 |
| 1535 BlockLabel grow_stack; | 1454 BlockLabel grow_stack; |
| 1536 BlockLabel fallthrough; | 1455 BlockLabel fallthrough; |
| 1537 *branch->true_successor_address() = TargetWithJoinGoto(fallthrough.block()); | 1456 *branch->true_successor_address() = TargetWithJoinGoto(fallthrough.block()); |
| 1538 *branch->false_successor_address() = TargetWithJoinGoto(grow_stack.block()); | 1457 *branch->false_successor_address() = TargetWithJoinGoto(grow_stack.block()); |
| 1539 | 1458 |
| 1540 BindBlock(&grow_stack); | 1459 BindBlock(&grow_stack); |
| 1541 GrowStack(); | 1460 GrowStack(); |
| 1542 | 1461 |
| 1543 BindBlock(&fallthrough); | 1462 BindBlock(&fallthrough); |
| 1544 } | 1463 } |
| 1545 | 1464 |
| 1546 | |
| 1547 void IRRegExpMacroAssembler::GrowStack() { | 1465 void IRRegExpMacroAssembler::GrowStack() { |
| 1548 TAG(); | 1466 TAG(); |
| 1549 const Library& lib = Library::Handle(Library::InternalLibrary()); | 1467 const Library& lib = Library::Handle(Library::InternalLibrary()); |
| 1550 const Function& grow_function = Function::ZoneHandle( | 1468 const Function& grow_function = Function::ZoneHandle( |
| 1551 Z, lib.LookupFunctionAllowPrivate(Symbols::GrowRegExpStack())); | 1469 Z, lib.LookupFunctionAllowPrivate(Symbols::GrowRegExpStack())); |
| 1552 StoreLocal(stack_, Bind(StaticCall(grow_function, PushLocal(stack_)))); | 1470 StoreLocal(stack_, Bind(StaticCall(grow_function, PushLocal(stack_)))); |
| 1553 | 1471 |
| 1554 // Note: :stack and stack_array_cell content might diverge because each | 1472 // Note: :stack and stack_array_cell content might diverge because each |
| 1555 // instance of :matcher code has its own stack_array_cell embedded into it | 1473 // instance of :matcher code has its own stack_array_cell embedded into it |
| 1556 // as a constant but :stack is a local variable and its value might be | 1474 // as a constant but :stack is a local variable and its value might be |
| 1557 // comming from OSR or deoptimization. This means we should never use | 1475 // comming from OSR or deoptimization. This means we should never use |
| 1558 // stack_array_cell in the body of the :matcher to reload the :stack. | 1476 // stack_array_cell in the body of the :matcher to reload the :stack. |
| 1559 PushArgumentInstr* stack_cell_push = | 1477 PushArgumentInstr* stack_cell_push = |
| 1560 PushArgument(Bind(new (Z) ConstantInstr(stack_array_cell_))); | 1478 PushArgument(Bind(new (Z) ConstantInstr(stack_array_cell_))); |
| 1561 PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(0))); | 1479 PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(0))); |
| 1562 PushArgumentInstr* stack_push = PushLocal(stack_); | 1480 PushArgumentInstr* stack_push = PushLocal(stack_); |
| 1563 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), | 1481 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), |
| 1564 stack_cell_push, index_push, stack_push)); | 1482 stack_cell_push, index_push, stack_push)); |
| 1565 } | 1483 } |
| 1566 | 1484 |
| 1567 | |
| 1568 void IRRegExpMacroAssembler::ReadCurrentPositionFromRegister(intptr_t reg) { | 1485 void IRRegExpMacroAssembler::ReadCurrentPositionFromRegister(intptr_t reg) { |
| 1569 TAG(); | 1486 TAG(); |
| 1570 StoreLocal(current_position_, LoadRegister(reg)); | 1487 StoreLocal(current_position_, LoadRegister(reg)); |
| 1571 } | 1488 } |
| 1572 | 1489 |
| 1573 // Resets the tip of the stack to the value stored in reg. | 1490 // Resets the tip of the stack to the value stored in reg. |
| 1574 void IRRegExpMacroAssembler::ReadStackPointerFromRegister(intptr_t reg) { | 1491 void IRRegExpMacroAssembler::ReadStackPointerFromRegister(intptr_t reg) { |
| 1575 TAG(); | 1492 TAG(); |
| 1576 ASSERT(reg < registers_count_); | 1493 ASSERT(reg < registers_count_); |
| 1577 StoreLocal(stack_pointer_, LoadRegister(reg)); | 1494 StoreLocal(stack_pointer_, LoadRegister(reg)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1591 StoreLocal(current_position_, Bind(Int64Constant(-by))); | 1508 StoreLocal(current_position_, Bind(Int64Constant(-by))); |
| 1592 | 1509 |
| 1593 // On RegExp code entry (where this operation is used), the character before | 1510 // On RegExp code entry (where this operation is used), the character before |
| 1594 // the current position is expected to be already loaded. | 1511 // the current position is expected to be already loaded. |
| 1595 // We have advanced the position, so it's safe to read backwards. | 1512 // We have advanced the position, so it's safe to read backwards. |
| 1596 LoadCurrentCharacterUnchecked(-1, 1); | 1513 LoadCurrentCharacterUnchecked(-1, 1); |
| 1597 | 1514 |
| 1598 BindBlock(&after_position); | 1515 BindBlock(&after_position); |
| 1599 } | 1516 } |
| 1600 | 1517 |
| 1601 | |
| 1602 void IRRegExpMacroAssembler::SetRegister(intptr_t reg, intptr_t to) { | 1518 void IRRegExpMacroAssembler::SetRegister(intptr_t reg, intptr_t to) { |
| 1603 TAG(); | 1519 TAG(); |
| 1604 // Reserved for positions! | 1520 // Reserved for positions! |
| 1605 ASSERT(reg >= saved_registers_count_); | 1521 ASSERT(reg >= saved_registers_count_); |
| 1606 StoreRegister(reg, to); | 1522 StoreRegister(reg, to); |
| 1607 } | 1523 } |
| 1608 | 1524 |
| 1609 | |
| 1610 bool IRRegExpMacroAssembler::Succeed() { | 1525 bool IRRegExpMacroAssembler::Succeed() { |
| 1611 TAG(); | 1526 TAG(); |
| 1612 GoTo(success_block_); | 1527 GoTo(success_block_); |
| 1613 return global(); | 1528 return global(); |
| 1614 } | 1529 } |
| 1615 | 1530 |
| 1616 | |
| 1617 void IRRegExpMacroAssembler::WriteCurrentPositionToRegister( | 1531 void IRRegExpMacroAssembler::WriteCurrentPositionToRegister( |
| 1618 intptr_t reg, | 1532 intptr_t reg, |
| 1619 intptr_t cp_offset) { | 1533 intptr_t cp_offset) { |
| 1620 TAG(); | 1534 TAG(); |
| 1621 | 1535 |
| 1622 PushArgumentInstr* registers_push = PushLocal(registers_); | 1536 PushArgumentInstr* registers_push = PushLocal(registers_); |
| 1623 PushArgumentInstr* index_push = PushRegisterIndex(reg); | 1537 PushArgumentInstr* index_push = PushRegisterIndex(reg); |
| 1624 PushArgumentInstr* pos_push = PushLocal(current_position_); | 1538 PushArgumentInstr* pos_push = PushLocal(current_position_); |
| 1625 PushArgumentInstr* off_push = PushArgument(Bind(Int64Constant(cp_offset))); | 1539 PushArgumentInstr* off_push = PushArgument(Bind(Int64Constant(cp_offset))); |
| 1626 PushArgumentInstr* neg_off_push = PushArgument(Bind(Add(pos_push, off_push))); | 1540 PushArgumentInstr* neg_off_push = PushArgument(Bind(Add(pos_push, off_push))); |
| 1627 // Push the negative offset; these are converted to positive string positions | 1541 // Push the negative offset; these are converted to positive string positions |
| 1628 // within the success block. | 1542 // within the success block. |
| 1629 StoreRegister(registers_push, index_push, neg_off_push); | 1543 StoreRegister(registers_push, index_push, neg_off_push); |
| 1630 } | 1544 } |
| 1631 | 1545 |
| 1632 | |
| 1633 void IRRegExpMacroAssembler::ClearRegisters(intptr_t reg_from, | 1546 void IRRegExpMacroAssembler::ClearRegisters(intptr_t reg_from, |
| 1634 intptr_t reg_to) { | 1547 intptr_t reg_to) { |
| 1635 TAG(); | 1548 TAG(); |
| 1636 | 1549 |
| 1637 ASSERT(reg_from <= reg_to); | 1550 ASSERT(reg_from <= reg_to); |
| 1638 | 1551 |
| 1639 // In order to clear registers to a final result value of -1, set them to | 1552 // In order to clear registers to a final result value of -1, set them to |
| 1640 // (-1 - string length), the offset of -1 from the end of the string. | 1553 // (-1 - string length), the offset of -1 from the end of the string. |
| 1641 | 1554 |
| 1642 for (intptr_t reg = reg_from; reg <= reg_to; reg++) { | 1555 for (intptr_t reg = reg_from; reg <= reg_to; reg++) { |
| 1643 PushArgumentInstr* registers_push = PushLocal(registers_); | 1556 PushArgumentInstr* registers_push = PushLocal(registers_); |
| 1644 PushArgumentInstr* index_push = PushRegisterIndex(reg); | 1557 PushArgumentInstr* index_push = PushRegisterIndex(reg); |
| 1645 PushArgumentInstr* minus_one_push = PushArgument(Bind(Int64Constant(-1))); | 1558 PushArgumentInstr* minus_one_push = PushArgument(Bind(Int64Constant(-1))); |
| 1646 PushArgumentInstr* length_push = PushLocal(string_param_length_); | 1559 PushArgumentInstr* length_push = PushLocal(string_param_length_); |
| 1647 PushArgumentInstr* value_push = | 1560 PushArgumentInstr* value_push = |
| 1648 PushArgument(Bind(Sub(minus_one_push, length_push))); | 1561 PushArgument(Bind(Sub(minus_one_push, length_push))); |
| 1649 StoreRegister(registers_push, index_push, value_push); | 1562 StoreRegister(registers_push, index_push, value_push); |
| 1650 } | 1563 } |
| 1651 } | 1564 } |
| 1652 | 1565 |
| 1653 | |
| 1654 void IRRegExpMacroAssembler::WriteStackPointerToRegister(intptr_t reg) { | 1566 void IRRegExpMacroAssembler::WriteStackPointerToRegister(intptr_t reg) { |
| 1655 TAG(); | 1567 TAG(); |
| 1656 | 1568 |
| 1657 PushArgumentInstr* registers_push = PushLocal(registers_); | 1569 PushArgumentInstr* registers_push = PushLocal(registers_); |
| 1658 PushArgumentInstr* index_push = PushRegisterIndex(reg); | 1570 PushArgumentInstr* index_push = PushRegisterIndex(reg); |
| 1659 PushArgumentInstr* tip_push = PushLocal(stack_pointer_); | 1571 PushArgumentInstr* tip_push = PushLocal(stack_pointer_); |
| 1660 StoreRegister(registers_push, index_push, tip_push); | 1572 StoreRegister(registers_push, index_push, tip_push); |
| 1661 } | 1573 } |
| 1662 | 1574 |
| 1663 | |
| 1664 // Private methods: | 1575 // Private methods: |
| 1665 | 1576 |
| 1666 | |
| 1667 void IRRegExpMacroAssembler::CheckPosition(intptr_t cp_offset, | 1577 void IRRegExpMacroAssembler::CheckPosition(intptr_t cp_offset, |
| 1668 BlockLabel* on_outside_input) { | 1578 BlockLabel* on_outside_input) { |
| 1669 TAG(); | 1579 TAG(); |
| 1670 Definition* curpos_def = LoadLocal(current_position_); | 1580 Definition* curpos_def = LoadLocal(current_position_); |
| 1671 Definition* cp_off_def = Int64Constant(-cp_offset); | 1581 Definition* cp_off_def = Int64Constant(-cp_offset); |
| 1672 | 1582 |
| 1673 // If (current_position_ < -cp_offset), we are in bounds. | 1583 // If (current_position_ < -cp_offset), we are in bounds. |
| 1674 // Remember, current_position_ is a negative offset from the string end. | 1584 // Remember, current_position_ is a negative offset from the string end. |
| 1675 | 1585 |
| 1676 BranchOrBacktrack(Comparison(kGTE, curpos_def, cp_off_def), on_outside_input); | 1586 BranchOrBacktrack(Comparison(kGTE, curpos_def, cp_off_def), on_outside_input); |
| 1677 } | 1587 } |
| 1678 | 1588 |
| 1679 | |
| 1680 void IRRegExpMacroAssembler::BranchOrBacktrack(ComparisonInstr* comparison, | 1589 void IRRegExpMacroAssembler::BranchOrBacktrack(ComparisonInstr* comparison, |
| 1681 BlockLabel* true_successor) { | 1590 BlockLabel* true_successor) { |
| 1682 if (comparison == NULL) { // No condition | 1591 if (comparison == NULL) { // No condition |
| 1683 if (true_successor == NULL) { | 1592 if (true_successor == NULL) { |
| 1684 Backtrack(); | 1593 Backtrack(); |
| 1685 return; | 1594 return; |
| 1686 } | 1595 } |
| 1687 GoTo(true_successor); | 1596 GoTo(true_successor); |
| 1688 return; | 1597 return; |
| 1689 } | 1598 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1700 BlockLabel fallthrough; | 1609 BlockLabel fallthrough; |
| 1701 | 1610 |
| 1702 BranchInstr* branch = new (Z) BranchInstr(comparison, GetNextDeoptId()); | 1611 BranchInstr* branch = new (Z) BranchInstr(comparison, GetNextDeoptId()); |
| 1703 *branch->true_successor_address() = TargetWithJoinGoto(true_successor_block); | 1612 *branch->true_successor_address() = TargetWithJoinGoto(true_successor_block); |
| 1704 *branch->false_successor_address() = TargetWithJoinGoto(fallthrough.block()); | 1613 *branch->false_successor_address() = TargetWithJoinGoto(fallthrough.block()); |
| 1705 | 1614 |
| 1706 CloseBlockWith(branch); | 1615 CloseBlockWith(branch); |
| 1707 BindBlock(&fallthrough); | 1616 BindBlock(&fallthrough); |
| 1708 } | 1617 } |
| 1709 | 1618 |
| 1710 | |
| 1711 TargetEntryInstr* IRRegExpMacroAssembler::TargetWithJoinGoto( | 1619 TargetEntryInstr* IRRegExpMacroAssembler::TargetWithJoinGoto( |
| 1712 JoinEntryInstr* dst) { | 1620 JoinEntryInstr* dst) { |
| 1713 TargetEntryInstr* target = new (Z) | 1621 TargetEntryInstr* target = new (Z) |
| 1714 TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); | 1622 TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); |
| 1715 blocks_.Add(target); | 1623 blocks_.Add(target); |
| 1716 | 1624 |
| 1717 target->AppendInstruction(new (Z) GotoInstr(dst, GetNextDeoptId())); | 1625 target->AppendInstruction(new (Z) GotoInstr(dst, GetNextDeoptId())); |
| 1718 | 1626 |
| 1719 return target; | 1627 return target; |
| 1720 } | 1628 } |
| 1721 | 1629 |
| 1722 | |
| 1723 IndirectEntryInstr* IRRegExpMacroAssembler::IndirectWithJoinGoto( | 1630 IndirectEntryInstr* IRRegExpMacroAssembler::IndirectWithJoinGoto( |
| 1724 JoinEntryInstr* dst) { | 1631 JoinEntryInstr* dst) { |
| 1725 IndirectEntryInstr* target = | 1632 IndirectEntryInstr* target = |
| 1726 new (Z) IndirectEntryInstr(block_id_.Alloc(), indirect_id_.Alloc(), | 1633 new (Z) IndirectEntryInstr(block_id_.Alloc(), indirect_id_.Alloc(), |
| 1727 kInvalidTryIndex, GetNextDeoptId()); | 1634 kInvalidTryIndex, GetNextDeoptId()); |
| 1728 blocks_.Add(target); | 1635 blocks_.Add(target); |
| 1729 | 1636 |
| 1730 target->AppendInstruction(new (Z) GotoInstr(dst, GetNextDeoptId())); | 1637 target->AppendInstruction(new (Z) GotoInstr(dst, GetNextDeoptId())); |
| 1731 | 1638 |
| 1732 return target; | 1639 return target; |
| 1733 } | 1640 } |
| 1734 | 1641 |
| 1735 | |
| 1736 void IRRegExpMacroAssembler::CheckPreemption(bool is_backtrack) { | 1642 void IRRegExpMacroAssembler::CheckPreemption(bool is_backtrack) { |
| 1737 TAG(); | 1643 TAG(); |
| 1738 | 1644 |
| 1739 // We don't have the loop_depth available when compiling regexps, but | 1645 // We don't have the loop_depth available when compiling regexps, but |
| 1740 // we set loop_depth to a non-zero value because this instruction does | 1646 // we set loop_depth to a non-zero value because this instruction does |
| 1741 // not act as an OSR entry outside loops. | 1647 // not act as an OSR entry outside loops. |
| 1742 AppendInstruction(new (Z) CheckStackOverflowInstr( | 1648 AppendInstruction(new (Z) CheckStackOverflowInstr( |
| 1743 TokenPosition::kNoSource, | 1649 TokenPosition::kNoSource, |
| 1744 /*loop_depth=*/1, GetNextDeoptId(), | 1650 /*loop_depth=*/1, GetNextDeoptId(), |
| 1745 is_backtrack ? CheckStackOverflowInstr::kOsrAndPreemption | 1651 is_backtrack ? CheckStackOverflowInstr::kOsrAndPreemption |
| 1746 : CheckStackOverflowInstr::kOsrOnly)); | 1652 : CheckStackOverflowInstr::kOsrOnly)); |
| 1747 } | 1653 } |
| 1748 | 1654 |
| 1749 | |
| 1750 Definition* IRRegExpMacroAssembler::Add(PushArgumentInstr* lhs, | 1655 Definition* IRRegExpMacroAssembler::Add(PushArgumentInstr* lhs, |
| 1751 PushArgumentInstr* rhs) { | 1656 PushArgumentInstr* rhs) { |
| 1752 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), lhs, rhs); | 1657 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), lhs, rhs); |
| 1753 } | 1658 } |
| 1754 | 1659 |
| 1755 | |
| 1756 Definition* IRRegExpMacroAssembler::Sub(PushArgumentInstr* lhs, | 1660 Definition* IRRegExpMacroAssembler::Sub(PushArgumentInstr* lhs, |
| 1757 PushArgumentInstr* rhs) { | 1661 PushArgumentInstr* rhs) { |
| 1758 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kSUB), lhs, rhs); | 1662 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kSUB), lhs, rhs); |
| 1759 } | 1663 } |
| 1760 | 1664 |
| 1761 | |
| 1762 void IRRegExpMacroAssembler::LoadCurrentCharacterUnchecked( | 1665 void IRRegExpMacroAssembler::LoadCurrentCharacterUnchecked( |
| 1763 intptr_t cp_offset, | 1666 intptr_t cp_offset, |
| 1764 intptr_t characters) { | 1667 intptr_t characters) { |
| 1765 TAG(); | 1668 TAG(); |
| 1766 | 1669 |
| 1767 ASSERT(characters == 1 || CanReadUnaligned()); | 1670 ASSERT(characters == 1 || CanReadUnaligned()); |
| 1768 if (mode_ == ASCII) { | 1671 if (mode_ == ASCII) { |
| 1769 ASSERT(characters == 1 || characters == 2 || characters == 4); | 1672 ASSERT(characters == 1 || characters == 2 || characters == 4); |
| 1770 } else { | 1673 } else { |
| 1771 ASSERT(mode_ == UC16); | 1674 ASSERT(mode_ == UC16); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1782 PushArgument(BindLoadLocal(*string_param_length_)); | 1685 PushArgument(BindLoadLocal(*string_param_length_)); |
| 1783 // Index is stored in a temporary local so that we can later load it safely. | 1686 // Index is stored in a temporary local so that we can later load it safely. |
| 1784 StoreLocal(index_temp_, Bind(Add(off_pos_arg, len_arg))); | 1687 StoreLocal(index_temp_, Bind(Add(off_pos_arg, len_arg))); |
| 1785 | 1688 |
| 1786 // Load and store the code units. | 1689 // Load and store the code units. |
| 1787 Value* code_unit_value = LoadCodeUnitsAt(index_temp_, characters); | 1690 Value* code_unit_value = LoadCodeUnitsAt(index_temp_, characters); |
| 1788 StoreLocal(current_character_, code_unit_value); | 1691 StoreLocal(current_character_, code_unit_value); |
| 1789 PRINT(PushLocal(current_character_)); | 1692 PRINT(PushLocal(current_character_)); |
| 1790 } | 1693 } |
| 1791 | 1694 |
| 1792 | |
| 1793 Value* IRRegExpMacroAssembler::CharacterAt(LocalVariable* index) { | 1695 Value* IRRegExpMacroAssembler::CharacterAt(LocalVariable* index) { |
| 1794 return LoadCodeUnitsAt(index, 1); | 1696 return LoadCodeUnitsAt(index, 1); |
| 1795 } | 1697 } |
| 1796 | 1698 |
| 1797 | |
| 1798 Value* IRRegExpMacroAssembler::LoadCodeUnitsAt(LocalVariable* index, | 1699 Value* IRRegExpMacroAssembler::LoadCodeUnitsAt(LocalVariable* index, |
| 1799 intptr_t characters) { | 1700 intptr_t characters) { |
| 1800 // Bind the pattern as the load receiver. | 1701 // Bind the pattern as the load receiver. |
| 1801 Value* pattern_val = BindLoadLocal(*string_param_); | 1702 Value* pattern_val = BindLoadLocal(*string_param_); |
| 1802 if (RawObject::IsExternalStringClassId(specialization_cid_)) { | 1703 if (RawObject::IsExternalStringClassId(specialization_cid_)) { |
| 1803 // The data of an external string is stored through two indirections. | 1704 // The data of an external string is stored through two indirections. |
| 1804 intptr_t external_offset = 0; | 1705 intptr_t external_offset = 0; |
| 1805 intptr_t data_offset = 0; | 1706 intptr_t data_offset = 0; |
| 1806 if (specialization_cid_ == kExternalOneByteStringCid) { | 1707 if (specialization_cid_ == kExternalOneByteStringCid) { |
| 1807 external_offset = ExternalOneByteString::external_data_offset(); | 1708 external_offset = ExternalOneByteString::external_data_offset(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1821 } | 1722 } |
| 1822 | 1723 |
| 1823 // Here pattern_val might be untagged so this must not trigger a GC. | 1724 // Here pattern_val might be untagged so this must not trigger a GC. |
| 1824 Value* index_val = BindLoadLocal(*index); | 1725 Value* index_val = BindLoadLocal(*index); |
| 1825 | 1726 |
| 1826 return Bind(new (Z) LoadCodeUnitsInstr(pattern_val, index_val, characters, | 1727 return Bind(new (Z) LoadCodeUnitsInstr(pattern_val, index_val, characters, |
| 1827 specialization_cid_, | 1728 specialization_cid_, |
| 1828 TokenPosition::kNoSource)); | 1729 TokenPosition::kNoSource)); |
| 1829 } | 1730 } |
| 1830 | 1731 |
| 1831 | |
| 1832 #undef __ | 1732 #undef __ |
| 1833 | 1733 |
| 1834 } // namespace dart | 1734 } // namespace dart |
| OLD | NEW |