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

Side by Side Diff: runtime/vm/flow_graph_compiler_arm.cc

Issue 2799373002: Pass a second type argument vector to all type instantiation calls in the VM. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_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
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
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
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(&not_smi, NE); 473 __ b(&not_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(&not_smi); 482 __ Bind(&not_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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698