github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/wasm/global_test.go (about) 1 package wasm 2 3 import ( 4 "context" 5 "math" 6 "testing" 7 8 "github.com/bananabytelabs/wazero/api" 9 "github.com/bananabytelabs/wazero/internal/internalapi" 10 "github.com/bananabytelabs/wazero/internal/leb128" 11 "github.com/bananabytelabs/wazero/internal/testing/require" 12 "github.com/bananabytelabs/wazero/internal/u64" 13 ) 14 15 func TestGlobalTypes(t *testing.T) { 16 tests := []struct { 17 name string 18 global api.Global 19 expectedType api.ValueType 20 expectedVal uint64 21 expectedString string 22 expectedMutable bool 23 }{ 24 { 25 name: "i32 - immutable", 26 global: constantGlobal{g: &GlobalInstance{ 27 Type: GlobalType{ValType: ValueTypeI32}, 28 Val: 1, 29 }}, 30 expectedType: ValueTypeI32, 31 expectedVal: 1, 32 expectedString: "global(1)", 33 }, 34 { 35 name: "i32 - immutable - max", 36 global: constantGlobal{g: &GlobalInstance{ 37 Type: GlobalType{ValType: ValueTypeI32}, 38 Val: math.MaxInt32, 39 }}, 40 expectedType: ValueTypeI32, 41 expectedVal: math.MaxInt32, 42 expectedString: "global(2147483647)", 43 }, 44 { 45 name: "i64 - immutable", 46 global: constantGlobal{g: &GlobalInstance{ 47 Type: GlobalType{ValType: ValueTypeI64}, 48 Val: 1, 49 }}, 50 expectedType: ValueTypeI64, 51 expectedVal: 1, 52 expectedString: "global(1)", 53 }, 54 { 55 name: "i64 - immutable - max", 56 global: constantGlobal{g: &GlobalInstance{ 57 Type: GlobalType{ValType: ValueTypeI64}, 58 Val: math.MaxInt64, 59 }}, 60 expectedType: ValueTypeI64, 61 expectedVal: math.MaxInt64, 62 expectedString: "global(9223372036854775807)", 63 }, 64 { 65 name: "f32 - immutable", 66 global: constantGlobal{g: &GlobalInstance{ 67 Type: GlobalType{ValType: ValueTypeF32}, 68 Val: api.EncodeF32(1.0), 69 }}, 70 expectedType: ValueTypeF32, 71 expectedVal: api.EncodeF32(1.0), 72 expectedString: "global(1.000000)", 73 }, 74 { 75 name: "f32 - immutable - max", 76 global: constantGlobal{g: &GlobalInstance{ 77 Type: GlobalType{ValType: ValueTypeF32}, 78 Val: api.EncodeF32(math.MaxFloat32), 79 }}, 80 expectedType: ValueTypeF32, 81 expectedVal: api.EncodeF32(math.MaxFloat32), 82 expectedString: "global(340282346638528859811704183484516925440.000000)", 83 }, 84 { 85 name: "f64 - immutable", 86 global: constantGlobal{g: &GlobalInstance{ 87 Type: GlobalType{ValType: ValueTypeF64}, 88 Val: api.EncodeF64(1.0), 89 }}, 90 expectedType: ValueTypeF64, 91 expectedVal: api.EncodeF64(1.0), 92 expectedString: "global(1.000000)", 93 }, 94 { 95 name: "f64 - immutable - max", 96 global: constantGlobal{g: &GlobalInstance{ 97 Type: GlobalType{ValType: ValueTypeF64}, 98 Val: api.EncodeF64(math.MaxFloat64), 99 }}, 100 expectedType: ValueTypeF64, 101 expectedVal: api.EncodeF64(math.MaxFloat64), 102 expectedString: "global(179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000)", 103 }, 104 { 105 name: "i32 - mutable", 106 global: mutableGlobal{internalapi.WazeroOnlyType{}, &GlobalInstance{ 107 Type: GlobalType{ValType: ValueTypeI32, Mutable: true}, 108 Val: 1, 109 }}, 110 expectedType: ValueTypeI32, 111 expectedVal: 1, 112 expectedString: "global(1)", 113 expectedMutable: true, 114 }, 115 { 116 name: "i64 - mutable", 117 global: mutableGlobal{internalapi.WazeroOnlyType{}, &GlobalInstance{ 118 Type: GlobalType{ValType: ValueTypeI64, Mutable: true}, 119 Val: 1, 120 }}, 121 expectedType: ValueTypeI64, 122 expectedVal: 1, 123 expectedString: "global(1)", 124 expectedMutable: true, 125 }, 126 { 127 name: "f32 - mutable", 128 global: mutableGlobal{internalapi.WazeroOnlyType{}, &GlobalInstance{ 129 Type: GlobalType{ValType: ValueTypeF32, Mutable: true}, 130 Val: api.EncodeF32(1.0), 131 }}, 132 expectedType: ValueTypeF32, 133 expectedVal: api.EncodeF32(1.0), 134 expectedString: "global(1.000000)", 135 expectedMutable: true, 136 }, 137 { 138 name: "f64 - mutable", 139 global: mutableGlobal{internalapi.WazeroOnlyType{}, &GlobalInstance{ 140 Type: GlobalType{ValType: ValueTypeF64, Mutable: true}, 141 Val: api.EncodeF64(1.0), 142 }}, 143 expectedType: ValueTypeF64, 144 expectedVal: api.EncodeF64(1.0), 145 expectedString: "global(1.000000)", 146 expectedMutable: true, 147 }, 148 } 149 150 for _, tt := range tests { 151 tc := tt 152 153 t.Run(tc.name, func(t *testing.T) { 154 require.Equal(t, tc.expectedType, tc.global.Type()) 155 require.Equal(t, tc.expectedVal, tc.global.Get()) 156 require.Equal(t, tc.expectedString, tc.global.String()) 157 158 mutable, ok := tc.global.(api.MutableGlobal) 159 require.Equal(t, tc.expectedMutable, ok) 160 if ok { 161 mutable.Set(2) 162 require.Equal(t, uint64(2), tc.global.Get()) 163 164 mutable.Set(tc.expectedVal) // Set it back! 165 require.Equal(t, tc.expectedVal, tc.global.Get()) 166 } 167 }) 168 } 169 } 170 171 func TestPublicModule_Global(t *testing.T) { 172 tests := []struct { 173 name string 174 module *Module // module as wat doesn't yet support globals 175 expected api.Global 176 }{ 177 { 178 name: "no global", 179 module: &Module{}, 180 }, 181 { 182 name: "global not exported", 183 module: &Module{ 184 GlobalSection: []Global{ 185 { 186 Type: GlobalType{ValType: ValueTypeI32}, 187 Init: ConstantExpression{Opcode: OpcodeI32Const, Data: const1}, 188 }, 189 }, 190 }, 191 }, 192 { 193 name: "global exported - immutable I32", 194 module: &Module{ 195 GlobalSection: []Global{ 196 { 197 Type: GlobalType{ValType: ValueTypeI32}, 198 Init: ConstantExpression{Opcode: OpcodeI32Const, Data: const1}, 199 }, 200 }, 201 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}}, 202 }, 203 expected: constantGlobal{g: &GlobalInstance{ 204 Type: GlobalType{ValType: ValueTypeI32}, 205 Val: 1, 206 }}, 207 }, 208 { 209 name: "global exported - immutable I64", 210 module: &Module{ 211 GlobalSection: []Global{ 212 { 213 Type: GlobalType{ValType: ValueTypeI64}, 214 Init: ConstantExpression{Opcode: OpcodeI64Const, Data: leb128.EncodeInt64(1)}, 215 }, 216 }, 217 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}}, 218 }, 219 expected: constantGlobal{g: &GlobalInstance{ 220 Type: GlobalType{ValType: ValueTypeI64}, 221 Val: 1, 222 }}, 223 }, 224 { 225 name: "global exported - immutable F32", 226 module: &Module{ 227 GlobalSection: []Global{ 228 { 229 Type: GlobalType{ValType: ValueTypeF32}, 230 Init: ConstantExpression{ 231 Opcode: OpcodeF32Const, 232 Data: u64.LeBytes(api.EncodeF32(1.0)), 233 }, 234 }, 235 }, 236 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}}, 237 }, 238 expected: constantGlobal{g: &GlobalInstance{ 239 Type: GlobalType{ValType: ValueTypeF32}, 240 Val: api.EncodeF32(1.0), 241 }}, 242 }, 243 { 244 name: "global exported - immutable F64", 245 module: &Module{ 246 GlobalSection: []Global{ 247 { 248 Type: GlobalType{ValType: ValueTypeF64}, 249 Init: ConstantExpression{ 250 Opcode: OpcodeF64Const, 251 Data: u64.LeBytes(api.EncodeF64(1.0)), 252 }, 253 }, 254 }, 255 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}}, 256 }, 257 expected: constantGlobal{g: &GlobalInstance{ 258 Type: GlobalType{ValType: ValueTypeF64}, 259 Val: api.EncodeF64(1.0), 260 }}, 261 }, 262 { 263 name: "global exported - mutable I32", 264 module: &Module{ 265 GlobalSection: []Global{ 266 { 267 Type: GlobalType{ValType: ValueTypeI32, Mutable: true}, 268 Init: ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(1)}, 269 }, 270 }, 271 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}}, 272 }, 273 expected: mutableGlobal{ 274 internalapi.WazeroOnlyType{}, &GlobalInstance{ 275 Type: GlobalType{ValType: ValueTypeI32, Mutable: true}, Val: 1, 276 }, 277 }, 278 }, 279 { 280 name: "global exported - mutable I64", 281 module: &Module{ 282 GlobalSection: []Global{ 283 { 284 Type: GlobalType{ValType: ValueTypeI64, Mutable: true}, 285 Init: ConstantExpression{Opcode: OpcodeI64Const, Data: leb128.EncodeInt64(1)}, 286 }, 287 }, 288 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}}, 289 }, 290 expected: mutableGlobal{ 291 internalapi.WazeroOnlyType{}, &GlobalInstance{ 292 Type: GlobalType{ValType: ValueTypeI64, Mutable: true}, Val: 1, 293 }, 294 }, 295 }, 296 { 297 name: "global exported - mutable F32", 298 module: &Module{ 299 GlobalSection: []Global{ 300 { 301 Type: GlobalType{ValType: ValueTypeF32, Mutable: true}, 302 Init: ConstantExpression{ 303 Opcode: OpcodeF32Const, 304 Data: u64.LeBytes(api.EncodeF32(1.0)), 305 }, 306 }, 307 }, 308 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}}, 309 }, 310 expected: mutableGlobal{ 311 internalapi.WazeroOnlyType{}, &GlobalInstance{ 312 Type: GlobalType{ValType: ValueTypeF32, Mutable: true}, Val: api.EncodeF32(1.0), 313 }, 314 }, 315 }, 316 { 317 name: "global exported - mutable F64", 318 module: &Module{ 319 GlobalSection: []Global{ 320 { 321 Type: GlobalType{ValType: ValueTypeF64, Mutable: true}, 322 Init: ConstantExpression{ 323 Opcode: OpcodeF64Const, 324 Data: u64.LeBytes(api.EncodeF64(1.0)), 325 }, 326 }, 327 }, 328 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}}, 329 }, 330 expected: mutableGlobal{ 331 internalapi.WazeroOnlyType{}, &GlobalInstance{ 332 Type: GlobalType{ValType: ValueTypeF64, Mutable: true}, Val: api.EncodeF64(1.0), 333 }, 334 }, 335 }, 336 } 337 338 for _, tt := range tests { 339 tc := tt 340 341 s := newStore() 342 t.Run(tc.name, func(t *testing.T) { 343 // Instantiate the module and get the export of the above global 344 module, err := s.Instantiate(context.Background(), tc.module, t.Name(), nil, nil) 345 require.NoError(t, err) 346 347 if global := module.ExportedGlobal("global"); tc.expected != nil { 348 require.Equal(t, tc.expected, global) 349 } else { 350 require.Nil(t, global) 351 } 352 }) 353 } 354 }