OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
7 | 7 |
8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
9 | 9 |
10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 } | 264 } |
265 | 265 |
266 | 266 |
267 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 267 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
268 // type test is conclusive, otherwise fallthrough if a type test could not | 268 // type test is conclusive, otherwise fallthrough if a type test could not |
269 // be completed. | 269 // be completed. |
270 // EAX: instance (must survive). | 270 // EAX: instance (must survive). |
271 // Clobbers ECX, EDI. | 271 // Clobbers ECX, EDI. |
272 RawSubtypeTestCache* | 272 RawSubtypeTestCache* |
273 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 273 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
274 intptr_t token_pos, | 274 TokenPosition token_pos, |
275 const AbstractType& type, | 275 const AbstractType& type, |
276 Label* is_instance_lbl, | 276 Label* is_instance_lbl, |
277 Label* is_not_instance_lbl) { | 277 Label* is_not_instance_lbl) { |
278 __ Comment("InstantiatedTypeWithArgumentsTest"); | 278 __ Comment("InstantiatedTypeWithArgumentsTest"); |
279 ASSERT(type.IsInstantiated()); | 279 ASSERT(type.IsInstantiated()); |
280 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); | 280 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
281 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); | 281 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); |
282 const Register kInstanceReg = EAX; | 282 const Register kInstanceReg = EAX; |
283 Error& bound_error = Error::Handle(zone()); | 283 Error& bound_error = Error::Handle(zone()); |
284 const Type& int_type = Type::Handle(zone(), Type::IntType()); | 284 const Type& int_type = Type::Handle(zone(), Type::IntType()); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 __ jmp(is_not_equal_lbl); | 353 __ jmp(is_not_equal_lbl); |
354 } | 354 } |
355 | 355 |
356 | 356 |
357 // Testing against an instantiated type with no arguments, without | 357 // Testing against an instantiated type with no arguments, without |
358 // SubtypeTestCache. | 358 // SubtypeTestCache. |
359 // EAX: instance to test against (preserved). | 359 // EAX: instance to test against (preserved). |
360 // Clobbers ECX, EDI. | 360 // Clobbers ECX, EDI. |
361 // Returns true if there is a fallthrough. | 361 // Returns true if there is a fallthrough. |
362 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 362 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
363 intptr_t token_pos, | 363 TokenPosition token_pos, |
364 const AbstractType& type, | 364 const AbstractType& type, |
365 Label* is_instance_lbl, | 365 Label* is_instance_lbl, |
366 Label* is_not_instance_lbl) { | 366 Label* is_not_instance_lbl) { |
367 __ Comment("InstantiatedTypeNoArgumentsTest"); | 367 __ Comment("InstantiatedTypeNoArgumentsTest"); |
368 ASSERT(type.IsInstantiated()); | 368 ASSERT(type.IsInstantiated()); |
369 if (type.IsFunctionType()) { | 369 if (type.IsFunctionType()) { |
370 // Fallthrough. | 370 // Fallthrough. |
371 return true; | 371 return true; |
372 } | 372 } |
373 const Class& type_class = Class::Handle(zone(), type.type_class()); | 373 const Class& type_class = Class::Handle(zone(), type.type_class()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 | 423 |
424 | 424 |
425 // Uses SubtypeTestCache to store instance class and result. | 425 // Uses SubtypeTestCache to store instance class and result. |
426 // EAX: instance to test. | 426 // EAX: instance to test. |
427 // Clobbers EDI, ECX. | 427 // Clobbers EDI, ECX. |
428 // Immediate class test already done. | 428 // Immediate class test already done. |
429 // TODO(srdjan): Implement a quicker subtype check, as type test | 429 // TODO(srdjan): Implement a quicker subtype check, as type test |
430 // arrays can grow too high, but they may be useful when optimizing | 430 // arrays can grow too high, but they may be useful when optimizing |
431 // code (type-feedback). | 431 // code (type-feedback). |
432 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 432 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
433 intptr_t token_pos, | 433 TokenPosition token_pos, |
434 const Class& type_class, | 434 const Class& type_class, |
435 Label* is_instance_lbl, | 435 Label* is_instance_lbl, |
436 Label* is_not_instance_lbl) { | 436 Label* is_not_instance_lbl) { |
437 __ Comment("Subtype1TestCacheLookup"); | 437 __ Comment("Subtype1TestCacheLookup"); |
438 const Register kInstanceReg = EAX; | 438 const Register kInstanceReg = EAX; |
439 __ LoadClass(ECX, kInstanceReg, EDI); | 439 __ LoadClass(ECX, kInstanceReg, EDI); |
440 // ECX: instance class. | 440 // ECX: instance class. |
441 // Check immediate superclass equality. | 441 // Check immediate superclass equality. |
442 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 442 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
443 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | 443 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
444 __ CompareObject(EDI, type_class); | 444 __ CompareObject(EDI, type_class); |
445 __ j(EQUAL, is_instance_lbl); | 445 __ j(EQUAL, is_instance_lbl); |
446 | 446 |
447 const Register kTypeArgumentsReg = kNoRegister; | 447 const Register kTypeArgumentsReg = kNoRegister; |
448 const Register kTempReg = EDI; | 448 const Register kTempReg = EDI; |
449 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 449 return GenerateCallSubtypeTestStub(kTestTypeOneArg, |
450 kInstanceReg, | 450 kInstanceReg, |
451 kTypeArgumentsReg, | 451 kTypeArgumentsReg, |
452 kTempReg, | 452 kTempReg, |
453 is_instance_lbl, | 453 is_instance_lbl, |
454 is_not_instance_lbl); | 454 is_not_instance_lbl); |
455 } | 455 } |
456 | 456 |
457 | 457 |
458 // Generates inlined check if 'type' is a type parameter or type itself | 458 // Generates inlined check if 'type' is a type parameter or type itself |
459 // EAX: instance (preserved). | 459 // EAX: instance (preserved). |
460 // Clobbers EDX, EDI, ECX. | 460 // Clobbers EDX, EDI, ECX. |
461 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 461 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
462 intptr_t token_pos, | 462 TokenPosition token_pos, |
463 const AbstractType& type, | 463 const AbstractType& type, |
464 Label* is_instance_lbl, | 464 Label* is_instance_lbl, |
465 Label* is_not_instance_lbl) { | 465 Label* is_not_instance_lbl) { |
466 __ Comment("UninstantiatedTypeTest"); | 466 __ Comment("UninstantiatedTypeTest"); |
467 ASSERT(!type.IsInstantiated()); | 467 ASSERT(!type.IsInstantiated()); |
468 // Skip check if destination is a dynamic type. | 468 // Skip check if destination is a dynamic type. |
469 const Immediate& raw_null = | 469 const Immediate& raw_null = |
470 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 470 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
471 if (type.IsTypeParameter()) { | 471 if (type.IsTypeParameter()) { |
472 const TypeParameter& type_param = TypeParameter::Cast(type); | 472 const TypeParameter& type_param = TypeParameter::Cast(type); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 // Inputs: | 537 // Inputs: |
538 // - EAX: instance to test against (preserved). | 538 // - EAX: instance to test against (preserved). |
539 // - EDX: optional instantiator type arguments (preserved). | 539 // - EDX: optional instantiator type arguments (preserved). |
540 // Clobbers ECX, EDI. | 540 // Clobbers ECX, EDI. |
541 // Returns: | 541 // Returns: |
542 // - preserved instance in EAX and optional instantiator type arguments in EDX. | 542 // - preserved instance in EAX and optional instantiator type arguments in EDX. |
543 // Note that this inlined code must be followed by the runtime_call code, as it | 543 // Note that this inlined code must be followed by the runtime_call code, as it |
544 // may fall through to it. Otherwise, this inline code will jump to the label | 544 // may fall through to it. Otherwise, this inline code will jump to the label |
545 // is_instance or to the label is_not_instance. | 545 // is_instance or to the label is_not_instance. |
546 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 546 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
547 intptr_t token_pos, | 547 TokenPosition token_pos, |
548 const AbstractType& type, | 548 const AbstractType& type, |
549 Label* is_instance_lbl, | 549 Label* is_instance_lbl, |
550 Label* is_not_instance_lbl) { | 550 Label* is_not_instance_lbl) { |
551 __ Comment("InlineInstanceof"); | 551 __ Comment("InlineInstanceof"); |
552 if (type.IsVoidType()) { | 552 if (type.IsVoidType()) { |
553 // A non-null value is returned from a void function, which will result in a | 553 // A non-null value is returned from a void function, which will result in a |
554 // type error. A null value is handled prior to executing this inline code. | 554 // type error. A null value is handled prior to executing this inline code. |
555 return SubtypeTestCache::null(); | 555 return SubtypeTestCache::null(); |
556 } | 556 } |
557 if (type.IsInstantiated()) { | 557 if (type.IsInstantiated()) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 // therefore eliminated, optimize it by adding inlined tests for: | 591 // therefore eliminated, optimize it by adding inlined tests for: |
592 // - NULL -> return false. | 592 // - NULL -> return false. |
593 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 593 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
594 // - Class equality (only if class is not parameterized). | 594 // - Class equality (only if class is not parameterized). |
595 // Inputs: | 595 // Inputs: |
596 // - EAX: object. | 596 // - EAX: object. |
597 // - EDX: instantiator type arguments or raw_null. | 597 // - EDX: instantiator type arguments or raw_null. |
598 // Clobbers EDX. | 598 // Clobbers EDX. |
599 // Returns: | 599 // Returns: |
600 // - true or false in EAX. | 600 // - true or false in EAX. |
601 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, | 601 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
602 intptr_t deopt_id, | 602 intptr_t deopt_id, |
603 const AbstractType& type, | 603 const AbstractType& type, |
604 bool negate_result, | 604 bool negate_result, |
605 LocationSummary* locs) { | 605 LocationSummary* locs) { |
606 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 606 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
607 | 607 |
608 const Immediate& raw_null = | 608 const Immediate& raw_null = |
609 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 609 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
610 Label is_instance, is_not_instance; | 610 Label is_instance, is_not_instance; |
611 __ pushl(EDX); // Store instantiator type arguments. | 611 __ pushl(EDX); // Store instantiator type arguments. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
673 // - NULL -> return NULL. | 673 // - NULL -> return NULL. |
674 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 674 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
675 // - Class equality (only if class is not parameterized). | 675 // - Class equality (only if class is not parameterized). |
676 // Inputs: | 676 // Inputs: |
677 // - EAX: object. | 677 // - EAX: object. |
678 // - EDX: instantiator type arguments or raw_null. | 678 // - EDX: instantiator type arguments or raw_null. |
679 // Returns: | 679 // Returns: |
680 // - object in EAX for successful assignable check (or throws TypeError). | 680 // - object in EAX for successful assignable check (or throws TypeError). |
681 // Performance notes: positive checks must be quick, negative checks can be slow | 681 // Performance notes: positive checks must be quick, negative checks can be slow |
682 // as they throw an exception. | 682 // as they throw an exception. |
683 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, | 683 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
684 intptr_t deopt_id, | 684 intptr_t deopt_id, |
685 const AbstractType& dst_type, | 685 const AbstractType& dst_type, |
686 const String& dst_name, | 686 const String& dst_name, |
687 LocationSummary* locs) { | 687 LocationSummary* locs) { |
688 ASSERT(!Token::IsClassifying(token_pos)); | 688 ASSERT(!token_pos.IsClassifying()); |
689 ASSERT(!dst_type.IsNull()); | 689 ASSERT(!dst_type.IsNull()); |
690 ASSERT(dst_type.IsFinalized()); | 690 ASSERT(dst_type.IsFinalized()); |
691 // Assignable check is skipped in FlowGraphBuilder, not here. | 691 // Assignable check is skipped in FlowGraphBuilder, not here. |
692 ASSERT(dst_type.IsMalformedOrMalbounded() || | 692 ASSERT(dst_type.IsMalformedOrMalbounded() || |
693 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 693 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
694 __ pushl(EDX); // Store instantiator type arguments. | 694 __ pushl(EDX); // Store instantiator type arguments. |
695 // A null object is always assignable and is returned as result. | 695 // A null object is always assignable and is returned as result. |
696 const Immediate& raw_null = | 696 const Immediate& raw_null = |
697 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 697 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
698 Label is_assignable, runtime_call; | 698 Label is_assignable, runtime_call; |
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1141 if (is_optimizing() && !FLAG_precompilation) { | 1141 if (is_optimizing() && !FLAG_precompilation) { |
1142 // Leave enough space for patching in case of lazy deoptimization from | 1142 // Leave enough space for patching in case of lazy deoptimization from |
1143 // deferred code. | 1143 // deferred code. |
1144 __ nop(CallPattern::pattern_length_in_bytes()); | 1144 __ nop(CallPattern::pattern_length_in_bytes()); |
1145 lazy_deopt_pc_offset_ = assembler()->CodeSize(); | 1145 lazy_deopt_pc_offset_ = assembler()->CodeSize(); |
1146 __ Jmp(*StubCode::DeoptimizeLazy_entry()); | 1146 __ Jmp(*StubCode::DeoptimizeLazy_entry()); |
1147 } | 1147 } |
1148 } | 1148 } |
1149 | 1149 |
1150 | 1150 |
1151 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1151 void FlowGraphCompiler::GenerateCall(TokenPosition token_pos, |
1152 const StubEntry& stub_entry, | 1152 const StubEntry& stub_entry, |
1153 RawPcDescriptors::Kind kind, | 1153 RawPcDescriptors::Kind kind, |
1154 LocationSummary* locs) { | 1154 LocationSummary* locs) { |
1155 __ Call(stub_entry); | 1155 __ Call(stub_entry); |
1156 AddCurrentDescriptor(kind, Thread::kNoDeoptId, token_pos); | 1156 AddCurrentDescriptor(kind, Thread::kNoDeoptId, token_pos); |
1157 RecordSafepoint(locs); | 1157 RecordSafepoint(locs); |
1158 } | 1158 } |
1159 | 1159 |
1160 | 1160 |
1161 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, | 1161 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, |
1162 intptr_t token_pos, | 1162 TokenPosition token_pos, |
1163 const StubEntry& stub_entry, | 1163 const StubEntry& stub_entry, |
1164 RawPcDescriptors::Kind kind, | 1164 RawPcDescriptors::Kind kind, |
1165 LocationSummary* locs) { | 1165 LocationSummary* locs) { |
1166 __ Call(stub_entry); | 1166 __ Call(stub_entry); |
1167 AddCurrentDescriptor(kind, deopt_id, token_pos); | 1167 AddCurrentDescriptor(kind, deopt_id, token_pos); |
1168 RecordSafepoint(locs); | 1168 RecordSafepoint(locs); |
1169 // Marks either the continuation point in unoptimized code or the | 1169 // Marks either the continuation point in unoptimized code or the |
1170 // deoptimization point in optimized code, after call. | 1170 // deoptimization point in optimized code, after call. |
1171 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1171 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1172 if (is_optimizing()) { | 1172 if (is_optimizing()) { |
1173 AddDeoptIndexAtCall(deopt_id_after, token_pos); | 1173 AddDeoptIndexAtCall(deopt_id_after, token_pos); |
1174 } else { | 1174 } else { |
1175 // Add deoptimization continuation point after the call and before the | 1175 // Add deoptimization continuation point after the call and before the |
1176 // arguments are removed. | 1176 // arguments are removed. |
1177 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1177 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1178 } | 1178 } |
1179 } | 1179 } |
1180 | 1180 |
1181 | 1181 |
1182 void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos, | 1182 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos, |
1183 intptr_t deopt_id, | 1183 intptr_t deopt_id, |
1184 const RuntimeEntry& entry, | 1184 const RuntimeEntry& entry, |
1185 intptr_t argument_count, | 1185 intptr_t argument_count, |
1186 LocationSummary* locs) { | 1186 LocationSummary* locs) { |
1187 __ CallRuntime(entry, argument_count); | 1187 __ CallRuntime(entry, argument_count); |
1188 AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id, token_pos); | 1188 AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id, token_pos); |
1189 RecordSafepoint(locs); | 1189 RecordSafepoint(locs); |
1190 if (deopt_id != Thread::kNoDeoptId) { | 1190 if (deopt_id != Thread::kNoDeoptId) { |
1191 // Marks either the continuation point in unoptimized code or the | 1191 // Marks either the continuation point in unoptimized code or the |
1192 // deoptimization point in optimized code, after call. | 1192 // deoptimization point in optimized code, after call. |
1193 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1193 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1194 if (is_optimizing()) { | 1194 if (is_optimizing()) { |
1195 AddDeoptIndexAtCall(deopt_id_after, token_pos); | 1195 AddDeoptIndexAtCall(deopt_id_after, token_pos); |
1196 } else { | 1196 } else { |
1197 // Add deoptimization continuation point after the call and before the | 1197 // Add deoptimization continuation point after the call and before the |
1198 // arguments are removed. | 1198 // arguments are removed. |
1199 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1199 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1200 } | 1200 } |
1201 } | 1201 } |
1202 } | 1202 } |
1203 | 1203 |
1204 | 1204 |
1205 void FlowGraphCompiler::EmitUnoptimizedStaticCall( | 1205 void FlowGraphCompiler::EmitUnoptimizedStaticCall( |
1206 intptr_t argument_count, | 1206 intptr_t argument_count, |
1207 intptr_t deopt_id, | 1207 intptr_t deopt_id, |
1208 intptr_t token_pos, | 1208 TokenPosition token_pos, |
1209 LocationSummary* locs, | 1209 LocationSummary* locs, |
1210 const ICData& ic_data) { | 1210 const ICData& ic_data) { |
1211 const StubEntry& stub_entry = | 1211 const StubEntry& stub_entry = |
1212 *StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); | 1212 *StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); |
1213 __ LoadObject(ECX, ic_data); | 1213 __ LoadObject(ECX, ic_data); |
1214 GenerateDartCall(deopt_id, | 1214 GenerateDartCall(deopt_id, |
1215 token_pos, | 1215 token_pos, |
1216 stub_entry, | 1216 stub_entry, |
1217 RawPcDescriptors::kUnoptStaticCall, | 1217 RawPcDescriptors::kUnoptStaticCall, |
1218 locs); | 1218 locs); |
(...skipping 12 matching lines...) Expand all Loading... |
1231 __ LoadObject(EAX, edge_counters_array_); | 1231 __ LoadObject(EAX, edge_counters_array_); |
1232 __ IncrementSmiField(FieldAddress(EAX, Array::element_offset(edge_id)), 1); | 1232 __ IncrementSmiField(FieldAddress(EAX, Array::element_offset(edge_id)), 1); |
1233 } | 1233 } |
1234 | 1234 |
1235 | 1235 |
1236 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1236 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
1237 const StubEntry& stub_entry, | 1237 const StubEntry& stub_entry, |
1238 const ICData& ic_data, | 1238 const ICData& ic_data, |
1239 intptr_t argument_count, | 1239 intptr_t argument_count, |
1240 intptr_t deopt_id, | 1240 intptr_t deopt_id, |
1241 intptr_t token_pos, | 1241 TokenPosition token_pos, |
1242 LocationSummary* locs) { | 1242 LocationSummary* locs) { |
1243 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1243 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); |
1244 // Each ICData propagated from unoptimized to optimized code contains the | 1244 // Each ICData propagated from unoptimized to optimized code contains the |
1245 // function that corresponds to the Dart function of that IC call. Due | 1245 // function that corresponds to the Dart function of that IC call. Due |
1246 // to inlining in optimized code, that function may not correspond to the | 1246 // to inlining in optimized code, that function may not correspond to the |
1247 // top-level function (parsed_function().function()) which could be | 1247 // top-level function (parsed_function().function()) which could be |
1248 // reoptimized and which counter needs to be incremented. | 1248 // reoptimized and which counter needs to be incremented. |
1249 // Pass the function explicitly, it is used in IC stub. | 1249 // Pass the function explicitly, it is used in IC stub. |
1250 __ LoadObject(EBX, parsed_function().function()); | 1250 __ LoadObject(EBX, parsed_function().function()); |
1251 __ LoadObject(ECX, ic_data); | 1251 __ LoadObject(ECX, ic_data); |
1252 GenerateDartCall(deopt_id, | 1252 GenerateDartCall(deopt_id, |
1253 token_pos, | 1253 token_pos, |
1254 stub_entry, | 1254 stub_entry, |
1255 RawPcDescriptors::kIcCall, | 1255 RawPcDescriptors::kIcCall, |
1256 locs); | 1256 locs); |
1257 __ Drop(argument_count); | 1257 __ Drop(argument_count); |
1258 } | 1258 } |
1259 | 1259 |
1260 | 1260 |
1261 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, | 1261 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, |
1262 const ICData& ic_data, | 1262 const ICData& ic_data, |
1263 intptr_t argument_count, | 1263 intptr_t argument_count, |
1264 intptr_t deopt_id, | 1264 intptr_t deopt_id, |
1265 intptr_t token_pos, | 1265 TokenPosition token_pos, |
1266 LocationSummary* locs) { | 1266 LocationSummary* locs) { |
1267 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1267 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); |
1268 __ LoadObject(ECX, ic_data); | 1268 __ LoadObject(ECX, ic_data); |
1269 GenerateDartCall(deopt_id, | 1269 GenerateDartCall(deopt_id, |
1270 token_pos, | 1270 token_pos, |
1271 stub_entry, | 1271 stub_entry, |
1272 RawPcDescriptors::kIcCall, | 1272 RawPcDescriptors::kIcCall, |
1273 locs); | 1273 locs); |
1274 __ Drop(argument_count); | 1274 __ Drop(argument_count); |
1275 } | 1275 } |
1276 | 1276 |
1277 | 1277 |
1278 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1278 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
1279 const ICData& ic_data, | 1279 const ICData& ic_data, |
1280 intptr_t argument_count, | 1280 intptr_t argument_count, |
1281 intptr_t deopt_id, | 1281 intptr_t deopt_id, |
1282 intptr_t token_pos, | 1282 TokenPosition token_pos, |
1283 LocationSummary* locs, | 1283 LocationSummary* locs, |
1284 intptr_t try_index) { | 1284 intptr_t try_index) { |
1285 const String& name = String::Handle(zone(), ic_data.target_name()); | 1285 const String& name = String::Handle(zone(), ic_data.target_name()); |
1286 const Array& arguments_descriptor = | 1286 const Array& arguments_descriptor = |
1287 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1287 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
1288 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1288 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
1289 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(), | 1289 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(), |
1290 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1290 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
1291 | 1291 |
1292 __ Comment("MegamorphicCall"); | 1292 __ Comment("MegamorphicCall"); |
(...skipping 20 matching lines...) Expand all Loading... |
1313 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1313 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1314 } | 1314 } |
1315 __ Drop(argument_count); | 1315 __ Drop(argument_count); |
1316 } | 1316 } |
1317 | 1317 |
1318 | 1318 |
1319 void FlowGraphCompiler::EmitSwitchableInstanceCall( | 1319 void FlowGraphCompiler::EmitSwitchableInstanceCall( |
1320 const ICData& ic_data, | 1320 const ICData& ic_data, |
1321 intptr_t argument_count, | 1321 intptr_t argument_count, |
1322 intptr_t deopt_id, | 1322 intptr_t deopt_id, |
1323 intptr_t token_pos, | 1323 TokenPosition token_pos, |
1324 LocationSummary* locs) { | 1324 LocationSummary* locs) { |
1325 // Only generated with precompilation. | 1325 // Only generated with precompilation. |
1326 UNREACHABLE(); | 1326 UNREACHABLE(); |
1327 } | 1327 } |
1328 | 1328 |
1329 | 1329 |
1330 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1330 void FlowGraphCompiler::EmitOptimizedStaticCall( |
1331 const Function& function, | 1331 const Function& function, |
1332 const Array& arguments_descriptor, | 1332 const Array& arguments_descriptor, |
1333 intptr_t argument_count, | 1333 intptr_t argument_count, |
1334 intptr_t deopt_id, | 1334 intptr_t deopt_id, |
1335 intptr_t token_pos, | 1335 TokenPosition token_pos, |
1336 LocationSummary* locs) { | 1336 LocationSummary* locs) { |
1337 __ LoadObject(EDX, arguments_descriptor); | 1337 __ LoadObject(EDX, arguments_descriptor); |
1338 // Do not use the code from the function, but let the code be patched so that | 1338 // Do not use the code from the function, but let the code be patched so that |
1339 // we can record the outgoing edges to other code. | 1339 // we can record the outgoing edges to other code. |
1340 GenerateDartCall(deopt_id, | 1340 GenerateDartCall(deopt_id, |
1341 token_pos, | 1341 token_pos, |
1342 *StubCode::CallStaticFunction_entry(), | 1342 *StubCode::CallStaticFunction_entry(), |
1343 RawPcDescriptors::kOther, | 1343 RawPcDescriptors::kOther, |
1344 locs); | 1344 locs); |
1345 AddStaticCallTarget(function); | 1345 AddStaticCallTarget(function); |
1346 __ Drop(argument_count); | 1346 __ Drop(argument_count); |
1347 } | 1347 } |
1348 | 1348 |
1349 | 1349 |
1350 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( | 1350 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( |
1351 Register reg, | 1351 Register reg, |
1352 const Object& obj, | 1352 const Object& obj, |
1353 bool needs_number_check, | 1353 bool needs_number_check, |
1354 intptr_t token_pos) { | 1354 TokenPosition token_pos) { |
1355 ASSERT(!needs_number_check || | 1355 ASSERT(!needs_number_check || |
1356 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint())); | 1356 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint())); |
1357 | 1357 |
1358 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { | 1358 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { |
1359 ASSERT(!needs_number_check); | 1359 ASSERT(!needs_number_check); |
1360 __ testl(reg, reg); | 1360 __ testl(reg, reg); |
1361 return EQUAL; | 1361 return EQUAL; |
1362 } | 1362 } |
1363 | 1363 |
1364 if (needs_number_check) { | 1364 if (needs_number_check) { |
1365 __ pushl(reg); | 1365 __ pushl(reg); |
1366 __ PushObject(obj); | 1366 __ PushObject(obj); |
1367 if (is_optimizing()) { | 1367 if (is_optimizing()) { |
1368 __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1368 __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1369 } else { | 1369 } else { |
1370 __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1370 __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1371 } | 1371 } |
1372 if (token_pos >= 0) { | 1372 if (token_pos.IsReal()) { |
1373 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1373 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, |
1374 Thread::kNoDeoptId, | 1374 Thread::kNoDeoptId, |
1375 token_pos); | 1375 token_pos); |
1376 } | 1376 } |
1377 // Stub returns result in flags (result of a cmpl, we need ZF computed). | 1377 // Stub returns result in flags (result of a cmpl, we need ZF computed). |
1378 __ popl(reg); // Discard constant. | 1378 __ popl(reg); // Discard constant. |
1379 __ popl(reg); // Restore 'reg'. | 1379 __ popl(reg); // Restore 'reg'. |
1380 } else { | 1380 } else { |
1381 __ CompareObject(reg, obj); | 1381 __ CompareObject(reg, obj); |
1382 } | 1382 } |
1383 return EQUAL; | 1383 return EQUAL; |
1384 } | 1384 } |
1385 | 1385 |
1386 | 1386 |
1387 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1387 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( |
1388 Register right, | 1388 Register left, |
1389 bool needs_number_check, | 1389 Register right, |
1390 intptr_t token_pos) { | 1390 bool needs_number_check, |
| 1391 TokenPosition token_pos) { |
1391 if (needs_number_check) { | 1392 if (needs_number_check) { |
1392 __ pushl(left); | 1393 __ pushl(left); |
1393 __ pushl(right); | 1394 __ pushl(right); |
1394 if (is_optimizing()) { | 1395 if (is_optimizing()) { |
1395 __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1396 __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1396 } else { | 1397 } else { |
1397 __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1398 __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1398 } | 1399 } |
1399 if (token_pos >= 0) { | 1400 if (token_pos.IsReal()) { |
1400 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1401 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, |
1401 Thread::kNoDeoptId, | 1402 Thread::kNoDeoptId, |
1402 token_pos); | 1403 token_pos); |
1403 } | 1404 } |
1404 // Stub returns result in flags (result of a cmpl, we need ZF computed). | 1405 // Stub returns result in flags (result of a cmpl, we need ZF computed). |
1405 __ popl(right); | 1406 __ popl(right); |
1406 __ popl(left); | 1407 __ popl(left); |
1407 } else { | 1408 } else { |
1408 __ cmpl(left, right); | 1409 __ cmpl(left, right); |
1409 } | 1410 } |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1486 } | 1487 } |
1487 #endif | 1488 #endif |
1488 | 1489 |
1489 | 1490 |
1490 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1491 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
1491 intptr_t argument_count, | 1492 intptr_t argument_count, |
1492 const Array& argument_names, | 1493 const Array& argument_names, |
1493 Label* failed, | 1494 Label* failed, |
1494 Label* match_found, | 1495 Label* match_found, |
1495 intptr_t deopt_id, | 1496 intptr_t deopt_id, |
1496 intptr_t token_index, | 1497 TokenPosition token_index, |
1497 LocationSummary* locs) { | 1498 LocationSummary* locs) { |
1498 ASSERT(is_optimizing()); | 1499 ASSERT(is_optimizing()); |
1499 __ Comment("EmitTestAndCall"); | 1500 __ Comment("EmitTestAndCall"); |
1500 const Array& arguments_descriptor = | 1501 const Array& arguments_descriptor = |
1501 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, | 1502 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, |
1502 argument_names)); | 1503 argument_names)); |
1503 // Load receiver into EAX. | 1504 // Load receiver into EAX. |
1504 __ movl(EAX, Address(ESP, (argument_count - 1) * kWordSize)); | 1505 __ movl(EAX, Address(ESP, (argument_count - 1) * kWordSize)); |
1505 __ LoadObject(EDX, arguments_descriptor); | 1506 __ LoadObject(EDX, arguments_descriptor); |
1506 | 1507 |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1839 __ movups(reg, Address(ESP, 0)); | 1840 __ movups(reg, Address(ESP, 0)); |
1840 __ addl(ESP, Immediate(kFpuRegisterSize)); | 1841 __ addl(ESP, Immediate(kFpuRegisterSize)); |
1841 } | 1842 } |
1842 | 1843 |
1843 | 1844 |
1844 #undef __ | 1845 #undef __ |
1845 | 1846 |
1846 } // namespace dart | 1847 } // namespace dart |
1847 | 1848 |
1848 #endif // defined TARGET_ARCH_IA32 | 1849 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |