Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: runtime/vm/flow_graph_compiler_ia32.cc

Issue 2799373002: Pass a second type argument vector to all type instantiation calls in the VM. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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, &not_smi, Assembler::kNearJump); 480 __ j(NOT_ZERO, &not_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(&not_smi); 489 __ Bind(&not_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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698