wa-lang.org/wazero@v1.0.2/internal/wasm/global_test.go (about)

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