第6章 控制流
WebAssembly 的控制流指令构成了程序逻辑的骨架。本章将深入学习条件分支、循环结构、异常处理等高级控制流技术,掌握编写复杂程序逻辑的核心技能。
结构化控制流
6.1.1 控制流基础
WebAssembly 采用结构化控制流,所有控制结构都有明确的开始和结束:
(module
;; 基本的控制流结构演示
(func $basic_control_flow (param $x i32) (result i32)
;; 块(block):创建标签作用域
(block $exit
;; 条件分支(if-then-else)
(if (i32.gt_s (local.get $x) (i32.const 10))
(then
;; 如果 x > 10,跳出块并返回 x*2
(br $exit (i32.mul (local.get $x) (i32.const 2)))))
;; 循环(loop)
(loop $increment
;; 递增 x
(local.set $x (i32.add (local.get $x) (i32.const 1)))
;; 如果 x < 10,继续循环
(br_if $increment (i32.lt_s (local.get $x) (i32.const 10))))
;; 默认返回值
local.get $x))
(export "basic_control_flow" (func $basic_control_flow)))
控制流指令概览:
控制结构:
- block : 创建标签块,可以跳出
- loop : 创建循环标签,可以跳回
- if : 条件分支,支持 then 和 else
跳转指令:
- br : 无条件跳转
- br_if : 条件跳转
- br_table : 多路跳转(类似 switch)
- return : 函数返回
异常处理:
- try : 异常捕获块
- catch : 异常处理
- throw : 抛出异常
6.1.2 条件分支的高级用法
(module
;; 复杂条件判断
(func $complex_conditions (param $a i32) (param $b i32) (param $c i32) (result i32)
;; 嵌套条件分支
(if (result i32)
(i32.gt_s (local.get $a) (i32.const 0))
(then
;; a > 0 的情况
(if (result i32)
(i32.gt_s (local.get $b) (i32.const 0))
(then
;; a > 0 && b > 0
(if (result i32)
(i32.gt_s (local.get $c) (i32.const 0))
(then (i32.const 1)) ;; 全部为正
(else (i32.const 2)))) ;; a,b 为正,c 非正
(else
;; a > 0 && b <= 0
(i32.const 3))))
(else
;; a <= 0 的情况
(if (result i32)
(i32.eqz (local.get $a))
(then (i32.const 0)) ;; a == 0
(else (i32.const -1)))))) ;; a < 0
;; 使用 select 指令进行简单条件选择
(func $conditional_select (param $condition i32) (param $true_val i32) (param $false_val i32) (result i32)
;; select 相当于三元运算符 condition ? true_val : false_val
(select
(local.get $true_val)
(local.get $false_val)
(local.get $condition)))
;; 条件链式判断
(func $grade_calculator (param $score i32) (result i32)
;; 返回等级:A=90+, B=80+, C=70+, D=60+, F<60
(if (result i32)
(i32.ge_s (local.get $score) (i32.const 90))
(then (i32.const 65)) ;; 'A'
(else
(if (result i32)
(i32.ge_s (local.get $score) (i32.const 80))
(then (i32.const 66)) ;; 'B'
(else
(if (result i32)
(i32.ge_s (local.get $score) (i32.const 70))
(then (i32.const 67)) ;; 'C'
(else
(if (result i32)
(i32.ge_s (local.get $score) (i32.const 60))
(then (i32.const 68)) ;; 'D'
(else (i32.const 70))))))))) ;; 'F'
;; 短路求值模拟
(func $short_circuit_and (param $a i32) (param $b i32) (result i32)
;; 模拟 a && b 的短路求值
(if (result i32)
(local.get $a)
(then (local.get $b)) ;; 如果 a 为真,返回 b
(else (i32.const 0)))) ;; 如果 a 为假,返回 0
(func $short_circuit_or (param $a i32) (param $b i32) (result i32)
;; 模拟 a || b 的短路求值
(if (result i32)
(local.get $a)
(then (local.get $a)) ;; 如果 a 为真,返回 a
(else (local.get $b)))) ;; 如果 a 为假,返回 b
(export "complex_conditions" (func $complex_conditions))
(export "conditional_select" (func $conditional_select))
(export "grade_calculator" (func $grade_calculator))
(export "short_circuit_and" (func $short_circuit_and))
(export "short_circuit_or" (func $short_circuit_or)))
6.1.3 多路分支与跳转表
(module
;; 使用 br_table 实现多路分支
(func $switch_statement (param $value i32) (result i32)
;; br_table 类似于 C 语言的 switch 语句
(block $default
(block $case_3
(block $case_2
(block $case_1
(block $case_0
;; 检查值的范围并跳转
(br_table $case_0 $case_1 $case_2 $case_3 $default
(local.get $value)))
;; case 0: 返回 100
(return (i32.const 100)))
;; case 1: 返回 200
(return (i32.const 200)))
;; case 2: 返回 300
(return (i32.const 300)))
;; case 3: 返回 400
(return (i32.const 400)))
;; default: 返回 -1
i32.const -1)
;; 函数指针模拟:通过跳转表调用不同函数
(func $operation_add (param $a i32) (param $b i32) (result i32)
(i32.add (local.get $a) (local.get $b)))
(func $operation_sub (param $a i32) (param $b i32) (result i32)
(i32.sub (local.get $a) (local.get $b)))
(func $operation_mul (param $a i32) (param $b i32) (result i32)
(i32.mul (local.get $a) (local.get $b)))
(func $operation_div (param $a i32) (param $b i32) (result i32)
(if (result i32)
(i32.eqz (local.get $b))
(then (i32.const 0)) ;; 除零保护
(else (i32.div_s (local.get $a) (local.get $b)))))
;; 通过操作码调用相应函数
(func $calculator (param $op i32) (param $a i32) (param $b i32) (result i32)
(block $invalid
(block $div
(block $mul
(block $sub
(block $add
;; 根据操作码跳转: 0=add, 1=sub, 2=mul, 3=div
(br_table $add $sub $mul $div $invalid (local.get $op)))
;; 加法
(return (call $operation_add (local.get $a) (local.get $b))))
;; 减法
(return (call $operation_sub (local.get $a) (local.get $b))))
;; 乘法
(return (call $operation_mul (local.get $a) (local.get $b))))
;; 除法
(return (call $operation_div (local.get $a) (local.get $b))))
;; 无效操作
i32.const -999)
;; 状态机实现
(func $state_machine (param $current_state i32) (param $input i32) (result i32)
;; 状态转换表:根据当前状态和输入决定下一个状态
;; 状态:0=初始, 1=处理中, 2=完成, 3=错误
(block $error_state
(block $complete_state
(block $processing_state
(block $initial_state
(br_table $initial_state $processing_state $complete_state $error_state
(local.get $current_state)))
;; 初始状态 (0)
(if (result i32)
(i32.eq (local.get $input) (i32.const 1)) ;; 开始信号
(then (i32.const 1)) ;; 转到处理中
(else
(if (result i32)
(i32.eq (local.get $input) (i32.const 99)) ;; 错误信号
(then (i32.const 3)) ;; 转到错误
(else (i32.const 0))))) ;; 保持初始状态
(return))
;; 处理中状态 (1)
(if (result i32)
(i32.eq (local.get $input) (i32.const 2)) ;; 完成信号
(then (i32.const 2)) ;; 转到完成
(else
(if (result i32)
(i32.eq (local.get $input) (i32.const 99)) ;; 错误信号
(then (i32.const 3)) ;; 转到错误
(else (i32.const 1))))) ;; 保持处理中
(return))
;; 完成状态 (2)
(if (result i32)
(i32.eq (local.get $input) (i32.const 0)) ;; 重置信号
(then (i32.const 0)) ;; 转到初始
(else (i32.const 2))) ;; 保持完成状态
(return))
;; 错误状态 (3)
(if (result i32)
(i32.eq (local.get $input) (i32.const 0)) ;; 重置信号
(then (i32.const 0)) ;; 转到初始
(else (i32.const 3)))) ;; 保持错误状态
(export "switch_statement" (func $switch_statement))
(export "calculator" (func $calculator))
(export "state_machine" (func $state_machine)))
循环控制
6.2.1 循环的基本形式
(module
;; while 循环模拟
(func $while_loop_sum (param $n i32) (result i32)
(local $sum i32)
(local $i i32)
(local.set $sum (i32.const 0))
(local.set $i (i32.const 1))
;; while (i <= n)
(loop $while_loop
;; 检查循环条件
(if (i32.gt_s (local.get $i) (local.get $n))
(then (br $while_loop))) ;; 跳出循环
;; 循环体
(local.set $sum
(i32.add (local.get $sum) (local.get $i)))
;; 递增计数器
(local.set $i (i32.add (local.get $i) (i32.const 1)))
;; 继续循环
(br $while_loop))
local.get $sum)
;; do-while 循环模拟
(func $do_while_factorial (param $n i32) (result i32)
(local $result i32)
(local $i i32)
(local.set $result (i32.const 1))
(local.set $i (local.get $n))
;; do { ... } while (i > 0)
(loop $do_while_loop
;; 循环体
(local.set $result
(i32.mul (local.get $result) (local.get $i)))
;; 递减计数器
(local.set $i (i32.sub (local.get $i) (i32.const 1)))
;; 检查继续条件
(br_if $do_while_loop (i32.gt_s (local.get $i) (i32.const 0))))
local.get $result)
;; for 循环模拟
(func $for_loop_power (param $base i32) (param $exp i32) (result i32)
(local $result i32)
(local $i i32)
(local.set $result (i32.const 1))
(local.set $i (i32.const 0))
;; for (i = 0; i < exp; i++)
(loop $for_loop
;; 检查循环条件
(if (i32.ge_s (local.get $i) (local.get $exp))
(then (br $for_loop))) ;; 跳出循环
;; 循环体
(local.set $result
(i32.mul (local.get $result) (local.get $base)))
;; 递增计数器
(local.set $i (i32.add (local.get $i) (i32.const 1)))
;; 继续循环
(br $for_loop))
local.get $result)
;; 无限循环与 break 模拟
(func $infinite_loop_with_break (param $target i32) (result i32)
(local $counter i32)
(local.set $counter (i32.const 0))
;; 无限循环
(loop $infinite_loop
;; 递增计数器
(local.set $counter (i32.add (local.get $counter) (i32.const 1)))
;; break 条件
(if (i32.eq (local.get $counter) (local.get $target))
(then (br $infinite_loop))) ;; 跳出循环
;; continue 条件示例
(if (i32.rem_s (local.get $counter) (i32.const 2))
(then (br $infinite_loop))) ;; 跳过奇数,继续循环
;; 这里可以添加其他处理逻辑
;; 继续循环
(br $infinite_loop))
local.get $counter)
(export "while_loop_sum" (func $while_loop_sum))
(export "do_while_factorial" (func $do_while_factorial))
(export "for_loop_power" (func $for_loop_power))
(export "infinite_loop_with_break" (func $infinite_loop_with_break)))
6.2.2 嵌套循环与复杂控制
(module
;; 嵌套循环:矩阵操作
(func $matrix_multiply_trace (param $size i32) (param $matrix_a i32) (param $matrix_b i32) (result i32)
;; 计算两个方阵相乘后的对角线元素之和
(local $trace i32)
(local $i i32)
(local $j i32)
(local $k i32)
(local $sum i32)
(local $a_elem i32)
(local $b_elem i32)
(local.set $trace (i32.const 0))
(local.set $i (i32.const 0))
;; 外层循环:遍历对角线元素
(loop $outer_loop
(if (i32.ge_s (local.get $i) (local.get $size))
(then (br $outer_loop)))
(local.set $sum (i32.const 0))
(local.set $k (i32.const 0))
;; 内层循环:计算 C[i][i] = Σ A[i][k] * B[k][i]
(loop $inner_loop
(if (i32.ge_s (local.get $k) (local.get $size))
(then (br $inner_loop)))
;; 读取 A[i][k]
(local.set $a_elem
(i32.load
(i32.add
(local.get $matrix_a)
(i32.mul
(i32.add
(i32.mul (local.get $i) (local.get $size))
(local.get $k))
(i32.const 4)))))
;; 读取 B[k][i]
(local.set $b_elem
(i32.load
(i32.add
(local.get $matrix_b)
(i32.mul
(i32.add
(i32.mul (local.get $k) (local.get $size))
(local.get $i))
(i32.const 4)))))
;; 累加乘积
(local.set $sum
(i32.add
(local.get $sum)
(i32.mul (local.get $a_elem) (local.get $b_elem))))
(local.set $k (i32.add (local.get $k) (i32.const 1)))
(br $inner_loop))
;; 累加到对角线和
(local.set $trace (i32.add (local.get $trace) (local.get $sum)))
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $outer_loop))
local.get $trace)
;; 多重 break 和 continue
(func $complex_nested_loops (param $rows i32) (param $cols i32) (result i32)
(local $found i32)
(local $i i32)
(local $j i32)
(local $value i32)
(local.set $found (i32.const 0))
(local.set $i (i32.const 0))
;; 外层循环标签
(block $outer_break
(loop $outer_loop
(if (i32.ge_s (local.get $i) (local.get $rows))
(then (br $outer_break)))
(local.set $j (i32.const 0))
;; 内层循环
(loop $inner_loop
(if (i32.ge_s (local.get $j) (local.get $cols))
(then (br $inner_loop)))
;; 模拟一些计算
(local.set $value
(i32.add
(i32.mul (local.get $i) (local.get $cols))
(local.get $j)))
;; 跳过偶数值(类似 continue)
(if (i32.eqz (i32.rem_s (local.get $value) (i32.const 2)))
(then
(local.set $j (i32.add (local.get $j) (i32.const 1)))
(br $inner_loop)))
;; 找到特定条件时跳出所有循环
(if (i32.eq (local.get $value) (i32.const 15))
(then
(local.set $found (i32.const 1))
(br $outer_break)))
(local.set $j (i32.add (local.get $j) (i32.const 1)))
(br $inner_loop))
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $outer_loop)))
local.get $found)
;; 循环展开优化示例
(func $unrolled_sum (param $array_ptr i32) (param $length i32) (result i32)
(local $sum i32)
(local $i i32)
(local $remaining i32)
(local.set $sum (i32.const 0))
(local.set $i (i32.const 0))
;; 计算可以4路展开的循环次数
(local.set $remaining (i32.rem_u (local.get $length) (i32.const 4)))
;; 4路展开的主循环
(loop $unrolled_loop
(if (i32.ge_u (local.get $i)
(i32.sub (local.get $length) (local.get $remaining)))
(then (br $unrolled_loop)))
;; 一次处理4个元素
(local.set $sum
(i32.add (local.get $sum)
(i32.add
(i32.add
(i32.load (i32.add (local.get $array_ptr)
(i32.mul (local.get $i) (i32.const 4))))
(i32.load (i32.add (local.get $array_ptr)
(i32.mul (i32.add (local.get $i) (i32.const 1)) (i32.const 4)))))
(i32.add
(i32.load (i32.add (local.get $array_ptr)
(i32.mul (i32.add (local.get $i) (i32.const 2)) (i32.const 4))))
(i32.load (i32.add (local.get $array_ptr)
(i32.mul (i32.add (local.get $i) (i32.const 3)) (i32.const 4))))))))
(local.set $i (i32.add (local.get $i) (i32.const 4)))
(br $unrolled_loop))
;; 处理剩余元素
(loop $remainder_loop
(if (i32.ge_u (local.get $i) (local.get $length))
(then (br $remainder_loop)))
(local.set $sum
(i32.add (local.get $sum)
(i32.load (i32.add (local.get $array_ptr)
(i32.mul (local.get $i) (i32.const 4))))))
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $remainder_loop))
local.get $sum)
(export "matrix_multiply_trace" (func $matrix_multiply_trace))
(export "complex_nested_loops" (func $complex_nested_loops))
(export "unrolled_sum" (func $unrolled_sum)))
异常处理(实验性)
6.3.1 异常处理基础
WebAssembly 的异常处理仍在发展中,以下是基本概念:
(module
;; 定义异常标签
(tag $division_by_zero_error)
(tag $overflow_error (param i32))
;; 可能抛出异常的除法函数
(func $safe_divide (param $a i32) (param $b i32) (result i32)
;; 检查除零
(if (i32.eqz (local.get $b))
(then (throw $division_by_zero_error)))
;; 检查溢出(简化检查)
(if (i32.and
(i32.eq (local.get $a) (i32.const 0x80000000))
(i32.eq (local.get $b) (i32.const -1)))
(then (throw $overflow_error (local.get $a))))
;; 正常除法
i32.div_s (local.get $a) (local.get $b))
;; 异常处理示例
(func $division_with_error_handling (param $a i32) (param $b i32) (result i32)
;; try-catch 块
(try (result i32)
;; try 块:尝试执行可能出错的代码
(do
(call $safe_divide (local.get $a) (local.get $b)))
;; catch 块:处理除零异常
(catch $division_by_zero_error
;; 返回特殊值表示除零错误
(i32.const -1))
;; catch 块:处理溢出异常
(catch $overflow_error
;; 参数已经在栈上,直接丢弃并返回最小值
drop
(i32.const 0x80000000))))
;; 嵌套异常处理
(func $nested_exception_handling (param $values_ptr i32) (param $count i32) (result i32)
(local $i i32)
(local $sum i32)
(local $value i32)
(local.set $sum (i32.const 0))
(local.set $i (i32.const 0))
;; 外层异常处理
(try (result i32)
(do
;; 遍历数组
(loop $process_loop
(if (i32.ge_u (local.get $i) (local.get $count))
(then (br $process_loop)))
;; 读取值
(local.set $value
(i32.load
(i32.add (local.get $values_ptr)
(i32.mul (local.get $i) (i32.const 4)))))
;; 内层异常处理:处理每个元素
(try
(do
;; 尝试用当前和除以当前值
(local.set $sum
(call $safe_divide (local.get $sum) (local.get $value))))
;; 处理除零:跳过这个值
(catch $division_by_zero_error
nop)
;; 处理溢出:使用安全值
(catch $overflow_error
drop
(local.set $sum (i32.const 1))))
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $process_loop))
;; 返回最终和
local.get $sum)
;; 外层捕获:处理意外情况
(catch_all
;; 返回错误码
(i32.const -999))))
;; 资源清理模式(模拟 finally)
(func $resource_management (param $resource_id i32) (result i32)
(local $result i32)
(local $resource_acquired i32)
;; 获取资源
(local.set $resource_acquired (i32.const 1))
;; 主要逻辑(可能抛出异常)
(try (result i32)
(do
;; 模拟可能失败的操作
(if (i32.eq (local.get $resource_id) (i32.const 13))
(then (throw $division_by_zero_error)))
;; 正常处理
(local.set $result (i32.mul (local.get $resource_id) (i32.const 10)))
local.get $result)
;; 异常处理
(catch_all
(local.set $result (i32.const -1))
local.get $result))
;; 资源清理(无论是否有异常都会执行)
(if (local.get $resource_acquired)
(then
;; 释放资源的逻辑
(local.set $resource_acquired (i32.const 0))))
local.get $result)
(export "safe_divide" (func $safe_divide))
(export "division_with_error_handling" (func $division_with_error_handling))
(export "nested_exception_handling" (func $nested_exception_handling))
(export "resource_management" (func $resource_management)))
6.3.2 错误处理最佳实践
在异常处理不可用时,使用传统的错误处理模式:
(module
;; 错误码定义
(global $ERROR_NONE i32 (i32.const 0))
(global $ERROR_INVALID_PARAM i32 (i32.const 1))
(global $ERROR_OUT_OF_MEMORY i32 (i32.const 2))
(global $ERROR_DIVISION_BY_ZERO i32 (i32.const 3))
(global $ERROR_OVERFLOW i32 (i32.const 4))
;; 全局错误状态
(global $last_error (mut i32) (i32.const 0))
;; 设置错误状态
(func $set_error (param $error_code i32)
(global.set $last_error (local.get $error_code)))
;; 获取错误状态
(func $get_error (result i32)
(global.get $last_error))
;; 清除错误状态
(func $clear_error
(global.set $last_error (global.get $ERROR_NONE)))
;; 结果和错误组合类型(模拟 Result<T, E>)
;; 使用内存布局:[error_code][value]
(func $create_result (param $error_code i32) (param $value i32) (param $result_ptr i32)
(i32.store (local.get $result_ptr) (local.get $error_code))
(i32.store (i32.add (local.get $result_ptr) (i32.const 4)) (local.get $value)))
;; 检查结果是否成功
(func $result_is_ok (param $result_ptr i32) (result i32)
(i32.eqz (i32.load (local.get $result_ptr))))
;; 获取结果值(假设已检查成功)
(func $result_get_value (param $result_ptr i32) (result i32)
(i32.load (i32.add (local.get $result_ptr) (i32.const 4))))
;; 获取错误码
(func $result_get_error (param $result_ptr i32) (result i32)
(i32.load (local.get $result_ptr)))
;; 安全的数学操作
(func $safe_add (param $a i32) (param $b i32) (param $result_ptr i32)
(local $sum i64)
;; 使用64位运算检查32位溢出
(local.set $sum
(i64.add
(i64.extend_i32_s (local.get $a))
(i64.extend_i32_s (local.get $b))))
;; 检查是否超出32位范围
(if (i64.or
(i64.gt_s (local.get $sum) (i64.const 0x7FFFFFFF))
(i64.lt_s (local.get $sum) (i64.const -0x80000000)))
(then
;; 溢出错误
(call $create_result
(global.get $ERROR_OVERFLOW)
(i32.const 0)
(local.get $result_ptr)))
(else
;; 成功
(call $create_result
(global.get $ERROR_NONE)
(i32.wrap_i64 (local.get $sum))
(local.get $result_ptr)))))
(func $safe_multiply (param $a i32) (param $b i32) (param $result_ptr i32)
(local $product i64)
;; 使用64位运算检查32位溢出
(local.set $product
(i64.mul
(i64.extend_i32_s (local.get $a))
(i64.extend_i32_s (local.get $b))))
;; 检查是否超出32位范围
(if (i64.or
(i64.gt_s (local.get $product) (i64.const 0x7FFFFFFF))
(i64.lt_s (local.get $product) (i64.const -0x80000000)))
(then
;; 溢出错误
(call $create_result
(global.get $ERROR_OVERFLOW)
(i32.const 0)
(local.get $result_ptr)))
(else
;; 成功
(call $create_result
(global.get $ERROR_NONE)
(i32.wrap_i64 (local.get $product))
(local.get $result_ptr)))))
(func $safe_divide (param $a i32) (param $b i32) (param $result_ptr i32)
;; 检查除零
(if (i32.eqz (local.get $b))
(then
(call $create_result
(global.get $ERROR_DIVISION_BY_ZERO)
(i32.const 0)
(local.get $result_ptr))
(return)))
;; 检查最小值除以-1的特殊情况
(if (i32.and
(i32.eq (local.get $a) (i32.const 0x80000000))
(i32.eq (local.get $b) (i32.const -1)))
(then
(call $create_result
(global.get $ERROR_OVERFLOW)
(i32.const 0)
(local.get $result_ptr))
(return)))
;; 正常除法
(call $create_result
(global.get $ERROR_NONE)
(i32.div_s (local.get $a) (local.get $b))
(local.get $result_ptr)))
;; 错误传播示例
(func $complex_calculation (param $a i32) (param $b i32) (param $c i32) (param $result_ptr i32)
(local $temp_result i64) ;; 8字节临时结果
(local $intermediate i32)
;; 分配临时结果空间
(local.set $temp_result (i64.const 0))
;; 第一步:a + b
(call $safe_add (local.get $a) (local.get $b) (i32.wrap_i64 (local.get $temp_result)))
;; 检查第一步是否成功
(if (i32.eqz (call $result_is_ok (i32.wrap_i64 (local.get $temp_result))))
(then
;; 传播错误
(call $create_result
(call $result_get_error (i32.wrap_i64 (local.get $temp_result)))
(i32.const 0)
(local.get $result_ptr))
(return)))
;; 获取中间结果
(local.set $intermediate (call $result_get_value (i32.wrap_i64 (local.get $temp_result))))
;; 第二步:result * c
(call $safe_multiply (local.get $intermediate) (local.get $c) (i32.wrap_i64 (local.get $temp_result)))
;; 检查第二步是否成功
(if (i32.eqz (call $result_is_ok (i32.wrap_i64 (local.get $temp_result))))
(then
;; 传播错误
(call $create_result
(call $result_get_error (i32.wrap_i64 (local.get $temp_result)))
(i32.const 0)
(local.get $result_ptr))
(return)))
;; 所有操作都成功,复制最终结果
(call $create_result
(global.get $ERROR_NONE)
(call $result_get_value (i32.wrap_i64 (local.get $temp_result)))
(local.get $result_ptr)))
(export "set_error" (func $set_error))
(export "get_error" (func $get_error))
(export "clear_error" (func $clear_error))
(export "result_is_ok" (func $result_is_ok))
(export "result_get_value" (func $result_get_value))
(export "result_get_error" (func $result_get_error))
(export "safe_add" (func $safe_add))
(export "safe_multiply" (func $safe_multiply))
(export "safe_divide" (func $safe_divide))
(export "complex_calculation" (func $complex_calculation)))
性能优化技巧
6.4.1 分支预测优化
(module
;; 分支预测友好的代码结构
(func $optimized_search (param $array_ptr i32) (param $length i32) (param $target i32) (result i32)
(local $i i32)
(local $value i32)
;; 将最常见的情况放在 then 分支
(loop $search_loop
(if (i32.ge_u (local.get $i) (local.get $length))
(then (br $search_loop))) ;; 跳出循环(不常见)
(local.set $value
(i32.load (i32.add (local.get $array_ptr)
(i32.mul (local.get $i) (i32.const 4)))))
;; 大多数情况下不会找到目标(继续循环)
(if (i32.ne (local.get $value) (local.get $target))
(then
;; 常见情况:继续搜索
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $search_loop))
(else
;; 不常见情况:找到目标
(return (local.get $i))))
;; 这里不会执行到
unreachable)
;; 没找到
i32.const -1)
;; 减少分支的优化
(func $branchless_max (param $a i32) (param $b i32) (result i32)
;; 使用 select 指令避免分支
(select
(local.get $a)
(local.get $b)
(i32.gt_s (local.get $a) (local.get $b))))
(func $branchless_abs (param $x i32) (result i32)
(local $mask i32)
;; 算术右移获取符号掩码
(local.set $mask (i32.shr_s (local.get $x) (i32.const 31)))
;; 无分支绝对值:(x ^ mask) - mask
(i32.sub
(i32.xor (local.get $x) (local.get $mask))
(local.get $mask)))
;; 分支表优化
(func $optimized_state_machine (param $state i32) (param $input i32) (result i32)
;; 将状态转换表存储在内存中以提高效率
(local $table_offset i32)
;; 状态转换表基址
(local.set $table_offset (i32.const 0x1000))
;; 计算表索引:state * 4 + input
;; 假设每个状态有4个可能的输入
(i32.load
(i32.add
(local.get $table_offset)
(i32.mul
(i32.add
(i32.mul (local.get $state) (i32.const 4))
(local.get $input))
(i32.const 4)))))
(export "optimized_search" (func $optimized_search))
(export "branchless_max" (func $branchless_max))
(export "branchless_abs" (func $branchless_abs))
(export "optimized_state_machine" (func $optimized_state_machine)))
6.4.2 循环优化技术
(module
;; 循环强度减少
(func $strength_reduction (param $array_ptr i32) (param $length i32) (result i32)
(local $sum i32)
(local $i i32)
(local $current_ptr i32)
;; 使用指针递增代替乘法
(local.set $current_ptr (local.get $array_ptr))
(loop $strength_loop
(if (i32.ge_u (local.get $i) (local.get $length))
(then (br $strength_loop)))
;; 直接使用指针,避免地址计算
(local.set $sum
(i32.add (local.get $sum) (i32.load (local.get $current_ptr))))
;; 指针递增(比乘法更快)
(local.set $current_ptr (i32.add (local.get $current_ptr) (i32.const 4)))
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $strength_loop))
local.get $sum)
;; 循环分割优化
(func $loop_splitting (param $array_ptr i32) (param $length i32) (param $threshold i32) (result i32)
(local $sum i32)
(local $i i32)
(local $value i32)
;; 第一个循环:处理小于阈值的元素
(local.set $i (i32.const 0))
(loop $small_values_loop
(if (i32.ge_u (local.get $i) (local.get $length))
(then (br $small_values_loop)))
(local.set $value
(i32.load (i32.add (local.get $array_ptr)
(i32.mul (local.get $i) (i32.const 4)))))
;; 只处理小值
(if (i32.lt_s (local.get $value) (local.get $threshold))
(then
(local.set $sum (i32.add (local.get $sum) (local.get $value)))))
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $small_values_loop))
;; 第二个循环:处理大于等于阈值的元素
(local.set $i (i32.const 0))
(loop $large_values_loop
(if (i32.ge_u (local.get $i) (local.get $length))
(then (br $large_values_loop)))
(local.set $value
(i32.load (i32.add (local.get $array_ptr)
(i32.mul (local.get $i) (i32.const 4)))))
;; 只处理大值
(if (i32.ge_s (local.get $value) (local.get $threshold))
(then
(local.set $sum (i32.add (local.get $sum) (local.get $value)))))
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $large_values_loop))
local.get $sum)
;; 循环融合
(func $loop_fusion (param $a_ptr i32) (param $b_ptr i32) (param $c_ptr i32) (param $length i32)
(local $i i32)
(local $a_val i32)
(local $b_val i32)
;; 融合两个独立的循环到一个
(loop $fused_loop
(if (i32.ge_u (local.get $i) (local.get $length))
(then (br $fused_loop)))
;; 原本的第一个循环:A[i] = A[i] * 2
(local.set $a_val
(i32.load (i32.add (local.get $a_ptr)
(i32.mul (local.get $i) (i32.const 4)))))
(i32.store
(i32.add (local.get $a_ptr) (i32.mul (local.get $i) (i32.const 4)))
(i32.mul (local.get $a_val) (i32.const 2)))
;; 原本的第二个循环:C[i] = A[i] + B[i]
(local.set $a_val
(i32.load (i32.add (local.get $a_ptr)
(i32.mul (local.get $i) (i32.const 4)))))
(local.set $b_val
(i32.load (i32.add (local.get $b_ptr)
(i32.mul (local.get $i) (i32.const 4)))))
(i32.store
(i32.add (local.get $c_ptr) (i32.mul (local.get $i) (i32.const 4)))
(i32.add (local.get $a_val) (local.get $b_val)))
(local.set $i (i32.add (local.get $i) (i32.const 1)))
(br $fused_loop)))
(export "strength_reduction" (func $strength_reduction))
(export "loop_splitting" (func $loop_splitting))
(export "loop_fusion" (func $loop_fusion)))
本章小结
通过本章学习,你已经掌握了:
- 结构化控制流:条件分支、多路跳转的高级技巧
- 循环控制:各种循环模式和嵌套循环的高效实现
- 异常处理:现代异常机制和传统错误处理模式
- 性能优化:分支预测、循环优化等关键技术
这些技能为编写高效、可维护的 WebAssembly 程序奠定了坚实基础。
📝 进入下一步:第7章 JavaScript 交互
🎯 重点技能:
- ✅ 条件分支优化
- ✅ 循环设计模式
- ✅ 异常处理策略
- ✅ 控制流性能调优
- ✅ 复杂逻辑实现