wardite 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6ed5daed5c5abae915387734fb0d00b7da8d824de1b7f6de5f5d6a19e422daa
4
- data.tar.gz: f3299bc55ab918c9b01a9251a5c2f0c94ee23d01bb2b5838c6a48c06c221579c
3
+ metadata.gz: 70bbc0a49f19757035ab126c1730f805e402c83e10010aaa7eb60f60af82c5fb
4
+ data.tar.gz: 5596c41c9af5bfdebb7e11a2ce1489f3ca941131dcf77292719f6e8d211c5ec8
5
5
  SHA512:
6
- metadata.gz: b4dd3cf8d61266fe8a106f5aacabf5663bede6ea7eee83d18f7fedf3d599cb080e4b80bccb973fc39dc107100b57052d8c34d7d9a0d5c5b7862ba32834cf04bc
7
- data.tar.gz: 84a45746ca727e3f552e6bd389fe0a046dc76fb7afc7617a9214472cda3ca1a0eb5c1f087a644dcb65518f71825a778a611bc44d8108534df870b88996a3996c
6
+ metadata.gz: 6fc262b77485384e5adad30621864bf6b7327c919e30db9cf9b59e3476107f549aadf4d6d346bbf0e06ecf24552441bfd2e5737d1df8d1ab134f3551b06956f1
7
+ data.tar.gz: 9feede8d3ab709382a34dae4ae33e5e2c471237fdd31f9af4674a4c33a20274dff04f143d6f722216e2ce69d0ef0fea29871a8a31e152b2db1821b88c2a29f39
data/Rakefile CHANGED
@@ -22,6 +22,29 @@ task :wasm, [:name] do |t, args|
22
22
  end
23
23
  end
24
24
 
25
+ desc "Run the official spec"
26
+ task :spec, [:name] do |t, args|
27
+ sh "which git && git clean -xf spec/ || true"
28
+
29
+ Dir.chdir "spec" do
30
+ sh "curl -L -o ./#{args.name}.wast https://raw.githubusercontent.com/WebAssembly/spec/refs/tags/wg-1.0/test/core/#{args.name}.wast"
31
+ sh "wast2json ./#{args.name}.wast"
32
+ sh "env JSON_PATH=./#{args.name}.json ruby ./runner.rb -v"
33
+
34
+ if File.exist?("./skip.txt")
35
+ puts
36
+ puts "\e[1;36mSkipped tests:\e[0m"
37
+ puts IO.read("./skip.txt")
38
+ end
39
+ end
40
+ end
41
+
42
+ desc "Run basic benchmark"
43
+ task :basic_benchmark do
44
+ sh "wasm-tools parse examples/i32_bench.wat -o examples/i32_bench.wasm"
45
+ sh "hyperfine --warmup 3 'bundle exec wardite --yjit --no-wasi --invoke detailed_arithmetic_loop examples/i32_bench.wasm'"
46
+ end
47
+
25
48
  desc "Generate codes"
26
49
  task :generate do
27
50
  require_relative "scripts/gen_alu"
