this repo has no description
at trunk 2240 lines 86 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "ic.h" 3 4#include "gtest/gtest.h" 5 6#include "attributedict.h" 7#include "dict-builtins.h" 8#include "str-builtins.h" 9#include "test-utils.h" 10#include "type-builtins.h" 11 12namespace py { 13namespace testing { 14 15using IcTest = RuntimeFixture; 16 17TEST_F( 18 IcTest, 19 icLookupMonomorphicWithEmptyCacheReturnsErrorNotFoundAndSetIsFoundToFalse) { 20 HandleScope scope(thread_); 21 MutableTuple caches(&scope, 22 runtime_->newMutableTuple(2 * kIcPointersPerEntry)); 23 caches.fill(NoneType::object()); 24 bool is_found; 25 EXPECT_TRUE(icLookupMonomorphic(*caches, 1, LayoutId::kSmallInt, &is_found) 26 .isErrorNotFound()); 27 EXPECT_FALSE(is_found); 28} 29 30TEST_F(IcTest, IcLookupBinaryOpReturnsErrorNotFound) { 31 HandleScope scope(thread_); 32 33 MutableTuple caches(&scope, runtime_->newMutableTuple(kIcPointersPerEntry)); 34 caches.fill(NoneType::object()); 35 BinaryOpFlags flags; 36 EXPECT_TRUE(icLookupBinaryOp(*caches, 0, LayoutId::kSmallInt, 37 LayoutId::kSmallInt, &flags) 38 .isErrorNotFound()); 39} 40 41TEST_F(IcTest, IcLookupGlobalVar) { 42 HandleScope scope(thread_); 43 MutableTuple caches(&scope, runtime_->newMutableTuple(2)); 44 caches.fill(NoneType::object()); 45 ValueCell cache(&scope, runtime_->newValueCell()); 46 cache.setValue(SmallInt::fromWord(99)); 47 caches.atPut(0, *cache); 48 EXPECT_TRUE( 49 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches, 0)), 99)); 50 EXPECT_TRUE(icLookupGlobalVar(*caches, 1).isNoneType()); 51} 52 53TEST_F(IcTest, IcUpdateAttrSetsMonomorphicEntry) { 54 HandleScope scope(thread_); 55 MutableTuple caches(&scope, 56 runtime_->newMutableTuple(1 * kIcPointersPerEntry)); 57 caches.fill(NoneType::object()); 58 Object value(&scope, runtime_->newInt(88)); 59 Object name(&scope, Str::empty()); 60 Function dependent(&scope, newEmptyFunction()); 61 EXPECT_EQ(icUpdateAttr(thread_, caches, 0, LayoutId::kSmallInt, value, name, 62 dependent), 63 ICState::kMonomorphic); 64 65 bool is_found; 66 EXPECT_EQ(icLookupMonomorphic(*caches, 0, LayoutId::kSmallInt, &is_found), 67 *value); 68} 69 70TEST_F(IcTest, IcUpdateAttrUpdatesExistingMonomorphicEntry) { 71 HandleScope scope(thread_); 72 MutableTuple caches(&scope, 73 runtime_->newMutableTuple(1 * kIcPointersPerEntry)); 74 caches.fill(NoneType::object()); 75 Object value(&scope, runtime_->newInt(88)); 76 Object name(&scope, Str::empty()); 77 Function dependent(&scope, newEmptyFunction()); 78 ASSERT_EQ(icUpdateAttr(thread_, caches, 0, LayoutId::kSmallInt, value, name, 79 dependent), 80 ICState::kMonomorphic); 81 bool is_found; 82 EXPECT_EQ(icLookupMonomorphic(*caches, 0, LayoutId::kSmallInt, &is_found), 83 *value); 84 EXPECT_TRUE(is_found); 85 86 Object new_value(&scope, runtime_->newInt(99)); 87 EXPECT_EQ(icUpdateAttr(thread_, caches, 0, LayoutId::kSmallInt, new_value, 88 name, dependent), 89 ICState::kMonomorphic); 90 EXPECT_EQ(icLookupMonomorphic(*caches, 0, LayoutId::kSmallInt, &is_found), 91 *new_value); 92 EXPECT_TRUE(is_found); 93} 94 95TEST_F(IcTest, IcUpdateAttrSetsPolymorphicEntry) { 96 HandleScope scope(thread_); 97 MutableTuple caches(&scope, 98 runtime_->newMutableTuple(1 * kIcPointersPerEntry)); 99 caches.fill(NoneType::object()); 100 Object int_value(&scope, runtime_->newInt(88)); 101 Object str_value(&scope, runtime_->newInt(99)); 102 Object name(&scope, Str::empty()); 103 Function dependent(&scope, newEmptyFunction()); 104 ASSERT_EQ(icUpdateAttr(thread_, caches, 0, LayoutId::kSmallInt, int_value, 105 name, dependent), 106 ICState::kMonomorphic); 107 EXPECT_EQ(icUpdateAttr(thread_, caches, 0, LayoutId::kSmallStr, str_value, 108 name, dependent), 109 ICState::kPolymorphic); 110 bool is_found; 111 EXPECT_EQ(icLookupPolymorphic(*caches, 0, LayoutId::kSmallInt, &is_found), 112 *int_value); 113 EXPECT_TRUE(is_found); 114 EXPECT_EQ(icLookupPolymorphic(*caches, 0, LayoutId::kSmallStr, &is_found), 115 *str_value); 116 EXPECT_TRUE(is_found); 117} 118 119TEST_F(IcTest, IcUpdateAttrUpdatesPolymorphicEntry) { 120 HandleScope scope(thread_); 121 MutableTuple caches(&scope, 122 runtime_->newMutableTuple(1 * kIcPointersPerEntry)); 123 caches.fill(NoneType::object()); 124 Object int_value(&scope, runtime_->newInt(88)); 125 Object str_value(&scope, runtime_->newInt(99)); 126 Object name(&scope, Str::empty()); 127 Function dependent(&scope, newEmptyFunction()); 128 ASSERT_EQ(icUpdateAttr(thread_, caches, 0, LayoutId::kSmallInt, int_value, 129 name, dependent), 130 ICState::kMonomorphic); 131 ASSERT_EQ(icUpdateAttr(thread_, caches, 0, LayoutId::kSmallStr, str_value, 132 name, dependent), 133 ICState::kPolymorphic); 134 bool is_found; 135 ASSERT_EQ(icLookupPolymorphic(*caches, 0, LayoutId::kSmallInt, &is_found), 136 *int_value); 137 ASSERT_TRUE(is_found); 138 ASSERT_EQ(icLookupPolymorphic(*caches, 0, LayoutId::kSmallStr, &is_found), 139 *str_value); 140 ASSERT_TRUE(is_found); 141 142 Object new_value(&scope, runtime_->newInt(101)); 143 EXPECT_EQ(icUpdateAttr(thread_, caches, 0, LayoutId::kSmallStr, new_value, 144 name, dependent), 145 ICState::kPolymorphic); 146 EXPECT_EQ(icLookupPolymorphic(*caches, 0, LayoutId::kSmallStr, &is_found), 147 *new_value); 148 EXPECT_TRUE(is_found); 149} 150 151TEST_F(IcTest, IcUpdateAttrInsertsDependencyUpToDefiningType) { 152 HandleScope scope(thread_); 153 ASSERT_FALSE(runFromCStr(runtime_, R"( 154class A: 155 pass 156 157class B(A): 158 foo = "class B" 159 160class C(B): 161 bar = "class C" 162 163c = C() 164)") 165 .isError()); 166 // Inserting dependent adds dependent to a new Placeholder in C for 'foo', and 167 // to the existing ValueCell in B. A won't be affected since it's not visited 168 // during MRO traversal. 169 MutableTuple caches(&scope, runtime_->newMutableTuple(4)); 170 caches.fill(NoneType::object()); 171 Object c(&scope, mainModuleAt(runtime_, "c")); 172 Object value(&scope, SmallInt::fromWord(1234)); 173 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo")); 174 Function dependent(&scope, newEmptyFunction()); 175 icUpdateAttr(thread_, caches, 0, c.layoutId(), value, foo, dependent); 176 177 Type type_a(&scope, mainModuleAt(runtime_, "A")); 178 RawObject unused = NoneType::object(); 179 EXPECT_FALSE(attributeValueCellAt(*type_a, *foo, &unused)); 180 181 Type type_b(&scope, mainModuleAt(runtime_, "B")); 182 ValueCell b_entry(&scope, typeValueCellAt(*type_b, *foo)); 183 EXPECT_FALSE(b_entry.isPlaceholder()); 184 WeakLink b_link(&scope, b_entry.dependencyLink()); 185 EXPECT_EQ(b_link.referent(), dependent); 186 EXPECT_TRUE(b_link.next().isNoneType()); 187 188 Type type_c(&scope, mainModuleAt(runtime_, "C")); 189 ValueCell c_entry(&scope, typeValueCellAt(*type_c, *foo)); 190 EXPECT_TRUE(c_entry.isPlaceholder()); 191 WeakLink c_link(&scope, c_entry.dependencyLink()); 192 EXPECT_EQ(c_link.referent(), dependent); 193 EXPECT_TRUE(c_link.next().isNoneType()); 194} 195 196TEST_F(IcTest, IcUpdateAttrDoesNotInsertsDependencyToSealedType) { 197 HandleScope scope(thread_); 198 Str instance(&scope, runtime_->newStrFromCStr("str instance")); 199 MutableTuple caches(&scope, runtime_->newMutableTuple(4)); 200 caches.fill(NoneType::object()); 201 Object value(&scope, SmallInt::fromWord(1234)); 202 Object dunder_add(&scope, runtime_->symbols()->at(ID(__add__))); 203 Function dependent(&scope, newEmptyFunction()); 204 icUpdateAttr(thread_, caches, 0, instance.layoutId(), value, dunder_add, 205 dependent); 206 207 Type type_str(&scope, runtime_->typeAt(LayoutId::kStr)); 208 ValueCell dunder_add_entry(&scope, typeValueCellAt(*type_str, *dunder_add)); 209 EXPECT_TRUE(dunder_add_entry.dependencyLink().isNoneType()); 210} 211 212static RawObject dependencyLinkOfTypeAttr(Thread* thread, const Type& type, 213 const char* attribute_name) { 214 HandleScope scope(thread); 215 Object attribute_name_str(&scope, 216 Runtime::internStrFromCStr(thread, attribute_name)); 217 ValueCell value_cell(&scope, typeValueCellAt(*type, *attribute_name_str)); 218 return value_cell.dependencyLink(); 219} 220 221static bool icDependentIncluded(RawObject dependent, RawObject link) { 222 for (; !link.isNoneType(); link = WeakLink::cast(link).next()) { 223 if (WeakLink::cast(link).referent() == dependent) { 224 return true; 225 } 226 } 227 return false; 228} 229 230TEST_F(IcTest, IcEvictAttr) { 231 ASSERT_FALSE(runFromCStr(runtime_, R"( 232class A: 233 def __init__(self): 234 self.foo = 4 235 236def cache_a_foo(a): 237 return a.foo 238 239a = A() 240cache_a_foo(a) 241 242class B: 243 pass 244)") 245 .isError()); 246 247 HandleScope scope(thread_); 248 Type type_a(&scope, mainModuleAt(runtime_, "A")); 249 Function cache_a_foo(&scope, mainModuleAt(runtime_, "cache_a_foo")); 250 MutableTuple caches(&scope, cache_a_foo.caches()); 251 Object cached_object(&scope, mainModuleAt(runtime_, "a")); 252 // Precondition check that the A.foo attribute lookup has been cached. 253 ASSERT_FALSE( 254 icLookupAttr(*caches, 1, cached_object.layoutId()).isErrorNotFound()); 255 ASSERT_EQ(WeakLink::cast(dependencyLinkOfTypeAttr(thread_, type_a, "foo")) 256 .referent(), 257 *cache_a_foo); 258 259 // Try evicting caches with an attribute name that is not in the cache. This 260 // should have no effect. 261 Type cached_type(&scope, mainModuleAt(runtime_, "A")); 262 IcIterator it(&scope, runtime_, *cache_a_foo); 263 Object not_cached_attr_name(&scope, 264 Runtime::internStrFromCStr(thread_, "random")); 265 icEvictAttr(thread_, it, cached_type, not_cached_attr_name, 266 AttributeKind::kNotADataDescriptor, cache_a_foo); 267 EXPECT_FALSE( 268 icLookupAttr(*caches, 1, cached_object.layoutId()).isErrorNotFound()); 269 EXPECT_EQ(WeakLink::cast(dependencyLinkOfTypeAttr(thread_, type_a, "foo")) 270 .referent(), 271 *cache_a_foo); 272 273 // Try evicting instance attribute caches for a non-data descriptor 274 // assignment. Because instance attributes have a higher priority than 275 // non-data descriptors, nothing should be evicted. 276 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo")); 277 icEvictAttr(thread_, it, cached_type, foo, AttributeKind::kNotADataDescriptor, 278 cache_a_foo); 279 EXPECT_FALSE( 280 icLookupAttr(*caches, 1, cached_object.layoutId()).isErrorNotFound()); 281 EXPECT_EQ(WeakLink::cast(dependencyLinkOfTypeAttr(thread_, type_a, "foo")) 282 .referent(), 283 *cache_a_foo); 284 285 // Try evicting caches with a type that is not being cached. This should have 286 // no effect. 287 Type not_cached_type(&scope, mainModuleAt(runtime_, "B")); 288 icEvictAttr(thread_, it, not_cached_type, foo, AttributeKind::kDataDescriptor, 289 cache_a_foo); 290 EXPECT_FALSE( 291 icLookupAttr(*caches, 1, cached_object.layoutId()).isErrorNotFound()); 292 EXPECT_EQ(WeakLink::cast(dependencyLinkOfTypeAttr(thread_, type_a, "foo")) 293 .referent(), 294 *cache_a_foo); 295 296 // An update to a type attribute whose type, Attribute name with a data 297 // desciptor value invalidates an instance attribute cache. 298 icEvictAttr(thread_, it, cached_type, foo, AttributeKind::kDataDescriptor, 299 cache_a_foo); 300 EXPECT_TRUE( 301 icLookupAttr(*caches, 1, cached_object.layoutId()).isErrorNotFound()); 302 // The dependency for cache_a_foo gets deleted. 303 EXPECT_FALSE(icDependentIncluded( 304 *cache_a_foo, dependencyLinkOfTypeAttr(thread_, type_a, "foo"))); 305} 306 307TEST_F(IcTest, IcEvictBinaryOpEvictsCacheForUpdateToLeftOperandType) { 308 ASSERT_FALSE(runFromCStr(runtime_, R"( 309class A: 310 def __ge__(self, other): 311 return True 312 313class B: 314 def __le__(self, other): 315 return True 316 317def cache_binop(a, b): 318 return a >= b 319 320a = A() 321b = B() 322 323cache_binop(a, b) 324)") 325 .isError()); 326 HandleScope scope(thread_); 327 Function cache_binop(&scope, mainModuleAt(runtime_, "cache_binop")); 328 MutableTuple caches(&scope, cache_binop.caches()); 329 Object left_operand(&scope, mainModuleAt(runtime_, "a")); 330 Object right_operand(&scope, mainModuleAt(runtime_, "b")); 331 Type left_operand_type(&scope, mainModuleAt(runtime_, "A")); 332 BinaryOpFlags flags_out; 333 // Precondition check that the A.__ge__ attribute lookup has been cached. 334 ASSERT_FALSE(icLookupBinaryOp(*caches, 0, left_operand.layoutId(), 335 right_operand.layoutId(), &flags_out) 336 .isErrorNotFound()); 337 338 IcIterator it(&scope, runtime_, *cache_binop); 339 340 // An update to A.__ge__ invalidates the binop cache for a >= b. 341 Object dunder_ge(&scope, Runtime::internStrFromCStr(thread_, "__ge__")); 342 icEvictBinaryOp(thread_, it, left_operand_type, dunder_ge, cache_binop); 343 EXPECT_TRUE(icLookupBinaryOp(*caches, 0, left_operand.layoutId(), 344 right_operand.layoutId(), &flags_out) 345 .isErrorNotFound()); 346} 347 348TEST_F(IcTest, IcEvictBinaryOpEvictsCacheForUpdateToRightOperand) { 349 ASSERT_FALSE(runFromCStr(runtime_, R"( 350class A: 351 def __ge__(self, other): 352 return True 353 354class B: 355 def __le__(self, other): 356 return True 357 358def cache_binop(a, b): 359 return a >= b 360 361a = A() 362b = B() 363 364cache_binop(a, b) 365)") 366 .isError()); 367 HandleScope scope(thread_); 368 Function cache_binop(&scope, mainModuleAt(runtime_, "cache_binop")); 369 MutableTuple caches(&scope, cache_binop.caches()); 370 Object left_operand(&scope, mainModuleAt(runtime_, "a")); 371 Object right_operand(&scope, mainModuleAt(runtime_, "b")); 372 Type right_operand_type(&scope, mainModuleAt(runtime_, "B")); 373 BinaryOpFlags flags_out; 374 // Precondition check that the A.__ge__ attribute lookup has been cached. 375 ASSERT_FALSE(icLookupBinaryOp(*caches, 0, left_operand.layoutId(), 376 right_operand.layoutId(), &flags_out) 377 .isErrorNotFound()); 378 379 IcIterator it(&scope, runtime_, *cache_binop); 380 Object dunder_le(&scope, Runtime::internStrFromCStr(thread_, "__le__")); 381 // An update to B.__le__ invalidates the binop cache for a >= b. 382 icEvictBinaryOp(thread_, it, right_operand_type, dunder_le, cache_binop); 383 EXPECT_TRUE(icLookupBinaryOp(*caches, 0, left_operand.layoutId(), 384 right_operand.layoutId(), &flags_out) 385 .isErrorNotFound()); 386} 387 388TEST_F(IcTest, IcEvictBinaryOpDoesnNotDeleteDependenciesFromCachedTypes) { 389 ASSERT_FALSE(runFromCStr(runtime_, R"( 390class A: 391 def __ge__(self, other): return True 392 393class B: 394 def __le__(self, other): return True 395 396def cache_compare_op(a, b): 397 t0 = a >= b 398 t1 = b <= 5 399 400a = A() 401b = B() 402 403cache_compare_op(a, b) 404 405A__ge__ = A.__ge__ 406B__le__ = B.__le__ 407)") 408 .isError()); 409 HandleScope scope(thread_); 410 Object a(&scope, mainModuleAt(runtime_, "a")); 411 Object b(&scope, mainModuleAt(runtime_, "b")); 412 413 Object type_a_dunder_ge(&scope, mainModuleAt(runtime_, "A__ge__")); 414 Object type_b_dunder_le(&scope, mainModuleAt(runtime_, "B__le__")); 415 Function cache_compare_op(&scope, mainModuleAt(runtime_, "cache_compare_op")); 416 MutableTuple caches(&scope, cache_compare_op.caches()); 417 BinaryOpFlags flags_out; 418 // Ensure that A.__ge__ is cached for t0 = a >= b. 419 ASSERT_EQ( 420 icLookupBinaryOp(*caches, 0, a.layoutId(), b.layoutId(), &flags_out), 421 *type_a_dunder_ge); 422 // Ensure that B.__le__ is cached for t1 = b >= 5. 423 ASSERT_EQ(icLookupBinaryOp(*caches, 1, b.layoutId(), 424 SmallInt::fromWord(0).layoutId(), &flags_out), 425 *type_b_dunder_le); 426 427 Type type_a(&scope, mainModuleAt(runtime_, "A")); 428 // Ensure cache_compare_op is a dependent of A.__ge__. 429 ASSERT_TRUE(icDependentIncluded( 430 *cache_compare_op, dependencyLinkOfTypeAttr(thread_, type_a, "__ge__"))); 431 432 Type type_b(&scope, mainModuleAt(runtime_, "B")); 433 // Ensure cache_compare_op is a dependent of B.__le__. 434 ASSERT_TRUE(icDependentIncluded( 435 *cache_compare_op, dependencyLinkOfTypeAttr(thread_, type_b, "__le__"))); 436 437 // Update A.__ge__ to invalidate cache for t0 = a >= b. 438 Object dunder_ge_name(&scope, Runtime::internStrFromCStr(thread_, "__ge__")); 439 icEvictCache(thread_, cache_compare_op, type_a, dunder_ge_name, 440 AttributeKind::kNotADataDescriptor); 441 // The invalidation removes dependency from cache_compare_op to A.__ge__. 442 EXPECT_FALSE(icDependentIncluded( 443 *cache_compare_op, dependencyLinkOfTypeAttr(thread_, type_a, "__ge__"))); 444 // However, cache_compare_op still depends on B.__le__ since b >= 5 is cached. 445 EXPECT_TRUE(icDependentIncluded( 446 *cache_compare_op, dependencyLinkOfTypeAttr(thread_, type_b, "__le__"))); 447} 448 449TEST_F(IcTest, IcDeleteDependentInValueCellDependencyLinkDeletesDependent) { 450 HandleScope scope(thread_); 451 ValueCell value_cell(&scope, runtime_->newValueCell()); 452 Object dependent0(&scope, newTupleWithNone(4)); 453 Object dependent1(&scope, newTupleWithNone(5)); 454 Object dependent2(&scope, newTupleWithNone(6)); 455 Object dependent3(&scope, newTupleWithNone(7)); 456 icInsertDependentToValueCellDependencyLink(thread_, dependent3, value_cell); 457 icInsertDependentToValueCellDependencyLink(thread_, dependent2, value_cell); 458 icInsertDependentToValueCellDependencyLink(thread_, dependent1, value_cell); 459 icInsertDependentToValueCellDependencyLink(thread_, dependent0, value_cell); 460 461 // Delete the head. 462 icDeleteDependentInValueCell(thread_, value_cell, dependent0); 463 464 WeakLink link(&scope, value_cell.dependencyLink()); 465 EXPECT_EQ(link.referent(), *dependent1); 466 EXPECT_TRUE(link.prev().isNoneType()); 467 EXPECT_EQ(WeakLink::cast(link.next()).referent(), *dependent2); 468 EXPECT_EQ(WeakLink::cast(link.next()).prev(), *link); 469 470 // Delete the dependent in the middle. 471 icDeleteDependentInValueCell(thread_, value_cell, dependent2); 472 473 link = value_cell.dependencyLink(); 474 EXPECT_EQ(link.referent(), *dependent1); 475 EXPECT_EQ(WeakLink::cast(link.next()).referent(), *dependent3); 476 EXPECT_EQ(WeakLink::cast(link.next()).prev(), *link); 477 478 // Delete the tail. 479 icDeleteDependentInValueCell(thread_, value_cell, dependent3); 480 481 link = value_cell.dependencyLink(); 482 EXPECT_EQ(link.referent(), *dependent1); 483 EXPECT_TRUE(link.next().isNoneType()); 484 485 // Delete the last node. 486 icDeleteDependentInValueCell(thread_, value_cell, dependent1); 487 EXPECT_TRUE(value_cell.dependencyLink().isNoneType()); 488} 489 490TEST_F( 491 IcTest, 492 IcDeleteDependentFromCachedAttributeDeletesDependentUnderAttributeNameInMro) { 493 ASSERT_FALSE(runFromCStr(runtime_, R"( 494class A: 495 def foo(self): return 1 496 def bar(self): return 1 497 498def x(a): 499 return a.foo() 500 501def y(a): 502 return a.bar() 503 504a = A() 505 506x(a) 507y(a) 508)") 509 .isError()); 510 511 HandleScope scope(thread_); 512 Type type_a(&scope, mainModuleAt(runtime_, "A")); 513 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 514 Object bar_name(&scope, Runtime::internStrFromCStr(thread_, "bar")); 515 Function dependent_x(&scope, mainModuleAt(runtime_, "x")); 516 Function dependent_y(&scope, mainModuleAt(runtime_, "y")); 517 518 // A.foo -> x 519 ValueCell foo_in_a(&scope, typeValueCellAt(*type_a, *foo_name)); 520 ASSERT_EQ(WeakLink::cast(foo_in_a.dependencyLink()).referent(), *dependent_x); 521 522 // A.bar -> y 523 ValueCell bar_in_a(&scope, typeValueCellAt(*type_a, *bar_name)); 524 ASSERT_EQ(WeakLink::cast(bar_in_a.dependencyLink()).referent(), *dependent_y); 525 526 LayoutId type_a_instance_layout_id = type_a.instanceLayoutId(); 527 // Try to delete dependent_y under name "foo". Nothing happens. 528 icDeleteDependentFromInheritingTypes(thread_, type_a_instance_layout_id, 529 foo_name, type_a, dependent_y); 530 EXPECT_EQ(WeakLink::cast(foo_in_a.dependencyLink()).referent(), *dependent_x); 531 EXPECT_EQ(WeakLink::cast(bar_in_a.dependencyLink()).referent(), *dependent_y); 532 533 // Try to delete dependent_x under name "bar". Nothing happens. 534 icDeleteDependentFromInheritingTypes(thread_, type_a_instance_layout_id, 535 bar_name, type_a, dependent_x); 536 EXPECT_EQ(WeakLink::cast(foo_in_a.dependencyLink()).referent(), *dependent_x); 537 EXPECT_EQ(WeakLink::cast(bar_in_a.dependencyLink()).referent(), *dependent_y); 538 539 icDeleteDependentFromInheritingTypes(thread_, type_a_instance_layout_id, 540 foo_name, type_a, dependent_x); 541 EXPECT_TRUE(foo_in_a.dependencyLink().isNoneType()); 542 EXPECT_EQ(WeakLink::cast(bar_in_a.dependencyLink()).referent(), *dependent_y); 543 544 icDeleteDependentFromInheritingTypes(thread_, type_a_instance_layout_id, 545 bar_name, type_a, dependent_y); 546 EXPECT_TRUE(foo_in_a.dependencyLink().isNoneType()); 547 EXPECT_TRUE(bar_in_a.dependencyLink().isNoneType()); 548} 549 550TEST_F(IcTest, 551 IcDeleteDependentFromCachedAttributeDeletesDependentUpToUpdatedType) { 552 ASSERT_FALSE(runFromCStr(runtime_, R"( 553class A: 554 def foo(self): return 1 555 556class B(A): 557 def foo(self): return 2 558 559class C(B): 560 pass 561 562def x(c): 563 return c.foo() 564 565c = C() 566x(c) 567 568a = A() 569x(a) 570)") 571 .isError()); 572 573 HandleScope scope(thread_); 574 Type a(&scope, mainModuleAt(runtime_, "A")); 575 Type b(&scope, mainModuleAt(runtime_, "B")); 576 Type c(&scope, mainModuleAt(runtime_, "C")); 577 Object dependent_x(&scope, mainModuleAt(runtime_, "x")); 578 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 579 580 // A.foo -> x 581 ValueCell foo_in_a(&scope, typeValueCellAt(*a, *foo_name)); 582 ASSERT_FALSE(foo_in_a.isPlaceholder()); 583 ASSERT_EQ(WeakLink::cast(foo_in_a.dependencyLink()).referent(), *dependent_x); 584 585 // B.foo -> x 586 ValueCell foo_in_b(&scope, typeValueCellAt(*b, *foo_name)); 587 ASSERT_FALSE(foo_in_b.isPlaceholder()); 588 ASSERT_EQ(WeakLink::cast(foo_in_b.dependencyLink()).referent(), *dependent_x); 589 590 // C.foo -> x 591 // Note that this dependency is a placeholder. 592 ValueCell foo_in_c(&scope, typeValueCellAt(*c, *foo_name)); 593 ASSERT_TRUE(foo_in_c.isPlaceholder()); 594 ASSERT_EQ(WeakLink::cast(foo_in_c.dependencyLink()).referent(), *dependent_x); 595 596 Object c_obj(&scope, mainModuleAt(runtime_, "c")); 597 // Delete dependent_x for an update to B.foo. 598 icDeleteDependentFromInheritingTypes(thread_, c_obj.layoutId(), foo_name, b, 599 dependent_x); 600 601 // B.foo's update doesn't affect the cache for A.foo since the update does not 602 // shadow a.foo where type(a) == A. 603 EXPECT_TRUE(foo_in_c.dependencyLink().isNoneType()); 604 EXPECT_TRUE(foo_in_b.dependencyLink().isNoneType()); 605 // Didn't delete this since type lookup cannot reach A by successful attribute 606 // lookup for "foo" in B. 607 EXPECT_EQ(WeakLink::cast(foo_in_a.dependencyLink()).referent(), *dependent_x); 608} 609 610TEST_F( 611 IcTest, 612 IcHighestSuperTypeNotInMroOfOtherCachedTypesReturnsHighestNotCachedSuperType) { 613 ASSERT_FALSE(runFromCStr(runtime_, R"( 614class A: 615 def foo(self): 616 return 4 617 618class B(A): 619 pass 620 621def cache_foo(x): 622 return x.foo 623 624a_foo = A.foo 625b = B() 626cache_foo(b) 627)") 628 .isError()); 629 HandleScope scope(thread_); 630 Function cache_foo(&scope, mainModuleAt(runtime_, "cache_foo")); 631 Object a_foo(&scope, mainModuleAt(runtime_, "a_foo")); 632 Object b_obj(&scope, mainModuleAt(runtime_, "b")); 633 Type a_type(&scope, mainModuleAt(runtime_, "A")); 634 MutableTuple caches(&scope, cache_foo.caches()); 635 ASSERT_EQ(icLookupAttr(*caches, 1, b_obj.layoutId()), *a_foo); 636 // Manually delete the cache for B.foo in cache_foo. 637 caches.atPut(1 * kIcPointersPerEntry + kIcEntryKeyOffset, NoneType::object()); 638 caches.atPut(1 * kIcPointersPerEntry + kIcEntryValueOffset, 639 NoneType::object()); 640 ASSERT_TRUE(icLookupAttr(*caches, 1, b_obj.layoutId()).isErrorNotFound()); 641 642 // Now cache_foo doesn't depend on neither A.foo nor B.foo, so this should 643 // return A. 644 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo")); 645 Object result(&scope, icHighestSuperTypeNotInMroOfOtherCachedTypes( 646 thread_, b_obj.layoutId(), foo, cache_foo)); 647 EXPECT_EQ(result, *a_type); 648} 649 650TEST_F(IcTest, IcIsCachedAttributeAffectedByUpdatedType) { 651 ASSERT_FALSE(runFromCStr(runtime_, R"( 652class A: 653 def foo(self): return 1 654 655class B(A): 656 def foo(self): return 2 657 658class C(B): 659 pass 660 661 662def x(c): 663 return c.foo() 664 665c = C() 666x(c) 667)") 668 .isError()); 669 HandleScope scope(thread_); 670 Type type_a(&scope, mainModuleAt(runtime_, "A")); 671 Type type_b(&scope, mainModuleAt(runtime_, "B")); 672 Type type_c(&scope, mainModuleAt(runtime_, "C")); 673 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 674 675 LayoutId type_c_instance_layout_id = type_c.instanceLayoutId(); 676 // Check if A.foo is not retrived from C.foo. 677 EXPECT_FALSE(icIsCachedAttributeAffectedByUpdatedType( 678 thread_, type_c_instance_layout_id, foo_name, type_a)); 679 // Check if B.foo is retrieved from C.foo. 680 EXPECT_TRUE(icIsCachedAttributeAffectedByUpdatedType( 681 thread_, type_c_instance_layout_id, foo_name, type_b)); 682 683 // Assign C.foo to a real value. 684 ValueCell foo_in_c(&scope, typeValueCellAt(*type_c, *foo_name)); 685 foo_in_c.setValue(NoneType::object()); 686 // Check if B.foo is not retrived from C.foo from now on. 687 EXPECT_FALSE(icIsCachedAttributeAffectedByUpdatedType( 688 thread_, type_c_instance_layout_id, foo_name, type_b)); 689 // Instead, C.foo is retrieved. 690 EXPECT_TRUE(icIsCachedAttributeAffectedByUpdatedType( 691 thread_, type_c_instance_layout_id, foo_name, type_c)); 692} 693 694// Create a function that maps cache index 1 to the given attribute name. 695static RawObject testingFunctionCachingAttributes( 696 Thread* thread, const Object& attribute_name) { 697 Runtime* runtime = thread->runtime(); 698 HandleScope scope(thread); 699 Tuple consts(&scope, runtime->emptyTuple()); 700 Object name(&scope, Str::empty()); 701 Tuple names(&scope, runtime->newTupleWith2(attribute_name, name)); 702 Code code(&scope, 703 newCodeWithBytesConstsNames(View<byte>(nullptr, 0), consts, names)); 704 705 MutableBytes rewritten_bytecode(&scope, 706 runtime->newMutableBytesUninitialized(8)); 707 rewrittenBytecodeOpAtPut(rewritten_bytecode, 0, LOAD_ATTR_ANAMORPHIC); 708 rewrittenBytecodeArgAtPut(rewritten_bytecode, 0, 0); 709 rewrittenBytecodeCacheAtPut(rewritten_bytecode, 0, 1); 710 711 Module module(&scope, findMainModule(runtime)); 712 Function function(&scope, 713 runtime->newFunctionWithCode(thread, name, code, module)); 714 function.setRewrittenBytecode(*rewritten_bytecode); 715 716 MutableTuple caches(&scope, 717 runtime->newMutableTuple(2 * kIcPointersPerEntry)); 718 caches.fill(NoneType::object()); 719 function.setCaches(*caches); 720 721 return *function; 722} 723 724TEST_F(IcTest, IcEvictCacheEvictsCachesForMatchingAttributeName) { 725 ASSERT_FALSE(runFromCStr(runtime_, R"( 726class C: pass 727 728c = C() 729)") 730 .isError()); 731 HandleScope scope(thread_); 732 Type type(&scope, mainModuleAt(runtime_, "C")); 733 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 734 Object bar_name(&scope, Runtime::internStrFromCStr(thread_, "bar")); 735 Function dependent(&scope, 736 testingFunctionCachingAttributes(thread_, foo_name)); 737 738 // foo -> dependent. 739 ValueCell foo(&scope, attributeValueCellAtPut(thread_, type, foo_name)); 740 ASSERT_TRUE( 741 icInsertDependentToValueCellDependencyLink(thread_, dependent, foo)); 742 743 // Create an attribute cache for an instance of C, under name "foo". 744 Object instance(&scope, mainModuleAt(runtime_, "c")); 745 MutableTuple caches(&scope, dependent.caches()); 746 Object value(&scope, SmallInt::fromWord(1234)); 747 Object name(&scope, Str::empty()); 748 icUpdateAttr(thread_, caches, 1, instance.layoutId(), value, name, dependent); 749 ASSERT_EQ(icLookupAttr(*caches, 1, instance.layoutId()), 750 SmallInt::fromWord(1234)); 751 752 // Deleting caches for "bar" doesn't affect the cache for "foo". 753 icEvictCache(thread_, dependent, type, bar_name, 754 AttributeKind::kDataDescriptor); 755 EXPECT_EQ(icLookupAttr(*caches, 1, instance.layoutId()), 756 SmallInt::fromWord(1234)); 757 758 // Deleting caches for "foo". 759 icEvictCache(thread_, dependent, type, foo_name, 760 AttributeKind::kDataDescriptor); 761 EXPECT_TRUE(icLookupAttr(*caches, 1, instance.layoutId()).isErrorNotFound()); 762} 763 764TEST_F(IcTest, 765 IcEvictCacheEvictsCachesForInstanceOffsetOnlyWhenDataDesciptorIsTrue) { 766 ASSERT_FALSE(runFromCStr(runtime_, R"( 767class C: pass 768 769c = C() 770)") 771 .isError()); 772 HandleScope scope(thread_); 773 Type type(&scope, mainModuleAt(runtime_, "C")); 774 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 775 Function dependent(&scope, 776 testingFunctionCachingAttributes(thread_, foo_name)); 777 778 // foo -> dependent. 779 ValueCell foo(&scope, attributeValueCellAtPut(thread_, type, foo_name)); 780 ASSERT_TRUE( 781 icInsertDependentToValueCellDependencyLink(thread_, dependent, foo)); 782 783 // Create an instance offset cache for an instance of C, under name "foo". 784 Object instance(&scope, mainModuleAt(runtime_, "c")); 785 MutableTuple caches(&scope, dependent.caches()); 786 Object value(&scope, SmallInt::fromWord(1234)); 787 Object name(&scope, Str::empty()); 788 icUpdateAttr(thread_, caches, 1, instance.layoutId(), value, name, dependent); 789 ASSERT_EQ(icLookupAttr(*caches, 1, instance.layoutId()), 790 SmallInt::fromWord(1234)); 791 792 // An attempt to delete caches for "foo" with data_descriptor == false doesn't 793 // affect it. 794 icEvictCache(thread_, dependent, type, foo_name, 795 AttributeKind::kNotADataDescriptor); 796 EXPECT_EQ(icLookupAttr(*caches, 1, instance.layoutId()), 797 SmallInt::fromWord(1234)); 798 799 // Delete caches for "foo" with data_descriptor == true actually deletes it. 800 icEvictCache(thread_, dependent, type, foo_name, 801 AttributeKind::kDataDescriptor); 802 EXPECT_TRUE(icLookupAttr(*caches, 1, instance.layoutId()).isErrorNotFound()); 803} 804 805TEST_F(IcTest, IcEvictCacheEvictsOnlyAffectedCaches) { 806 ASSERT_FALSE(runFromCStr(runtime_, R"( 807class A: 808 def foo(self): return 1 809 810class B(A): 811 def foo(self): return 2 812 813class C(B): pass 814 815a = A() 816b = B() 817c = C() 818)") 819 .isError()); 820 HandleScope scope(thread_); 821 Type a_type(&scope, mainModuleAt(runtime_, "A")); 822 Type b_type(&scope, mainModuleAt(runtime_, "B")); 823 Type c_type(&scope, mainModuleAt(runtime_, "C")); 824 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 825 Function dependent(&scope, 826 testingFunctionCachingAttributes(thread_, foo_name)); 827 828 // The following lines simulate that dependent caches a.foo, b.foo, c.foo, and 829 // x.foo. A.foo -> dependent. 830 ValueCell a_foo(&scope, typeValueCellAt(*a_type, *foo_name)); 831 ASSERT_TRUE( 832 icInsertDependentToValueCellDependencyLink(thread_, dependent, a_foo)); 833 // B.foo -> dependent. 834 ValueCell b_foo(&scope, typeValueCellAt(*b_type, *foo_name)); 835 ASSERT_TRUE( 836 icInsertDependentToValueCellDependencyLink(thread_, dependent, b_foo)); 837 // C.foo -> dependent. 838 ValueCell c_foo(&scope, attributeValueCellAtPut(thread_, c_type, foo_name)); 839 // This is a placeholder since C.foo is resolved to B.foo. 840 c_foo.makePlaceholder(); 841 ASSERT_TRUE( 842 icInsertDependentToValueCellDependencyLink(thread_, dependent, c_foo)); 843 844 // Create a cache for a.foo in dependent. 845 Object a(&scope, mainModuleAt(runtime_, "a")); 846 MutableTuple caches(&scope, dependent.caches()); 847 Object value_100(&scope, SmallInt::fromWord(100)); 848 Object name(&scope, Str::empty()); 849 icUpdateAttr(thread_, caches, 1, a.layoutId(), value_100, name, dependent); 850 ASSERT_EQ(icLookupAttr(*caches, 1, a.layoutId()), SmallInt::fromWord(100)); 851 // Create a cache for b.foo in dependent. 852 Object b(&scope, mainModuleAt(runtime_, "b")); 853 Object value_200(&scope, SmallInt::fromWord(200)); 854 icUpdateAttr(thread_, caches, 1, b.layoutId(), value_200, name, dependent); 855 ASSERT_EQ(icLookupAttr(*caches, 1, b.layoutId()), SmallInt::fromWord(200)); 856 // Create a cache for c.foo in dependent. 857 Object c(&scope, mainModuleAt(runtime_, "c")); 858 Object value_300(&scope, SmallInt::fromWord(300)); 859 icUpdateAttr(thread_, caches, 1, c.layoutId(), value_300, name, dependent); 860 ASSERT_EQ(icLookupAttr(*caches, 1, c.layoutId()), SmallInt::fromWord(300)); 861 862 // Trigger invalidation by updating B.foo. 863 icEvictCache(thread_, dependent, b_type, foo_name, 864 AttributeKind::kDataDescriptor); 865 // Note that only caches made for the type attribute are evincted, and 866 // dependent is dropped from them. 867 EXPECT_EQ(icLookupAttr(*caches, 1, a.layoutId()), SmallInt::fromWord(100)); 868 EXPECT_EQ(WeakLink::cast(a_foo.dependencyLink()).referent(), *dependent); 869 EXPECT_TRUE(icLookupAttr(*caches, 1, b.layoutId()).isErrorNotFound()); 870 EXPECT_TRUE(b_foo.dependencyLink().isNoneType()); 871 EXPECT_TRUE(icLookupAttr(*caches, 1, c.layoutId()).isErrorNotFound()); 872 EXPECT_TRUE(c_foo.dependencyLink().isNoneType()); 873 874 // Trigger invalidation by updating A.foo. 875 icEvictCache(thread_, dependent, a_type, foo_name, 876 AttributeKind::kDataDescriptor); 877 EXPECT_TRUE(icLookupAttr(*caches, 1, a.layoutId()).isErrorNotFound()); 878 EXPECT_TRUE(a_foo.dependencyLink().isNoneType()); 879} 880 881TEST_F(IcTest, IcEvictCacheWithPolymorphicCacheEvictsCache) { 882 ASSERT_FALSE(runFromCStr(runtime_, R"( 883class A: pass 884 885class B: pass 886 887a = A() 888b = B() 889)") 890 .isError()); 891 HandleScope scope(thread_); 892 Type a_type(&scope, mainModuleAt(runtime_, "A")); 893 Object a(&scope, mainModuleAt(runtime_, "a")); 894 Type b_type(&scope, mainModuleAt(runtime_, "B")); 895 Object b(&scope, mainModuleAt(runtime_, "b")); 896 897 Object a_value(&scope, runtime_->newInt(88)); 898 Object b_value(&scope, runtime_->newInt(99)); 899 Object name(&scope, Str::empty()); 900 Function dependent(&scope, testingFunctionCachingAttributes(thread_, name)); 901 MutableTuple caches(&scope, dependent.caches()); 902 ASSERT_EQ( 903 icUpdateAttr(thread_, caches, 1, a.layoutId(), a_value, name, dependent), 904 ICState::kMonomorphic); 905 EXPECT_EQ( 906 icUpdateAttr(thread_, caches, 1, b.layoutId(), b_value, name, dependent), 907 ICState::kPolymorphic); 908 bool is_found; 909 EXPECT_EQ(icLookupPolymorphic(*caches, 1, a.layoutId(), &is_found), *a_value); 910 EXPECT_TRUE(is_found); 911 EXPECT_EQ(icLookupPolymorphic(*caches, 1, b.layoutId(), &is_found), *b_value); 912 EXPECT_TRUE(is_found); 913 icEvictCache(thread_, dependent, a_type, name, 914 AttributeKind::kDataDescriptor); 915 EXPECT_TRUE(icLookupPolymorphic(*caches, 1, a.layoutId(), &is_found) 916 .isErrorNotFound()); 917 EXPECT_FALSE(is_found); 918 icEvictCache(thread_, dependent, b_type, name, 919 AttributeKind::kDataDescriptor); 920 EXPECT_TRUE(icLookupPolymorphic(*caches, 1, b.layoutId(), &is_found) 921 .isErrorNotFound()); 922 EXPECT_FALSE(is_found); 923} 924 925// Verify if IcInvalidateCachesForTypeAttr calls 926// DeleteCachesForTypeAttrInDependent with all dependents. 927TEST_F(IcTest, IcInvalidateCachesForTypeAttrProcessesAllDependents) { 928 ASSERT_FALSE(runFromCStr(runtime_, R"( 929class C: pass 930 931c = C() 932)") 933 .isError()); 934 HandleScope scope(thread_); 935 Type type(&scope, mainModuleAt(runtime_, "C")); 936 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 937 Object bar_name(&scope, Runtime::internStrFromCStr(thread_, "bar")); 938 Function dependent0(&scope, 939 testingFunctionCachingAttributes(thread_, foo_name)); 940 Function dependent1(&scope, 941 testingFunctionCachingAttributes(thread_, bar_name)); 942 943 // Create a property so these value cells look like data descriptor attributes 944 Object none(&scope, NoneType::object()); 945 Object data_descriptor(&scope, runtime_->newProperty(none, none, none)); 946 947 // foo -> dependent0. 948 ValueCell foo(&scope, attributeValueCellAtPut(thread_, type, foo_name)); 949 foo.setValue(*data_descriptor); 950 ASSERT_TRUE( 951 icInsertDependentToValueCellDependencyLink(thread_, dependent0, foo)); 952 953 // bar -> dependent1. 954 ValueCell bar(&scope, attributeValueCellAtPut(thread_, type, bar_name)); 955 bar.setValue(*data_descriptor); 956 957 ASSERT_TRUE( 958 icInsertDependentToValueCellDependencyLink(thread_, dependent1, bar)); 959 960 MutableTuple dependent0_caches(&scope, dependent0.caches()); 961 Object instance(&scope, mainModuleAt(runtime_, "c")); 962 { 963 // Create an attribute cache for an instance of C, under name "foo" in 964 // dependent0. 965 Object name(&scope, Str::empty()); 966 Object value(&scope, SmallInt::fromWord(1234)); 967 icUpdateAttr(thread_, dependent0_caches, 1, instance.layoutId(), value, 968 name, dependent0); 969 ASSERT_EQ(icLookupAttr(*dependent0_caches, 1, instance.layoutId()), 970 SmallInt::fromWord(1234)); 971 } 972 973 MutableTuple dependent1_caches(&scope, dependent1.caches()); 974 { 975 // Create an attribute cache for an instance of C, under name "bar" in 976 // dependent1. 977 Object name(&scope, Str::empty()); 978 Object value(&scope, SmallInt::fromWord(5678)); 979 icUpdateAttr(thread_, dependent1_caches, 1, instance.layoutId(), value, 980 name, dependent1); 981 ASSERT_EQ(icLookupAttr(*dependent1_caches, 1, instance.layoutId()), 982 SmallInt::fromWord(5678)); 983 } 984 985 icInvalidateAttr(thread_, type, foo_name, foo); 986 EXPECT_TRUE(icLookupAttr(*dependent0_caches, 1, instance.layoutId()) 987 .isErrorNotFound()); 988 EXPECT_EQ(icLookupAttr(*dependent1_caches, 1, instance.layoutId()), 989 SmallInt::fromWord(5678)); 990 991 icInvalidateAttr(thread_, type, bar_name, bar); 992 EXPECT_TRUE(icLookupAttr(*dependent0_caches, 1, instance.layoutId()) 993 .isErrorNotFound()); 994 EXPECT_TRUE(icLookupAttr(*dependent1_caches, 1, instance.layoutId()) 995 .isErrorNotFound()); 996} 997 998TEST_F(IcTest, 999 BinarySubscrUpdateCacheWithRaisingDescriptorPropagatesException) { 1000 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"( 1001class Desc: 1002 def __get__(self, instance, type): 1003 raise UserWarning("foo") 1004 1005class C: 1006 __getitem__ = Desc() 1007 1008container = C() 1009result = container[0] 1010)"), 1011 LayoutId::kUserWarning, "foo")); 1012} 1013 1014TEST_F(IcTest, IcIsAttrCachedInDependentReturnsTrueForAttrCaches) { 1015 ASSERT_FALSE(runFromCStr(runtime_, R"( 1016class X: 1017 def foo(self): return 4 1018 1019class Y(X): 1020 pass 1021 1022class A: 1023 def foo(self): return 4 1024 1025class B(A): 1026 pass 1027 1028def cache_Y_foo(): 1029 return Y().foo() 1030 1031cache_Y_foo() 1032)") 1033 .isError()); 1034 HandleScope scope(thread_); 1035 Type type_a(&scope, mainModuleAt(runtime_, "A")); 1036 Type type_b(&scope, mainModuleAt(runtime_, "B")); 1037 Type type_x(&scope, mainModuleAt(runtime_, "X")); 1038 Type type_y(&scope, mainModuleAt(runtime_, "Y")); 1039 Object foo(&scope, Runtime::internStrFromCStr(thread_, "foo")); 1040 Object bar(&scope, Runtime::internStrFromCStr(thread_, "bar")); 1041 Function cache_y_foo(&scope, mainModuleAt(runtime_, "cache_Y_foo")); 1042 1043 // Note that cache_y_foo depends both on X.foo and Y.foo since an 1044 // update to either one of them flows to Y().foo(). 1045 EXPECT_TRUE(icIsAttrCachedInDependent(thread_, type_x, foo, cache_y_foo)); 1046 EXPECT_TRUE(icIsAttrCachedInDependent(thread_, type_y, foo, cache_y_foo)); 1047 EXPECT_FALSE(icIsAttrCachedInDependent(thread_, type_x, bar, cache_y_foo)); 1048 EXPECT_FALSE(icIsAttrCachedInDependent(thread_, type_a, foo, cache_y_foo)); 1049 EXPECT_FALSE(icIsAttrCachedInDependent(thread_, type_b, foo, cache_y_foo)); 1050} 1051 1052TEST_F(IcTest, IcIsAttrCachedInDependentReturnsTrueForBinaryOpCaches) { 1053 ASSERT_FALSE(runFromCStr(runtime_, R"( 1054class X: 1055 def __ge__(self, other): return 5 1056 1057class Y(X): 1058 pass 1059 1060class A: 1061 def foo(self): return 4 1062 1063class B(A): 1064 pass 1065 1066def cache_Y_ge(): 1067 return Y() >= B() 1068 1069cache_Y_ge() 1070)") 1071 .isError()); 1072 HandleScope scope(thread_); 1073 Type type_x(&scope, mainModuleAt(runtime_, "X")); 1074 Type type_y(&scope, mainModuleAt(runtime_, "Y")); 1075 Type type_a(&scope, mainModuleAt(runtime_, "A")); 1076 Type type_b(&scope, mainModuleAt(runtime_, "B")); 1077 Object dunder_ge(&scope, Runtime::internStrFromCStr(thread_, "__ge__")); 1078 Object dunder_le(&scope, Runtime::internStrFromCStr(thread_, "__le__")); 1079 Function cache_ge(&scope, mainModuleAt(runtime_, "cache_Y_ge")); 1080 1081 // Note that cache_ge indirectly depends on X, but directly on Y since both 1082 // X.__ge__ and Y.__ge__ affect Y() >= sth. 1083 EXPECT_TRUE(icIsAttrCachedInDependent(thread_, type_x, dunder_ge, cache_ge)); 1084 EXPECT_TRUE(icIsAttrCachedInDependent(thread_, type_y, dunder_ge, cache_ge)); 1085 // Note that cache_ge indirectly depends on A, but directly on B since both 1086 // B.__le__ and C.__le__ affect sth >= B(). 1087 EXPECT_TRUE(icIsAttrCachedInDependent(thread_, type_a, dunder_le, cache_ge)); 1088 EXPECT_TRUE(icIsAttrCachedInDependent(thread_, type_b, dunder_le, cache_ge)); 1089 1090 EXPECT_FALSE(icIsAttrCachedInDependent(thread_, type_x, dunder_le, cache_ge)); 1091 EXPECT_FALSE(icIsAttrCachedInDependent(thread_, type_y, dunder_le, cache_ge)); 1092 EXPECT_FALSE(icIsAttrCachedInDependent(thread_, type_a, dunder_ge, cache_ge)); 1093 EXPECT_FALSE(icIsAttrCachedInDependent(thread_, type_b, dunder_ge, cache_ge)); 1094} 1095 1096TEST_F(IcTest, IcDependentIncludedWithNoneLinkReturnsFalse) { 1097 EXPECT_FALSE(icDependentIncluded(Unbound::object(), NoneType::object())); 1098} 1099 1100TEST_F(IcTest, IcDependentIncludedWithDependentInChainReturnsTrue) { 1101 HandleScope scope(thread_); 1102 Object none(&scope, NoneType::object()); 1103 Object one(&scope, runtime_->newSet()); 1104 Object two(&scope, runtime_->newSet()); 1105 Object three(&scope, runtime_->newSet()); 1106 // Set up None <- link0 <-> link1 <-> link2 -> None 1107 WeakLink link0(&scope, runtime_->newWeakLink(thread_, one, none, none)); 1108 WeakLink link1(&scope, runtime_->newWeakLink(thread_, two, link0, none)); 1109 WeakLink link2(&scope, runtime_->newWeakLink(thread_, three, link1, none)); 1110 link0.setNext(*link1); 1111 link1.setNext(*link2); 1112 EXPECT_TRUE(icDependentIncluded(*one, *link0)); 1113 EXPECT_TRUE(icDependentIncluded(*two, *link0)); 1114 EXPECT_TRUE(icDependentIncluded(*three, *link0)); 1115 1116 EXPECT_FALSE(icDependentIncluded(*one, *link1)); 1117 EXPECT_TRUE(icDependentIncluded(*two, *link1)); 1118 EXPECT_TRUE(icDependentIncluded(*three, *link1)); 1119 1120 EXPECT_FALSE(icDependentIncluded(*one, *link2)); 1121 EXPECT_FALSE(icDependentIncluded(*two, *link2)); 1122 EXPECT_TRUE(icDependentIncluded(*three, *link2)); 1123 1124 EXPECT_FALSE(icDependentIncluded(Unbound::object(), *link0)); 1125 EXPECT_FALSE(icDependentIncluded(Unbound::object(), *link1)); 1126 EXPECT_FALSE(icDependentIncluded(Unbound::object(), *link2)); 1127} 1128 1129TEST_F(IcTest, IcEvictCacheEvictsCompareOpCaches) { 1130 ASSERT_FALSE(runFromCStr(runtime_, R"( 1131class A: 1132 def __ge__(self, other): return True 1133 1134class B: pass 1135 1136def cache_compare_op(a, b): 1137 return a >= b 1138 1139a = A() 1140b = B() 1141A__ge__ = A.__ge__ 1142 1143cache_compare_op(a, b) 1144)") 1145 .isError()); 1146 HandleScope scope(thread_); 1147 Object a(&scope, mainModuleAt(runtime_, "a")); 1148 Object b(&scope, mainModuleAt(runtime_, "b")); 1149 Object type_a_dunder_ge(&scope, mainModuleAt(runtime_, "A__ge__")); 1150 Function cache_compare_op(&scope, mainModuleAt(runtime_, "cache_compare_op")); 1151 MutableTuple caches(&scope, cache_compare_op.caches()); 1152 BinaryOpFlags flags_out; 1153 Object cached(&scope, icLookupBinaryOp(*caches, 0, a.layoutId(), b.layoutId(), 1154 &flags_out)); 1155 // Precondition check that the A.__ge__ lookup has been cached. 1156 ASSERT_EQ(*cached, *type_a_dunder_ge); 1157 Type type_a(&scope, mainModuleAt(runtime_, "A")); 1158 Object dunder_ge_name(&scope, Runtime::internStrFromCStr(thread_, "__ge__")); 1159 ValueCell dunder_ge(&scope, typeValueCellAt(*type_a, *dunder_ge_name)); 1160 WeakLink dunder_ge_link(&scope, dunder_ge.dependencyLink()); 1161 // Precondition check that cache_compare_op is a dependent of A.__ge__. 1162 ASSERT_EQ(dunder_ge_link.referent(), *cache_compare_op); 1163 Type type_b(&scope, mainModuleAt(runtime_, "B")); 1164 Object dunder_le_name(&scope, Runtime::internStrFromCStr(thread_, "__le__")); 1165 ValueCell dunder_le(&scope, typeValueCellAt(*type_b, *dunder_le_name)); 1166 WeakLink dunder_le_link(&scope, dunder_le.dependencyLink()); 1167 // Precondition check that cache_compare_op is a dependent of B.__le__. 1168 ASSERT_EQ(dunder_le_link.referent(), *cache_compare_op); 1169 1170 // Updating A.__ge__ triggers cache invalidation. 1171 icEvictCache(thread_, cache_compare_op, type_a, dunder_ge_name, 1172 AttributeKind::kNotADataDescriptor); 1173 EXPECT_TRUE( 1174 icLookupBinaryOp(*caches, 0, a.layoutId(), b.layoutId(), &flags_out) 1175 .isErrorNotFound()); 1176 EXPECT_FALSE( 1177 icDependentIncluded(*cache_compare_op, dunder_ge.dependencyLink())); 1178 EXPECT_TRUE(dunder_le.dependencyLink().isNoneType()); 1179} 1180 1181TEST_F(IcTest, 1182 ForIterUpdateCacheWithRaisingDescriptorDunderNextPropagatesException) { 1183 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"( 1184class Desc: 1185 def __get__(self, instance, type): 1186 raise UserWarning("foo") 1187 1188class C: 1189 def __iter__(self): 1190 return self 1191 __next__ = Desc() 1192 1193container = C() 1194result = [x for x in container] 1195)"), 1196 LayoutId::kUserWarning, "foo")); 1197} 1198 1199TEST_F(IcTest, BinarySubscrUpdateCacheWithFunctionUpdatesCache) { 1200 ASSERT_FALSE(runFromCStr(runtime_, R"( 1201class Container: 1202 def __getitem__(self, index): 1203 return index + 1 1204 1205def f(c, k): 1206 return c[k] 1207 1208container = Container() 1209getitem = type(container).__getitem__ 1210result = f(container, 0) 1211)") 1212 .isError()); 1213 1214 HandleScope scope(thread_); 1215 Object result(&scope, mainModuleAt(runtime_, "result")); 1216 EXPECT_TRUE(isIntEqualsWord(*result, 1)); 1217 1218 Object container(&scope, mainModuleAt(runtime_, "container")); 1219 Object getitem(&scope, mainModuleAt(runtime_, "getitem")); 1220 Function f(&scope, mainModuleAt(runtime_, "f")); 1221 MutableTuple caches(&scope, f.caches()); 1222 // Expect that BINARY_SUBSCR is the only cached opcode in f(). 1223 ASSERT_EQ(caches.length(), 1 * kIcPointersPerEntry); 1224 EXPECT_EQ(icLookupAttr(*caches, 0, container.layoutId()), *getitem); 1225 1226 ASSERT_FALSE(runFromCStr(runtime_, R"( 1227container2 = Container() 1228result2 = f(container2, 1) 1229)") 1230 .isError()); 1231 Object container2(&scope, mainModuleAt(runtime_, "container2")); 1232 Object result2(&scope, mainModuleAt(runtime_, "result2")); 1233 EXPECT_EQ(container2.layoutId(), container.layoutId()); 1234 EXPECT_TRUE(isIntEqualsWord(*result2, 2)); 1235} 1236 1237TEST_F(IcTest, BinarySubscrUpdateCacheWithNonFunctionDoesntUpdateCache) { 1238 ASSERT_FALSE(runFromCStr(runtime_, R"( 1239def f(c, k): 1240 return c[k] 1241class Container: 1242 def get(self): 1243 def getitem(key): 1244 return key 1245 return getitem 1246 1247 __getitem__ = property(get) 1248 1249container = Container() 1250result = f(container, "hi") 1251)") 1252 .isError()); 1253 1254 HandleScope scope(thread_); 1255 Object result(&scope, mainModuleAt(runtime_, "result")); 1256 EXPECT_TRUE(isStrEqualsCStr(*result, "hi")); 1257 1258 Object container(&scope, mainModuleAt(runtime_, "container")); 1259 Function f(&scope, mainModuleAt(runtime_, "f")); 1260 MutableTuple caches(&scope, f.caches()); 1261 // Expect that BINARY_SUBSCR is the only cached opcode in f(). 1262 ASSERT_EQ(caches.length(), 1 * kIcPointersPerEntry); 1263 EXPECT_TRUE(icLookupAttr(*caches, 0, container.layoutId()).isErrorNotFound()); 1264 1265 ASSERT_FALSE(runFromCStr(runtime_, R"( 1266container2 = Container() 1267result2 = f(container, "hello there!") 1268)") 1269 .isError()); 1270 Object container2(&scope, mainModuleAt(runtime_, "container2")); 1271 Object result2(&scope, mainModuleAt(runtime_, "result2")); 1272 ASSERT_EQ(container2.layoutId(), container.layoutId()); 1273 EXPECT_TRUE(isStrEqualsCStr(*result2, "hello there!")); 1274} 1275 1276TEST_F(IcTest, IcUpdateBinaryOpSetsEmptyEntry) { 1277 HandleScope scope(thread_); 1278 MutableTuple caches(&scope, 1279 runtime_->newMutableTuple(2 * kIcPointersPerEntry)); 1280 caches.fill(NoneType::object()); 1281 Object value(&scope, runtime_->newStrFromCStr("this is a random value")); 1282 EXPECT_EQ(icUpdateBinOp(thread_, caches, 1, LayoutId::kLargeInt, 1283 LayoutId::kSmallInt, value, kBinaryOpNone), 1284 ICState::kMonomorphic); 1285 BinaryOpFlags flags; 1286 EXPECT_EQ(icLookupBinOpMonomorphic(*caches, 1, LayoutId::kLargeInt, 1287 LayoutId::kSmallInt, &flags), 1288 *value); 1289} 1290 1291TEST_F(IcTest, IcUpdateBinaryOpSetsExistingMonomorphicEntry) { 1292 HandleScope scope(thread_); 1293 1294 MutableTuple caches(&scope, 1295 runtime_->newMutableTuple(2 * kIcPointersPerEntry)); 1296 caches.fill(NoneType::object()); 1297 Object value(&scope, runtime_->newStrFromCStr("xxx")); 1298 ASSERT_EQ(icUpdateBinOp(thread_, caches, 1, LayoutId::kLargeInt, 1299 LayoutId::kSmallInt, value, kBinaryOpNone), 1300 ICState::kMonomorphic); 1301 Object new_value(&scope, runtime_->newStrFromCStr("yyy")); 1302 EXPECT_EQ(icUpdateBinOp(thread_, caches, 1, LayoutId::kLargeInt, 1303 LayoutId::kSmallInt, new_value, kBinaryOpNone), 1304 ICState::kMonomorphic); 1305 BinaryOpFlags flags; 1306 EXPECT_EQ(icLookupBinOpMonomorphic(*caches, 1, LayoutId::kLargeInt, 1307 LayoutId::kSmallInt, &flags), 1308 *new_value); 1309} 1310 1311TEST_F(IcTest, IcUpdateBinaryOpSetsExistingPolymorphicEntry) { 1312 HandleScope scope(thread_); 1313 1314 MutableTuple caches(&scope, 1315 runtime_->newMutableTuple(2 * kIcPointersPerEntry)); 1316 caches.fill(NoneType::object()); 1317 Object value(&scope, runtime_->newStrFromCStr("xxx")); 1318 ASSERT_EQ(icUpdateBinOp(thread_, caches, 1, LayoutId::kLargeInt, 1319 LayoutId::kSmallInt, value, kBinaryOpNone), 1320 ICState::kMonomorphic); 1321 BinaryOpFlags flags; 1322 ASSERT_EQ(icLookupBinOpMonomorphic(*caches, 1, LayoutId::kLargeInt, 1323 LayoutId::kSmallInt, &flags), 1324 *value); 1325 1326 ASSERT_EQ(icUpdateBinOp(thread_, caches, 1, LayoutId::kSmallInt, 1327 LayoutId::kLargeInt, value, kBinaryOpNone), 1328 ICState::kPolymorphic); 1329 ASSERT_EQ(icLookupBinOpPolymorphic(*caches, 1, LayoutId::kSmallInt, 1330 LayoutId::kLargeInt, &flags), 1331 *value); 1332 1333 Object new_value(&scope, runtime_->newStrFromCStr("yyy")); 1334 EXPECT_EQ(icUpdateBinOp(thread_, caches, 1, LayoutId::kLargeInt, 1335 LayoutId::kSmallInt, new_value, kBinaryOpNone), 1336 ICState::kPolymorphic); 1337 EXPECT_EQ(icLookupBinOpPolymorphic(*caches, 1, LayoutId::kLargeInt, 1338 LayoutId::kSmallInt, &flags), 1339 *new_value); 1340} 1341 1342TEST_F(IcTest, ForIterUpdateCacheWithFunctionUpdatesCache) { 1343 ASSERT_FALSE(runFromCStr(runtime_, R"( 1344def f(container): 1345 for i in container: 1346 return i 1347 1348class C: 1349 def __iter__(self): 1350 return Iterator() 1351 1352class Iterator: 1353 def __init__(self): 1354 self.next_called = False 1355 1356 def __next__(self): 1357 if self.next_called: 1358 raise StopIteration 1359 return 1 1360 1361container = C() 1362iterator = iter(container) 1363iter_next = Iterator.__next__ 1364result = f(container) 1365)") 1366 .isError()); 1367 1368 HandleScope scope(thread_); 1369 Object result(&scope, mainModuleAt(runtime_, "result")); 1370 EXPECT_TRUE(isIntEqualsWord(*result, 1)); 1371 1372 Object iterator(&scope, mainModuleAt(runtime_, "iterator")); 1373 Object iter_next(&scope, mainModuleAt(runtime_, "iter_next")); 1374 Function f(&scope, mainModuleAt(runtime_, "f")); 1375 MutableTuple caches(&scope, f.caches()); 1376 // Expect that FOR_ITER is the only cached opcode in f(). 1377 ASSERT_EQ(caches.length(), 1 * kIcPointersPerEntry); 1378 EXPECT_EQ(icLookupAttr(*caches, 0, iterator.layoutId()), *iter_next); 1379} 1380 1381TEST_F(IcTest, ForIterUpdateCacheWithNonFunctionDoesntUpdateCache) { 1382 ASSERT_FALSE(runFromCStr(runtime_, R"( 1383def f(container): 1384 for i in container: 1385 return i 1386 1387class Iter: 1388 def get(self): 1389 def next(): 1390 return 123 1391 return next 1392 __next__ = property(get) 1393 1394class Container: 1395 def __iter__(self): 1396 return Iter() 1397 1398container = Container() 1399iterator = iter(container) 1400result = f(container) 1401)") 1402 .isError()); 1403 1404 HandleScope scope(thread_); 1405 Object result(&scope, mainModuleAt(runtime_, "result")); 1406 EXPECT_TRUE(isIntEqualsWord(*result, 123)); 1407 1408 Object iterator(&scope, mainModuleAt(runtime_, "iterator")); 1409 Function f(&scope, mainModuleAt(runtime_, "f")); 1410 MutableTuple caches(&scope, f.caches()); 1411 // Expect that FOR_ITER is the only cached opcode in f(). 1412 ASSERT_EQ(caches.length(), 1 * kIcPointersPerEntry); 1413 EXPECT_TRUE(icLookupAttr(*caches, 0, iterator.layoutId()).isErrorNotFound()); 1414} 1415 1416static RawObject testingFunction(Thread* thread) { 1417 Runtime* runtime = thread->runtime(); 1418 HandleScope scope(thread); 1419 Object name(&scope, Str::empty()); 1420 Tuple consts(&scope, runtime->emptyTuple()); 1421 Tuple names(&scope, runtime->newTupleWith2(name, name)); 1422 Code code(&scope, 1423 newCodeWithBytesConstsNames(View<byte>(nullptr, 0), consts, names)); 1424 MutableBytes rewritten_bytecode( 1425 &scope, runtime->newMutableBytesUninitialized(4 * kCodeUnitSize)); 1426 rewrittenBytecodeOpAtPut(rewritten_bytecode, 0, LOAD_GLOBAL); 1427 rewrittenBytecodeArgAtPut(rewritten_bytecode, 0, 0); 1428 rewrittenBytecodeOpAtPut(rewritten_bytecode, 1, STORE_GLOBAL); 1429 rewrittenBytecodeArgAtPut(rewritten_bytecode, 1, 1); 1430 rewrittenBytecodeOpAtPut(rewritten_bytecode, 2, LOAD_GLOBAL); 1431 rewrittenBytecodeArgAtPut(rewritten_bytecode, 2, 0); 1432 rewrittenBytecodeOpAtPut(rewritten_bytecode, 3, STORE_GLOBAL); 1433 rewrittenBytecodeArgAtPut(rewritten_bytecode, 3, 1); 1434 1435 Module module(&scope, findMainModule(runtime)); 1436 Function function(&scope, 1437 runtime->newFunctionWithCode(thread, name, code, module)); 1438 function.setRewrittenBytecode(*rewritten_bytecode); 1439 1440 MutableTuple caches(&scope, runtime->newMutableTuple(2)); 1441 caches.fill(NoneType::object()); 1442 function.setCaches(*caches); 1443 return *function; 1444} 1445 1446TEST_F(IcTest, 1447 IcInsertDependentToValueCellDependencyLinkInsertsDependentAsHead) { 1448 HandleScope scope(thread_); 1449 Function function0(&scope, testingFunction(thread_)); 1450 Function function1(&scope, testingFunction(thread_)); 1451 1452 ValueCell cache(&scope, runtime_->newValueCell()); 1453 ASSERT_TRUE(cache.dependencyLink().isNoneType()); 1454 1455 EXPECT_TRUE( 1456 icInsertDependentToValueCellDependencyLink(thread_, function0, cache)); 1457 WeakLink link0(&scope, cache.dependencyLink()); 1458 EXPECT_EQ(link0.referent(), *function0); 1459 EXPECT_TRUE(link0.prev().isNoneType()); 1460 EXPECT_TRUE(link0.next().isNoneType()); 1461 1462 EXPECT_TRUE( 1463 icInsertDependentToValueCellDependencyLink(thread_, function1, cache)); 1464 WeakLink link1(&scope, cache.dependencyLink()); 1465 EXPECT_EQ(link1.referent(), *function1); 1466 EXPECT_TRUE(link1.prev().isNoneType()); 1467 EXPECT_EQ(link1.next(), *link0); 1468} 1469 1470TEST_F( 1471 IcTest, 1472 IcInsertDependentToValueCellDependencyLinkDoesNotInsertExistingDependent) { 1473 HandleScope scope(thread_); 1474 Function function0(&scope, testingFunction(thread_)); 1475 Function function1(&scope, testingFunction(thread_)); 1476 1477 ValueCell cache(&scope, runtime_->newValueCell()); 1478 EXPECT_TRUE( 1479 icInsertDependentToValueCellDependencyLink(thread_, function0, cache)); 1480 EXPECT_TRUE( 1481 icInsertDependentToValueCellDependencyLink(thread_, function1, cache)); 1482 EXPECT_FALSE( 1483 icInsertDependentToValueCellDependencyLink(thread_, function0, cache)); 1484 1485 WeakLink link(&scope, cache.dependencyLink()); 1486 EXPECT_EQ(link.referent(), *function1); 1487 EXPECT_TRUE(link.prev().isNoneType()); 1488 EXPECT_EQ(WeakLink::cast(link.next()).referent(), *function0); 1489 EXPECT_TRUE(WeakLink::cast(link.next()).next().isNoneType()); 1490} 1491 1492TEST_F(IcTest, IcUpdateGlobalVarFillsCacheLineAndReplaceOpcode) { 1493 HandleScope scope(thread_); 1494 Function function(&scope, testingFunction(thread_)); 1495 MutableTuple caches(&scope, function.caches()); 1496 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode()); 1497 1498 ValueCell cache(&scope, runtime_->newValueCell()); 1499 cache.setValue(SmallInt::fromWord(99)); 1500 ValueCell another_cache(&scope, runtime_->newValueCell()); 1501 another_cache.setValue(SmallInt::fromWord(123)); 1502 1503 icUpdateGlobalVar(thread_, function, 0, cache); 1504 1505 EXPECT_EQ(caches.at(0), cache); 1506 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 0), LOAD_GLOBAL_CACHED); 1507 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 1), STORE_GLOBAL); 1508 1509 icUpdateGlobalVar(thread_, function, 1, another_cache); 1510 1511 EXPECT_EQ(caches.at(0), cache); 1512 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 0), LOAD_GLOBAL_CACHED); 1513 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 1), STORE_GLOBAL_CACHED); 1514} 1515 1516TEST_F(IcTest, IcUpdateGlobalVarFillsCacheLineAndReplaceOpcodeWithExtendedArg) { 1517 HandleScope scope(thread_); 1518 Function function(&scope, testingFunction(thread_)); 1519 MutableTuple caches(&scope, function.caches()); 1520 1521 MutableBytes rewritten_bytecode( 1522 &scope, runtime_->newMutableBytesUninitialized(4 * kCodeUnitSize)); 1523 // TODO(T45440363): Replace the argument of EXTENDED_ARG for a non-zero value. 1524 rewrittenBytecodeOpAtPut(rewritten_bytecode, 0, EXTENDED_ARG); 1525 rewrittenBytecodeArgAtPut(rewritten_bytecode, 0, 0); 1526 rewrittenBytecodeOpAtPut(rewritten_bytecode, 1, LOAD_GLOBAL); 1527 rewrittenBytecodeArgAtPut(rewritten_bytecode, 1, 0); 1528 rewrittenBytecodeOpAtPut(rewritten_bytecode, 2, EXTENDED_ARG); 1529 rewrittenBytecodeArgAtPut(rewritten_bytecode, 2, 0); 1530 rewrittenBytecodeOpAtPut(rewritten_bytecode, 3, STORE_GLOBAL); 1531 rewrittenBytecodeArgAtPut(rewritten_bytecode, 3, 1); 1532 function.setRewrittenBytecode(*rewritten_bytecode); 1533 1534 ValueCell cache(&scope, runtime_->newValueCell()); 1535 cache.setValue(SmallInt::fromWord(99)); 1536 ValueCell another_cache(&scope, runtime_->newValueCell()); 1537 another_cache.setValue(SmallInt::fromWord(123)); 1538 1539 icUpdateGlobalVar(thread_, function, 0, cache); 1540 1541 EXPECT_EQ(caches.at(0), cache); 1542 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 1), LOAD_GLOBAL_CACHED); 1543 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 3), STORE_GLOBAL); 1544 1545 icUpdateGlobalVar(thread_, function, 1, another_cache); 1546 1547 EXPECT_EQ(caches.at(0), cache); 1548 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 1), LOAD_GLOBAL_CACHED); 1549 EXPECT_EQ(rewrittenBytecodeOpAt(rewritten_bytecode, 3), STORE_GLOBAL_CACHED); 1550} 1551 1552TEST_F(IcTest, IcUpdateGlobalVarCreatesDependencyLink) { 1553 HandleScope scope(thread_); 1554 Function function(&scope, testingFunction(thread_)); 1555 ValueCell cache(&scope, runtime_->newValueCell()); 1556 cache.setValue(SmallInt::fromWord(99)); 1557 icUpdateGlobalVar(thread_, function, 0, cache); 1558 1559 ASSERT_TRUE(cache.dependencyLink().isWeakLink()); 1560 WeakLink link(&scope, cache.dependencyLink()); 1561 EXPECT_EQ(link.referent(), *function); 1562 EXPECT_EQ(link.prev(), NoneType::object()); 1563 EXPECT_EQ(link.next(), NoneType::object()); 1564} 1565 1566TEST_F(IcTest, IcUpdateGlobalVarInsertsHeadOfDependencyLink) { 1567 HandleScope scope(thread_); 1568 Function function0(&scope, testingFunction(thread_)); 1569 Function function1(&scope, testingFunction(thread_)); 1570 1571 // Adds cache into function0's caches first, then to function1's. 1572 ValueCell cache(&scope, runtime_->newValueCell()); 1573 cache.setValue(SmallInt::fromWord(99)); 1574 icUpdateGlobalVar(thread_, function0, 0, cache); 1575 icUpdateGlobalVar(thread_, function1, 0, cache); 1576 1577 ASSERT_TRUE(cache.dependencyLink().isWeakLink()); 1578 WeakLink link(&scope, cache.dependencyLink()); 1579 EXPECT_EQ(link.referent(), *function1); 1580 EXPECT_TRUE(link.prev().isNoneType()); 1581 1582 WeakLink next_link(&scope, link.next()); 1583 EXPECT_EQ(next_link.referent(), *function0); 1584 EXPECT_EQ(next_link.prev(), *link); 1585 EXPECT_TRUE(next_link.next().isNoneType()); 1586} 1587 1588TEST_F(IcTest, 1589 IcInvalidateGlobalVarRemovesInvalidatedCacheFromReferencedFunctions) { 1590 HandleScope scope(thread_); 1591 Function function0(&scope, testingFunction(thread_)); 1592 Function function1(&scope, testingFunction(thread_)); 1593 MutableTuple caches0(&scope, function0.caches()); 1594 MutableTuple caches1(&scope, function1.caches()); 1595 1596 // Both caches of Function0 & 1 caches the same cache value. 1597 ValueCell cache(&scope, runtime_->newValueCell()); 1598 cache.setValue(SmallInt::fromWord(99)); 1599 ValueCell another_cache(&scope, runtime_->newValueCell()); 1600 another_cache.setValue(SmallInt::fromWord(123)); 1601 1602 icUpdateGlobalVar(thread_, function0, 0, cache); 1603 icUpdateGlobalVar(thread_, function0, 1, another_cache); 1604 icUpdateGlobalVar(thread_, function1, 0, another_cache); 1605 icUpdateGlobalVar(thread_, function1, 1, cache); 1606 1607 EXPECT_TRUE( 1608 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches0, 0)), 99)); 1609 EXPECT_TRUE( 1610 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches0, 1)), 123)); 1611 EXPECT_TRUE( 1612 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches1, 0)), 123)); 1613 EXPECT_TRUE( 1614 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches1, 1)), 99)); 1615 1616 // Invalidating cache makes it removed from both caches, and nobody depends on 1617 // it anymore. 1618 icInvalidateGlobalVar(thread_, cache); 1619 1620 EXPECT_TRUE(icLookupGlobalVar(*caches0, 0).isNoneType()); 1621 EXPECT_TRUE( 1622 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches0, 1)), 123)); 1623 EXPECT_TRUE( 1624 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches1, 0)), 123)); 1625 EXPECT_TRUE(icLookupGlobalVar(*caches1, 1).isNoneType()); 1626 EXPECT_TRUE(cache.dependencyLink().isNoneType()); 1627} 1628 1629TEST_F(IcTest, IcInvalidateGlobalVarDoNotDeferenceDeallocatedReferent) { 1630 HandleScope scope(thread_); 1631 Function function0(&scope, testingFunction(thread_)); 1632 Function function1(&scope, testingFunction(thread_)); 1633 MutableTuple caches0(&scope, function0.caches()); 1634 MutableTuple caches1(&scope, function1.caches()); 1635 1636 // Both caches of Function0 & 1 caches the same cache value. 1637 ValueCell cache(&scope, runtime_->newValueCell()); 1638 cache.setValue(SmallInt::fromWord(99)); 1639 ValueCell another_cache(&scope, runtime_->newValueCell()); 1640 another_cache.setValue(SmallInt::fromWord(123)); 1641 1642 icUpdateGlobalVar(thread_, function0, 0, cache); 1643 icUpdateGlobalVar(thread_, function0, 1, another_cache); 1644 icUpdateGlobalVar(thread_, function1, 0, another_cache); 1645 icUpdateGlobalVar(thread_, function1, 1, cache); 1646 1647 ASSERT_TRUE( 1648 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches0, 0)), 99)); 1649 ASSERT_TRUE( 1650 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches0, 1)), 123)); 1651 ASSERT_TRUE( 1652 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches1, 0)), 123)); 1653 ASSERT_TRUE( 1654 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches1, 1)), 99)); 1655 1656 // Simulate GCing function1. 1657 WeakLink link(&scope, cache.dependencyLink()); 1658 ASSERT_EQ(link.referent(), *function1); 1659 link.setReferent(NoneType::object()); 1660 1661 // Invalidation cannot touch function1 anymore. 1662 icInvalidateGlobalVar(thread_, cache); 1663 1664 EXPECT_TRUE(icLookupGlobalVar(*caches0, 0).isNoneType()); 1665 EXPECT_TRUE( 1666 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches0, 1)), 123)); 1667 EXPECT_TRUE( 1668 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches1, 0)), 123)); 1669 EXPECT_TRUE( 1670 isIntEqualsWord(valueCellValue(icLookupGlobalVar(*caches1, 1)), 99)); 1671 EXPECT_TRUE(cache.dependencyLink().isNoneType()); 1672} 1673 1674TEST_F(IcTest, IcInvalidateGlobalVarRevertsOpCodeToOriginalOnes) { 1675 HandleScope scope(thread_); 1676 Function function(&scope, testingFunction(thread_)); 1677 MutableBytes bytecode(&scope, function.rewrittenBytecode()); 1678 ValueCell cache(&scope, runtime_->newValueCell()); 1679 cache.setValue(SmallInt::fromWord(99)); 1680 ValueCell another_cache(&scope, runtime_->newValueCell()); 1681 another_cache.setValue(SmallInt::fromWord(123)); 1682 1683 byte original_expected[] = {LOAD_GLOBAL, 0, 0, 0, STORE_GLOBAL, 1, 0, 0, 1684 LOAD_GLOBAL, 0, 0, 0, STORE_GLOBAL, 1, 0, 0}; 1685 ASSERT_TRUE(isMutableBytesEqualsBytes(bytecode, original_expected)); 1686 1687 icUpdateGlobalVar(thread_, function, 0, cache); 1688 byte cached_expected0[] = { 1689 LOAD_GLOBAL_CACHED, 0, 0, 0, STORE_GLOBAL, 1, 0, 0, 1690 LOAD_GLOBAL_CACHED, 0, 0, 0, STORE_GLOBAL, 1, 0, 0}; 1691 EXPECT_TRUE(isMutableBytesEqualsBytes(bytecode, cached_expected0)); 1692 1693 icUpdateGlobalVar(thread_, function, 1, another_cache); 1694 byte cached_expected1[] = { 1695 LOAD_GLOBAL_CACHED, 0, 0, 0, STORE_GLOBAL_CACHED, 1, 0, 0, 1696 LOAD_GLOBAL_CACHED, 0, 0, 0, STORE_GLOBAL_CACHED, 1, 0, 0}; 1697 EXPECT_TRUE(isMutableBytesEqualsBytes(bytecode, cached_expected1)); 1698 1699 icInvalidateGlobalVar(thread_, cache); 1700 1701 // Only invalidated cache's opcode gets reverted to the original one. 1702 byte invalidated_expected[] = { 1703 LOAD_GLOBAL, 0, 0, 0, STORE_GLOBAL_CACHED, 1, 0, 0, 1704 LOAD_GLOBAL, 0, 0, 0, STORE_GLOBAL_CACHED, 1, 0, 0, 1705 }; 1706 EXPECT_TRUE(isMutableBytesEqualsBytes(bytecode, invalidated_expected)); 1707} 1708 1709TEST_F(IcTest, IcIteratorIteratesOverAttrCaches) { 1710 HandleScope scope(thread_); 1711 MutableBytes bytecode( 1712 &scope, runtime_->newMutableBytesUninitialized(10 * kCodeUnitSize)); 1713 rewrittenBytecodeOpAtPut(bytecode, 0, LOAD_GLOBAL); 1714 rewrittenBytecodeArgAtPut(bytecode, 0, 100); 1715 rewrittenBytecodeCacheAtPut(bytecode, 0, 0); 1716 rewrittenBytecodeOpAtPut(bytecode, 1, LOAD_ATTR_ANAMORPHIC); 1717 rewrittenBytecodeArgAtPut(bytecode, 1, 0); 1718 rewrittenBytecodeCacheAtPut(bytecode, 1, 0); 1719 rewrittenBytecodeOpAtPut(bytecode, 2, LOAD_GLOBAL); 1720 rewrittenBytecodeArgAtPut(bytecode, 2, 100); 1721 rewrittenBytecodeCacheAtPut(bytecode, 2, 0); 1722 rewrittenBytecodeOpAtPut(bytecode, 3, LOAD_METHOD_ANAMORPHIC); 1723 rewrittenBytecodeArgAtPut(bytecode, 3, 1); 1724 rewrittenBytecodeCacheAtPut(bytecode, 3, 1); 1725 rewrittenBytecodeOpAtPut(bytecode, 4, LOAD_GLOBAL); 1726 rewrittenBytecodeArgAtPut(bytecode, 4, 100); 1727 rewrittenBytecodeCacheAtPut(bytecode, 4, 0); 1728 rewrittenBytecodeOpAtPut(bytecode, 5, LOAD_ATTR_ANAMORPHIC); 1729 rewrittenBytecodeArgAtPut(bytecode, 5, 2); 1730 rewrittenBytecodeCacheAtPut(bytecode, 5, 2); 1731 rewrittenBytecodeOpAtPut(bytecode, 6, STORE_ATTR_ANAMORPHIC); 1732 rewrittenBytecodeArgAtPut(bytecode, 6, 3); 1733 rewrittenBytecodeCacheAtPut(bytecode, 6, 3); 1734 rewrittenBytecodeOpAtPut(bytecode, 7, FOR_ITER_ANAMORPHIC); 1735 rewrittenBytecodeArgAtPut(bytecode, 7, -1); 1736 rewrittenBytecodeCacheAtPut(bytecode, 7, 4); 1737 rewrittenBytecodeOpAtPut(bytecode, 8, BINARY_SUBSCR_ANAMORPHIC); 1738 rewrittenBytecodeArgAtPut(bytecode, 8, -1); 1739 rewrittenBytecodeCacheAtPut(bytecode, 8, 5); 1740 rewrittenBytecodeOpAtPut(bytecode, 9, LOAD_GLOBAL); 1741 rewrittenBytecodeArgAtPut(bytecode, 9, 100); 1742 rewrittenBytecodeCacheAtPut(bytecode, 9, 0); 1743 1744 word num_caches = 6; 1745 1746 Object name1(&scope, Runtime::internStrFromCStr( 1747 thread_, "load_attr_cached_attr_name")); 1748 Object name2(&scope, Runtime::internStrFromCStr( 1749 thread_, "load_method_cached_attr_name")); 1750 Object name3(&scope, Runtime::internStrFromCStr( 1751 thread_, "load_attr_cached_attr_name2")); 1752 Object name4(&scope, Runtime::internStrFromCStr( 1753 thread_, "store_attr_cached_attr_name")); 1754 Tuple names(&scope, runtime_->newTupleWith4(name1, name2, name3, name4)); 1755 1756 Object name(&scope, runtime_->newStrFromCStr("name")); 1757 Function dependent(&scope, newEmptyFunction()); 1758 Object value(&scope, NoneType::object()); 1759 MutableTuple caches( 1760 &scope, runtime_->newMutableTuple(num_caches * kIcPointersPerEntry)); 1761 caches.fill(NoneType::object()); 1762 // Caches for LOAD_ATTR_ANAMORPHIC at PC 2. 1763 value = SmallInt::fromWord(10); 1764 icUpdateAttr(thread_, caches, 0, LayoutId::kBool, value, name, dependent); 1765 value = SmallInt::fromWord(20); 1766 icUpdateAttr(thread_, caches, 0, LayoutId::kSmallInt, value, name, dependent); 1767 1768 // Caches for LOAD_METHOD_ANAMORPHIC at PC 6. 1769 value = SmallInt::fromWord(30); 1770 icUpdateAttr(thread_, caches, 1, LayoutId::kSmallInt, value, name, dependent); 1771 1772 // Caches are empty for LOAD_ATTR_ANAMORPHIC at PC 10. 1773 1774 // Caches for STORE_ATTR_ANAMORPHIC at PC 12. 1775 value = SmallInt::fromWord(40); 1776 icUpdateAttr(thread_, caches, 3, LayoutId::kNoneType, value, name, dependent); 1777 1778 // Caches for FOR_ITER_ANAMORPHIC at PC 14. 1779 value = SmallInt::fromWord(50); 1780 icUpdateAttr(thread_, caches, 4, LayoutId::kStr, value, name, dependent); 1781 1782 // Caches for BINARY_SUBSCR_ANAMORPHIC at PC 16. 1783 value = SmallInt::fromWord(60); 1784 icUpdateAttr(thread_, caches, 5, LayoutId::kTuple, value, name, dependent); 1785 1786 Function function(&scope, newEmptyFunction()); 1787 function.setRewrittenBytecode(*bytecode); 1788 function.setCaches(*caches); 1789 Code::cast(function.code()).setNames(*names); 1790 1791 IcIterator it(&scope, runtime_, *function); 1792 ASSERT_TRUE(it.hasNext()); 1793 ASSERT_TRUE(it.isAttrCache()); 1794 EXPECT_FALSE(it.isBinaryOpCache()); 1795 Object load_attr_cached_attr_name( 1796 &scope, 1797 Runtime::internStrFromCStr(thread_, "load_attr_cached_attr_name")); 1798 EXPECT_TRUE(it.isAttrNameEqualTo(load_attr_cached_attr_name)); 1799 EXPECT_EQ(it.layoutId(), LayoutId::kBool); 1800 EXPECT_TRUE(it.isInstanceAttr()); 1801 1802 it.next(); 1803 ASSERT_TRUE(it.hasNext()); 1804 ASSERT_TRUE(it.isAttrCache()); 1805 EXPECT_FALSE(it.isBinaryOpCache()); 1806 EXPECT_TRUE(it.isAttrNameEqualTo(load_attr_cached_attr_name)); 1807 EXPECT_EQ(it.layoutId(), LayoutId::kSmallInt); 1808 EXPECT_TRUE(it.isInstanceAttr()); 1809 1810 it.next(); 1811 ASSERT_TRUE(it.hasNext()); 1812 ASSERT_TRUE(it.isAttrCache()); 1813 EXPECT_FALSE(it.isBinaryOpCache()); 1814 Object load_method_cached_attr_name( 1815 &scope, 1816 Runtime::internStrFromCStr(thread_, "load_method_cached_attr_name")); 1817 EXPECT_TRUE(it.isAttrNameEqualTo(load_method_cached_attr_name)); 1818 EXPECT_EQ(it.layoutId(), SmallInt::fromWord(100).layoutId()); 1819 EXPECT_TRUE(it.isInstanceAttr()); 1820 1821 it.next(); 1822 ASSERT_TRUE(it.hasNext()); 1823 ASSERT_TRUE(it.isAttrCache()); 1824 EXPECT_FALSE(it.isBinaryOpCache()); 1825 Object store_attr_cached_attr_name( 1826 &scope, 1827 Runtime::internStrFromCStr(thread_, "store_attr_cached_attr_name")); 1828 EXPECT_TRUE(it.isAttrNameEqualTo(store_attr_cached_attr_name)); 1829 EXPECT_EQ(it.layoutId(), NoneType::object().layoutId()); 1830 EXPECT_TRUE(it.isInstanceAttr()); 1831 1832 ASSERT_EQ( 1833 caches.at(3 * kIcPointersPerEntry + kIcEntryKeyOffset), 1834 SmallInt::fromWord(static_cast<word>(NoneType::object().layoutId()))); 1835 ASSERT_FALSE( 1836 caches.at(3 * kIcPointersPerEntry + kIcEntryValueOffset).isNoneType()); 1837 1838 it.evict(); 1839 1840 EXPECT_TRUE( 1841 caches.at(3 * kIcPointersPerEntry + kIcEntryKeyOffset).isNoneType()); 1842 EXPECT_TRUE( 1843 caches.at(3 * kIcPointersPerEntry + kIcEntryValueOffset).isNoneType()); 1844 1845 it.next(); 1846 ASSERT_TRUE(it.hasNext()); 1847 ASSERT_TRUE(it.isAttrCache()); 1848 EXPECT_FALSE(it.isBinaryOpCache()); 1849 Object for_iter_cached_attr_name( 1850 &scope, Runtime::internStrFromCStr(thread_, "__next__")); 1851 EXPECT_TRUE(it.isAttrNameEqualTo(for_iter_cached_attr_name)); 1852 EXPECT_EQ(it.layoutId(), LayoutId::kStr); 1853 EXPECT_TRUE(it.isInstanceAttr()); 1854 1855 it.next(); 1856 ASSERT_TRUE(it.hasNext()); 1857 ASSERT_TRUE(it.isAttrCache()); 1858 EXPECT_FALSE(it.isBinaryOpCache()); 1859 Object binary_subscr_cached_attr_name( 1860 &scope, Runtime::internStrFromCStr(thread_, "__getitem__")); 1861 EXPECT_TRUE(it.isAttrNameEqualTo(binary_subscr_cached_attr_name)); 1862 EXPECT_EQ(it.layoutId(), LayoutId::kTuple); 1863 EXPECT_TRUE(it.isInstanceAttr()); 1864 1865 it.next(); 1866 EXPECT_FALSE(it.hasNext()); 1867} 1868 1869TEST_F(IcTest, IcIteratorIteratesOverBinaryOpCaches) { 1870 HandleScope scope(thread_); 1871 MutableBytes bytecode( 1872 &scope, runtime_->newMutableBytesUninitialized(4 * kCodeUnitSize)); 1873 rewrittenBytecodeOpAtPut(bytecode, 0, LOAD_GLOBAL); 1874 rewrittenBytecodeArgAtPut(bytecode, 0, 100); 1875 rewrittenBytecodeCacheAtPut(bytecode, 0, 0); 1876 rewrittenBytecodeOpAtPut(bytecode, 1, COMPARE_OP_ANAMORPHIC); 1877 rewrittenBytecodeArgAtPut(bytecode, 1, CompareOp::GE); 1878 rewrittenBytecodeCacheAtPut(bytecode, 1, 0); 1879 rewrittenBytecodeOpAtPut(bytecode, 2, BINARY_OP_ANAMORPHIC); 1880 rewrittenBytecodeArgAtPut(bytecode, 2, 1881 static_cast<word>(Interpreter::BinaryOp::ADD)); 1882 rewrittenBytecodeCacheAtPut(bytecode, 2, 1); 1883 rewrittenBytecodeOpAtPut(bytecode, 3, LOAD_GLOBAL); 1884 rewrittenBytecodeArgAtPut(bytecode, 3, 100); 1885 rewrittenBytecodeCacheAtPut(bytecode, 3, 0); 1886 1887 word num_caches = 2; 1888 MutableTuple caches( 1889 &scope, runtime_->newMutableTuple(num_caches * kIcPointersPerEntry)); 1890 1891 // Caches for COMPARE_OP_ANAMORPHIC at 2. 1892 word compare_op_cached_index = 1893 0 * kIcPointersPerEntry + 0 * kIcPointersPerEntry; 1894 word compare_op_key_high_bits = 1895 static_cast<word>(SmallInt::fromWord(0).layoutId()) 1896 << Header::kLayoutIdBits | 1897 static_cast<word>(SmallStr::fromCStr("test").layoutId()); 1898 caches.atPut(compare_op_cached_index + kIcEntryKeyOffset, 1899 SmallInt::fromWord(compare_op_key_high_bits << kBitsPerByte | 1900 static_cast<word>(kBinaryOpReflected))); 1901 caches.atPut(compare_op_cached_index + kIcEntryValueOffset, 1902 SmallInt::fromWord(50)); 1903 1904 // Caches for BINARY_OP_ANAMORPHIC at 4. 1905 word binary_op_cached_index = 1906 1 * kIcPointersPerEntry + 0 * kIcPointersPerEntry; 1907 word binary_op_key_high_bits = 1908 static_cast<word>(SmallStr::fromCStr("").layoutId()) 1909 << Header::kLayoutIdBits | 1910 static_cast<word>(SmallInt::fromWord(0).layoutId()); 1911 caches.atPut(binary_op_cached_index + kIcEntryKeyOffset, 1912 SmallInt::fromWord(binary_op_key_high_bits << kBitsPerByte | 1913 static_cast<word>(kBinaryOpReflected))); 1914 caches.atPut(binary_op_cached_index + kIcEntryValueOffset, 1915 SmallInt::fromWord(60)); 1916 1917 Function function(&scope, newEmptyFunction()); 1918 function.setRewrittenBytecode(*bytecode); 1919 function.setCaches(*caches); 1920 1921 IcIterator it(&scope, runtime_, *function); 1922 ASSERT_TRUE(it.hasNext()); 1923 ASSERT_TRUE(it.isBinaryOpCache()); 1924 EXPECT_FALSE(it.isAttrCache()); 1925 EXPECT_EQ(it.leftLayoutId(), SmallInt::fromWord(-1).layoutId()); 1926 EXPECT_EQ(it.rightLayoutId(), SmallStr::fromCStr("").layoutId()); 1927 { 1928 Object left_operator_name(&scope, 1929 Runtime::internStrFromCStr(thread_, "__ge__")); 1930 EXPECT_EQ(left_operator_name, it.leftMethodName()); 1931 Object right_operator_name(&scope, 1932 Runtime::internStrFromCStr(thread_, "__le__")); 1933 EXPECT_EQ(right_operator_name, it.rightMethodName()); 1934 } 1935 1936 it.next(); 1937 ASSERT_TRUE(it.hasNext()); 1938 ASSERT_TRUE(it.isBinaryOpCache()); 1939 EXPECT_FALSE(it.isAttrCache()); 1940 EXPECT_EQ(it.leftLayoutId(), SmallStr::fromCStr("").layoutId()); 1941 EXPECT_EQ(it.rightLayoutId(), SmallInt::fromWord(-1).layoutId()); 1942 { 1943 Object left_operator_name(&scope, 1944 Runtime::internStrFromCStr(thread_, "__add__")); 1945 EXPECT_EQ(left_operator_name, it.leftMethodName()); 1946 Object right_operator_name(&scope, 1947 Runtime::internStrFromCStr(thread_, "__radd__")); 1948 EXPECT_EQ(right_operator_name, it.rightMethodName()); 1949 } 1950 1951 it.next(); 1952 EXPECT_FALSE(it.hasNext()); 1953} 1954 1955TEST_F(IcTest, IcIteratorIteratesOverInplaceOpCaches) { 1956 HandleScope scope(thread_); 1957 MutableBytes bytecode( 1958 &scope, runtime_->newMutableBytesUninitialized(4 * kCodeUnitSize)); 1959 rewrittenBytecodeOpAtPut(bytecode, 0, LOAD_GLOBAL); 1960 rewrittenBytecodeArgAtPut(bytecode, 0, 100); 1961 rewrittenBytecodeCacheAtPut(bytecode, 0, 0); 1962 rewrittenBytecodeOpAtPut(bytecode, 1, INPLACE_OP_ANAMORPHIC); 1963 rewrittenBytecodeArgAtPut(bytecode, 1, 1964 static_cast<word>(Interpreter::BinaryOp::MUL)); 1965 rewrittenBytecodeCacheAtPut(bytecode, 1, 0); 1966 rewrittenBytecodeOpAtPut(bytecode, 2, LOAD_GLOBAL); 1967 rewrittenBytecodeArgAtPut(bytecode, 2, 100); 1968 rewrittenBytecodeCacheAtPut(bytecode, 2, 0); 1969 1970 word num_caches = 1; 1971 MutableTuple caches( 1972 &scope, runtime_->newMutableTuple(num_caches * kIcPointersPerEntry)); 1973 1974 // Caches for BINARY_OP_ANAMORPHIC at 2. 1975 word inplace_op_cached_index = 1976 0 * kIcPointersPerEntry + 0 * kIcPointersPerEntry; 1977 word inplace_op_key_high_bits = 1978 static_cast<word>(SmallStr::fromCStr("a").layoutId()) 1979 << Header::kLayoutIdBits | 1980 static_cast<word>(SmallInt::fromWord(3).layoutId()); 1981 caches.atPut(inplace_op_cached_index + kIcEntryKeyOffset, 1982 SmallInt::fromWord(inplace_op_key_high_bits << kBitsPerByte | 1983 static_cast<word>(kBinaryOpReflected))); 1984 caches.atPut(inplace_op_cached_index + kIcEntryValueOffset, 1985 SmallInt::fromWord(70)); 1986 1987 Function function(&scope, newEmptyFunction()); 1988 function.setRewrittenBytecode(*bytecode); 1989 function.setCaches(*caches); 1990 1991 IcIterator it(&scope, runtime_, *function); 1992 ASSERT_TRUE(it.hasNext()); 1993 ASSERT_TRUE(it.isInplaceOpCache()); 1994 EXPECT_FALSE(it.isBinaryOpCache()); 1995 EXPECT_FALSE(it.isAttrCache()); 1996 EXPECT_EQ(it.leftLayoutId(), SmallStr::fromCStr("").layoutId()); 1997 EXPECT_EQ(it.rightLayoutId(), SmallInt::fromWord(-1).layoutId()); 1998 { 1999 Object inplace_operator_name( 2000 &scope, Runtime::internStrFromCStr(thread_, "__imul__")); 2001 EXPECT_EQ(inplace_operator_name, it.inplaceMethodName()); 2002 Object left_operator_name(&scope, 2003 Runtime::internStrFromCStr(thread_, "__mul__")); 2004 EXPECT_EQ(left_operator_name, it.leftMethodName()); 2005 Object right_operator_name(&scope, 2006 Runtime::internStrFromCStr(thread_, "__rmul__")); 2007 EXPECT_EQ(right_operator_name, it.rightMethodName()); 2008 } 2009 2010 it.next(); 2011 EXPECT_FALSE(it.hasNext()); 2012} 2013 2014TEST_F(IcTest, IcRemoveDeadWeakLinksRemoveRemovesDeadHead) { 2015 HandleScope scope(thread_); 2016 ValueCell value_cell(&scope, runtime_->newValueCell()); 2017 Object dependent1(&scope, newTupleWithNone(1)); 2018 Object dependent2(&scope, newTupleWithNone(2)); 2019 Object dependent3(&scope, newTupleWithNone(3)); 2020 icInsertDependentToValueCellDependencyLink(thread_, dependent1, value_cell); 2021 icInsertDependentToValueCellDependencyLink(thread_, dependent2, value_cell); 2022 icInsertDependentToValueCellDependencyLink(thread_, dependent3, value_cell); 2023 // The dependenty link looks like dependent3 -> dependent2 -> dependent1. 2024 // Kill dependent3. 2025 WeakLink head(&scope, value_cell.dependencyLink()); 2026 head.setReferent(NoneType::object()); 2027 2028 icRemoveDeadWeakLinks(*value_cell); 2029 2030 ASSERT_TRUE(value_cell.dependencyLink().isWeakLink()); 2031 WeakLink new_head(&scope, value_cell.dependencyLink()); 2032 EXPECT_EQ(new_head.referent(), *dependent2); 2033 EXPECT_TRUE(new_head.prev().isNoneType()); 2034 WeakLink new_next(&scope, new_head.next()); 2035 EXPECT_EQ(new_next.referent(), *dependent1); 2036 EXPECT_EQ(new_next.prev(), *new_head); 2037 EXPECT_TRUE(new_next.next().isNoneType()); 2038} 2039 2040TEST_F(IcTest, IcRemoveDeadWeakLinksRemoveRemovesDeadMiddleNode) { 2041 HandleScope scope(thread_); 2042 ValueCell value_cell(&scope, runtime_->newValueCell()); 2043 Object dependent1(&scope, newTupleWithNone(1)); 2044 Object dependent2(&scope, newTupleWithNone(2)); 2045 Object dependent3(&scope, newTupleWithNone(3)); 2046 icInsertDependentToValueCellDependencyLink(thread_, dependent1, value_cell); 2047 icInsertDependentToValueCellDependencyLink(thread_, dependent2, value_cell); 2048 icInsertDependentToValueCellDependencyLink(thread_, dependent3, value_cell); 2049 // The dependenty link looks like dependent3 -> dependent2 -> dependent1. 2050 WeakLink head(&scope, value_cell.dependencyLink()); 2051 // Kill dependent2. 2052 WeakLink next(&scope, head.next()); 2053 next.setReferent(NoneType::object()); 2054 2055 icRemoveDeadWeakLinks(*value_cell); 2056 2057 ASSERT_TRUE(value_cell.dependencyLink().isWeakLink()); 2058 WeakLink new_head(&scope, value_cell.dependencyLink()); 2059 EXPECT_EQ(new_head.referent(), *dependent3); 2060 EXPECT_TRUE(new_head.prev().isNoneType()); 2061 WeakLink new_next(&scope, new_head.next()); 2062 EXPECT_EQ(new_next.referent(), *dependent1); 2063 EXPECT_EQ(new_next.prev(), *new_head); 2064 EXPECT_TRUE(new_next.next().isNoneType()); 2065} 2066 2067TEST_F(IcTest, IcRemoveDeadWeakLinksRemoveRemovesDeadTailNode) { 2068 HandleScope scope(thread_); 2069 ValueCell value_cell(&scope, runtime_->newValueCell()); 2070 Object dependent1(&scope, newTupleWithNone(1)); 2071 Object dependent2(&scope, newTupleWithNone(2)); 2072 Object dependent3(&scope, newTupleWithNone(3)); 2073 icInsertDependentToValueCellDependencyLink(thread_, dependent1, value_cell); 2074 icInsertDependentToValueCellDependencyLink(thread_, dependent2, value_cell); 2075 icInsertDependentToValueCellDependencyLink(thread_, dependent3, value_cell); 2076 // The dependenty link looks like dependent3 -> dependent2 -> dependent1. 2077 WeakLink head(&scope, value_cell.dependencyLink()); 2078 // Kill dependent1. 2079 WeakLink next_next(&scope, WeakLink::cast(head.next()).next()); 2080 next_next.setReferent(NoneType::object()); 2081 2082 icRemoveDeadWeakLinks(*value_cell); 2083 2084 ASSERT_TRUE(value_cell.dependencyLink().isWeakLink()); 2085 WeakLink new_head(&scope, value_cell.dependencyLink()); 2086 EXPECT_EQ(new_head.referent(), *dependent3); 2087 EXPECT_TRUE(new_head.prev().isNoneType()); 2088 WeakLink new_next(&scope, new_head.next()); 2089 EXPECT_EQ(new_next.referent(), *dependent2); 2090 EXPECT_EQ(new_next.prev(), *new_head); 2091 EXPECT_TRUE(new_next.next().isNoneType()); 2092} 2093 2094TEST_F(IcTest, 2095 EncodeBinaryOpKeyEntryReturnsKeyAccessedByLookupBinOpMonomorphic) { 2096 HandleScope scope(thread_); 2097 SmallInt entry_key(&scope, encodeBinaryOpKey(LayoutId::kStr, LayoutId::kInt, 2098 kBinaryOpReflected)); 2099 Object entry_value(&scope, runtime_->newStrFromCStr("value")); 2100 MutableTuple caches(&scope, runtime_->newMutableTuple(kIcPointersPerEntry)); 2101 caches.fill(NoneType::object()); 2102 caches.atPut(kIcEntryKeyOffset, *entry_key); 2103 caches.atPut(kIcEntryValueOffset, *entry_value); 2104 2105 BinaryOpFlags flags_out; 2106 Object result(&scope, icLookupBinOpMonomorphic(*caches, 0, LayoutId::kStr, 2107 LayoutId::kInt, &flags_out)); 2108 EXPECT_EQ(result, entry_value); 2109 EXPECT_TRUE(icLookupBinOpMonomorphic(*caches, 0, LayoutId::kInt, 2110 LayoutId::kStr, &flags_out) 2111 .isErrorNotFound()); 2112} 2113 2114TEST_F( 2115 IcTest, 2116 IcInvalidateAttrWithDunderFunctionsUpdatesCorrespondingAttributeTypeFlags) { 2117 HandleScope scope(thread_); 2118 ASSERT_FALSE(runFromCStr(runtime_, R"( 2119class A: 2120 pass 2121 2122class B(A): 2123 pass 2124 2125class C(B): 2126 pass 2127 2128class X: 2129 pass 2130 2131class D(X, C): 2132 pass 2133 2134class E(D): 2135 pass 2136 2137def custom_getattribute(self, name): 2138 return "bogus" 2139 2140object_getattribute = object.__getattribute__ 2141)") 2142 .isError()); 2143 2144 Type a(&scope, mainModuleAt(runtime_, "A")); 2145 Type b(&scope, mainModuleAt(runtime_, "B")); 2146 Type c(&scope, mainModuleAt(runtime_, "C")); 2147 Type d(&scope, mainModuleAt(runtime_, "D")); 2148 Type e(&scope, mainModuleAt(runtime_, "E")); 2149 Type x(&scope, mainModuleAt(runtime_, "X")); 2150 2151 ASSERT_TRUE(a.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2152 ASSERT_TRUE(b.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2153 ASSERT_TRUE(c.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2154 ASSERT_TRUE(d.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2155 ASSERT_TRUE(e.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2156 ASSERT_TRUE(x.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2157 2158 Object custom_getattribute(&scope, 2159 mainModuleAt(runtime_, "custom_getattribute")); 2160 typeAtPutById(thread_, c, ID(__getattribute__), custom_getattribute); 2161 2162 EXPECT_TRUE(a.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2163 EXPECT_TRUE(b.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2164 EXPECT_FALSE(c.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2165 EXPECT_FALSE(d.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2166 EXPECT_FALSE(e.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2167 EXPECT_TRUE(x.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2168 2169 Object object_getattribute(&scope, 2170 mainModuleAt(runtime_, "object_getattribute")); 2171 typeAtPutById(thread_, c, ID(__getattribute__), object_getattribute); 2172 2173 EXPECT_TRUE(a.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2174 EXPECT_TRUE(b.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2175 EXPECT_TRUE(c.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2176 EXPECT_TRUE(d.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2177 EXPECT_TRUE(e.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2178 EXPECT_TRUE(x.hasFlag(Type::Flag::kHasObjectDunderGetattribute)); 2179} 2180 2181TEST_F(IcTest, IcInvalidateTypeHierarchy) { 2182 ASSERT_FALSE(runFromCStr(runtime_, R"( 2183class A: 2184 def __init__(self): 2185 self.foo = 400 2186 2187class B(A): 2188 pass 2189 2190def cache_attribute(c): 2191 return c.foo 2192 2193def invalidate(): 2194 A.foo = property(lambda self: 123) 2195 2196a = A() 2197b = B() 2198a_init = A.__init__ 2199)") 2200 .isError()); 2201 HandleScope scope(thread_); 2202 Function a_init(&scope, mainModuleAt(runtime_, "a_init")); 2203 Function cache_attribute(&scope, mainModuleAt(runtime_, "cache_attribute")); 2204 Type type_a(&scope, mainModuleAt(runtime_, "A")); 2205 Type type_b(&scope, mainModuleAt(runtime_, "B")); 2206 Object obj_a(&scope, mainModuleAt(runtime_, "a")); 2207 Object obj_b(&scope, mainModuleAt(runtime_, "b")); 2208 Object foo_name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 2209 ValueCell foo_in_a(&scope, typeValueCellAt(*type_a, *foo_name)); 2210 ValueCell foo_in_b(&scope, typeValueCellAt(*type_b, *foo_name)); 2211 2212 // We've called __init__ already so it should be a dependent. 2213 EXPECT_TRUE(icDependentIncluded(*a_init, foo_in_a.dependencyLink())); 2214 EXPECT_TRUE(icDependentIncluded(*a_init, foo_in_b.dependencyLink())); 2215 EXPECT_FALSE(icDependentIncluded(*cache_attribute, foo_in_a.dependencyLink())); 2216 EXPECT_FALSE(icDependentIncluded(*cache_attribute, foo_in_b.dependencyLink())); 2217 2218 // Cache an attribute elsewhere. 2219 ASSERT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, cache_attribute, obj_a), 400)); 2220 ASSERT_TRUE(isIntEqualsWord(Interpreter::call1(thread_, cache_attribute, obj_b), 400)); 2221 2222 // That function should be a dependent too. 2223 EXPECT_TRUE(icDependentIncluded(*a_init, foo_in_a.dependencyLink())); 2224 EXPECT_TRUE(icDependentIncluded(*a_init, foo_in_b.dependencyLink())); 2225 EXPECT_TRUE(icDependentIncluded(*cache_attribute, foo_in_a.dependencyLink())); 2226 EXPECT_TRUE(icDependentIncluded(*cache_attribute, foo_in_b.dependencyLink())); 2227 2228 // Invalidate the attribute. 2229 Function invalidate(&scope, mainModuleAt(runtime_, "invalidate")); 2230 ASSERT_TRUE(Interpreter::call0(thread_, invalidate).isNoneType()); 2231 2232 EXPECT_FALSE(icDependentIncluded(*a_init, foo_in_a.dependencyLink())); 2233 EXPECT_FALSE(icDependentIncluded(*a_init, foo_in_b.dependencyLink())); 2234 // TODO(#269): Change to EXPECT_FALSE. 2235 EXPECT_TRUE(icDependentIncluded(*cache_attribute, foo_in_a.dependencyLink())); 2236 EXPECT_TRUE(icDependentIncluded(*cache_attribute, foo_in_b.dependencyLink())); 2237} 2238 2239} // namespace testing 2240} // namespace py