Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
a4ebc135
Kaydet (Commit)
a4ebc135
authored
Nis 18, 2006
tarafından
Jeremy Hylton
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Refactor: Move code that uses co_lnotab from ceval to codeobject
üst
6db67821
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
162 additions
and
117 deletions
+162
-117
code.h
Include/code.h
+15
-0
codeobject.c
Objects/codeobject.c
+133
-0
ceval.c
Python/ceval.c
+14
-117
No files found.
Include/code.h
Dosyayı görüntüle @
a4ebc135
...
...
@@ -72,6 +72,21 @@ PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int);
((*(co)->co_code->ob_type->tp_as_buffer->bf_getreadbuffer) \
((co)->co_code, 0, (void **)(pp)))
typedef
struct
_addr_pair
{
int
ap_lower
;
int
ap_upper
;
}
PyAddrPair
;
/* Check whether lasti (an instruction offset) falls outside bounds
and whether it is a line number that should be traced. Returns
a line number if it should be traced or -1 if the line should not.
If lasti is not within bounds, updates bounds.
*/
PyAPI_FUNC
(
int
)
PyCode_CheckLineNumber
(
PyCodeObject
*
co
,
int
lasti
,
PyAddrPair
*
bounds
);
#ifdef __cplusplus
}
#endif
...
...
Objects/codeobject.c
Dosyayı görüntüle @
a4ebc135
...
...
@@ -451,3 +451,136 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq)
}
return
line
;
}
/*
Check whether the current instruction is at the start of a line.
*/
/* The theory of SET_LINENO-less tracing.
In a nutshell, we use the co_lnotab field of the code object
to tell when execution has moved onto a different line.
As mentioned above, the basic idea is so set things up so
that
*instr_lb <= frame->f_lasti < *instr_ub
is true so long as execution does not change lines.
This is all fairly simple. Digging the information out of
co_lnotab takes some work, but is conceptually clear.
Somewhat harder to explain is why we don't *always* call the
line trace function when the above test fails.
Consider this code:
1: def f(a):
2: if a:
3: print 1
4: else:
5: print 2
which compiles to this:
2 0 LOAD_FAST 0 (a)
3 JUMP_IF_FALSE 9 (to 15)
6 POP_TOP
3 7 LOAD_CONST 1 (1)
10 PRINT_ITEM
11 PRINT_NEWLINE
12 JUMP_FORWARD 6 (to 21)
>> 15 POP_TOP
5 16 LOAD_CONST 2 (2)
19 PRINT_ITEM
20 PRINT_NEWLINE
>> 21 LOAD_CONST 0 (None)
24 RETURN_VALUE
If 'a' is false, execution will jump to instruction at offset
15 and the co_lnotab will claim that execution has moved to
line 3. This is at best misleading. In this case we could
associate the POP_TOP with line 4, but that doesn't make
sense in all cases (I think).
What we do is only call the line trace function if the co_lnotab
indicates we have jumped to the *start* of a line, i.e. if the
current instruction offset matches the offset given for the
start of a line by the co_lnotab.
This also takes care of the situation where 'a' is true.
Execution will jump from instruction offset 12 to offset 21.
Then the co_lnotab would imply that execution has moved to line
5, which is again misleading.
Why do we set f_lineno when tracing? Well, consider the code
above when 'a' is true. If stepping through this with 'n' in
pdb, you would stop at line 1 with a "call" type event, then
line events on lines 2 and 3, then a "return" type event -- but
you would be shown line 5 during this event. This is a change
from the behaviour in 2.2 and before, and I've found it
confusing in practice. By setting and using f_lineno when
tracing, one can report a line number different from that
suggested by f_lasti on this one occasion where it's desirable.
*/
int
PyCode_CheckLineNumber
(
PyCodeObject
*
co
,
int
lasti
,
PyAddrPair
*
bounds
)
{
int
size
,
addr
,
line
;
unsigned
char
*
p
;
p
=
(
unsigned
char
*
)
PyString_AS_STRING
(
co
->
co_lnotab
);
size
=
PyString_GET_SIZE
(
co
->
co_lnotab
)
/
2
;
addr
=
0
;
line
=
co
->
co_firstlineno
;
assert
(
line
>
0
);
/* possible optimization: if f->f_lasti == instr_ub
(likely to be a common case) then we already know
instr_lb -- if we stored the matching value of p
somwhere we could skip the first while loop. */
/* see comments in compile.c for the description of
co_lnotab. A point to remember: increments to p
should come in pairs -- although we don't care about
the line increments here, treating them as byte
increments gets confusing, to say the least. */
while
(
size
>
0
)
{
if
(
addr
+
*
p
>
lasti
)
break
;
addr
+=
*
p
++
;
if
(
*
p
)
bounds
->
ap_lower
=
addr
;
line
+=
*
p
++
;
--
size
;
}
/* If lasti and addr don't match exactly, we don't want to
change the lineno slot on the frame or execute a trace
function. Return -1 instead.
*/
if
(
addr
!=
lasti
)
line
=
-
1
;
if
(
size
>
0
)
{
while
(
--
size
>=
0
)
{
addr
+=
*
p
++
;
if
(
*
p
++
)
break
;
}
bounds
->
ap_upper
=
addr
;
}
else
{
bounds
->
ap_upper
=
INT_MAX
;
}
return
line
;
}
Python/ceval.c
Dosyayı görüntüle @
a4ebc135
...
...
@@ -3219,132 +3219,29 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
PyFrameObject
*
frame
,
int
*
instr_lb
,
int
*
instr_ub
,
int
*
instr_prev
)
{
/* The theory of SET_LINENO-less tracing.
In a nutshell, we use the co_lnotab field of the code object
to tell when execution has moved onto a different line.
As mentioned above, the basic idea is so set things up so
that
*instr_lb <= frame->f_lasti < *instr_ub
is true so long as execution does not change lines.
This is all fairly simple. Digging the information out of
co_lnotab takes some work, but is conceptually clear.
Somewhat harder to explain is why we don't *always* call the
line trace function when the above test fails.
Consider this code:
1: def f(a):
2: if a:
3: print 1
4: else:
5: print 2
which compiles to this:
2 0 LOAD_FAST 0 (a)
3 JUMP_IF_FALSE 9 (to 15)
6 POP_TOP
3 7 LOAD_CONST 1 (1)
10 PRINT_ITEM
11 PRINT_NEWLINE
12 JUMP_FORWARD 6 (to 21)
>> 15 POP_TOP
5 16 LOAD_CONST 2 (2)
19 PRINT_ITEM
20 PRINT_NEWLINE
>> 21 LOAD_CONST 0 (None)
24 RETURN_VALUE
If 'a' is false, execution will jump to instruction at offset
15 and the co_lnotab will claim that execution has moved to
line 3. This is at best misleading. In this case we could
associate the POP_TOP with line 4, but that doesn't make
sense in all cases (I think).
What we do is only call the line trace function if the co_lnotab
indicates we have jumped to the *start* of a line, i.e. if the
current instruction offset matches the offset given for the
start of a line by the co_lnotab.
This also takes care of the situation where 'a' is true.
Execution will jump from instruction offset 12 to offset 21.
Then the co_lnotab would imply that execution has moved to line
5, which is again misleading.
Why do we set f_lineno when tracing? Well, consider the code
above when 'a' is true. If stepping through this with 'n' in
pdb, you would stop at line 1 with a "call" type event, then
line events on lines 2 and 3, then a "return" type event -- but
you would be shown line 5 during this event. This is a change
from the behaviour in 2.2 and before, and I've found it
confusing in practice. By setting and using f_lineno when
tracing, one can report a line number different from that
suggested by f_lasti on this one occasion where it's desirable.
*/
int
result
=
0
;
/* If the last instruction executed isn't in the current
instruction window, reset the window. If the last
instruction happens to fall at the start of a line or if it
represents a jump backwards, call the trace function.
*/
if
((
frame
->
f_lasti
<
*
instr_lb
||
frame
->
f_lasti
>=
*
instr_ub
))
{
PyCodeObject
*
co
=
frame
->
f_code
;
int
size
,
addr
,
line
;
unsigned
char
*
p
;
size
=
PyString_GET_SIZE
(
co
->
co_lnotab
)
/
2
;
p
=
(
unsigned
char
*
)
PyString_AS_STRING
(
co
->
co_lnotab
);
addr
=
0
;
line
=
co
->
co_firstlineno
;
/* possible optimization: if f->f_lasti == instr_ub
(likely to be a common case) then we already know
instr_lb -- if we stored the matching value of p
somwhere we could skip the first while loop. */
/* see comments in compile.c for the description of
co_lnotab. A point to remember: increments to p
should come in pairs -- although we don't care about
the line increments here, treating them as byte
increments gets confusing, to say the least. */
while
(
size
>
0
)
{
if
(
addr
+
*
p
>
frame
->
f_lasti
)
break
;
addr
+=
*
p
++
;
if
(
*
p
)
*
instr_lb
=
addr
;
line
+=
*
p
++
;
--
size
;
}
int
line
;
PyAddrPair
bounds
;
if
(
addr
==
frame
->
f_lasti
)
{
line
=
PyCode_CheckLineNumber
(
frame
->
f_code
,
frame
->
f_lasti
,
&
bounds
);
if
(
line
>=
0
)
{
frame
->
f_lineno
=
line
;
result
=
call_trace
(
func
,
obj
,
frame
,
PyTrace_LINE
,
Py_None
);
}
if
(
size
>
0
)
{
while
(
--
size
>=
0
)
{
addr
+=
*
p
++
;
if
(
*
p
++
)
break
;
}
*
instr_ub
=
addr
;
}
else
{
*
instr_ub
=
INT_MAX
;
}
}
*
instr_lb
=
bounds
.
ap_lower
;
*
instr_ub
=
bounds
.
ap_upper
;
}
else
if
(
frame
->
f_lasti
<=
*
instr_prev
)
{
/* jumping back in the same line forces a trace event */
result
=
call_trace
(
func
,
obj
,
frame
,
PyTrace_LINE
,
Py_None
);
result
=
call_trace
(
func
,
obj
,
frame
,
PyTrace_LINE
,
Py_None
);
}
*
instr_prev
=
frame
->
f_lasti
;
return
result
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment