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

Side by Side Diff: runtime/vm/flow_graph_compiler_mips.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_MIPS. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS.
6 #if defined(TARGET_ARCH_MIPS) 6 #if defined(TARGET_ARCH_MIPS)
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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 Label fall_through; 194 Label fall_through;
195 __ BranchEqual(bool_register, Object::null_object(), &fall_through); 195 __ BranchEqual(bool_register, Object::null_object(), &fall_through);
196 __ BranchEqual(bool_register, Bool::True(), is_true); 196 __ BranchEqual(bool_register, Bool::True(), is_true);
197 __ b(is_false); 197 __ b(is_false);
198 __ Bind(&fall_through); 198 __ Bind(&fall_through);
199 } 199 }
200 200
201 201
202 // A0: instance (must be preserved). 202 // A0: instance (must be preserved).
203 // A1: instantiator type arguments (if used). 203 // A1: instantiator type arguments (if used).
204 // A2: function type arguments (if used).
siva 2017/04/10 22:04:55 doesn't seem to document that A3 is clobbered, I s
regis 2017/04/11 04:23:08 Added. I do not think that these comments are all
204 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( 205 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
205 TypeTestStubKind test_kind, 206 TypeTestStubKind test_kind,
206 Register instance_reg, 207 Register instance_reg,
207 Register type_arguments_reg, 208 Register instantiator_type_arguments_reg,
209 Register function_type_arguments_reg,
208 Register temp_reg, 210 Register temp_reg,
209 Label* is_instance_lbl, 211 Label* is_instance_lbl,
210 Label* is_not_instance_lbl) { 212 Label* is_not_instance_lbl) {
211 __ Comment("CallSubtypeTestStub"); 213 __ Comment("CallSubtypeTestStub");
212 ASSERT(instance_reg == A0); 214 ASSERT(instance_reg == A0);
213 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. 215 ASSERT(temp_reg == kNoRegister); // Unused on MIPS.
214 const SubtypeTestCache& type_test_cache = 216 const SubtypeTestCache& type_test_cache =
215 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); 217 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
216 __ LoadUniqueObject(A2, type_test_cache); 218 __ LoadUniqueObject(A3, type_test_cache);
217 if (test_kind == kTestTypeOneArg) { 219 if (test_kind == kTestTypeOneArg) {
218 ASSERT(type_arguments_reg == kNoRegister); 220 ASSERT(instantiator_type_arguments_reg == kNoRegister);
219 __ LoadObject(A1, Object::null_object()); 221 ASSERT(function_type_arguments_reg == kNoRegister);
220 __ BranchLink(*StubCode::Subtype1TestCache_entry()); 222 __ BranchLink(*StubCode::Subtype1TestCache_entry());
221 } else if (test_kind == kTestTypeTwoArgs) { 223 } else if (test_kind == kTestTypeTwoArgs) {
222 ASSERT(type_arguments_reg == kNoRegister); 224 ASSERT(instantiator_type_arguments_reg == kNoRegister);
223 __ LoadObject(A1, Object::null_object()); 225 ASSERT(function_type_arguments_reg == kNoRegister);
224 __ BranchLink(*StubCode::Subtype2TestCache_entry()); 226 __ BranchLink(*StubCode::Subtype2TestCache_entry());
225 } else if (test_kind == kTestTypeThreeArgs) { 227 } else if (test_kind == kTestTypeFourArgs) {
226 ASSERT(type_arguments_reg == A1); 228 ASSERT(instantiator_type_arguments_reg == A1);
227 __ BranchLink(*StubCode::Subtype3TestCache_entry()); 229 ASSERT(function_type_arguments_reg == A2);
230 __ BranchLink(*StubCode::Subtype4TestCache_entry());
228 } else { 231 } else {
229 UNREACHABLE(); 232 UNREACHABLE();
230 } 233 }
231 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False. 234 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False.
232 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl); 235 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl);
233 return type_test_cache.raw(); 236 return type_test_cache.raw();
234 } 237 }
235 238
236 239
237 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 240 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); 297 const Type& object_type = Type::Handle(zone(), Type::ObjectType());
295 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { 298 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) {
296 // Instance class test only necessary. 299 // Instance class test only necessary.
297 return GenerateSubtype1TestCacheLookup( 300 return GenerateSubtype1TestCacheLookup(
298 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); 301 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
299 } 302 }
300 } 303 }
301 } 304 }
302 } 305 }
303 // Regular subtype test cache involving instance's type arguments. 306 // Regular subtype test cache involving instance's type arguments.
304 const Register kTypeArgumentsReg = kNoRegister; 307 const Register kInstantiatorTypeArgumentsReg = kNoRegister;
308 const Register kFunctionTypeArgumentsReg = kNoRegister;
305 const Register kTempReg = kNoRegister; 309 const Register kTempReg = kNoRegister;
306 // A0: instance (must be preserved). 310 // A0: instance (must be preserved).
307 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, 311 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg,
308 kTypeArgumentsReg, kTempReg, 312 kInstantiatorTypeArgumentsReg,
313 kFunctionTypeArgumentsReg, kTempReg,
309 is_instance_lbl, is_not_instance_lbl); 314 is_instance_lbl, is_not_instance_lbl);
310 } 315 }
311 316
312 317
313 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, 318 void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
314 const GrowableArray<intptr_t>& class_ids, 319 const GrowableArray<intptr_t>& class_ids,
315 Label* is_equal_lbl, 320 Label* is_equal_lbl,
316 Label* is_not_equal_lbl) { 321 Label* is_not_equal_lbl) {
317 __ Comment("CheckClassIds"); 322 __ Comment("CheckClassIds");
318 for (intptr_t i = 0; i < class_ids.length(); i++) { 323 for (intptr_t i = 0; i < class_ids.length(); i++) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 if (!type_class.is_abstract()) { 387 if (!type_class.is_abstract()) {
383 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl); 388 __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl);
384 } 389 }
385 // Otherwise fallthrough. 390 // Otherwise fallthrough.
386 return true; 391 return true;
387 } 392 }
388 393
389 394
390 // Uses SubtypeTestCache to store instance class and result. 395 // Uses SubtypeTestCache to store instance class and result.
391 // A0: instance to test. 396 // A0: instance to test.
392 // Clobbers A1, A2, T0-T3. 397 // Clobbers A1-A3, T0-T3.
393 // Immediate class test already done. 398 // Immediate class test already done.
394 // TODO(srdjan): Implement a quicker subtype check, as type test 399 // TODO(srdjan): Implement a quicker subtype check, as type test
395 // arrays can grow too high, but they may be useful when optimizing 400 // arrays can grow too high, but they may be useful when optimizing
396 // code (type-feedback). 401 // code (type-feedback).
397 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 402 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
398 TokenPosition token_pos, 403 TokenPosition token_pos,
399 const Class& type_class, 404 const Class& type_class,
400 Label* is_instance_lbl, 405 Label* is_instance_lbl,
401 Label* is_not_instance_lbl) { 406 Label* is_not_instance_lbl) {
402 __ Comment("Subtype1TestCacheLookup"); 407 __ Comment("Subtype1TestCacheLookup");
403 const Register kInstanceReg = A0; 408 const Register kInstanceReg = A0;
404 __ LoadClass(T0, kInstanceReg); 409 __ LoadClass(T0, kInstanceReg);
405 // T0: instance class. 410 // T0: instance class.
406 // Check immediate superclass equality. 411 // Check immediate superclass equality.
407 __ lw(T0, FieldAddress(T0, Class::super_type_offset())); 412 __ lw(T0, FieldAddress(T0, Class::super_type_offset()));
408 __ lw(T0, FieldAddress(T0, Type::type_class_id_offset())); 413 __ lw(T0, FieldAddress(T0, Type::type_class_id_offset()));
409 __ BranchEqual(T0, Immediate(Smi::RawValue(type_class.id())), 414 __ BranchEqual(T0, Immediate(Smi::RawValue(type_class.id())),
410 is_instance_lbl); 415 is_instance_lbl);
411 416
412 const Register kTypeArgumentsReg = kNoRegister; 417 const Register kInstantiatorTypeArgumentsReg = kNoRegister;
418 const Register kFunctionTypeArgumentsReg = kNoRegister;
413 const Register kTempReg = kNoRegister; 419 const Register kTempReg = kNoRegister;
414 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, 420 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg,
415 kTypeArgumentsReg, kTempReg, 421 kInstantiatorTypeArgumentsReg,
422 kFunctionTypeArgumentsReg, kTempReg,
416 is_instance_lbl, is_not_instance_lbl); 423 is_instance_lbl, is_not_instance_lbl);
417 } 424 }
418 425
419 426
420 // Generates inlined check if 'type' is a type parameter or type itself 427 // Generates inlined check if 'type' is a type parameter or type itself
421 // A0: instance (preserved). 428 // A0: instance (preserved).
422 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 429 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
423 TokenPosition token_pos, 430 TokenPosition token_pos,
424 const AbstractType& type, 431 const AbstractType& type,
425 Label* is_instance_lbl, 432 Label* is_instance_lbl,
426 Label* is_not_instance_lbl) { 433 Label* is_not_instance_lbl) {
427 __ Comment("UninstantiatedTypeTest"); 434 __ Comment("UninstantiatedTypeTest");
428 ASSERT(!type.IsInstantiated()); 435 ASSERT(!type.IsInstantiated());
429 // Skip check if destination is a dynamic type. 436 // Skip check if destination is a dynamic type.
430 if (type.IsTypeParameter()) { 437 if (type.IsTypeParameter()) {
431 const TypeParameter& type_param = TypeParameter::Cast(type); 438 const TypeParameter& type_param = TypeParameter::Cast(type);
432 // Load instantiator type arguments on stack. 439 __ lw(A1, Address(SP, 1 * kWordSize)); // Get instantiator type args.
433 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. 440 __ lw(A2, Address(SP, 0 * kWordSize)); // Get function type args.
434 // A1: instantiator type arguments. 441 // A1: instantiator type arguments.
442 // A2: function type arguments.
443 const Register kTypeArgumentsReg =
444 type_param.IsClassTypeParameter() ? A1 : A2;
435 // Check if type arguments are null, i.e. equivalent to vector of dynamic. 445 // Check if type arguments are null, i.e. equivalent to vector of dynamic.
436 __ LoadObject(T7, Object::null_object()); 446 __ LoadObject(T7, Object::null_object());
437 __ beq(A1, T7, is_instance_lbl); 447 __ beq(kTypeArgumentsReg, T7, is_instance_lbl);
438 __ lw(T2, 448 __ lw(T2, FieldAddress(kTypeArgumentsReg,
439 FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); 449 TypeArguments::type_at_offset(type_param.index())));
440 // R2: concrete type of type. 450 // T2: concrete type of type.
441 // Check if type argument is dynamic. 451 // Check if type argument is dynamic.
442 __ BranchEqual(T2, Object::dynamic_type(), is_instance_lbl); 452 __ BranchEqual(T2, Object::dynamic_type(), is_instance_lbl);
443 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::ObjectType()), 453 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::ObjectType()),
444 is_instance_lbl); 454 is_instance_lbl);
455 // TODO(regis): Optimize void type as well once allowed as type argument.
445 456
446 // For Smi check quickly against int and num interfaces. 457 // For Smi check quickly against int and num interfaces.
447 Label not_smi; 458 Label not_smi;
448 __ andi(CMPRES1, A0, Immediate(kSmiTagMask)); 459 __ andi(CMPRES1, A0, Immediate(kSmiTagMask));
449 __ bne(CMPRES1, ZR, &not_smi); // Value is Smi? 460 __ bne(CMPRES1, ZR, &not_smi); // Value is Smi?
450 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::IntType()), 461 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::IntType()),
451 is_instance_lbl); 462 is_instance_lbl);
452 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::Number()), 463 __ BranchEqual(T2, Type::ZoneHandle(zone(), Type::Number()),
453 is_instance_lbl); 464 is_instance_lbl);
454 // Smi must be handled in runtime. 465 // Smi must be handled in runtime.
455 Label fall_through; 466 Label fall_through;
456 __ b(&fall_through); 467 __ b(&fall_through);
457 468
458 __ Bind(&not_smi); 469 __ Bind(&not_smi);
459 // T1: instantiator type arguments.
460 // A0: instance. 470 // A0: instance.
471 // A1: instantiator type arguments.
472 // A2: function type arguments.
461 const Register kInstanceReg = A0; 473 const Register kInstanceReg = A0;
462 const Register kTypeArgumentsReg = A1; 474 const Register kInstantiatorTypeArgumentsReg = A1;
475 const Register kFunctionTypeArgumentsReg = A2;
463 const Register kTempReg = kNoRegister; 476 const Register kTempReg = kNoRegister;
464 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( 477 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
465 zone(), GenerateCallSubtypeTestStub( 478 zone(), GenerateCallSubtypeTestStub(
466 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, 479 kTestTypeFourArgs, kInstanceReg,
480 kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg,
467 kTempReg, is_instance_lbl, is_not_instance_lbl)); 481 kTempReg, is_instance_lbl, is_not_instance_lbl));
468 __ Bind(&fall_through); 482 __ Bind(&fall_through);
469 return type_test_cache.raw(); 483 return type_test_cache.raw();
470 } 484 }
471 if (type.IsType()) { 485 if (type.IsType()) {
472 const Register kInstanceReg = A0; 486 const Register kInstanceReg = A0;
473 const Register kTypeArgumentsReg = A1; 487 const Register kInstantiatorTypeArgumentsReg = A1;
488 const Register kFunctionTypeArgumentsReg = A2;
474 __ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask)); 489 __ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask));
475 __ beq(CMPRES1, ZR, is_not_instance_lbl); // Is instance Smi? 490 __ beq(CMPRES1, ZR, is_not_instance_lbl); // Is instance Smi?
476 __ lw(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args. 491 __ lw(kInstantiatorTypeArgumentsReg, Address(SP, 1 * kWordSize));
492 __ lw(kFunctionTypeArgumentsReg, Address(SP, 0 * kWordSize));
477 // Uninstantiated type class is known at compile time, but the type 493 // Uninstantiated type class is known at compile time, but the type
478 // arguments are determined at runtime by the instantiator. 494 // arguments are determined at runtime by the instantiator.
479 const Register kTempReg = kNoRegister; 495 const Register kTempReg = kNoRegister;
480 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, 496 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg,
481 kTypeArgumentsReg, kTempReg, 497 kInstantiatorTypeArgumentsReg,
498 kFunctionTypeArgumentsReg, kTempReg,
482 is_instance_lbl, is_not_instance_lbl); 499 is_instance_lbl, is_not_instance_lbl);
483 } 500 }
484 return SubtypeTestCache::null(); 501 return SubtypeTestCache::null();
485 } 502 }
486 503
487 504
488 // Inputs: 505 // Inputs:
489 // - A0: instance being type checked (preserved). 506 // - A0: instance being type checked (preserved).
490 // - A1: optional instantiator type arguments (preserved). 507 // - A1: optional instantiator type arguments (preserved).
508 // - A2: optional function type arguments (preserved).
491 // Returns: 509 // Returns:
492 // - preserved instance in A0 and optional instantiator type arguments in A1. 510 // - preserved instance in A0, optional instantiator type arguments in A1, and
511 // optional function type arguments in A2.
493 // Clobbers: T0, T1, T2 512 // Clobbers: T0, T1, T2
494 // Note that this inlined code must be followed by the runtime_call code, as it 513 // Note that this inlined code must be followed by the runtime_call code, as it
495 // may fall through to it. Otherwise, this inline code will jump to the label 514 // may fall through to it. Otherwise, this inline code will jump to the label
496 // is_instance or to the label is_not_instance. 515 // is_instance or to the label is_not_instance.
497 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( 516 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
498 TokenPosition token_pos, 517 TokenPosition token_pos,
499 const AbstractType& type, 518 const AbstractType& type,
500 Label* is_instance_lbl, 519 Label* is_instance_lbl,
501 Label* is_not_instance_lbl) { 520 Label* is_not_instance_lbl) {
502 __ Comment("InlineInstanceof"); 521 __ Comment("InlineInstanceof");
(...skipping 29 matching lines...) Expand all
532 551
533 552
534 // If instanceof type test cannot be performed successfully at compile time and 553 // If instanceof type test cannot be performed successfully at compile time and
535 // therefore eliminated, optimize it by adding inlined tests for: 554 // therefore eliminated, optimize it by adding inlined tests for:
536 // - NULL -> return type == Null (type is not Object or dynamic). 555 // - NULL -> return type == Null (type is not Object or dynamic).
537 // - Smi -> compile time subtype check (only if dst class is not parameterized). 556 // - Smi -> compile time subtype check (only if dst class is not parameterized).
538 // - Class equality (only if class is not parameterized). 557 // - Class equality (only if class is not parameterized).
539 // Inputs: 558 // Inputs:
540 // - A0: object. 559 // - A0: object.
541 // - A1: instantiator type arguments or raw_null. 560 // - A1: instantiator type arguments or raw_null.
561 // - A2: function type arguments or raw_null.
542 // Returns: 562 // Returns:
543 // - true or false in V0. 563 // - true or false in V0.
544 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, 564 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
545 intptr_t deopt_id, 565 intptr_t deopt_id,
546 const AbstractType& type, 566 const AbstractType& type,
547 LocationSummary* locs) { 567 LocationSummary* locs) {
548 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); 568 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded());
549 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); 569 ASSERT(!type.IsObjectType() && !type.IsDynamicType());
550 570
551 // Preserve instantiator type arguments (A1). 571 // Preserve instantiator type arguments (A1) and function type arguments (A2).
552 __ addiu(SP, SP, Immediate(-1 * kWordSize)); 572 __ addiu(SP, SP, Immediate(-2 * kWordSize));
553 __ sw(A1, Address(SP, 0 * kWordSize)); 573 __ sw(A1, Address(SP, 1 * kWordSize));
574 __ sw(A2, Address(SP, 0 * kWordSize));
554 575
555 Label is_instance, is_not_instance; 576 Label is_instance, is_not_instance;
556 // If type is instantiated and non-parameterized, we can inline code 577 // If type is instantiated and non-parameterized, we can inline code
557 // checking whether the tested instance is a Smi. 578 // checking whether the tested instance is a Smi.
558 if (type.IsInstantiated()) { 579 if (type.IsInstantiated()) {
559 // A null object is only an instance of Null, Object, and dynamic. 580 // A null object is only an instance of Null, Object, and dynamic.
560 // Object and dynamic have already been checked above (if the type is 581 // Object and dynamic have already been checked above (if the type is
561 // instantiated). So we can return false here if the instance is null, 582 // instantiated). So we can return false here if the instance is null,
562 // unless the type is Null (and if the type is instantiated). 583 // unless the type is Null (and if the type is instantiated).
563 // We can only inline this null check if the type is instantiated at compile 584 // We can only inline this null check if the type is instantiated at compile
564 // time, since an uninstantiated type at compile time could be Null, Object, 585 // time, since an uninstantiated type at compile time could be Null, Object,
565 // or dynamic at run time. 586 // or dynamic at run time.
566 __ BranchEqual(A0, Object::null_object(), 587 __ BranchEqual(A0, Object::null_object(),
567 type.IsNullType() ? &is_instance : &is_not_instance); 588 type.IsNullType() ? &is_instance : &is_not_instance);
568 } 589 }
569 590
570 // Generate inline instanceof test. 591 // Generate inline instanceof test.
571 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); 592 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
572 test_cache = 593 test_cache =
573 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); 594 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance);
574 595
575 // test_cache is null if there is no fall-through. 596 // test_cache is null if there is no fall-through.
576 Label done; 597 Label done;
577 if (!test_cache.IsNull()) { 598 if (!test_cache.IsNull()) {
578 // Generate runtime call. 599 // Generate runtime call.
579 // Load instantiator type arguments (A1). 600 __ lw(A1, Address(SP, 1 * kWordSize)); // Get instantiator type args.
580 __ lw(A1, Address(SP, 0 * kWordSize)); 601 __ lw(A2, Address(SP, 0 * kWordSize)); // Get function type args.
581 602 __ addiu(SP, SP, Immediate(-6 * kWordSize));
582 __ addiu(SP, SP, Immediate(-5 * kWordSize));
583 __ LoadObject(TMP, Object::null_object()); 603 __ LoadObject(TMP, Object::null_object());
584 __ sw(TMP, Address(SP, 4 * kWordSize)); // Make room for the result. 604 __ sw(TMP, Address(SP, 5 * kWordSize)); // Make room for the result.
585 __ sw(A0, Address(SP, 3 * kWordSize)); // Push the instance. 605 __ sw(A0, Address(SP, 4 * kWordSize)); // Push the instance.
586 __ LoadObject(TMP, type); 606 __ LoadObject(TMP, type);
587 __ sw(TMP, Address(SP, 2 * kWordSize)); // Push the type. 607 __ sw(TMP, Address(SP, 3 * kWordSize)); // Push the type.
588 __ sw(A1, Address(SP, 1 * kWordSize)); // Push type arguments. 608 __ sw(A1, Address(SP, 2 * kWordSize)); // Push instantiator type args.
609 __ sw(A2, Address(SP, 1 * kWordSize)); // Push function type args.
589 __ LoadUniqueObject(A0, test_cache); 610 __ LoadUniqueObject(A0, test_cache);
590 __ sw(A0, Address(SP, 0 * kWordSize)); 611 __ sw(A0, Address(SP, 0 * kWordSize));
591 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); 612 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs);
592 // Pop the parameters supplied to the runtime entry. The result of the 613 // Pop the parameters supplied to the runtime entry. The result of the
593 // instanceof runtime call will be left as the result of the operation. 614 // instanceof runtime call will be left as the result of the operation.
594 __ lw(T0, Address(SP, 4 * kWordSize)); 615 __ lw(V0, Address(SP, 5 * kWordSize));
595 __ addiu(SP, SP, Immediate(5 * kWordSize)); 616 __ addiu(SP, SP, Immediate(6 * kWordSize));
596 __ mov(V0, T0);
597 __ b(&done); 617 __ b(&done);
zra 2017/04/07 17:36:31 (optional) Branch delay slot can be used here.
regis 2017/04/11 04:23:08 Done.
598 } 618 }
599 __ Bind(&is_not_instance); 619 __ Bind(&is_not_instance);
600 __ LoadObject(V0, Bool::Get(false)); 620 __ LoadObject(V0, Bool::Get(false));
601 __ b(&done); 621 __ b(&done);
602 622
603 __ Bind(&is_instance); 623 __ Bind(&is_instance);
604 __ LoadObject(V0, Bool::Get(true)); 624 __ LoadObject(V0, Bool::Get(true));
605 __ Bind(&done); 625 __ Bind(&done);
606 // Remove instantiator type arguments (A1). 626 // Remove instantiator type arguments and function type arguments.
607 __ Drop(1); 627 __ Drop(2);
608 } 628 }
609 629
610 630
611 // Optimize assignable type check by adding inlined tests for: 631 // Optimize assignable type check by adding inlined tests for:
612 // - NULL -> return NULL. 632 // - NULL -> return NULL.
613 // - Smi -> compile time subtype check (only if dst class is not parameterized). 633 // - Smi -> compile time subtype check (only if dst class is not parameterized).
614 // - Class equality (only if class is not parameterized). 634 // - Class equality (only if class is not parameterized).
615 // Inputs: 635 // Inputs:
616 // - A0: instance being type checked. 636 // - A0: instance being type checked.
617 // - A1: instantiator type arguments or raw_null. 637 // - A1: instantiator type arguments or raw_null.
638 // - A2: function type arguments or raw_null.
618 // Returns: 639 // Returns:
619 // - object in A0 for successful assignable check (or throws TypeError). 640 // - object in A0 for successful assignable check (or throws TypeError).
620 // Clobbers: T0, T1, T2 641 // Clobbers: T0, T1, T2
621 // Performance notes: positive checks must be quick, negative checks can be slow 642 // Performance notes: positive checks must be quick, negative checks can be slow
622 // as they throw an exception. 643 // as they throw an exception.
623 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, 644 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
624 intptr_t deopt_id, 645 intptr_t deopt_id,
625 const AbstractType& dst_type, 646 const AbstractType& dst_type,
626 const String& dst_name, 647 const String& dst_name,
627 LocationSummary* locs) { 648 LocationSummary* locs) {
628 __ Comment("AssertAssignable"); 649 __ Comment("AssertAssignable");
629 ASSERT(!token_pos.IsClassifying()); 650 ASSERT(!token_pos.IsClassifying());
630 ASSERT(!dst_type.IsNull()); 651 ASSERT(!dst_type.IsNull());
631 ASSERT(dst_type.IsFinalized()); 652 ASSERT(dst_type.IsFinalized());
632 // Assignable check is skipped in FlowGraphBuilder, not here. 653 // Assignable check is skipped in FlowGraphBuilder, not here.
633 ASSERT(dst_type.IsMalformedOrMalbounded() || 654 ASSERT(dst_type.IsMalformedOrMalbounded() ||
634 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); 655 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
635 // Preserve instantiator type arguments. 656
636 __ addiu(SP, SP, Immediate(-1 * kWordSize)); 657 // Preserve instantiator type arguments (A1) and function type arguments (A2).
637 __ sw(A1, Address(SP, 0 * kWordSize)); 658 __ addiu(SP, SP, Immediate(-2 * kWordSize));
659 __ sw(A1, Address(SP, 1 * kWordSize));
660 __ sw(A2, Address(SP, 0 * kWordSize));
638 661
639 // A null object is always assignable and is returned as result. 662 // A null object is always assignable and is returned as result.
640 Label is_assignable, runtime_call; 663 Label is_assignable, runtime_call;
641 664
642 __ BranchEqual(A0, Object::null_object(), &is_assignable); 665 __ BranchEqual(A0, Object::null_object(), &is_assignable);
643 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize));
644 666
645 // Generate throw new TypeError() if the type is malformed or malbounded. 667 // Generate throw new TypeError() if the type is malformed or malbounded.
646 if (dst_type.IsMalformedOrMalbounded()) { 668 if (dst_type.IsMalformedOrMalbounded()) {
647 __ addiu(SP, SP, Immediate(-4 * kWordSize)); 669 __ addiu(SP, SP, Immediate(-4 * kWordSize));
648 __ LoadObject(TMP, Object::null_object()); 670 __ LoadObject(TMP, Object::null_object());
649 __ sw(TMP, Address(SP, 3 * kWordSize)); // Make room for the result. 671 __ sw(TMP, Address(SP, 3 * kWordSize)); // Make room for the result.
650 __ sw(A0, Address(SP, 2 * kWordSize)); // Push the source object. 672 __ sw(A0, Address(SP, 2 * kWordSize)); // Push the source object.
651 __ LoadObject(TMP, dst_name); 673 __ LoadObject(TMP, dst_name);
652 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the destination name. 674 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the destination name.
653 __ LoadObject(TMP, dst_type); 675 __ LoadObject(TMP, dst_type);
654 __ sw(TMP, Address(SP, 0 * kWordSize)); // Push the destination type. 676 __ sw(TMP, Address(SP, 0 * kWordSize)); // Push the destination type.
655 677
656 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, 678 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3,
657 locs); 679 locs);
658 // We should never return here. 680 // We should never return here.
659 __ break_(0); 681 __ break_(0);
660 682
661 __ Bind(&is_assignable); // For a null object. 683 __ Bind(&is_assignable); // For a null object.
662 // Restore instantiator type arguments. 684 __ lw(A1, Address(SP, 1 * kWordSize)); // Restore instantiator type args.
663 __ lw(A1, Address(SP, 0 * kWordSize)); 685 __ lw(A2, Address(SP, 0 * kWordSize)); // Restore function type args.
664 __ addiu(SP, SP, Immediate(1 * kWordSize)); 686 __ addiu(SP, SP, Immediate(2 * kWordSize));
665 return; 687 return;
666 } 688 }
667 689
668 // Generate inline type check, linking to runtime call if not assignable. 690 // Generate inline type check, linking to runtime call if not assignable.
669 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); 691 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
670 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, 692 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable,
671 &runtime_call); 693 &runtime_call);
672 694
673 __ Bind(&runtime_call); 695 __ Bind(&runtime_call);
674 // Load instantiator type arguments (A1). 696 __ lw(A1, Address(SP, 1 * kWordSize)); // Load instantiator type args.
675 __ lw(A1, Address(SP, 0 * kWordSize)); 697 __ lw(A2, Address(SP, 0 * kWordSize)); // Load function type args.
676 698
677 __ addiu(SP, SP, Immediate(-6 * kWordSize)); 699 __ addiu(SP, SP, Immediate(-7 * kWordSize));
678 __ LoadObject(TMP, Object::null_object()); 700 __ LoadObject(TMP, Object::null_object());
679 __ sw(TMP, Address(SP, 5 * kWordSize)); // Make room for the result. 701 __ sw(TMP, Address(SP, 6 * kWordSize)); // Make room for the result.
680 __ sw(A0, Address(SP, 4 * kWordSize)); // Push the source object. 702 __ sw(A0, Address(SP, 5 * kWordSize)); // Push the source object.
681 __ LoadObject(TMP, dst_type); 703 __ LoadObject(TMP, dst_type);
682 __ sw(TMP, Address(SP, 3 * kWordSize)); // Push the type of the destination. 704 __ sw(TMP, Address(SP, 4 * kWordSize)); // Push the type of the destination.
683 __ sw(A1, Address(SP, 2 * kWordSize)); // Push type arguments. 705 __ sw(A1, Address(SP, 3 * kWordSize)); // Push instantiator type args.
706 __ sw(A2, Address(SP, 2 * kWordSize)); // Push function type args.
684 __ LoadObject(TMP, dst_name); 707 __ LoadObject(TMP, dst_name);
685 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the name of the destination. 708 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the name of the destination.
686 __ LoadUniqueObject(T0, test_cache); 709 __ LoadUniqueObject(T0, test_cache);
687 __ sw(T0, Address(SP, 0 * kWordSize)); 710 __ sw(T0, Address(SP, 0 * kWordSize));
688 711
689 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); 712 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
690 // Pop the parameters supplied to the runtime entry. The result of the 713 // Pop the parameters supplied to the runtime entry. The result of the
691 // type check runtime call is the checked value. 714 // type check runtime call is the checked value.
692 __ lw(A0, Address(SP, 5 * kWordSize)); 715 __ lw(A0, Address(SP, 6 * kWordSize));
693 __ addiu(SP, SP, Immediate(6 * kWordSize)); 716 __ addiu(SP, SP, Immediate(7 * kWordSize));
694 717
695 __ Bind(&is_assignable); 718 __ Bind(&is_assignable);
696 // Restore instantiator type arguments. 719 __ lw(A1, Address(SP, 1 * kWordSize)); // Restore instantiator type args.
697 __ lw(A1, Address(SP, 0 * kWordSize)); 720 __ lw(A2, Address(SP, 0 * kWordSize)); // Restore function type args.
698 __ addiu(SP, SP, Immediate(1 * kWordSize)); 721 __ addiu(SP, SP, Immediate(2 * kWordSize));
699 } 722 }
700 723
701 724
702 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { 725 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
703 if (is_optimizing()) return; 726 if (is_optimizing()) return;
704 Definition* defn = instr->AsDefinition(); 727 Definition* defn = instr->AsDefinition();
705 if ((defn != NULL) && defn->HasTemp()) { 728 if ((defn != NULL) && defn->HasTemp()) {
706 __ Push(defn->locs()->out(0).reg()); 729 __ Push(defn->locs()->out(0).reg());
707 } 730 }
708 } 731 }
(...skipping 1155 matching lines...) Expand 10 before | Expand all | Expand 10 after
1864 __ AddImmediate(SP, kDoubleSize); 1887 __ AddImmediate(SP, kDoubleSize);
1865 } 1888 }
1866 1889
1867 1890
1868 #undef __ 1891 #undef __
1869 1892
1870 1893
1871 } // namespace dart 1894 } // namespace dart
1872 1895
1873 #endif // defined TARGET_ARCH_MIPS 1896 #endif // defined TARGET_ARCH_MIPS
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698