| 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 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 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 } | 260 } |
| 261 | 261 |
| 262 | 262 |
| 263 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 263 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 264 // type test is conclusive, otherwise fallthrough if a type test could not | 264 // type test is conclusive, otherwise fallthrough if a type test could not |
| 265 // be completed. | 265 // be completed. |
| 266 // R0: instance being type checked (preserved). | 266 // R0: instance being type checked (preserved). |
| 267 // Clobbers R2. | 267 // Clobbers R2. |
| 268 RawSubtypeTestCache* | 268 RawSubtypeTestCache* |
| 269 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 269 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 270 intptr_t token_pos, | 270 TokenPosition token_pos, |
| 271 const AbstractType& type, | 271 const AbstractType& type, |
| 272 Label* is_instance_lbl, | 272 Label* is_instance_lbl, |
| 273 Label* is_not_instance_lbl) { | 273 Label* is_not_instance_lbl) { |
| 274 __ Comment("InstantiatedTypeWithArgumentsTest"); | 274 __ Comment("InstantiatedTypeWithArgumentsTest"); |
| 275 ASSERT(type.IsInstantiated()); | 275 ASSERT(type.IsInstantiated()); |
| 276 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); | 276 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 277 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); | 277 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); |
| 278 const Register kInstanceReg = R0; | 278 const Register kInstanceReg = R0; |
| 279 Error& bound_error = Error::Handle(zone()); | 279 Error& bound_error = Error::Handle(zone()); |
| 280 const Type& int_type = Type::Handle(zone(), Type::IntType()); | 280 const Type& int_type = Type::Handle(zone(), Type::IntType()); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 __ b(is_not_equal_lbl); | 350 __ b(is_not_equal_lbl); |
| 351 } | 351 } |
| 352 | 352 |
| 353 | 353 |
| 354 // Testing against an instantiated type with no arguments, without | 354 // Testing against an instantiated type with no arguments, without |
| 355 // SubtypeTestCache. | 355 // SubtypeTestCache. |
| 356 // R0: instance being type checked (preserved). | 356 // R0: instance being type checked (preserved). |
| 357 // Clobbers R2, R3. | 357 // Clobbers R2, R3. |
| 358 // Returns true if there is a fallthrough. | 358 // Returns true if there is a fallthrough. |
| 359 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 359 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
| 360 intptr_t token_pos, | 360 TokenPosition token_pos, |
| 361 const AbstractType& type, | 361 const AbstractType& type, |
| 362 Label* is_instance_lbl, | 362 Label* is_instance_lbl, |
| 363 Label* is_not_instance_lbl) { | 363 Label* is_not_instance_lbl) { |
| 364 __ Comment("InstantiatedTypeNoArgumentsTest"); | 364 __ Comment("InstantiatedTypeNoArgumentsTest"); |
| 365 ASSERT(type.IsInstantiated()); | 365 ASSERT(type.IsInstantiated()); |
| 366 if (type.IsFunctionType()) { | 366 if (type.IsFunctionType()) { |
| 367 // Fallthrough. | 367 // Fallthrough. |
| 368 return true; | 368 return true; |
| 369 } | 369 } |
| 370 const Class& type_class = Class::Handle(zone(), type.type_class()); | 370 const Class& type_class = Class::Handle(zone(), type.type_class()); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 | 420 |
| 421 | 421 |
| 422 // Uses SubtypeTestCache to store instance class and result. | 422 // Uses SubtypeTestCache to store instance class and result. |
| 423 // R0: instance to test. | 423 // R0: instance to test. |
| 424 // Clobbers R1-R4,R9. | 424 // Clobbers R1-R4,R9. |
| 425 // Immediate class test already done. | 425 // Immediate class test already done. |
| 426 // TODO(srdjan): Implement a quicker subtype check, as type test | 426 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 427 // arrays can grow too high, but they may be useful when optimizing | 427 // arrays can grow too high, but they may be useful when optimizing |
| 428 // code (type-feedback). | 428 // code (type-feedback). |
| 429 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 429 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
| 430 intptr_t token_pos, | 430 TokenPosition token_pos, |
| 431 const Class& type_class, | 431 const Class& type_class, |
| 432 Label* is_instance_lbl, | 432 Label* is_instance_lbl, |
| 433 Label* is_not_instance_lbl) { | 433 Label* is_not_instance_lbl) { |
| 434 __ Comment("Subtype1TestCacheLookup"); | 434 __ Comment("Subtype1TestCacheLookup"); |
| 435 const Register kInstanceReg = R0; | 435 const Register kInstanceReg = R0; |
| 436 __ LoadClass(R1, kInstanceReg, R2); | 436 __ LoadClass(R1, kInstanceReg, R2); |
| 437 // R1: instance class. | 437 // R1: instance class. |
| 438 // Check immediate superclass equality. | 438 // Check immediate superclass equality. |
| 439 __ ldr(R2, FieldAddress(R1, Class::super_type_offset())); | 439 __ ldr(R2, FieldAddress(R1, Class::super_type_offset())); |
| 440 __ ldr(R2, FieldAddress(R2, Type::type_class_offset())); | 440 __ ldr(R2, FieldAddress(R2, Type::type_class_offset())); |
| 441 __ CompareObject(R2, type_class); | 441 __ CompareObject(R2, type_class); |
| 442 __ b(is_instance_lbl, EQ); | 442 __ b(is_instance_lbl, EQ); |
| 443 | 443 |
| 444 const Register kTypeArgumentsReg = kNoRegister; | 444 const Register kTypeArgumentsReg = kNoRegister; |
| 445 const Register kTempReg = kNoRegister; | 445 const Register kTempReg = kNoRegister; |
| 446 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 446 return GenerateCallSubtypeTestStub(kTestTypeOneArg, |
| 447 kInstanceReg, | 447 kInstanceReg, |
| 448 kTypeArgumentsReg, | 448 kTypeArgumentsReg, |
| 449 kTempReg, | 449 kTempReg, |
| 450 is_instance_lbl, | 450 is_instance_lbl, |
| 451 is_not_instance_lbl); | 451 is_not_instance_lbl); |
| 452 } | 452 } |
| 453 | 453 |
| 454 | 454 |
| 455 // Generates inlined check if 'type' is a type parameter or type itself | 455 // Generates inlined check if 'type' is a type parameter or type itself |
| 456 // R0: instance (preserved). | 456 // R0: instance (preserved). |
| 457 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 457 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 458 intptr_t token_pos, | 458 TokenPosition token_pos, |
| 459 const AbstractType& type, | 459 const AbstractType& type, |
| 460 Label* is_instance_lbl, | 460 Label* is_instance_lbl, |
| 461 Label* is_not_instance_lbl) { | 461 Label* is_not_instance_lbl) { |
| 462 __ Comment("UninstantiatedTypeTest"); | 462 __ Comment("UninstantiatedTypeTest"); |
| 463 ASSERT(!type.IsInstantiated()); | 463 ASSERT(!type.IsInstantiated()); |
| 464 // Skip check if destination is a dynamic type. | 464 // Skip check if destination is a dynamic type. |
| 465 if (type.IsTypeParameter()) { | 465 if (type.IsTypeParameter()) { |
| 466 const TypeParameter& type_param = TypeParameter::Cast(type); | 466 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 467 // Load instantiator type arguments on stack. | 467 // Load instantiator type arguments on stack. |
| 468 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. | 468 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 // Inputs: | 531 // Inputs: |
| 532 // - R0: instance being type checked (preserved). | 532 // - R0: instance being type checked (preserved). |
| 533 // - R1: optional instantiator type arguments (preserved). | 533 // - R1: optional instantiator type arguments (preserved). |
| 534 // Clobbers R2, R3. | 534 // Clobbers R2, R3. |
| 535 // Returns: | 535 // Returns: |
| 536 // - preserved instance in R0 and optional instantiator type arguments in R1. | 536 // - preserved instance in R0 and optional instantiator type arguments in R1. |
| 537 // Note that this inlined code must be followed by the runtime_call code, as it | 537 // Note that this inlined code must be followed by the runtime_call code, as it |
| 538 // may fall through to it. Otherwise, this inline code will jump to the label | 538 // may fall through to it. Otherwise, this inline code will jump to the label |
| 539 // is_instance or to the label is_not_instance. | 539 // is_instance or to the label is_not_instance. |
| 540 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 540 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
| 541 intptr_t token_pos, | 541 TokenPosition token_pos, |
| 542 const AbstractType& type, | 542 const AbstractType& type, |
| 543 Label* is_instance_lbl, | 543 Label* is_instance_lbl, |
| 544 Label* is_not_instance_lbl) { | 544 Label* is_not_instance_lbl) { |
| 545 __ Comment("InlineInstanceof"); | 545 __ Comment("InlineInstanceof"); |
| 546 if (type.IsVoidType()) { | 546 if (type.IsVoidType()) { |
| 547 // A non-null value is returned from a void function, which will result in a | 547 // A non-null value is returned from a void function, which will result in a |
| 548 // type error. A null value is handled prior to executing this inline code. | 548 // type error. A null value is handled prior to executing this inline code. |
| 549 return SubtypeTestCache::null(); | 549 return SubtypeTestCache::null(); |
| 550 } | 550 } |
| 551 if (type.IsInstantiated()) { | 551 if (type.IsInstantiated()) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 // If instanceof type test cannot be performed successfully at compile time and | 584 // If instanceof type test cannot be performed successfully at compile time and |
| 585 // therefore eliminated, optimize it by adding inlined tests for: | 585 // therefore eliminated, optimize it by adding inlined tests for: |
| 586 // - NULL -> return false. | 586 // - NULL -> return false. |
| 587 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 587 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 588 // - Class equality (only if class is not parameterized). | 588 // - Class equality (only if class is not parameterized). |
| 589 // Inputs: | 589 // Inputs: |
| 590 // - R0: object. | 590 // - R0: object. |
| 591 // - R1: instantiator type arguments or raw_null. | 591 // - R1: instantiator type arguments or raw_null. |
| 592 // Returns: | 592 // Returns: |
| 593 // - true or false in R0. | 593 // - true or false in R0. |
| 594 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, | 594 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
| 595 intptr_t deopt_id, | 595 intptr_t deopt_id, |
| 596 const AbstractType& type, | 596 const AbstractType& type, |
| 597 bool negate_result, | 597 bool negate_result, |
| 598 LocationSummary* locs) { | 598 LocationSummary* locs) { |
| 599 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); | 599 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
| 600 | 600 |
| 601 // Preserve instantiator type arguments (R1). | 601 // Preserve instantiator type arguments (R1). |
| 602 __ Push(R1); | 602 __ Push(R1); |
| 603 | 603 |
| 604 Label is_instance, is_not_instance; | 604 Label is_instance, is_not_instance; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 664 // - NULL -> return NULL. | 664 // - NULL -> return NULL. |
| 665 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 665 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 666 // - Class equality (only if class is not parameterized). | 666 // - Class equality (only if class is not parameterized). |
| 667 // Inputs: | 667 // Inputs: |
| 668 // - R0: instance being type checked. | 668 // - R0: instance being type checked. |
| 669 // - R1: instantiator type arguments or raw_null. | 669 // - R1: instantiator type arguments or raw_null. |
| 670 // Returns: | 670 // Returns: |
| 671 // - object in R0 for successful assignable check (or throws TypeError). | 671 // - object in R0 for successful assignable check (or throws TypeError). |
| 672 // Performance notes: positive checks must be quick, negative checks can be slow | 672 // Performance notes: positive checks must be quick, negative checks can be slow |
| 673 // as they throw an exception. | 673 // as they throw an exception. |
| 674 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, | 674 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
| 675 intptr_t deopt_id, | 675 intptr_t deopt_id, |
| 676 const AbstractType& dst_type, | 676 const AbstractType& dst_type, |
| 677 const String& dst_name, | 677 const String& dst_name, |
| 678 LocationSummary* locs) { | 678 LocationSummary* locs) { |
| 679 ASSERT(!Token::IsClassifying(token_pos)); | 679 ASSERT(!token_pos.IsClassifying()); |
| 680 ASSERT(!dst_type.IsNull()); | 680 ASSERT(!dst_type.IsNull()); |
| 681 ASSERT(dst_type.IsFinalized()); | 681 ASSERT(dst_type.IsFinalized()); |
| 682 // Assignable check is skipped in FlowGraphBuilder, not here. | 682 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 683 ASSERT(dst_type.IsMalformedOrMalbounded() || | 683 ASSERT(dst_type.IsMalformedOrMalbounded() || |
| 684 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 684 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 685 // Preserve instantiator type arguments (R1). | 685 // Preserve instantiator type arguments (R1). |
| 686 __ Push(R1); | 686 __ Push(R1); |
| 687 // A null object is always assignable and is returned as result. | 687 // A null object is always assignable and is returned as result. |
| 688 Label is_assignable, runtime_call; | 688 Label is_assignable, runtime_call; |
| 689 __ CompareObject(R0, Object::null_object()); | 689 __ CompareObject(R0, Object::null_object()); |
| (...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1132 i < CallPattern::DeoptCallPatternLengthInInstructions(); | 1132 i < CallPattern::DeoptCallPatternLengthInInstructions(); |
| 1133 ++i) { | 1133 ++i) { |
| 1134 __ nop(); | 1134 __ nop(); |
| 1135 } | 1135 } |
| 1136 lazy_deopt_pc_offset_ = assembler()->CodeSize(); | 1136 lazy_deopt_pc_offset_ = assembler()->CodeSize(); |
| 1137 __ Branch(*StubCode::DeoptimizeLazy_entry()); | 1137 __ Branch(*StubCode::DeoptimizeLazy_entry()); |
| 1138 } | 1138 } |
| 1139 } | 1139 } |
| 1140 | 1140 |
| 1141 | 1141 |
| 1142 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1142 void FlowGraphCompiler::GenerateCall(TokenPosition token_pos, |
| 1143 const StubEntry& stub_entry, | 1143 const StubEntry& stub_entry, |
| 1144 RawPcDescriptors::Kind kind, | 1144 RawPcDescriptors::Kind kind, |
| 1145 LocationSummary* locs) { | 1145 LocationSummary* locs) { |
| 1146 __ BranchLinkPatchable(stub_entry); | 1146 __ BranchLinkPatchable(stub_entry); |
| 1147 AddCurrentDescriptor(kind, Thread::kNoDeoptId, token_pos); | 1147 AddCurrentDescriptor(kind, Thread::kNoDeoptId, token_pos); |
| 1148 RecordSafepoint(locs); | 1148 RecordSafepoint(locs); |
| 1149 } | 1149 } |
| 1150 | 1150 |
| 1151 | 1151 |
| 1152 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, | 1152 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, |
| 1153 intptr_t token_pos, | 1153 TokenPosition token_pos, |
| 1154 const StubEntry& stub_entry, | 1154 const StubEntry& stub_entry, |
| 1155 RawPcDescriptors::Kind kind, | 1155 RawPcDescriptors::Kind kind, |
| 1156 LocationSummary* locs) { | 1156 LocationSummary* locs) { |
| 1157 __ BranchLinkPatchable(stub_entry); | 1157 __ BranchLinkPatchable(stub_entry); |
| 1158 AddCurrentDescriptor(kind, deopt_id, token_pos); | 1158 AddCurrentDescriptor(kind, deopt_id, token_pos); |
| 1159 RecordSafepoint(locs); | 1159 RecordSafepoint(locs); |
| 1160 // Marks either the continuation point in unoptimized code or the | 1160 // Marks either the continuation point in unoptimized code or the |
| 1161 // deoptimization point in optimized code, after call. | 1161 // deoptimization point in optimized code, after call. |
| 1162 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1162 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
| 1163 if (is_optimizing()) { | 1163 if (is_optimizing()) { |
| 1164 AddDeoptIndexAtCall(deopt_id_after, token_pos); | 1164 AddDeoptIndexAtCall(deopt_id_after, token_pos); |
| 1165 } else { | 1165 } else { |
| 1166 // Add deoptimization continuation point after the call and before the | 1166 // Add deoptimization continuation point after the call and before the |
| 1167 // arguments are removed. | 1167 // arguments are removed. |
| 1168 AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 1168 AddCurrentDescriptor(RawPcDescriptors::kDeopt, |
| 1169 deopt_id_after, token_pos); | 1169 deopt_id_after, token_pos); |
| 1170 } | 1170 } |
| 1171 } | 1171 } |
| 1172 | 1172 |
| 1173 | 1173 |
| 1174 void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos, | 1174 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos, |
| 1175 intptr_t deopt_id, | 1175 intptr_t deopt_id, |
| 1176 const RuntimeEntry& entry, | 1176 const RuntimeEntry& entry, |
| 1177 intptr_t argument_count, | 1177 intptr_t argument_count, |
| 1178 LocationSummary* locs) { | 1178 LocationSummary* locs) { |
| 1179 __ CallRuntime(entry, argument_count); | 1179 __ CallRuntime(entry, argument_count); |
| 1180 AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id, token_pos); | 1180 AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id, token_pos); |
| 1181 RecordSafepoint(locs); | 1181 RecordSafepoint(locs); |
| 1182 if (deopt_id != Thread::kNoDeoptId) { | 1182 if (deopt_id != Thread::kNoDeoptId) { |
| 1183 // Marks either the continuation point in unoptimized code or the | 1183 // Marks either the continuation point in unoptimized code or the |
| 1184 // deoptimization point in optimized code, after call. | 1184 // deoptimization point in optimized code, after call. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1218 assembler_->set_use_far_branches(old_use_far_branches); | 1218 assembler_->set_use_far_branches(old_use_far_branches); |
| 1219 #endif // DEBUG | 1219 #endif // DEBUG |
| 1220 } | 1220 } |
| 1221 | 1221 |
| 1222 | 1222 |
| 1223 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1223 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
| 1224 const StubEntry& stub_entry, | 1224 const StubEntry& stub_entry, |
| 1225 const ICData& ic_data, | 1225 const ICData& ic_data, |
| 1226 intptr_t argument_count, | 1226 intptr_t argument_count, |
| 1227 intptr_t deopt_id, | 1227 intptr_t deopt_id, |
| 1228 intptr_t token_pos, | 1228 TokenPosition token_pos, |
| 1229 LocationSummary* locs) { | 1229 LocationSummary* locs) { |
| 1230 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1230 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1231 // Each ICData propagated from unoptimized to optimized code contains the | 1231 // Each ICData propagated from unoptimized to optimized code contains the |
| 1232 // function that corresponds to the Dart function of that IC call. Due | 1232 // function that corresponds to the Dart function of that IC call. Due |
| 1233 // to inlining in optimized code, that function may not correspond to the | 1233 // to inlining in optimized code, that function may not correspond to the |
| 1234 // top-level function (parsed_function().function()) which could be | 1234 // top-level function (parsed_function().function()) which could be |
| 1235 // reoptimized and which counter needs to be incremented. | 1235 // reoptimized and which counter needs to be incremented. |
| 1236 // Pass the function explicitly, it is used in IC stub. | 1236 // Pass the function explicitly, it is used in IC stub. |
| 1237 | 1237 |
| 1238 __ LoadObject(R8, parsed_function().function()); | 1238 __ LoadObject(R8, parsed_function().function()); |
| 1239 __ LoadUniqueObject(R9, ic_data); | 1239 __ LoadUniqueObject(R9, ic_data); |
| 1240 GenerateDartCall(deopt_id, | 1240 GenerateDartCall(deopt_id, |
| 1241 token_pos, | 1241 token_pos, |
| 1242 stub_entry, | 1242 stub_entry, |
| 1243 RawPcDescriptors::kIcCall, | 1243 RawPcDescriptors::kIcCall, |
| 1244 locs); | 1244 locs); |
| 1245 __ Drop(argument_count); | 1245 __ Drop(argument_count); |
| 1246 } | 1246 } |
| 1247 | 1247 |
| 1248 | 1248 |
| 1249 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, | 1249 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, |
| 1250 const ICData& ic_data, | 1250 const ICData& ic_data, |
| 1251 intptr_t argument_count, | 1251 intptr_t argument_count, |
| 1252 intptr_t deopt_id, | 1252 intptr_t deopt_id, |
| 1253 intptr_t token_pos, | 1253 TokenPosition token_pos, |
| 1254 LocationSummary* locs) { | 1254 LocationSummary* locs) { |
| 1255 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1255 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
| 1256 __ LoadUniqueObject(R9, ic_data); | 1256 __ LoadUniqueObject(R9, ic_data); |
| 1257 GenerateDartCall(deopt_id, | 1257 GenerateDartCall(deopt_id, |
| 1258 token_pos, | 1258 token_pos, |
| 1259 stub_entry, | 1259 stub_entry, |
| 1260 RawPcDescriptors::kIcCall, | 1260 RawPcDescriptors::kIcCall, |
| 1261 locs); | 1261 locs); |
| 1262 __ Drop(argument_count); | 1262 __ Drop(argument_count); |
| 1263 } | 1263 } |
| 1264 | 1264 |
| 1265 | 1265 |
| 1266 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1266 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 1267 const ICData& ic_data, | 1267 const ICData& ic_data, |
| 1268 intptr_t argument_count, | 1268 intptr_t argument_count, |
| 1269 intptr_t deopt_id, | 1269 intptr_t deopt_id, |
| 1270 intptr_t token_pos, | 1270 TokenPosition token_pos, |
| 1271 LocationSummary* locs, | 1271 LocationSummary* locs, |
| 1272 intptr_t try_index) { | 1272 intptr_t try_index) { |
| 1273 const String& name = String::Handle(zone(), ic_data.target_name()); | 1273 const String& name = String::Handle(zone(), ic_data.target_name()); |
| 1274 const Array& arguments_descriptor = | 1274 const Array& arguments_descriptor = |
| 1275 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1275 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
| 1276 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1276 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
| 1277 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(), | 1277 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(zone(), |
| 1278 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1278 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
| 1279 | 1279 |
| 1280 __ Comment("MegamorphicCall"); | 1280 __ Comment("MegamorphicCall"); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1313 deopt_id_after, token_pos); | 1313 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 __ Comment("SwitchableCall"); | 1325 __ Comment("SwitchableCall"); |
| 1326 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); | 1326 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); |
| 1327 if (ic_data.NumArgsTested() == 1) { | 1327 if (ic_data.NumArgsTested() == 1) { |
| 1328 __ LoadUniqueObject(R9, ic_data); | 1328 __ LoadUniqueObject(R9, ic_data); |
| 1329 __ BranchLinkPatchable(*StubCode::ICLookup_entry()); | 1329 __ BranchLinkPatchable(*StubCode::ICLookup_entry()); |
| 1330 } else { | 1330 } else { |
| 1331 const String& name = String::Handle(zone(), ic_data.target_name()); | 1331 const String& name = String::Handle(zone(), ic_data.target_name()); |
| 1332 const Array& arguments_descriptor = | 1332 const Array& arguments_descriptor = |
| 1333 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1333 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1352 AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 1352 AddCurrentDescriptor(RawPcDescriptors::kDeopt, |
| 1353 deopt_id_after, token_pos); | 1353 deopt_id_after, token_pos); |
| 1354 } | 1354 } |
| 1355 __ Drop(argument_count); | 1355 __ Drop(argument_count); |
| 1356 } | 1356 } |
| 1357 | 1357 |
| 1358 | 1358 |
| 1359 void FlowGraphCompiler::EmitUnoptimizedStaticCall( | 1359 void FlowGraphCompiler::EmitUnoptimizedStaticCall( |
| 1360 intptr_t argument_count, | 1360 intptr_t argument_count, |
| 1361 intptr_t deopt_id, | 1361 intptr_t deopt_id, |
| 1362 intptr_t token_pos, | 1362 TokenPosition token_pos, |
| 1363 LocationSummary* locs, | 1363 LocationSummary* locs, |
| 1364 const ICData& ic_data) { | 1364 const ICData& ic_data) { |
| 1365 const StubEntry* stub_entry = | 1365 const StubEntry* stub_entry = |
| 1366 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); | 1366 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); |
| 1367 __ LoadObject(R9, ic_data); | 1367 __ LoadObject(R9, ic_data); |
| 1368 GenerateDartCall(deopt_id, | 1368 GenerateDartCall(deopt_id, |
| 1369 token_pos, | 1369 token_pos, |
| 1370 *stub_entry, | 1370 *stub_entry, |
| 1371 RawPcDescriptors::kUnoptStaticCall, | 1371 RawPcDescriptors::kUnoptStaticCall, |
| 1372 locs); | 1372 locs); |
| 1373 __ Drop(argument_count); | 1373 __ Drop(argument_count); |
| 1374 } | 1374 } |
| 1375 | 1375 |
| 1376 | 1376 |
| 1377 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1377 void FlowGraphCompiler::EmitOptimizedStaticCall( |
| 1378 const Function& function, | 1378 const Function& function, |
| 1379 const Array& arguments_descriptor, | 1379 const Array& arguments_descriptor, |
| 1380 intptr_t argument_count, | 1380 intptr_t argument_count, |
| 1381 intptr_t deopt_id, | 1381 intptr_t deopt_id, |
| 1382 intptr_t token_pos, | 1382 TokenPosition token_pos, |
| 1383 LocationSummary* locs) { | 1383 LocationSummary* locs) { |
| 1384 __ LoadObject(R4, arguments_descriptor); | 1384 __ LoadObject(R4, arguments_descriptor); |
| 1385 // Do not use the code from the function, but let the code be patched so that | 1385 // Do not use the code from the function, but let the code be patched so that |
| 1386 // we can record the outgoing edges to other code. | 1386 // we can record the outgoing edges to other code. |
| 1387 GenerateDartCall(deopt_id, | 1387 GenerateDartCall(deopt_id, |
| 1388 token_pos, | 1388 token_pos, |
| 1389 *StubCode::CallStaticFunction_entry(), | 1389 *StubCode::CallStaticFunction_entry(), |
| 1390 RawPcDescriptors::kOther, | 1390 RawPcDescriptors::kOther, |
| 1391 locs); | 1391 locs); |
| 1392 AddStaticCallTarget(function); | 1392 AddStaticCallTarget(function); |
| 1393 __ Drop(argument_count); | 1393 __ Drop(argument_count); |
| 1394 } | 1394 } |
| 1395 | 1395 |
| 1396 | 1396 |
| 1397 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( | 1397 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( |
| 1398 Register reg, | 1398 Register reg, |
| 1399 const Object& obj, | 1399 const Object& obj, |
| 1400 bool needs_number_check, | 1400 bool needs_number_check, |
| 1401 intptr_t token_pos) { | 1401 TokenPosition token_pos) { |
| 1402 if (needs_number_check) { | 1402 if (needs_number_check) { |
| 1403 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); | 1403 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); |
| 1404 __ Push(reg); | 1404 __ Push(reg); |
| 1405 __ PushObject(obj); | 1405 __ PushObject(obj); |
| 1406 if (is_optimizing()) { | 1406 if (is_optimizing()) { |
| 1407 __ BranchLinkPatchable( | 1407 __ BranchLinkPatchable( |
| 1408 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1408 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
| 1409 } else { | 1409 } else { |
| 1410 __ BranchLinkPatchable( | 1410 __ BranchLinkPatchable( |
| 1411 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1411 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
| 1412 } | 1412 } |
| 1413 if (token_pos >= 0) { | 1413 if (token_pos.IsReal()) { |
| 1414 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1414 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, |
| 1415 Thread::kNoDeoptId, | 1415 Thread::kNoDeoptId, |
| 1416 token_pos); | 1416 token_pos); |
| 1417 } | 1417 } |
| 1418 // Stub returns result in flags (result of a cmp, we need Z computed). | 1418 // Stub returns result in flags (result of a cmp, we need Z computed). |
| 1419 __ Drop(1); // Discard constant. | 1419 __ Drop(1); // Discard constant. |
| 1420 __ Pop(reg); // Restore 'reg'. | 1420 __ Pop(reg); // Restore 'reg'. |
| 1421 } else { | 1421 } else { |
| 1422 __ CompareObject(reg, obj); | 1422 __ CompareObject(reg, obj); |
| 1423 } | 1423 } |
| 1424 return EQ; | 1424 return EQ; |
| 1425 } | 1425 } |
| 1426 | 1426 |
| 1427 | 1427 |
| 1428 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1428 Condition FlowGraphCompiler::EmitEqualityRegRegCompare( |
| 1429 Register right, | 1429 Register left, |
| 1430 bool needs_number_check, | 1430 Register right, |
| 1431 intptr_t token_pos) { | 1431 bool needs_number_check, |
| 1432 TokenPosition token_pos) { |
| 1432 if (needs_number_check) { | 1433 if (needs_number_check) { |
| 1433 __ Push(left); | 1434 __ Push(left); |
| 1434 __ Push(right); | 1435 __ Push(right); |
| 1435 if (is_optimizing()) { | 1436 if (is_optimizing()) { |
| 1436 __ BranchLinkPatchable( | 1437 __ BranchLinkPatchable( |
| 1437 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1438 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
| 1438 } else { | 1439 } else { |
| 1439 __ BranchLinkPatchable( | 1440 __ BranchLinkPatchable( |
| 1440 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1441 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
| 1441 } | 1442 } |
| 1442 if (token_pos >= 0) { | 1443 if (token_pos.IsReal()) { |
| 1443 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1444 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, |
| 1444 Thread::kNoDeoptId, | 1445 Thread::kNoDeoptId, |
| 1445 token_pos); | 1446 token_pos); |
| 1446 } | 1447 } |
| 1447 // Stub returns result in flags (result of a cmp, we need Z computed). | 1448 // Stub returns result in flags (result of a cmp, we need Z computed). |
| 1448 __ Pop(right); | 1449 __ Pop(right); |
| 1449 __ Pop(left); | 1450 __ Pop(left); |
| 1450 } else { | 1451 } else { |
| 1451 __ cmp(left, Operand(right)); | 1452 __ cmp(left, Operand(right)); |
| 1452 } | 1453 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1546 } | 1547 } |
| 1547 #endif | 1548 #endif |
| 1548 | 1549 |
| 1549 | 1550 |
| 1550 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1551 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
| 1551 intptr_t argument_count, | 1552 intptr_t argument_count, |
| 1552 const Array& argument_names, | 1553 const Array& argument_names, |
| 1553 Label* failed, | 1554 Label* failed, |
| 1554 Label* match_found, | 1555 Label* match_found, |
| 1555 intptr_t deopt_id, | 1556 intptr_t deopt_id, |
| 1556 intptr_t token_index, | 1557 TokenPosition token_index, |
| 1557 LocationSummary* locs) { | 1558 LocationSummary* locs) { |
| 1558 ASSERT(is_optimizing()); | 1559 ASSERT(is_optimizing()); |
| 1559 __ Comment("EmitTestAndCall"); | 1560 __ Comment("EmitTestAndCall"); |
| 1560 const Array& arguments_descriptor = | 1561 const Array& arguments_descriptor = |
| 1561 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, | 1562 Array::ZoneHandle(zone(), ArgumentsDescriptor::New(argument_count, |
| 1562 argument_names)); | 1563 argument_names)); |
| 1563 | 1564 |
| 1564 // Load receiver into R0. | 1565 // Load receiver into R0. |
| 1565 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); | 1566 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); |
| 1566 __ LoadObject(R4, arguments_descriptor); | 1567 __ LoadObject(R4, arguments_descriptor); |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1935 DRegister dreg = EvenDRegisterOf(reg); | 1936 DRegister dreg = EvenDRegisterOf(reg); |
| 1936 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); | 1937 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); |
| 1937 } | 1938 } |
| 1938 | 1939 |
| 1939 | 1940 |
| 1940 #undef __ | 1941 #undef __ |
| 1941 | 1942 |
| 1942 } // namespace dart | 1943 } // namespace dart |
| 1943 | 1944 |
| 1944 #endif // defined TARGET_ARCH_ARM | 1945 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |