Tạo cây cú pháp trừu tượng [AST] cho nguồn Python có hai giai đoạn. Cái đầu tiên tạo một cây cú pháp đơn giản [SST] và một cây phạm vi. Giai đoạn thứ hai chuyển đổi SST thành cây khung Triển khai Ngôn ngữ Truffle
Đối với việc chuyển đổi, cây phạm vi nó cần. Cây phạm vi chứa các vị trí phạm vi cho các định nghĩa hàm và biến cũng như thông tin về phạm vi. Cây cú pháp đơn giản chứa các nút phản ánh nguồn. So sánh SST và cây khung triển khai ngôn ngữ, SST nhỏ hơn nhiều. Nó chỉ chứa các nút đại diện cho nguồn theo cách đơn giản. Một nút SST thường được dịch sang nhiều nút Khung triển khai ngôn ngữ
Cây cú pháp đơn giản có thể được tạo theo hai cách. với phân tích cú pháp ANTLR hoặc giải tuần tự hóa từ tệp *.pyc
thích hợp. Nếu không có tệp .pyc
thích hợp cho một nguồn, thì nguồn đó sẽ được phân tích cú pháp bằng ANTLR. Nếu logic nhập tiêu chuẩn của Python tìm thấy một tệp .pyc
thích hợp, thì nó sẽ chỉ kích hoạt quá trình giải tuần tự hóa SST và cây phạm vi từ nó
Quá trình khử lưu huỳnh nhanh hơn nhiều so với phân tích cú pháp nguồn bằng ANTLR và chỉ cần khoảng 30% thời gian mà ANTLR cần. Tất nhiên, lần nhập tệp mới đầu tiên chậm hơn một chút – bên cạnh việc phân tích cú pháp bằng ANTLR, logic nhập thư viện chuẩn Python tuần tự hóa đối tượng mã kết quả thành tệp .pyc
, trong trường hợp của chúng tôi có nghĩa là SST và cây phạm vi được đánh số thứ tự như vậy
Tạo và quản lý tệp pyc
Các tệp .pyc
được tạo tự động bởi thời gian chạy GraalVM Python khi không tìm thấy hoặc tìm thấy tệp .pyc
không hợp lệ khớp với tệp MAGIC_NUMBER
source text
binary data - scope tree
binary data - simple syntax tree
4 mong muốn
MAGIC_NUMBER
source text
binary data - scope tree
binary data - simple syntax tree
Khi tệp nguồn Python [mô-đun] được nhập lần đầu tiên trong quá trình thực thi, tệp .pyc
thích hợp sẽ được tạo tự động. Nếu cùng một mô-đun được nhập lại, thì tệp .pyc
đã tạo sẽ được sử dụng. Điều đó có nghĩa là không có tệp .pyc
nào cho tệp nguồn chưa được thực thi [nhập]. Việc tạo các tệp .pyc
được thực hiện hoàn toàn thông qua API Hệ thống tệp để người nhúng có thể quản lý quyền truy cập hệ thống tệp
Mỗi lần thực hiện tiếp theo của tập lệnh sẽ sử dụng lại các tệp .pyc
hiện có hoặc sẽ tạo một tệp mới. Tệp .pyc
được tạo lại nếu dấu thời gian hoặc mã băm của tệp nguồn ban đầu bị thay đổi. Mã băm chỉ được tạo dựa trên nguồn Python bằng cách gọi
MAGIC_NUMBER
source text
binary data - scope tree
binary data - simple syntax tree
8, là mã băm JDK trên mảng byte tệp nguồn, được tính bằng MAGIC_NUMBER
source text
binary data - scope tree
binary data - simple syntax tree
9Các tệp .pyc
cũng được tạo lại nếu một số ma thuật trong trình phân tích cú pháp Python bị thay đổi. Số ma thuật được mã hóa cứng trong nguồn Python và người dùng không thể thay đổi [tất nhiên trừ khi người dùng đó có quyền truy cập vào mã byte của Python]
Các nhà phát triển thời gian chạy Python của GraalVM thay đổi số ma thuật khi định dạng của SST hoặc dữ liệu nhị phân cây phạm vi bị thay đổi. Đây là một chi tiết triển khai, do đó, số ma thuật không nhất thiết phải tương ứng với phiên bản thời gian chạy Python của GraalVM [giống như trong CPython]. Số ma thuật của pyc là một chức năng của mã Java thời gian chạy Python cụ thể đang chạy
Lưu ý rằng nếu bạn sử dụng tệp .pyc
, bạn sẽ cần cho phép ghi quyền truy cập vào thời gian chạy Python của GraalVM ít nhất khi chuyển đổi phiên bản hoặc thay đổi mã nguồn ban đầu. Nếu không, việc tạo lại các tệp nguồn sẽ không thành công và mỗi lần nhập sẽ có chi phí truy cập vào tệp .pyc
cũ, phân tích cú pháp mã, đánh số thứ tự và cố gắng [và không thành công] để ghi ra một tệp .pyc
mới
Tệp *.pyc
không bao giờ bị xóa bởi thời gian chạy Python của GraalVM, chỉ được tạo lại. Nó được tạo lại khi tệp nguồn thích hợp bị thay đổi [dấu thời gian của lần sửa đổi cuối cùng hoặc mã băm của nội dung] hoặc số ma thuật của trình phân tích cú pháp triển khai Python thay đổi. Các thay đổi về số ma thuật sẽ được thông báo trong ghi chú phát hành để người nhúng hoặc quản trị viên hệ thống có thể xóa các tệp .pyc
cũ khi nâng cấp
Cấu trúc thư mục được tạo cho các tệp .pyc
trông như thế này
top_folder
__pycache__
sourceA.graalpython.pyc
sourceB.graalpython.pyc
sourceA.py
sourceB.py
sub_folder
__pycache__
sourceX.graalpython.pyc
sourceX.py
Theo mặc định, thư mục
>>> def add[x, y]:
.. return x+y
...
>>> add.__code__.co_code
b'\x01\x00\x00\x02[]K\xbf\xd1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 ...'
7 được tạo ở cùng cấp thư mục với tệp mã nguồn và trong thư mục này, tất cả các tệp .pyc
từ cùng thư mục được lưu trữ. Thư mục này có thể lưu trữ .pyc
tệp được tạo bằng các phiên bản Python khác nhau [bao gồm, e. g. , CPython], vì vậy người dùng có thể thấy các tệp kết thúc bằng .pyc
0 chẳng hạnViệc triển khai hiện tại cũng bao gồm một bản sao của văn bản gốc trong tệp .pyc
. Đây là một tối ưu hóa hiệu suất nhỏ để bạn có thể tạo một đối tượng .pyc
2 với đường dẫn đến tệp nguồn ban đầu, nhưng bạn không cần phải đọc tệp .pyc
3 ban đầu, điều này giúp tăng tốc quá trình lấy cây khung Triển khai Ngôn ngữ [chỉ cần một tệp là . Cấu trúc của tệp .pyc
4 là thế này
MAGIC_NUMBER
source text
binary data - scope tree
binary data - simple syntax tree
Lưu ý rằng các tệp .pyc
không phải là phương tiện hiệu quả để ẩn mã nguồn thư viện Python khỏi mã khách, vì nguồn ban đầu vẫn có thể được khôi phục. Ngay cả khi nguồn bị bỏ qua, cây cú pháp vẫn chứa đủ thông tin để dịch ngược thành mã nguồn một cách dễ dàng
SST tuần tự hóa và cây phạm vi cũng được lưu trữ trong một đối tượng Python .pyc
6, như nội dung của thuộc tính .pyc
7 [chứa mã byte trên CPython]. Ví dụ
>>> def add[x, y]:
.. return x+y
...
>>> add.__code__.co_code
b'\x01\x00\x00\x02[]K\xbf\xd1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 ...'
Các tệp .pyc
phần lớn được quản lý tự động bởi thời gian chạy theo cách tương thích với CPython. Giống như trên CPython, có các tùy chọn để chỉ định vị trí của chúng và liệu chúng có nên được viết hay không và cả hai tùy chọn này đều có thể được thay đổi bằng mã khách
Việc tạo các tệp *.pyc
có thể được kiểm soát theo cách tương tự như trên CPython [c. f. https. // tài liệu. con trăn. org/3/sử dụng/dòng lệnh. html]
- Trình khởi chạy Python của GraalVM [_______140] đọc biến môi trường
41. Nếu điều này được đặt thành một chuỗi không trống, Python sẽ không cố ghi các tệpMAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
.pyc
khi nhập mô-đun - Tùy chọn dòng lệnh trình khởi chạy
43, nếu được cung cấp, có tác dụng tương tự như trênMAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
- Mã ngôn ngữ khách có thể thay đổi thuộc tính
44 của mô-đun tích hợp sẵnMAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
45 trong thời gian chạy để thay đổi hành vi cho các lần nhập tiếp theoMAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
- Trình khởi chạy đọc biến môi trường
46. Nếu được đặt, thư mụcMAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
7 sẽ được tạo tại đường dẫn được chỉ ra bởi tiền tố và bản sao cấu trúc thư mục của cây nguồn sẽ được tạo theo yêu cầu để chứa các tệp>>> def add[x, y]: .. return x+y ... >>> add.__code__.co_code b'\x01\x00\x00\x02[]K\xbf\xd1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 ...'
.pyc
- Mã ngôn ngữ khách có thể thay đổi thuộc tính
49 của mô-đunMAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
45 trong thời gian chạy để thay đổi vị trí cho các lần nhập tiếp theoMAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
Vì trình nhúng không thể sử dụng các biến môi trường hoặc tùy chọn CPython để giao tiếp các tùy chọn này với việc triển khai Python của GraalVM, nên các tùy chọn này được cung cấp dưới dạng các tùy chọn ngôn ngữ này
*.pyc
1 - tương đương với
43 hoặcMAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
41MAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
*.pyc
4 - tương đương với
46MAGIC_NUMBER source text binary data - scope tree binary data - simple syntax tree
Lưu ý rằng ngữ cảnh Python sẽ không cho phép ghi tệp .pyc
theo mặc định. Trình khởi chạy
MAGIC_NUMBER
source text
binary data - scope tree
binary data - simple syntax tree
40 kích hoạt nó theo mặc định, nhưng nếu điều này là mong muốn trong trường hợp sử dụng nhúng, thì cần cẩn thận để đảm bảo rằng vị trí >>> def add[x, y]:
.. return x+y
...
>>> add.__code__.co_code
b'\x01\x00\x00\x02[]K\xbf\xd1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 ...'
7 được quản lý đúng cách và các tệp ở vị trí đó được bảo vệ khỏi thao tác giống như các tệp nguồn MAGIC_NUMBER
source text
binary data - scope tree
binary data - simple syntax tree
4 Cũng lưu ý rằng để nâng cấp các nguồn ứng dụng lên thời gian chạy Python của GraalVM Enteprise, các tệp .pyc
cũ phải được trình nhúng xóa theo yêu cầu
Cân nhắc về Bảo mật
Việc tuần tự hóa SST và cây phạm vi được viết tay và trong quá trình giải tuần tự hóa, không thể tải các lớp khác ngoài Nút SST. Tuần tự hóa Java hoặc các khung khác không được sử dụng để tuần tự hóa các đối tượng Java. Lý do chính là hiệu suất, nhưng điều này có tác dụng là không thể tải lớp bằng tệp .pyc
được tạo độc hại
Tất cả các hoạt động của tệp [lấy dữ liệu, dấu thời gian và ghi tệp .pyc
2] được thực hiện thông qua API Hệ thống tệp. Trình nhúng có thể sửa đổi tất cả các hoạt động này bằng phương tiện tùy chỉnh [e. g. , chỉ đọc] .pyc
3 triển khai. Trình nhúng cũng có thể vô hiệu hóa hiệu quả việc tạo tệp .pyc
bằng cách vô hiệu hóa quyền I/O cho thời gian chạy Python của GraalVM
Nếu tệp .pyc
không thể đọc được, vị trí của chúng không thể ghi được. Nếu dữ liệu tuần tự hóa hoặc số ma thuật của tệp .pyc
bị hỏng theo bất kỳ cách nào, quá trình giải tuần tự hóa không thành công và chúng tôi chỉ phân tích lại tệp
MAGIC_NUMBER
source text
binary data - scope tree
binary data - simple syntax tree
4. Điều này đi kèm với một hiệu suất nhỏ chỉ đạt được khi phân tích cú pháp các mô-đun, điều này không đáng kể đối với hầu hết các ứng dụng [miễn là ứng dụng thực sự hoạt động bên cạnh việc tải mã Python]