| Index: runtime/vm/stub_code_arm.cc
|
| ===================================================================
|
| --- runtime/vm/stub_code_arm.cc (revision 21773)
|
| +++ runtime/vm/stub_code_arm.cc (working copy)
|
| @@ -1533,8 +1533,89 @@
|
| }
|
|
|
|
|
| +// Implements equality operator when one of the arguments is null
|
| +// (identity check) and updates ICData if necessary.
|
| +// LR: return address.
|
| +// R1: left argument.
|
| +// R0: right argument.
|
| +// R5: ICData.
|
| +// R0: result.
|
| +// TODO(srdjan): Move to VM stubs once Boolean objects become VM objects.
|
| void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) {
|
| - __ Unimplemented("EqualityWithNullArg Stub");
|
| + __ EnterStubFrame();
|
| + static const intptr_t kNumArgsTested = 2;
|
| +#if defined(DEBUG)
|
| + { Label ok;
|
| + __ ldr(IP, FieldAddress(R5, ICData::num_args_tested_offset()));
|
| + __ cmp(IP, ShifterOperand(kNumArgsTested));
|
| + __ b(&ok, EQ);
|
| + __ Stop("Incorrect ICData for equality");
|
| + __ Bind(&ok);
|
| + }
|
| +#endif // DEBUG
|
| + // Check IC data, update if needed.
|
| + // R5: IC data object (preserved).
|
| + __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset()));
|
| + // R6: ic_data_array with check entries: classes and target functions.
|
| + __ AddImmediate(R6, Array::data_offset() - kHeapObjectTag);
|
| + // R6: points directly to the first ic data array element.
|
| +
|
| + Label get_class_id_as_smi, no_match, loop, found;
|
| + __ Bind(&loop);
|
| + // Check left.
|
| + __ mov(R2, ShifterOperand(R1));
|
| + __ bl(&get_class_id_as_smi);
|
| + __ ldr(R3, Address(R6, 0 * kWordSize));
|
| + __ cmp(R2, ShifterOperand(R3)); // Class id match?
|
| + __ b(&no_match, NE);
|
| + // Check right.
|
| + __ mov(R2, ShifterOperand(R0));
|
| + __ bl(&get_class_id_as_smi);
|
| + __ ldr(R3, Address(R6, 1 * kWordSize));
|
| + __ cmp(R2, ShifterOperand(R3)); // Class id match?
|
| + __ b(&found, EQ);
|
| + __ Bind(&no_match);
|
| + // Next check group.
|
| + __ AddImmediate(R6, kWordSize * ICData::TestEntryLengthFor(kNumArgsTested));
|
| + __ CompareImmediate(R3, Smi::RawValue(kIllegalCid)); // Done?
|
| + __ b(&loop, NE);
|
| + Label update_ic_data;
|
| + __ b(&update_ic_data);
|
| +
|
| + __ Bind(&found);
|
| + const intptr_t count_offset =
|
| + ICData::CountIndexFor(kNumArgsTested) * kWordSize;
|
| + __ ldr(IP, Address(R6, count_offset));
|
| + __ adds(IP, IP, ShifterOperand(Smi::RawValue(1)));
|
| + __ LoadImmediate(IP, Smi::RawValue(Smi::kMaxValue), VS); // If overflow.
|
| + __ str(IP, Address(R6, count_offset));
|
| +
|
| + Label compute_result;
|
| + __ Bind(&compute_result);
|
| + __ cmp(R0, ShifterOperand(R1));
|
| + __ LoadObject(R0, Bool::False(), NE);
|
| + __ LoadObject(R0, Bool::True(), EQ);
|
| + __ LeaveStubFrame();
|
| + __ Ret();
|
| +
|
| + __ Bind(&get_class_id_as_smi);
|
| + // Test if Smi -> load Smi class for comparison.
|
| + __ tst(R2, ShifterOperand(kSmiTagMask));
|
| + __ mov(R2, ShifterOperand(Smi::RawValue(kSmiCid)), EQ);
|
| + __ bx(LR, EQ);
|
| + __ LoadClassId(R2, R2);
|
| + __ SmiTag(R2);
|
| + __ bx(LR);
|
| +
|
| + __ Bind(&update_ic_data);
|
| + // R5: ICData
|
| + __ PushList((1 << R0) | (1 << R1));
|
| + __ PushObject(Symbols::EqualOperator()); // Target's name.
|
| + __ Push(R5); // ICData
|
| + __ CallRuntime(kUpdateICDataTwoArgsRuntimeEntry); // Clobbers R4, R5.
|
| + __ Drop(2);
|
| + __ PopList((1 << R0) | (1 << R1));
|
| + __ b(&compute_result);
|
| }
|
|
|
|
|
|
|