@@ -188,7 +188,15 @@ void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
188
188
__ Bind (&fall_through);
189
189
}
190
190
191
- // Clobbers RCX.
191
+ // Call stub to perform subtype test using a cache (see
192
+ // stub_code_x64.cc:GenerateSubtypeNTestCacheStub)
193
+ //
194
+ // Inputs:
195
+ // - RAX : instance to test against.
196
+ // - RDX : instantiator type arguments (if necessary).
197
+ // - RCX : function type arguments (if necessary).
198
+ //
199
+ // Preserves RAX/RCX/RDX.
192
200
RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub (
193
201
TypeTestStubKind test_kind,
194
202
Register instance_reg,
@@ -197,37 +205,27 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
197
205
Register temp_reg,
198
206
Label* is_instance_lbl,
199
207
Label* is_not_instance_lbl) {
208
+ ASSERT (temp_reg == kNoRegister );
200
209
const SubtypeTestCache& type_test_cache =
201
210
SubtypeTestCache::ZoneHandle (zone (), SubtypeTestCache::New ());
202
- __ LoadUniqueObject (temp_reg, type_test_cache);
203
- __ pushq (temp_reg); // Subtype test cache.
204
- __ pushq (instance_reg); // Instance.
211
+ __ LoadUniqueObject (R9, type_test_cache);
205
212
if (test_kind == kTestTypeOneArg ) {
206
213
ASSERT (instantiator_type_arguments_reg == kNoRegister );
207
214
ASSERT (function_type_arguments_reg == kNoRegister );
208
- __ PushObject (Object::null_object ()); // Unused instantiator type args.
209
- __ PushObject (Object::null_object ()); // Unused function type args.
210
215
__ Call (*StubCode::Subtype1TestCache_entry ());
211
216
} else if (test_kind == kTestTypeTwoArgs ) {
212
217
ASSERT (instantiator_type_arguments_reg == kNoRegister );
213
218
ASSERT (function_type_arguments_reg == kNoRegister );
214
- __ PushObject (Object::null_object ()); // Unused instantiator type args.
215
- __ PushObject (Object::null_object ()); // Unused function type args.
216
219
__ Call (*StubCode::Subtype2TestCache_entry ());
217
220
} else if (test_kind == kTestTypeFourArgs ) {
218
- __ pushq ( instantiator_type_arguments_reg);
219
- __ pushq ( function_type_arguments_reg);
221
+ ASSERT (RDX == instantiator_type_arguments_reg);
222
+ ASSERT (RCX == function_type_arguments_reg);
220
223
__ Call (*StubCode::Subtype4TestCache_entry ());
221
224
} else {
222
225
UNREACHABLE ();
223
226
}
224
- // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
225
- ASSERT (instance_reg != RCX);
226
- ASSERT (temp_reg != RCX);
227
- __ Drop (2 );
228
- __ popq (instance_reg); // Restore receiver.
229
- __ popq (temp_reg); // Discard.
230
- GenerateBoolToJump (RCX, is_instance_lbl, is_not_instance_lbl);
227
+ // Result is in R8: null -> not found, otherwise Bool::True or Bool::False.
228
+ GenerateBoolToJump (R8, is_instance_lbl, is_not_instance_lbl);
231
229
return type_test_cache.raw ();
232
230
}
233
231
@@ -301,7 +299,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
301
299
// Regular subtype test cache involving instance's type arguments.
302
300
const Register kInstantiatorTypeArgumentsReg = kNoRegister ;
303
301
const Register kFunctionTypeArgumentsReg = kNoRegister ;
304
- const Register kTempReg = R10 ;
302
+ const Register kTempReg = kNoRegister ;
305
303
return GenerateCallSubtypeTestStub (kTestTypeTwoArgs , kInstanceReg ,
306
304
kInstantiatorTypeArgumentsReg ,
307
305
kFunctionTypeArgumentsReg , kTempReg ,
@@ -320,9 +318,13 @@ void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
320
318
}
321
319
322
320
// Testing against an instantiated type with no arguments, without
323
- // SubtypeTestCache.
324
- // RAX: instance to test against (preserved).
325
- // Clobbers R10, R13.
321
+ // SubtypeTestCache
322
+ //
323
+ // Inputs:
324
+ // - RAX : instance to test against
325
+ //
326
+ // Preserves RAX/RCX/RDX.
327
+ //
326
328
// Returns true if there is a fallthrough.
327
329
bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest (
328
330
TokenPosition token_pos,
@@ -387,9 +389,13 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
387
389
}
388
390
389
391
// Uses SubtypeTestCache to store instance class and result.
390
- // RAX: instance to test.
391
- // Clobbers R10, R13.
392
392
// Immediate class test already done.
393
+ //
394
+ // Inputs:
395
+ // RAX : instance to test against.
396
+ //
397
+ // Preserves RAX/RCX/RDX.
398
+ //
393
399
// TODO(srdjan): Implement a quicker subtype check, as type test
394
400
// arrays can grow too high, but they may be useful when optimizing
395
401
// code (type-feedback).
@@ -410,28 +416,35 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
410
416
411
417
const Register kInstantiatorTypeArgumentsReg = kNoRegister ;
412
418
const Register kFunctionTypeArgumentsReg = kNoRegister ;
413
- const Register kTempReg = R10 ;
419
+ const Register kTempReg = kNoRegister ;
414
420
return GenerateCallSubtypeTestStub (kTestTypeOneArg , kInstanceReg ,
415
421
kInstantiatorTypeArgumentsReg ,
416
422
kFunctionTypeArgumentsReg , kTempReg ,
417
423
is_instance_lbl, is_not_instance_lbl);
418
424
}
419
425
420
426
// Generates inlined check if 'type' is a type parameter or type itself
421
- // RAX: instance (preserved).
422
- // Clobbers RDI, RDX, R10.
427
+ //
428
+ // Inputs:
429
+ // - RAX : instance to test against.
430
+ // - RDX : instantiator type arguments (if necessary).
431
+ // - RCX : function type arguments (if necessary).
432
+ //
433
+ // Preserves RAX/RCX/RDX.
423
434
RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest (
424
435
TokenPosition token_pos,
425
436
const AbstractType& type,
426
437
Label* is_instance_lbl,
427
438
Label* is_not_instance_lbl) {
439
+ const Register kInstanceReg = RAX;
440
+ const Register kInstantiatorTypeArgumentsReg = RDX;
441
+ const Register kFunctionTypeArgumentsReg = RCX;
442
+ const Register kTempReg = kNoRegister ;
428
443
__ Comment (" UninstantiatedTypeTest" );
429
444
ASSERT (!type.IsInstantiated ());
430
445
// Skip check if destination is a dynamic type.
431
446
if (type.IsTypeParameter ()) {
432
447
const TypeParameter& type_param = TypeParameter::Cast (type);
433
- __ movq (RDX, Address (RSP, 1 * kWordSize )); // Get instantiator type args.
434
- __ movq (RCX, Address (RSP, 0 * kWordSize )); // Get function type args.
435
448
// RDX: instantiator type arguments.
436
449
// RCX: function type arguments.
437
450
const Register kTypeArgumentsReg =
@@ -463,13 +476,6 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
463
476
__ jmp (&fall_through);
464
477
465
478
__ Bind (¬_smi);
466
- // RAX: instance.
467
- // RDX: instantiator type arguments.
468
- // RCX: function type arguments.
469
- const Register kInstanceReg = RAX;
470
- const Register kInstantiatorTypeArgumentsReg = RDX;
471
- const Register kFunctionTypeArgumentsReg = RCX;
472
- const Register kTempReg = R10;
473
479
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle (
474
480
zone (), GenerateCallSubtypeTestStub (
475
481
kTestTypeFourArgs , kInstanceReg ,
@@ -479,16 +485,10 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
479
485
return type_test_cache.raw ();
480
486
}
481
487
if (type.IsType ()) {
482
- const Register kInstanceReg = RAX;
483
- const Register kInstantiatorTypeArgumentsReg = RDX;
484
- const Register kFunctionTypeArgumentsReg = RCX;
485
488
__ testq (kInstanceReg , Immediate (kSmiTagMask )); // Is instance Smi?
486
489
__ j (ZERO, is_not_instance_lbl);
487
- __ movq (kInstantiatorTypeArgumentsReg , Address (RSP, 1 * kWordSize ));
488
- __ movq (kFunctionTypeArgumentsReg , Address (RSP, 0 * kWordSize ));
489
490
// Uninstantiated type class is known at compile time, but the type
490
491
// arguments are determined at runtime by the instantiator(s).
491
- const Register kTempReg = R10;
492
492
return GenerateCallSubtypeTestStub (kTestTypeFourArgs , kInstanceReg ,
493
493
kInstantiatorTypeArgumentsReg ,
494
494
kFunctionTypeArgumentsReg , kTempReg ,
@@ -498,13 +498,12 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
498
498
}
499
499
500
500
// Inputs:
501
- // - RAX: instance to test against (preserved).
502
- // - RDX: optional instantiator type arguments (preserved).
503
- // - RCX: optional function type arguments (preserved).
504
- // Clobbers R10, R13.
505
- // Returns:
506
- // - preserved instance in RAX, optional instantiator type arguments in RDX, and
507
- // optional function type arguments in RCX.
501
+ // - RAX : instance to test against.
502
+ // - RDX : instantiator type arguments.
503
+ // - RCX : function type arguments.
504
+ //
505
+ // Preserves RAX/RCX/RDX.
506
+ //
508
507
// Note that this inlined code must be followed by the runtime_call code, as it
509
508
// may fall through to it. Otherwise, this inline code will jump to the label
510
509
// is_instance or to the label is_not_instance.
@@ -557,9 +556,6 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
557
556
ASSERT (type.IsFinalized () && !type.IsMalformedOrMalbounded ());
558
557
ASSERT (!type.IsObjectType () && !type.IsDynamicType () && !type.IsVoidType ());
559
558
560
- __ pushq (RDX); // Store instantiator type arguments.
561
- __ pushq (RCX); // Store function type arguments.
562
-
563
559
Label is_instance, is_not_instance;
564
560
// If type is instantiated and non-parameterized, we can inline code
565
561
// checking whether the tested instance is a Smi.
@@ -577,15 +573,14 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
577
573
578
574
// Generate inline instanceof test.
579
575
SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle (zone ());
576
+ // The registers RAX, RCX, RDX are preserved across the call.
580
577
test_cache =
581
578
GenerateInlineInstanceof (token_pos, type, &is_instance, &is_not_instance);
582
579
583
580
// test_cache is null if there is no fall-through.
584
581
Label done;
585
582
if (!test_cache.IsNull ()) {
586
583
// Generate runtime call.
587
- __ movq (RDX, Address (RSP, 1 * kWordSize )); // Get instantiator type args.
588
- __ movq (RCX, Address (RSP, 0 * kWordSize )); // Get function type args.
589
584
__ PushObject (Object::null_object ()); // Make room for the result.
590
585
__ pushq (RAX); // Push the instance.
591
586
__ PushObject (type); // Push the type.
@@ -607,8 +602,6 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
607
602
__ Bind (&is_instance);
608
603
__ LoadObject (RAX, Bool::Get (true ));
609
604
__ Bind (&done);
610
- __ popq (RCX); // Remove pushed function type arguments.
611
- __ popq (RDX); // Remove pushed instantiator type arguments.
612
605
}
613
606
614
607
// Optimize assignable type check by adding inlined tests for:
@@ -635,8 +628,6 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
635
628
ASSERT (dst_type.IsMalformedOrMalbounded () ||
636
629
(!dst_type.IsDynamicType () && !dst_type.IsObjectType () &&
637
630
!dst_type.IsVoidType ()));
638
- __ pushq (RDX); // Store instantiator type arguments.
639
- __ pushq (RCX); // Store function type arguments.
640
631
// A null object is always assignable and is returned as result.
641
632
Label is_assignable, runtime_call;
642
633
__ CompareObject (RAX, Object::null_object ());
@@ -654,19 +645,16 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
654
645
__ int3 ();
655
646
656
647
__ Bind (&is_assignable); // For a null object.
657
- __ popq (RCX); // Remove pushed function type arguments.
658
- __ popq (RDX); // Remove pushed instantiator type arguments.
659
648
return ;
660
649
}
661
650
662
651
// Generate inline type check, linking to runtime call if not assignable.
663
652
SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle (zone ());
653
+ // The registers RAX, RCX, RDX are preserved across the call.
664
654
test_cache = GenerateInlineInstanceof (token_pos, dst_type, &is_assignable,
665
655
&runtime_call);
666
656
667
657
__ Bind (&runtime_call);
668
- __ movq (RDX, Address (RSP, 1 * kWordSize )); // Get instantiator type args.
669
- __ movq (RCX, Address (RSP, 0 * kWordSize )); // Get function type args.
670
658
__ PushObject (Object::null_object ()); // Make room for the result.
671
659
__ pushq (RAX); // Push the source object.
672
660
__ PushObject (dst_type); // Push the type of the destination.
@@ -682,8 +670,6 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
682
670
__ popq (RAX);
683
671
684
672
__ Bind (&is_assignable);
685
- __ popq (RCX); // Remove pushed function type arguments.
686
- __ popq (RDX); // Remove pushed instantiator type arguments.
687
673
}
688
674
689
675
void FlowGraphCompiler::EmitInstructionEpilogue (Instruction* instr) {
0 commit comments