[vm/test] Make vm/cc/TTS_Regress_CidRangeChecks less brittle.
Since we're adding the classes in a known order, we can calculate
how many unrelated classes are needed to align the cids from
the next cid to be allocated.
TEST=TTS_Regress_CidRangeChecks
Fixes https://github.com/dart-lang/sdk/issues/48673
Change-Id: I04b750c64cf739bc6ba0bda2a93373a6443cedaf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/239025
Reviewed-by: Clement Skau <cskau@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
diff --git a/runtime/vm/type_testing_stubs_test.cc b/runtime/vm/type_testing_stubs_test.cc
index 6d3d94b..2a0f8e9 100644
--- a/runtime/vm/type_testing_stubs_test.cc
+++ b/runtime/vm/type_testing_stubs_test.cc
@@ -2272,7 +2272,7 @@
//
// To ensure that the register is clobbered on all architectures, we set things
// up by generating the following classes:
-// * B<X>, an generic abstract class which is implemented by the others.
+// * B<X>, a generic abstract class which is implemented by the others.
// * I, implements B<String>, has a single int field x, and is
// used to create the checked instance.
// * G<Y>, which implements B<Y> and has no fields (so its TAV field
@@ -2284,26 +2284,33 @@
// We'll carefully set things up so that the following equation between their
// class ids holds:
//
-// G = I - C.
+// G = I - C.
//
// Thus, when we create a TTS for B<int> and check it against an instance V
// of I. The cid for I will be loaded into a register R, and then two
// check blocks will be generated:
//
-// * A check for the cid range [C-D], hich has the side effect of
+// * A check for the cid range [C-D], which has the side effect of
// subtracting the cid of C from the contents of R (here, the cid of I).
//
// * A check that R contains the cid for G.
//
// Thus, if the cid of I is not reloaded into R before the second check, and
-// the equation earlier holds,we'll get a false positive that V is an instance
+// the equation earlier holds, we'll get a false positive that V is an instance
// of G, so the code will then try to load the instance type arguments from V
// as if it was an instance of G. This means the contents of x will be loaded
// and attempted to be used as a TypeArgumentsPtr, which will cause a crash
// during the checks that the instantiation of Y is int.
ISOLATE_UNIT_TEST_CASE(TTS_Regress_CidRangeChecks) {
- // Bump this appropriately if the EXPECT_EQ below fails.
- const intptr_t kNumUnrelated = 1186;
+ // We create the classes in this order: B, G, C, D, U..., I. We need
+ // G = I - C => G + C = I
+ // => G + C = D + N + 1 (where N is the number of U classes)
+ // => (B + 1) + C = (C + 1) + N + 1
+ // => B - 1 = N.
+ // The cid for B will be the next allocated cid, which is the number of
+ // non-top-level cids in the current class table.
+ ClassTable* const class_table = IsolateGroup::Current()->class_table();
+ const intptr_t kNumUnrelated = class_table->NumCids() - 1;
TextBuffer buffer(1024);
buffer.AddString(R"(
abstract class B<X> {}
@@ -2329,6 +2336,8 @@
const auto& class_b = Class::Handle(GetClass(root_library, "B"));
const auto& class_g = Class::Handle(GetClass(root_library, "G"));
const auto& class_c = Class::Handle(GetClass(root_library, "C"));
+ const auto& class_d = Class::Handle(GetClass(root_library, "D"));
+ const auto& class_u0 = Class::Handle(GetClass(root_library, "U0"));
const auto& class_i = Class::Handle(GetClass(root_library, "I"));
const auto& obj_i = Object::Handle(Invoke(root_library, "createI"));
{
@@ -2336,6 +2345,12 @@
ClassFinalizer::FinalizeClass(class_g);
}
+ // Double-check assumptions from calculating kNumUnrelated.
+ EXPECT_EQ(kNumUnrelated, class_b.id() - 1);
+ EXPECT_EQ(class_b.id() + 1, class_g.id());
+ EXPECT_EQ(class_c.id() + 1, class_d.id());
+ EXPECT_EQ(class_d.id() + 1, class_u0.id());
+ EXPECT_EQ(class_u0.id() + kNumUnrelated, class_i.id());
EXPECT_EQ(class_g.id(), class_i.id() - class_c.id());
const auto& tav_null = Object::null_type_arguments();