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 |