Chromium Code Reviews| 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 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 200 __ j(EQUAL, is_true); | 200 __ j(EQUAL, is_true); |
| 201 __ jmp(is_false); | 201 __ jmp(is_false); |
| 202 __ Bind(&fall_through); | 202 __ Bind(&fall_through); |
| 203 } | 203 } |
| 204 | 204 |
| 205 | 205 |
| 206 // Clobbers ECX. | 206 // Clobbers ECX. |
| 207 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 207 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 208 TypeTestStubKind test_kind, | 208 TypeTestStubKind test_kind, |
| 209 Register instance_reg, | 209 Register instance_reg, |
| 210 Register type_arguments_reg, | 210 Register instantiator_type_arguments_reg, |
| 211 Register function_type_arguments_reg, | |
| 211 Register temp_reg, | 212 Register temp_reg, |
| 212 Label* is_instance_lbl, | 213 Label* is_instance_lbl, |
| 213 Label* is_not_instance_lbl) { | 214 Label* is_not_instance_lbl) { |
| 214 const SubtypeTestCache& type_test_cache = | 215 const SubtypeTestCache& type_test_cache = |
| 215 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); | 216 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
| 216 const Immediate& raw_null = | 217 const Immediate& raw_null = |
| 217 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 218 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 218 __ LoadObject(temp_reg, type_test_cache); | 219 __ LoadObject(temp_reg, type_test_cache); |
| 219 __ pushl(temp_reg); // Subtype test cache. | 220 __ pushl(temp_reg); // Subtype test cache. |
| 220 __ pushl(instance_reg); // Instance. | 221 __ pushl(instance_reg); // Instance. |
| 221 if (test_kind == kTestTypeOneArg) { | 222 if (test_kind == kTestTypeOneArg) { |
| 222 ASSERT(type_arguments_reg == kNoRegister); | 223 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
| 224 ASSERT(function_type_arguments_reg == kNoRegister); | |
| 225 __ pushl(raw_null); | |
| 223 __ pushl(raw_null); | 226 __ pushl(raw_null); |
| 224 __ Call(*StubCode::Subtype1TestCache_entry()); | 227 __ Call(*StubCode::Subtype1TestCache_entry()); |
| 225 } else if (test_kind == kTestTypeTwoArgs) { | 228 } else if (test_kind == kTestTypeTwoArgs) { |
| 226 ASSERT(type_arguments_reg == kNoRegister); | 229 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
| 230 ASSERT(function_type_arguments_reg == kNoRegister); | |
| 231 __ pushl(raw_null); | |
| 227 __ pushl(raw_null); | 232 __ pushl(raw_null); |
| 228 __ Call(*StubCode::Subtype2TestCache_entry()); | 233 __ Call(*StubCode::Subtype2TestCache_entry()); |
| 229 } else if (test_kind == kTestTypeThreeArgs) { | 234 } else if (test_kind == kTestTypeFourArgs) { |
| 230 __ pushl(type_arguments_reg); | 235 __ pushl(instantiator_type_arguments_reg); |
| 231 __ Call(*StubCode::Subtype3TestCache_entry()); | 236 __ pushl(function_type_arguments_reg); |
| 237 __ Call(*StubCode::Subtype4TestCache_entry()); | |
| 232 } else { | 238 } else { |
| 233 UNREACHABLE(); | 239 UNREACHABLE(); |
| 234 } | 240 } |
| 235 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. | 241 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 236 ASSERT(instance_reg != ECX); | 242 ASSERT(instance_reg != ECX); |
| 237 ASSERT(temp_reg != ECX); | 243 ASSERT(temp_reg != ECX); |
| 238 __ popl(instance_reg); // Discard. | 244 __ popl(instance_reg); // Discard. |
| 245 __ popl(instance_reg); // Discard. | |
| 239 __ popl(instance_reg); // Restore receiver. | 246 __ popl(instance_reg); // Restore receiver. |
| 240 __ popl(temp_reg); // Discard. | 247 __ popl(temp_reg); // Discard. |
|
siva
2017/04/10 22:04:55
Does it make sense to use
__ Drop(4, temp_reg);
he
regis
2017/04/11 04:23:08
Per the comments, we need to restore the receiver.
| |
| 241 GenerateBoolToJump(ECX, is_instance_lbl, is_not_instance_lbl); | 248 GenerateBoolToJump(ECX, is_instance_lbl, is_not_instance_lbl); |
| 242 return type_test_cache.raw(); | 249 return type_test_cache.raw(); |
| 243 } | 250 } |
| 244 | 251 |
| 245 | 252 |
| 246 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 253 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 247 // type test is conclusive, otherwise fallthrough if a type test could not | 254 // type test is conclusive, otherwise fallthrough if a type test could not |
| 248 // be completed. | 255 // be completed. |
| 249 // EAX: instance (must survive). | 256 // EAX: instance (must survive). |
| 250 // Clobbers ECX, EDI. | 257 // Clobbers ECX, EDI. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 304 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 311 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
| 305 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 312 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
| 306 // Instance class test only necessary. | 313 // Instance class test only necessary. |
| 307 return GenerateSubtype1TestCacheLookup( | 314 return GenerateSubtype1TestCacheLookup( |
| 308 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 315 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 309 } | 316 } |
| 310 } | 317 } |
| 311 } | 318 } |
| 312 } | 319 } |
| 313 // Regular subtype test cache involving instance's type arguments. | 320 // Regular subtype test cache involving instance's type arguments. |
| 314 const Register kTypeArgumentsReg = kNoRegister; | 321 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 322 const Register kFunctionTypeArgumentsReg = kNoRegister; | |
| 315 const Register kTempReg = EDI; | 323 const Register kTempReg = EDI; |
| 316 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, | 324 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
| 317 kTypeArgumentsReg, kTempReg, | 325 kInstantiatorTypeArgumentsReg, |
| 326 kFunctionTypeArgumentsReg, kTempReg, | |
| 318 is_instance_lbl, is_not_instance_lbl); | 327 is_instance_lbl, is_not_instance_lbl); |
| 319 } | 328 } |
| 320 | 329 |
| 321 | 330 |
| 322 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 331 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
| 323 const GrowableArray<intptr_t>& class_ids, | 332 const GrowableArray<intptr_t>& class_ids, |
| 324 Label* is_equal_lbl, | 333 Label* is_equal_lbl, |
| 325 Label* is_not_equal_lbl) { | 334 Label* is_not_equal_lbl) { |
| 326 for (intptr_t i = 0; i < class_ids.length(); i++) { | 335 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 327 __ cmpl(class_id_reg, Immediate(class_ids[i])); | 336 __ cmpl(class_id_reg, Immediate(class_ids[i])); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 414 __ Comment("Subtype1TestCacheLookup"); | 423 __ Comment("Subtype1TestCacheLookup"); |
| 415 const Register kInstanceReg = EAX; | 424 const Register kInstanceReg = EAX; |
| 416 __ LoadClass(ECX, kInstanceReg, EDI); | 425 __ LoadClass(ECX, kInstanceReg, EDI); |
| 417 // ECX: instance class. | 426 // ECX: instance class. |
| 418 // Check immediate superclass equality. | 427 // Check immediate superclass equality. |
| 419 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 428 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
| 420 __ movl(EDI, FieldAddress(EDI, Type::type_class_id_offset())); | 429 __ movl(EDI, FieldAddress(EDI, Type::type_class_id_offset())); |
| 421 __ cmpl(EDI, Immediate(Smi::RawValue(type_class.id()))); | 430 __ cmpl(EDI, Immediate(Smi::RawValue(type_class.id()))); |
| 422 __ j(EQUAL, is_instance_lbl); | 431 __ j(EQUAL, is_instance_lbl); |
| 423 | 432 |
| 424 const Register kTypeArgumentsReg = kNoRegister; | 433 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 434 const Register kFunctionTypeArgumentsReg = kNoRegister; | |
| 425 const Register kTempReg = EDI; | 435 const Register kTempReg = EDI; |
| 426 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, | 436 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
| 427 kTypeArgumentsReg, kTempReg, | 437 kInstantiatorTypeArgumentsReg, |
| 438 kFunctionTypeArgumentsReg, kTempReg, | |
| 428 is_instance_lbl, is_not_instance_lbl); | 439 is_instance_lbl, is_not_instance_lbl); |
| 429 } | 440 } |
| 430 | 441 |
| 431 | 442 |
| 432 // Generates inlined check if 'type' is a type parameter or type itself | 443 // Generates inlined check if 'type' is a type parameter or type itself |
| 433 // EAX: instance (preserved). | 444 // EAX: instance (preserved). |
| 434 // Clobbers EDX, EDI, ECX. | 445 // Clobbers EDX, EDI, ECX. |
| 435 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 446 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 436 TokenPosition token_pos, | 447 TokenPosition token_pos, |
| 437 const AbstractType& type, | 448 const AbstractType& type, |
| 438 Label* is_instance_lbl, | 449 Label* is_instance_lbl, |
| 439 Label* is_not_instance_lbl) { | 450 Label* is_not_instance_lbl) { |
| 440 __ Comment("UninstantiatedTypeTest"); | 451 __ Comment("UninstantiatedTypeTest"); |
| 441 ASSERT(!type.IsInstantiated()); | 452 ASSERT(!type.IsInstantiated()); |
| 442 // Skip check if destination is a dynamic type. | 453 // Skip check if destination is a dynamic type. |
| 443 const Immediate& raw_null = | 454 const Immediate& raw_null = |
| 444 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 455 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 445 if (type.IsTypeParameter()) { | 456 if (type.IsTypeParameter()) { |
| 446 const TypeParameter& type_param = TypeParameter::Cast(type); | 457 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 447 // Load instantiator type arguments on stack. | 458 __ movl(EDX, Address(ESP, 1 * kWordSize)); // Get instantiator type args. |
| 448 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 459 __ movl(ECX, Address(ESP, 0 * kWordSize)); // Get function type args. |
| 449 // EDX: instantiator type arguments. | 460 // EDX: instantiator type arguments. |
| 461 // ECX: function type arguments. | |
| 462 const Register kTypeArgumentsReg = | |
| 463 type_param.IsClassTypeParameter() ? EDX : ECX; | |
| 450 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 464 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 451 __ cmpl(EDX, raw_null); | 465 __ cmpl(kTypeArgumentsReg, raw_null); |
| 452 __ j(EQUAL, is_instance_lbl); | 466 __ j(EQUAL, is_instance_lbl); |
| 453 __ movl(EDI, FieldAddress( | 467 __ movl(EDI, FieldAddress(kTypeArgumentsReg, TypeArguments::type_at_offset( |
| 454 EDX, TypeArguments::type_at_offset(type_param.index()))); | 468 type_param.index()))); |
| 455 // EDI: concrete type of type. | 469 // EDI: concrete type of type. |
| 456 // Check if type argument is dynamic. | 470 // Check if type argument is dynamic. |
| 457 __ CompareObject(EDI, Object::dynamic_type()); | 471 __ CompareObject(EDI, Object::dynamic_type()); |
| 458 __ j(EQUAL, is_instance_lbl); | 472 __ j(EQUAL, is_instance_lbl); |
| 459 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::ObjectType())); | 473 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::ObjectType())); |
| 460 __ j(EQUAL, is_instance_lbl); | 474 __ j(EQUAL, is_instance_lbl); |
| 475 // TODO(regis): Optimize void type as well once allowed as type argument. | |
| 461 | 476 |
| 462 // For Smi check quickly against int and num interfaces. | 477 // For Smi check quickly against int and num interfaces. |
| 463 Label not_smi; | 478 Label not_smi; |
| 464 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? | 479 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 465 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 480 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 466 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::IntType())); | 481 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::IntType())); |
| 467 __ j(EQUAL, is_instance_lbl); | 482 __ j(EQUAL, is_instance_lbl); |
| 468 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::Number())); | 483 __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::Number())); |
| 469 __ j(EQUAL, is_instance_lbl); | 484 __ j(EQUAL, is_instance_lbl); |
| 470 // Smi must be handled in runtime. | 485 // Smi must be handled in runtime. |
| 471 Label fall_through; | 486 Label fall_through; |
| 472 __ jmp(&fall_through); | 487 __ jmp(&fall_through); |
| 473 | 488 |
| 474 __ Bind(¬_smi); | 489 __ Bind(¬_smi); |
| 475 // EDX: instantiator type arguments. | 490 // EDX: instantiator type arguments. |
| 491 // ECX: function type arguments. | |
| 476 // EAX: instance. | 492 // EAX: instance. |
| 477 const Register kInstanceReg = EAX; | 493 const Register kInstanceReg = EAX; |
| 478 const Register kTypeArgumentsReg = EDX; | 494 const Register kInstantiatorTypeArgumentsReg = EDX; |
| 495 const Register kFunctionTypeArgumentsReg = ECX; | |
| 479 const Register kTempReg = EDI; | 496 const Register kTempReg = EDI; |
| 480 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( | 497 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
| 481 zone(), GenerateCallSubtypeTestStub( | 498 zone(), GenerateCallSubtypeTestStub( |
| 482 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, | 499 kTestTypeFourArgs, kInstanceReg, |
| 500 kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, | |
| 483 kTempReg, is_instance_lbl, is_not_instance_lbl)); | 501 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
| 484 __ Bind(&fall_through); | 502 __ Bind(&fall_through); |
| 485 return type_test_cache.raw(); | 503 return type_test_cache.raw(); |
| 486 } | 504 } |
| 487 if (type.IsType()) { | 505 if (type.IsType()) { |
| 488 const Register kInstanceReg = EAX; | 506 const Register kInstanceReg = EAX; |
| 489 const Register kTypeArgumentsReg = EDX; | 507 const Register kInstantiatorTypeArgumentsReg = EDX; |
| 508 const Register kFunctionTypeArgumentsReg = ECX; | |
| 490 __ testl(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? | 509 __ testl(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? |
| 491 __ j(ZERO, is_not_instance_lbl); | 510 __ j(ZERO, is_not_instance_lbl); |
| 492 __ movl(kTypeArgumentsReg, Address(ESP, 0)); // Instantiator type args. | 511 __ movl(kInstantiatorTypeArgumentsReg, Address(ESP, 1 * kWordSize)); |
| 512 __ movl(kFunctionTypeArgumentsReg, Address(ESP, 0 * kWordSize)); | |
| 493 // Uninstantiated type class is known at compile time, but the type | 513 // Uninstantiated type class is known at compile time, but the type |
| 494 // arguments are determined at runtime by the instantiator. | 514 // arguments are determined at runtime by the instantiator(s). |
| 495 const Register kTempReg = EDI; | 515 const Register kTempReg = EDI; |
| 496 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, | 516 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, |
| 497 kTypeArgumentsReg, kTempReg, | 517 kInstantiatorTypeArgumentsReg, |
| 518 kFunctionTypeArgumentsReg, kTempReg, | |
| 498 is_instance_lbl, is_not_instance_lbl); | 519 is_instance_lbl, is_not_instance_lbl); |
| 499 } | 520 } |
| 500 return SubtypeTestCache::null(); | 521 return SubtypeTestCache::null(); |
| 501 } | 522 } |
| 502 | 523 |
| 503 | 524 |
| 504 // Inputs: | 525 // Inputs: |
| 505 // - EAX: instance to test against (preserved). | 526 // - EAX: instance to test against (preserved). |
| 506 // - EDX: optional instantiator type arguments (preserved). | 527 // - EDX: optional instantiator type arguments (preserved). |
| 507 // Clobbers ECX, EDI. | 528 // - ECX: optional function type arguments (preserved). |
| 529 // Clobbers EDI. | |
| 508 // Returns: | 530 // Returns: |
| 509 // - preserved instance in EAX and optional instantiator type arguments in EDX. | 531 // - preserved instance in EAX, optional instantiator type arguments in EDX, and |
| 532 // optional function type arguments in RCX. | |
| 510 // Note that this inlined code must be followed by the runtime_call code, as it | 533 // Note that this inlined code must be followed by the runtime_call code, as it |
| 511 // may fall through to it. Otherwise, this inline code will jump to the label | 534 // may fall through to it. Otherwise, this inline code will jump to the label |
| 512 // is_instance or to the label is_not_instance. | 535 // is_instance or to the label is_not_instance. |
| 513 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 536 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
| 514 TokenPosition token_pos, | 537 TokenPosition token_pos, |
| 515 const AbstractType& type, | 538 const AbstractType& type, |
| 516 Label* is_instance_lbl, | 539 Label* is_instance_lbl, |
| 517 Label* is_not_instance_lbl) { | 540 Label* is_not_instance_lbl) { |
| 518 __ Comment("InlineInstanceof"); | 541 __ Comment("InlineInstanceof"); |
| 519 if (type.IsVoidType()) { | 542 if (type.IsVoidType()) { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 548 | 571 |
| 549 | 572 |
| 550 // If instanceof type test cannot be performed successfully at compile time and | 573 // If instanceof type test cannot be performed successfully at compile time and |
| 551 // therefore eliminated, optimize it by adding inlined tests for: | 574 // therefore eliminated, optimize it by adding inlined tests for: |
| 552 // - NULL -> return type == Null (type is not Object or dynamic). | 575 // - NULL -> return type == Null (type is not Object or dynamic). |
| 553 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 576 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 554 // - Class equality (only if class is not parameterized). | 577 // - Class equality (only if class is not parameterized). |
| 555 // Inputs: | 578 // Inputs: |
| 556 // - EAX: object. | 579 // - EAX: object. |
| 557 // - EDX: instantiator type arguments or raw_null. | 580 // - EDX: instantiator type arguments or raw_null. |
| 558 // Clobbers EDX. | 581 // - ECX: function type arguments or raw_null. |
| 559 // Returns: | 582 // Returns: |
| 560 // - true or false in EAX. | 583 // - true or false in EAX. |
| 561 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, | 584 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
| 562 intptr_t deopt_id, | 585 intptr_t deopt_id, |
| 563 const AbstractType& type, | 586 const AbstractType& type, |
| 564 LocationSummary* locs) { | 587 LocationSummary* locs) { |
| 565 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 588 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
| 566 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); | 589 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); |
| 567 | 590 |
| 591 __ pushl(EDX); // Store instantiator type arguments. | |
| 592 __ pushl(ECX); // Store function type arguments. | |
| 593 | |
| 568 const Immediate& raw_null = | 594 const Immediate& raw_null = |
| 569 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 595 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 570 Label is_instance, is_not_instance; | 596 Label is_instance, is_not_instance; |
| 571 __ pushl(EDX); // Store instantiator type arguments. | |
| 572 // If type is instantiated and non-parameterized, we can inline code | 597 // If type is instantiated and non-parameterized, we can inline code |
| 573 // checking whether the tested instance is a Smi. | 598 // checking whether the tested instance is a Smi. |
| 574 if (type.IsInstantiated()) { | 599 if (type.IsInstantiated()) { |
| 575 // A null object is only an instance of Null, Object, and dynamic. | 600 // A null object is only an instance of Null, Object, and dynamic. |
| 576 // Object and dynamic have already been checked above (if the type is | 601 // Object and dynamic have already been checked above (if the type is |
| 577 // instantiated). So we can return false here if the instance is null, | 602 // instantiated). So we can return false here if the instance is null, |
| 578 // unless the type is Null (and if the type is instantiated). | 603 // unless the type is Null (and if the type is instantiated). |
| 579 // We can only inline this null check if the type is instantiated at compile | 604 // We can only inline this null check if the type is instantiated at compile |
| 580 // time, since an uninstantiated type at compile time could be Null, Object, | 605 // time, since an uninstantiated type at compile time could be Null, Object, |
| 581 // or dynamic at run time. | 606 // or dynamic at run time. |
| 582 __ cmpl(EAX, raw_null); | 607 __ cmpl(EAX, raw_null); |
| 583 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); | 608 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); |
| 584 } | 609 } |
| 585 | 610 |
| 586 // Generate inline instanceof test. | 611 // Generate inline instanceof test. |
| 587 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 612 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 588 test_cache = | 613 test_cache = |
| 589 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); | 614 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
| 590 | 615 |
| 591 // test_cache is null if there is no fall-through. | 616 // test_cache is null if there is no fall-through. |
| 592 Label done; | 617 Label done; |
| 593 if (!test_cache.IsNull()) { | 618 if (!test_cache.IsNull()) { |
| 594 // Generate runtime call. | 619 // Generate runtime call. |
| 595 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 620 __ movl(EDX, Address(ESP, 1 * kWordSize)); // Get instantiator type args. |
| 621 __ movl(ECX, Address(ESP, 0 * kWordSize)); // Get function type args. | |
| 596 __ PushObject(Object::null_object()); // Make room for the result. | 622 __ PushObject(Object::null_object()); // Make room for the result. |
| 597 __ pushl(EAX); // Push the instance. | 623 __ pushl(EAX); // Push the instance. |
| 598 __ PushObject(type); // Push the type. | 624 __ PushObject(type); // Push the type. |
| 599 __ pushl(EDX); // Instantiator type arguments. | 625 __ pushl(EDX); // Instantiator type arguments. |
| 626 __ pushl(ECX); // Function type arguments. | |
| 600 __ LoadObject(EAX, test_cache); | 627 __ LoadObject(EAX, test_cache); |
| 601 __ pushl(EAX); | 628 __ pushl(EAX); |
| 602 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); | 629 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); |
| 603 // Pop the parameters supplied to the runtime entry. The result of the | 630 // Pop the parameters supplied to the runtime entry. The result of the |
| 604 // instanceof runtime call will be left as the result of the operation. | 631 // instanceof runtime call will be left as the result of the operation. |
| 605 __ Drop(4); | 632 __ Drop(5); |
| 606 __ popl(EAX); | 633 __ popl(EAX); |
| 607 __ jmp(&done, Assembler::kNearJump); | 634 __ jmp(&done, Assembler::kNearJump); |
| 608 } | 635 } |
| 609 __ Bind(&is_not_instance); | 636 __ Bind(&is_not_instance); |
| 610 __ LoadObject(EAX, Bool::Get(false)); | 637 __ LoadObject(EAX, Bool::Get(false)); |
| 611 __ jmp(&done, Assembler::kNearJump); | 638 __ jmp(&done, Assembler::kNearJump); |
| 612 | 639 |
| 613 __ Bind(&is_instance); | 640 __ Bind(&is_instance); |
| 614 __ LoadObject(EAX, Bool::Get(true)); | 641 __ LoadObject(EAX, Bool::Get(true)); |
| 615 __ Bind(&done); | 642 __ Bind(&done); |
| 643 __ popl(ECX); // Remove pushed function type arguments. | |
| 616 __ popl(EDX); // Remove pushed instantiator type arguments. | 644 __ popl(EDX); // Remove pushed instantiator type arguments. |
| 617 } | 645 } |
| 618 | 646 |
| 619 | 647 |
| 620 // Optimize assignable type check by adding inlined tests for: | 648 // Optimize assignable type check by adding inlined tests for: |
| 621 // - NULL -> return NULL. | 649 // - NULL -> return NULL. |
| 622 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 650 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 623 // - Class equality (only if class is not parameterized). | 651 // - Class equality (only if class is not parameterized). |
| 624 // Inputs: | 652 // Inputs: |
| 625 // - EAX: object. | 653 // - EAX: object. |
| 626 // - EDX: instantiator type arguments or raw_null. | 654 // - EDX: instantiator type arguments or raw_null. |
| 655 // - ECX: function type arguments or raw_null. | |
| 627 // Returns: | 656 // Returns: |
| 628 // - object in EAX for successful assignable check (or throws TypeError). | 657 // - object in EAX for successful assignable check (or throws TypeError). |
| 629 // Performance notes: positive checks must be quick, negative checks can be slow | 658 // Performance notes: positive checks must be quick, negative checks can be slow |
| 630 // as they throw an exception. | 659 // as they throw an exception. |
| 631 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, | 660 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
| 632 intptr_t deopt_id, | 661 intptr_t deopt_id, |
| 633 const AbstractType& dst_type, | 662 const AbstractType& dst_type, |
| 634 const String& dst_name, | 663 const String& dst_name, |
| 635 LocationSummary* locs) { | 664 LocationSummary* locs) { |
| 636 ASSERT(!token_pos.IsClassifying()); | 665 ASSERT(!token_pos.IsClassifying()); |
| 637 ASSERT(!dst_type.IsNull()); | 666 ASSERT(!dst_type.IsNull()); |
| 638 ASSERT(dst_type.IsFinalized()); | 667 ASSERT(dst_type.IsFinalized()); |
| 639 // Assignable check is skipped in FlowGraphBuilder, not here. | 668 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 640 ASSERT(dst_type.IsMalformedOrMalbounded() || | 669 ASSERT(dst_type.IsMalformedOrMalbounded() || |
| 641 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 670 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 642 __ pushl(EDX); // Store instantiator type arguments. | 671 __ pushl(EDX); // Store instantiator type arguments. |
| 672 __ pushl(ECX); // Store function type arguments. | |
| 643 // A null object is always assignable and is returned as result. | 673 // A null object is always assignable and is returned as result. |
| 644 const Immediate& raw_null = | 674 const Immediate& raw_null = |
| 645 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 675 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 646 Label is_assignable, runtime_call; | 676 Label is_assignable, runtime_call; |
| 647 __ cmpl(EAX, raw_null); | 677 __ cmpl(EAX, raw_null); |
| 648 __ j(EQUAL, &is_assignable); | 678 __ j(EQUAL, &is_assignable); |
| 649 | 679 |
| 650 // Generate throw new TypeError() if the type is malformed or malbounded. | 680 // Generate throw new TypeError() if the type is malformed or malbounded. |
| 651 if (dst_type.IsMalformedOrMalbounded()) { | 681 if (dst_type.IsMalformedOrMalbounded()) { |
| 652 __ PushObject(Object::null_object()); // Make room for the result. | 682 __ PushObject(Object::null_object()); // Make room for the result. |
| 653 __ pushl(EAX); // Push the source object. | 683 __ pushl(EAX); // Push the source object. |
| 654 __ PushObject(dst_name); // Push the name of the destination. | 684 __ PushObject(dst_name); // Push the name of the destination. |
| 655 __ PushObject(dst_type); // Push the type of the destination. | 685 __ PushObject(dst_type); // Push the type of the destination. |
| 656 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, | 686 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
| 657 locs); | 687 locs); |
| 658 // We should never return here. | 688 // We should never return here. |
| 659 __ int3(); | 689 __ int3(); |
| 660 | 690 |
| 661 __ Bind(&is_assignable); // For a null object. | 691 __ Bind(&is_assignable); // For a null object. |
| 692 __ popl(ECX); // Remove pushed function type arguments. | |
| 662 __ popl(EDX); // Remove pushed instantiator type arguments. | 693 __ popl(EDX); // Remove pushed instantiator type arguments. |
| 663 return; | 694 return; |
| 664 } | 695 } |
| 665 | 696 |
| 666 // Generate inline type check, linking to runtime call if not assignable. | 697 // Generate inline type check, linking to runtime call if not assignable. |
| 667 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 698 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 668 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, | 699 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
| 669 &runtime_call); | 700 &runtime_call); |
| 670 | 701 |
| 671 __ Bind(&runtime_call); | 702 __ Bind(&runtime_call); |
| 672 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 703 __ movl(EDX, Address(ESP, 1 * kWordSize)); // Get instantiator type args. |
| 704 __ movl(ECX, Address(ESP, 0 * kWordSize)); // Get function type args. | |
| 673 __ PushObject(Object::null_object()); // Make room for the result. | 705 __ PushObject(Object::null_object()); // Make room for the result. |
| 674 __ pushl(EAX); // Push the source object. | 706 __ pushl(EAX); // Push the source object. |
| 675 __ PushObject(dst_type); // Push the type of the destination. | 707 __ PushObject(dst_type); // Push the type of the destination. |
| 676 __ pushl(EDX); // Instantiator type arguments. | 708 __ pushl(EDX); // Instantiator type arguments. |
| 709 __ pushl(ECX); // Function type arguments. | |
| 677 __ PushObject(dst_name); // Push the name of the destination. | 710 __ PushObject(dst_name); // Push the name of the destination. |
| 678 __ LoadObject(EAX, test_cache); | 711 __ LoadObject(EAX, test_cache); |
| 679 __ pushl(EAX); | 712 __ pushl(EAX); |
| 680 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 713 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
| 681 // Pop the parameters supplied to the runtime entry. The result of the | 714 // Pop the parameters supplied to the runtime entry. The result of the |
| 682 // type check runtime call is the checked value. | 715 // type check runtime call is the checked value. |
| 683 __ Drop(5); | 716 __ Drop(6); |
| 684 __ popl(EAX); | 717 __ popl(EAX); |
| 685 | 718 |
| 686 __ Bind(&is_assignable); | 719 __ Bind(&is_assignable); |
| 720 __ popl(ECX); // Remove pushed function type arguments. | |
| 687 __ popl(EDX); // Remove pushed instantiator type arguments. | 721 __ popl(EDX); // Remove pushed instantiator type arguments. |
| 688 } | 722 } |
| 689 | 723 |
| 690 | 724 |
| 691 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 725 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
| 692 if (is_optimizing()) { | 726 if (is_optimizing()) { |
| 693 return; | 727 return; |
| 694 } | 728 } |
| 695 Definition* defn = instr->AsDefinition(); | 729 Definition* defn = instr->AsDefinition(); |
| 696 if ((defn != NULL) && defn->HasTemp()) { | 730 if ((defn != NULL) && defn->HasTemp()) { |
| (...skipping 1070 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1767 __ movups(reg, Address(ESP, 0)); | 1801 __ movups(reg, Address(ESP, 0)); |
| 1768 __ addl(ESP, Immediate(kFpuRegisterSize)); | 1802 __ addl(ESP, Immediate(kFpuRegisterSize)); |
| 1769 } | 1803 } |
| 1770 | 1804 |
| 1771 | 1805 |
| 1772 #undef __ | 1806 #undef __ |
| 1773 | 1807 |
| 1774 } // namespace dart | 1808 } // namespace dart |
| 1775 | 1809 |
| 1776 #endif // defined TARGET_ARCH_IA32 | 1810 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |