| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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, ¬_smi); // Value is Smi? | 461 __ bne(CMPRES1, ZR, ¬_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(¬_smi); | 470 __ Bind(¬_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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |