this repo has no description

Parse EXTENDED_ARG in Runtime::collectAttributes

Add and modify tests.

Fix #428

authored by bernsteinbear.com and committed by

Max Bernstein 2f1bc0cd ed0876e9

+38 -18
+29 -11
runtime/runtime-test.cpp
··· 1438 1438 result = dictAtByStr(thread_, attributes, baz); 1439 1439 ASSERT_TRUE(result.isStr()); 1440 1440 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)); 1441 1465 } 1442 1466 1443 - TEST_F(RuntimeTest, CollectAttributesWithExtendedArg) { 1467 + TEST_F(RuntimeTest, CollectAttributesWithExtendedArgAccumulates) { 1444 1468 HandleScope scope(thread_); 1445 1469 1446 1470 Str foo(&scope, runtime_->newStrFromCStr("foo")); ··· 1461 1485 // 1462 1486 // There is an additional LOAD_FAST that is preceded by an EXTENDED_ARG 1463 1487 // 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}; 1467 1490 Code code(&scope, newCodeWithBytesConstsNamesLocals(bytecode, consts, names, 1468 1491 &locals)); 1469 1492 1470 1493 Dict attributes(&scope, runtime_->newDict()); 1471 1494 runtime_->collectAttributes(code, attributes); 1472 1495 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); 1480 1498 } 1481 1499 1482 1500 TEST_F(RuntimeTest, GetTypeConstructor) {
+9 -7
runtime/runtime.cpp
··· 2879 2879 Tuple names(&scope, code.names()); 2880 2880 2881 2881 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); 2888 2890 } 2889 2891 // 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) { 2891 2893 continue; 2892 2894 } 2893 2895 // Followed by a STORE_ATTR