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

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

Powered by Google App Engine
This is Rietveld 408576698