Chromium Code Reviews| 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 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 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 202 __ b(&fall_through, EQ); | 202 __ b(&fall_through, EQ); |
| 203 __ CompareObject(bool_register, Bool::True()); | 203 __ CompareObject(bool_register, Bool::True()); |
| 204 __ b(is_true, EQ); | 204 __ b(is_true, EQ); |
| 205 __ b(is_false); | 205 __ b(is_false); |
| 206 __ Bind(&fall_through); | 206 __ Bind(&fall_through); |
| 207 } | 207 } |
| 208 | 208 |
| 209 | 209 |
| 210 // R0: instance (must be preserved). | 210 // R0: instance (must be preserved). |
| 211 // R1: instantiator type arguments (if used). | 211 // R1: instantiator type arguments (if used). |
| 212 // R2: function type arguments (if used). | |
| 213 // R3: type test cache. | |
| 212 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 214 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 213 TypeTestStubKind test_kind, | 215 TypeTestStubKind test_kind, |
| 214 Register instance_reg, | 216 Register instance_reg, |
| 215 Register type_arguments_reg, | 217 Register instantiator_type_arguments_reg, |
| 218 Register function_type_arguments_reg, | |
| 216 Register temp_reg, | 219 Register temp_reg, |
| 217 Label* is_instance_lbl, | 220 Label* is_instance_lbl, |
| 218 Label* is_not_instance_lbl) { | 221 Label* is_not_instance_lbl) { |
| 219 ASSERT(instance_reg == R0); | 222 ASSERT(instance_reg == R0); |
| 220 ASSERT(temp_reg == kNoRegister); // Unused on ARM. | 223 ASSERT(temp_reg == kNoRegister); // Unused on ARM. |
| 221 const SubtypeTestCache& type_test_cache = | 224 const SubtypeTestCache& type_test_cache = |
| 222 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); | 225 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
| 223 __ LoadUniqueObject(R2, type_test_cache); | 226 __ LoadUniqueObject(R3, type_test_cache); |
| 224 if (test_kind == kTestTypeOneArg) { | 227 if (test_kind == kTestTypeOneArg) { |
| 225 ASSERT(type_arguments_reg == kNoRegister); | 228 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
| 226 __ LoadObject(R1, Object::null_object()); | 229 ASSERT(function_type_arguments_reg == kNoRegister); |
| 227 __ BranchLink(*StubCode::Subtype1TestCache_entry()); | 230 __ BranchLink(*StubCode::Subtype1TestCache_entry()); |
| 228 } else if (test_kind == kTestTypeTwoArgs) { | 231 } else if (test_kind == kTestTypeTwoArgs) { |
| 229 ASSERT(type_arguments_reg == kNoRegister); | 232 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
| 230 __ LoadObject(R1, Object::null_object()); | 233 ASSERT(function_type_arguments_reg == kNoRegister); |
| 231 __ BranchLink(*StubCode::Subtype2TestCache_entry()); | 234 __ BranchLink(*StubCode::Subtype2TestCache_entry()); |
| 232 } else if (test_kind == kTestTypeThreeArgs) { | 235 } else if (test_kind == kTestTypeFourArgs) { |
| 233 ASSERT(type_arguments_reg == R1); | 236 ASSERT(instantiator_type_arguments_reg == R1); |
| 234 __ BranchLink(*StubCode::Subtype3TestCache_entry()); | 237 ASSERT(function_type_arguments_reg == R2); |
| 238 __ BranchLink(*StubCode::Subtype4TestCache_entry()); | |
| 235 } else { | 239 } else { |
| 236 UNREACHABLE(); | 240 UNREACHABLE(); |
| 237 } | 241 } |
| 238 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. | 242 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. |
| 239 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); | 243 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); |
| 240 return type_test_cache.raw(); | 244 return type_test_cache.raw(); |
| 241 } | 245 } |
| 242 | 246 |
| 243 | 247 |
| 244 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 248 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 245 // type test is conclusive, otherwise fallthrough if a type test could not | 249 // type test is conclusive, otherwise fallthrough if a type test could not |
| 246 // be completed. | 250 // be completed. |
| 247 // R0: instance being type checked (preserved). | 251 // R0: instance being type checked (preserved). |
| 248 // Clobbers R2. | 252 // Clobbers R1, R2. |
| 249 RawSubtypeTestCache* | 253 RawSubtypeTestCache* |
| 250 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 254 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 251 TokenPosition token_pos, | 255 TokenPosition token_pos, |
| 252 const AbstractType& type, | 256 const AbstractType& type, |
| 253 Label* is_instance_lbl, | 257 Label* is_instance_lbl, |
| 254 Label* is_not_instance_lbl) { | 258 Label* is_not_instance_lbl) { |
| 255 __ Comment("InstantiatedTypeWithArgumentsTest"); | 259 __ Comment("InstantiatedTypeWithArgumentsTest"); |
| 256 ASSERT(type.IsInstantiated()); | 260 ASSERT(type.IsInstantiated()); |
| 257 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); | 261 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
| 258 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); | 262 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 302 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 306 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
| 303 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 307 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
| 304 // Instance class test only necessary. | 308 // Instance class test only necessary. |
| 305 return GenerateSubtype1TestCacheLookup( | 309 return GenerateSubtype1TestCacheLookup( |
| 306 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 310 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
| 307 } | 311 } |
| 308 } | 312 } |
| 309 } | 313 } |
| 310 } | 314 } |
| 311 // Regular subtype test cache involving instance's type arguments. | 315 // Regular subtype test cache involving instance's type arguments. |
| 312 const Register kTypeArgumentsReg = kNoRegister; | 316 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 317 const Register kFunctionTypeArgumentsReg = kNoRegister; | |
| 313 const Register kTempReg = kNoRegister; | 318 const Register kTempReg = kNoRegister; |
| 314 // R0: instance (must be preserved). | 319 // R0: instance (must be preserved). |
| 315 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, | 320 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
| 316 kTypeArgumentsReg, kTempReg, | 321 kInstantiatorTypeArgumentsReg, |
| 322 kFunctionTypeArgumentsReg, kTempReg, | |
| 317 is_instance_lbl, is_not_instance_lbl); | 323 is_instance_lbl, is_not_instance_lbl); |
| 318 } | 324 } |
| 319 | 325 |
| 320 | 326 |
| 321 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 327 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
| 322 const GrowableArray<intptr_t>& class_ids, | 328 const GrowableArray<intptr_t>& class_ids, |
| 323 Label* is_equal_lbl, | 329 Label* is_equal_lbl, |
| 324 Label* is_not_equal_lbl) { | 330 Label* is_not_equal_lbl) { |
| 325 for (intptr_t i = 0; i < class_ids.length(); i++) { | 331 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 326 __ CompareImmediate(class_id_reg, class_ids[i]); | 332 __ CompareImmediate(class_id_reg, class_ids[i]); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 393 __ CompareImmediate(kClassIdReg, type_class.id()); | 399 __ CompareImmediate(kClassIdReg, type_class.id()); |
| 394 __ b(is_instance_lbl, EQ); | 400 __ b(is_instance_lbl, EQ); |
| 395 } | 401 } |
| 396 // Otherwise fallthrough. | 402 // Otherwise fallthrough. |
| 397 return true; | 403 return true; |
| 398 } | 404 } |
| 399 | 405 |
| 400 | 406 |
| 401 // Uses SubtypeTestCache to store instance class and result. | 407 // Uses SubtypeTestCache to store instance class and result. |
| 402 // R0: instance to test. | 408 // R0: instance to test. |
| 403 // Clobbers R1-R4,R9. | 409 // Clobbers R1-R4, R8, R9. |
| 404 // Immediate class test already done. | 410 // Immediate class test already done. |
| 405 // TODO(srdjan): Implement a quicker subtype check, as type test | 411 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 406 // arrays can grow too high, but they may be useful when optimizing | 412 // arrays can grow too high, but they may be useful when optimizing |
| 407 // code (type-feedback). | 413 // code (type-feedback). |
| 408 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 414 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
| 409 TokenPosition token_pos, | 415 TokenPosition token_pos, |
| 410 const Class& type_class, | 416 const Class& type_class, |
| 411 Label* is_instance_lbl, | 417 Label* is_instance_lbl, |
| 412 Label* is_not_instance_lbl) { | 418 Label* is_not_instance_lbl) { |
| 413 __ Comment("Subtype1TestCacheLookup"); | 419 __ Comment("Subtype1TestCacheLookup"); |
| 414 const Register kInstanceReg = R0; | 420 const Register kInstanceReg = R0; |
| 415 __ LoadClass(R1, kInstanceReg, R2); | 421 __ LoadClass(R1, kInstanceReg, R2); |
| 416 // R1: instance class. | 422 // R1: instance class. |
| 417 // Check immediate superclass equality. | 423 // Check immediate superclass equality. |
| 418 __ ldr(R2, FieldAddress(R1, Class::super_type_offset())); | 424 __ ldr(R2, FieldAddress(R1, Class::super_type_offset())); |
| 419 __ ldr(R2, FieldAddress(R2, Type::type_class_id_offset())); | 425 __ ldr(R2, FieldAddress(R2, Type::type_class_id_offset())); |
| 420 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); | 426 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); |
| 421 __ b(is_instance_lbl, EQ); | 427 __ b(is_instance_lbl, EQ); |
| 422 | 428 |
| 423 const Register kTypeArgumentsReg = kNoRegister; | 429 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 430 const Register kFunctionTypeArgumentsReg = kNoRegister; | |
| 424 const Register kTempReg = kNoRegister; | 431 const Register kTempReg = kNoRegister; |
| 425 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, | 432 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
| 426 kTypeArgumentsReg, kTempReg, | 433 kInstantiatorTypeArgumentsReg, |
| 434 kFunctionTypeArgumentsReg, kTempReg, | |
| 427 is_instance_lbl, is_not_instance_lbl); | 435 is_instance_lbl, is_not_instance_lbl); |
| 428 } | 436 } |
| 429 | 437 |
| 430 | 438 |
| 431 // Generates inlined check if 'type' is a type parameter or type itself | 439 // Generates inlined check if 'type' is a type parameter or type itself |
| 432 // R0: instance (preserved). | 440 // R0: instance (preserved). |
| 433 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 441 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 434 TokenPosition token_pos, | 442 TokenPosition token_pos, |
| 435 const AbstractType& type, | 443 const AbstractType& type, |
| 436 Label* is_instance_lbl, | 444 Label* is_instance_lbl, |
| 437 Label* is_not_instance_lbl) { | 445 Label* is_not_instance_lbl) { |
| 438 __ Comment("UninstantiatedTypeTest"); | 446 __ Comment("UninstantiatedTypeTest"); |
| 439 ASSERT(!type.IsInstantiated()); | 447 ASSERT(!type.IsInstantiated()); |
| 440 // Skip check if destination is a dynamic type. | 448 // Skip check if destination is a dynamic type. |
| 441 if (type.IsTypeParameter()) { | 449 if (type.IsTypeParameter()) { |
| 442 const TypeParameter& type_param = TypeParameter::Cast(type); | 450 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 443 // Load instantiator type arguments on stack. | 451 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
|
zra
2017/04/07 17:36:29
Could you use an ldm that doesn't adjust SP?
regis
2017/04/11 04:23:07
I'd prefer now, as I would need to renumber the re
| |
| 444 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. | 452 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. |
| 445 // R1: instantiator type arguments. | 453 // R1: instantiator type arguments. |
| 454 // R2: function type arguments. | |
| 455 const Register kTypeArgumentsReg = | |
| 456 type_param.IsClassTypeParameter() ? R1 : R2; | |
| 446 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 457 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 447 __ CompareObject(R1, Object::null_object()); | 458 __ CompareObject(kTypeArgumentsReg, Object::null_object()); |
| 448 __ b(is_instance_lbl, EQ); | 459 __ b(is_instance_lbl, EQ); |
| 449 __ ldr(R2, | 460 __ ldr(R3, FieldAddress(kTypeArgumentsReg, |
| 450 FieldAddress(R1, TypeArguments::type_at_offset(type_param.index()))); | 461 TypeArguments::type_at_offset(type_param.index()))); |
| 451 // R2: concrete type of type. | 462 // R3: concrete type of type. |
| 452 // Check if type argument is dynamic. | 463 // Check if type argument is dynamic. |
| 453 __ CompareObject(R2, Object::dynamic_type()); | 464 __ CompareObject(R3, Object::dynamic_type()); |
| 454 __ b(is_instance_lbl, EQ); | 465 __ b(is_instance_lbl, EQ); |
| 455 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); | 466 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::ObjectType())); |
| 456 __ b(is_instance_lbl, EQ); | 467 __ b(is_instance_lbl, EQ); |
| 468 // TODO(regis): Optimize void type as well once allowed as type argument. | |
| 457 | 469 |
| 458 // For Smi check quickly against int and num interfaces. | 470 // For Smi check quickly against int and num interfaces. |
| 459 Label not_smi; | 471 Label not_smi; |
| 460 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi? | 472 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi? |
| 461 __ b(¬_smi, NE); | 473 __ b(¬_smi, NE); |
| 462 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType())); | 474 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::IntType())); |
| 463 __ b(is_instance_lbl, EQ); | 475 __ b(is_instance_lbl, EQ); |
| 464 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number())); | 476 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number())); |
| 465 __ b(is_instance_lbl, EQ); | 477 __ b(is_instance_lbl, EQ); |
| 466 // Smi must be handled in runtime. | 478 // Smi must be handled in runtime. |
| 467 Label fall_through; | 479 Label fall_through; |
| 468 __ b(&fall_through); | 480 __ b(&fall_through); |
| 469 | 481 |
| 470 __ Bind(¬_smi); | 482 __ Bind(¬_smi); |
| 483 // R0: instance. | |
| 471 // R1: instantiator type arguments. | 484 // R1: instantiator type arguments. |
| 472 // R0: instance. | 485 // R2: function type arguments. |
| 473 const Register kInstanceReg = R0; | 486 const Register kInstanceReg = R0; |
| 474 const Register kTypeArgumentsReg = R1; | 487 const Register kInstantiatorTypeArgumentsReg = R1; |
| 488 const Register kFunctionTypeArgumentsReg = R2; | |
| 475 const Register kTempReg = kNoRegister; | 489 const Register kTempReg = kNoRegister; |
| 476 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( | 490 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
| 477 zone(), GenerateCallSubtypeTestStub( | 491 zone(), GenerateCallSubtypeTestStub( |
| 478 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, | 492 kTestTypeFourArgs, kInstanceReg, |
| 493 kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, | |
| 479 kTempReg, is_instance_lbl, is_not_instance_lbl)); | 494 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
| 480 __ Bind(&fall_through); | 495 __ Bind(&fall_through); |
| 481 return type_test_cache.raw(); | 496 return type_test_cache.raw(); |
| 482 } | 497 } |
| 483 if (type.IsType()) { | 498 if (type.IsType()) { |
| 484 const Register kInstanceReg = R0; | 499 const Register kInstanceReg = R0; |
| 485 const Register kTypeArgumentsReg = R1; | 500 const Register kInstantiatorTypeArgumentsReg = R1; |
| 501 const Register kFunctionTypeArgumentsReg = R2; | |
| 486 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi? | 502 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi? |
| 487 __ b(is_not_instance_lbl, EQ); | 503 __ b(is_not_instance_lbl, EQ); |
| 488 __ ldr(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args. | 504 __ ldr(kInstantiatorTypeArgumentsReg, Address(SP, 1 * kWordSize)); |
|
zra
2017/04/07 17:36:30
ditto if these are adjacent registers.
regis
2017/04/11 04:23:07
ditto
| |
| 505 __ ldr(kFunctionTypeArgumentsReg, Address(SP, 0 * kWordSize)); | |
| 489 // Uninstantiated type class is known at compile time, but the type | 506 // Uninstantiated type class is known at compile time, but the type |
| 490 // arguments are determined at runtime by the instantiator. | 507 // arguments are determined at runtime by the instantiator(s). |
| 491 const Register kTempReg = kNoRegister; | 508 const Register kTempReg = kNoRegister; |
| 492 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, | 509 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, |
| 493 kTypeArgumentsReg, kTempReg, | 510 kInstantiatorTypeArgumentsReg, |
| 511 kFunctionTypeArgumentsReg, kTempReg, | |
| 494 is_instance_lbl, is_not_instance_lbl); | 512 is_instance_lbl, is_not_instance_lbl); |
| 495 } | 513 } |
| 496 return SubtypeTestCache::null(); | 514 return SubtypeTestCache::null(); |
| 497 } | 515 } |
| 498 | 516 |
| 499 | 517 |
| 500 // Inputs: | 518 // Inputs: |
| 501 // - R0: instance being type checked (preserved). | 519 // - R0: instance being type checked (preserved). |
| 502 // - R1: optional instantiator type arguments (preserved). | 520 // - R1: optional instantiator type arguments (preserved). |
| 503 // Clobbers R2, R3. | 521 // - R2: optional function type arguments (preserved). |
| 522 // Clobbers R3, R4, R8, R9. | |
| 504 // Returns: | 523 // Returns: |
| 505 // - preserved instance in R0 and optional instantiator type arguments in R1. | 524 // - preserved instance in R0, optional instantiator type arguments in R1, and |
| 525 // optional function type arguments in R2. | |
| 506 // Note that this inlined code must be followed by the runtime_call code, as it | 526 // Note that this inlined code must be followed by the runtime_call code, as it |
| 507 // may fall through to it. Otherwise, this inline code will jump to the label | 527 // may fall through to it. Otherwise, this inline code will jump to the label |
| 508 // is_instance or to the label is_not_instance. | 528 // is_instance or to the label is_not_instance. |
| 509 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 529 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
| 510 TokenPosition token_pos, | 530 TokenPosition token_pos, |
| 511 const AbstractType& type, | 531 const AbstractType& type, |
| 512 Label* is_instance_lbl, | 532 Label* is_instance_lbl, |
| 513 Label* is_not_instance_lbl) { | 533 Label* is_not_instance_lbl) { |
| 514 __ Comment("InlineInstanceof"); | 534 __ Comment("InlineInstanceof"); |
| 515 if (type.IsVoidType()) { | 535 if (type.IsVoidType()) { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 544 | 564 |
| 545 | 565 |
| 546 // If instanceof type test cannot be performed successfully at compile time and | 566 // If instanceof type test cannot be performed successfully at compile time and |
| 547 // therefore eliminated, optimize it by adding inlined tests for: | 567 // therefore eliminated, optimize it by adding inlined tests for: |
| 548 // - NULL -> return type == Null (type is not Object or dynamic). | 568 // - NULL -> return type == Null (type is not Object or dynamic). |
| 549 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 569 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 550 // - Class equality (only if class is not parameterized). | 570 // - Class equality (only if class is not parameterized). |
| 551 // Inputs: | 571 // Inputs: |
| 552 // - R0: object. | 572 // - R0: object. |
| 553 // - R1: instantiator type arguments or raw_null. | 573 // - R1: instantiator type arguments or raw_null. |
| 574 // - R2: function type arguments or raw_null. | |
| 554 // Returns: | 575 // Returns: |
| 555 // - true or false in R0. | 576 // - true or false in R0. |
| 556 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, | 577 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
| 557 intptr_t deopt_id, | 578 intptr_t deopt_id, |
| 558 const AbstractType& type, | 579 const AbstractType& type, |
| 559 LocationSummary* locs) { | 580 LocationSummary* locs) { |
| 560 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); | 581 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
| 561 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); | 582 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); |
| 562 | 583 |
| 563 // Preserve instantiator type arguments (R1). | 584 __ Push(R1); // Store instantiator type arguments. |
|
zra
2017/04/07 17:36:30
PushList
regis
2017/04/11 04:23:07
Added TODO.
| |
| 564 __ Push(R1); | 585 __ Push(R2); // Store function type arguments. |
| 565 | 586 |
| 566 Label is_instance, is_not_instance; | 587 Label is_instance, is_not_instance; |
| 567 // If type is instantiated and non-parameterized, we can inline code | 588 // If type is instantiated and non-parameterized, we can inline code |
| 568 // checking whether the tested instance is a Smi. | 589 // checking whether the tested instance is a Smi. |
| 569 if (type.IsInstantiated()) { | 590 if (type.IsInstantiated()) { |
| 570 // A null object is only an instance of Null, Object, and dynamic. | 591 // A null object is only an instance of Null, Object, and dynamic. |
| 571 // Object and dynamic have already been checked above (if the type is | 592 // Object and dynamic have already been checked above (if the type is |
| 572 // instantiated). So we can return false here if the instance is null, | 593 // instantiated). So we can return false here if the instance is null, |
| 573 // unless the type is Null (and if the type is instantiated). | 594 // unless the type is Null (and if the type is instantiated). |
| 574 // We can only inline this null check if the type is instantiated at compile | 595 // We can only inline this null check if the type is instantiated at compile |
| 575 // time, since an uninstantiated type at compile time could be Null, Object, | 596 // time, since an uninstantiated type at compile time could be Null, Object, |
| 576 // or dynamic at run time. | 597 // or dynamic at run time. |
| 577 __ CompareObject(R0, Object::null_object()); | 598 __ CompareObject(R0, Object::null_object()); |
| 578 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); | 599 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); |
| 579 } | 600 } |
| 580 | 601 |
| 581 // Generate inline instanceof test. | 602 // Generate inline instanceof test. |
| 582 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 603 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 583 test_cache = | 604 test_cache = |
| 584 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); | 605 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
| 585 | 606 |
| 586 // test_cache is null if there is no fall-through. | 607 // test_cache is null if there is no fall-through. |
| 587 Label done; | 608 Label done; |
| 588 if (!test_cache.IsNull()) { | 609 if (!test_cache.IsNull()) { |
| 589 // Generate runtime call. | 610 // Generate runtime call. |
| 590 // Load instantiator type arguments (R1). | 611 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
|
zra
2017/04/07 17:36:30
ldm?
regis
2017/04/11 04:23:07
ditto
| |
| 591 __ ldr(R1, Address(SP, 0 * kWordSize)); | 612 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. |
| 592 __ PushObject(Object::null_object()); // Make room for the result. | 613 __ PushObject(Object::null_object()); // Make room for the result. |
| 593 __ Push(R0); // Push the instance. | 614 __ Push(R0); // Push the instance. |
| 594 __ PushObject(type); // Push the type. | 615 __ PushObject(type); // Push the type. |
| 595 __ Push(R1); // Push instantiator type arguments (R1). | 616 __ Push(R1); // Instantiator type arguments. |
|
zra
2017/04/07 17:36:30
PushList
regis
2017/04/11 04:23:07
ditto
| |
| 617 __ Push(R2); // Function type arguments. | |
| 596 __ LoadUniqueObject(R0, test_cache); | 618 __ LoadUniqueObject(R0, test_cache); |
| 597 __ Push(R0); | 619 __ Push(R0); |
| 598 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); | 620 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); |
| 599 // Pop the parameters supplied to the runtime entry. The result of the | 621 // Pop the parameters supplied to the runtime entry. The result of the |
| 600 // instanceof runtime call will be left as the result of the operation. | 622 // instanceof runtime call will be left as the result of the operation. |
| 601 __ Drop(4); | 623 __ Drop(5); |
| 602 __ Pop(R0); | 624 __ Pop(R0); |
| 603 __ b(&done); | 625 __ b(&done); |
| 604 } | 626 } |
| 605 __ Bind(&is_not_instance); | 627 __ Bind(&is_not_instance); |
| 606 __ LoadObject(R0, Bool::Get(false)); | 628 __ LoadObject(R0, Bool::Get(false)); |
| 607 __ b(&done); | 629 __ b(&done); |
| 608 | 630 |
| 609 __ Bind(&is_instance); | 631 __ Bind(&is_instance); |
| 610 __ LoadObject(R0, Bool::Get(true)); | 632 __ LoadObject(R0, Bool::Get(true)); |
| 611 __ Bind(&done); | 633 __ Bind(&done); |
| 612 // Remove instantiator type arguments (R1). | 634 // Remove instantiator type arguments and function type arguments. |
| 613 __ Drop(1); | 635 __ Drop(2); |
| 614 } | 636 } |
| 615 | 637 |
| 616 | 638 |
| 617 // Optimize assignable type check by adding inlined tests for: | 639 // Optimize assignable type check by adding inlined tests for: |
| 618 // - NULL -> return NULL. | 640 // - NULL -> return NULL. |
| 619 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 641 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 620 // - Class equality (only if class is not parameterized). | 642 // - Class equality (only if class is not parameterized). |
| 621 // Inputs: | 643 // Inputs: |
| 622 // - R0: instance being type checked. | 644 // - R0: instance being type checked. |
| 623 // - R1: instantiator type arguments or raw_null. | 645 // - R1: instantiator type arguments or raw_null. |
| 646 // - R2: function type arguments or raw_null. | |
| 624 // Returns: | 647 // Returns: |
| 625 // - object in R0 for successful assignable check (or throws TypeError). | 648 // - object in R0 for successful assignable check (or throws TypeError). |
| 626 // Performance notes: positive checks must be quick, negative checks can be slow | 649 // Performance notes: positive checks must be quick, negative checks can be slow |
| 627 // as they throw an exception. | 650 // as they throw an exception. |
| 628 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, | 651 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
| 629 intptr_t deopt_id, | 652 intptr_t deopt_id, |
| 630 const AbstractType& dst_type, | 653 const AbstractType& dst_type, |
| 631 const String& dst_name, | 654 const String& dst_name, |
| 632 LocationSummary* locs) { | 655 LocationSummary* locs) { |
| 633 ASSERT(!token_pos.IsClassifying()); | 656 ASSERT(!token_pos.IsClassifying()); |
| 634 ASSERT(!dst_type.IsNull()); | 657 ASSERT(!dst_type.IsNull()); |
| 635 ASSERT(dst_type.IsFinalized()); | 658 ASSERT(dst_type.IsFinalized()); |
| 636 // Assignable check is skipped in FlowGraphBuilder, not here. | 659 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 637 ASSERT(dst_type.IsMalformedOrMalbounded() || | 660 ASSERT(dst_type.IsMalformedOrMalbounded() || |
| 638 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 661 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 639 // Preserve instantiator type arguments (R1). | 662 __ Push(R1); // Store instantiator type arguments. |
|
zra
2017/04/07 17:36:29
PushList
regis
2017/04/11 04:23:07
ditto
| |
| 640 __ Push(R1); | 663 __ Push(R2); // Store function type arguments. |
| 641 // A null object is always assignable and is returned as result. | 664 // A null object is always assignable and is returned as result. |
| 642 Label is_assignable, runtime_call; | 665 Label is_assignable, runtime_call; |
| 643 __ CompareObject(R0, Object::null_object()); | 666 __ CompareObject(R0, Object::null_object()); |
| 644 __ b(&is_assignable, EQ); | 667 __ b(&is_assignable, EQ); |
| 645 | 668 |
| 646 // Generate throw new TypeError() if the type is malformed or malbounded. | 669 // Generate throw new TypeError() if the type is malformed or malbounded. |
| 647 if (dst_type.IsMalformedOrMalbounded()) { | 670 if (dst_type.IsMalformedOrMalbounded()) { |
| 648 __ PushObject(Object::null_object()); // Make room for the result. | 671 __ PushObject(Object::null_object()); // Make room for the result. |
| 649 __ Push(R0); // Push the source object. | 672 __ Push(R0); // Push the source object. |
| 650 __ PushObject(dst_name); // Push the name of the destination. | 673 __ PushObject(dst_name); // Push the name of the destination. |
| 651 __ PushObject(dst_type); // Push the type of the destination. | 674 __ PushObject(dst_type); // Push the type of the destination. |
| 652 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, | 675 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
| 653 locs); | 676 locs); |
| 654 // We should never return here. | 677 // We should never return here. |
| 655 __ bkpt(0); | 678 __ bkpt(0); |
| 656 | 679 |
| 657 __ Bind(&is_assignable); // For a null object. | 680 __ Bind(&is_assignable); // For a null object. |
| 658 // Restore instantiator type arguments (R1). | 681 __ Pop(R2); // Remove pushed function type arguments. |
|
zra
2017/04/07 17:36:29
PopList
regis
2017/04/11 04:23:07
ditto
| |
| 659 __ Pop(R1); | 682 __ Pop(R1); // Remove pushed instantiator type arguments. |
| 660 return; | 683 return; |
| 661 } | 684 } |
| 662 | 685 |
| 663 // Generate inline type check, linking to runtime call if not assignable. | 686 // Generate inline type check, linking to runtime call if not assignable. |
| 664 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 687 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 665 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, | 688 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
| 666 &runtime_call); | 689 &runtime_call); |
| 667 | 690 |
| 668 __ Bind(&runtime_call); | 691 __ Bind(&runtime_call); |
| 669 // Load instantiator type arguments (R1). | 692 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
|
zra
2017/04/07 17:36:29
ldm?
regis
2017/04/11 04:23:07
ditto
| |
| 670 __ ldr(R1, Address(SP, 0 * kWordSize)); | 693 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. |
| 671 __ PushObject(Object::null_object()); // Make room for the result. | 694 __ PushObject(Object::null_object()); // Make room for the result. |
| 672 __ Push(R0); // Push the source object. | 695 __ Push(R0); // Push the source object. |
| 673 __ PushObject(dst_type); // Push the type of the destination. | 696 __ PushObject(dst_type); // Push the type of the destination. |
| 674 __ Push(R1); // Push instantiator type arguments (R1). | 697 __ Push(R1); // Instantiator type arguments. |
|
zra
2017/04/07 17:36:30
PushList
regis
2017/04/11 04:23:07
ditto
| |
| 675 __ PushObject(dst_name); // Push the name of the destination. | 698 __ Push(R2); // Function type arguments. |
| 699 __ PushObject(dst_name); // Push the name of the destination. | |
| 676 __ LoadUniqueObject(R0, test_cache); | 700 __ LoadUniqueObject(R0, test_cache); |
| 677 __ Push(R0); | 701 __ Push(R0); |
| 678 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 702 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
| 679 // Pop the parameters supplied to the runtime entry. The result of the | 703 // Pop the parameters supplied to the runtime entry. The result of the |
| 680 // type check runtime call is the checked value. | 704 // type check runtime call is the checked value. |
| 681 __ Drop(5); | 705 __ Drop(6); |
| 682 __ Pop(R0); | 706 __ Pop(R0); |
| 683 | 707 |
| 684 __ Bind(&is_assignable); | 708 __ Bind(&is_assignable); |
| 685 // Restore instantiator type arguments (R1). | 709 __ Pop(R2); // Remove pushed function type arguments. |
|
zra
2017/04/07 17:36:30
PopList
regis
2017/04/11 04:23:07
ditto
| |
| 686 __ Pop(R1); | 710 __ Pop(R1); // Remove pushed instantiator type arguments. |
| 687 } | 711 } |
| 688 | 712 |
| 689 | 713 |
| 690 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 714 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
| 691 if (is_optimizing()) { | 715 if (is_optimizing()) { |
| 692 return; | 716 return; |
| 693 } | 717 } |
| 694 Definition* defn = instr->AsDefinition(); | 718 Definition* defn = instr->AsDefinition(); |
| 695 if ((defn != NULL) && defn->HasTemp()) { | 719 if ((defn != NULL) && defn->HasTemp()) { |
| 696 __ Push(defn->locs()->out(0).reg()); | 720 __ Push(defn->locs()->out(0).reg()); |
| (...skipping 1192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1889 DRegister dreg = EvenDRegisterOf(reg); | 1913 DRegister dreg = EvenDRegisterOf(reg); |
| 1890 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); | 1914 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); |
| 1891 } | 1915 } |
| 1892 | 1916 |
| 1893 | 1917 |
| 1894 #undef __ | 1918 #undef __ |
| 1895 | 1919 |
| 1896 } // namespace dart | 1920 } // namespace dart |
| 1897 | 1921 |
| 1898 #endif // defined TARGET_ARCH_ARM | 1922 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |