this repo has no description
at trunk 831 lines 27 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "bytecode.h" 3 4#include "gtest/gtest.h" 5 6#include "ic.h" 7#include "test-utils.h" 8 9namespace py { 10namespace testing { 11 12using BytecodeTest = RuntimeFixture; 13 14TEST_F(BytecodeTest, NextBytecodeOpReturnsNextBytecodeOpPair) { 15 HandleScope scope(thread_); 16 const byte bytecode_raw[] = { 17 NOP, 99, 0, 0, EXTENDED_ARG, 0xca, 0, 0, 18 LOAD_ATTR, 0xfe, 0, 0, LOAD_GLOBAL, 10, 0, 0, 19 EXTENDED_ARG, 1, 0, 0, EXTENDED_ARG, 2, 0, 0, 20 EXTENDED_ARG, 3, 0, 0, LOAD_ATTR, 4, 0, 0}; 21 Bytes original_bytecode(&scope, runtime_->newBytesWithAll(bytecode_raw)); 22 MutableBytes bytecode( 23 &scope, runtime_->mutableBytesFromBytes(thread_, original_bytecode)); 24 word index = 0; 25 BytecodeOp bc = nextBytecodeOp(bytecode, &index); 26 EXPECT_EQ(bc.bc, NOP); 27 EXPECT_EQ(bc.arg, 99); 28 29 bc = nextBytecodeOp(bytecode, &index); 30 EXPECT_EQ(bc.bc, LOAD_ATTR); 31 EXPECT_EQ(bc.arg, 0xcafe); 32 33 bc = nextBytecodeOp(bytecode, &index); 34 EXPECT_EQ(bc.bc, LOAD_GLOBAL); 35 EXPECT_EQ(bc.arg, 10); 36 37 bc = nextBytecodeOp(bytecode, &index); 38 EXPECT_EQ(bc.bc, LOAD_ATTR); 39 EXPECT_EQ(bc.arg, 0x01020304); 40} 41 42TEST_F(BytecodeTest, OpargFromObject) { 43 EXPECT_EQ(NoneType::object(), 44 objectFromOparg(opargFromObject(NoneType::object()))); 45 EXPECT_EQ(SmallInt::fromWord(-1), 46 objectFromOparg(opargFromObject(SmallInt::fromWord(-1)))); 47 EXPECT_EQ(SmallInt::fromWord(-64), 48 objectFromOparg(opargFromObject(SmallInt::fromWord(-64)))); 49 EXPECT_EQ(SmallInt::fromWord(0), 50 objectFromOparg(opargFromObject(SmallInt::fromWord(0)))); 51 EXPECT_EQ(SmallInt::fromWord(63), 52 objectFromOparg(opargFromObject(SmallInt::fromWord(63)))); 53 EXPECT_EQ(Str::empty(), objectFromOparg(opargFromObject(Str::empty()))); 54 // Not immediate since it doesn't fit in byte. 55 EXPECT_NE(SmallInt::fromWord(64), 56 objectFromOparg(opargFromObject(SmallInt::fromWord(64)))); 57} 58 59TEST_F(BytecodeTest, RewriteBytecodeWithMoreThanCacheLimitCapsRewriting) { 60 HandleScope scope(thread_); 61 Object name(&scope, Str::empty()); 62 static const int cache_limit = 65536; 63 byte bytecode[(cache_limit + 2) * kCompilerCodeUnitSize]; 64 std::memset(bytecode, 0, sizeof bytecode); 65 for (word i = 0; i < cache_limit; i++) { 66 bytecode[i * kCompilerCodeUnitSize] = LOAD_ATTR; 67 bytecode[(i * kCompilerCodeUnitSize) + 1] = i * 3; 68 } 69 // LOAD_GLOBAL 1039 == 4 * 256 + 15. 70 bytecode[cache_limit * kCompilerCodeUnitSize] = EXTENDED_ARG; 71 bytecode[cache_limit * kCompilerCodeUnitSize + 1] = 4; 72 bytecode[(cache_limit + 1) * kCompilerCodeUnitSize] = LOAD_GLOBAL; 73 bytecode[(cache_limit + 1) * kCompilerCodeUnitSize + 1] = 15; 74 75 word global_names_length = 600; 76 Tuple consts(&scope, runtime_->emptyTuple()); 77 MutableTuple names(&scope, runtime_->newMutableTuple(global_names_length)); 78 for (word i = 0; i < global_names_length; i++) { 79 names.atPut(i, runtime_->newStrFromFmt("g%w", i)); 80 } 81 Tuple names_tuple(&scope, names.becomeImmutable()); 82 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names_tuple)); 83 84 Module module(&scope, findMainModule(runtime_)); 85 Function function(&scope, 86 runtime_->newFunctionWithCode(thread_, name, code, module)); 87 88 // newFunctionWithCode() calls rewriteBytecode(). 89 Object rewritten_bytecode_obj(&scope, function.rewrittenBytecode()); 90 ASSERT_TRUE(rewritten_bytecode_obj.isMutableBytes()); 91 MutableBytes rewritten_bytecode(&scope, *rewritten_bytecode_obj); 92 word expected_cache = global_names_length / kIcPointersPerEntry; 93 word i = 0; 94 for (; i < cache_limit - global_names_length / kIcPointersPerEntry;) { 95 BytecodeOp op = nextBytecodeOp(rewritten_bytecode, &i); 96 EXPECT_EQ(op.bc, LOAD_ATTR_ANAMORPHIC) 97 << "unexpected " << kBytecodeNames[op.bc] << " at idx " << i; 98 EXPECT_EQ(op.arg, ((i - 1) * 3) % 256); // What fits in a byte 99 EXPECT_EQ(op.cache, expected_cache); 100 expected_cache++; 101 } 102 for (; i < cache_limit;) { 103 BytecodeOp op = nextBytecodeOp(rewritten_bytecode, &i); 104 EXPECT_EQ(op.bc, LOAD_ATTR) 105 << "unexpected " << kBytecodeNames[op.bc] << " at idx " << i; 106 } 107 BytecodeOp op = nextBytecodeOp(rewritten_bytecode, &i); 108 EXPECT_EQ(op.bc, LOAD_GLOBAL); 109 EXPECT_EQ(op.arg, 1039); 110 EXPECT_EQ(op.cache, 0); 111 EXPECT_EQ(Tuple::cast(function.caches()).length(), 112 cache_limit * kIcPointersPerEntry); 113 // The cache for LOAD_GLOBAL was populated. 114 EXPECT_GT(Tuple::cast(function.caches()).length(), 527); 115} 116 117TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadAttrOperations) { 118 HandleScope scope(thread_); 119 Object name(&scope, Str::empty()); 120 const byte bytecode[] = { 121 NOP, 99, EXTENDED_ARG, 0xca, LOAD_ATTR, 0xfe, 122 NOP, 106, EXTENDED_ARG, 1, EXTENDED_ARG, 2, 123 EXTENDED_ARG, 3, LOAD_ATTR, 4, LOAD_ATTR, 77, 124 }; 125 Code code(&scope, newCodeWithBytes(bytecode)); 126 Module module(&scope, findMainModule(runtime_)); 127 Function function(&scope, 128 runtime_->newFunctionWithCode(thread_, name, code, module)); 129 // newFunctionWithCode() calls rewriteBytecode(). 130 131 byte expected[] = { 132 NOP, 133 99, 134 0, 135 0, 136 EXTENDED_ARG, 137 0xca, 138 0, 139 0, 140 LOAD_ATTR_ANAMORPHIC, 141 0xfe, 142 0, 143 0, 144 NOP, 145 106, 146 0, 147 0, 148 EXTENDED_ARG, 149 1, 150 0, 151 0, 152 EXTENDED_ARG, 153 2, 154 0, 155 0, 156 EXTENDED_ARG, 157 3, 158 0, 159 0, 160 LOAD_ATTR_ANAMORPHIC, 161 4, 162 1, 163 0, 164 LOAD_ATTR_ANAMORPHIC, 165 77, 166 2, 167 0, 168 }; 169 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 170 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 171 172 ASSERT_TRUE(function.caches().isTuple()); 173 Tuple caches(&scope, function.caches()); 174 EXPECT_EQ(caches.length(), 3 * kIcPointersPerEntry); 175 for (word i = 0, length = caches.length(); i < length; i++) { 176 EXPECT_TRUE(caches.at(i).isNoneType()) << "index " << i; 177 } 178} 179 180TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadConstOperations) { 181 HandleScope scope(thread_); 182 Object name(&scope, Str::empty()); 183 const byte bytecode[] = {LOAD_CONST, 0, LOAD_CONST, 1, LOAD_CONST, 2, 184 LOAD_CONST, 3, LOAD_CONST, 4}; 185 186 // Immediate objects. 187 Object obj0(&scope, NoneType::object()); 188 Object obj1(&scope, SmallInt::fromWord(0)); 189 Object obj2(&scope, Str::empty()); 190 // Not immediate since it doesn't fit in byte. 191 Object obj3(&scope, SmallInt::fromWord(64)); 192 // Not immediate since it's a heap object. 193 Object obj4(&scope, runtime_->newList()); 194 Tuple consts(&scope, 195 runtime_->newTupleWithN(5, &obj0, &obj1, &obj2, &obj3, &obj4)); 196 Code code(&scope, newCodeWithBytesConsts(bytecode, consts)); 197 198 Module module(&scope, findMainModule(runtime_)); 199 Function function(&scope, 200 runtime_->newFunctionWithCode(thread_, name, code, module)); 201 202 byte expected[] = { 203 LOAD_IMMEDIATE, 204 static_cast<byte>(opargFromObject(NoneType::object())), 205 0, 206 0, 207 LOAD_IMMEDIATE, 208 static_cast<byte>(opargFromObject(SmallInt::fromWord(0))), 209 0, 210 0, 211 LOAD_IMMEDIATE, 212 static_cast<byte>(opargFromObject(Str::empty())), 213 0, 214 0, 215 LOAD_CONST, 216 3, 217 0, 218 0, 219 LOAD_CONST, 220 4, 221 0, 222 0, 223 }; 224 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode()); 225 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 226} 227 228TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadConstToLoadBool) { 229 HandleScope scope(thread_); 230 Object name(&scope, Str::empty()); 231 const byte bytecode[] = {LOAD_CONST, 0, LOAD_CONST, 1}; 232 233 // Immediate objects. 234 Object obj0(&scope, Bool::trueObj()); 235 Object obj1(&scope, Bool::falseObj()); 236 Tuple consts(&scope, runtime_->newTupleWith2(obj0, obj1)); 237 Code code(&scope, newCodeWithBytesConsts(bytecode, consts)); 238 239 Module module(&scope, findMainModule(runtime_)); 240 Function function(&scope, 241 runtime_->newFunctionWithCode(thread_, name, code, module)); 242 243 byte expected[] = { 244 LOAD_BOOL, 0x80, 0, 0, LOAD_BOOL, 0, 0, 0, 245 }; 246 MutableBytes rewritten_bytecode(&scope, function.rewrittenBytecode()); 247 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 248} 249 250TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadMethodOperations) { 251 HandleScope scope(thread_); 252 Object name(&scope, Str::empty()); 253 const byte bytecode[] = { 254 NOP, 99, EXTENDED_ARG, 0xca, LOAD_METHOD, 0xfe, 255 NOP, 160, EXTENDED_ARG, 1, EXTENDED_ARG, 2, 256 EXTENDED_ARG, 3, LOAD_METHOD, 4, LOAD_METHOD, 77, 257 }; 258 Code code(&scope, newCodeWithBytes(bytecode)); 259 260 Module module(&scope, findMainModule(runtime_)); 261 Function function(&scope, 262 runtime_->newFunctionWithCode(thread_, name, code, module)); 263 // newFunctionWithCode() calls rewriteBytecode(). 264 265 byte expected[] = { 266 NOP, 267 99, 268 0, 269 0, 270 EXTENDED_ARG, 271 0xca, 272 0, 273 0, 274 LOAD_METHOD_ANAMORPHIC, 275 0xfe, 276 0, 277 0, 278 NOP, 279 160, 280 0, 281 0, 282 EXTENDED_ARG, 283 1, 284 0, 285 0, 286 EXTENDED_ARG, 287 2, 288 0, 289 0, 290 EXTENDED_ARG, 291 3, 292 0, 293 0, 294 LOAD_METHOD_ANAMORPHIC, 295 4, 296 1, 297 0, 298 LOAD_METHOD_ANAMORPHIC, 299 77, 300 2, 301 0, 302 }; 303 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 304 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 305 306 ASSERT_TRUE(function.caches().isTuple()); 307 Tuple caches(&scope, function.caches()); 308 EXPECT_EQ(caches.length(), 3 * kIcPointersPerEntry); 309 for (word i = 0, length = caches.length(); i < length; i++) { 310 EXPECT_TRUE(caches.at(i).isNoneType()) << "index " << i; 311 } 312} 313 314TEST_F(BytecodeTest, RewriteBytecodeRewritesStoreAttr) { 315 HandleScope scope(thread_); 316 Object name(&scope, Str::empty()); 317 const byte bytecode[] = {STORE_ATTR, 48}; 318 Code code(&scope, newCodeWithBytes(bytecode)); 319 320 Module module(&scope, findMainModule(runtime_)); 321 Function function(&scope, 322 runtime_->newFunctionWithCode(thread_, name, code, module)); 323 // newFunctionWithCode() calls rewriteBytecode(). 324 325 byte expected[] = { 326 STORE_ATTR_ANAMORPHIC, 327 48, 328 0, 329 0, 330 }; 331 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 332 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 333} 334 335TEST_F(BytecodeTest, RewriteBytecodeRewritesBinaryOpcodes) { 336 HandleScope scope(thread_); 337 Object name(&scope, Str::empty()); 338 const byte bytecode[] = { 339 BINARY_MATRIX_MULTIPLY, 340 0, 341 BINARY_POWER, 342 0, 343 BINARY_MULTIPLY, 344 0, 345 BINARY_MODULO, 346 0, 347 BINARY_ADD, 348 0, 349 BINARY_SUBTRACT, 350 0, 351 BINARY_FLOOR_DIVIDE, 352 0, 353 BINARY_TRUE_DIVIDE, 354 0, 355 BINARY_LSHIFT, 356 0, 357 BINARY_RSHIFT, 358 0, 359 BINARY_AND, 360 0, 361 BINARY_XOR, 362 0, 363 BINARY_OR, 364 0, 365 }; 366 Code code(&scope, newCodeWithBytes(bytecode)); 367 368 Module module(&scope, findMainModule(runtime_)); 369 Function function(&scope, 370 runtime_->newFunctionWithCode(thread_, name, code, module)); 371 // newFunctionWithCode() calls rewriteBytecode(). 372 373 byte expected[] = { 374 BINARY_OP_ANAMORPHIC, 375 static_cast<word>(Interpreter::BinaryOp::MATMUL), 376 0, 377 0, 378 BINARY_OP_ANAMORPHIC, 379 static_cast<word>(Interpreter::BinaryOp::POW), 380 1, 381 0, 382 BINARY_OP_ANAMORPHIC, 383 static_cast<word>(Interpreter::BinaryOp::MUL), 384 2, 385 0, 386 BINARY_OP_ANAMORPHIC, 387 static_cast<word>(Interpreter::BinaryOp::MOD), 388 3, 389 0, 390 BINARY_OP_ANAMORPHIC, 391 static_cast<word>(Interpreter::BinaryOp::ADD), 392 4, 393 0, 394 BINARY_OP_ANAMORPHIC, 395 static_cast<word>(Interpreter::BinaryOp::SUB), 396 5, 397 0, 398 BINARY_OP_ANAMORPHIC, 399 static_cast<word>(Interpreter::BinaryOp::FLOORDIV), 400 6, 401 0, 402 BINARY_OP_ANAMORPHIC, 403 static_cast<word>(Interpreter::BinaryOp::TRUEDIV), 404 7, 405 0, 406 BINARY_OP_ANAMORPHIC, 407 static_cast<word>(Interpreter::BinaryOp::LSHIFT), 408 8, 409 0, 410 BINARY_OP_ANAMORPHIC, 411 static_cast<word>(Interpreter::BinaryOp::RSHIFT), 412 9, 413 0, 414 BINARY_OP_ANAMORPHIC, 415 static_cast<word>(Interpreter::BinaryOp::AND), 416 10, 417 0, 418 BINARY_OP_ANAMORPHIC, 419 static_cast<word>(Interpreter::BinaryOp::XOR), 420 11, 421 0, 422 BINARY_OP_ANAMORPHIC, 423 static_cast<word>(Interpreter::BinaryOp::OR), 424 12, 425 0, 426 }; 427 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 428 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 429} 430 431TEST_F(BytecodeTest, RewriteBytecodeRewritesInplaceOpcodes) { 432 HandleScope scope(thread_); 433 Object name(&scope, Str::empty()); 434 const byte bytecode[] = { 435 INPLACE_MATRIX_MULTIPLY, 436 0, 437 INPLACE_POWER, 438 0, 439 INPLACE_MULTIPLY, 440 0, 441 INPLACE_MODULO, 442 0, 443 INPLACE_ADD, 444 0, 445 INPLACE_SUBTRACT, 446 0, 447 INPLACE_FLOOR_DIVIDE, 448 0, 449 INPLACE_TRUE_DIVIDE, 450 0, 451 INPLACE_LSHIFT, 452 0, 453 INPLACE_RSHIFT, 454 0, 455 INPLACE_AND, 456 0, 457 INPLACE_XOR, 458 0, 459 INPLACE_OR, 460 0, 461 }; 462 Code code(&scope, newCodeWithBytes(bytecode)); 463 464 Module module(&scope, findMainModule(runtime_)); 465 Function function(&scope, 466 runtime_->newFunctionWithCode(thread_, name, code, module)); 467 // newFunctionWithCode() calls rewriteBytecode(). 468 469 byte expected[] = { 470 INPLACE_OP_ANAMORPHIC, 471 static_cast<word>(Interpreter::BinaryOp::MATMUL), 472 0, 473 0, 474 INPLACE_OP_ANAMORPHIC, 475 static_cast<word>(Interpreter::BinaryOp::POW), 476 1, 477 0, 478 INPLACE_OP_ANAMORPHIC, 479 static_cast<word>(Interpreter::BinaryOp::MUL), 480 2, 481 0, 482 INPLACE_OP_ANAMORPHIC, 483 static_cast<word>(Interpreter::BinaryOp::MOD), 484 3, 485 0, 486 INPLACE_OP_ANAMORPHIC, 487 static_cast<word>(Interpreter::BinaryOp::ADD), 488 4, 489 0, 490 INPLACE_OP_ANAMORPHIC, 491 static_cast<word>(Interpreter::BinaryOp::SUB), 492 5, 493 0, 494 INPLACE_OP_ANAMORPHIC, 495 static_cast<word>(Interpreter::BinaryOp::FLOORDIV), 496 6, 497 0, 498 INPLACE_OP_ANAMORPHIC, 499 static_cast<word>(Interpreter::BinaryOp::TRUEDIV), 500 7, 501 0, 502 INPLACE_OP_ANAMORPHIC, 503 static_cast<word>(Interpreter::BinaryOp::LSHIFT), 504 8, 505 0, 506 INPLACE_OP_ANAMORPHIC, 507 static_cast<word>(Interpreter::BinaryOp::RSHIFT), 508 9, 509 0, 510 INPLACE_OP_ANAMORPHIC, 511 static_cast<word>(Interpreter::BinaryOp::AND), 512 10, 513 0, 514 INPLACE_OP_ANAMORPHIC, 515 static_cast<word>(Interpreter::BinaryOp::XOR), 516 11, 517 0, 518 INPLACE_OP_ANAMORPHIC, 519 static_cast<word>(Interpreter::BinaryOp::OR), 520 12, 521 0, 522 }; 523 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 524 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 525} 526 527TEST_F(BytecodeTest, RewriteBytecodeRewritesCompareOpOpcodes) { 528 HandleScope scope(thread_); 529 Object name(&scope, Str::empty()); 530 const byte bytecode[] = { 531 COMPARE_OP, CompareOp::LT, COMPARE_OP, CompareOp::LE, 532 COMPARE_OP, CompareOp::EQ, COMPARE_OP, CompareOp::NE, 533 COMPARE_OP, CompareOp::GT, COMPARE_OP, CompareOp::GE, 534 COMPARE_OP, CompareOp::IN, COMPARE_OP, CompareOp::NOT_IN, 535 COMPARE_OP, CompareOp::IS, COMPARE_OP, CompareOp::IS_NOT, 536 COMPARE_OP, CompareOp::EXC_MATCH, 537 }; 538 Code code(&scope, newCodeWithBytes(bytecode)); 539 540 Module module(&scope, findMainModule(runtime_)); 541 Function function(&scope, 542 runtime_->newFunctionWithCode(thread_, name, code, module)); 543 // newFunctionWithCode() calls rewriteBytecode(). 544 545 byte expected[] = { 546 COMPARE_OP_ANAMORPHIC, 547 CompareOp::LT, 548 0, 549 0, 550 COMPARE_OP_ANAMORPHIC, 551 CompareOp::LE, 552 1, 553 0, 554 COMPARE_OP_ANAMORPHIC, 555 CompareOp::EQ, 556 2, 557 0, 558 COMPARE_OP_ANAMORPHIC, 559 CompareOp::NE, 560 3, 561 0, 562 COMPARE_OP_ANAMORPHIC, 563 CompareOp::GT, 564 4, 565 0, 566 COMPARE_OP_ANAMORPHIC, 567 CompareOp::GE, 568 5, 569 0, 570 COMPARE_IN_ANAMORPHIC, 571 0, 572 6, 573 0, 574 COMPARE_OP, 575 CompareOp::NOT_IN, 576 0, 577 0, 578 COMPARE_IS, 579 0, 580 0, 581 0, 582 COMPARE_IS_NOT, 583 0, 584 0, 585 0, 586 COMPARE_OP, 587 CompareOp::EXC_MATCH, 588 0, 589 0, 590 }; 591 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 592 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 593} 594 595TEST_F(BytecodeTest, RewriteBytecodeRewritesReservesCachesForGlobalVariables) { 596 HandleScope scope(thread_); 597 Object name(&scope, Str::empty()); 598 const byte bytecode[] = { 599 LOAD_GLOBAL, 0, STORE_GLOBAL, 1, LOAD_ATTR, 9, DELETE_GLOBAL, 2, 600 STORE_NAME, 3, DELETE_NAME, 4, LOAD_ATTR, 9, LOAD_NAME, 5, 601 }; 602 Tuple consts(&scope, runtime_->emptyTuple()); 603 MutableTuple names(&scope, runtime_->newMutableTuple(12)); 604 for (word i = 0; i < 12; i++) { 605 names.atPut(i, runtime_->newStrFromFmt("g%w", i)); 606 } 607 Tuple names_tuple(&scope, names.becomeImmutable()); 608 Code code(&scope, newCodeWithBytesConstsNames(bytecode, consts, names_tuple)); 609 610 Module module(&scope, findMainModule(runtime_)); 611 Function function(&scope, 612 runtime_->newFunctionWithCode(thread_, name, code, module)); 613 // newFunctionWithCode() calls rewriteBytecode(). 614 615 byte expected[] = { 616 LOAD_GLOBAL, 617 0, 618 0, 619 0, 620 STORE_GLOBAL, 621 1, 622 0, 623 0, 624 // Note that LOAD_ATTR's cache index starts at 6 to reserve the first 6 625 // cache lines for 12 global variables. 626 LOAD_ATTR_ANAMORPHIC, 627 9, 628 6, 629 0, 630 DELETE_GLOBAL, 631 2, 632 0, 633 0, 634 STORE_NAME, 635 3, 636 0, 637 0, 638 DELETE_NAME, 639 4, 640 0, 641 0, 642 LOAD_ATTR_ANAMORPHIC, 643 9, 644 7, 645 0, 646 LOAD_NAME, 647 5, 648 0, 649 0, 650 }; 651 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 652 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 653 654 Tuple caches(&scope, function.caches()); 655 word num_global = 6; 656 word num_attr = 2; 657 EXPECT_EQ(caches.length(), (num_global + num_attr) * kIcPointersPerEntry); 658} 659 660TEST_F( 661 BytecodeTest, 662 RewriteBytecodeDoesNotRewriteLoadFastAndStoreFastOpcodesWithLargeLocalCount) { 663 HandleScope scope(thread_); 664 Object arg0(&scope, Runtime::internStrFromCStr(thread_, "arg0")); 665 Object var0(&scope, Runtime::internStrFromCStr(thread_, "var0")); 666 Object var1(&scope, Runtime::internStrFromCStr(thread_, "var1")); 667 Tuple varnames(&scope, runtime_->newTupleWith3(arg0, var0, var1)); 668 Object freevar0(&scope, Runtime::internStrFromCStr(thread_, "freevar0")); 669 Tuple freevars(&scope, runtime_->newTupleWith1(freevar0)); 670 Object cellvar0(&scope, Runtime::internStrFromCStr(thread_, "cellvar0")); 671 Tuple cellvars(&scope, runtime_->newTupleWith1(cellvar0)); 672 word argcount = 1; 673 // Set nlocals > 255 674 word nlocals = kMaxByte + 3; 675 byte bytecode[] = { 676 LOAD_FAST, 2, LOAD_FAST, 1, LOAD_FAST, 1, 677 STORE_FAST, 2, STORE_FAST, 1, STORE_FAST, 0, 678 }; 679 Bytes code_code(&scope, runtime_->newBytesWithAll(bytecode)); 680 Object empty_tuple(&scope, runtime_->emptyTuple()); 681 Object empty_string(&scope, Str::empty()); 682 Object lnotab(&scope, Bytes::empty()); 683 word flags = Code::Flags::kOptimized | Code::Flags::kNewlocals; 684 Code code(&scope, 685 runtime_->newCode(argcount, /*posonlyargcount=*/0, 686 /*kwonlyargcount=*/0, nlocals, 687 /*stacksize=*/0, /*flags=*/flags, code_code, 688 /*consts=*/empty_tuple, /*names=*/empty_tuple, 689 varnames, freevars, cellvars, 690 /*filename=*/empty_string, /*name=*/empty_string, 691 /*firstlineno=*/0, lnotab)); 692 693 Module module(&scope, findMainModule(runtime_)); 694 Function function(&scope, runtime_->newFunctionWithCode(thread_, empty_string, 695 code, module)); 696 // newFunctionWithCode() calls rewriteBytecode(). 697 698 byte expected[] = { 699 LOAD_FAST, 2, 0, 0, LOAD_FAST, 1, 0, 0, LOAD_FAST, 1, 0, 0, 700 STORE_FAST, 2, 0, 0, STORE_FAST, 1, 0, 0, STORE_FAST, 0, 0, 0, 701 }; 702 703 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 704 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 705 EXPECT_TRUE(function.caches().isNoneType()); 706} 707 708TEST_F(BytecodeTest, RewriteBytecodeRewritesLoadFastAndStoreFastOpcodes) { 709 HandleScope scope(thread_); 710 Object arg0(&scope, Runtime::internStrFromCStr(thread_, "arg0")); 711 Object var0(&scope, Runtime::internStrFromCStr(thread_, "var0")); 712 Object var1(&scope, Runtime::internStrFromCStr(thread_, "var1")); 713 Tuple varnames(&scope, runtime_->newTupleWith3(arg0, var0, var1)); 714 Object freevar0(&scope, Runtime::internStrFromCStr(thread_, "freevar0")); 715 Tuple freevars(&scope, runtime_->newTupleWith1(freevar0)); 716 Object cellvar0(&scope, Runtime::internStrFromCStr(thread_, "cellvar0")); 717 Tuple cellvars(&scope, runtime_->newTupleWith1(cellvar0)); 718 word argcount = 1; 719 word nlocals = 3; 720 byte bytecode[] = { 721 LOAD_FAST, 2, LOAD_FAST, 1, LOAD_FAST, 1, 722 STORE_FAST, 2, STORE_FAST, 1, STORE_FAST, 0, 723 }; 724 Bytes code_code(&scope, runtime_->newBytesWithAll(bytecode)); 725 Object empty_tuple(&scope, runtime_->emptyTuple()); 726 Object empty_string(&scope, Str::empty()); 727 Object lnotab(&scope, Bytes::empty()); 728 word flags = Code::Flags::kOptimized | Code::Flags::kNewlocals; 729 Code code(&scope, 730 runtime_->newCode(argcount, /*posonlyargcount=*/0, 731 /*kwonlyargcount=*/0, nlocals, 732 /*stacksize=*/0, /*flags=*/flags, code_code, 733 /*consts=*/empty_tuple, /*names=*/empty_tuple, 734 varnames, freevars, cellvars, 735 /*filename=*/empty_string, /*name=*/empty_string, 736 /*firstlineno=*/0, lnotab)); 737 738 Module module(&scope, findMainModule(runtime_)); 739 Function function(&scope, runtime_->newFunctionWithCode(thread_, empty_string, 740 code, module)); 741 // newFunctionWithCode() calls rewriteBytecode(). 742 743 byte expected[] = { 744 LOAD_FAST_REVERSE, 2, 0, 0, LOAD_FAST_REVERSE, 3, 0, 0, 745 LOAD_FAST_REVERSE, 3, 0, 0, STORE_FAST_REVERSE, 2, 0, 0, 746 STORE_FAST_REVERSE, 3, 0, 0, STORE_FAST_REVERSE, 4, 0, 0, 747 }; 748 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 749 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 750 EXPECT_TRUE(function.caches().isNoneType()); 751} 752 753TEST_F( 754 BytecodeTest, 755 RewriteBytecodeRewritesLoadFastToLoadFastReverseWhenDeleteFastIsPresent) { 756 HandleScope scope(thread_); 757 Object arg0(&scope, Runtime::internStrFromCStr(thread_, "arg0")); 758 Object var0(&scope, Runtime::internStrFromCStr(thread_, "var0")); 759 Object var1(&scope, Runtime::internStrFromCStr(thread_, "var1")); 760 Tuple varnames(&scope, runtime_->newTupleWith3(arg0, var0, var1)); 761 Object freevar0(&scope, Runtime::internStrFromCStr(thread_, "freevar0")); 762 Tuple freevars(&scope, runtime_->newTupleWith1(freevar0)); 763 Object cellvar0(&scope, Runtime::internStrFromCStr(thread_, "cellvar0")); 764 Tuple cellvars(&scope, runtime_->newTupleWith1(cellvar0)); 765 word argcount = 1; 766 word nlocals = 3; 767 const byte bytecode[] = { 768 LOAD_FAST, 2, LOAD_FAST, 1, LOAD_FAST, 0, STORE_FAST, 2, 769 STORE_FAST, 1, STORE_FAST, 0, DELETE_FAST, 0, 770 }; 771 Bytes code_code(&scope, runtime_->newBytesWithAll(bytecode)); 772 Object empty_tuple(&scope, runtime_->emptyTuple()); 773 Object empty_string(&scope, Str::empty()); 774 Object lnotab(&scope, Bytes::empty()); 775 word flags = Code::Flags::kOptimized | Code::Flags::kNewlocals; 776 Code code(&scope, 777 runtime_->newCode(argcount, /*posonlyargcount=*/0, 778 /*kwonlyargcount=*/0, nlocals, 779 /*stacksize=*/0, /*flags=*/flags, code_code, 780 /*consts=*/empty_tuple, /*names=*/empty_tuple, 781 varnames, freevars, cellvars, 782 /*filename=*/empty_string, /*name=*/empty_string, 783 /*firstlineno=*/0, lnotab)); 784 785 Module module(&scope, findMainModule(runtime_)); 786 Function function(&scope, runtime_->newFunctionWithCode(thread_, empty_string, 787 code, module)); 788 // newFunctionWithCode() calls rewriteBytecode(). 789 790 byte expected[] = { 791 LOAD_FAST_REVERSE, 2, 0, 0, LOAD_FAST_REVERSE, 3, 0, 0, 792 LOAD_FAST_REVERSE, 4, 0, 0, STORE_FAST_REVERSE, 2, 0, 0, 793 STORE_FAST_REVERSE, 3, 0, 0, STORE_FAST_REVERSE, 4, 0, 0, 794 DELETE_FAST, 0, 0, 0, 795 }; 796 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 797 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 798 EXPECT_TRUE(function.caches().isNoneType()); 799} 800 801TEST_F(BytecodeTest, 802 RewriteBytecodeDoesNotRewriteFunctionsWithNoOptimizedNorNewLocalsFlag) { 803 HandleScope scope(thread_); 804 Object name(&scope, Str::empty()); 805 Tuple consts(&scope, runtime_->emptyTuple()); 806 Tuple names(&scope, runtime_->emptyTuple()); 807 const byte bytecode[] = { 808 NOP, 99, EXTENDED_ARG, 0xca, LOAD_ATTR, 0xfe, 809 NOP, 106, EXTENDED_ARG, 1, EXTENDED_ARG, 2, 810 EXTENDED_ARG, 3, LOAD_ATTR, 4, LOAD_ATTR, 77, 811 }; 812 Code code(&scope, 813 newCodeWithBytesConstsNamesFlags(bytecode, consts, names, 0)); 814 815 Module module(&scope, findMainModule(runtime_)); 816 Function function(&scope, 817 runtime_->newFunctionWithCode(thread_, name, code, module)); 818 819 byte expected[] = { 820 NOP, 99, 0, 0, EXTENDED_ARG, 0xca, 0, 0, 821 LOAD_ATTR, 0xfe, 0, 0, NOP, 106, 0, 0, 822 EXTENDED_ARG, 1, 0, 0, EXTENDED_ARG, 2, 0, 0, 823 EXTENDED_ARG, 3, 0, 0, LOAD_ATTR, 4, 0, 0, 824 LOAD_ATTR, 77, 0, 0, 825 }; 826 Object rewritten_bytecode(&scope, function.rewrittenBytecode()); 827 EXPECT_TRUE(isMutableBytesEqualsBytes(rewritten_bytecode, expected)); 828} 829 830} // namespace testing 831} // namespace py