Skip to content

Commit ee8e857

Browse files
committed
Approach suggested by Irit
1 parent c76d0b5 commit ee8e857

File tree

10 files changed

+96
-66
lines changed

10 files changed

+96
-66
lines changed

Include/internal/pycore_instruction_sequence.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ typedef struct instruction_sequence {
4545

4646
/* PyList of instruction sequences of nested functions */
4747
PyObject *s_nested;
48+
49+
/* Code for creating annotations, spliced into the main sequence later */
50+
struct instruction_sequence *s_annotations_code;
4851
} _PyInstructionSequence;
4952

5053
typedef struct {
@@ -66,8 +69,8 @@ _PyJumpTargetLabel _PyInstructionSequence_NewLabel(_PyInstructionSequence *seq);
6669
int _PyInstructionSequence_ApplyLabelMap(_PyInstructionSequence *seq);
6770
int _PyInstructionSequence_InsertInstruction(_PyInstructionSequence *seq, int pos,
6871
int opcode, int oparg, _Py_SourceLocation loc);
69-
int _PyInstructionSequence_InjectSequence(_PyInstructionSequence *seq, int pos,
70-
_PyInstructionSequence *injected);
72+
int _PyInstructionSequence_SetAnnotationsCode(_PyInstructionSequence *seq,
73+
_PyInstructionSequence *annotations);
7174
int _PyInstructionSequence_AddNested(_PyInstructionSequence *seq, _PyInstructionSequence *nested);
7275
void PyInstructionSequence_Fini(_PyInstructionSequence *seq);
7376

Include/internal/pycore_opcode_metadata.h

Lines changed: 16 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/opcode_ids.h

Lines changed: 11 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/_opcode_metadata.py

Lines changed: 11 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_dis.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,8 @@ def test_boundaries(self):
10071007
def test_widths(self):
10081008
long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT',
10091009
'LOAD_FAST_BORROW_LOAD_FAST_BORROW',
1010-
'INSTRUMENTED_CALL_FUNCTION_EX'])
1010+
'INSTRUMENTED_CALL_FUNCTION_EX',
1011+
'ANNOTATIONS_PLACEHOLDER'])
10111012
for op, opname in enumerate(dis.opname):
10121013
if opname in long_opcodes or opname.startswith("INSTRUMENTED"):
10131014
continue
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
Raise an error if the ``__annotations__`` attribute is accessed on a module
2-
that has not finished executing.
1+
If the ``__annotations__`` of a module object are accessed while the
2+
module is executing, return the annotations that have been defined so far,
3+
without caching them.

Python/bytecodes.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,6 +2026,10 @@ dummy_func(
20262026
}
20272027
}
20282028

2029+
pseudo(ANNOTATIONS_PLACEHOLDER, (--)) = {
2030+
NOP,
2031+
};
2032+
20292033
inst(DICT_UPDATE, (dict, unused[oparg - 1], update -- dict, unused[oparg - 1])) {
20302034
PyObject *dict_o = PyStackRef_AsPyObjectBorrow(dict);
20312035
PyObject *update_o = PyStackRef_AsPyObjectBorrow(update);

Python/codegen.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,9 @@ codegen_enter_scope(compiler *c, identifier name, int scope_type,
654654
loc.lineno = 0;
655655
}
656656
ADDOP_I(c, loc, RESUME, RESUME_AT_FUNC_START);
657+
if (scope_type == COMPILE_SCOPE_MODULE) {
658+
ADDOP(c, loc, ANNOTATIONS_PLACEHOLDER);
659+
}
657660
return SUCCESS;
658661
}
659662

@@ -832,9 +835,8 @@ codegen_process_deferred_annotations(compiler *c, location loc)
832835

833836
if (nested_instr_seq != NULL) {
834837
RETURN_IF_ERROR(
835-
_PyInstructionSequence_InjectSequence(old_instr_seq, 1, nested_instr_seq));
838+
_PyInstructionSequence_SetAnnotationsCode(old_instr_seq, nested_instr_seq));
836839
_PyCompile_SetInstrSequence(c, old_instr_seq);
837-
PyInstructionSequence_Fini(nested_instr_seq);
838840
}
839841

840842
return SUCCESS;

Python/flowgraph.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3847,16 +3847,38 @@ _PyCfg_FromInstructionSequence(_PyInstructionSequence *seq)
38473847
seq->s_instrs[instr->i_oparg].i_target = 1;
38483848
}
38493849
}
3850+
int offset = 0;
38503851
for (int i = 0; i < seq->s_used; i++) {
38513852
_PyInstruction *instr = &seq->s_instrs[i];
3853+
if (instr->i_opcode == ANNOTATIONS_PLACEHOLDER) {
3854+
if (seq->s_annotations_code != NULL) {
3855+
assert(seq->s_annotations_code->s_labelmap_size == 0
3856+
&& seq->s_annotations_code->s_nested == NULL);
3857+
for (int j = 0; j < seq->s_annotations_code->s_used; j++) {
3858+
_PyInstruction *ann_instr = &seq->s_annotations_code->s_instrs[j];
3859+
assert(!HAS_TARGET(ann_instr->i_opcode));
3860+
if (_PyCfgBuilder_Addop(g, ann_instr->i_opcode, ann_instr->i_oparg, ann_instr->i_loc) < 0) {
3861+
goto error;
3862+
}
3863+
}
3864+
offset += seq->s_annotations_code->s_used - 1;
3865+
}
3866+
else {
3867+
offset -= 1;
3868+
}
3869+
continue;
3870+
}
38523871
if (instr->i_target) {
3853-
jump_target_label lbl_ = {i};
3872+
jump_target_label lbl_ = {i + offset};
38543873
if (_PyCfgBuilder_UseLabel(g, lbl_) < 0) {
38553874
goto error;
38563875
}
38573876
}
38583877
int opcode = instr->i_opcode;
38593878
int oparg = instr->i_oparg;
3879+
if (HAS_TARGET(opcode)) {
3880+
oparg += offset;
3881+
}
38603882
if (_PyCfgBuilder_Addop(g, opcode, oparg, instr->i_loc) < 0) {
38613883
goto error;
38623884
}

Python/instruction_sequence.c

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,24 @@ typedef _Py_SourceLocation location;
3434
}
3535

3636
static int
37-
instr_sequence_grow(instr_sequence *seq, int size) {
37+
instr_sequence_next_inst(instr_sequence *seq) {
3838
assert(seq->s_instrs != NULL || seq->s_used == 0);
3939

40+
4041
_Py_c_array_t array = {
4142
.array = (void*)seq->s_instrs,
4243
.allocated_entries = seq->s_allocated,
4344
.item_size = sizeof(instruction),
4445
.initial_num_entries = INITIAL_INSTR_SEQUENCE_SIZE,
4546
};
4647

47-
RETURN_IF_ERROR(_Py_CArray_EnsureCapacity(&array, seq->s_used + size));
48+
RETURN_IF_ERROR(_Py_CArray_EnsureCapacity(&array, seq->s_used + 1));
4849
seq->s_instrs = array.array;
4950
seq->s_allocated = array.allocated_entries;
5051

5152
assert(seq->s_allocated >= 0);
5253
assert(seq->s_used < seq->s_allocated);
53-
seq->s_used += size;
54-
return seq->s_used - 1;
55-
}
56-
57-
static int
58-
instr_sequence_next_inst(instr_sequence *seq) {
59-
return instr_sequence_grow(seq, 1);
54+
return seq->s_used++;
6055
}
6156

6257
_PyJumpTargetLabel
@@ -160,28 +155,11 @@ _PyInstructionSequence_InsertInstruction(instr_sequence *seq, int pos,
160155
}
161156

162157
int
163-
_PyInstructionSequence_InjectSequence(instr_sequence *seq, int pos,
164-
instr_sequence *injected)
158+
_PyInstructionSequence_SetAnnotationsCode(instr_sequence *seq,
159+
instr_sequence *annotations)
165160
{
166-
assert(pos >= 0 && pos <= seq->s_used);
167-
// Merging labelmaps is not supported
168-
assert(injected->s_labelmap_size == 0 && injected->s_nested == NULL);
169-
if (injected->s_used == 0) {
170-
return SUCCESS;
171-
}
172-
173-
int last_idx = instr_sequence_grow(seq, injected->s_used);
174-
175-
RETURN_IF_ERROR(last_idx);
176-
for (int i = last_idx - injected->s_used; i >= pos; i--) {
177-
seq->s_instrs[i + injected->s_used] = seq->s_instrs[i];
178-
}
179-
for (int i=0; i < injected->s_used; i++) {
180-
seq->s_instrs[i + pos] = injected->s_instrs[i];
181-
}
182-
for(int lbl=0; lbl < seq->s_labelmap_size; lbl++) {
183-
seq->s_labelmap[lbl] += injected->s_used;
184-
}
161+
assert(seq->s_annotations_code == NULL);
162+
seq->s_annotations_code = annotations;
185163
return SUCCESS;
186164
}
187165

@@ -209,6 +187,12 @@ PyInstructionSequence_Fini(instr_sequence *seq) {
209187

210188
PyMem_Free(seq->s_instrs);
211189
seq->s_instrs = NULL;
190+
191+
if (seq->s_annotations_code != NULL) {
192+
PyInstructionSequence_Fini(seq->s_annotations_code);
193+
Py_CLEAR(seq->s_annotations_code);
194+
}
195+
212196
}
213197

214198
/*[clinic input]
@@ -231,6 +215,7 @@ inst_seq_create(void)
231215
seq->s_labelmap = NULL;
232216
seq->s_labelmap_size = 0;
233217
seq->s_nested = NULL;
218+
seq->s_annotations_code = NULL;
234219

235220
PyObject_GC_Track(seq);
236221
return seq;
@@ -445,6 +430,7 @@ inst_seq_traverse(PyObject *op, visitproc visit, void *arg)
445430
{
446431
_PyInstructionSequence *seq = (_PyInstructionSequence *)op;
447432
Py_VISIT(seq->s_nested);
433+
Py_VISIT((PyObject *)seq->s_annotations_code);
448434
return 0;
449435
}
450436

@@ -453,6 +439,7 @@ inst_seq_clear(PyObject *op)
453439
{
454440
_PyInstructionSequence *seq = (_PyInstructionSequence *)op;
455441
Py_CLEAR(seq->s_nested);
442+
Py_CLEAR(seq->s_annotations_code);
456443
return 0;
457444
}
458445

0 commit comments

Comments
 (0)