Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 11ad25a

Browse files
creliercommit-bot@chromium.org
authored andcommitted
Reland "[VM runtime] Support Smi instances in type test cache."
This is a reland of 6ba3e55 The issue was that SlowTypeTestStub used in precompiled mode did not handle a Smi instance before calling the Subtype2TestCache stub which does not support it. See PatchSet 2 for the fix. Is there a more efficient solution? Original change's description: > [VM runtime] Support Smi instances in type test cache. > > This adds SubtypeTestCache-based optimizations for type tests against > * dst_type = FutureOr<T> (when T=int/num) > * dst_type = T (when T = FutureOr<int/num>) > > Remove dangerous LoadClass pseudo assembler instruction (does not work for Smi). > Handle instantiated void in type tests (along with dynamic and Object). > > Change-Id: I0df0fc72ff173b9464d16cc971969132b055a429 > Reviewed-on: https://dart-review.googlesource.com/c/81182 > Commit-Queue: Régis Crelier <regis@google.com> > Reviewed-by: Martin Kustermann <kustermann@google.com> Change-Id: I333ca47aebd7f0b663059ab6afc5d1cd8d7d5210 Reviewed-on: https://dart-review.googlesource.com/c/81320 Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
1 parent 3dc9119 commit 11ad25a

18 files changed

+150
-123
lines changed

runtime/vm/compiler/aot/precompiler.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ void Precompiler::AddConstObject(const Instance& instance) {
705705
return;
706706
}
707707

708-
// Can't ask immediate objects if they're canoncial.
708+
// Can't ask immediate objects if they're canonical.
709709
if (instance.IsSmi()) return;
710710

711711
// Some Instances in the ObjectPool aren't const objects, such as

runtime/vm/compiler/assembler/assembler_arm.cc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,12 +1825,6 @@ void Assembler::LoadClassById(Register result, Register class_id) {
18251825
ldr(result, Address(result, class_id, LSL, kSizeOfClassPairLog2));
18261826
}
18271827

1828-
void Assembler::LoadClass(Register result, Register object, Register scratch) {
1829-
ASSERT(scratch != result);
1830-
LoadClassId(scratch, object);
1831-
LoadClassById(result, scratch);
1832-
}
1833-
18341828
void Assembler::CompareClassId(Register object,
18351829
intptr_t class_id,
18361830
Register scratch) {

runtime/vm/compiler/assembler/assembler_arm.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,6 @@ class Assembler : public ValueObject {
860860

861861
void LoadClassId(Register result, Register object, Condition cond = AL);
862862
void LoadClassById(Register result, Register class_id);
863-
void LoadClass(Register result, Register object, Register scratch);
864863
void CompareClassId(Register object, intptr_t class_id, Register scratch);
865864
void LoadClassIdMayBeSmi(Register result, Register object);
866865
void LoadTaggedClassIdMayBeSmi(Register result, Register object);

runtime/vm/compiler/assembler/assembler_arm64.cc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,12 +1115,6 @@ void Assembler::LoadClassById(Register result, Register class_id) {
11151115
ldr(result, Address(result, class_id, UXTX, Address::Scaled));
11161116
}
11171117

1118-
void Assembler::LoadClass(Register result, Register object) {
1119-
ASSERT(object != TMP);
1120-
LoadClassId(TMP, object);
1121-
LoadClassById(result, TMP);
1122-
}
1123-
11241118
void Assembler::CompareClassId(Register object,
11251119
intptr_t class_id,
11261120
Register scratch) {

runtime/vm/compiler/assembler/assembler_arm64.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,6 @@ class Assembler : public ValueObject {
15311531
void LoadClassId(Register result, Register object);
15321532
// Overwrites class_id register (it will be tagged afterwards).
15331533
void LoadClassById(Register result, Register class_id);
1534-
void LoadClass(Register result, Register object);
15351534
void CompareClassId(Register object,
15361535
intptr_t class_id,
15371536
Register scratch = kNoRegister);

runtime/vm/compiler/assembler/assembler_ia32.cc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2434,12 +2434,6 @@ void Assembler::LoadClassById(Register result, Register class_id) {
24342434
movl(result, Address(result, class_id, TIMES_8, 0));
24352435
}
24362436

2437-
void Assembler::LoadClass(Register result, Register object, Register scratch) {
2438-
ASSERT(scratch != result);
2439-
LoadClassId(scratch, object);
2440-
LoadClassById(result, scratch);
2441-
}
2442-
24432437
void Assembler::CompareClassId(Register object,
24442438
intptr_t class_id,
24452439
Register scratch) {

runtime/vm/compiler/assembler/assembler_ia32.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,8 +666,6 @@ class Assembler : public ValueObject {
666666

667667
void LoadClassById(Register result, Register class_id);
668668

669-
void LoadClass(Register result, Register object, Register scratch);
670-
671669
void CompareClassId(Register object, intptr_t class_id, Register scratch);
672670

673671
void LoadClassIdMayBeSmi(Register result, Register object);

runtime/vm/compiler/assembler/assembler_x64.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,11 +1952,6 @@ void Assembler::LoadClassById(Register result, Register class_id) {
19521952
movq(result, Address(result, class_id, TIMES_8, 0));
19531953
}
19541954

1955-
void Assembler::LoadClass(Register result, Register object) {
1956-
LoadClassId(TMP, object);
1957-
LoadClassById(result, TMP);
1958-
}
1959-
19601955
void Assembler::CompareClassId(Register object,
19611956
intptr_t class_id,
19621957
Register scratch) {

runtime/vm/compiler/assembler/assembler_x64.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -782,8 +782,6 @@ class Assembler : public ValueObject {
782782
// Overwrites class_id register (it will be tagged afterwards).
783783
void LoadClassById(Register result, Register class_id);
784784

785-
void LoadClass(Register result, Register object);
786-
787785
void CompareClassId(Register object,
788786
intptr_t class_id,
789787
Register scratch = kNoRegister);

runtime/vm/compiler/backend/flow_graph_compiler_arm.cc

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,14 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
248248
ASSERT(type_class.NumTypeArguments() > 0);
249249
const Register kInstanceReg = R0;
250250
Error& bound_error = Error::Handle(zone());
251-
const Type& int_type = Type::Handle(zone(), Type::IntType());
251+
const Type& smi_type = Type::Handle(zone(), Type::SmiType());
252252
const bool smi_is_ok =
253-
int_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
253+
smi_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
254254
// Malformed type should have been handled at graph construction time.
255255
ASSERT(smi_is_ok || bound_error.IsNull());
256256
__ tst(kInstanceReg, Operand(kSmiTagMask));
257257
if (smi_is_ok) {
258+
// Fast case for type = FutureOr<int/num/top-type>.
258259
__ b(is_instance_lbl, EQ);
259260
} else {
260261
__ b(is_not_instance_lbl, EQ);
@@ -286,7 +287,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
286287
ASSERT(!tp_argument.IsMalformed());
287288
if (tp_argument.IsType()) {
288289
ASSERT(tp_argument.HasResolvedTypeClass());
289-
// Check if type argument is dynamic or Object.
290+
// Check if type argument is dynamic, Object, or void.
290291
const Type& object_type = Type::Handle(zone(), Type::ObjectType());
291292
if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) {
292293
// Instance class test only necessary.
@@ -341,6 +342,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
341342
if (smi_class.IsSubtypeOf(Object::null_type_arguments(), type_class,
342343
Object::null_type_arguments(), NULL, NULL,
343344
Heap::kOld)) {
345+
// Fast case for type = int/num/top-type.
344346
__ b(is_instance_lbl, EQ);
345347
} else {
346348
__ b(is_not_instance_lbl, EQ);
@@ -398,7 +400,14 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
398400
Label* is_not_instance_lbl) {
399401
__ Comment("Subtype1TestCacheLookup");
400402
const Register kInstanceReg = R0;
401-
__ LoadClass(R1, kInstanceReg, R2);
403+
#if defined(DEBUG)
404+
Label ok;
405+
__ BranchIfNotSmi(kInstanceReg, &ok);
406+
__ Breakpoint();
407+
__ Bind(&ok);
408+
#endif
409+
__ LoadClassId(R2, kInstanceReg);
410+
__ LoadClassById(R1, R2);
402411
// R1: instance class.
403412
// Check immediate superclass equality.
404413
__ ldr(R2, FieldAddress(R1, Class::super_type_offset()));
@@ -447,12 +456,13 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
447456
__ ldr(R3, FieldAddress(kTypeArgumentsReg,
448457
TypeArguments::type_at_offset(type_param.index())));
449458
// R3: concrete type of type.
450-
// Check if type argument is dynamic.
459+
// Check if type argument is dynamic, Object, or void.
451460
__ CompareObject(R3, Object::dynamic_type());
452461
__ b(is_instance_lbl, EQ);
453462
__ CompareObject(R3, Type::ZoneHandle(zone(), Type::ObjectType()));
454463
__ b(is_instance_lbl, EQ);
455-
// TODO(regis): Optimize void type as well once allowed as type argument.
464+
__ CompareObject(R3, Object::void_type());
465+
__ b(is_instance_lbl, EQ);
456466

457467
// For Smi check quickly against int and num interfaces.
458468
Label not_smi;
@@ -462,9 +472,8 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
462472
__ b(is_instance_lbl, EQ);
463473
__ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number()));
464474
__ b(is_instance_lbl, EQ);
465-
// Smi must be handled in runtime.
466-
Label fall_through;
467-
__ b(&fall_through);
475+
// Smi can be handled by type test cache.
476+
__ Bind(&not_smi);
468477

469478
// If it's guaranteed, by type-parameter bound, that the type parameter will
470479
// never have a value of a function type, then we can safely do a 4-type
@@ -474,17 +483,18 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
474483
? kTestTypeSixArgs
475484
: kTestTypeFourArgs;
476485

477-
__ Bind(&not_smi);
478486
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
479487
zone(), GenerateCallSubtypeTestStub(
480488
test_kind, kInstanceReg, kInstantiatorTypeArgumentsReg,
481489
kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
482490
is_not_instance_lbl));
483-
__ Bind(&fall_through);
484491
return type_test_cache.raw();
485492
}
486493
if (type.IsType()) {
487-
__ BranchIfSmi(kInstanceReg, is_not_instance_lbl);
494+
// Smi is FutureOr<T>, when T is a top type or int or num.
495+
if (!FLAG_strong || !Class::Handle(type.type_class()).IsFutureOrClass()) {
496+
__ BranchIfSmi(kInstanceReg, is_not_instance_lbl);
497+
}
488498
__ ldm(IA, SP,
489499
(1 << kFunctionTypeArgumentsReg) |
490500
(1 << kInstantiatorTypeArgumentsReg));

runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,12 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
243243
ASSERT(type_class.NumTypeArguments() > 0);
244244
const Register kInstanceReg = R0;
245245
Error& bound_error = Error::Handle(zone());
246-
const Type& int_type = Type::Handle(zone(), Type::IntType());
246+
const Type& smi_type = Type::Handle(zone(), Type::SmiType());
247247
const bool smi_is_ok =
248-
int_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
248+
smi_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
249249
// Malformed type should have been handled at graph construction time.
250250
ASSERT(smi_is_ok || bound_error.IsNull());
251+
// Fast case for type = FutureOr<int/num/top-type>.
251252
__ BranchIfSmi(kInstanceReg,
252253
smi_is_ok ? is_instance_lbl : is_not_instance_lbl);
253254

@@ -278,7 +279,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
278279
ASSERT(!tp_argument.IsMalformed());
279280
if (tp_argument.IsType()) {
280281
ASSERT(tp_argument.HasResolvedTypeClass());
281-
// Check if type argument is dynamic or Object.
282+
// Check if type argument is dynamic, Object, or void.
282283
const Type& object_type = Type::Handle(zone(), Type::ObjectType());
283284
if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) {
284285
// Instance class test only necessary.
@@ -331,6 +332,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
331332
if (smi_class.IsSubtypeOf(Object::null_type_arguments(), type_class,
332333
Object::null_type_arguments(), NULL, NULL,
333334
Heap::kOld)) {
335+
// Fast case for type = int/num/top-type.
334336
__ BranchIfSmi(kInstanceReg, is_instance_lbl);
335337
} else {
336338
__ BranchIfSmi(kInstanceReg, is_not_instance_lbl);
@@ -388,7 +390,14 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
388390
Label* is_not_instance_lbl) {
389391
__ Comment("Subtype1TestCacheLookup");
390392
const Register kInstanceReg = R0;
391-
__ LoadClass(R1, kInstanceReg);
393+
#if defined(DEBUG)
394+
Label ok;
395+
__ BranchIfNotSmi(kInstanceReg, &ok);
396+
__ Breakpoint();
397+
__ Bind(&ok);
398+
#endif
399+
__ LoadClassId(TMP, kInstanceReg);
400+
__ LoadClassById(R1, TMP);
392401
// R1: instance class.
393402
// Check immediate superclass equality.
394403
__ LoadFieldFromOffset(R2, R1, Class::super_type_offset());
@@ -435,12 +444,13 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
435444
__ LoadFieldFromOffset(R3, kTypeArgumentsReg,
436445
TypeArguments::type_at_offset(type_param.index()));
437446
// R3: concrete type of type.
438-
// Check if type argument is dynamic.
447+
// Check if type argument is dynamic, Object, or void.
439448
__ CompareObject(R3, Object::dynamic_type());
440449
__ b(is_instance_lbl, EQ);
441450
__ CompareObject(R3, Type::ZoneHandle(zone(), Type::ObjectType()));
442451
__ b(is_instance_lbl, EQ);
443-
// TODO(regis): Optimize void type as well once allowed as type argument.
452+
__ CompareObject(R3, Object::void_type());
453+
__ b(is_instance_lbl, EQ);
444454

445455
// For Smi check quickly against int and num interfaces.
446456
Label not_smi;
@@ -449,9 +459,8 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
449459
__ b(is_instance_lbl, EQ);
450460
__ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number()));
451461
__ b(is_instance_lbl, EQ);
452-
// Smi must be handled in runtime.
453-
Label fall_through;
454-
__ b(&fall_through);
462+
// Smi can be handled by type test cache.
463+
__ Bind(&not_smi);
455464

456465
// If it's guaranteed, by type-parameter bound, that the type parameter will
457466
// never have a value of a function type, then we can safely do a 4-type
@@ -461,17 +470,18 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
461470
? kTestTypeSixArgs
462471
: kTestTypeFourArgs;
463472

464-
__ Bind(&not_smi);
465473
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
466474
zone(), GenerateCallSubtypeTestStub(
467475
test_kind, kInstanceReg, kInstantiatorTypeArgumentsReg,
468476
kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
469477
is_not_instance_lbl));
470-
__ Bind(&fall_through);
471478
return type_test_cache.raw();
472479
}
473480
if (type.IsType()) {
474-
__ BranchIfSmi(kInstanceReg, is_not_instance_lbl);
481+
// Smi is FutureOr<T>, when T is a top type or int or num.
482+
if (!FLAG_strong || !Class::Handle(type.type_class()).IsFutureOrClass()) {
483+
__ BranchIfSmi(kInstanceReg, is_not_instance_lbl);
484+
}
475485
__ ldp(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg,
476486
Address(SP, 0 * kWordSize, Address::PairOffset));
477487
// Uninstantiated type class is known at compile time, but the type

runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,14 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
256256
ASSERT(type_class.NumTypeArguments() > 0);
257257
const Register kInstanceReg = EAX;
258258
Error& bound_error = Error::Handle(zone());
259-
const Type& int_type = Type::Handle(zone(), Type::IntType());
259+
const Type& smi_type = Type::Handle(zone(), Type::SmiType());
260260
const bool smi_is_ok =
261-
int_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
261+
smi_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
262262
// Malformed type should have been handled at graph construction time.
263263
ASSERT(smi_is_ok || bound_error.IsNull());
264264
__ testl(kInstanceReg, Immediate(kSmiTagMask));
265265
if (smi_is_ok) {
266+
// Fast case for type = FutureOr<int/num/top-type>.
266267
__ j(ZERO, is_instance_lbl);
267268
} else {
268269
__ j(ZERO, is_not_instance_lbl);
@@ -294,7 +295,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
294295
ASSERT(!tp_argument.IsMalformed());
295296
if (tp_argument.IsType()) {
296297
ASSERT(tp_argument.HasResolvedTypeClass());
297-
// Check if type argument is dynamic or Object.
298+
// Check if type argument is dynamic, Object, or void.
298299
const Type& object_type = Type::Handle(zone(), Type::ObjectType());
299300
if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) {
300301
// Instance class test only necessary.
@@ -347,6 +348,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
347348
if (smi_class.IsSubtypeOf(Object::null_type_arguments(), type_class,
348349
Object::null_type_arguments(), NULL, NULL,
349350
Heap::kOld)) {
351+
// Fast case for type = int/num/top-type.
350352
__ j(ZERO, is_instance_lbl);
351353
} else {
352354
__ j(ZERO, is_not_instance_lbl);
@@ -404,7 +406,14 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
404406
Label* is_not_instance_lbl) {
405407
__ Comment("Subtype1TestCacheLookup");
406408
const Register kInstanceReg = EAX;
407-
__ LoadClass(ECX, kInstanceReg, EDI);
409+
#if defined(DEBUG)
410+
Label ok;
411+
__ BranchIfNotSmi(kInstanceReg, &ok);
412+
__ Breakpoint();
413+
__ Bind(&ok);
414+
#endif
415+
__ LoadClassId(EDI, kInstanceReg);
416+
__ LoadClassById(ECX, EDI);
408417
// ECX: instance class.
409418
// Check immediate superclass equality.
410419
__ movl(EDI, FieldAddress(ECX, Class::super_type_offset()));
@@ -455,12 +464,13 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
455464
__ movl(EDI, FieldAddress(kTypeArgumentsReg, TypeArguments::type_at_offset(
456465
type_param.index())));
457466
// EDI: concrete type of type.
458-
// Check if type argument is dynamic.
467+
// Check if type argument is dynamic, Object, or void.
459468
__ CompareObject(EDI, Object::dynamic_type());
460469
__ j(EQUAL, is_instance_lbl);
461470
__ CompareObject(EDI, Type::ZoneHandle(zone(), Type::ObjectType()));
462471
__ j(EQUAL, is_instance_lbl);
463-
// TODO(regis): Optimize void type as well once allowed as type argument.
472+
__ CompareObject(EDI, Object::void_type());
473+
__ j(EQUAL, is_instance_lbl);
464474

465475
// For Smi check quickly against int and num interfaces.
466476
Label not_smi;
@@ -470,9 +480,8 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
470480
__ j(EQUAL, is_instance_lbl);
471481
__ CompareObject(EDI, Type::ZoneHandle(zone(), Type::Number()));
472482
__ j(EQUAL, is_instance_lbl);
473-
// Smi must be handled in runtime.
474-
Label fall_through;
475-
__ jmp(&fall_through);
483+
// Smi can be handled by type test cache.
484+
__ Bind(&not_smi);
476485

477486
// If it's guaranteed, by type-parameter bound, that the type parameter will
478487
// never have a value of a function type.
@@ -481,18 +490,19 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
481490
? kTestTypeSixArgs
482491
: kTestTypeFourArgs;
483492

484-
__ Bind(&not_smi);
485493
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
486494
zone(), GenerateCallSubtypeTestStub(
487495
test_kind, kInstanceReg, kInstantiatorTypeArgumentsReg,
488496
kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
489497
is_not_instance_lbl));
490-
__ Bind(&fall_through);
491498
return type_test_cache.raw();
492499
}
493500
if (type.IsType()) {
494-
__ testl(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi?
495-
__ j(ZERO, is_not_instance_lbl);
501+
// Smi is FutureOr<T>, when T is a top type or int or num.
502+
if (!FLAG_strong || !Class::Handle(type.type_class()).IsFutureOrClass()) {
503+
__ testl(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi?
504+
__ j(ZERO, is_not_instance_lbl);
505+
}
496506
__ movl(kInstantiatorTypeArgumentsReg, Address(ESP, 1 * kWordSize));
497507
__ movl(kFunctionTypeArgumentsReg, Address(ESP, 0 * kWordSize));
498508
// Uninstantiated type class is known at compile time, but the type

0 commit comments

Comments
 (0)