Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 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 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 195 __ b(&fall_through, EQ); | 195 __ b(&fall_through, EQ); |
| 196 __ CompareObject(bool_register, Bool::True()); | 196 __ CompareObject(bool_register, Bool::True()); |
| 197 __ b(is_true, EQ); | 197 __ b(is_true, EQ); |
| 198 __ b(is_false); | 198 __ b(is_false); |
| 199 __ Bind(&fall_through); | 199 __ Bind(&fall_through); |
| 200 } | 200 } |
| 201 | 201 |
| 202 | 202 |
| 203 // R0: instance (must be preserved). | 203 // R0: instance (must be preserved). |
| 204 // R1: instantiator type arguments (if used). | 204 // R1: instantiator type arguments (if used). |
| 205 // R2: function type arguments (if used). | |
| 205 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 206 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 206 TypeTestStubKind test_kind, | 207 TypeTestStubKind test_kind, |
| 207 Register instance_reg, | 208 Register instance_reg, |
| 208 Register type_arguments_reg, | 209 Register instantiator_type_arguments_reg, |
| 210 Register function_type_arguments_reg, | |
| 209 Register temp_reg, | 211 Register temp_reg, |
| 210 Label* is_instance_lbl, | 212 Label* is_instance_lbl, |
| 211 Label* is_not_instance_lbl) { | 213 Label* is_not_instance_lbl) { |
| 212 ASSERT(instance_reg == R0); | 214 ASSERT(instance_reg == R0); |
| 213 ASSERT(temp_reg == kNoRegister); // Unused on ARM. | 215 ASSERT(temp_reg == kNoRegister); // Unused on ARM64. |
| 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(R2, type_test_cache); | 218 __ LoadUniqueObject(R3, 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(R1, 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(R1, 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 == R1); | 228 ASSERT(instantiator_type_arguments_reg == R1); |
| 227 __ BranchLink(*StubCode::Subtype3TestCache_entry()); | 229 ASSERT(function_type_arguments_reg == R2); |
| 230 __ BranchLink(*StubCode::Subtype4TestCache_entry()); | |
| 228 } else { | 231 } else { |
| 229 UNREACHABLE(); | 232 UNREACHABLE(); |
| 230 } | 233 } |
| 231 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. | 234 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. |
| 232 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); | 235 GenerateBoolToJump(R1, 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 |
| 238 // type test is conclusive, otherwise fallthrough if a type test could not | 241 // type test is conclusive, otherwise fallthrough if a type test could not |
| 239 // be completed. | 242 // be completed. |
| 240 // R0: instance being type checked (preserved). | 243 // R0: instance being type checked (preserved). |
| 241 // Clobbers R2. | 244 // Clobbers R1, R2. |
| 242 RawSubtypeTestCache* | 245 RawSubtypeTestCache* |
| 243 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 246 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 244 TokenPosition token_pos, | 247 TokenPosition token_pos, |
| 245 const AbstractType& type, | 248 const AbstractType& type, |
| 246 Label* is_instance_lbl, | 249 Label* is_instance_lbl, |
| 247 Label* is_not_instance_lbl) { | 250 Label* is_not_instance_lbl) { |
| 248 __ Comment("InstantiatedTypeWithArgumentsTest"); | 251 __ Comment("InstantiatedTypeWithArgumentsTest"); |
| 249 ASSERT(type.IsInstantiated()); | 252 ASSERT(type.IsInstantiated()); |
| 250 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); | 253 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 251 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); | 254 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 295 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 298 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
| 296 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 299 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
| 297 // Instance class test only necessary. | 300 // Instance class test only necessary. |
| 298 return GenerateSubtype1TestCacheLookup( | 301 return GenerateSubtype1TestCacheLookup( |
| 299 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 302 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 300 } | 303 } |
| 301 } | 304 } |
| 302 } | 305 } |
| 303 } | 306 } |
| 304 // Regular subtype test cache involving instance's type arguments. | 307 // Regular subtype test cache involving instance's type arguments. |
| 305 const Register kTypeArgumentsReg = kNoRegister; | 308 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 309 const Register kFunctionTypeArgumentsReg = kNoRegister; | |
| 306 const Register kTempReg = kNoRegister; | 310 const Register kTempReg = kNoRegister; |
| 307 // R0: instance (must be preserved). | 311 // R0: instance (must be preserved). |
| 308 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, | 312 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
| 309 kTypeArgumentsReg, kTempReg, | 313 kInstantiatorTypeArgumentsReg, |
| 314 kFunctionTypeArgumentsReg, kTempReg, | |
| 310 is_instance_lbl, is_not_instance_lbl); | 315 is_instance_lbl, is_not_instance_lbl); |
| 311 } | 316 } |
| 312 | 317 |
| 313 | 318 |
| 314 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 319 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
| 315 const GrowableArray<intptr_t>& class_ids, | 320 const GrowableArray<intptr_t>& class_ids, |
| 316 Label* is_equal_lbl, | 321 Label* is_equal_lbl, |
| 317 Label* is_not_equal_lbl) { | 322 Label* is_not_equal_lbl) { |
| 318 for (intptr_t i = 0; i < class_ids.length(); i++) { | 323 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 319 __ CompareImmediate(class_id_reg, class_ids[i]); | 324 __ CompareImmediate(class_id_reg, class_ids[i]); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 406 __ Comment("Subtype1TestCacheLookup"); | 411 __ Comment("Subtype1TestCacheLookup"); |
| 407 const Register kInstanceReg = R0; | 412 const Register kInstanceReg = R0; |
| 408 __ LoadClass(R1, kInstanceReg); | 413 __ LoadClass(R1, kInstanceReg); |
| 409 // R1: instance class. | 414 // R1: instance class. |
| 410 // Check immediate superclass equality. | 415 // Check immediate superclass equality. |
| 411 __ LoadFieldFromOffset(R2, R1, Class::super_type_offset()); | 416 __ LoadFieldFromOffset(R2, R1, Class::super_type_offset()); |
| 412 __ LoadFieldFromOffset(R2, R2, Type::type_class_id_offset()); | 417 __ LoadFieldFromOffset(R2, R2, Type::type_class_id_offset()); |
| 413 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); | 418 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); |
| 414 __ b(is_instance_lbl, EQ); | 419 __ b(is_instance_lbl, EQ); |
| 415 | 420 |
| 416 const Register kTypeArgumentsReg = kNoRegister; | 421 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 422 const Register kFunctionTypeArgumentsReg = kNoRegister; | |
| 417 const Register kTempReg = kNoRegister; | 423 const Register kTempReg = kNoRegister; |
| 418 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, | 424 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
| 419 kTypeArgumentsReg, kTempReg, | 425 kInstantiatorTypeArgumentsReg, |
| 426 kFunctionTypeArgumentsReg, kTempReg, | |
| 420 is_instance_lbl, is_not_instance_lbl); | 427 is_instance_lbl, is_not_instance_lbl); |
| 421 } | 428 } |
| 422 | 429 |
| 423 | 430 |
| 424 // Generates inlined check if 'type' is a type parameter or type itself | 431 // Generates inlined check if 'type' is a type parameter or type itself |
| 425 // R0: instance (preserved). | 432 // R0: instance (preserved). |
| 426 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 433 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 427 TokenPosition token_pos, | 434 TokenPosition token_pos, |
| 428 const AbstractType& type, | 435 const AbstractType& type, |
| 429 Label* is_instance_lbl, | 436 Label* is_instance_lbl, |
| 430 Label* is_not_instance_lbl) { | 437 Label* is_not_instance_lbl) { |
| 431 __ Comment("UninstantiatedTypeTest"); | 438 __ Comment("UninstantiatedTypeTest"); |
| 432 ASSERT(!type.IsInstantiated()); | 439 ASSERT(!type.IsInstantiated()); |
| 433 // Skip check if destination is a dynamic type. | 440 // Skip check if destination is a dynamic type. |
| 434 if (type.IsTypeParameter()) { | 441 if (type.IsTypeParameter()) { |
| 435 const TypeParameter& type_param = TypeParameter::Cast(type); | 442 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 436 // Load instantiator type arguments on stack. | 443 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
|
zra
2017/04/07 17:36:30
ldp to load a pair.
regis
2017/04/11 04:23:07
Done.
| |
| 437 __ ldr(R1, Address(SP)); // Get instantiator type arguments. | 444 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. |
| 438 // R1: instantiator type arguments. | 445 // R1: instantiator type arguments. |
| 446 // R2: function type arguments. | |
| 447 const Register kTypeArgumentsReg = | |
| 448 type_param.IsClassTypeParameter() ? R1 : R2; | |
| 439 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 449 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 440 __ CompareObject(R1, Object::null_object()); | 450 __ CompareObject(kTypeArgumentsReg, Object::null_object()); |
| 441 __ b(is_instance_lbl, EQ); | 451 __ b(is_instance_lbl, EQ); |
| 442 __ LoadFieldFromOffset(R2, R1, | 452 __ LoadFieldFromOffset(R3, kTypeArgumentsReg, |
| 443 TypeArguments::type_at_offset(type_param.index())); | 453 TypeArguments::type_at_offset(type_param.index())); |
| 444 // R2: concrete type of type. | 454 // R3: concrete type of type. |
| 445 // Check if type argument is dynamic. | 455 // Check if type argument is dynamic. |
| 446 __ CompareObject(R2, Object::dynamic_type()); | 456 __ CompareObject(R3, Object::dynamic_type()); |
| 447 __ b(is_instance_lbl, EQ); | 457 __ b(is_instance_lbl, EQ); |
| 448 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); | 458 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::ObjectType())); |
| 449 __ b(is_instance_lbl, EQ); | 459 __ b(is_instance_lbl, EQ); |
| 460 // TODO(regis): Optimize void type as well once allowed as type argument. | |
| 450 | 461 |
| 451 // For Smi check quickly against int and num interfaces. | 462 // For Smi check quickly against int and num interfaces. |
| 452 Label not_smi; | 463 Label not_smi; |
| 453 __ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi? | 464 __ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi? |
| 454 __ b(¬_smi, NE); | 465 __ b(¬_smi, NE); |
| 455 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType())); | 466 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::IntType())); |
| 456 __ b(is_instance_lbl, EQ); | 467 __ b(is_instance_lbl, EQ); |
| 457 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number())); | 468 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number())); |
| 458 __ b(is_instance_lbl, EQ); | 469 __ b(is_instance_lbl, EQ); |
| 459 // Smi must be handled in runtime. | 470 // Smi must be handled in runtime. |
| 460 Label fall_through; | 471 Label fall_through; |
| 461 __ b(&fall_through); | 472 __ b(&fall_through); |
| 462 | 473 |
| 463 __ Bind(¬_smi); | 474 __ Bind(¬_smi); |
| 464 // R1: instantiator type arguments. | 475 // R1: instantiator type arguments. |
| 476 // R2: function type arguments. | |
| 465 // R0: instance. | 477 // R0: instance. |
| 466 const Register kInstanceReg = R0; | 478 const Register kInstanceReg = R0; |
| 467 const Register kTypeArgumentsReg = R1; | 479 const Register kInstantiatorTypeArgumentsReg = R1; |
| 480 const Register kFunctionTypeArgumentsReg = R2; | |
| 468 const Register kTempReg = kNoRegister; | 481 const Register kTempReg = kNoRegister; |
| 469 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( | 482 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
| 470 zone(), GenerateCallSubtypeTestStub( | 483 zone(), GenerateCallSubtypeTestStub( |
| 471 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, | 484 kTestTypeFourArgs, kInstanceReg, |
| 485 kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, | |
| 472 kTempReg, is_instance_lbl, is_not_instance_lbl)); | 486 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
| 473 __ Bind(&fall_through); | 487 __ Bind(&fall_through); |
| 474 return type_test_cache.raw(); | 488 return type_test_cache.raw(); |
| 475 } | 489 } |
| 476 if (type.IsType()) { | 490 if (type.IsType()) { |
| 477 const Register kInstanceReg = R0; | 491 const Register kInstanceReg = R0; |
| 478 const Register kTypeArgumentsReg = R1; | 492 const Register kInstantiatorTypeArgumentsReg = R1; |
| 493 const Register kFunctionTypeArgumentsReg = R2; | |
| 479 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? | 494 __ tsti(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? |
| 480 __ b(is_not_instance_lbl, EQ); | 495 __ b(is_not_instance_lbl, EQ); |
| 481 __ ldr(kTypeArgumentsReg, Address(SP)); // Instantiator type args. | 496 __ ldr(kInstantiatorTypeArgumentsReg, Address(SP, 1 * kWordSize)); |
|
zra
2017/04/07 17:36:30
ditto
regis
2017/04/11 04:23:08
Done.
| |
| 497 __ ldr(kFunctionTypeArgumentsReg, Address(SP, 0 * kWordSize)); | |
| 482 // Uninstantiated type class is known at compile time, but the type | 498 // Uninstantiated type class is known at compile time, but the type |
| 483 // arguments are determined at runtime by the instantiator. | 499 // arguments are determined at runtime by the instantiator. |
| 484 const Register kTempReg = kNoRegister; | 500 const Register kTempReg = kNoRegister; |
| 485 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, | 501 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, |
| 486 kTypeArgumentsReg, kTempReg, | 502 kInstantiatorTypeArgumentsReg, |
| 503 kFunctionTypeArgumentsReg, kTempReg, | |
| 487 is_instance_lbl, is_not_instance_lbl); | 504 is_instance_lbl, is_not_instance_lbl); |
| 488 } | 505 } |
| 489 return SubtypeTestCache::null(); | 506 return SubtypeTestCache::null(); |
| 490 } | 507 } |
| 491 | 508 |
| 492 | 509 |
| 493 // Inputs: | 510 // Inputs: |
| 494 // - R0: instance being type checked (preserved). | 511 // - R0: instance being type checked (preserved). |
| 495 // - R1: optional instantiator type arguments (preserved). | 512 // - R1: optional instantiator type arguments (preserved). |
| 496 // Clobbers R2, R3. | 513 // - R2: optional function type arguments (preserved). |
| 514 // Clobbers R3, R4, R8, R9. | |
| 497 // Returns: | 515 // Returns: |
| 498 // - preserved instance in R0 and optional instantiator type arguments in R1. | 516 // - preserved instance in R0, optional instantiator type arguments in R1, and |
| 517 // optional function type arguments in R2. | |
| 499 // Note that this inlined code must be followed by the runtime_call code, as it | 518 // Note that this inlined code must be followed by the runtime_call code, as it |
| 500 // may fall through to it. Otherwise, this inline code will jump to the label | 519 // may fall through to it. Otherwise, this inline code will jump to the label |
| 501 // is_instance or to the label is_not_instance. | 520 // is_instance or to the label is_not_instance. |
| 502 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 521 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
| 503 TokenPosition token_pos, | 522 TokenPosition token_pos, |
| 504 const AbstractType& type, | 523 const AbstractType& type, |
| 505 Label* is_instance_lbl, | 524 Label* is_instance_lbl, |
| 506 Label* is_not_instance_lbl) { | 525 Label* is_not_instance_lbl) { |
| 507 __ Comment("InlineInstanceof"); | 526 __ Comment("InlineInstanceof"); |
| 508 if (type.IsVoidType()) { | 527 if (type.IsVoidType()) { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 537 | 556 |
| 538 | 557 |
| 539 // If instanceof type test cannot be performed successfully at compile time and | 558 // If instanceof type test cannot be performed successfully at compile time and |
| 540 // therefore eliminated, optimize it by adding inlined tests for: | 559 // therefore eliminated, optimize it by adding inlined tests for: |
| 541 // - NULL -> return type == Null (type is not Object or dynamic). | 560 // - NULL -> return type == Null (type is not Object or dynamic). |
| 542 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 561 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 543 // - Class equality (only if class is not parameterized). | 562 // - Class equality (only if class is not parameterized). |
| 544 // Inputs: | 563 // Inputs: |
| 545 // - R0: object. | 564 // - R0: object. |
| 546 // - R1: instantiator type arguments or raw_null. | 565 // - R1: instantiator type arguments or raw_null. |
| 566 // - R2: function type arguments or raw_null. | |
| 547 // Returns: | 567 // Returns: |
| 548 // - true or false in R0. | 568 // - true or false in R0. |
| 549 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, | 569 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
| 550 intptr_t deopt_id, | 570 intptr_t deopt_id, |
| 551 const AbstractType& type, | 571 const AbstractType& type, |
| 552 LocationSummary* locs) { | 572 LocationSummary* locs) { |
| 553 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); | 573 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
| 554 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); | 574 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); |
| 555 | 575 |
| 556 // Preserve instantiator type arguments (R1). | 576 __ Push(R1); // Store instantiator type arguments. |
|
zra
2017/04/07 17:36:30
PushPair
regis
2017/04/11 04:23:08
Done.
However, the argument names 'first' and 'se
| |
| 557 __ Push(R1); | 577 __ Push(R2); // Store function type arguments. |
| 558 | 578 |
| 559 Label is_instance, is_not_instance; | 579 Label is_instance, is_not_instance; |
| 560 // If type is instantiated and non-parameterized, we can inline code | 580 // If type is instantiated and non-parameterized, we can inline code |
| 561 // checking whether the tested instance is a Smi. | 581 // checking whether the tested instance is a Smi. |
| 562 if (type.IsInstantiated()) { | 582 if (type.IsInstantiated()) { |
| 563 // A null object is only an instance of Null, Object, and dynamic. | 583 // A null object is only an instance of Null, Object, and dynamic. |
| 564 // Object and dynamic have already been checked above (if the type is | 584 // Object and dynamic have already been checked above (if the type is |
| 565 // instantiated). So we can return false here if the instance is null, | 585 // instantiated). So we can return false here if the instance is null, |
| 566 // unless the type is Null (and if the type is instantiated). | 586 // unless the type is Null (and if the type is instantiated). |
| 567 // We can only inline this null check if the type is instantiated at compile | 587 // We can only inline this null check if the type is instantiated at compile |
| 568 // time, since an uninstantiated type at compile time could be Null, Object, | 588 // time, since an uninstantiated type at compile time could be Null, Object, |
| 569 // or dynamic at run time. | 589 // or dynamic at run time. |
| 570 __ CompareObject(R0, Object::null_object()); | 590 __ CompareObject(R0, Object::null_object()); |
| 571 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); | 591 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); |
| 572 } | 592 } |
| 573 | 593 |
| 574 // Generate inline instanceof test. | 594 // Generate inline instanceof test. |
| 575 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 595 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 576 test_cache = | 596 test_cache = |
| 577 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); | 597 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
| 578 | 598 |
| 579 // test_cache is null if there is no fall-through. | 599 // test_cache is null if there is no fall-through. |
| 580 Label done; | 600 Label done; |
| 581 if (!test_cache.IsNull()) { | 601 if (!test_cache.IsNull()) { |
| 582 // Generate runtime call. | 602 // Generate runtime call. |
| 583 // Load instantiator (R2) and its type arguments (R1). | 603 // Load instantiator (R2) and its type arguments (R1). |
| 584 __ ldr(R1, Address(SP, 0 * kWordSize)); | 604 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
|
zra
2017/04/07 17:36:30
ldp
regis
2017/04/11 04:23:08
Done.
| |
| 585 __ PushObject(Object::null_object()); // Make room for the result. | 605 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. |
| 586 __ Push(R0); // Push the instance. | 606 __ PushObject(Object::null_object()); // Make room for the result. |
| 587 __ PushObject(type); // Push the type. | 607 __ Push(R0); // Push the instance. |
| 588 __ Push(R1); // Push instantiator type arguments (R1). | 608 __ PushObject(type); // Push the type. |
| 609 __ Push(R1); // Instantiator type arguments. | |
|
zra
2017/04/07 17:36:30
PushPair
regis
2017/04/11 04:23:08
Done.
| |
| 610 __ Push(R2); // Function type arguments. | |
| 589 __ LoadUniqueObject(R0, test_cache); | 611 __ LoadUniqueObject(R0, test_cache); |
| 590 __ Push(R0); | 612 __ Push(R0); |
| 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 __ Drop(4); | 616 __ Drop(5); |
| 595 __ Pop(R0); | 617 __ Pop(R0); |
| 596 __ b(&done); | 618 __ b(&done); |
| 597 } | 619 } |
| 598 __ Bind(&is_not_instance); | 620 __ Bind(&is_not_instance); |
| 599 __ LoadObject(R0, Bool::Get(false)); | 621 __ LoadObject(R0, Bool::Get(false)); |
| 600 __ b(&done); | 622 __ b(&done); |
| 601 | 623 |
| 602 __ Bind(&is_instance); | 624 __ Bind(&is_instance); |
| 603 __ LoadObject(R0, Bool::Get(true)); | 625 __ LoadObject(R0, Bool::Get(true)); |
| 604 __ Bind(&done); | 626 __ Bind(&done); |
| 605 // Remove instantiator type arguments (R1). | 627 // Remove instantiator type arguments and function type arguments. |
| 606 __ Drop(1); | 628 __ Drop(2); |
| 607 } | 629 } |
| 608 | 630 |
| 609 | 631 |
| 610 // Optimize assignable type check by adding inlined tests for: | 632 // Optimize assignable type check by adding inlined tests for: |
| 611 // - NULL -> return NULL. | 633 // - NULL -> return NULL. |
| 612 // - 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). |
| 613 // - Class equality (only if class is not parameterized). | 635 // - Class equality (only if class is not parameterized). |
| 614 // Inputs: | 636 // Inputs: |
| 615 // - R0: instance being type checked. | 637 // - R0: instance being type checked. |
| 616 // - R1: instantiator type arguments or raw_null. | 638 // - R1: instantiator type arguments or raw_null. |
| 639 // - R2: function type arguments or raw_null. | |
| 617 // Returns: | 640 // Returns: |
| 618 // - object in R0 for successful assignable check (or throws TypeError). | 641 // - object in R0 for successful assignable check (or throws TypeError). |
| 619 // 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 |
| 620 // as they throw an exception. | 643 // as they throw an exception. |
| 621 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, | 644 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
| 622 intptr_t deopt_id, | 645 intptr_t deopt_id, |
| 623 const AbstractType& dst_type, | 646 const AbstractType& dst_type, |
| 624 const String& dst_name, | 647 const String& dst_name, |
| 625 LocationSummary* locs) { | 648 LocationSummary* locs) { |
| 626 ASSERT(!TokenPosition(token_pos).IsClassifying()); | 649 ASSERT(!TokenPosition(token_pos).IsClassifying()); |
| 627 ASSERT(!dst_type.IsNull()); | 650 ASSERT(!dst_type.IsNull()); |
| 628 ASSERT(dst_type.IsFinalized()); | 651 ASSERT(dst_type.IsFinalized()); |
| 629 // Assignable check is skipped in FlowGraphBuilder, not here. | 652 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 630 ASSERT(dst_type.IsMalformedOrMalbounded() || | 653 ASSERT(dst_type.IsMalformedOrMalbounded() || |
| 631 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 654 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 632 // Preserve instantiator type arguments (R1). | 655 __ Push(R1); // Store instantiator type arguments. |
|
zra
2017/04/07 17:36:30
PushPair
regis
2017/04/11 04:23:08
Done.
| |
| 633 __ Push(R1); | 656 __ Push(R2); // Store function type arguments. |
| 634 // A null object is always assignable and is returned as result. | 657 // A null object is always assignable and is returned as result. |
| 635 Label is_assignable, runtime_call; | 658 Label is_assignable, runtime_call; |
| 636 __ CompareObject(R0, Object::null_object()); | 659 __ CompareObject(R0, Object::null_object()); |
| 637 __ b(&is_assignable, EQ); | 660 __ b(&is_assignable, EQ); |
| 638 | 661 |
| 639 // Generate throw new TypeError() if the type is malformed or malbounded. | 662 // Generate throw new TypeError() if the type is malformed or malbounded. |
| 640 if (dst_type.IsMalformedOrMalbounded()) { | 663 if (dst_type.IsMalformedOrMalbounded()) { |
| 641 __ PushObject(Object::null_object()); // Make room for the result. | 664 __ PushObject(Object::null_object()); // Make room for the result. |
| 642 __ Push(R0); // Push the source object. | 665 __ Push(R0); // Push the source object. |
| 643 __ PushObject(dst_name); // Push the name of the destination. | 666 __ PushObject(dst_name); // Push the name of the destination. |
| 644 __ PushObject(dst_type); // Push the type of the destination. | 667 __ PushObject(dst_type); // Push the type of the destination. |
| 645 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, | 668 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
| 646 locs); | 669 locs); |
| 647 // We should never return here. | 670 // We should never return here. |
| 648 __ brk(0); | 671 __ brk(0); |
| 649 | 672 |
| 650 __ Bind(&is_assignable); // For a null object. | 673 __ Bind(&is_assignable); // For a null object. |
| 651 // Restore instantiator type arguments (R1). | 674 __ Pop(R2); // Remove pushed function type arguments. |
|
zra
2017/04/07 17:36:30
PopPair
regis
2017/04/11 04:23:08
Done.
| |
| 652 __ Pop(R1); | 675 __ Pop(R1); // Remove pushed instantiator type arguments. |
| 653 return; | 676 return; |
| 654 } | 677 } |
| 655 | 678 |
| 656 // Generate inline type check, linking to runtime call if not assignable. | 679 // Generate inline type check, linking to runtime call if not assignable. |
| 657 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 680 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 658 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, | 681 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
| 659 &runtime_call); | 682 &runtime_call); |
| 660 | 683 |
| 661 __ Bind(&runtime_call); | 684 __ Bind(&runtime_call); |
| 662 __ ldr(R1, Address(SP)); // Load instantiator type arguments (R1). | 685 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
|
zra
2017/04/07 17:36:30
ldp
regis
2017/04/11 04:23:07
Done.
| |
| 663 __ PushObject(Object::null_object()); // Make room for the result. | 686 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. |
| 664 __ Push(R0); // Push the source object. | 687 __ PushObject(Object::null_object()); // Make room for the result. |
| 665 __ PushObject(dst_type); // Push the type of the destination. | 688 __ Push(R0); // Push the source object. |
| 666 __ Push(R1); // Push instantiator type arguments (R1). | 689 __ PushObject(dst_type); // Push the type of the destination. |
| 667 __ PushObject(dst_name); // Push the name of the destination. | 690 __ Push(R1); // Instantiator type arguments. |
|
zra
2017/04/07 17:36:30
PushPair
regis
2017/04/11 04:23:07
Done.
| |
| 691 __ Push(R2); // Function type arguments. | |
| 692 __ PushObject(dst_name); // Push the name of the destination. | |
| 668 __ LoadUniqueObject(R0, test_cache); | 693 __ LoadUniqueObject(R0, test_cache); |
| 669 __ Push(R0); | 694 __ Push(R0); |
| 670 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 695 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
| 671 // Pop the parameters supplied to the runtime entry. The result of the | 696 // Pop the parameters supplied to the runtime entry. The result of the |
| 672 // type check runtime call is the checked value. | 697 // type check runtime call is the checked value. |
| 673 __ Drop(5); | 698 __ Drop(6); |
| 674 __ Pop(R0); | 699 __ Pop(R0); |
| 675 | 700 |
| 676 __ Bind(&is_assignable); | 701 __ Bind(&is_assignable); |
| 677 // Restore instantiator type arguments (R1). | 702 __ Pop(R2); // Remove pushed function type arguments. |
|
zra
2017/04/07 17:36:30
PopPair
regis
2017/04/11 04:23:08
Done.
| |
| 678 __ Pop(R1); | 703 __ Pop(R1); // Remove pushed instantiator type arguments. |
| 679 } | 704 } |
| 680 | 705 |
| 681 | 706 |
| 682 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 707 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
| 683 if (is_optimizing()) { | 708 if (is_optimizing()) { |
| 684 return; | 709 return; |
| 685 } | 710 } |
| 686 Definition* defn = instr->AsDefinition(); | 711 Definition* defn = instr->AsDefinition(); |
| 687 if ((defn != NULL) && defn->HasTemp()) { | 712 if ((defn != NULL) && defn->HasTemp()) { |
| 688 __ Push(defn->locs()->out(0).reg()); | 713 __ Push(defn->locs()->out(0).reg()); |
| (...skipping 1144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1833 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1858 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 1834 __ PopDouble(reg); | 1859 __ PopDouble(reg); |
| 1835 } | 1860 } |
| 1836 | 1861 |
| 1837 | 1862 |
| 1838 #undef __ | 1863 #undef __ |
| 1839 | 1864 |
| 1840 } // namespace dart | 1865 } // namespace dart |
| 1841 | 1866 |
| 1842 #endif // defined TARGET_ARCH_ARM64 | 1867 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |