Loops: loop และ br_if
loop ใน WebAssembly ไม่วนซ้ำอัตโนมัติ เป็นเพียง labeled construct ที่จุดเริ่มต้นเป็น branch target การวนซ้ำจะเกิดขึ้นเมื่อวาง br_if ไว้ที่ท้าย body เพื่อกระโดดกลับไปที่ loop label เมื่อ condition ยังเป็นจริง
Loop construct
หัวข้อที่มีชื่อว่า “Loop construct”(loop $label ...) กำหนดจุดเริ่มต้นของ loop br $label ภายใน body จะกระโดดกลับไปที่จุดเริ่มต้น — ตรงข้ามกับทิศทางของ br ใน block การออกจาก loop ทำได้โดยให้ execution ไปถึง end (fall-through) หรือกระโดดไปที่ outer label
(module (func (export "countDown") (param $n i32) (loop $again ;; body here local.get $n i32.const 1 i32.sub local.tee $n ;; decrement $n and keep value on stack i32.const 0 i32.gt_s br_if $again))) ;; repeat while $n > 0Loop flow
หัวข้อที่มีชื่อว่า “Loop flow”flowchart LR A["init locals"] --> B["loop $again (start)"] B --> C["body: update acc, increment i"] C --> D["i <= n?"] D -->|yes| B D -->|no| E["exit: return acc"]
ตัวอย่าง counted loop: sumTo
หัวข้อที่มีชื่อว่า “ตัวอย่าง counted loop: sumTo”ฟังก์ชันด้านล่างรวมจำนวนเต็มตั้งแต่ 1 ถึง n โดยใช้ loop local $i เป็น counter และ $acc สะสมผลรวม
(module (func (export "sumTo") (param $n i32) (result i32) (local $i i32) (local $acc i32) i32.const 1 local.set $i ;; i = 1 i32.const 0 local.set $acc ;; acc = 0 (loop $again local.get $i local.get $acc i32.add local.set $acc ;; acc += i local.get $i i32.const 1 i32.add local.set $i ;; i++ local.get $i local.get $n i32.le_s br_if $again) ;; repeat while i <= n local.get $acc)) ;; return accทดลองรัน
หัวข้อที่มีชื่อว่า “ทดลองรัน”ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
loop + br_if (structured back-edge) | validate ได้ตั้งแต่ compile time และปลอดภัยกว่า arbitrary backward goto | ต้องเขียน exit condition เองทุกครั้ง ไม่มี built-in for/while ให้ engine จัดการให้ |
| ไม่มี arbitrary jump ระหว่าง loop | engine ทำ loop compilation/JIT ได้เร็วเพราะรู้ boundary ของ loop ชัดเจน | portability ของ CFG ที่ซับซ้อนจาก native code ต้องแปลงผ่าน relooper ก่อนจะ map เข้า loop/br ได้ |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- เข้าใจผิดว่า
br_ifในloopทำงานเหมือนbreakแต่จริง ๆ แล้วกระโดดกลับไปที่จุดเริ่มต้นของloop(ทำงานคล้ายcontinueมากกว่า) ไม่ใช่ทางออกจาก loop - ลืมใส่ exit condition ที่ถูกต้อง ทำให้
br_if $againเป็นจริงตลอดไปและ loop วนไม่รู้จบ (Wasm ไม่มี infinite-loop guard ให้อัตโนมัติ) - Off-by-one ใน exit condition เช่นใช้
i <= nผิดเป็นi < nทำให้ loop วนขาดหรือเกินไปหนึ่งรอบ อย่างในตัวอย่างsumTo
💡 ตัวอย่างจากของจริง
Wasmtime ใช้ประโยชน์จาก structured
loopconstruct ของ Wasm ในการ compile loop เป็น native machine code ที่มี back-edge ชัดเจน ทำให้ JIT ทำ loop optimization ได้เร็วและปลอดภัยกว่าการวิเคราะห์ arbitrary jump graph