mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:00:09 +00:00
Terminate IC data array with a null group (preparation for new style of inline caching; easier to terminate when iterating over the array in assembly).
Review URL: https://chromereviews.googleplex.com/3507023 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@46 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
0e08858598
commit
288938bd88
|
@ -27,7 +27,8 @@ intptr_t ICData::NumberOfChecks() const {
|
|||
intptr_t length = data.Length();
|
||||
// First element is number of classes (N), followed by a group of elements,
|
||||
// each element consisting of N classes + 1 target.
|
||||
return (length - 1) / (number_of_classes + 1);
|
||||
// Subtract the terminating NULL group.
|
||||
return (length - 1) / (number_of_classes + 1) - 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,15 +59,34 @@ void ICData::SetCheckAt(intptr_t index,
|
|||
intptr_t num_classes = NumberOfClasses();
|
||||
intptr_t pos = 1 + (num_classes + 1) * index;
|
||||
for (intptr_t i = 0; i < num_classes; i++) {
|
||||
// Null is used as terminating object, do not add it.
|
||||
ASSERT(!classes[i]->IsNull());
|
||||
// Contract says that no null classes may be added.
|
||||
ASSERT(!classes[i]->IsNullClass());
|
||||
data.SetAt(pos++, *(classes[i]));
|
||||
}
|
||||
ASSERT(!target.IsNull());
|
||||
// Null is used as terminating object, do not add it.
|
||||
data.SetAt(pos, target);
|
||||
}
|
||||
|
||||
|
||||
void ICData::AddCheck(const GrowableArray<const Class*>& classes,
|
||||
const Function& target) {
|
||||
const Array& data = Array::Handle(ic_stub_.ic_data());
|
||||
ASSERT(classes.length() == NumberOfClasses());
|
||||
intptr_t number_of_checks = NumberOfChecks();
|
||||
intptr_t new_len = data.Length() + classes.length() + 1;
|
||||
const Array& new_data = Array::Handle(Array::Grow(data, new_len, Heap::kOld));
|
||||
ic_stub_.set_ic_data(new_data);
|
||||
SetCheckAt(number_of_checks, classes, target);
|
||||
}
|
||||
|
||||
|
||||
void ICData::SetICDataArray(intptr_t num_classes, intptr_t num_checks) {
|
||||
intptr_t len = 1 + (num_classes + 1) * num_checks;
|
||||
const Array& ic_data = Array::Handle(Array::New(len));
|
||||
// Add a terminating group to num_checks.
|
||||
intptr_t len = 1 + (num_classes + 1) * (num_checks + 1);
|
||||
const Array& ic_data = Array::Handle(Array::New(len), Heap::kOld);
|
||||
ic_data.SetAt(0, Smi::Handle(Smi::New(num_classes)));
|
||||
ic_stub_.set_ic_data(ic_data);
|
||||
}
|
||||
|
|
|
@ -29,12 +29,14 @@ class RawCode;
|
|||
|
||||
// Class that interprets the array stored in ICData::ic_data_.
|
||||
// The array format is:
|
||||
// - number of arguments checked, i.e., number of classes in each check -> N.
|
||||
// - number of arguments checked, i.e., N number of classes in each check.
|
||||
// - group of checks, each check containing:
|
||||
// - N classes.
|
||||
// - 1 target/function.
|
||||
// Whenever first N arguments have the same class, jump to the matching
|
||||
// function/target.
|
||||
// - 1 target function.
|
||||
// Whenever first N arguments of a dynamic call have the same class as the
|
||||
// check, jump to the matching target function.
|
||||
// Array is terminated with a null group (all classes and target are NULL).
|
||||
// The array does not contain Null-Classes. Null objects cannot be added.
|
||||
class ICData : public ValueObject {
|
||||
public:
|
||||
explicit ICData(const Code& ic_stub);
|
||||
|
@ -57,6 +59,9 @@ class ICData : public ValueObject {
|
|||
// Use 'SetCheckAt' to populate the array.
|
||||
void SetICDataArray(intptr_t num_classes, intptr_t num_checks);
|
||||
|
||||
void AddCheck(const GrowableArray<const Class*>& classes,
|
||||
const Function& target);
|
||||
|
||||
void Print();
|
||||
|
||||
// Temporary helper method to check that the existing inline
|
||||
|
|
|
@ -246,6 +246,8 @@ TEST_CASE(ICDataTest) {
|
|||
const Function& function0 = Function::ZoneHandle(GetDummyTarget("SmiSmi"));
|
||||
const Function& function1 = Function::ZoneHandle(GetDummyTarget("SmiDouble"));
|
||||
const Function& function2 = Function::ZoneHandle(GetDummyTarget("DoubleSmi"));
|
||||
const Function& function3 =
|
||||
Function::ZoneHandle(GetDummyTarget("DoubleDouble"));
|
||||
ic_data.SetCheckAt(0, check0, function0);
|
||||
ic_data.SetCheckAt(1, check1, function1);
|
||||
ic_data.SetCheckAt(2, check2, function2);
|
||||
|
@ -268,6 +270,20 @@ TEST_CASE(ICDataTest) {
|
|||
ic_data.GetCheckAt(2, &test_classes, &test_function);
|
||||
EXPECT_EQ(function2.raw(), test_function.raw());
|
||||
EXPECT_EQ(true, SameClassArrays(test_classes, check2));
|
||||
|
||||
// Test AddCheck, test new and old data.
|
||||
GrowableArray<const Class*> double_double_classes;
|
||||
double_double_classes.Add(&double_class);
|
||||
double_double_classes.Add(&double_class);
|
||||
ic_data.AddCheck(double_double_classes, function3);
|
||||
EXPECT_EQ(4, ic_data.NumberOfChecks());
|
||||
ic_data.GetCheckAt(3, &test_classes, &test_function);
|
||||
EXPECT_EQ(function3.raw(), test_function.raw());
|
||||
EXPECT_EQ(true, SameClassArrays(test_classes, double_double_classes));
|
||||
|
||||
ic_data.GetCheckAt(1, &test_classes, &test_function);
|
||||
EXPECT_EQ(function1.raw(), test_function.raw());
|
||||
EXPECT_EQ(true, SameClassArrays(test_classes, check1));
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue