PyWasm — Kapsamlı Teknik Dökümantasyon
Belgelenen sürüm:
2.2.3Hedef spesifikasyon: WebAssembly Core Specification 2.0 (Taslak 2025-04-25) · WASI Preview 1 Python gereksinimi: ≥ 3.12 Lisans: MIT
İçindekiler
- Yönetici Özeti
- Projeye Genel Bakış
- Dizin Yapısı
- Mimari
- Bağımlılık Analizi
- Dosya Bazlı Dokümantasyon
- Çalıştırma Akışı
- API Dokümantasyonu
- Yapılandırma Dokümantasyonu
- Derleme ve Dağıtım
- Güvenlik Analizi
- Performans Analizi
- Geliştirici Kılavuzu
- İyileştirme Önerileri
1. Yönetici Özeti
pywasm, tamamen standart Python ile yazılmış eksiksiz bir WebAssembly yorumlayıcısıdır (üçüncü taraf kütüphane kullanılmaz). .wasm ikili dosyalarını çözümler, modülleri WebAssembly soyut makine semantiğine göre başlatır ve Python düzeyinde bir değerlendirme döngüsü içinde bayt kodunu talimat talimat çalıştırır.
Çözdüğü sorun
WebAssembly çalışma zamanları (Wasmtime, V8, Wasmer) hızlıdır; ancak yerel kod gerektirirler ve ikili yamalar olmadan saf-Python ortamlarına gömülmeleri ya da araçlanmaları zordur. pywasm, %100 taşınabilir, incelenebilir ve gömülebilir bir WebAssembly yorumlayıcısı nişini doldurur: CPython veya PyPy çalıştıran her yerde çalışır ve sıradan Python'da yazılmış host işlevlerle genişletilebilir.
Hedef kullanıcılar
| Kitle | Kullanım senaryosu |
|---|---|
| Araştırmacılar / güvenlik denetçileri | WebAssembly çalıştırmasını izleme, her talimatı yakalama |
| Eğitimciler | Okunabilir Python ile WebAssembly soyut makinesini inceleme |
| Araç geliştiriciler | Yerel bağımlılıklar olmadan Wasm çalıştırmayı Python betiklerine gömme |
| CI/CD boru hatları | Herhangi bir platformda Wasm modüllerini doğrulama |
Temel özellikler
- Tam WebAssembly 2.0 talimat seti (tamsayı, kayan nokta, SIMD, referans türleri, toplu bellek, tablo işlemleri)
- WASI Preview 1 host uygulaması (dosya G/Ç, soketler, saatler, rastgelelik, ortam, sinyaller, yoklama)
- Host işlev enjeksiyonu API'si — Wasm içinden Python çağrılabilirlerini çağırma
- CLI giriş noktası (
python -m pywasm) - Her kodu çözülen bölüm ve her çalıştırılan talimat için isteğe bağlı hata ayıklama düzeyinde izleme
- PyPy uyumlu tasarım (PyPy üzerinde CPython'dan ≈10× hız artışı)
- Kapsamlı spesifikasyon testi paketi ve WASI test paketi
Üst düzey mimari
┌─────────────────────────────────────────────────────────────┐
│ Host / Kullanıcı │
│ pywasm.Runtime ◄──► pywasm.wasi.Preview1 │
└─────────────────┬───────────────────────────────────────────┘
│ instance_from_file / invocate
┌─────────────────▼───────────────────────────────────────────┐
│ pywasm.core.Machine │
│ ┌───────────┐ ┌────────────────────────────────────────┐ │
│ │ Store │ │ Yığın (Stack) │ │
│ │ func[] │ │ value[] (ValInst) │ │
│ │ tabl[] │ │ label[] (Label / kontrol akışı) │ │
│ │ mems[] │ │ frame[] (Frame / etkinleştirme kd.) │ │
│ │ glob[] │ └────────────────────────────────────────┘ │
│ │ elem[] │ │
│ │ data[] │ ← allocate() / instance() / invocate() │
│ └───────────┘ │
└─────────────────┬───────────────────────────────────────────┘
│ bayt akışı
┌─────────────────▼───────────────────────────────────────────┐
│ pywasm.core.ModuleDesc (ikili çözümleyici) │
│ Bölüm döngüsü: type / import / func / table / mem / │
│ global / export / start / elem / code / data│
└─────────────────────────────────────────────────────────────┘
yardımcılar: pywasm.leb128 · pywasm.arith · pywasm.opcode
2. Projeye Genel Bakış
Proje hedefleri
- Önce doğruluk. Resmi WebAssembly spesifikasyon test paketini (çekirdek + SIMD) ve WASI preview-1 test paketini geçmek.
- Okunabilirlik. Her sınıf ve yöntem WebAssembly spesifikasyonunun düzyazısını yansıtır. Spesifikasyonu okuyan biri terminolojiyi doğrudan koda eşleyebilir.
- Gömülebilirlik. Genel API kasıtlı olarak küçük tutulmuştur:
Runtime,instance_from_file,invocate,allocate_func_host. - Sıfır bağımlılık. Yalnızca Python'un standart kütüphanesi (
io,struct,ctypes,math,typing,platform,os,socket, …).
Temel kavramlar
| Kavram | Açıklama |
|---|---|
| ValType | i32, i64, f32, f64, v128, ref.func, ref.extern'den biri |
| ValInst | Herhangi bir WebAssembly değerini tutan 16 baytlık etiketli birleşim |
| ModuleDesc | Bir .wasm ikilisinin statik, çözümlenmiş açıklaması (çalışma zamanı durumu yok) |
| ModuleInst | Çalışma zamanı örneği: paylaşılan Store içine işaret eden dizin tabloları |
| Store | İşlev, tablo, bellek, global, öğe ve veri örneklerinin paylaşılan heap'i |
| Machine | Bir Store ve bir Stack'e sahiptir; değerlendirme döngüsünü yönetir |
| Label | block / loop / if için kontrol akışı kaydı; geçerli talimat işaretçisini izler |
| Frame | Bir işlev çağrısı için etkinleştirme kaydı; yerel değişkenleri ve modül bağlamını tutar |
| Runtime | Machine etrafında kolaylık sarmalayıcısı; içe aktarma kaydını yönetir |
Tasarım felsefesi
- Spesifikasyona sadık adlandırma. Sınıflar, alanlar ve yöntemler mümkün olduğunca WebAssembly spesifikasyonunun söz dağarcığını kullanır (örn.
ModuleInst,FuncInst,Store,allocate_func_wasm). - Her şey bir dizindir.
ModuleInst, doğrudan referanslar değilStorelistelerine tamsayı dizinleri saklar. Bu, modüller kararlı tutamaçlara sahipken store'un büyümesine olanak tanır. - 16 baytlık değer gösterimi.
ValInst.dataher zaman tam 16 baytlık birbytearray'dir; ölçekli değerlerin yanı sırav128'i (SIMD) tekdüze biçimde destekler. Ölçekli değerler düşük baytları kaplar; yüksek baytlar sıfırla doldurulur. - Yinelemeli değerlendirme döngüsü. Özyinelemeli işlev çağrıları yerine çalıştırma,
stack.labelüzerinde yinelemeli bir döngü kullanır.FrameveLabelgirişleri çağrı ve kontrol akışı talimatları tarafından itilip çıkarılır. Bu Python'un çağrı yığınını sığ tutar ve tasarımı JIT dostu yapar.
Teknoloji yığını
| Katman | Teknoloji |
|---|---|
| Dil | Python ≥ 3.12 (match/case, typing.Self kullanır) |
| İkili kodlama | struct, özel LEB128 okuyucu |
| Aritmetik hassasiyet | IEEE 754 için ctypes.c_float, struct.pack/unpack |
| WASI G/Ç | os, fcntl, socket, select, stat, io (yalnızca Linux/macOS) |
| Wasm kaynak örnekleri | Rust → wasm32-unknown-unknown / wasm32-wasip1 |
| Test altyapısı | Resmi WebAssembly spesifikasyon testleri, resmi WASI test paketi, WABT'dan wast2json |
| Paketleme | hatchling (pyproject.toml) |
| CI | GitHub Actions (macOS, Ubuntu, Windows, Python 3.14) |
3. Dizin Yapısı
pywasm/ ← depo kökü
├── .github/
│ └── workflows/
│ └── develop.yaml ← CI: 3 İS × Python 3.14 üzerinde test
├── .gitignore
├── LICENSE ← MIT
├── MANIFEST.in ← sdist'e LICENSE dahil eder
├── README.md
├── pyproject.toml ← hatchling derleme; sürüm 2.2.3
│
├── pywasm/ ← KÜTÜPHANENİN KENDİSİ (Python paketi)
│ ├── __init__.py ← yeniden dışa aktarmalar, sürüm, platform koruması
│ ├── __main__.py ← CLI giriş noktası
│ ├── arith.py ← sabit genişlikli tamsayı ve IEEE 754 aritmetiği
│ ├── core.py ← 4193 satırlık yorumlayıcı kalbi
│ ├── leb128.py ← LEB128 kodlama/çözme yardımcıları
│ ├── log.py ← hafif hata ayıklama kaydedici
│ ├── opcode.py ← işlem kodu sabitleri + ad arama tablosu
│ └── wasi.py ← WASI Preview 1 uygulaması (Linux/macOS)
│
├── example/ ← çalıştırılabilir Python sürücü betikleri
│ ├── blake2b.py ← Wasm aracılığıyla Blake2b
│ ├── blake2b_direct.py
│ ├── blake2b_iter.py
│ ├── blake2b_simd.py
│ ├── fibonacci.py
│ ├── fibonacci_env.py ← host işlev enjeksiyonu demosu
│ ├── pi.py
│ ├── wasi_httpbin.py
│ ├── wasi_ll.py
│ ├── wasi_stdout.py ← stdout yakalama demosu
│ ├── wasi_zen.py
│ └── <isim>/ ← her örnek için Rust crate'i
│ ├── Cargo.toml
│ ├── src/lib.rs (veya main.rs)
│ └── bin/<isim>.wasm ← önceden derlenmiş ikili (depoya eklendi)
│
├── res/
│ └── pywasm.jpg ← proje logosu
│
├── script/
│ ├── build_example.py ← tüm Rust örneklerini → .wasm olarak derler
│ ├── build_spec.py ← spec test paketini klonlar/günceller, wast2json çalıştırır
│ ├── build_wabt.py ← platforma uygun WABT sürümünü indirir
│ └── build_wasi.py ← wasi-testsuite'i indirir
│
└── test/
├── example.py ← tüm example/ betiklerini çalıştırır
├── main.py ← CLI duman testi (pi, wasi_ll)
├── spec.py ← WebAssembly spesifikasyon uyumluluk test koşucusu
└── wasi.py ← WASI test koşucusu
Dizin rolleri
| Dizin | Rol |
|---|---|
pywasm/ |
Dağıtılabilir Python paketi. Bir son kullanıcının kurduğu her şey. |
example/ |
Tüm genel API yüzeylerini gösterir; Rust kaynağı gerçeğin kaynağıdır; .wasm ikilileri depoya eklenmiştir, böylece depo Rust araç zinciri olmadan kullanılabilir. |
script/ |
Yalnızca geliştirici otomasyonu: araçları indirir, örnekleri derler, test armatürlerini hazırlar. sdist'e dahil edilmez. |
test/ |
Test paketi. script/ tarafından oluşturulan harici armatürler gerektirir. |
res/ |
Statik varlıklar (logo). |
.github/ |
CI yapılandırması. |
4. Mimari
4.1 Sistem mimarisi
pywasm, tek süreçli, tek iş parçacıklı bir yorumlayıcıdır. Çalışma zamanında ağ çağrıları, arka plan iş parçacıkları veya yabancı işlev arabirimleri yoktur. Geliştirme zamanında yalnızca harici süreçler oluşturulur (betikler tarafından) — cargo build, wast2json, git.
4.2 Bileşen mimarisi
┌──────────────────────────────────────────────────┐
│ Genel API Katmanı │
│ Runtime (core.py) │
│ ├── allocate_func_host() │
│ ├── allocate_table() │
│ ├── allocate_memory() │
│ ├── allocate_global() │
│ ├── instance() / instance_from_file() │
│ ├── invocate() │
│ ├── exported_memory() │
│ └── exported_global() │
└──────────────────┬───────────────────────────────┘
│
┌──────────────────▼───────────────────────────────┐
│ Machine (core.py) │
│ ├── Store ─► FuncInst | FuncHost │
│ │ TableInst │
│ │ MemInst (bytearray, sayfalar) │
│ │ GlobalInst │
│ │ ElemInst │
│ │ DataInst │
│ ├── Stack ─► value: list[ValInst] │
│ │ label: list[Label] │
│ │ frame: list[Frame] │
│ │ │
│ ├── allocate() — Store'u doldurur, ModInst d. │
│ ├── instance() — içe aktarmaları doğrular │
│ ├── invocate() — genel işlev çağrı girişi │
│ └── evaluate() — bayt kodu gönderim döngüsü │
└──────────────────┬───────────────────────────────┘
│
┌──────────────────▼───────────────────────────────┐
│ İkili Çözümleyici (core.py) │
│ ModuleDesc.from_reader() │
│ ├── Bölüm 0x01 — type (FuncType) │
│ ├── Bölüm 0x02 — import (Import) │
│ ├── Bölüm 0x03 — func (FuncDesc tür ref) │
│ ├── Bölüm 0x04 — table (TableType) │
│ ├── Bölüm 0x05 — memory (MemType) │
│ ├── Bölüm 0x06 — global (GlobalDesc+Expr) │
│ ├── Bölüm 0x07 — export (ExportDesc) │
│ ├── Bölüm 0x08 — start (işlev dizini) │
│ ├── Bölüm 0x09 — elem (ElemDesc) │
│ ├── Bölüm 0x0a — code (LocalsDesc+Expr) │
│ ├── Bölüm 0x0b — data (DataDesc) │
│ └── Bölüm 0x0c — datacount │
└──────────────────────────────────────────────────┘
↑ kullanır
┌─────────────────────────────────────────────────┐
│ Destek Modülleri │
│ leb128.py — işaretsiz/işaretli LEB128 G/Ç │
│ arith.py — sabit genişlikli aritmetik yrd. │
│ opcode.py — işlem kodu sabitleri + ad tab. │
│ log.py — zaman damgalı hata ayıklama çık.│
└─────────────────────────────────────────────────┘
4.3 Çalışma zamanı mimarisi (soyut makine)
WebAssembly spesifikasyonu çalıştırmayı bir Store ve bir Stack açısından tanımlar. pywasm her ikisini de sadakatle uygular.
Store
Tüm çalışma zamanı nesneleri Machine başına tek bir Store'da yaşar:
Store.func : list[FuncInst | FuncHost] # işlev örnekleri
Store.tabl : list[TableInst] # tablo örnekleri
Store.mems : list[MemInst] # doğrusal bellek örnekleri
Store.glob : list[GlobalInst] # global değişken örnekleri
Store.elem : list[ElemInst] # öğe segmenti örnekleri
Store.data : list[DataInst] # veri segmenti örnekleri
Bu listelerdeki dizinler adresler olarak hizmet eder. Bir ModuleInst, her kategori için modül-yerel dizinleri store adreslerine eşleyen list[int] tutar.
Stack
Stack.value : list[ValInst] # operand yığını
Stack.label : list[Label] # kontrol akışı yığını
Stack.frame : list[Frame] # çağrı çerçevesi yığını
Üçü de Python listesidir ve yığın olarak kullanılır (append / pop). Spesifikasyon üç türü de kavramsal tek bir yığında karıştırır; pywasm bunları çerçeve/etiket derinliğine göre dizinlenen üç paralel listeye ayırır.
Label
class Label:
arity : int # dönüş değerlerinin sayısı
frame : int # etiket girişindeki çerçeve derinliği
value : int # etiket girişindeki değer-yığını derinliği
carry : int # 0x00 = döngüye geri dön, 0x01 = etiketi çıkar, 0x03 = çerçeveyi de çıkar
instr : list[Inst] # çalıştırılacak talimat dizisi
index : int # instr içindeki geçerli talimat işaretçisi
carry bir bit alanıdır. Bit 0 dal semantiğini kontrol eder (döngü vs blok). Bit 1 etiketin bir Frame ile ilişkilendirildiğini gösterir (yani bir işlev etkinleştirmesi), bu nedenle etiketi çıkarmak çerçeveyi de çıkarır.
Frame
class Frame:
module : ModuleInst # dizinleri çözümlemek için modül bağlamı
locals : LocalsInst # yerel değişkenler (bağımsız değişkenler dahil)
arity : int # beklenen dönüş değerlerinin sayısı
label : int # çerçeve girişindeki etiket-yığını derinliği
value : int # çerçeve girişindeki değer-yığını derinliği
4.4 İşlem kodu gönderimi
Machine.evaluate() yöntemi sıkı bir yinelemeli döngüdür:
for _ in range(1 << 32): # pratikte sonsuz; istisna çıkar
label = self.stack.label[-1]
frame = self.stack.frame[-1]
if label.index == len(label.instr):
self.stack.label.pop()
if label.carry & 2: # çerçeve taşıyan etiket
self.stack.frame.pop()
continue
instr = label.instr[label.index]
label.index += 1
match instr.opcode:
case opcode.i32_add: ...
case opcode.call: ...
# ... 400+ durum
Her yineleme:
- Geçerli etiketi (etiket yığınının üstü) alır
- Talimat listesi tükenirse etiketi çıkarır (ve isteğe bağlı olarak çerçeveyi)
- Aksi takdirde sonraki talimatı alır ve
matcharacılığıyla gönderir
Bu tasarım çoğu aritmetik talimat için yineleme başına tahsisattan bağımsızdır (yalnızca liste dizinleme ve ValInst oluşturma).
4.5 Kontrol akışı mekaniği
| Talimat | Efekt |
|---|---|
block |
Bloğun talimat listesiyle yeni bir Label(carry=1) iter |
loop |
Yeni bir Label(carry=0) iter — br, index'i 0'a sıfırlar (döngüye geri döner) |
if |
Koşulu çıkarır; ya then ya da else talimat listesiyle Label iter |
br n |
evaluate_br(n): n etiketi etiket yığınından çıkarır, arity değerlerini toplar, değer yığınını geri yükler |
br_if |
Koşullu br |
br_table |
Dizinli br |
return |
Çerçeve etiketine kadar ve dahil olmak üzere tüm etiketleri çıkarır |
call |
Yeni bir Frame ve çağrılanın talimat listesini içeren yeni bir Label(carry=3) iter |
4.6 Başlatma yaşam döngüsü
Kullanıcı → Runtime.instance_from_file(yol)
→ open(yol) → ModuleDesc.from_reader()
→ Machine.instance(modül, extern_listesi)
→ içe aktarmaları doğrula
→ yardımcı Frame it
→ global başlatma ifadelerini değerlendir
→ öğe başlatma ifadelerini değerlendir
→ allocate(modül, extern, globin, elemin)
→ ModuleInst döndürür
→ newmod Frame it
→ aktif öğe segmentlerini çalıştır (table_init)
→ aktif veri segmentlerini çalıştır (memory_init)
→ başlangıç işlevini çağır (varsa)
→ newmod Frame'i çıkar
→ ModuleInst döndür
→ Kullanıcıya ModuleInst döndür
4.7 WASI entegrasyon mimarisi
┌──────────────────────┐
│ Preview1 (wasi.py) │ bind(runtime) → "wasi_snapshot_preview1" altında
│ │ 45 host işlev kaydeder
│ fd: list[File] │
│ args, dirs, envs │
│ return_on_exit │
└──────────┬───────────┘
│ call_indirect/call aracılığıyla Wasm'dan çağrılan host işlevleri
▼
┌──────────────────────┐
│ Machine (evaluate) │ FuncHost.hostcode(machine, args) → rets
│ │
│ iovec, stat yapıları│
│ vb. için doğrusal │
│ belleği okur/yazar │
└──────────────────────┘
│
▼
İS: open/read/write/socket/...
WASI işlevleri bir Machine referansı ve zaten paketinden çıkarılmış bağımsız değişken değerlerinin list[int]'ini alır. Doğrusal belleğe machine.store.mems[...].get_u32(ptr) vb. aracılığıyla erişirler. Sonuçlar belleğe geri yazılır ve bir hata kodu list[int] olarak döndürülür.
5. Bağımlılık Analizi
pywasm'ın Python standart kütüphanesi dışında sıfır çalışma zamanı bağımlılığı vardır.
| Modül | Kullanan | Amaç |
|---|---|---|
ctypes |
arith.py, core.py |
IEEE 754 tek hassasiyetli yuvarlama için c_float; bayt düzeni için struct |
struct |
arith.py, core.py |
Little-endian tamsayıları ve kayan noktaları paketleme/paket açma |
math |
arith.py, core.py |
Kayan nokta talimatları için isnan, isinf, copysign, ceil, floor, trunc, sqrt |
io |
leb128.py, core.py |
Bölüm düzeyinde ayrıştırma için aranabilir bayt okuyucu olarak io.BytesIO |
typing |
core.py, leb128.py |
Tür ipuçları için typing.Self, typing.Any, typing.Callable |
platform |
__init__.py, wasi.py |
wasi'yi koşullu olarak içe aktarmak için İS algılama |
os |
wasi.py |
Tüm POSIX dosya işlemleri |
fcntl |
wasi.py |
Engellemesiz / ekleme bayrağı değişiklikleri için fcntl.F_SETFL |
socket |
wasi.py |
sock_accept, sock_recv, sock_send, sock_shutdown için TCP/UDP soket işlemleri |
select |
wasi.py |
poll_oneoff abonelik yoklaması için select.select() |
stat |
wasi.py |
WASI dosya türü eşlemesi için stat.S_ISREG, stat.S_ISDIR |
random |
wasi.py |
random_get için random.randbytes() |
time |
wasi.py |
WASI saatleri için time.time_ns(), time.monotonic_ns(), time.process_time_ns() |
dataclasses |
wasi.py |
Preview1.File tanımlayıcısı için @dataclasses.dataclass |
sys |
wasi.py, __main__.py |
sys.stdin/stdout/stderr dosya tanımlayıcıları; sys.exit() |
argparse |
__main__.py |
CLI bağımsız değişken ayrıştırma |
Derleme zamanı (yalnızca geliştirici)
| Araç | Amaç |
|---|---|
hatchling |
PEP 517 derleme arka ucu (pyproject.toml'de bildirilmiş) |
wabt (wast2json) |
.wast spesifikasyon testlerini .json + .wasm'a dönüştürür |
| Rust + cargo | Örnek Wasm ikilileri derler (wasm32-unknown-unknown, wasm32-wasip1) |
| git | Resmi WebAssembly spesifikasyonunu ve WASI test paketi depolarını klonlar |
6. Dosya Bazlı Dokümantasyon
6.1 pywasm/__init__.py
Dosya amacı
Paket giriş noktası. core'un genel yüzeyini yeniden dışa aktarır, wasi'yi koşullu olarak içe aktarır (yalnızca POSIX) ve kütüphane sürümünü bildirir.
Temel bileşenler
version = '2.2.3'
Sürüm dizisi pyproject.toml'de kopyalanmıştır. İkisi arasında otomatik senkronizasyon yoktur.
Platform koruması
if platform.system().lower() in ['darwin', 'linux']:
from . import wasi
wasi.py, Windows'ta mevcut olmayan fcntl, select, os.pread ve POSIX'e özgü dir_fd= bağımsız değişkenlerini kullanır. Koruma, Windows'ta ImportError'ı önler; burada WASI programları şu anda pywasm aracılığıyla çalıştırılamaz.
İlişkiler
- Şunlardan içe aktarır:
arith,core,leb128,log,opcode, koşullu olarakwasi from .core import *,core.py'deki tüm genel sembolleripywasmad alanı düzeyinde kullanılabilir kılar
6.2 pywasm/log.py
Dosya amacı
Yorumlayıcı boyunca hata ayıklama izlemesi için kullanılan minimal zaman damgalı kaydedici.
Temel bileşenler
lvl = 0 # global hata ayıklama düzeyi; izlemeyi etkinleştirmek için 1 olarak ayarla
def debugln(*args):
if lvl > 0:
println(*args)
def println(*args):
pre = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
print(pre, 'pywasm:', *args)
İç mantık
debugln, lvl tarafından korunur. pywasm.log.lvl = 1 ayarı şunları içeren ayrıntılı çıktıyı etkinleştirir:
- İkili çözümlenirken her bölüm başlığı
evaluate()sırasında çalıştırılan her talimat- Global ve öğe başlatıcı değerlendirmeleri
Notlar
- 1'in üzerinde bir günlük düzeyi yoktur (herhangi bir sıfırdan farklı değer hata ayıklama çıktısını etkinleştirir).
- Dosya tabanlı günlük kaydı veya yapılandırılmış günlük kaydı yoktur. Tüm çıktı
stdout'a gider. - İzlemeyi etkinleştirmek, her talimat için dize biçimlendirmesi gerçekleştiğinden önemli ek yük oluşturur.
6.3 pywasm/leb128.py
Dosya amacı
WebAssembly ikili biçimi tarafından belirtilen LEB128 (Little-Endian Base-128) değişken uzunluklu tamsayı kodlamasının uygulaması.
Temel bileşenler
class _U — İşaretsiz LEB128
| Yöntem | İmza | Açıklama |
|---|---|---|
encode |
(i: int) → bytearray |
Negatif olmayan bir tamsayıyı kodlar |
decode |
(b: bytearray) → int |
Önceden okunan bir bytearray'i çözer |
decode_reader |
(r: io.IOBase) → tuple[int, int] |
MSB 0 olana kadar bir akıştan bayt okur; (değer, okunan_bayt) döndürür |
class _I — İşaretli LEB128
_U ile aynı arabirim, ancak decode'da iki tümleyenli işaret genişletmesini işler:
if e & 0x40 != 0: # son baytın işaret biti ayarlandıysa
r |= - (1 << (i * 7) + 7) # işaret genişletme
Modül düzeyinde tekil nesneler
u = _U() # işaretsiz LEB128 kod çözücüsü
i = _I() # işaretli LEB128 kod çözücüsü
Bunlar core.py boyunca pywasm.leb128.u.decode_reader(r) olarak kullanılır.
İç mantık
Kodlama döngüsü, devam bayrağı olarak yüksek bit (0x80) ayarlanmış şekilde bayt başına 7 bit biriktirir. Çözücü bunu tersine çevirir ve devam bayrağı olmayan birine kadar bayt toplar.
Notlar
decode_reader,(değer, okunan_bayt_sayısı)demeti döndürür, ancak neredeyse tüm çağrı sitelerinde yalnızca[0](değer) kullanılır.- Maksimum bayt uzunluğu doğrulaması yoktur. Sonsuz devam-bit akışına sahip hatalı biçimlendirilmiş girdiler sonsuza kadar döner.
6.4 pywasm/arith.py
Dosya amacı
Python'un keyfi hassasiyetli varsayılanlarından farklı olan WebAssembly tamsayı ve kayan nokta semantiğini doğru biçimde uygulayan sabit genişlikli aritmetik yardımcı sınıfları.
Temel bileşenler
class I(blen) — blen baytlık işaretli tamsayı
| Öznitelik | Değer (I(4) için) |
|---|---|
bits_length |
32 |
byte_length |
4 |
mask |
0xFFFFFFFF |
mask_sign |
0x80000000 |
max |
2147483647 |
min |
-2147483648 |
Temel yöntemler:
fit(n)—n'yi iki tümleyenli maskeleme kullanarak işaretli aralığa sarar:n = n & self.mask # bit genişliğine kes n = n - ((n & self.mask_sign) << 1) # işaret genişletmediv(a, b)— Sıfıra doğru kesmeli bölme uygular (WebAssembly gereksinimi):
Python'un yerelreturn a // b if a * b > 0 else (a + (-a % b)) // b//'si negatif sonsuza doğru keser; bu düzeltme doğruluk açısından kritiktir.rem(a, b)— Eşleşen işaretli kalan (her zaman bölünenin işaretine sahiptir).shl/shr— Kaydırma miktarıbits_length - 1ile maskelenir (WebAssembly gereksinimi).
class U(blen) — İşaretsiz tamsayı
Aynı yapı ancak fit yalnızca n & mask'tir. Döndürme ve bit sayma işlemleri ekler:
rotl(a, b)/rotr(a, b)— Dairesel bit döndürmeclz(a)— Baştaki sıfırları say (bit döngüsü, O(bits_length))ctz(a)— Sondaki sıfırları saypopcnt(a)— Popülasyon sayımı (ayarlı bitleri say)
class F32 ve class F64 — IEEE 754 kayan nokta sarmalayıcıları
F32.fit(n), 32 bit hassasiyete yuvarlamak içinctypes.c_float(n).valuekullanır — Python'unfloat'ı her zaman 64 bit olduğundan doğruluk açısından önemlidir.F64.div(a, b), WebAssembly'ye göre sıfıra bölmeyi işler: doğru işaretle ±∞ veya NaN döndürür.min/max— Her iki operanddaki NaN'yi yayar (WebAssembly NaN yayma kuralları Python'unmin/max'inden farklıdır).
Modül düzeyinde tekil nesneler
i8, u8, i16, u16, i32, i64, u32, u64 = I(1), U(1), I(2), U(2), I(4), I(8), U(4), U(8)
f32, f64 = F32(), F64()
Bunlar core.py tarafından pywasm.arith.i32.add(a, b) vb. olarak içe aktarılır.
Notlar
clz,ctz,popcntO(N) bit-bit döngülerdir. N=64 (i64) için bu 64 yinelemedir — bir yorumlayıcı için kabul edilebilir ancak optimal değil.int.bit_count()(Python 3.10+)popcnt'nin yerini alabilir.I.divözel durumu:assert a != self.min or b != -1,INT_MIN / -1üzerindeki tamsayı taşmasına karşı koruma sağlar.
6.5 pywasm/opcode.py
Dosya amacı
İşlem kodu sabitleri ve hata ayıklama ekranı için bir name sözlüğü içeren düz modül. SIMD (0xfd öneki), doyurucu kesme (0xfc öneki) ve referans türleri dahil olmak üzere 2.0 spesifikasyonundaki her WebAssembly işlem kodunu içerir.
Temel bileşenler
# Temel işlem kodları (tek bayt)
unreachable = 0x00
nop = 0x01
block = 0x02
...
# Genişletilmiş işlem kodları (0xfc önekli iki bayt, birleşik int olarak kodlanmış)
i32_trunc_sat_f32_s = 0xfc00
memory_init = 0xfc08
...
# SIMD işlem kodları (0xfd öneki)
v128_load = 0xfd00
i8x16_shuffle = 0xfd0d
...
Notlar
- Modül 437 işlem kodu tanımı ve 437 karşılık gelen
namegirişi içerir. - Tamamen bildirimseldir — mantık yok, içe aktarma yok. Bu, içe aktarmayı çok ucuz yapar.
6.6 pywasm/core.py
Dosya amacı
4193 satırlık merkezi modül. Şunları içerir:
- Tüm tür-tanımlayıcı ve çalışma zamanı-örneği sınıfları (WebAssembly spesifikasyonunu yansıtır)
- İkili modül çözümleyici (
ModuleDesc.from_reader) - Soyut makine (
Machine) - Genel kolaylık API'si (
Runtime)
6.6.1 Değer sistemi
class ValType
Tek bayt olarak kodlanmış yedi WebAssembly değer türü:
| Sabit | Değer | Anlam |
|---|---|---|
0x7f |
i32 |
32 bitlik tamsayı |
0x7e |
i64 |
64 bitlik tamsayı |
0x7d |
f32 |
32 bitlik kayan nokta |
0x7c |
f64 |
64 bitlik kayan nokta |
0x7b |
v128 |
128 bitlik SIMD vektörü |
0x70 |
ref.func |
İşlev referansı |
0x6f |
ref.extern |
Harici referans |
Fabrika sınıf yöntemleri: ValType.i32(), ValType.f32(), vb.
class ValInst
16 baytlık etiketli değer. data alanı her zaman tam 16 bayttır.
i32 değeri 42 için düzen:
bayt 0-3: little-endian 42 (0x2a 0x00 0x00 0x00)
bayt 4-15: sıfırlar
ref (işlev dizini 7, null değil) için düzen:
bayt 0-3: işaretli 32 bit little-endian 7
bayt 4: 0x01 (null-olmayan bayrağı)
bayt 5-15: sıfırlar
v128 için düzen:
bayt 0-15: vektörün ham 16 baytı
Oluşturma yöntemleri (sınıf yöntemleri): from_i32, from_i64, from_u32, from_u64, from_f32, from_f64, from_v128, from_v128_i8 … from_v128_f64, from_ref, from_all.
Çıkarma yöntemleri (örnek yöntemleri): into_i32, into_i64, into_u32, into_u64, into_f32, into_f64, into_v128, into_v128_i8 … into_v128_f64, into_ref, into_all.
6.6.2 Tür tanımlayıcılar (statik / ikili dosyadan çözümlenmiş)
| Sınıf | Amaç |
|---|---|
Bype |
Blok türü — boş (0x40), tek değer türü veya işlev türü dizini |
Inst |
Tek çözümlenmiş talimat: opcode + args listesi |
Expr |
end ile sonlandırılan Inst listesi |
LocalsDesc |
Yerel değişken bildirimi için n × tür çifti |
LocalsInst |
ValInst yerellerinin çalışma zamanı değiştirilebilir listesi |
FuncType |
args: list[ValType], rets: list[ValType] |
FuncDesc |
Tür dizini + yereller + gövde Expr |
Limits |
n (min), m (max, 0 = sınırsız) |
MemType |
Limits'i sarar |
TableType |
ValType + Limits |
GlobalType |
ValType + değiştirilebilirlik bayrağı (0=sabit, 1=değiştirilebilir) |
GlobalDesc |
GlobalType + başlatıcı Expr |
Import |
Modül adı, öğe adı, tür, tanımlayıcı |
Extern |
Çalışma zamanı harici değer: tür + store adresi |
ExportDesc |
Ad, tür (func/table/mem/global), tanımlayıcı dizini |
ElemDesc |
Öğe segmenti (spesifikasyona göre 8 tür) |
DataDesc |
Veri segmenti (spesifikasyona göre 3 tür) |
Custom |
Özel bölüm (semantikler tarafından göz ardı edilir) |
ModuleDesc |
Tüm çözümlenmiş bölümler toplulaştırılmış |
6.6.3 Inst.from_reader — talimat çözümleyici
Bir BytesIO okuyucudan bir kerede bir talimat okuyan yaklaşık 350 satırlık bir match ifadesi. Yapılandırılmış kontrol talimatları için (block, loop, if) end'e kadar (veya if için else) özyinelemeli olarak okur ve iç içe talimat listelerinden oluşan bir ağaç oluşturur.
Bellek talimatları için hizalama+ofset anlık çiftlerini okur ve hizalamanın spesifikasyon sınırları içinde olduğunu doğrular.
f32/f64 sabit kodlama notu:
case opcode.f32_const:
# Python, float'a dönüştürüldüğünde 0x7fa00000'i 0x7fe00000 olarak yanlış yorumlar.
o.args.append(struct.unpack('<i', r.read(4))[0]) # ham int olarak sakla
Kayan nokta sabitleri Python'un NaN kanonizasyonundan kaçınmak için ham bit örüntüleri (işaretli int32/int64) olarak saklanır. Çalıştırma zamanında ValInst.from_f32_u32 aracılığıyla yeniden yorumlanırlar.
6.6.4 ModuleDesc.from_reader — ikili modül çözümleyici
Wasm ikili biçimini okur:
- Sihirli
\x00asmve sürüm\x01\x00\x00\x00'ı kontrol eder - Her birini
BytesIOalt okuyucusu olarak okuyarak 32 bölüme kadar döngü yapar - Bölüm ID'sine göre gönderir (0–12)
- Kod bölümü (0x0a) özeldir: her biri kendi LEB128 uzunluğu ile boyutlandırılmış işlev gövdelerinin sayısıdır
6.6.5 Çalışma zamanı örnekleri
| Sınıf | Açıklama |
|---|---|
ModuleInst |
Modül başına dizin tabloları (type, func, tabl, mems, glob, elem, data, exps) |
FuncInst |
Wasm tanımlı işlev: tür, modül bağlamı, kod |
FuncHost |
Python tarafından barındırılan işlev: tür, çağrılabilir |
MemInst |
Doğrusal bellek: bytearray verisi + sayfa sayısı; grow(n) 64KiB sayfaları ekler |
TableInst |
Tablo: referansların list[ValInst]'i; grow(n, v) v değerinin n kopyasını ekler |
GlobalInst |
Global: data: ValInst + değiştirilebilirlik bayrağı |
ElemInst |
Öğe segmenti: tür + list[ValInst] referansları |
DataInst |
Veri segmenti: bytearray |
MemInst bellek sınırları:
memory_grow talimatı ayrıca 1024 sayfaya (64 MiB) sabitlenmiştir:
cnda = size + incr <= 1024 # sabit üst sınır
cndb = mems.type.limits.m == 0 or size + incr <= mems.type.limits.m
Bu, spesifikasyon gereksinimi değil, kasıtlı bir yerleştirici politikasıdır.
6.6.6 Machine.allocate — kaynak tahsisi
ModuleDesc → ModuleInst'i kaynak tahsis ederek eşler:
- Harici değerler (içe aktarmalardan) modül dizin tablolarına eklenir
store.allocate_func_wasm(inst, func)→FuncInstoluşturur, store adresi döndürürstore.allocate_table,allocate_memory,allocate_global,allocate_elem,allocate_databenzer şekilde- Dışa aktarma tanımlayıcıları
ExportInstgirişlerine çözümlenir
6.6.7 Machine.instance — modül başlatma
Tam spesifikasyon tanımlı başlatma prosedürü:
- İçe aktarma listesi uzunluğunun ve türlerinin bildirilmiş içe aktarmalarla eşleştiğini doğrula
- Her içe aktarmayı bildirilmiş tanımlayıcıya karşı tür kontrol et
- Global/öğe başlatma ifadelerinin çalışmasına izin vermek için yardımcı
Frameit - Her global başlatıcı ifadesini değerlendir
- Her öğe başlatıcı ifadesini değerlendir
- Gerçek
ModuleInst'i oluşturmak içinallocate()çağır - Gerçek modülle çerçeveyi yeniden it
- Aktif öğe segmentlerini çalıştır (
table_init+elem_drop) - Bildirimsel öğe segmentlerini çalıştır (
elem_drop) - Aktif veri segmentlerini çalıştır (
memory_init+data_drop) - Bildirilmişse başlangıç işlevini çağır
- Çerçeveyi çıkar ve
ModuleInstdöndür
6.6.8 Machine.invocate — işlev çağrısı
Dışa aktarılan bir işlevi çağırmak için genel giriş noktası:
- Bağımsız değişken türlerini doğrula
- Sentinel
Frameit (aşırı açmayı algılamak için) - Bağımsız değişkenlerden + sıfır başlatılmış yerel değişkenlerden yerelleri oluştur
- Gerçek
Frame'i ve işlev gövdesini içeren başlangıçLabel(carry=3)'ü it evaluate()çağır- Değer yığınından dönüş değerlerini çıkar
- Dönüş türlerini doğrula
- Sentinel çerçeveyi çıkar; yığınların boş olduğunu doğrula
6.6.9 Machine.evaluate — gönderim döngüsü
Yorumlayıcının kalbi. Bir for döngüsü içinde yaklaşık 2300 satırlık tek bir match instr.opcode: ifadesi. Dikkat çekici uygulama kalıpları:
Bellek talimatları:
def evaluate_mem_load(self, offset: int, size: int) -> bytearray:
mems = self.store.mems[self.stack.frame[-1].module.mems[0]]
addr = self.stack.value.pop().into_u32() + offset
assert addr + size <= len(mems.data) # sınır dışında tuzak
return mems.data[addr:addr+size]
Dal işleme (evaluate_br):
def evaluate_br(self, l: int) -> None:
label = self.stack.label[-1 - l] # hedef etiket (derinlik l)
rets = [self.stack.value.pop() for _ in range(label.arity)][::-1]
self.stack.frame = self.stack.frame[:label.frame] # çerçeveleri aç
self.stack.label = self.stack.label[:len(self.stack.label)-l]
match label.carry & 1:
case 0x00: label.index = 0 # döngü: başa sıfırla
case 0x01: self.stack.label.pop() # blok: etiketten çık
self.stack.value = self.stack.value[:label.value]
self.stack.value.extend(rets)
SIMD talimatları — hepsi aynı kalıbı izler: v128 operandlarını yazılı listeler olarak çıkar, öğe bazında işlem uygula, sonucu it:
case opcode.i8x16_add:
b = self.stack.value.pop().into_v128_i8()
a = self.stack.value.pop().into_v128_i8()
c = [pywasm.arith.i8.add(a[i], b[i]) for i in range(16)]
self.stack.value.append(ValInst.from_v128_i8(c))
6.6.10 class Runtime
Genel API cephesi. Bir Machine ve bir imports sözlüğüne sahiptir:
class Runtime:
machine: Machine
imports: dict[str, dict[str, Extern]] # modül_adı → {öğe_adı → Extern}
| Yöntem | Açıklama |
|---|---|
allocate_func_host(type, func) |
Python çağrılabilirini host işlev olarak kaydet |
allocate_table(type) |
İçe aktarma için tablo önceden tahsis et |
allocate_memory(type) |
İçe aktarma için bellek önceden tahsis et |
allocate_global(type, data) |
İçe aktarma için global önceden tahsis et |
exported_memory(module, name) |
Dışa aktarılan MemInst'i ara |
exported_global(module, name) |
Dışa aktarılan GlobalInst'i ara |
instance(module) |
ModuleDesc'ten başlat; içe aktarmaları self.imports'tan çöz |
instance_from_file(path) |
Dosya aç → ModuleDesc.from_reader → instance() |
invocate(module, func, args) |
Dışa aktarılan işlevi ada göre çağır; Python değerlerini ValInst'e otomatik dönüştür |
Host işlev çağrı kuralı:
# Tüm host işlevleri için gerekli imza:
def my_func(machine: pywasm.core.Machine, args: list[int|float|...]) -> list[int|float|...]:
...
Machine referansı, host işlevlerine bellek, globaller ve çağrı yığınına tam erişim sağlar.
6.7 pywasm/__main__.py
Dosya amacı
python -m pywasm olarak çağrılan CLI giriş noktası.
Temel bileşenler
Bağımsız değişkenler:
file wasm dosya yolu (gerekli)
--version, -v sürümü yazdır ve çık
--func çağrılacak dışa aktarılan işlev adı (varsayılan: _start)
--func-args tekrar eden; dize olarak bağımsız değişken değerleri
--wasi WASI'yi etkinleştirmek için 'preview1'
--wasi-envs 'ANAHTAR=DEĞER' çiftleri
--wasi-dirs 'wasm_yolu:host_yolu' dizin eşlemeleri
--wasi-args WASI programı için argv
İç mantık
İki kod yolu:
main_wasi()—--wasi preview1mevcutsa:RuntimevePreview1nesnesi oluşturur- Host işlevleri kaydetmek için
wasi.bind(runtime)çağırır runtime.instance_from_file(file)çağırır_start'ı çağırmak içinwasi.main(runtime, inst)çağırır- Süreç çıkış koduyla
sys.exit(code)
main_wasm()— düz Wasm:Runtimeoluşturur, modülü başlatır- Adlandırılmış dışa aktarmayı çözer
--func-argsdizelerini yazılı Python değerlerine dönüştürürruntime.invocate(...)çağırır ve sonuç listesini yazdırır
6.8 pywasm/wasi.py
Dosya amacı
WASI Preview 1 ABI'nin Python sınıfı olarak eksiksiz uygulaması. wasm32-wasip1 hedefine karşı derlenen Wasm programlarının çağıracağı 45 sistem çağrısı benzeri host işlevi sağlar.
Önemli: Platform kısıtlaması
wasi.py, fcntl (POSIX) ve os işlevlerine dir_fd= bağımsız değişkenleri kullanır. Bu modül yalnızca Linux ve macOS'ta içe aktarılır.
Temel bileşenler
class Preview1.File (veri sınıfı)
Hem host tarafında hem de WASI tarafında meta verilerle açık bir dosya tanımlayıcısını temsil eder:
| Alan | Açıklama |
|---|---|
host_fd |
İS dosya tanımlayıcısı tamsayısı |
host_flag |
İS bayrakları (O_RDONLY, O_APPEND, vb.) |
host_name |
Host dosya sistemindeki mutlak yol |
host_status |
FILE_STATUS_OPENED veya FILE_STATUS_CLOSED |
pipe |
Okuma/yazmaları yönlendirmek için isteğe bağlı io.BytesIO |
wasm_fd |
WASI dosya tanımlayıcısı numarası |
wasm_flag |
WASI fdflags |
wasm_name |
Wasm programının gördüğü yol |
wasm_rights_base |
İzin verilen işlemlerin bit maskesi |
wasm_rights_root |
Devralınabilir hakların bit maskesi |
wasm_status |
WASI fd durumu |
wasm_type |
WASI dosya türü (normal, dizin, soket, vb.) |
WASI işlev kategorileri
| Kategori | İşlevler |
|---|---|
| Bağımsız değişkenler/Ortam | args_get, args_sizes_get, environ_get, environ_sizes_get |
| Saat | clock_res_get, clock_time_get |
| Dosya tanımlayıcısı | fd_advise, fd_allocate, fd_close, fd_datasync, fd_fdstat_get, fd_fdstat_set_flags, fd_fdstat_set_rights, fd_filestat_get, fd_filestat_set_size, fd_filestat_set_times, fd_pread, fd_prestat_get, fd_prestat_dir_name, fd_pwrite, fd_read, fd_readdir, fd_renumber, fd_seek, fd_sync, fd_tell, fd_write |
| Yol | path_create_directory, path_filestat_get, path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory, path_rename, path_symlink, path_unlink_file |
| Yoklama | poll_oneoff |
| Süreç | proc_exit, proc_raise |
| Rastgelelik | random_get |
| Zamanlayıcı | sched_yield |
| Soket | sock_accept, sock_recv, sock_send, sock_shutdown |
Yol korumalı alan oluşturma
Her path_* işlevi, yol geçiş girişimlerini (örn. ../../etc/passwd) algılamak için help_escp(wasm_name, user_path) çağırır. Normalleştirilmiş yol önceden açılmış dizinden kaçarsa ERRNO_PERM döndürülür.
proc_exit davranışı
def proc_exit(self, _, args):
if self.return_on_exit:
raise Exception(SystemExit, args[0]) # main() tarafından yakalanır
sys.exit(args[0])
return_on_exit = 1 varsayılan olarak — bu Python programının Wasm programı çıktıktan sonra devam etmesini sağlar. 0 olarak ayarlanması Python sürecinin sona ermesine neden olur.
7. Çalıştırma Akışı
7.1 Kütüphane kullanımı başlangıç dizisi
import pywasm
│
├── arith.py modülü çalıştırılır → i8, u8, …, f32, f64 tekil nesneleri oluşturur
├── leb128.py modülü çalıştırılır → u, i tekil nesneleri oluşturur
├── log.py modülü çalıştırılır → lvl = 0
├── opcode.py modülü çalıştırılır → 437 sabit + name sözlüğü
├── core.py modülü çalıştırılır → yalnızca sınıf tanımları
└── wasi.py içe aktarılır (yalnızca Linux/macOS)
runtime = pywasm.core.Runtime()
│
└── Machine()
└── Store()
└── Stack()
runtime.imports = {}
runtime.instance_from_file('module.wasm')
│
├── open('module.wasm', 'rb')
├── ModuleDesc.from_reader(f)
│ ├── Sihirli + sürüm kontrol et
│ └── Bölümler üzerinde döngü (type, import, func, table, mem, global, export, start, elem, code, data)
│
└── Runtime.instance(module)
└── Machine.instance(module, extern_listesi)
├── İçe aktarmaları doğrula
├── Global başlatma ifadelerini değerlendir
├── Machine.allocate(module, extern, globin, elemin)
├── Aktif öğe segmentlerini çalıştır
├── Aktif veri segmentlerini çalıştır
└── Başlangıç işlevini çalıştır
→ ModuleInst döndür
7.2 İşlev çağrısı dizisi
runtime.invocate(module, 'fibonacci', [10])
│
├── 'fibonacci'yi module.exps'de ara → func_addr
├── func_inst = store.func[func_addr] al
├── func_args = [ValInst.from_i32(10)] oluştur
└── Machine.invocate(func_addr, func_args)
├── Sentinel Frame it
├── LocalsInst oluştur
├── Gerçek Frame ve Label(carry=3) it
└── Machine.evaluate()
Label yığını boşalana kadar döngü:
label.instr[label.index++]'dan talimat al
match instr.opcode:
... gönder ...
← label yığını boş
Değer yığınından dönüş değerlerini çıkar
Sentinel Frame'i çıkar
→ [55] döndür (fibonacci(10))
8. API Dokümantasyonu
8.1 Runtime (birincil genel arabirim)
Runtime()
Yeni, izole bir WebAssembly çalışma zamanı oluşturur.
runtime = pywasm.core.Runtime()
runtime.imports
runtime.imports: dict[str, dict[str, Extern]]
İçe aktarma kaydı. Başlatmadan önce doldurun:
runtime.imports['env'] = {
'my_func': runtime.allocate_func_host(type, callable),
}
runtime.allocate_func_host(type, func) → Extern
Python çağrılabilirini WebAssembly host işlevi olarak kaydeder.
def my_print(machine, args):
print(f"Wasm diyor ki: {args[0]}")
return []
extern = runtime.allocate_func_host(
pywasm.core.FuncType([pywasm.core.ValType.i32()], []),
my_print
)
runtime.instance_from_file(path) → ModuleInst
Bir .wasm ikilisi yükler ve başlatır. Tüm içe aktarmaları runtime.imports'tan çözer.
Hatalar: Sihirli/sürüm uyuşmazlığı, içe aktarmaların karşılanamaması veya tür doğrulama başarısızlığında AssertionError.
runtime.invocate(module, func, args) → list
Dışa aktarılan işlevi ada göre çağırır.
result = runtime.invocate(m, 'fibonacci', [10])
# result == [55]
runtime.exported_memory(module, name) → MemInst
Dışa aktarılan doğrusal belleğe doğrudan erişim sağlar.
mem = runtime.exported_memory(m, 'memory')
data = mem.get(ptr, length) # bayt oku
mem.put(ptr, bytearray(...)) # bayt yaz
runtime.exported_global(module, name) → GlobalInst
Dışa aktarılan bir globalin geçerli değerine erişim sağlar.
g = runtime.exported_global(m, 'my_global')
print(g.data.into_i32())
g.data = pywasm.core.ValInst.from_i32(99) # değiştirilebilir globali değiştir
8.2 API'de kullanılan temel türler
| Tür | Oluşturma | Açıklama |
|---|---|---|
ValType.i32() |
Sınıf yöntemi | 32 bitlik tamsayı türü |
ValType.i64() |
Sınıf yöntemi | 64 bitlik tamsayı türü |
ValType.f32() |
Sınıf yöntemi | 32 bitlik kayan nokta türü |
ValType.f64() |
Sınıf yöntemi | 64 bitlik kayan nokta türü |
ValType.v128() |
Sınıf yöntemi | 128 bitlik SIMD türü |
FuncType(args, rets) |
Yapıcı | İşlev imzası |
Limits(n, m) |
Yapıcı | Min/max sınırları (m=0 sınırsız anlamına gelir) |
MemType(limits) |
Yapıcı | Bellek türü |
TableType(valtype, limits) |
Yapıcı | Tablo türü |
GlobalType(valtype, mut) |
Yapıcı | Global türü (mut: 0=sabit, 1=değiştirilebilir) |
ValInst.from_i32(n) |
Sınıf yöntemi | i32 değeri oluştur |
ValInst.from_f64(n) |
Sınıf yöntemi | f64 değeri oluştur |
ValInst.zero(type) |
Sınıf yöntemi | Verilen türde sıfır değeri oluştur |
9. Yapılandırma Dokümantasyonu
9.1 Hata ayıklama günlük kaydı
import pywasm
pywasm.log.lvl = 1 # ayrıntılı hata ayıklama çıktısını etkinleştir
lvl'yi sıfırdan farklı herhangi bir tamsayıya ayarlamak stdout'a bölüm başına ve talimat başına izlemeyi etkinleştirir.
9.2 Bellek sınırı
Machine.evaluate, memory_grow'u 1024 sayfaya (64 MiB) sabitler. core.py değiştirilmeden çalışma zamanında yapılandırılamaz:
# core.py:2008
cnda = size + incr <= 1024 # sabit üst sınır — artırmak için bunu değiştir
9.3 Çağrı yığını derinliği
Machine.evaluate_call, 1024 çerçeve sınırı uygular:
assert len(self.stack.frame) < 1024
9.4 WASI return_on_exit
wasi = pywasm.wasi.Preview1(args, dirs, envs)
wasi.return_on_exit = 0 # istisna yerine sys.exit() çağırmak için 0 olarak ayarla
9.5 WASI stdout/stdin yakalama
import io
wasi.fd[1].pipe = io.BytesIO(bytearray()) # stdout → arabellek
wasi.fd[0].pipe = io.BytesIO(b'giriş verisi') # stdin ← arabellek
9.6 Ortam değişkenleri ve dizin eşlemeleri (WASI)
wasi = pywasm.wasi.Preview1(
args=['program.wasm', '--bayrak'],
dirs={'/korumalı_alan': '/host/yolu/dizin'}, # wasm_yolu: host_yolu
envs={'HOME': '/korumalı_alan', 'LANG': 'C'}
)
10. Derleme ve Dağıtım
10.1 PyPI'den kurulum
pip install pywasm
10.2 Kaynaktan kurulum (düzenlenebilir)
git clone https://github.com/libraries/pywasm
cd pywasm
pip install --editable .
10.3 Dağıtım paketi oluşturma
pip install build
python -m build # dist/pywasm-2.2.3.tar.gz ve dist/pywasm-2.2.3-py3-none-any.whl oluşturur
10.4 Wasm örnekleri derleme (yalnızca geliştirici)
wasm32-unknown-unknown ve wasm32-wasip1 hedefleriyle Rust gerektirir:
rustup target add wasm32-unknown-unknown wasm32-wasip1
python script/build_wabt.py # wabt araçlarını indir
python script/build_example.py # tüm Rust örneklerini derle
10.5 Testleri çalıştırma
python script/build_wabt.py # tek seferlik
python script/build_spec.py # spec testlerini klonla + derle
python script/build_wasi.py # WASI test paketini klonla
python test/example.py # tüm örnekleri çalıştır
python test/main.py # CLI duman testleri
python test/spec.py # spec uyumluluğu (yavaş)
python test/wasi.py # WASI uyumluluğu
10.6 CI/CD boru hattı
GitHub Actions (.github/workflows/develop.yaml):
- Her push ve PR açmada tetiklenir
- Matris: macOS, Ubuntu, Windows × Python 3.14
- Adımlar: checkout → setup-python → build_wabt → pywasm kurulumu → testleri oluştur → tüm testleri çalıştır
- Dağıtım adımı yok (PyPI yayınlama manueldir)
10.7 Sürüm stratejisi
Sürüm iki yerde ayarlanır:
pyproject.toml:version = "2.2.3"pywasm/__init__.py:version = '2.2.3'
Otomatik sürüm artışı yoktur. Bir geliştirici, yayınlamadan önce her iki dosyayı da manüel olarak güncellemelidir.
11. Güvenlik Analizi
11.1 Güven sınırları
Güvenilmez: .wasm dosya içeriği
Güvenilir: Python host kodu, WASI önceden açılan dizin yolları
11.2 Korumalı alan özellikleri
Bellek erişimi: Tüm MemInst.data erişimleri, açık sınır doğrulamaları ile Python dilimleme dizinlemesi kullanır. Sınır dışı erişimler AssertionError (tuzak) yükseltir, segfault değil.
Dosya sistemi: WASI path_* işlevleri, dizin geçişini önlemek için help_escp çağırır. Önceden açılan dizinler korumalı alan sınırını tanımlar.
Ağ: Soket işlemleri, fd tablosu aracılığıyla var olan bir soketin iletilmesini gerektirir. Wasm programı bağımsız olarak yeni bağlantılar başlatamaz.
Süreç yalıtımı: Wasm programı, işlemleri başlatamaz, paylaşılan kütüphaneler yükleyemez veya Python yorumlayıcısının nesnelerine doğrudan erişemez.
11.3 Olası güvenlik açıkları
| Risk | Önem | Notlar |
|---|---|---|
Sınır kontrolü için assert |
Orta | python -O ile assert ifadeleri devre dışı bırakılır. Optimize edilmiş pywasm çalıştırmak tüm güvenlik kontrollerini devre dışı bırakır. |
| LEB128 sonsuz döngü | Düşük | Eksik durdurma baytına sahip hatalı biçimlendirilmiş .wasm sonsuza kadar döner. Maksimum bayt sayısı koruması yok. |
| Sabit kodlanmış bellek sınırı | Düşük | 64 MiB üst sınırı atlatılabilir. |
help_escp güvenilirliği |
Orta | Yol kaçış kontrolü os.path.normpath ve dize öneki eşleştirmesi kullanır. Büyük/küçük harf duyarsız dosya sistemlerinde kaçışlar mümkün olabilir. |
random.randbytes |
Düşük | Python'un random modülü (Mersenne Twister) kullanır, kriptografik açıdan güvenli RNG değil. |
| Kaynak sınırı yok | Orta | Kontrolden çıkan bir Wasm programı CPU zamanını ve Python heap'ini tüketebilir. |
12. Performans Analizi
12.1 Temel özellikler
pywasm, JIT derleyicisi olmayan bir yorumlayıcıdır. Her WebAssembly talimatı bir Python işlev çağrısıdır. Yaklaşık büyüklük sırası:
- Yerel Wasmtime: ~1 ns/talimat
- CPython üzerinde pywasm: ~1 µs/talimat (1000× daha yavaş)
- PyPy üzerinde pywasm: ~100 ns/talimat (CPython'dan ~10× daha hızlı)
12.2 Birincil darboğazlar
| Darboğaz | Açıklama |
|---|---|
match instr.opcode gönderimi |
Python'un yapısal desen eşleştirmesi bir anahtar tablosu kadar hızlı değildir. |
ValInst tahsisi |
Çoğu talimat yeni bir ValInst (16 baytlık bytearray + tür) oluşturur. Bu önemli GC baskısı oluşturur. |
| SIMD liste kavrayışları | Her SIMD talimatı 16 baytlık bytearray'i Python listesine dönüştürür, öğe bazında işlem uygular ve yeniden paketler. |
arith.clz/ctz/popcnt |
O(64) yineleme için saf Python bit döngüleri. |
| Hata ayıklama modu ek yükü | Her talimat için f-string biçimlendirme ve print() çağrıları. |
12.3 Ölçeklenebilirlik
pywasm tek iş parçacıklıdır. threading veya asyncio desteği yoktur.
12.4 Optimizasyon fırsatları
| Fırsat | Beklenen kazanım |
|---|---|
popcnt için int.bit_count() kullan |
O(N) döngüsünü yerel yöntemle değiştirir |
label.instr[label.index]'i yerel değişkende önbelleğe al |
Yineleme başına öznitelik aramalarını azaltır |
| Talimat listesini tuple dizisi olarak önceden hesapla | Inst nesne ek yükünü azaltır |
| Sık çağrılan işlevleri Python bayt koduna derle (JIT) | "JIT dostu" tasarım yorumu bunu amaçladığını ima eder |
ValInst nesnelerini havuzla (ortak değerler için flyweight) |
Tahsis/GC baskısını azaltır |
Bellek dilimleri için memoryview kullan |
evaluate_mem_load'da bytearray kopyasını önler |
13. Geliştirici Kılavuzu
13.1 Ön koşullar
| Araç | Sürüm | Amaç |
|---|---|---|
| Python | ≥ 3.12 | Çalışma zamanı ve geliştirme |
| Rust + cargo | kararlı | Örnek .wasm ikilileri derle |
| wasm32 hedefleri | — | rustup target add wasm32-unknown-unknown wasm32-wasip1 |
| WABT (otomatik indirilir) | 1.0.41 | Spec testleri için wast2json |
| Git | herhangi | Spec ve WASI test depolarını klonla |
13.2 İlk kurulum
# 1. Klonla
git clone <depo>
cd pywasm
# 2. Kur (düzenlenebilir)
pip install --editable .
# 3. Geliştirici araçlarını indir
python script/build_wabt.py
# 4. İsteğe bağlı: Rust örneklerini derle (Rust gerektirir)
python script/build_example.py
# 5. Temel testleri çalıştır
python test/example.py
python test/main.py
13.3 Hızlı duman testi çalıştırma
import pywasm
runtime = pywasm.core.Runtime()
m = runtime.instance_from_file('example/fibonacci/bin/fibonacci.wasm')
r = runtime.invocate(m, 'fibonacci', [10])
assert r == [55], r
print("TAMAM")
13.4 Hata ayıklama izlemesini etkinleştirme
import pywasm
pywasm.log.lvl = 1
runtime = pywasm.core.Runtime()
m = runtime.instance_from_file('example/fibonacci/bin/fibonacci.wasm')
r = runtime.invocate(m, 'fibonacci', [3])
# Çıktı:
# 2026/06/07 12:00:00 pywasm: bölüm type [i32] -> [i32]
# 2026/06/07 12:00:00 pywasm: invocate 0 [i32 3]
# ...
13.5 Host işlev enjekte etme
import pywasm
def my_log(machine: pywasm.core.Machine, args: list) -> list:
print(f"[WASM LOG] değer={args[0]}")
return []
runtime = pywasm.core.Runtime()
runtime.imports['env'] = {
'log': runtime.allocate_func_host(
pywasm.core.FuncType([pywasm.core.ValType.i32()], []),
my_log
)
}
m = runtime.instance_from_file('my_module.wasm')
runtime.invocate(m, 'run', [])
Karşılık gelen Rust kodu içe aktarmayı bildirir:
extern "C" { fn log(value: i32); }
13.6 Doğrusal belleği okuma / yazma
mem = runtime.exported_memory(m, 'memory')
# 1000 adresinde null sonlandırılmış C dizesi oku
ptr = 1000
end = mem.data.index(0, ptr)
s = mem.data[ptr:end].decode('utf-8')
# 2000 adresine 4 bayt yaz
mem.put(2000, bytearray([0x01, 0x02, 0x03, 0x04]))
13.7 Yeni işlem kodu ekleme
opcode.py'ye sabiti ekle:my_new_op = 0xXX name[my_new_op] = 'my_new.op'core.py'dekiInst.from_reader'a çözme mantığı ekle:case pywasm.opcode.my_new_op: o.args.append(pywasm.leb128.u.decode_reader(r)[0])core.py'dekiMachine.evaluate'a çalıştırma mantığı ekle:case pywasm.opcode.my_new_op: a = self.stack.value.pop().into_i32() b = ValInst.from_i32(my_operation(a)) self.stack.value.append(b)
13.8 Yeni WASI sistem çağrısı ekleme
Preview1sınıfına sabitler ekle (errno, bayraklar, vb.)- Uygulama yöntemini yaz:
def my_syscall(self, m: pywasm.core.Machine, args: list[int]) -> list[int]: if self.help_badf(args[0]): return [self.ERRNO_BADF] # ... uygulama ... return [self.ERRNO_SUCCESS] Preview1.bind()'a kaydet:['my_syscall', [i32, i32], [i32], self.my_syscall],
13.9 Spec testlerini çalıştırma
python script/build_spec.py # tek seferlik
python test/spec.py
13.10 Başarısız spec testinde hata ayıklama
test/spec.py'depywasm.log.lvl = 1ayarlaall_test'i tek bir dosyaya filtrele:all_test = ['res/spec/test/core/i32.json']- JSON komutlarını belirli bir test durumu dizinine filtrele
14. İyileştirme Önerileri
14.1 Mimari iyileştirmeler
| Öneri | Gerekçe |
|---|---|
| Çözümleyiciyi core'dan ayır | ModuleDesc ve tüm *Desc sınıfları makinenin yanında core.py'de yaşar. decoder.py'ye bölmek gezinmeyi iyileştirir. |
| Uygun istisna hiyerarşisi tanıt | Tüm hatalar şu anda AssertionError (tuzaklar için) veya yalın Exception kullanır. Bir WasmTrap, WasmLinkError, WasiError hiyerarşisi çağırıcıların hata türlerini ayırt etmesini sağlar. |
| Bellek sınırını yapılandırılabilir yap | 1024 sayfa sabit üst sınırı ve 1024 çerçeve derinlik sınırı core.py'deki sihirli sayılar değil, Runtime'ın parametreleri olmalıdır. |
| İş parçacığı güvenli çok modüllü çalıştırma | Store'un tahsis listeleri etrafında threading.Lock, çok iş parçacıklı yerleştirici senaryolarında eşzamanlı başlatmaya izin verir. |
14.2 Kod kalitesi iyileştirmeleri
| Öneri | Gerekçe |
|---|---|
pyproject.toml'e python_requires = ">=3.12" ekle |
Eski Python'da kafa karıştırıcı başarısızlıkları önler. |
| Sürümü tek kaynaktan senkronize et | __init__.py'de importlib.metadata.version('pywasm') kullan veya sürüm dosyası kullan. |
assert'i açık kontrollerle değiştir |
python -O ile assert devre dışı bırakılır. Güvenlik açısından kritik sınır kontrolleri if ... raise ... olmalıdır. |
wasi.py yöntemlerine tür ipuçları ekle |
args: list[int] ipucu çoğu sistem çağrısı için doğrudur, ancak eksiksiz doğruluk için `list[int |
| SIMD işlem kodu işlemeyi ayır | evaluate()'daki 1200+ SIMD durumu, ana döngünün boyutunu azaltmak için evaluate_simd(instr) yardımcısına çıkarılabilir. |
14.3 Sürdürülebilirlik iyileştirmeleri
| Öneri | Gerekçe |
|---|---|
| Docstring ekle | Kod tamamen satır içi yorumlara dayanır. Runtime, Machine, Store, Preview1 üzerindeki docstring'ler IDE entegrasyonunu iyileştirir. |
| Değişiklik günlüğü tanıt | CHANGELOG.md yoktur. Katkıda bulunanlar sürümler arasında neyin değiştiğini göremez. |
| WABT sürümünü CI'da sabitle | build_wabt.py sabit kodlanmış v1.0.41 indirir. Bu, spec checkout tarafından beklenen sürümle eşleşmelidir. |
14.4 Performans iyileştirmeleri
| Öneri | Öncelik | Beklenen kazanım |
|---|---|---|
arith.popcnt'ü int.bit_count() ile değiştir |
Düşük | Popcount için 64× hız artışı |
Ortak ValInst nesnelerini havuzla |
Orta | GC baskısını ~%30 azalt |
Talimatları (opcode, *args) demeti olarak temsil et |
Orta | Daha küçük nesneler, daha az öznitelik araması |
evaluate() için isteğe bağlı Cython uzantısı ekle |
Yüksek | CPU'ya bağlı kod için 5–50× hız artışı |
compile() / exec() aracılığıyla temel JIT uygula |
Çok Yüksek | CPython'da PyPy performansıyla eşleşebilir |
14.5 Güvenlik iyileştirmeleri
| Öneri | Gerekçe |
|---|---|
Bellek OOB için assert'i raise ile değiştir |
python -O assert'i devre dışı bırakır; OOB erişimi host belleği bozar. |
random_get için os.urandom kullan |
random.randbytes'ı os.urandom ile değiştirerek "yüksek kaliteli rastgelelik" WASI spec gereksinimini karşıla. |
| WASI için yol geçiş testleri ekle | help_escp mantığı uç durumlara karşı test edilmelidir: sembolik bağlantılar, .. bileşenleri, Windows yolları, Unicode normalleştirme. |
| LEB128 maksimum uzunluk koruması ekle | Hatalı girişte sonsuz döngüleri önlemek için LEB128 okumalarını ceil(64/7) = 10 bayta sınırla. |
Dokümantasyon, pywasm v2.2.3 kod analizi ile oluşturulmuştur. Tüm satır referansları analiz zamanındaki depo durumuna dayanmaktadır.