FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
RustPython/tools/opcode_metadata/opcodes.py at main · RustPython/RustPython · GitHub
RustPython
RustPython
Repository navigation
Code
Issues
185
(185)
Pull requests
112
(112)
Discussions
Actions
Projects
Wiki
Security and quality
Insights
Expand file tree
Breadcrumbs
RustPython
/
tools
/
opcode_metadata
/
opcodes.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
186 lines (142 loc) · 5.81 KB
Breadcrumbs
RustPython
/
tools
/
opcode_metadata
/
opcodes.py
Copy path
File metadata and controls
186 lines (142 loc) · 5.81 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
from
__future__
import
annotations
import
collections
import
dataclasses
import
re
import
typing
import
warnings
import
utils
from
cpython
import
SKIP_PROPERTIES
,
Family
,
Properties
,
get_analysis
,
get_stack_effect
from
utils
import
SKIP_OVERRIDE
,
Override
,
OverrideConfs
,
StackEffect
,
to_pascal_case
if
typing
.
TYPE_CHECKING
:
from
collections
.
abc
import
Iterable
@
dataclasses
.
dataclass
(
frozen
=
True
,
slots
=
True
)
class
OpcodeInfo
:
enum_name
:
str
size
:
str
opcodes
:
tuple
[
Opcode
, ...]
@
property
def
deopts
(
self
)
->
dict
[
str
,
list
[
str
]]:
analysis
=
get_analysis
()
names
=
{
opcode
.
rust_name
for
opcode
in
self
}
res
=
collections
.
defaultdict
(
list
)
for
family
in
analysis
.
families
.
values
():
family_name
=
to_pascal_case
(
family
.
name
)
if
family_name
not
in
names
:
continue
for
member
in
family
.
members
:
member_name
=
to_pascal_case
(
member
.
name
)
if
member
.
name
==
family_name
:
continue
res
[
family_name
].
append
(
member_name
)
return
dict
(
res
)
def
__iter__
(
self
):
yield
from
self
.
opcodes
@
classmethod
def
iter_infos
(
cls
,
text
:
str
,
override_confs
:
OverrideConfs
)
->
Iterable
[
typing
.
Self
]:
for
block_match
in
re
.
finditer
(
r"define_opcodes!\s*\((.+?)\);"
,
text
,
re
.
DOTALL
):
block
=
block_match
.
group
(
1
).
strip
()
size
=
re
.
search
(
r"#\[repr\((\w+)\)\]"
,
block
).
group
(
1
)
enum_name
=
re
.
search
(
r"#\[repr\(\w+\)\]\s*pub\s+enum\s+(\w+)\s*;"
,
block
).
group
(
1
)
second_enum_match
=
re
.
search
(
r"pub\s+enum\s+(\w+)\s*\{"
,
block
,
re
.
DOTALL
)
entries
=
utils
.
extract_enum_body
(
block
,
second_enum_match
.
end
()
-
1
)
opcodes
=
tuple
(
sorted
(
iter_opcodes
(
entries
,
override_confs
)))
yield
cls
(
enum_name
,
size
,
opcodes
)
def
iter_opcodes
(
text
:
str
,
override_confs
:
OverrideConfs
)
->
Iterable
[
Opcode
]:
analysis
=
get_analysis
()
# Split on commas that are followed by a newline + an uppercase letter (new entry)
entries
=
map
(
str
.
strip
,
re
.
split
(
r",\s*\n\s*(?=[A-Z])"
,
text
))
for
entry
in
entries
:
if
not
entry
:
continue
opcode
=
Opcode
.
from_str
(
entry
)
rust_name
=
opcode
.
rust_name
override
=
override_confs
.
get
(
rust_name
,
SKIP_OVERRIDE
)
cpython_name
=
opcode
.
cpython_name
kwargs
=
{}
if
instr
:=
analysis
.
instructions
.
get
(
cpython_name
):
kwargs
[
"properties"
]
=
properties_with_pseudo_flags
(
instr
)
kwargs
[
"family"
]
=
getattr
(
instr
,
"family"
,
None
)
kwargs
[
"cache_entry"
]
=
getattr
(
instr
,
"size"
,
-
1
)
stack
=
get_stack_effect
(
instr
)
popped
=
(
-
stack
.
base_offset
).
to_c
()
pushed
=
(
stack
.
logical_sp
-
stack
.
base_offset
).
to_c
()
kwargs
[
"stack_effect"
]
=
StackEffect
(
popped
=
popped
,
pushed
=
pushed
)
elif
override
==
SKIP_OVERRIDE
:
warnings
.
warn
(
f"Could not get instruction metadata for
{
rust_name
}
"
" from CPython or override conf"
)
yield
dataclasses
.
replace
(
opcode
,
override
=
override
,
**
kwargs
)
# opcode_metadata_generator.py generate_metadata_table: cflags(pseudo.properties)
# plus each explicit flag from the pseudo() definition.
_PSEUDO_FLAG_ATTRS
=
{
"HAS_ARG"
:
"oparg"
,
"HAS_CONST"
:
"uses_co_consts"
,
"HAS_NAME"
:
"uses_co_names"
,
"HAS_JUMP"
:
"jumps"
,
"HAS_FREE"
:
"has_free"
,
"HAS_LOCAL"
:
"uses_locals"
,
"HAS_EVAL_BREAK"
:
"eval_breaker"
,
"HAS_DEOPT"
:
"deopts"
,
"HAS_EXIT"
:
"side_exit"
,
"HAS_PURE"
:
"pure"
,
}
def
properties_with_pseudo_flags
(
instr
):
props
=
instr
.
properties
flags
=
getattr
(
instr
,
"flags"
,
None
)
if
not
flags
:
return
props
updates
=
{
attr
:
True
for
flag
in
flags
if
(
attr
:=
_PSEUDO_FLAG_ATTRS
.
get
(
flag
))}
if
not
updates
:
return
props
return
dataclasses
.
replace
(
props
,
**
updates
)
@
dataclasses
.
dataclass
(
frozen
=
True
,
slots
=
True
)
class
Opcode
:
rust_name
:
str
id
:
int
have_argument
:
bool
=
False
cache_entry
:
int
=
0
stack_effect
:
StackEffect
|
None
=
None
properties
:
Properties
=
dataclasses
.
field
(
default_factory
=
lambda
:
SKIP_PROPERTIES
)
family
:
Family
|
None
=
None
override
:
Override
=
dataclasses
.
field
(
default_factory
=
Override
)
@
property
def
is_instrumented
(
self
)
->
bool
:
if
(
res
:=
self
.
override
.
is_instrumented
)
is
not
None
:
return
res
return
self
.
cpython_name
.
startswith
(
"INSTRUMENTED_"
)
@
property
def
cpython_name
(
self
):
return
utils
.
to_upper_snake_case
(
self
.
rust_name
)
@
property
def
cpy_popped
(
self
)
->
str
|
None
:
return
getattr
(
self
.
stack_effect
,
"popped"
,
None
)
@
property
def
cpy_pushed
(
self
)
->
str
|
None
:
return
getattr
(
self
.
stack_effect
,
"pushed"
,
None
)
@
property
def
stack_effect_popped
(
self
)
->
str
:
ove_popped
=
self
.
override
.
stack_effect
.
popped
if
(
ove_popped
is
None
)
and
(
self
.
cpy_popped
is
None
):
raise
ValueError
(
f"
{
self
.
rust_name
}
is missing popped stack_effect"
)
return
ove_popped
or
self
.
cpy_popped
@
property
def
stack_effect_pushed
(
self
)
->
str
:
ove_pushed
=
self
.
override
.
stack_effect
.
pushed
if
(
ove_pushed
is
None
)
and
(
self
.
cpy_pushed
is
None
):
raise
ValueError
(
f"
{
self
.
rust_name
}
is missing pushed stack_effect"
)
return
ove_pushed
or
self
.
cpy_pushed
@
classmethod
def
from_str
(
cls
,
entry
:
str
)
->
typing
.
Self
:
rust_name
=
re
.
match
(
r"(\w+)"
,
entry
).
group
(
1
)
id_num
=
re
.
findall
(
r"= (\d+)"
,
entry
)[
0
]
have_argument
=
"Arg<"
in
entry
return
cls
(
rust_name
,
int
(
id_num
),
have_argument
=
have_argument
)
def
__lt__
(
self
,
other
:
typing
.
Self
)
->
bool
:
return
self
.
id
<
other
.
id
Back
|
FazBrowse Home
|
New Git URL