| Index: runtime/vm/stub_code_mips.cc
|
| diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
|
| index e2001b628de39f6f74e567c9fef192f842aa735b..53394cf82eb4beda3bcd581482bc3bb36f8a0f71 100644
|
| --- a/runtime/vm/stub_code_mips.cc
|
| +++ b/runtime/vm/stub_code_mips.cc
|
| @@ -1403,10 +1403,13 @@ static void EmitFastSmiOp(Assembler* assembler,
|
| __ Bind(&ok);
|
| #endif
|
| if (FLAG_optimization_counter_threshold >= 0) {
|
| - // Update counter, ignore overflow.
|
| + // Update counter.
|
| const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
|
| __ lw(T4, Address(T0, count_offset));
|
| - __ AddImmediate(T4, T4, Smi::RawValue(1));
|
| + __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6);
|
| + __ slt(CMPRES1, T5, ZR); // T5 is < 0 if there was overflow.
|
| + __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue));
|
| + __ movz(T4, T7, CMPRES1);
|
| __ sw(T4, Address(T0, count_offset));
|
| }
|
|
|
| @@ -1431,7 +1434,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
|
| Token::Kind kind,
|
| bool optimized) {
|
| __ Comment("NArgsCheckInlineCacheStub");
|
| - ASSERT(num_args == 1 || num_args == 2);
|
| + ASSERT(num_args > 0);
|
| #if defined(DEBUG)
|
| {
|
| Label ok;
|
| @@ -1468,7 +1471,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
|
| // Preserve return address, since RA is needed for subroutine call.
|
| __ mov(T2, RA);
|
| // Loop that checks if there is an IC data match.
|
| - Label loop, found, miss;
|
| + Label loop, update, test, found;
|
| // S5: IC data object (preserved).
|
| __ lw(T0, FieldAddress(S5, ICData::ic_data_offset()));
|
| // T0: ic_data_array with check entries: classes and target functions.
|
| @@ -1485,54 +1488,53 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
|
| __ lw(T3, Address(T3));
|
| __ LoadTaggedClassIdMayBeSmi(T3, T3);
|
|
|
| - if (num_args == 2) {
|
| - __ LoadImmediate(TMP, Smi::RawValue(1));
|
| - __ subu(T5, T1, TMP);
|
| - __ sll(T5, T5, 1);
|
| - __ addu(T5, SP, T5);
|
| - __ lw(T5, Address(T5));
|
| - __ LoadTaggedClassIdMayBeSmi(T5, T5);
|
| - }
|
| -
|
| // T1: argument_count - 1 (smi).
|
| // T3: receiver's class ID (smi).
|
| - // T5: first argument's class ID (smi).
|
| -
|
| - // We unroll the generic one that is generated once more than the others.
|
| - bool optimize = kind == Token::kILLEGAL;
|
| + __ b(&test);
|
| + __ delay_slot()->lw(T4, Address(T0)); // First class id (smi) to check.
|
|
|
| __ Comment("ICData loop");
|
| __ Bind(&loop);
|
| - for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) {
|
| - Label update;
|
| - for (int i = 0; i < num_args; i++) {
|
| + for (int i = 0; i < num_args; i++) {
|
| + if (i > 0) {
|
| + // If not the first, load the next argument's class ID.
|
| + __ LoadImmediate(T3, Smi::RawValue(-i));
|
| + __ addu(T3, T1, T3);
|
| + __ sll(T3, T3, 1);
|
| + __ addu(T3, SP, T3);
|
| + __ lw(T3, Address(T3));
|
| + __ LoadTaggedClassIdMayBeSmi(T3, T3);
|
| + // T3: next argument class ID (smi).
|
| __ lw(T4, Address(T0, i * kWordSize));
|
| - if (i == 0) {
|
| - if (num_args == 1) {
|
| - __ beq(T3, T4, &found); // IC hit.
|
| - } else {
|
| - __ bne(T3, T4, &update); // Continue.
|
| - }
|
| - } else {
|
| - __ beq(T5, T4, &found); // IC hit.
|
| - }
|
| + // T4: next class ID to check (smi).
|
| }
|
| - __ Bind(&update);
|
| -
|
| - const intptr_t entry_size =
|
| - ICData::TestEntryLengthFor(num_args) * kWordSize;
|
| - __ AddImmediate(T0, entry_size); // Next entry.
|
| - if (unroll == 0) {
|
| - __ BranchNotEqual(T4, Immediate(Smi::RawValue(kIllegalCid)),
|
| - &loop); // Done?
|
| + if (i < (num_args - 1)) {
|
| + __ bne(T3, T4, &update); // Continue.
|
| } else {
|
| - __ BranchEqual(T4, Immediate(Smi::RawValue(kIllegalCid)),
|
| - &miss); // Done?
|
| + // Last check, all checks before matched.
|
| + Label skip;
|
| + __ bne(T3, T4, &skip);
|
| + __ b(&found); // Break.
|
| + __ delay_slot()->mov(RA, T2); // Restore return address if found.
|
| + __ Bind(&skip);
|
| }
|
| - __ delay_slot()->lw(T4, Address(T0)); // Next class ID.
|
| + }
|
| + __ Bind(&update);
|
| + // Reload receiver class ID. It has not been destroyed when num_args == 1.
|
| + if (num_args > 1) {
|
| + __ sll(T3, T1, 1);
|
| + __ addu(T3, T3, SP);
|
| + __ lw(T3, Address(T3));
|
| + __ LoadTaggedClassIdMayBeSmi(T3, T3);
|
| }
|
|
|
| - __ Bind(&miss);
|
| + const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
|
| + __ AddImmediate(T0, entry_size); // Next entry.
|
| + __ lw(T4, Address(T0)); // Next class ID.
|
| +
|
| + __ Bind(&test);
|
| + __ BranchNotEqual(T4, Immediate(Smi::RawValue(kIllegalCid)), &loop); // Done?
|
| +
|
| __ Comment("IC miss");
|
| // Restore return address.
|
| __ mov(RA, T2);
|
| @@ -1582,7 +1584,6 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
|
| }
|
|
|
| __ Bind(&found);
|
| - __ mov(RA, T2); // Restore return address if found.
|
| __ Comment("Update caller's counter");
|
| // T0: Pointer to an IC data check group.
|
| const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
|
| @@ -1590,9 +1591,12 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
|
| __ lw(T3, Address(T0, target_offset));
|
|
|
| if (FLAG_optimization_counter_threshold >= 0) {
|
| - // Update counter, ignore overflow.
|
| + // Update counter.
|
| __ lw(T4, Address(T0, count_offset));
|
| - __ AddImmediate(T4, T4, Smi::RawValue(1));
|
| + __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6);
|
| + __ slt(CMPRES1, T5, ZR); // T5 is < 0 if there was overflow.
|
| + __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue));
|
| + __ movz(T4, T7, CMPRES1);
|
| __ sw(T4, Address(T0, count_offset));
|
| }
|
|
|
| @@ -1725,9 +1729,12 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
|
| const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
|
|
|
| if (FLAG_optimization_counter_threshold >= 0) {
|
| - // Increment count for this call, ignore overflow.
|
| + // Increment count for this call.
|
| __ lw(T4, Address(T0, count_offset));
|
| - __ AddImmediate(T4, T4, Smi::RawValue(1));
|
| + __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6);
|
| + __ slt(CMPRES1, T5, ZR); // T5 is < 0 if there was overflow.
|
| + __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue));
|
| + __ movz(T4, T7, CMPRES1);
|
| __ sw(T4, Address(T0, count_offset));
|
| }
|
|
|
|
|