Skip to content

Commit 1379050

Browse files
committed
Parse EXTENDED_ARG in Runtime::collectAttributes
Add and modify tests. Fix #428
1 parent 99b54e1 commit 1379050

File tree

2 files changed

+38
-18
lines changed

2 files changed

+38
-18
lines changed

runtime/runtime-test.cpp

+29-11
Original file line numberDiff line numberDiff line change
@@ -1438,9 +1438,33 @@ TEST_F(RuntimeTest, CollectAttributes) {
14381438
result = dictAtByStr(thread_, attributes, baz);
14391439
ASSERT_TRUE(result.isStr());
14401440
EXPECT_TRUE(Str::cast(*result).equals(*baz));
1441+
1442+
// Bytecode for the snippet:
1443+
//
1444+
// def __init__(self):
1445+
// self.foo = 100
1446+
//
1447+
// Manually add duplicate and useless EXTENDED_ARG intentionally to ensure
1448+
// that collectAttributes can handle it.
1449+
const byte bytecode2[] = {LOAD_CONST, 0, EXTENDED_ARG, 0, EXTENDED_ARG, 0,
1450+
EXTENDED_ARG, 0, LOAD_FAST, 0, STORE_ATTR, 0,
1451+
RETURN_VALUE, 0};
1452+
Code code2(&scope, newCodeWithBytesConstsNamesLocals(bytecode2, consts, names,
1453+
&locals));
1454+
1455+
attributes = runtime_->newDict();
1456+
runtime_->collectAttributes(code2, attributes);
1457+
1458+
// We should have collected a single attribute: 'foo'
1459+
EXPECT_EQ(attributes.numItems(), 1);
1460+
1461+
// Check that we collected 'foo'
1462+
result = dictAtByStr(thread_, attributes, foo);
1463+
ASSERT_TRUE(result.isStr());
1464+
EXPECT_TRUE(Str::cast(*result).equals(*foo));
14411465
}
14421466

1443-
TEST_F(RuntimeTest, CollectAttributesWithExtendedArg) {
1467+
TEST_F(RuntimeTest, CollectAttributesWithExtendedArgAccumulates) {
14441468
HandleScope scope(thread_);
14451469

14461470
Str foo(&scope, runtime_->newStrFromCStr("foo"));
@@ -1461,22 +1485,16 @@ TEST_F(RuntimeTest, CollectAttributesWithExtendedArg) {
14611485
//
14621486
// There is an additional LOAD_FAST that is preceded by an EXTENDED_ARG
14631487
// that must be skipped.
1464-
const byte bytecode[] = {LOAD_CONST, 0, EXTENDED_ARG, 1, LOAD_FAST, 0,
1465-
STORE_ATTR, 1, LOAD_CONST, 0, LOAD_FAST, 0,
1466-
STORE_ATTR, 0, RETURN_VALUE, 0};
1488+
const byte bytecode[] = {LOAD_CONST, 0, EXTENDED_ARG, 1, LOAD_FAST, 0,
1489+
STORE_ATTR, 1, LOAD_CONST, 0, RETURN_VALUE, 0};
14671490
Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names,
14681491
&locals));
14691492

14701493
Dict attributes(&scope, runtime_->newDict());
14711494
runtime_->collectAttributes(code, attributes);
14721495

1473-
// We should have collected a single attribute: 'foo'
1474-
EXPECT_EQ(attributes.numItems(), 1);
1475-
1476-
// Check that we collected 'foo'
1477-
Object result(&scope, dictAtByStr(thread_, attributes, foo));
1478-
ASSERT_TRUE(result.isStr());
1479-
EXPECT_TRUE(Str::cast(*result).equals(*foo));
1496+
// We should have collected no attributes because EXTENDED_ARG makes 0x0100
1497+
EXPECT_EQ(attributes.numItems(), 0);
14801498
}
14811499

14821500
TEST_F(RuntimeTest, GetTypeConstructor) {

runtime/runtime.cpp

+9-7
Original file line numberDiff line numberDiff line change
@@ -2879,15 +2879,17 @@ void Runtime::collectAttributes(const Code& code, const Dict& attributes) {
28792879
Tuple names(&scope, code.names());
28802880

28812881
word len = bc.length();
2882-
for (word i = 0; i < len - 3; i += 2) {
2883-
// If the current instruction is EXTENDED_ARG we must skip it and the next
2884-
// instruction.
2885-
if (bc.byteAt(i) == Bytecode::EXTENDED_ARG) {
2886-
i += 2;
2887-
continue;
2882+
for (word i = 0; i < len - (kCompilerCodeUnitSize + 1);
2883+
i += kCompilerCodeUnitSize) {
2884+
byte op = bc.byteAt(i);
2885+
int32_t arg = bc.byteAt(i + 1);
2886+
while (op == Bytecode::EXTENDED_ARG) {
2887+
i += kCompilerCodeUnitSize;
2888+
op = bc.byteAt(i);
2889+
arg = (arg << kBitsPerByte) | bc.byteAt(i + 1);
28882890
}
28892891
// Check for LOAD_FAST 0 (self)
2890-
if (bc.byteAt(i) != Bytecode::LOAD_FAST || bc.byteAt(i + 1) != 0) {
2892+
if (op != Bytecode::LOAD_FAST || arg != 0) {
28912893
continue;
28922894
}
28932895
// Followed by a STORE_ATTR

0 commit comments

Comments
 (0)