Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-105481: expose opcode metadata via the _opcode module#106688

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
iritkatriel merged 10 commits intopython:mainfromiritkatriel:expose_metadata
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletionsInclude/cpython/compile.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,3 +67,9 @@ typedef struct {
#define PY_INVALID_STACK_EFFECT INT_MAX
PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg);
PyAPI_FUNC(int) PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump);

PyAPI_FUNC(int) PyUnstable_OpcodeIsValid(int opcode);
PyAPI_FUNC(int) PyUnstable_OpcodeHasArg(int opcode);
PyAPI_FUNC(int) PyUnstable_OpcodeHasConst(int opcode);
PyAPI_FUNC(int) PyUnstable_OpcodeHasName(int opcode);
PyAPI_FUNC(int) PyUnstable_OpcodeHasJump(int opcode);
32 changes: 22 additions & 10 deletionsInclude/internal/pycore_opcode_metadata.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

64 changes: 64 additions & 0 deletionsLib/test/test__opcode.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,70 @@

class OpcodeTests(unittest.TestCase):

def check_bool_function_result(self, func, ops, expected):
for op in ops:
if isinstance(op, str):
op = dis.opmap[op]
with self.subTest(opcode=op, func=func):
self.assertIsInstance(func(op), bool)
self.assertEqual(func(op), expected)

def test_invalid_opcodes(self):
invalid = [-100, -1, 255, 512, 513, 1000]
self.check_bool_function_result(_opcode.is_valid, invalid, False)
self.check_bool_function_result(_opcode.has_arg, invalid, False)
self.check_bool_function_result(_opcode.has_const, invalid, False)
self.check_bool_function_result(_opcode.has_name, invalid, False)
self.check_bool_function_result(_opcode.has_jump, invalid, False)

def test_is_valid(self):
names = [
'CACHE',
'POP_TOP',
'IMPORT_NAME',
'JUMP',
'INSTRUMENTED_RETURN_VALUE',
]
opcodes = [dis.opmap[opname] for opname in names]
self.check_bool_function_result(_opcode.is_valid, opcodes, True)

def test_has_arg(self):
has_arg = ['SWAP', 'LOAD_FAST', 'INSTRUMENTED_POP_JUMP_IF_TRUE', 'JUMP']
no_arg = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE']
self.check_bool_function_result(_opcode.has_arg, has_arg, True)
self.check_bool_function_result(_opcode.has_arg, no_arg, False)

def test_has_const(self):
has_const = ['LOAD_CONST', 'RETURN_CONST', 'KW_NAMES']
no_const = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE']
self.check_bool_function_result(_opcode.has_const, has_const, True)
self.check_bool_function_result(_opcode.has_const, no_const, False)

def test_has_name(self):
has_name = ['STORE_NAME', 'DELETE_ATTR', 'STORE_GLOBAL', 'IMPORT_FROM',
'LOAD_FROM_DICT_OR_GLOBALS']
no_name = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE']
self.check_bool_function_result(_opcode.has_name, has_name, True)
self.check_bool_function_result(_opcode.has_name, no_name, False)

def test_has_jump(self):
has_jump = ['FOR_ITER', 'JUMP_FORWARD', 'JUMP', 'POP_JUMP_IF_TRUE', 'SEND']
no_jump = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE']
self.check_bool_function_result(_opcode.has_jump, has_jump, True)
self.check_bool_function_result(_opcode.has_jump, no_jump, False)

# the following test is part of the refactor, it will be removed soon
def test_against_legacy_bool_values(self):
# limiting to ops up to ENTER_EXECUTOR, because everything after that
# is not currently categorized correctly in opcode.py.
for op in range(0, opcode.opmap['ENTER_EXECUTOR']):
with self.subTest(op=op):
if opcode.opname[op] != f'<{op}>':
self.assertEqual(op in dis.hasarg, _opcode.has_arg(op))
self.assertEqual(op in dis.hasconst, _opcode.has_const(op))
self.assertEqual(op in dis.hasname, _opcode.has_name(op))
self.assertEqual(op in dis.hasjrel, _opcode.has_jump(op))

def test_stack_effect(self):
self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1)
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1)
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
Expose opcode metadata through :mod:`_opcode`.
91 changes: 91 additions & 0 deletionsModules/_opcode.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
#include"Python.h"
#include"compile.h"
#include"opcode.h"
#include"internal/pycore_code.h"

Expand DownExpand Up@@ -61,6 +62,91 @@ _opcode_stack_effect_impl(PyObject *module, int opcode, PyObject *oparg,

/*[clinic input]
_opcode.is_valid -> bool
opcode: int
Return True if opcode is valid, False otherwise.
[clinic start generated code]*/

staticint
_opcode_is_valid_impl(PyObject*module,intopcode)
/*[clinic end generated code: output=b0d918ea1d073f65 input=fe23e0aa194ddae0]*/
{
returnPyUnstable_OpcodeIsValid(opcode);
}

/*[clinic input]
_opcode.has_arg -> bool
opcode: int
Return True if the opcode uses its oparg, False otherwise.
[clinic start generated code]*/

staticint
_opcode_has_arg_impl(PyObject*module,intopcode)
/*[clinic end generated code: output=7a062d3b2dcc0815 input=93d878ba6361db5f]*/
{
returnPyUnstable_OpcodeIsValid(opcode)&&
PyUnstable_OpcodeHasArg(opcode);
}

/*[clinic input]
_opcode.has_const -> bool
opcode: int
Return True if the opcode accesses a constant, False otherwise.
[clinic start generated code]*/

staticint
_opcode_has_const_impl(PyObject*module,intopcode)
/*[clinic end generated code: output=c646d5027c634120 input=a6999e4cf13f9410]*/
{
returnPyUnstable_OpcodeIsValid(opcode)&&
PyUnstable_OpcodeHasConst(opcode);
}

/*[clinic input]
_opcode.has_name -> bool
opcode: int
Return True if the opcode accesses an attribute by name, False otherwise.
[clinic start generated code]*/

staticint
_opcode_has_name_impl(PyObject*module,intopcode)
/*[clinic end generated code: output=b49a83555c2fa517 input=448aa5e4bcc947ba]*/
{
returnPyUnstable_OpcodeIsValid(opcode)&&
PyUnstable_OpcodeHasName(opcode);
}

/*[clinic input]
_opcode.has_jump -> bool
opcode: int
Return True if the opcode has a jump target, False otherwise.
[clinic start generated code]*/

staticint
_opcode_has_jump_impl(PyObject*module,intopcode)
/*[clinic end generated code: output=e9c583c669f1c46a input=35f711274357a0c3]*/
{
returnPyUnstable_OpcodeIsValid(opcode)&&
PyUnstable_OpcodeHasJump(opcode);

}

/*[clinic input]
_opcode.get_specialization_stats
Return the specialization stats
Expand All@@ -80,6 +166,11 @@ _opcode_get_specialization_stats_impl(PyObject *module)
staticPyMethodDef
opcode_functions[]= {
_OPCODE_STACK_EFFECT_METHODDEF
_OPCODE_IS_VALID_METHODDEF
_OPCODE_HAS_ARG_METHODDEF
_OPCODE_HAS_CONST_METHODDEF
_OPCODE_HAS_NAME_METHODDEF
_OPCODE_HAS_JUMP_METHODDEF
_OPCODE_GET_SPECIALIZATION_STATS_METHODDEF
{NULL,NULL,0,NULL}
};
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp