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

Commitc179c0e

Browse files
authored
gh-117680: make _PyInstructionSequence a PyObject and use it in tests (#117629)
1 parentae8dfd2 commitc179c0e

17 files changed

+838
-242
lines changed

‎Include/internal/pycore_global_objects_fini_generated.h‎

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Include/internal/pycore_global_strings.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ struct _Py_global_strings {
353353
STRUCT_FOR_ID(co_stacksize)
354354
STRUCT_FOR_ID(co_varnames)
355355
STRUCT_FOR_ID(code)
356+
STRUCT_FOR_ID(col_offset)
356357
STRUCT_FOR_ID(command)
357358
STRUCT_FOR_ID(comment_factory)
358359
STRUCT_FOR_ID(compile_mode)
@@ -402,6 +403,7 @@ struct _Py_global_strings {
402403
STRUCT_FOR_ID(encode)
403404
STRUCT_FOR_ID(encoding)
404405
STRUCT_FOR_ID(end)
406+
STRUCT_FOR_ID(end_col_offset)
405407
STRUCT_FOR_ID(end_lineno)
406408
STRUCT_FOR_ID(end_offset)
407409
STRUCT_FOR_ID(endpos)
@@ -522,6 +524,7 @@ struct _Py_global_strings {
522524
STRUCT_FOR_ID(kw1)
523525
STRUCT_FOR_ID(kw2)
524526
STRUCT_FOR_ID(kwdefaults)
527+
STRUCT_FOR_ID(label)
525528
STRUCT_FOR_ID(lambda)
526529
STRUCT_FOR_ID(last)
527530
STRUCT_FOR_ID(last_exc)
@@ -585,6 +588,7 @@ struct _Py_global_strings {
585588
STRUCT_FOR_ID(namespaces)
586589
STRUCT_FOR_ID(narg)
587590
STRUCT_FOR_ID(ndigits)
591+
STRUCT_FOR_ID(nested)
588592
STRUCT_FOR_ID(new_file_name)
589593
STRUCT_FOR_ID(new_limit)
590594
STRUCT_FOR_ID(newline)

‎Include/internal/pycore_instruction_sequence.h‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
# error "this header requires Py_BUILD_CORE define"
66
#endif
77

8+
#include"pycore_symtable.h"
9+
810
#ifdef__cplusplus
911
extern"C" {
1012
#endif
1113

14+
1215
typedefstruct {
1316
inth_label;
1417
inth_startdepth;
@@ -26,23 +29,30 @@ typedef struct {
2629
inti_offset;
2730
}_PyInstruction;
2831

29-
typedefstruct {
32+
typedefstructinstruction_sequence {
33+
PyObject_HEAD
3034
_PyInstruction*s_instrs;
3135
ints_allocated;
3236
ints_used;
3337

3438
ints_next_free_label;/* next free label id */
39+
3540
/* Map of a label id to instruction offset (index into s_instrs).
3641
* If s_labelmap is NULL, then each label id is the offset itself.
3742
*/
38-
int*s_labelmap;/* label id --> instr offset */
43+
int*s_labelmap;
3944
ints_labelmap_size;
45+
46+
/* PyList of instruction sequences of nested functions */
47+
PyObject*s_nested;
4048
}_PyInstructionSequence;
4149

4250
typedefstruct {
4351
intid;
4452
}_PyJumpTargetLabel;
4553

54+
PyAPI_FUNC(PyObject*)_PyInstructionSequence_New(void);
55+
4656
int_PyInstructionSequence_UseLabel(_PyInstructionSequence*seq,intlbl);
4757
int_PyInstructionSequence_Addop(_PyInstructionSequence*seq,
4858
intopcode,intoparg,
@@ -53,6 +63,8 @@ int _PyInstructionSequence_InsertInstruction(_PyInstructionSequence *seq, int po
5363
intopcode,intoparg,_Py_SourceLocationloc);
5464
voidPyInstructionSequence_Fini(_PyInstructionSequence*seq);
5565

66+
externPyTypeObject_PyInstructionSequence_Type;
67+
#define_PyInstructionSequence_Check(v) Py_IS_TYPE((v), &_PyInstructionSequence_Type)
5668

5769
#ifdef__cplusplus
5870
}

‎Include/internal/pycore_runtime_init_generated.h‎

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Include/internal/pycore_unicodeobject_generated.h‎

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Lib/test/support/bytecode_helper.py‎

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
importunittest
44
importdis
55
importio
6+
importopcode
67
try:
78
import_testinternalcapi
89
exceptImportError:
@@ -68,16 +69,14 @@ class CompilationStepTestCase(unittest.TestCase):
6869
classLabel:
6970
pass
7071

71-
defassertInstructionsMatch(self,actual_,expected_):
72-
# gettwo lists where each entry is a label or
73-
# an instruction tuple.Normalize the labels to the
74-
# instructioncount of the target,and compare thelists.
72+
defassertInstructionsMatch(self,actual_seq,expected):
73+
# getan InstructionSequence and an expected list, where each
74+
#entry is a label oran instruction tuple.Construct an expcted
75+
# instructionsequenceand comparewiththeone given.
7576

76-
self.assertIsInstance(actual_,list)
77-
self.assertIsInstance(expected_,list)
78-
79-
actual=self.normalize_insts(actual_)
80-
expected=self.normalize_insts(expected_)
77+
self.assertIsInstance(expected,list)
78+
actual=actual_seq.get_instructions()
79+
expected=self.seq_from_insts(expected).get_instructions()
8180
self.assertEqual(len(actual),len(expected))
8281

8382
# compare instructions
@@ -87,10 +86,8 @@ def assertInstructionsMatch(self, actual_, expected_):
8786
continue
8887
self.assertIsInstance(exp,tuple)
8988
self.assertIsInstance(act,tuple)
90-
# crop comparison to the provided expected values
91-
iflen(act)>len(exp):
92-
act=act[:len(exp)]
93-
self.assertEqual(exp,act)
89+
idx=max([p[0]forpinenumerate(exp)ifp[1]!=-1])
90+
self.assertEqual(exp[:idx],act[:idx])
9491

9592
defresolveAndRemoveLabels(self,insts):
9693
idx=0
@@ -105,35 +102,37 @@ def resolveAndRemoveLabels(self, insts):
105102

106103
returnres
107104

108-
defnormalize_insts(self,insts):
109-
""" Map labels to instruction index.
110-
Map opcodes to opnames.
111-
"""
112-
insts=self.resolveAndRemoveLabels(insts)
113-
res= []
114-
foritemininsts:
115-
assertisinstance(item,tuple)
116-
opcode,oparg,*loc=item
117-
opcode=dis.opmap.get(opcode,opcode)
118-
ifisinstance(oparg,self.Label):
119-
arg=oparg.value
120-
else:
121-
arg=opargifopcodeinself.HAS_ARGelseNone
122-
opcode=dis.opname[opcode]
123-
res.append((opcode,arg,*loc))
124-
returnres
105+
defseq_from_insts(self,insts):
106+
labels= {itemforitemininstsifisinstance(item,self.Label)}
107+
fori,lblinenumerate(labels):
108+
lbl.value=i
125109

126-
defcomplete_insts_info(self,insts):
127-
# fill in omitted fields in location, and oparg 0 for ops with no arg.
128-
res= []
110+
seq=_testinternalcapi.new_instruction_sequence()
129111
foritemininsts:
130-
assertisinstance(item,tuple)
131-
inst=list(item)
132-
opcode=dis.opmap[inst[0]]
133-
oparg=inst[1]
134-
loc=inst[2:]+ [-1]* (6-len(inst))
135-
res.append((opcode,oparg,*loc))
136-
returnres
112+
ifisinstance(item,self.Label):
113+
seq.use_label(item.value)
114+
else:
115+
op=item[0]
116+
ifisinstance(op,str):
117+
op=opcode.opmap[op]
118+
arg,*loc=item[1:]
119+
ifisinstance(arg,self.Label):
120+
arg=arg.value
121+
loc=loc+ [-1]* (4-len(loc))
122+
seq.addop(op,argor0,*loc)
123+
returnseq
124+
125+
defcheck_instructions(self,insts):
126+
forinstininsts:
127+
ifisinstance(inst,self.Label):
128+
continue
129+
op,arg,*loc=inst
130+
ifisinstance(op,str):
131+
op=opcode.opmap[op]
132+
self.assertEqual(opinopcode.hasarg,
133+
argisnotNone,
134+
f"{opcode.opname[op]=}{arg=}")
135+
self.assertTrue(all(isinstance(l,int)forlinloc))
137136

138137

139138
@unittest.skipIf(_testinternalcapiisNone,"requires _testinternalcapi")
@@ -147,10 +146,8 @@ def generate_code(self, ast):
147146
@unittest.skipIf(_testinternalcapiisNone,"requires _testinternalcapi")
148147
classCfgOptimizationTestCase(CompilationStepTestCase):
149148

150-
defget_optimized(self,insts,consts,nlocals=0):
151-
insts=self.normalize_insts(insts)
152-
insts=self.complete_insts_info(insts)
153-
insts=_testinternalcapi.optimize_cfg(insts,consts,nlocals)
149+
defget_optimized(self,seq,consts,nlocals=0):
150+
insts=_testinternalcapi.optimize_cfg(seq,consts,nlocals)
154151
returninsts,consts
155152

156153
@unittest.skipIf(_testinternalcapiisNone,"requires _testinternalcapi")

‎Lib/test/test_compile.py‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
importdis
33
importio
44
importmath
5+
importopcode
56
importos
67
importunittest
78
importsys
@@ -11,6 +12,8 @@
1112
importtypes
1213
importtextwrap
1314
importwarnings
15+
import_testinternalcapi
16+
1417
fromtestimportsupport
1518
fromtest.supportimport (script_helper,requires_debug_ranges,
1619
requires_specialization,get_c_recursion_limit)
@@ -2419,6 +2422,49 @@ def test_return_inside_async_with_block(self):
24192422
"""
24202423
self.check_stack_size(snippet,async_=True)
24212424

2425+
classTestInstructionSequence(unittest.TestCase):
2426+
defcompare_instructions(self,seq,expected):
2427+
self.assertEqual([(opcode.opname[i[0]],)+i[1:]foriinseq.get_instructions()],
2428+
expected)
2429+
2430+
deftest_basics(self):
2431+
seq=_testinternalcapi.new_instruction_sequence()
2432+
2433+
defadd_op(seq,opname,oparg,bl,bc=0,el=0,ec=0):
2434+
seq.addop(opcode.opmap[opname],oparg,bl,bc,el,el)
2435+
2436+
add_op(seq,'LOAD_CONST',1,1)
2437+
add_op(seq,'JUMP',lbl1:=seq.new_label(),2)
2438+
add_op(seq,'LOAD_CONST',1,3)
2439+
add_op(seq,'JUMP',lbl2:=seq.new_label(),4)
2440+
seq.use_label(lbl1)
2441+
add_op(seq,'LOAD_CONST',2,4)
2442+
seq.use_label(lbl2)
2443+
add_op(seq,'RETURN_VALUE',0,3)
2444+
2445+
expected= [('LOAD_CONST',1,1),
2446+
('JUMP',4,2),
2447+
('LOAD_CONST',1,3),
2448+
('JUMP',5,4),
2449+
('LOAD_CONST',2,4),
2450+
('RETURN_VALUE',None,3),
2451+
]
2452+
2453+
self.compare_instructions(seq, [ex+ (0,0,0)forexinexpected])
2454+
2455+
deftest_nested(self):
2456+
seq=_testinternalcapi.new_instruction_sequence()
2457+
seq.addop(opcode.opmap['LOAD_CONST'],1,1,0,0,0)
2458+
nested=_testinternalcapi.new_instruction_sequence()
2459+
nested.addop(opcode.opmap['LOAD_CONST'],2,2,0,0,0)
2460+
2461+
self.compare_instructions(seq, [('LOAD_CONST',1,1,0,0,0)])
2462+
self.compare_instructions(nested, [('LOAD_CONST',2,2,0,0,0)])
2463+
2464+
seq.add_nested(nested)
2465+
self.compare_instructions(seq, [('LOAD_CONST',1,1,0,0,0)])
2466+
self.compare_instructions(seq.get_nested()[0], [('LOAD_CONST',2,2,0,0,0)])
2467+
24222468

24232469
if__name__=="__main__":
24242470
unittest.main()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp