v2 / vlib / wasm / constant.v
171 lines · 146 sloc · 4.48 KB · c51d30bf5309653c6b573ec815268e69a78ea8cc
Raw
1// Copyright (c) 2023 l-m.dev. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module wasm
5
6import encoding.leb128
7
8// constexpr_value returns a constant expression that evaluates to a single value.
9pub fn constexpr_value[T](v T) ConstExpression {
10 mut expr := ConstExpression{}
11
12 $if T is i64 {
13 expr.i64_const(v)
14 } $else $if T is $int {
15 expr.i32_const(i32(v))
16 } $else $if T is f32 {
17 expr.f32_const(v)
18 } $else $if T is f64 {
19 expr.f64_const(v)
20 } $else {
21 $compile_error('values can only be int, i32, i64, f32, f64')
22 }
23
24 return expr
25}
26
27// constexpr_value_zero returns a constant expression that evaluates to zero.
28pub fn constexpr_value_zero(v ValType) ConstExpression {
29 mut expr := ConstExpression{}
30
31 match v {
32 .i32_t {
33 expr.i32_const(0)
34 }
35 .i64_t {
36 expr.i64_const(0)
37 }
38 .f32_t {
39 expr.f32_const(0.0)
40 }
41 .f64_t {
42 expr.f64_const(0.0)
43 }
44 .funcref_t, .externref_t {
45 expr.ref_null(RefType(v))
46 }
47 .v128_t {
48 panic('type `v128_t` not permitted in a constant expression')
49 }
50 }
51
52 return expr
53}
54
55// constexpr_ref_null returns a constant expression that evaluates to a null reference.
56pub fn constexpr_ref_null(rt RefType) ConstExpression {
57 mut expr := ConstExpression{}
58
59 expr.ref_null(rt)
60
61 return expr
62}
63
64// WebAssembly constant expressions are permitted to use a subset of valid instructions.
65pub struct ConstExpression {
66mut:
67 call_patches []CallPatch
68 code []u8
69}
70
71// i32_const places a constant i32 value on the stack.
72// WebAssembly instruction: `i32.const`.
73pub fn (mut expr ConstExpression) i32_const(v i32) {
74 expr.code << 0x41 // i32.const
75 expr.code << leb128.encode_i32(v)
76}
77
78// i64_const places a constant i64 value on the stack.
79// WebAssembly instruction: `i64.const`.
80pub fn (mut expr ConstExpression) i64_const(v i64) {
81 expr.code << 0x42 // i64.const
82 expr.code << leb128.encode_i64(v)
83}
84
85// f32_const places a constant f32 value on the stack.
86// WebAssembly instruction: `f32.const`.
87pub fn (mut expr ConstExpression) f32_const(v f32) {
88 expr.code << 0x43 // f32.const
89 push_f32(mut expr.code, v)
90}
91
92// f64_const places a constant f64 value on the stack.
93// WebAssembly instruction: `f64.const`.
94pub fn (mut expr ConstExpression) f64_const(v f64) {
95 expr.code << 0x44 // f64.const
96 push_f64(mut expr.code, v)
97}
98
99// add adds two values on the stack with type `typ`.
100// WebAssembly instructions: `i32|i64.add`.
101pub fn (mut expr ConstExpression) add(typ NumType) {
102 assert typ in [.i32_t, .i64_t]
103
104 match typ {
105 .i32_t { expr.code << 0x6A } // i32.add
106 .i64_t { expr.code << 0x7C } // i64.add
107 else {}
108 }
109}
110
111// sub subtracts two values on the stack with type `typ`.
112// WebAssembly instructions: `i32|i64.sub`.
113pub fn (mut expr ConstExpression) sub(typ NumType) {
114 assert typ in [.i32_t, .i64_t]
115
116 match typ {
117 .i32_t { expr.code << 0x6B } // i32.sub
118 .i64_t { expr.code << 0x7D } // i64.sub
119 else {}
120 }
121}
122
123// mul multiplies two values on the stack with type `typ`.
124// WebAssembly instructions: `i32|i64.mul`.
125pub fn (mut expr ConstExpression) mul(typ NumType) {
126 assert typ in [.i32_t, .i64_t]
127
128 match typ {
129 .i32_t { expr.code << 0x6C } // i32.mul
130 .i64_t { expr.code << 0x7E } // i64.mul
131 else {}
132 }
133}
134
135// global_get places the value of the global at the index `global` on the stack.
136// Constant expressions are only allowed to refer to imported globals.
137// WebAssembly instruction: `global.get`.
138pub fn (mut expr ConstExpression) global_get(global GlobalImportIndex) {
139 expr.code << 0x23 // global.get
140 expr.code << leb128.encode_u32(u32(global))
141}
142
143// ref_null places a null reference on the stack.
144// WebAssembly instruction: `ref.null`.
145pub fn (mut expr ConstExpression) ref_null(rt RefType) {
146 expr.code << 0xD0 // ref.null
147 expr.code << u8(rt)
148}
149
150// ref_func places a reference to a function with `name` on the stack.
151// If this function does not exist when calling `compile` on the module, it will panic.
152// WebAssembly instruction: `ref.func`.
153pub fn (mut expr ConstExpression) ref_func(name string) {
154 expr.code << 0xD2 // ref.func
155 expr.call_patches << FunctionCallPatch{
156 name: name
157 pos: expr.code.len
158 }
159}
160
161// ref_func places a reference to an imported function with `name` on the stack.
162// If the imported function does not exist when calling `compile` on the module, it will panic.
163// WebAssembly instruction: `ref.func`.
164pub fn (mut expr ConstExpression) ref_func_import(mod string, name string) {
165 expr.code << 0xD2 // ref.func
166 expr.call_patches << ImportCallPatch{
167 mod: mod
168 name: name
169 pos: expr.code.len
170 }
171}
172