@@ -26,7 +26,7 @@ function emit_a() {
26
26
// value 0 to 9 indicating the function called, or will throw an exception if
27
27
// the table entry is empty.
28
28
29
- function emit_b ( insn ) {
29
+ function emit_b ( insn , t0 , t1 ) {
30
30
print (
31
31
`
32
32
(module
@@ -36,22 +36,27 @@ function emit_b(insn) {
36
36
(import "a" "ef2" (func (result i32)))
37
37
(import "a" "ef3" (func (result i32)))
38
38
(import "a" "ef4" (func (result i32))) ;; index 4
39
- (table 30 30 funcref)
40
- (elem (i32.const 2) 3 1 4 1)
39
+ (table $t0 30 30 funcref)
40
+ (table $t1 30 30 funcref)
41
+ (elem (table $t${ t0 } ) (i32.const 2) func 3 1 4 1)
41
42
(elem funcref
42
43
(ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
43
- (elem (i32.const 12) 7 5 2 3 6)
44
+ (elem (table $t ${ t0 } ) ( i32.const 12) func 7 5 2 3 6)
44
45
(elem funcref
45
46
(ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
47
+ (elem (table $t${ t1 } ) (i32.const 3) func 1 3 1 4)
48
+ (elem (table $t${ t1 } ) (i32.const 11) func 6 3 2 5 7)
46
49
(func (result i32) (i32.const 5)) ;; index 5
47
50
(func (result i32) (i32.const 6))
48
51
(func (result i32) (i32.const 7))
49
52
(func (result i32) (i32.const 8))
50
53
(func (result i32) (i32.const 9)) ;; index 9
51
54
(func (export "test")
52
55
${ insn } )
53
- (func (export "check") (param i32) (result i32)
54
- (call_indirect (type 0) (local.get 0)))
56
+ (func (export "check_t0") (param i32) (result i32)
57
+ (call_indirect $t${ t0 } (type 0) (local.get 0)))
58
+ (func (export "check_t1") (param i32) (result i32)
59
+ (call_indirect $t${ t1 } (type 0) (local.get 0)))
55
60
)
56
61
` ) ;
57
62
}
@@ -60,16 +65,29 @@ function emit_b(insn) {
60
65
// given |instruction| to modify the table, and then probes the table by making
61
66
// indirect calls, one for each element of |expected_result_vector|. The
62
67
// results are compared to those in the vector.
68
+ //
69
+ // "dest_table" may be t0 or t1.
63
70
64
- function tab_test ( instruction , expected_result_vector ) {
65
- emit_b ( instruction ) ;
71
+ function tab_test ( args , t0 , t1 , dest_table , expected_t0 , expected_t1 ) {
72
+ if ( typeof args != "string" )
73
+ emit_b ( "(nop)" , t0 , t1 ) ;
74
+ else
75
+ emit_b ( `(table.copy $t${ dest_table } $t${ t0 } ${ args } )` , t0 , t1 ) ;
66
76
print ( `(invoke "test")` ) ;
67
- for ( let i = 0 ; i < expected_result_vector . length ; i ++ ) {
68
- let expected = expected_result_vector [ i ] ;
77
+ for ( let i = 0 ; i < expected_t0 . length ; i ++ ) {
78
+ let expected = expected_t0 [ i ] ;
69
79
if ( expected === undefined ) {
70
- print ( `(assert_trap (invoke "check " (i32.const ${ i } )) "uninitialized element")` ) ;
80
+ print ( `(assert_trap (invoke "check_t0 " (i32.const ${ i } )) "uninitialized element")` ) ;
71
81
} else {
72
- print ( `(assert_return (invoke "check" (i32.const ${ i } )) (i32.const ${ expected } ))` ) ;
82
+ print ( `(assert_return (invoke "check_t0" (i32.const ${ i } )) (i32.const ${ expected } ))` ) ;
83
+ }
84
+ }
85
+ for ( let i = 0 ; i < expected_t1 . length ; i ++ ) {
86
+ let expected = expected_t1 [ i ] ;
87
+ if ( expected === undefined ) {
88
+ print ( `(assert_trap (invoke "check_t1" (i32.const ${ i } )) "uninitialized element")` ) ;
89
+ } else {
90
+ print ( `(assert_return (invoke "check_t1" (i32.const ${ i } )) (i32.const ${ expected } ))` ) ;
73
91
}
74
92
}
75
93
}
@@ -80,50 +98,72 @@ emit_a();
80
98
// to count through the vector entries when debugging.
81
99
let e = undefined ;
82
100
83
- // This just gives the initial state of the table, with its active
84
- // initialisers applied
85
- tab_test ( "(nop)" ,
86
- [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
87
-
88
- // Copy non-null over non-null
89
- tab_test ( "(table.copy (i32.const 13) (i32.const 2) (i32.const 3))" ,
90
- [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 3 , 1 , 4 , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
91
-
92
- // Copy non-null over null
93
- tab_test ( "(table.copy (i32.const 25) (i32.const 15) (i32.const 2))" ,
94
- [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , 3 , 6 , e , e , e ] ) ;
95
-
96
- // Copy null over non-null
97
- tab_test ( "(table.copy (i32.const 13) (i32.const 25) (i32.const 3))" ,
98
- [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , e , e , e , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
99
-
100
- // Copy null over null
101
- tab_test ( "(table.copy (i32.const 20) (i32.const 22) (i32.const 4))" ,
102
- [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
103
-
104
- // Copy null and non-null entries, non overlapping
105
- tab_test ( "(table.copy (i32.const 25) (i32.const 1) (i32.const 3))" ,
106
- [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , 3 , 1 , e , e ] ) ;
107
-
108
- // Copy null and non-null entries, overlapping, backwards
109
- tab_test ( "(table.copy (i32.const 10) (i32.const 12) (i32.const 7))" ,
110
- [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
111
-
112
- // Copy null and non-null entries, overlapping, forwards
113
- tab_test ( "(table.copy (i32.const 12) (i32.const 10) (i32.const 7))" ,
114
- [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , e , e ] ) ;
101
+ for ( let table of [ 0 , 1 ] ) {
102
+ let other_table = ( table + 1 ) % 2 ;
103
+
104
+ // Tests for copying in a single table.
105
+
106
+ // This just gives the initial state of the table, with its active
107
+ // initialisers applied
108
+ tab_test ( false , table , other_table , table ,
109
+ [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e ] ,
110
+ [ e , e , e , 1 , 3 , 1 , 4 , e , e , e , e , 6 , 3 , 2 , 5 , 7 , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
111
+
112
+ // Copy non-null over non-null
113
+ tab_test ( "(i32.const 13) (i32.const 2) (i32.const 3)" , table , other_table , table ,
114
+ [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 3 , 1 , 4 , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e ] ,
115
+ [ e , e , e , 1 , 3 , 1 , 4 , e , e , e , e , 6 , 3 , 2 , 5 , 7 , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
116
+
117
+ // Copy non-null over null
118
+ tab_test ( "(i32.const 25) (i32.const 15) (i32.const 2)" , table , other_table , table ,
119
+ [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , 3 , 6 , e , e , e ] ,
120
+ [ e , e , e , 1 , 3 , 1 , 4 , e , e , e , e , 6 , 3 , 2 , 5 , 7 , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
121
+
122
+ // Copy null over non-null
123
+ tab_test ( "(i32.const 13) (i32.const 25) (i32.const 3)" , table , other_table , table ,
124
+ [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , e , e , e , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e ] ,
125
+ [ e , e , e , 1 , 3 , 1 , 4 , e , e , e , e , 6 , 3 , 2 , 5 , 7 , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
126
+
127
+ // Copy null over null
128
+ tab_test ( "(i32.const 20) (i32.const 22) (i32.const 4)" , table , other_table , table ,
129
+ [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e ] ,
130
+ [ e , e , e , 1 , 3 , 1 , 4 , e , e , e , e , 6 , 3 , 2 , 5 , 7 , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
131
+
132
+ // Copy null and non-null entries, non overlapping
133
+ tab_test ( "(i32.const 25) (i32.const 1) (i32.const 3)" , table , other_table , table ,
134
+ [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , 3 , 1 , e , e ] ,
135
+ [ e , e , e , 1 , 3 , 1 , 4 , e , e , e , e , 6 , 3 , 2 , 5 , 7 , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
136
+
137
+ // Copy null and non-null entries, overlapping, backwards
138
+ tab_test ( "(i32.const 10) (i32.const 12) (i32.const 7)" , table , other_table , table ,
139
+ [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ,
140
+ [ e , e , e , 1 , 3 , 1 , 4 , e , e , e , e , 6 , 3 , 2 , 5 , 7 , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
141
+
142
+ // Copy null and non-null entries, overlapping, forwards
143
+ tab_test ( "(i32.const 12) (i32.const 10) (i32.const 7)" , table , other_table , table ,
144
+ [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , e , e ] ,
145
+ [ e , e , e , 1 , 3 , 1 , 4 , e , e , e , e , 6 , 3 , 2 , 5 , 7 , e , e , e , e , e , e , e , e , e , e , e , e , e , e ] ) ;
146
+
147
+ // Tests for copying from one table to the other. Here, overlap and copy
148
+ // direction don't matter.
149
+
150
+ tab_test ( "(i32.const 10) (i32.const 0) (i32.const 20)" , table , other_table , other_table ,
151
+ [ e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e , e , e , e , e , e , e , e , e , e , e ] ,
152
+ [ e , e , e , 1 , 3 , 1 , 4 , e , e , e , e , e , 3 , 1 , 4 , 1 , e , e , e , e , e , e , 7 , 5 , 2 , 3 , 6 , e , e , e ] ) ;
153
+ }
115
154
116
155
// Out-of-bounds checks.
117
156
118
157
function do_test ( insn1 , insn2 , errText )
119
158
{
120
159
print ( `
121
160
(module
122
- (table 30 30 funcref)
123
- (elem (i32.const 2) 3 1 4 1)
161
+ (table $t0 30 30 funcref)
162
+ (table $t1 30 30 funcref)
163
+ (elem (table $t0) (i32.const 2) func 3 1 4 1)
124
164
(elem funcref
125
165
(ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
126
- (elem (i32.const 12) 7 5 2 3 6)
166
+ (elem (table $t0) ( i32.const 12) func 7 5 2 3 6)
127
167
(elem funcref
128
168
(ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
129
169
(func (result i32) (i32.const 0))
@@ -156,63 +196,65 @@ function tab_test_nofail(insn1, insn2) {
156
196
do_test ( insn1 , insn2 , undefined , undefined ) ;
157
197
}
158
198
159
- // Here we test the boundary-failure cases. The table's valid indices are 0..29
160
- // inclusive.
161
-
162
- // copy: dst range invalid
163
- tab_test2 ( "(table.copy (i32.const 28) (i32.const 1) (i32.const 3))" ,
164
- "" ,
165
- "out of bounds" ) ;
166
-
167
- // copy: dst wraparound end of 32 bit offset space
168
- tab_test2 ( "(table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))" ,
169
- "" ,
170
- "out of bounds" ) ;
171
-
172
- // copy: src range invalid
173
- tab_test2 ( "(table.copy (i32.const 15) (i32.const 25) (i32.const 6))" ,
174
- "" ,
175
- "out of bounds" ) ;
176
-
177
- // copy: src wraparound end of 32 bit offset space
178
- tab_test2 ( "(table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))" ,
179
- "" ,
180
- "out of bounds" ) ;
181
-
182
- // copy: zero length with both offsets in-bounds is OK
183
- tab_test_nofail (
184
- "(table.copy (i32.const 15) (i32.const 25) (i32.const 0))" ,
185
- "" ) ;
186
-
187
- // copy: zero length with dst offset out of bounds at the end of the table is allowed
188
- tab_test2 ( "(table.copy (i32.const 30) (i32.const 15) (i32.const 0))" ,
189
- "" ,
190
- undefined ) ;
191
-
192
- // copy: zero length with dst offset out of bounds past the end of the table is not allowed
193
- tab_test2 ( "(table.copy (i32.const 31) (i32.const 15) (i32.const 0))" ,
194
- "" ,
195
- "out of bounds" ) ;
196
-
197
- // copy: zero length with src offset out of bounds at the end of the table is allowed
198
- tab_test2 ( "(table.copy (i32.const 15) (i32.const 30) (i32.const 0))" ,
199
- "" ,
200
- undefined ) ;
201
-
202
- // copy: zero length with src offset out of bounds past the end of the table is not allowed
203
- tab_test2 ( "(table.copy (i32.const 15) (i32.const 31) (i32.const 0))" ,
204
- "" ,
205
- "out of bounds" ) ;
206
-
207
- // copy: zero length with both dst and src offset out of bounds at the end of the table is allowed
208
- tab_test2 ( "(table.copy (i32.const 30) (i32.const 30) (i32.const 0))" ,
209
- "" ,
210
- undefined ) ;
211
-
212
- // copy: zero length with both dst and src offset out of bounds past the end of the table is not allowed
213
- tab_test2 ( "(table.copy (i32.const 31) (i32.const 31) (i32.const 0))" ,
214
- "" ,
215
- "out of bounds" ) ;
199
+ for ( let dest of [ "$t0" , "$t1" ] ) {
200
+ // Here we test the boundary-failure cases. The table's valid indices are 0..29
201
+ // inclusive.
202
+
203
+ // copy: dst range invalid
204
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 28) (i32.const 1) (i32.const 3))` ,
205
+ "" ,
206
+ "out of bounds" ) ;
207
+
208
+ // copy: dst wraparound end of 32 bit offset space
209
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))` ,
210
+ "" ,
211
+ "out of bounds" ) ;
212
+
213
+ // copy: src range invalid
214
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 15) (i32.const 25) (i32.const 6))` ,
215
+ "" ,
216
+ "out of bounds" ) ;
217
+
218
+ // copy: src wraparound end of 32 bit offset space
219
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))` ,
220
+ "" ,
221
+ "out of bounds" ) ;
222
+
223
+ // copy: zero length with both offsets in-bounds is OK
224
+ tab_test_nofail (
225
+ `(table.copy ${ dest } $t0 (i32.const 15) (i32.const 25) (i32.const 0))` ,
226
+ "" ) ;
227
+
228
+ // copy: zero length with dst offset out of bounds at the end of the table is allowed
229
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 30) (i32.const 15) (i32.const 0))` ,
230
+ "" ,
231
+ undefined ) ;
232
+
233
+ // copy: zero length with dst offset out of bounds past the end of the table is not allowed
234
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 31) (i32.const 15) (i32.const 0))` ,
235
+ "" ,
236
+ "out of bounds" ) ;
237
+
238
+ // copy: zero length with src offset out of bounds at the end of the table is allowed
239
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 15) (i32.const 30) (i32.const 0))` ,
240
+ "" ,
241
+ undefined ) ;
242
+
243
+ // copy: zero length with src offset out of bounds past the end of the table is not allowed
244
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 15) (i32.const 31) (i32.const 0))` ,
245
+ "" ,
246
+ "out of bounds" ) ;
247
+
248
+ // copy: zero length with both dst and src offset out of bounds at the end of the table is allowed
249
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 30) (i32.const 30) (i32.const 0))` ,
250
+ "" ,
251
+ undefined ) ;
252
+
253
+ // copy: zero length with both dst and src offset out of bounds past the end of the table is not allowed
254
+ tab_test2 ( `(table.copy ${ dest } $t0 (i32.const 31) (i32.const 31) (i32.const 0))` ,
255
+ "" ,
256
+ "out of bounds" ) ;
257
+ }
216
258
217
259
// table.copy: out of bounds of the table for the source or target, but should
218
260
// perform the operation up to the appropriate bound. Major cases:
0 commit comments