···14381438 result = dictAtByStr(thread_, attributes, baz);
14391439 ASSERT_TRUE(result.isStr());
14401440 EXPECT_TRUE(Str::cast(*result).equals(*baz));
14411441+14421442+ // Bytecode for the snippet:
14431443+ //
14441444+ // def __init__(self):
14451445+ // self.foo = 100
14461446+ //
14471447+ // Manually add duplicate and useless EXTENDED_ARG intentionally to ensure
14481448+ // that collectAttributes can handle it.
14491449+ const byte bytecode2[] = {LOAD_CONST, 0, EXTENDED_ARG, 0, EXTENDED_ARG, 0,
14501450+ EXTENDED_ARG, 0, LOAD_FAST, 0, STORE_ATTR, 0,
14511451+ RETURN_VALUE, 0};
14521452+ Code code2(&scope, newCodeWithBytesConstsNamesLocals(bytecode2, consts, names,
14531453+ &locals));
14541454+14551455+ attributes = runtime_->newDict();
14561456+ runtime_->collectAttributes(code2, attributes);
14571457+14581458+ // We should have collected a single attribute: 'foo'
14591459+ EXPECT_EQ(attributes.numItems(), 1);
14601460+14611461+ // Check that we collected 'foo'
14621462+ result = dictAtByStr(thread_, attributes, foo);
14631463+ ASSERT_TRUE(result.isStr());
14641464+ EXPECT_TRUE(Str::cast(*result).equals(*foo));
14411465}
1442146614431443-TEST_F(RuntimeTest, CollectAttributesWithExtendedArg) {
14671467+TEST_F(RuntimeTest, CollectAttributesWithExtendedArgAccumulates) {
14441468 HandleScope scope(thread_);
1445146914461470 Str foo(&scope, runtime_->newStrFromCStr("foo"));
···14611485 //
14621486 // There is an additional LOAD_FAST that is preceded by an EXTENDED_ARG
14631487 // that must be skipped.
14641464- const byte bytecode[] = {LOAD_CONST, 0, EXTENDED_ARG, 1, LOAD_FAST, 0,
14651465- STORE_ATTR, 1, LOAD_CONST, 0, LOAD_FAST, 0,
14661466- STORE_ATTR, 0, RETURN_VALUE, 0};
14881488+ const byte bytecode[] = {LOAD_CONST, 0, EXTENDED_ARG, 1, LOAD_FAST, 0,
14891489+ STORE_ATTR, 1, LOAD_CONST, 0, RETURN_VALUE, 0};
14671490 Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names,
14681491 &locals));
1469149214701493 Dict attributes(&scope, runtime_->newDict());
14711494 runtime_->collectAttributes(code, attributes);
1472149514731473- // We should have collected a single attribute: 'foo'
14741474- EXPECT_EQ(attributes.numItems(), 1);
14751475-14761476- // Check that we collected 'foo'
14771477- Object result(&scope, dictAtByStr(thread_, attributes, foo));
14781478- ASSERT_TRUE(result.isStr());
14791479- EXPECT_TRUE(Str::cast(*result).equals(*foo));
14961496+ // We should have collected no attributes because EXTENDED_ARG makes 0x0100
14971497+ EXPECT_EQ(attributes.numItems(), 0);
14801498}
1481149914821500TEST_F(RuntimeTest, GetTypeConstructor) {
+9-7
runtime/runtime.cpp
···28792879 Tuple names(&scope, code.names());
2880288028812881 word len = bc.length();
28822882- for (word i = 0; i < len - 3; i += 2) {
28832883- // If the current instruction is EXTENDED_ARG we must skip it and the next
28842884- // instruction.
28852885- if (bc.byteAt(i) == Bytecode::EXTENDED_ARG) {
28862886- i += 2;
28872887- continue;
28822882+ for (word i = 0; i < len - (kCompilerCodeUnitSize + 1);
28832883+ i += kCompilerCodeUnitSize) {
28842884+ byte op = bc.byteAt(i);
28852885+ int32_t arg = bc.byteAt(i + 1);
28862886+ while (op == Bytecode::EXTENDED_ARG) {
28872887+ i += kCompilerCodeUnitSize;
28882888+ op = bc.byteAt(i);
28892889+ arg = (arg << kBitsPerByte) | bc.byteAt(i + 1);
28882890 }
28892891 // Check for LOAD_FAST 0 (self)
28902890- if (bc.byteAt(i) != Bytecode::LOAD_FAST || bc.byteAt(i + 1) != 0) {
28922892+ if (op != Bytecode::LOAD_FAST || arg != 0) {
28912893 continue;
28922894 }
28932895 // Followed by a STORE_ATTR