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:
srdjan@google.com 2011-10-05 16:25:14 +00:00
parent 0e08858598
commit 288938bd88
3 changed files with 48 additions and 7 deletions

View file

@ -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);
}

View file

@ -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

View file

@ -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));
}