25. Tạo mã byte
25. Tạo mã byte
Tạo bytecode là giai đoạn CPython chuyển đổi cú pháp có cấu trúc thành các hướng dẫn máy ảo có thể thực thi được.
Trình phân tích cú pháp xây dựng AST.
Bảng ký hiệu xác định hành vi phạm vi.
Sau đó, trình biên dịch sẽ đưa ra các hướng dẫn mã byte triển khai ngữ nghĩa Python.
Đối với nguồn này:python id="bjlwm8" def add(a, b): return a + b CPython tạo mã byte có hình dạng như sau:text id="plhxq4" LOAD_FAST a LOAD_FAST b BINARY_OP + RETURN_VALUE Tên và định dạng lệnh chính xác khác nhau giữa các phiên bản Python, nhưng mô hình vẫn ổn định:```text id="ecx81v"
bytecode is a low-level instruction stream
executed by the CPython virtual machine
Việc tạo mã byte xảy ra sau khi xây dựng AST và phân tích phạm vi.```text id="5v2o9v"
source
↓
tokenization
↓
parsing
↓
AST
↓
symbol table
↓
bytecode generation
↓
code object
↓
evaluation loop
```Trình biên dịch thực hiện AST và đưa ra các hướng dẫn cùng với siêu dữ liệu.
Đầu ra trở thành một phần của đối tượng mã.
## 25.2 Mã byte đại diện cho điều gì
Bytecode là tập lệnh ảo cho CPython.
Nó không phải là mã máy.
Nó không phải là mã nguồn.
Nó là ngôn ngữ thực thi trung gian được thiết kế cho trình thông dịch CPython.
Nguồn ví dụ:```python id="mwhlwe"
x = 1 + 2
```Mã byte có thể có:```text id="cv4c36"
LOAD_CONST 3
STORE_NAME x
LOAD_CONST None
RETURN_VALUE
```Trình thông dịch sau đó sẽ thực hiện từng lệnh một.
Công việc của trình biên dịch là:```text id="wlk7tq"
preserve Python semantics
emit correct stack behavior
emit correct control flow
emit correct scope access
record source metadata
```## 25.3 Mã byte dựa trên ngăn xếp
Mã byte CPython sử dụng máy xếp chồng.
Hầu hết các hướng dẫn đẩy hoặc bật các giá trị từ ngăn xếp đánh giá.
Ví dụ:```python id="qggm8k"
a + b
```Biên soạn:```text id="jlwm0j"
LOAD_FAST a
LOAD_FAST b
BINARY_OP +
```Sự phát triển của ngăn xếp:```text id="4tq4zg"
LOAD_FAST a
stack: a
LOAD_FAST b
stack: a, b
BINARY_OP +
pop a and b
push result
stack: result
```Trình biên dịch phải giữ hiệu ứng ngăn xếp nhất quán.
Mọi đường dẫn mã byte phải duy trì trạng thái ngăn xếp hợp lệ.
## 25.4 Biên dịch biểu thức
Biểu thức tạo ra giá trị.
Ví dụ:```python id="nl8bg0"
x + y * z
```AST duy trì quyền ưu tiên:```text id="0u6c93"
x + (y * z)
```Việc tạo mã byte tuân theo cấu trúc đó.
Mã byte khái niệm:```text id="jlwm0m"
LOAD_FAST x
LOAD_FAST y
LOAD_FAST z
BINARY_OP *
BINARY_OP +
```Sự phát triển của ngăn xếp:```text id="f2zv3g"
x
x, y
x, y, z
x, temp
result
```Trình biên dịch biên dịch đệ quy các biểu thức con.
## 25.5 Biên soạn câu lệnh
Các câu lệnh thường phát ra các hướng dẫn về tác dụng phụ.
Ví dụ:```python id="rj0nwu"
x = value
```Biên soạn:```text id="zyulq0"
compile expression value
store into target x
```Mã byte có thể có:```text id="jlwm0n"
LOAD_FAST value
STORE_FAST x
```Ví dụ:```python id="9hq2o6"
return x
```Biên soạn:```text id="jlwm0o"
LOAD_FAST x
RETURN_VALUE
```Trình biên dịch phân biệt giữa:```text id="n0c2jr"
expressions producing values
statements performing actions
```## 25.6 Đang tải hằng số
Các hằng số được tải từ`co_consts`.
Ví dụ:```python id="s7hy3e"
x = 123
```Mã byte:```text id="jlwm0p"
LOAD_CONST 123
STORE_NAME x
```Trình biên dịch chèn hằng số vào`co_consts`và phát ra một tham chiếu chỉ mục.
Về mặt khái niệm:```text id="j49sul"
co_consts:
0: 123
instruction:
LOAD_CONST 0
```Trình thông dịch giải quyết chỉ mục trong khi thực thi.
## 25.7 Đang tải người dân địa phương
Người dân địa phương nhanh chóng sử dụng các vị trí được lập chỉ mục.
Ví dụ:```python id="bhz0x7"
def f(a, b):
return a + b
```Mã byte:```text id="jlwm0q"
LOAD_FAST a
LOAD_FAST b
BINARY_OP +
RETURN_VALUE
```Trình biên dịch sử dụng`LOAD_FAST`bởi vì phân tích biểu tượng đã được phân loại`a`Và`b`dưới dạng các biến cục bộ.
Người dân địa phương nhanh chóng tránh tra cứu từ điển.
## 25.8 Đang tải quả cầu
Tra cứu toàn cục và tích hợp sử dụng các hướng dẫn khác nhau.
Ví dụ:```python id="y3afqz"
x = 10
def f():
return x
```Bên trong`f`:
```text id="jlwm0r"
LOAD_GLOBAL x
RETURN_VALUE
```Trình thông dịch kiểm tra:```text id="l1ajyz"
function globals
then builtins
```Trình biên dịch chọn`LOAD_GLOBAL`dựa trên thông tin bảng ký hiệu.
## 25.9 Đang tải các biến đóng
Các biến đóng sử dụng các hoạt động quy định.
Ví dụ:```python id="cv9ngd"
def outer():
x = 1
def inner():
return x
```Bên trong`inner`:
```text id="jlwm0s"
LOAD_DEREF x
RETURN_VALUE
```Trình biên dịch phát ra mã byte không tham chiếu vì`x`là một biến miễn phí được ghi lại từ một phạm vi kèm theo.
Mã byte đóng truy cập vào các đối tượng ô thay vì các vị trí cục bộ thông thường.
## 25.10 Mục tiêu nhiệm vụ
Mục tiêu bài tập được biên dịch khác với các biểu thức thông thường.
Ví dụ:```python id="mav3fq"
x = 1
```Mã byte:```text id="jlwm0t"
LOAD_CONST 1
STORE_NAME x
```Nhưng việc gán thuộc tính:```python id="y7g47q"
obj.value = 1
```Hình dạng mã byte:```text id="jlwm0u"
LOAD_FAST obj
LOAD_CONST 1
STORE_ATTR value
```Bài tập chỉ số dưới:```python id="oxtk8t"
items[i] = value
```Hình dạng mã byte:```text id="jlwm0v"
LOAD_FAST items
LOAD_FAST i
LOAD_FAST value
STORE_SUBSCR
```Biên dịch mục tiêu phụ thuộc vào bối cảnh AST.
## 25.11 Xóa
Việc xóa sử dụng các hướng dẫn chuyên dụng.
Ví dụ:```python id="d8j5gc"
del x
```Mã byte có thể có:```text id="jlwm0w"
DELETE_FAST x
```Ví dụ:```python id="b4d5gn"
del obj.attr
```Mã byte có thể có:```text id="jlwm0x"
LOAD_FAST obj
DELETE_ATTR attr
```Việc xóa không phải là gán cho`None`. Nó loại bỏ các ràng buộc hoặc mục nhập đối tượng theo loại mục tiêu.
## 25.12 Lệnh gọi hàm
Các cuộc gọi hàm tạo ra nhiều hướng dẫn.
Ví dụ:```python id="a3j0ut"
f(x, y)
```Mã byte khái niệm:```text id="jlwm0y"
LOAD_NAME f
LOAD_FAST x
LOAD_FAST y
CALL 2
POP_TOP
```Trình biên dịch phải:```text id="e8qjkl"
compile callable expression
compile positional arguments
compile keyword arguments
emit call instruction
handle stack layout
```Các cuộc gọi phương thức có thể sử dụng các dạng mã byte chuyên dụng.
Ví dụ:```python id="s4m8cq"
obj.run()
```Hình dạng có thể:```text id="jlwm0z"
LOAD_FAST obj
LOAD_METHOD run
CALL 0
```Các phiên bản CPython hiện đại chứa chuyên môn hóa bổ sung và hành vi bộ nhớ đệm nội tuyến xung quanh các cuộc gọi.
## 25.13 Hoạt động nhị phân
Các phép toán số học và nhị phân phát ra hướng dẫn thao tác.
Ví dụ:```python id="gt4c4x"
a + b
```Mã byte:```text id="jlwm10"
LOAD_FAST a
LOAD_FAST b
BINARY_OP +
```Các ví dụ khác:
| Biểu hiện | Hoạt động |
| ---------- | --------------- |
|`a - b`| phép trừ |
|`a * b`| phép nhân |
|`a / b`| phép chia |
|`a // b`| chia tầng |
|`a % b`| modulo |
|`a ** b`| quyền lực |
|`a @ b`| ma trận nhân |
|`a << b`| dịch chuyển trái |
|`a & b`| theo chiều bit và |
Trình biên dịch đưa ra hướng dẫn vận hành. Việc gửi loại thời gian chạy xảy ra sau đó.
Ví dụ:```python id="x8vwdk"
1 + 2
"a" + "b"
```Cả hai đều biên dịch tương tự nhau, nhưng hành vi của đối tượng thời gian chạy khác nhau.
## 25.14 So sánh
So sánh phát ra các hoạt động so sánh.
Ví dụ:```python id="e98twa"
a < b
```Mã byte có thể có:```text id="jlwm11"
LOAD_FAST a
LOAD_FAST b
COMPARE_OP <
```So sánh theo chuỗi yêu cầu luồng điều khiển phức tạp hơn.
Ví dụ:```python id="pxo93r"
a < b < c
```Điều này phải đánh giá`b`một lần.
Biên soạn khái niệm:```text id="jlwm12"
LOAD_FAST a
LOAD_FAST b
COMPARE_OP <
conditional jump if false
LOAD_FAST b
LOAD_FAST c
COMPARE_OP <
```Trình biên dịch duy trì ngữ nghĩa so sánh theo chuỗi của Python.
## 25.15 Phép toán Boolean
Hoạt động Boolean ngắn mạch.
Ví dụ:```python id="dd8v9m"
a and b
```Mẫu biên dịch:```text id="jlwm13"
evaluate a
jump if false
evaluate b
bchỉ thực hiện nếu cần thiết.
Tương tự:python id="a3pgh7" a or b đánh giábchỉ nếualà sai.
Hành vi đoản mạch được thực hiện thông qua các bước nhảy chứ không phải các lệnh gọi hàm thông thường.
25.16 Biểu thức điều kiện
Ví dụ:python id="r74d92" x if cond else y Mẫu biên dịch:```text id="jlwm14"
evaluate cond
jump to else branch if false
evaluate x
jump to end
evaluate y
## 25,17`if`Báo cáo
Ví dụ:```python id="q70zfx"
if cond:
a()
else:
b()
```Mẫu biên dịch:```text id="jlwm15"
compile condition
jump to else if false
compile a()
jump to end
compile b()
end
```Hình dạng mã byte có thể có:```text id="jlwm16"
LOAD_NAME cond
POP_JUMP_IF_FALSE else_label
LOAD_NAME a
CALL
POP_TOP
JUMP_FORWARD end_label
else_label:
LOAD_NAME b
CALL
POP_TOP
end_label:
```Trình biên dịch quản lý nhãn và mục tiêu nhảy nội bộ trước khi lắp ráp cuối cùng.
## 25,18`while`Vòng lặp
Ví dụ:```python id="0wdg4v"
while cond:
work()
```Mẫu biên dịch:```text id="jlwm17"
loop_start:
evaluate cond
jump to end if false
compile body
jump to loop_start
loop_end:
```Các vòng lặp yêu cầu theo dõi ngăn xếp khối cho:```text id="jlwm18"
break
continue
exception cleanup
```## 25,19`for`Vòng lặp
Ví dụ:```python id="uk10dk"
for item in items:
work(item)
```Mẫu biên dịch:```text id="jlwm19"
load iterable
get iterator
loop_start:
get next item
jump to end on StopIteration
store item
compile body
jump to loop_start
loop_end:
```Trình biên dịch phát ra mã byte giao thức iterator.
một con trăn`for`vòng lặp được điều khiển bằng trình lặp chứ không phải điều khiển theo chỉ mục.
## 25,20`break`Và`continue`Ví dụ:```python id="h5f6ov"
while True:
if stop:
break
continue
breaknhảy để thoát khỏi vòng lặp.continuenhảy tới điểm tiếp tục vòng lặp.
Trình biên dịch duy trì cấu trúc bối cảnh vòng lặp để các vòng lặp lồng nhau hoạt động chính xác.
Ví dụ:python id="r7bz0d" for x in xs: for y in ys: break Bên trongbreakchỉ thoát khỏi vòng lặp bên trong.
25.21 Xử lý ngoại lệ
Xử lý ngoại lệ yêu cầu siêu dữ liệu luồng điều khiển có cấu trúc.
Ví dụ:python id="12cm6v" try: risky() except ValueError: recover() finally: cleanup() Trách nhiệm biên soạn:```text id="jlwm1a"
protected instruction ranges
exception handler targets
finally cleanup
reraising behavior
stack restoration
Trình biên dịch ghi lại:```text id="jlwm1b"
instruction range
handler entry
handler type
stack depth information
```Siêu dữ liệu này cho phép trình thông dịch chuyển sang trình xử lý một cách chính xác khi xảy ra ngoại lệ.
## 25,22`with`Báo cáo
Ví dụ:```python id="wq6o7z"
with open(path) as f:
data = f.read()
```Mẫu biên dịch:```text id="jlwm1c"
evaluate context manager
call __enter__
store result
execute body
ensure __exit__ runs
handle exceptions correctly
```Trình biên dịch phát ra logic dọn dẹp đảm bảo`__exit__`thực thi ngay cả khi có ngoại lệ xảy ra.`with`quá trình biên dịch được kết nối chặt chẽ với máy xử lý ngoại lệ.
## 25.23 Định nghĩa hàm
Các định nghĩa hàm biên dịch theo hai giai đoạn.
Ví dụ:```python id="8k2d07"
def f(x):
return x + 1
```Giai đoạn 1:```text id="jlwm1d"
compile function body into nested code object
```Giai đoạn 2:```text id="jlwm1e"
emit runtime instructions creating function object
```Mã byte khái niệm:```text id="jlwm1f"
LOAD_CONST <code object f>
MAKE_FUNCTION
STORE_NAME f
```Bản thân phần thân sẽ trở thành mã byte bên trong đối tượng mã lồng nhau.
## 25,24 Đóng cửa
Ví dụ:```python id="b4pshk"
def outer():
x = 1
def inner():
return x
```Trách nhiệm biên soạn:```text id="jlwm1g"
create closure cell for x
compile inner with free variable access
pass closure tuple during function creation
```Hình dạng mã byte có thể có bên trong`outer`:
```text id="jlwm1h"
MAKE_CELL x
LOAD_CONST 1
STORE_DEREF x
LOAD_CLOSURE x
BUILD_TUPLE 1
LOAD_CONST <code object inner>
MAKE_FUNCTION closure
```Bên trong`inner`:
```text id="jlwm1i"
LOAD_DEREF x
RETURN_VALUE
```## 25.25 Định nghĩa lớp
Ví dụ:```python id="1br4s3"
class C:
x = 1
```Nội dung lớp trở thành một đối tượng mã lồng nhau.
Mẫu biên dịch:```text id="jlwm1j"
compile class body code object
emit runtime class construction logic
bind resulting class object
```Thân lớp thực thi giống như các mô-đun nhỏ với không gian tên riêng.
Các phương thức trở thành các định nghĩa hàm lồng nhau bên trong đối tượng mã nội dung lớp.
## 25.26 Hiểu biết
Sự hiểu biết được biên dịch thành các phạm vi lồng nhau.
Ví dụ:```python id="9w8n9x"
[x * x for x in xs]
```Trách nhiệm biên soạn:```text id="jlwm1k"
create nested comprehension code object
iterate input iterable
bind local iteration variable
append results
return constructed container
```Các biến hiểu không bị rò rỉ ra phạm vi bên ngoài vì trình biên dịch tạo ra bộ máy phạm vi thực thi riêng biệt.
## 25.27 Máy phát điện
Chức năng của máy phát điện sử dụng điểm treo.
Ví dụ:```python id="i8gtwx"
def gen():
yield 1
yield 2
```Trách nhiệm biên soạn:```text id="jlwm1l"
mark code object as generator
emit yield instructions
preserve resumable execution state
```Hình dạng mã byte có thể có:```text id="jlwm1m"
LOAD_CONST 1
YIELD_VALUE
LOAD_CONST 2
YIELD_VALUE
LOAD_CONST None
RETURN_VALUE
```Khung phải bảo toàn trạng thái trong suốt hệ thống treo.
## 25.28 Coroutine và`await`Ví dụ:```python id="oqf8so"
async def fetch():
return await client.get()
```Trách nhiệm biên soạn:```text id="jlwm1n"
mark coroutine flags
emit await handling
preserve suspension semantics
```Trình biên dịch tạo mã byte cho hành vi lập lịch coroutine thay vì các lệnh gọi đồng bộ thông thường.
## 25,29 Nhập khẩu
Ví dụ:```python id="3k7d9u"
import os
```Mẫu biên dịch:```text id="jlwm1o"
IMPORT_NAME os
STORE_NAME os
```Ví dụ:```python id="38ef9k"
from math import sin
```Mẫu biên dịch:```text id="jlwm1p"
IMPORT_NAME math
IMPORT_FROM sin
STORE_NAME sin
```Trình biên dịch phát ra các hoạt động nhập. Quá trình tải mô-đun thực tế diễn ra trong thời gian chạy.
## 25:30 Khẳng định
Ví dụ:```python id="g2m5qn"
assert x > 0
```Mẫu biên dịch:```text id="jlwm1q"
evaluate condition
jump if true
raise AssertionError
```Trong chế độ tối ưu hóa (`python -O`), các câu lệnh khẳng định có thể được bỏ qua hoàn toàn.
Đây là một sự chuyển đổi cấp độ trình biên dịch.
## 25.31 Vị trí nguồn và Bảng dòng
Trình biên dịch ghi lại ánh xạ giữa mã byte và vị trí nguồn.
Các ánh xạ này hỗ trợ:```text id="jlwm1r"
tracebacks
debuggers
profilers
coverage tools
stepping
error reporting
```Mỗi phạm vi hướng dẫn có thể tương ứng với:```text id="jlwm1s"
line number
column offset
end line
end column
```Đối tượng mã lưu trữ các bảng ánh xạ nén.
## 25,32 Tính toán kích thước ngăn xếp
Trình biên dịch tính toán độ sâu ngăn xếp tối đa.
Ví dụ:```python id="7qdzg3"
a + b * c
```Có thể phát triển ngăn xếp:```text id="jlwm1t"
a
a, b
a, b, c
a, temp
result
```Độ sâu tối đa: 3.
Điều này trở thành`co_stacksize`.
Các khung phân bổ đủ không gian ngăn xếp dựa trên giá trị này.
## 25.33 Khối cơ bản
Trong nội bộ, trình biên dịch thường nhóm các lệnh thành các khối cơ bản.
Một khối cơ bản là một chuỗi các hướng dẫn với:```text id="jlwm1u"
single entry
single exit
no internal jumps
```Ví dụ:```python id="w2g2q7"
if cond:
a()
b()
```Cấu trúc khối có thể:```text id="jlwm1v"
block 1:
evaluate cond
conditional jump
block 2:
a()
jump
block 3:
b()
```Các khối cơ bản đơn giản hóa việc phân tích luồng điều khiển và độ phân giải bước nhảy.
## 25,34 Độ phân giải nhảy
Trình biên dịch ban đầu phát ra các nhãn tượng trưng.
Việc lắp ráp sau này sẽ giải quyết các sai lệch lệnh thực tế.
Quá trình khái niệm:```text id="jlwm1w"
emit instructions
emit labels
calculate instruction offsets
replace labels with offsets
insert extended arguments if needed
recalculate offsets if sizes changed
```Độ phân giải bước nhảy là một lý do khiến quá trình biên dịch có nhiều giai đoạn.
## 25.35 Bộ nhớ đệm nội tuyến và Hỗ trợ chuyên môn
Mã byte CPython hiện đại hỗ trợ chuyên môn hóa thích ứng.
Trình biên dịch có thể phát ra các mục trong bộ đệm liên quan đến hướng dẫn.
Các hoạt động ví dụ được hưởng lợi từ chuyên môn hóa:```text id="jlwm1x"
attribute access
global lookup
binary operations
calls
method dispatch
```Mã byte ban đầu là chung chung.
Chuyên môn hóa thời gian chạy sau này có thể thay thế hành vi bằng các đường dẫn nhanh được tối ưu hóa.
Trình biên dịch chuẩn bị các bố cục hướng dẫn cho phép điều chỉnh này.
## 25.36 Kiểm tra mã byte
sử dụng`dis`để kiểm tra mã byte được tạo.
Ví dụ:```python id="jlwm1y"
import dis
def f(a, b):
return a + b
dis.dis(f)
```Các chức năng kiểm tra hữu ích bao gồm:```text id="jlwm1z"
dis.dis
dis.Bytecode
dis.get_instructions
```Kiểm tra mã byte là cần thiết cho:```text id="jlwm20"
compiler debugging
performance analysis
tooling
education
reverse engineering Python behavior
```## 25.37 Độ nhạy của phiên bản
Thay đổi mã byte giữa các phiên bản CPython.
Những thay đổi có thể bao gồm:```text id="jlwm21"
new opcodes
removed opcodes
opcode renaming
instruction format changes
specialization changes
exception handling changes
line table changes
```Các công cụ nên tránh phụ thuộc vào bố cục mã byte chính xác trên các phiên bản trừ khi có hỗ trợ dành riêng cho phiên bản.
Sử dụng API công khai thay vì phân tích mã byte thô theo cách thủ công bất cứ khi nào có thể.
## 25.38 Vùng nguồn CPython quan trọng
Các tập tin quan trọng bao gồm:```text id="jlwm22"
Python/compile.c
Python/flowgraph.c
Python/assemble.c
Python/bytecodes.c
Include/opcode_ids.h
Lib/dis.py
Lib/opcode.py
```Vai trò khái niệm:
| Khu vực | Vai trò |
| ------------- | -------------------------------------- |
|`compile.c`| Truyền tải AST và phát lệnh hướng dẫn |
|`flowgraph.c`| Xử lý biểu đồ luồng điều khiển |
|`assemble.c`| Lắp ráp mã byte và độ phân giải nhảy |
|`bytecodes.c`| Định nghĩa Opcode |
|`opcode.py`| Siêu dữ liệu Opcode |
|`dis.py`| Kiểm tra mã byte |
## 25,39 Mô hình tinh thần tối thiểu
Sử dụng mô hình này:```text id="jlwm23"
The compiler walks the AST.
Expressions emit stack-based instructions.
Statements emit side-effect and control-flow instructions.
Constants, names, and locals become indexed table references.
Control flow becomes jumps and exception metadata.
Functions, classes, comprehensions, and generators create nested code objects.
The final instruction stream becomes part of a code object executed by the CPython virtual machine.
```Việc tạo mã byte là giai đoạn trong đó cú pháp Python trở thành các hoạt động thực thi của máy ảo.