@@ -0,0 +1,482 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>WebAssembly Performance Test</title>
7
+ <style>
8
+ body {
9
+ font-family: 'Arial', sans-serif;
10
+ max-width: 1200px;
11
+ margin: 0 auto;
12
+ padding: 20px;
13
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
14
+ color: white;
15
+ min-height: 100vh;
16
+ }
17
+
18
+ .container {
19
+ background: rgba(255, 255, 255, 0.1);
20
+ border-radius: 15px;
21
+ padding: 30px;
22
+ backdrop-filter: blur(10px);
23
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
24
+ }
25
+
26
+ h1 {
27
+ text-align: center;
28
+ margin-bottom: 30px;
29
+ font-size: 2.5em;
30
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
31
+ }
32
+
33
+ .controls {
34
+ display: flex;
35
+ gap: 15px;
36
+ margin-bottom: 30px;
37
+ flex-wrap: wrap;
38
+ justify-content: center;
39
+ }
40
+
41
+ button {
42
+ padding: 12px 24px;
43
+ font-size: 16px;
44
+ border: none;
45
+ border-radius: 8px;
46
+ cursor: pointer;
47
+ background: linear-gradient(45deg, #ff6b6b, #ee5a24);
48
+ color: white;
49
+ font-weight: bold;
50
+ transition: all 0.3s ease;
51
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
52
+ }
53
+
54
+ button:hover {
55
+ transform: translateY(-2px);
56
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
57
+ }
58
+
59
+ button:disabled {
60
+ background: #666;
61
+ cursor: not-allowed;
62
+ transform: none;
63
+ }
64
+
65
+ #fileInput {
66
+ padding: 8px;
67
+ border-radius: 5px;
68
+ border: 2px solid rgba(255, 255, 255, 0.3);
69
+ background: rgba(255, 255, 255, 0.1);
70
+ color: white;
71
+ }
72
+
73
+ .results {
74
+ display: grid;
75
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
76
+ gap: 20px;
77
+ margin-top: 30px;
78
+ }
79
+
80
+ .result-card {
81
+ background: rgba(255, 255, 255, 0.15);
82
+ padding: 20px;
83
+ border-radius: 10px;
84
+ border: 1px solid rgba(255, 255, 255, 0.2);
85
+ }
86
+
87
+ .result-card h3 {
88
+ margin-top: 0;
89
+ color: #ffd700;
90
+ font-size: 1.2em;
91
+ }
92
+
93
+ .metric {
94
+ display: flex;
95
+ justify-content: space-between;
96
+ margin: 10px 0;
97
+ padding: 5px 0;
98
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
99
+ }
100
+
101
+ .metric:last-child {
102
+ border-bottom: none;
103
+ }
104
+
105
+ .value {
106
+ font-weight: bold;
107
+ color: #90ee90;
108
+ }
109
+
110
+ .status {
111
+ text-align: center;
112
+ padding: 15px;
113
+ margin: 15px 0;
114
+ border-radius: 8px;
115
+ font-weight: bold;
116
+ }
117
+
118
+ .status.loading {
119
+ background: rgba(255, 193, 7, 0.3);
120
+ color: #ffc107;
121
+ }
122
+
123
+ .status.success {
124
+ background: rgba(40, 167, 69, 0.3);
125
+ color: #28a745;
126
+ }
127
+
128
+ .status.error {
129
+ background: rgba(220, 53, 69, 0.3);
130
+ color: #dc3545;
131
+ }
132
+
133
+ .comparison {
134
+ margin-top: 30px;
135
+ padding: 20px;
136
+ background: rgba(255, 255, 255, 0.1);
137
+ border-radius: 10px;
138
+ }
139
+
140
+ .progress-bar {
141
+ width: 100%;
142
+ height: 8px;
143
+ background: rgba(255, 255, 255, 0.2);
144
+ border-radius: 4px;
145
+ overflow: hidden;
146
+ margin: 10px 0;
147
+ }
148
+
149
+ .progress-fill {
150
+ height: 100%;
151
+ background: linear-gradient(90deg, #00d4ff, #090979);
152
+ width: 0%;
153
+ transition: width 0.3s ease;
154
+ }
155
+ </style>
156
+ </head>
157
+ <body>
158
+ <div class="container">
159
+ <h1>🚀 WebAssembly Performance Test</h1>
160
+
161
+ <div class="controls">
162
+ <input type="file" id="fileInput" accept=".wasm" />
163
+ <button id="loadBtn">Load WASM File</button>
164
+ <button id="runAllBtn" disabled>Run All Tests</button>
165
+ <button id="runSingleBtn" disabled>Single Test</button>
166
+ <button id="compareBtn" disabled>JS Comparison Test</button>
167
+ </div>
168
+
169
+ <div id="status" class="status loading" style="display: none;">
170
+ Preparing...
171
+ </div>
172
+
173
+ <div class="progress-bar" id="progressContainer" style="display: none;">
174
+ <div class="progress-fill" id="progressFill"></div>
175
+ </div>
176
+
177
+ <div class="results" id="results"></div>
178
+
179
+ <div class="comparison" id="comparison" style="display: none;">
180
+ <h3>📊 Performance Comparison</h3>
181
+ <div id="comparisonContent"></div>
182
+ </div>
183
+ </div>
184
+
185
+ <script>
186
+ let wasmModule = null;
187
+
188
+ // Get DOM elements
189
+ const fileInput = document.getElementById('fileInput');
190
+ const loadBtn = document.getElementById('loadBtn');
191
+ const runAllBtn = document.getElementById('runAllBtn');
192
+ const runSingleBtn = document.getElementById('runSingleBtn');
193
+ const compareBtn = document.getElementById('compareBtn');
194
+ const status = document.getElementById('status');
195
+ const results = document.getElementById('results');
196
+ const comparison = document.getElementById('comparison');
197
+ const comparisonContent = document.getElementById('comparisonContent');
198
+ const progressContainer = document.getElementById('progressContainer');
199
+ const progressFill = document.getElementById('progressFill');
200
+
201
+ // Status display function
202
+ function showStatus(message, type = 'loading') {
203
+ status.textContent = message;
204
+ status.className = `status ${type}`;
205
+ status.style.display = 'block';
206
+ }
207
+
208
+ function hideStatus() {
209
+ status.style.display = 'none';
210
+ }
211
+
212
+ // Progress bar update
213
+ function updateProgress(percent) {
214
+ progressFill.style.width = `${percent}%`;
215
+ }
216
+
217
+ function showProgress() {
218
+ progressContainer.style.display = 'block';
219
+ }
220
+
221
+ function hideProgress() {
222
+ progressContainer.style.display = 'none';
223
+ }
224
+
225
+ // Load WASM file
226
+ async function loadWasmFile(file) {
227
+ try {
228
+ showStatus('Loading WASM file...', 'loading');
229
+
230
+ const arrayBuffer = await file.arrayBuffer();
231
+ const wasmInstance = await WebAssembly.instantiate(arrayBuffer);
232
+
233
+ wasmModule = wasmInstance.instance;
234
+
235
+ showStatus('WASM file loaded successfully!', 'success');
236
+
237
+ // Enable buttons
238
+ runAllBtn.disabled = false;
239
+ runSingleBtn.disabled = false;
240
+ compareBtn.disabled = false;
241
+
242
+ setTimeout(hideStatus, 2000);
243
+
244
+ } catch (error) {
245
+ console.error('WASM loading error:', error);
246
+ showStatus(`Error: ${error.message}`, 'error');
247
+ }
248
+ }
249
+
250
+ // Execute performance test
251
+ function runPerformanceTest(testName, testFunction, iterations = 5) {
252
+ const times = [];
253
+ let result = null;
254
+
255
+ for (let i = 0; i < iterations; i++) {
256
+ const startTime = performance.now();
257
+ result = testFunction();
258
+ const endTime = performance.now();
259
+ times.push(endTime - startTime);
260
+ }
261
+
262
+ const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
263
+ const minTime = Math.min(...times);
264
+ const maxTime = Math.max(...times);
265
+
266
+ return {
267
+ name: testName,
268
+ result: result,
269
+ avgTime: avgTime,
270
+ minTime: minTime,
271
+ maxTime: maxTime,
272
+ times: times
273
+ };
274
+ }
275
+
276
+ // Display results
277
+ function displayResult(testResult) {
278
+ const card = document.createElement('div');
279
+ card.className = 'result-card';
280
+
281
+ card.innerHTML = `
282
+ <h3>${testResult.name}</h3>
283
+ <div class="metric">
284
+ <span>Result Value:</span>
285
+ <span class="value">${testResult.result.toLocaleString()}</span>
286
+ </div>
287
+ <div class="metric">
288
+ <span>Average Execution Time:</span>
289
+ <span class="value">${testResult.avgTime.toFixed(3)} ms</span>
290
+ </div>
291
+ <div class="metric">
292
+ <span>Minimum Time:</span>
293
+ <span class="value">${testResult.minTime.toFixed(3)} ms</span>
294
+ </div>
295
+ <div class="metric">
296
+ <span>Maximum Time:</span>
297
+ <span class="value">${testResult.maxTime.toFixed(3)} ms</span>
298
+ </div>
299
+ <div class="metric">
300
+ <span>Number of Executions:</span>
301
+ <span class="value">${testResult.times.length} times</span>
302
+ </div>
303
+ `;
304
+
305
+ results.appendChild(card);
306
+ }
307
+
308
+ // JavaScript version of detailed arithmetic (for comparison)
309
+ function jsDetailedArithmetic(x, y) {
310
+ const sum = x + y;
311
+ const diff = x - y;
312
+ const product = x * y;
313
+ const quotient = y !== 0 ? Math.floor(x / y) : 0;
314
+ return sum + diff + product + quotient;
315
+ }
316
+
317
+ function jsDetailedArithmeticLoop() {
318
+ let totalResult = 0;
319
+ let x = 5;
320
+ let y = 2;
321
+
322
+ for (let i = 0; i < 100000; i++) {
323
+ const currentResult = jsDetailedArithmetic(x, y);
324
+ totalResult += currentResult;
325
+
326
+ x += 1;
327
+ y = (y * 2) % 17 + 1;
328
+
329
+ if (x > 1000) {
330
+ x = 1;
331
+ }
332
+ }
333
+
334
+ return totalResult;
335
+ }
336
+
337
+ // Run all tests
338
+ async function runAllTests() {
339
+ if (!wasmModule) return;
340
+
341
+ results.innerHTML = '';
342
+ showStatus('Running all tests...', 'loading');
343
+ showProgress();
344
+
345
+ const tests = [
346
+ {
347
+ name: '🔄 Basic 4-Operation Loop (10000 times)',
348
+ func: () => wasmModule.exports.arithmetic_loop()
349
+ },
350
+ {
351
+ name: '📊 Detailed Arithmetic Loop',
352
+ func: () => wasmModule.exports.detailed_arithmetic_loop()
353
+ },
354
+ {
355
+ name: '🎯 Complex Pattern Arithmetic Loop',
356
+ func: () => wasmModule.exports.detailed_arithmetic_complex_loop()
357
+ },
358
+ {
359
+ name: '🧮 Single Detailed Arithmetic (100, 7)',
360
+ func: () => wasmModule.exports.detailed_arithmetic(100, 7)
361
+ }
362
+ ];
363
+
364
+ for (let i = 0; i < tests.length; i++) {
365
+ updateProgress((i / tests.length) * 100);
366
+
367
+ const testResult = runPerformanceTest(tests[i].name, tests[i].func, 10);
368
+ displayResult(testResult);
369
+
370
+ // Wait a bit to update UI
371
+ await new Promise(resolve => setTimeout(resolve, 100));
372
+ }
373
+
374
+ updateProgress(100);
375
+ showStatus('All tests completed!', 'success');
376
+
377
+ setTimeout(() => {
378
+ hideStatus();
379
+ hideProgress();
380
+ }, 2000);
381
+ }
382
+
383
+ // Run comparison test
384
+ async function runComparisonTest() {
385
+ if (!wasmModule) return;
386
+
387
+ showStatus('Running WebAssembly vs JavaScript comparison test...', 'loading');
388
+ showProgress();
389
+
390
+ updateProgress(25);
391
+ const wasmResult = runPerformanceTest('WebAssembly Version',
392
+ () => wasmModule.exports.detailed_arithmetic_loop(), 10);
393
+
394
+ updateProgress(75);
395
+ const jsResult = runPerformanceTest('JavaScript Version',
396
+ jsDetailedArithmeticLoop, 10);
397
+
398
+ updateProgress(100);
399
+
400
+ // Display comparison results
401
+ const speedup = jsResult.avgTime / wasmResult.avgTime;
402
+ const resultMatch = wasmResult.result === jsResult.result;
403
+
404
+ comparisonContent.innerHTML = `
405
+ <div class="metric">
406
+ <span>WebAssembly Average Time:</span>
407
+ <span class="value">${wasmResult.avgTime.toFixed(3)} ms</span>
408
+ </div>
409
+ <div class="metric">
410
+ <span>JavaScript Average Time:</span>
411
+ <span class="value">${jsResult.avgTime.toFixed(3)} ms</span>
412
+ </div>
413
+ <div class="metric">
414
+ <span>Speed Improvement:</span>
415
+ <span class="value">${speedup.toFixed(2)}x ${speedup > 1 ? 'faster' : 'slower'}</span>
416
+ </div>
417
+ <div class="metric">
418
+ <span>Result Match:</span>
419
+ <span class="value" style="color: ${resultMatch ? '#90ee90' : '#ff6b6b'}">
420
+ ${resultMatch ? '✅ Match' : '❌ Mismatch'}
421
+ </span>
422
+ </div>
423
+ <div class="metric">
424
+ <span>WASM Result Value:</span>
425
+ <span class="value">${wasmResult.result.toLocaleString()}</span>
426
+ </div>
427
+ <div class="metric">
428
+ <span>JS Result Value:</span>
429
+ <span class="value">${jsResult.result.toLocaleString()}</span>
430
+ </div>
431
+ `;
432
+
433
+ comparison.style.display = 'block';
434
+
435
+ showStatus('Comparison test completed!', 'success');
436
+
437
+ setTimeout(() => {
438
+ hideStatus();
439
+ hideProgress();
440
+ }, 2000);
441
+ }
442
+
443
+ // Event listeners
444
+ loadBtn.addEventListener('click', () => {
445
+ const file = fileInput.files[0];
446
+ if (file) {
447
+ loadWasmFile(file);
448
+ } else {
449
+ showStatus('Please select a WASM file', 'error');
450
+ setTimeout(hideStatus, 2000);
451
+ }
452
+ });
453
+
454
+ runAllBtn.addEventListener('click', runAllTests);
455
+ runSingleBtn.addEventListener('click', () => {
456
+ if (!wasmModule) return;
457
+ results.innerHTML = '';
458
+ const testResult = runPerformanceTest('🎯 Single Test',
459
+ () => wasmModule.exports.detailed_arithmetic_loop(), 1);
460
+ displayResult(testResult);
461
+ });
462
+ compareBtn.addEventListener('click', runComparisonTest);
463
+
464
+ // File drag & drop support
465
+ document.addEventListener('dragover', (e) => {
466
+ e.preventDefault();
467
+ });
468
+
469
+ document.addEventListener('drop', (e) => {
470
+ e.preventDefault();
471
+ const file = e.dataTransfer.files[0];
472
+ if (file && file.name.endsWith('.wasm')) {
473
+ fileInput.files = e.dataTransfer.files;
474
+ loadWasmFile(file);
475
+ }
476
+ });
477
+
478
+ console.log('WebAssembly Performance Test Tool ready!');
479
+ console.log('Please select and load your bench.wasm file.');
480
+ </script>
481
+ </body>
482
+ </html>
@@ -0,0 +1,137 @@
1
+ (module
2
+ ;; Detailed 4-operation arithmetic function (execute each operation individually)
3
+ (func $detailed_arithmetic (export "detailed_arithmetic") (param $x i32) (param $y i32) (result i32)
4
+ (local $sum i32)
5
+ (local $diff i32)
6
+ (local $product i32)
7
+ (local $quotient i32)
8
+ (local $final_result i32)
9
+
10
+ ;; Addition
11
+ local.get $x
12
+ local.get $y
13
+ i32.add
14
+ local.set $sum
15
+
16
+ ;; Subtraction
17
+ local.get $x
18
+ local.get $y
19
+ i32.sub
20
+ local.set $diff
21
+
22
+ ;; Multiplication
23
+ local.get $x
24
+ local.get $y
25
+ i32.mul
26
+ local.set $product
27
+
28
+ ;; Division (with zero division check)
29
+ local.get $y
30
+ i32.const 0
31
+ i32.eq
32
+ (if
33
+ (then
34
+ i32.const 0
35
+ local.set $quotient
36
+ )
37
+ (else
38
+ local.get $x
39
+ local.get $y
40
+ i32.div_s
41
+ local.set $quotient
42
+ )
43
+ )
44
+
45
+ ;; Sum all results
46
+ local.get $sum
47
+ local.get $diff
48
+ i32.add
49
+ local.get $product
50
+ i32.add
51
+ local.get $quotient
52
+ i32.add
53
+ local.set $final_result
54
+
55
+ local.get $final_result
56
+ )
57
+
58
+ ;; Execute detailed_arithmetic with changing numbers 10000 times
59
+ (func $detailed_arithmetic_loop (export "detailed_arithmetic_loop") (result i32)
60
+ (local $i i32) ;; Loop counter
61
+ (local $x i32) ;; First argument
62
+ (local $y i32) ;; Second argument
63
+ (local $total_result i32) ;; Accumulated result
64
+ (local $current_result i32) ;; Current arithmetic result
65
+
66
+ ;; Initialize values
67
+ i32.const 0
68
+ local.set $i ;; i = 0
69
+
70
+ i32.const 5
71
+ local.set $x ;; x = 5 (initial value)
72
+
73
+ i32.const 2
74
+ local.set $y ;; y = 2 (initial value)
75
+
76
+ i32.const 0
77
+ local.set $total_result ;; total_result = 0
78
+
79
+ ;; Start loop
80
+ (loop $detailed_loop
81
+ ;; Call detailed_arithmetic function
82
+ local.get $x
83
+ local.get $y
84
+ call $detailed_arithmetic
85
+ local.set $current_result
86
+
87
+ ;; Accumulate result
88
+ local.get $total_result
89
+ local.get $current_result
90
+ i32.add
91
+ local.set $total_result
92
+
93
+ ;; Change x and y values (add variation)
94
+ ;; x = x + 1
95
+ local.get $x
96
+ i32.const 1
97
+ i32.add
98
+ local.set $x
99
+
100
+ ;; y = (y * 2) % 17 + 1 (cycle in range 1-17, avoid zero division)
101
+ local.get $y
102
+ i32.const 2
103
+ i32.mul
104
+ i32.const 17
105
+ i32.rem_s
106
+ i32.const 1
107
+ i32.add
108
+ local.set $y
109
+
110
+ ;; Limit x to prevent overflow (overflow protection)
111
+ local.get $x
112
+ i32.const 1000
113
+ i32.gt_s
114
+ (if
115
+ (then
116
+ i32.const 1
117
+ local.set $x
118
+ )
119
+ )
120
+
121
+ ;; Increment counter
122
+ local.get $i
123
+ i32.const 1
124
+ i32.add
125
+ local.set $i
126
+
127
+ ;; Check loop continuation condition (i < 100000)
128
+ local.get $i
129
+ i32.const 100000
130
+ i32.lt_s
131
+ br_if $detailed_loop
132
+ )
133
+
134
+ ;; Return accumulated result
135
+ local.get $total_result
136
+ )
137
+ )
@@ -0,0 +1,314 @@
1
+ (module
2
+ ;; Export function that performs basic 4-operation arithmetic loop 10000 times
3
+ (func $arithmetic_loop (export "arithmetic_loop") (result i32)
4
+ (local $i i32) ;; Loop counter
5
+ (local $a i32) ;; Arithmetic variable a
6
+ (local $b i32) ;; Arithmetic variable b
7
+ (local $result i32) ;; Result storage
8
+
9
+ ;; Initialize values
10
+ i32.const 0
11
+ local.set $i ;; i = 0
12
+
13
+ i32.const 10
14
+ local.set $a ;; a = 10
15
+
16
+ i32.const 3
17
+ local.set $b ;; b = 3
18
+
19
+ i32.const 0
20
+ local.set $result ;; result = 0
21
+
22
+ ;; Start loop
23
+ (loop $main_loop
24
+ ;; Addition: result += a + b
25
+ local.get $result
26
+ local.get $a
27
+ local.get $b
28
+ i32.add
29
+ i32.add
30
+ local.set $result
31
+
32
+ ;; Subtraction: result += a - b
33
+ local.get $result
34
+ local.get $a
35
+ local.get $b
36
+ i32.sub
37
+ i32.add
38
+ local.set $result
39
+
40
+ ;; Multiplication: result += a * b
41
+ local.get $result
42
+ local.get $a
43
+ local.get $b
44
+ i32.mul
45
+ i32.add
46
+ local.set $result
47
+
48
+ ;; Division: result += a / b
49
+ local.get $result
50
+ local.get $a
51
+ local.get $b
52
+ i32.div_s
53
+ i32.add
54
+ local.set $result
55
+
56
+ ;; Increment counter
57
+ local.get $i
58
+ i32.const 1
59
+ i32.add
60
+ local.set $i
61
+
62
+ ;; Check loop continuation condition (i < 100000)
63
+ local.get $i
64
+ i32.const 100000
65
+ i32.lt_s
66
+ br_if $main_loop
67
+ )
68
+
69
+ ;; Return result
70
+ local.get $result
71
+ )
72
+
73
+ ;; Detailed 4-operation arithmetic function (execute each operation individually)
74
+ (func $detailed_arithmetic (export "detailed_arithmetic") (param $x i32) (param $y i32) (result i32)
75
+ (local $sum i32)
76
+ (local $diff i32)
77
+ (local $product i32)
78
+ (local $quotient i32)
79
+ (local $final_result i32)
80
+
81
+ ;; Addition
82
+ local.get $x
83
+ local.get $y
84
+ i32.add
85
+ local.set $sum
86
+
87
+ ;; Subtraction
88
+ local.get $x
89
+ local.get $y
90
+ i32.sub
91
+ local.set $diff
92
+
93
+ ;; Multiplication
94
+ local.get $x
95
+ local.get $y
96
+ i32.mul
97
+ local.set $product
98
+
99
+ ;; Division (with zero division check)
100
+ local.get $y
101
+ i32.const 0
102
+ i32.eq
103
+ (if
104
+ (then
105
+ i32.const 0
106
+ local.set $quotient
107
+ )
108
+ (else
109
+ local.get $x
110
+ local.get $y
111
+ i32.div_s
112
+ local.set $quotient
113
+ )
114
+ )
115
+
116
+ ;; Sum all results
117
+ local.get $sum
118
+ local.get $diff
119
+ i32.add
120
+ local.get $product
121
+ i32.add
122
+ local.get $quotient
123
+ i32.add
124
+ local.set $final_result
125
+
126
+ local.get $final_result
127
+ )
128
+
129
+ ;; Execute detailed_arithmetic with changing numbers 10000 times
130
+ (func $detailed_arithmetic_loop (export "detailed_arithmetic_loop") (result i32)
131
+ (local $i i32) ;; Loop counter
132
+ (local $x i32) ;; First argument
133
+ (local $y i32) ;; Second argument
134
+ (local $total_result i32) ;; Accumulated result
135
+ (local $current_result i32) ;; Current arithmetic result
136
+
137
+ ;; Initialize values
138
+ i32.const 0
139
+ local.set $i ;; i = 0
140
+
141
+ i32.const 5
142
+ local.set $x ;; x = 5 (initial value)
143
+
144
+ i32.const 2
145
+ local.set $y ;; y = 2 (initial value)
146
+
147
+ i32.const 0
148
+ local.set $total_result ;; total_result = 0
149
+
150
+ ;; Start loop
151
+ (loop $detailed_loop
152
+ ;; Call detailed_arithmetic function
153
+ local.get $x
154
+ local.get $y
155
+ call $detailed_arithmetic
156
+ local.set $current_result
157
+
158
+ ;; Accumulate result
159
+ local.get $total_result
160
+ local.get $current_result
161
+ i32.add
162
+ local.set $total_result
163
+
164
+ ;; Change x and y values (add variation)
165
+ ;; x = x + 1
166
+ local.get $x
167
+ i32.const 1
168
+ i32.add
169
+ local.set $x
170
+
171
+ ;; y = (y * 2) % 17 + 1 (cycle in range 1-17, avoid zero division)
172
+ local.get $y
173
+ i32.const 2
174
+ i32.mul
175
+ i32.const 17
176
+ i32.rem_s
177
+ i32.const 1
178
+ i32.add
179
+ local.set $y
180
+
181
+ ;; Limit x to prevent overflow (overflow protection)
182
+ local.get $x
183
+ i32.const 1000
184
+ i32.gt_s
185
+ (if
186
+ (then
187
+ i32.const 1
188
+ local.set $x
189
+ )
190
+ )
191
+
192
+ ;; Increment counter
193
+ local.get $i
194
+ i32.const 1
195
+ i32.add
196
+ local.set $i
197
+
198
+ ;; Check loop continuation condition (i < 100000)
199
+ local.get $i
200
+ i32.const 100000
201
+ i32.lt_s
202
+ br_if $detailed_loop
203
+ )
204
+
205
+ ;; Return accumulated result
206
+ local.get $total_result
207
+ )
208
+
209
+ ;; Version with more complex pattern for number changes
210
+ (func $detailed_arithmetic_complex_loop (export "detailed_arithmetic_complex_loop") (result i32)
211
+ (local $i i32) ;; Loop counter
212
+ (local $x i32) ;; First argument
213
+ (local $y i32) ;; Second argument
214
+ (local $total_result i32) ;; Accumulated result
215
+ (local $current_result i32) ;; Current arithmetic result
216
+
217
+ ;; Initialize values
218
+ i32.const 0
219
+ local.set $i ;; i = 0
220
+
221
+ i32.const 10
222
+ local.set $x ;; x = 10 (initial value)
223
+
224
+ i32.const 3
225
+ local.set $y ;; y = 3 (initial value)
226
+
227
+ i32.const 0
228
+ local.set $total_result ;; total_result = 0
229
+
230
+ ;; Start loop
231
+ (loop $complex_loop
232
+ ;; Call detailed_arithmetic function
233
+ local.get $x
234
+ local.get $y
235
+ call $detailed_arithmetic
236
+ local.set $current_result
237
+
238
+ ;; Accumulate result
239
+ local.get $total_result
240
+ local.get $current_result
241
+ i32.add
242
+ local.set $total_result
243
+
244
+ ;; Change numbers with more complex pattern
245
+ ;; x = (x + i) % 100 + 1 (range 1-100)
246
+ local.get $x
247
+ local.get $i
248
+ i32.add
249
+ i32.const 100
250
+ i32.rem_s
251
+ i32.const 1
252
+ i32.add
253
+ local.set $x
254
+
255
+ ;; y = (i * 3 + 7) % 13 + 1 (range 1-13, avoid zero division)
256
+ local.get $i
257
+ i32.const 3
258
+ i32.mul
259
+ i32.const 7
260
+ i32.add
261
+ i32.const 13
262
+ i32.rem_s
263
+ i32.const 1
264
+ i32.add
265
+ local.set $y
266
+
267
+ ;; Increment counter
268
+ local.get $i
269
+ i32.const 1
270
+ i32.add
271
+ local.set $i
272
+
273
+ ;; Check loop continuation condition (i < 100000)
274
+ local.get $i
275
+ i32.const 100000
276
+ i32.lt_s
277
+ br_if $complex_loop
278
+ )
279
+
280
+ ;; Return accumulated result
281
+ local.get $total_result
282
+ )
283
+
284
+ ;; Floating-point 4-operation arithmetic (f32)
285
+ (func $float_arithmetic (export "float_arithmetic") (param $x f32) (param $y f32) (result f32)
286
+ (local $result f32)
287
+
288
+ ;; Addition
289
+ local.get $x
290
+ local.get $y
291
+ f32.add
292
+
293
+ ;; Add subtraction
294
+ local.get $x
295
+ local.get $y
296
+ f32.sub
297
+ f32.add
298
+
299
+ ;; Add multiplication
300
+ local.get $x
301
+ local.get $y
302
+ f32.mul
303
+ f32.add
304
+
305
+ ;; Add division
306
+ local.get $x
307
+ local.get $y
308
+ f32.div
309
+ f32.add
310
+
311
+ local.set $result
312
+ local.get $result
313
+ )
314
+ )
@@ -47,6 +47,10 @@ module Wardite
47
47
  if (yjit || ENV["WARDITE_YJIT_ON"] == "1") && (defined? RubyVM::YJIT)
48
48
  RubyVM::YJIT.enable
49
49
  end
50
+
51
+ if (yjit || ENV["WARDITE_YJIT_ON"] == "1") && !defined?(RubyVM::YJIT)
52
+ warn "Warning: --yjit option is specified, but not available in this Ruby build"
53
+ end
50
54
  end
51
55
 
52
56
  # @rbs return: Array[Integer | Float]
data/lib/wardite/load.rb CHANGED
@@ -254,6 +254,7 @@ module Wardite
254
254
  # @rbs enable_wasi: boolish
255
255
  # @rbs return: Instance
256
256
  def self.load_from_buffer(buf, import_object: {}, enable_wasi: true)
257
+ start = Time.now.to_f #: Float
257
258
  @buf = buf
258
259
 
259
260
  version = preamble
@@ -273,6 +274,8 @@ module Wardite
273
274
  i.wasi = wasi_env
274
275
  end
275
276
  end
277
+ ensure
278
+ $stderr.puts "load_from_buffer: #{Time.now.to_f - start}" if ENV['WARITE_TRACE']
276
279
  end
277
280
 
278
281
  # @rbs return: Integer
@@ -2,5 +2,5 @@
2
2
  # rbs_inline: enabled
3
3
 
4
4
  module Wardite
5
- VERSION = "0.8.1" #: String
5
+ VERSION = "0.8.2" #: String
6
6
  end
data/lib/wardite.rb CHANGED
@@ -362,9 +362,22 @@ module Wardite
362
362
  return nil
363
363
  end
364
364
 
365
+ # @rbs!
366
+ # $GLOBAL_EXTERNAL_ELAP: Float
367
+ # $GLOBAL_EXTERNAL_TIMES: Integer
368
+ $GLOBAL_EXTERNAL_ELAP = 0.0 #: Float
369
+ $GLOBAL_EXTERNAL_TIMES = 0 #: Integer
370
+ END {
371
+ if ENV["WARDITE_TRACE"] == "1"
372
+ $stderr.puts "external call count: #{$GLOBAL_EXTERNAL_TIMES}"
373
+ $stderr.puts "external call elapsed: #{$GLOBAL_EXTERNAL_ELAP}(s)"
374
+ end
375
+ }
376
+
365
377
  # @rbs external_function: ExternalFunction
366
378
  # @rbs return: wasmValue|nil
367
379
  def invoke_external(external_function)
380
+ start = Time.now.to_f
368
381
  $stderr.puts "[trace] call external function: #{external_function.name}" if ENV["WARDITE_TRACE"]
369
382
  local_start = stack.size - external_function.callsig.size
370
383
  args = stack[local_start..]
@@ -399,6 +412,9 @@ module Wardite
399
412
  end
400
413
 
401
414
  raise "invalid type of value returned in proc. val: #{val.inspect}"
415
+ ensure
416
+ $GLOBAL_EXTERNAL_TIMES += 1
417
+ $GLOBAL_EXTERNAL_ELAP += (Time.now.to_f - start)
402
418
  end
403
419
 
404
420
  # @rbs return: void
@@ -6,7 +6,7 @@ gems:
6
6
  source:
7
7
  type: git
8
8
  name: ruby/gem_rbs_collection
9
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
9
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
10
10
  remote: https://github.com/ruby/gem_rbs_collection.git
11
11
  repo_dir: gems
12
12
  - name: ast
@@ -14,7 +14,7 @@ gems:
14
14
  source:
15
15
  type: git
16
16
  name: ruby/gem_rbs_collection
17
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
17
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
18
18
  remote: https://github.com/ruby/gem_rbs_collection.git
19
19
  repo_dir: gems
20
20
  - name: base64
@@ -22,7 +22,7 @@ gems:
22
22
  source:
23
23
  type: git
24
24
  name: ruby/gem_rbs_collection
25
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
25
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
26
26
  remote: https://github.com/ruby/gem_rbs_collection.git
27
27
  repo_dir: gems
28
28
  - name: bigdecimal
@@ -30,7 +30,7 @@ gems:
30
30
  source:
31
31
  type: git
32
32
  name: ruby/gem_rbs_collection
33
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
33
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
34
34
  remote: https://github.com/ruby/gem_rbs_collection.git
35
35
  repo_dir: gems
36
36
  - name: concurrent-ruby
@@ -38,7 +38,7 @@ gems:
38
38
  source:
39
39
  type: git
40
40
  name: ruby/gem_rbs_collection
41
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
41
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
42
42
  remote: https://github.com/ruby/gem_rbs_collection.git
43
43
  repo_dir: gems
44
44
  - name: connection_pool
@@ -46,7 +46,7 @@ gems:
46
46
  source:
47
47
  type: git
48
48
  name: ruby/gem_rbs_collection
49
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
49
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
50
50
  remote: https://github.com/ruby/gem_rbs_collection.git
51
51
  repo_dir: gems
52
52
  - name: csv
@@ -54,7 +54,7 @@ gems:
54
54
  source:
55
55
  type: git
56
56
  name: ruby/gem_rbs_collection
57
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
57
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
58
58
  remote: https://github.com/ruby/gem_rbs_collection.git
59
59
  repo_dir: gems
60
60
  - name: date
@@ -86,7 +86,7 @@ gems:
86
86
  source:
87
87
  type: git
88
88
  name: ruby/gem_rbs_collection
89
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
89
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
90
90
  remote: https://github.com/ruby/gem_rbs_collection.git
91
91
  repo_dir: gems
92
92
  - name: json
@@ -98,7 +98,7 @@ gems:
98
98
  source:
99
99
  type: git
100
100
  name: ruby/gem_rbs_collection
101
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
101
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
102
102
  remote: https://github.com/ruby/gem_rbs_collection.git
103
103
  repo_dir: gems
104
104
  - name: logger
@@ -106,17 +106,17 @@ gems:
106
106
  source:
107
107
  type: stdlib
108
108
  - name: minitest
109
- version: '0'
109
+ version: '5.25'
110
110
  source:
111
- type: stdlib
111
+ type: git
112
+ name: ruby/gem_rbs_collection
113
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
114
+ remote: https://github.com/ruby/gem_rbs_collection.git
115
+ repo_dir: gems
112
116
  - name: monitor
113
117
  version: '0'
114
118
  source:
115
119
  type: stdlib
116
- - name: mutex_m
117
- version: '0'
118
- source:
119
- type: stdlib
120
120
  - name: openssl
121
121
  version: '0'
122
122
  source:
@@ -130,7 +130,7 @@ gems:
130
130
  source:
131
131
  type: git
132
132
  name: ruby/gem_rbs_collection
133
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
133
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
134
134
  remote: https://github.com/ruby/gem_rbs_collection.git
135
135
  repo_dir: gems
136
136
  - name: pathname
@@ -142,7 +142,7 @@ gems:
142
142
  source:
143
143
  type: git
144
144
  name: ruby/gem_rbs_collection
145
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
145
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
146
146
  remote: https://github.com/ruby/gem_rbs_collection.git
147
147
  repo_dir: gems
148
148
  - name: rake
@@ -150,11 +150,11 @@ gems:
150
150
  source:
151
151
  type: git
152
152
  name: ruby/gem_rbs_collection
153
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
153
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
154
154
  remote: https://github.com/ruby/gem_rbs_collection.git
155
155
  repo_dir: gems
156
156
  - name: rbs
157
- version: 3.7.0
157
+ version: 3.9.4
158
158
  source:
159
159
  type: rubygems
160
160
  - name: rdoc
@@ -198,7 +198,11 @@ gems:
198
198
  source:
199
199
  type: git
200
200
  name: ruby/gem_rbs_collection
201
- revision: 1288acc1cdecc0a273740212da0df35b108dbfb6
201
+ revision: 4873ad046b4ea8931591626cd547becae6d1e84e
202
202
  remote: https://github.com/ruby/gem_rbs_collection.git
203
203
  repo_dir: gems
204
+ - name: uri
205
+ version: '0'
206
+ source:
207
+ type: stdlib
204
208
  gemfile_lock_path: Gemfile.lock
@@ -110,6 +110,10 @@ module Wardite
110
110
  # @rbs return: Object|nil
111
111
  def invoke_internal: (WasmFunction wasm_function) -> (Object | nil)
112
112
 
113
+ $GLOBAL_EXTERNAL_ELAP: Float
114
+
115
+ $GLOBAL_EXTERNAL_TIMES: Integer
116
+
113
117
  # @rbs external_function: ExternalFunction
114
118
  # @rbs return: wasmValue|nil
115
119
  def invoke_external: (ExternalFunction external_function) -> (wasmValue | nil)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wardite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uchio Kondo
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: A pure-ruby webassembly runtime
13
13
  email:
@@ -31,6 +31,9 @@ files:
31
31
  - examples/global.wat
32
32
  - examples/grayscale.rb
33
33
  - examples/helloworld.wat
34
+ - examples/i32_bench.html
35
+ - examples/i32_bench.wat
36
+ - examples/i32_bench_original.wat
34
37
  - examples/i32_const.wat
35
38
  - examples/i32_store.wat
36
39
  - examples/local_set.wat
@@ -117,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
120
  - !ruby/object:Gem::Version
118
121
  version: '0'
119
122
  requirements: []
120
- rubygems_version: 3.6.2
123
+ rubygems_version: 3.6.9
121
124
  specification_version: 4
122
125
  summary: A pure-ruby webassembly runtime
123
126
  test_files: []