Compare commits

..
Author SHA1 Message Date
t3hn3rd 93dfff358d refactor: Split monolithic wasm.vm.opcodes.pas into 119 individual opcode units
- Extract each opcode procedure from wasm.vm.opcodes.pas into its own
unit file under src/wasm/vm/opcodes/ following the naming convention
wasm.vm.opcode.<name>.pas. The hub file now only imports the individual
units and contains initializeOpcodeJumpTable with fully qualified
procedure references.
- Add missing test coverage for the else opcode (4 tests), bringing the
total from 425 to 429 with all tests passing.

Files:
- 119 new opcode units under src/wasm/vm/opcodes/
- 1 new test: wasm.test.opcode.elseop.pas
- Modified: wasm.vm.opcodes.pas (hub-only), wasm.test.pas, build.bat
2026-02-24 15:38:36 +00:00
t3hn3rd 3ed5c0a847 Merge branch 'feature/build-clean' into develop 2026-02-24 14:57:43 +00:00
t3hn3rd ff65a0d5f0 refactor: build.bat flexible argument parsing, add run & help commands
- Replaced positional `%1` checks with a loop-based argument parser
  so flags (`test`, `clean`, `run`, `help`) work in any order/combination
- Added `run` flag: executes `bin\WASURO.exe` after a successful build
- Added `help` flag: prints usage info and exits
- Fixed `clean` early-exit to also check `DO_RUN` (not just `TESTFLAGS`),
  so `build.bat clean run` correctly continues to build+run
- Added section comment headers (Build, Run) for consistency
2026-02-24 14:57:30 +00:00
t3hn3rd 76d7d737c0 Merge branch 'feature/missing-opcodes' into develop 2026-02-24 14:47:01 +00:00
123 changed files with 3624 additions and 1885 deletions

No files matched your search

+35
View File
@@ -8,7 +8,34 @@ set LIB=%ROOT%lib
set FPC=C:\Lazarus\fpc\3.2.2\bin\x86_64-win64\fpc.exe
set TESTFLAGS=
set DO_CLEAN=0
set DO_RUN=0
:parse_args
if "%1"=="" goto args_done
if "%1"=="test" set TESTFLAGS=-dRUN_TESTS
if "%1"=="clean" set DO_CLEAN=1
if "%1"=="run" set DO_RUN=1
if "%1"=="help" (
echo Usage: build.bat [options]
echo Options:
echo test - Build with tests enabled
echo clean - Clean build outputs
echo run - Run the built executable after building
echo help - Show this help message
exit /b 0
)
shift
goto parse_args
:args_done
if %DO_CLEAN%==1 (
echo Cleaning build outputs...
if exist "%BIN%" rd /s /q "%BIN%"
if exist "%LIB%" rd /s /q "%LIB%"
echo Clean complete.
if "%TESTFLAGS%"=="" if %DO_RUN%==0 exit /b 0
)
if not exist "%BIN%" mkdir "%BIN%"
if not exist "%LIB%" mkdir "%LIB%"
@@ -17,6 +44,7 @@ REM ── Lint ─────────────────────
powershell -NoProfile -ExecutionPolicy Bypass -File "%ROOT%lint.ps1" -SrcRoot "%SRC%"
if %ERRORLEVEL% NEQ 0 exit /b 1
REM ── Build ────────────────────────────────────────────────────────────
"%FPC%" ^
%TESTFLAGS% ^
-FE"%BIN%" ^
@@ -32,6 +60,7 @@ if %ERRORLEVEL% NEQ 0 exit /b 1
-Fu"%SRC%\wasm\test\infra" ^
-Fu"%SRC%\wasm\types" ^
-Fu"%SRC%\wasm\vm" ^
-Fu"%SRC%\wasm\vm\opcodes" ^
-gw3 ^
-o"%BIN%\WASURO.exe" ^
"%SRC%\project\WASURO.lpr"
@@ -42,3 +71,9 @@ if %ERRORLEVEL% NEQ 0 (
)
echo Build succeeded: %BIN%\WASURO.exe
REM ── Run ────────────────────────────────────────────────────────────
if %DO_RUN%==1 (
echo Running WASURO...
"%BIN%\WASURO.exe"
)
@@ -0,0 +1,92 @@
unit wasm.test.opcode.elseop;
interface
procedure run;
implementation
uses
wasm.types.builtin, wasm.types.context, wasm.types.stack, wasm.vm, wasm.test.framework;
procedure run;
var
code : array[0..20] of TWASMUInt8;
ctx : PWASMProcessContext;
begin
test_begin('opcode.else');
{ Test 1: else skips else-body when if-true path taken }
{ i32.const 1 if $40 i32.const 10 else i32.const 20 end }
{ When condition is true the if-true body runs and else skips to past end }
code[0] := $41; { i32.const 1 }
code[1] := $01;
code[2] := $04; { if }
code[3] := $40; { blocktype empty }
code[4] := $41; { i32.const 10 }
code[5] := $0A;
code[6] := $05; { else }
code[7] := $41; { i32.const 20 }
code[8] := $14;
code[9] := $0B; { end }
ctx := make_test_context(@code[0], 10);
while wasm.vm.tick(ctx) do;
assert_i32('true path skips else body', wasm.types.stack.popi32(ctx^.ExecutionState.Operand_Stack), 10);
{ Test 2: else-body executes when condition is false }
{ i32.const 0 if $40 i32.const 10 else i32.const 20 end }
code[0] := $41; { i32.const 0 }
code[1] := $00;
code[2] := $04; { if }
code[3] := $40;
code[4] := $41; { i32.const 10 }
code[5] := $0A;
code[6] := $05; { else }
code[7] := $41; { i32.const 20 }
code[8] := $14;
code[9] := $0B; { end }
ctx := make_test_context(@code[0], 10);
while wasm.vm.tick(ctx) do;
assert_i32('false path executes else body', wasm.types.stack.popi32(ctx^.ExecutionState.Operand_Stack), 20);
{ Test 3: else skips nested block in else-body }
{ i32.const 1 if $40 i32.const 5 else block $40 i32.const 99 end end }
code[0] := $41; { i32.const 1 }
code[1] := $01;
code[2] := $04; { if }
code[3] := $40;
code[4] := $41; { i32.const 5 }
code[5] := $05;
code[6] := $05; { else }
code[7] := $02; { block }
code[8] := $40;
code[9] := $41; { i32.const 99 }
code[10] := $63;
code[11] := $0B; { end block }
code[12] := $0B; { end if }
ctx := make_test_context(@code[0], 13);
while wasm.vm.tick(ctx) do;
assert_i32('else skips nested block', wasm.types.stack.popi32(ctx^.ExecutionState.Operand_Stack), 5);
{ Test 4: execution continues after end when else is skipped }
{ i32.const 1 if $40 i32.const 3 else i32.const 4 end i32.const 7 }
code[0] := $41; { i32.const 1 }
code[1] := $01;
code[2] := $04; { if }
code[3] := $40;
code[4] := $41; { i32.const 3 }
code[5] := $03;
code[6] := $05; { else }
code[7] := $41; { i32.const 4 }
code[8] := $04;
code[9] := $0B; { end }
code[10] := $41; { i32.const 7 }
code[11] := $07;
ctx := make_test_context(@code[0], 12);
while wasm.vm.tick(ctx) do;
assert_i32('continues after else skip', wasm.types.stack.popi32(ctx^.ExecutionState.Operand_Stack), 7);
test_end;
end;
end.
+2
View File
@@ -34,6 +34,7 @@ uses
wasm.test.opcode.block,
wasm.test.opcode.loop,
wasm.test.opcode.ifop,
wasm.test.opcode.elseop,
wasm.test.opcode.endop,
wasm.test.opcode.br,
wasm.test.opcode.brif,
@@ -196,6 +197,7 @@ begin
wasm.test.opcode.block.run;
wasm.test.opcode.loop.run;
wasm.test.opcode.ifop.run;
wasm.test.opcode.elseop.run;
wasm.test.opcode.endop.run;
wasm.test.opcode.br.run;
wasm.test.opcode.brif.run;
@@ -0,0 +1,30 @@
unit wasm.vm.opcode.block;
interface
uses wasm.types.context;
procedure _WASM_opcode_BlockOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.constants, wasm.vm.control;
procedure _WASM_opcode_BlockOp(Context : PWASMProcessContext);
var
end_ip: TWASMUInt32;
begin
Inc(Context^.ExecutionState.IP); { past opcode $02 }
Inc(Context^.ExecutionState.IP); { past blocktype byte }
{ Find the matching end byte }
end_ip := scan_forward(Context^.ExecutionState.Code,
Context^.ExecutionState.IP,
Context^.ExecutionState.Limit, false);
{ Push block frame: br target = past the end byte }
push_control_frame(Context^.ExecutionState.Control_Stack,
CTRL_FRAME_BLOCK,
TWASMInt32(end_ip + 1),
TWASMInt32(Context^.ExecutionState.Operand_Stack^.Top));
end;
end.
+27
View File
@@ -0,0 +1,27 @@
unit wasm.vm.opcode.br;
interface
uses wasm.types.context;
procedure _WASM_opcode_BrOp(Context : PWASMProcessContext);
implementation
uses leb128, wasm.types.builtin, wasm.vm.control;
procedure _WASM_opcode_BrOp(Context : PWASMProcessContext);
var
label_depth: TWASMUInt32;
bytesRead: TWASMUInt8;
begin
Inc(Context^.ExecutionState.IP); { past opcode $0C }
bytesRead := read_leb128_to_uint32(
@Context^.ExecutionState.Code[Context^.ExecutionState.IP],
@Context^.ExecutionState.Code[Context^.ExecutionState.Limit],
@label_depth);
{ do_branch sets IP; no need to advance past immediate }
do_branch(Context, label_depth);
end;
end.
@@ -0,0 +1,31 @@
unit wasm.vm.opcode.brif;
interface
uses wasm.types.context;
procedure _WASM_opcode_BrIfOp(Context : PWASMProcessContext);
implementation
uses leb128, wasm.types.builtin, wasm.types.stack, wasm.vm.control;
procedure _WASM_opcode_BrIfOp(Context : PWASMProcessContext);
var
label_depth: TWASMUInt32;
bytesRead: TWASMUInt8;
cond: TWASMInt32;
begin
Inc(Context^.ExecutionState.IP); { past opcode $0D }
bytesRead := read_leb128_to_uint32(
@Context^.ExecutionState.Code[Context^.ExecutionState.IP],
@Context^.ExecutionState.Code[Context^.ExecutionState.Limit],
@label_depth);
Inc(Context^.ExecutionState.IP, bytesRead); { past label depth }
cond := wasm.types.stack.popi32(Context^.ExecutionState.Operand_Stack);
if cond <> 0 then
do_branch(Context, label_depth);
{ else: continue at current IP }
end;
end.
@@ -0,0 +1,50 @@
unit wasm.vm.opcode.brtable;
interface
uses wasm.types.context;
procedure _WASM_opcode_BrTableOp(Context : PWASMProcessContext);
implementation
uses leb128, wasm.types.builtin, wasm.types.stack, wasm.vm.control;
procedure _WASM_opcode_BrTableOp(Context : PWASMProcessContext);
var
count, idx, selected, dummy: TWASMUInt32;
skip_count, i: TWASMUInt32;
bytesRead: TWASMUInt8;
begin
Inc(Context^.ExecutionState.IP); { past opcode $0E }
{ Read label count }
bytesRead := read_leb128_to_uint32(
@Context^.ExecutionState.Code[Context^.ExecutionState.IP],
@Context^.ExecutionState.Code[Context^.ExecutionState.Limit],
@count);
Inc(Context^.ExecutionState.IP, bytesRead);
{ Pop index from operand stack }
idx := TWASMUInt32(wasm.types.stack.popi32(Context^.ExecutionState.Operand_Stack));
{ Determine how many labels to skip to reach our target }
if idx >= count then
skip_count := count
else
skip_count := idx;
{ Skip labels we don't need }
for i := 1 to skip_count do begin
bytesRead := read_leb128_to_uint32(
@Context^.ExecutionState.Code[Context^.ExecutionState.IP],
@Context^.ExecutionState.Code[Context^.ExecutionState.Limit],
@dummy);
Inc(Context^.ExecutionState.IP, bytesRead);
end;
{ Read the selected label (or default if idx >= count) }
bytesRead := read_leb128_to_uint32(
@Context^.ExecutionState.Code[Context^.ExecutionState.IP],
@Context^.ExecutionState.Code[Context^.ExecutionState.Limit],
@selected);
{ Branch to selected depth }
do_branch(Context, selected);
end;
end.
@@ -0,0 +1,97 @@
unit wasm.vm.opcode.call;
interface
uses wasm.types.context;
procedure _WASM_opcode_CallOp(Context : PWASMProcessContext);
implementation
uses leb128, lmemorymanager, wasm.types.builtin, wasm.types.enums,
wasm.types.values, wasm.types.sections, wasm.types.stack,
wasm.types.constants, wasm.vm.control;
procedure _WASM_opcode_CallOp(Context : PWASMProcessContext);
var
func_idx, type_idx: TWASMUInt32;
bytesRead: TWASMUInt8;
func_type: PWASMType;
code_entry: PWASMCodeEntry;
param_count, decl_count, total_count: TWASMUInt32;
new_locals: PWASMLocals;
i, j: TWASMUInt32;
return_ip, saved_top: TWASMUInt32;
cs, os: PWASMStack;
begin
cs := Context^.ExecutionState.Control_Stack;
os := Context^.ExecutionState.Operand_Stack;
Inc(Context^.ExecutionState.IP); { past opcode $10 }
bytesRead := read_leb128_to_uint32(
@Context^.ExecutionState.Code[Context^.ExecutionState.IP],
@Context^.ExecutionState.Code[Context^.ExecutionState.Limit],
@func_idx);
Inc(Context^.ExecutionState.IP, bytesRead);
return_ip := Context^.ExecutionState.IP; { instruction after call }
{ Look up function metadata }
type_idx := Context^.Sections.FunctionSection^.Functions[func_idx].Index;
func_type := @Context^.Sections.TypeSection^.Types[type_idx];
code_entry := @Context^.Sections.CodeSection^.Entries[func_idx];
param_count := func_type^.ParamCount;
decl_count := code_entry^.Locals.LocalCount;
total_count := param_count + decl_count;
{ Allocate new locals }
new_locals := PWASMLocals(kalloc(sizeof(TWASMLocals)));
new_locals^.LocalCount := total_count;
new_locals^.TypeCount := total_count;
if total_count > 0 then
new_locals^.Locals := PWASMValueEntry(kalloc(sizeof(TWASMValueEntry) * total_count))
else
new_locals^.Locals := nil;
{ Pop parameters from operand stack (reverse order into locals) }
if param_count > 0 then begin
for i := param_count downto 1 do begin
j := i - 1;
new_locals^.Locals[j].ValueType := func_type^.ParamTypes[j].ValueType;
case func_type^.ParamTypes[j].ValueType of
vti32: new_locals^.Locals[j].i32Value := wasm.types.stack.popi32(os);
vti64: new_locals^.Locals[j].i64Value := wasm.types.stack.popi64(os);
vtf32: new_locals^.Locals[j].f32Value := wasm.types.stack.popf32(os);
vtf64: new_locals^.Locals[j].f64Value := wasm.types.stack.popf64(os);
end;
end;
end;
{ Initialize declared locals to zero }
if decl_count > 0 then begin
for i := param_count to total_count - 1 do begin
j := i - param_count;
new_locals^.Locals[i].ValueType := code_entry^.Locals.Locals[j].ValueType;
new_locals^.Locals[i].i64Value := 0;
end;
end;
saved_top := os^.Top; { stack depth after popping args }
{ Push call frame (4 entries): saved_locals_ptr, return_ip, saved_top, marker }
wasm.types.stack.pushi64(cs, TWASMInt64(Context^.ExecutionState.Locals));
wasm.types.stack.pushi32(cs, TWASMInt32(return_ip));
wasm.types.stack.pushi32(cs, TWASMInt32(saved_top));
wasm.types.stack.pushi32(cs, CTRL_FRAME_CALL);
{ Push implicit function block frame }
push_control_frame(cs, CTRL_FRAME_BLOCK,
TWASMInt32(code_entry^.CodeIndex + code_entry^.CodeLength),
TWASMInt32(os^.Top));
{ Switch to callee }
Context^.ExecutionState.IP := code_entry^.CodeIndex;
Context^.ExecutionState.Locals := new_locals;
end;
end.
@@ -0,0 +1,19 @@
unit wasm.vm.opcode.callindirect;
interface
uses wasm.types.context;
procedure _WASM_opcode_CallIndirectOp(Context : PWASMProcessContext);
implementation
uses console;
procedure _WASM_opcode_CallIndirectOp(Context : PWASMProcessContext);
begin
console.writestringln('[wasm.vm.opcodes] Trap: call_indirect requires table support!');
Context^.ExecutionState.Running := false;
end;
end.
@@ -0,0 +1,24 @@
unit wasm.vm.opcode.drop;
interface
uses wasm.types.context;
procedure _WASM_opcode_DropOp(Context : PWASMProcessContext);
implementation
uses console;
procedure _WASM_opcode_DropOp(Context : PWASMProcessContext);
begin
Inc(Context^.ExecutionState.IP);
if Context^.ExecutionState.Operand_Stack^.Top > 0 then
Dec(Context^.ExecutionState.Operand_Stack^.Top)
else begin
console.writestringln('[wasm.vm.opcodes.dropop] Stack underflow!');
Context^.ExecutionState.Running := false;
end;
end;
end.
@@ -0,0 +1,43 @@
unit wasm.vm.opcode.elseop;
interface
uses wasm.types.context;
procedure _WASM_opcode_ElseOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.values, wasm.types.stack, wasm.vm.control;
procedure _WASM_opcode_ElseOp(Context : PWASMProcessContext);
var
cs, os: PWASMStack;
saved_top: TWASMInt32;
end_ip: TWASMUInt32;
result_entry: TWASMStackEntry;
begin
cs := Context^.ExecutionState.Control_Stack;
os := Context^.ExecutionState.Operand_Stack;
{ Reached by falling through from if-true body }
saved_top := cs^.Entries[cs^.Top - 2].i32Value;
{ Preserve result value if any }
if os^.Top > TWASMUInt32(saved_top) then begin
result_entry := os^.Entries[os^.Top - 1];
os^.Top := TWASMUInt32(saved_top);
os^.Entries[os^.Top] := result_entry;
Inc(os^.Top);
end else begin
os^.Top := TWASMUInt32(saved_top);
end;
{ Pop the IF frame }
Dec(cs^.Top, 3);
{ Skip the else body to the matching end }
Inc(Context^.ExecutionState.IP); { past else byte }
end_ip := scan_forward(Context^.ExecutionState.Code,
Context^.ExecutionState.IP,
Context^.ExecutionState.Limit, false);
Context^.ExecutionState.IP := end_ip + 1; { past end byte }
end;
end.
@@ -0,0 +1,70 @@
unit wasm.vm.opcode.endop;
interface
uses wasm.types.context;
procedure _WASM_opcode_EndOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.values, wasm.types.constants;
procedure _WASM_opcode_EndOp(Context : PWASMProcessContext);
var
cs, os: PWASMStack;
saved_top, return_ip: TWASMInt32;
result_entry: TWASMStackEntry;
begin
cs := Context^.ExecutionState.Control_Stack;
os := Context^.ExecutionState.Operand_Stack;
{ No control frame: end of top-level code }
if cs^.Top = 0 then begin
Context^.ExecutionState.Running := false;
exit;
end;
{ Read the top control frame }
saved_top := cs^.Entries[cs^.Top - 2].i32Value;
{ Preserve block result value }
if os^.Top > TWASMUInt32(saved_top) then begin
result_entry := os^.Entries[os^.Top - 1];
os^.Top := TWASMUInt32(saved_top);
os^.Entries[os^.Top] := result_entry;
Inc(os^.Top);
end else begin
os^.Top := TWASMUInt32(saved_top);
end;
{ Pop the block frame }
Dec(cs^.Top, 3);
{ Check if a call frame is now on top (function return) }
if (cs^.Top >= 4) and (cs^.Entries[cs^.Top - 1].i32Value = CTRL_FRAME_CALL) then begin
saved_top := cs^.Entries[cs^.Top - 2].i32Value;
return_ip := cs^.Entries[cs^.Top - 3].i32Value;
{ Move return values to caller stack level }
if os^.Top > TWASMUInt32(saved_top) then begin
result_entry := os^.Entries[os^.Top - 1];
os^.Top := TWASMUInt32(saved_top);
os^.Entries[os^.Top] := result_entry;
Inc(os^.Top);
end else begin
os^.Top := TWASMUInt32(saved_top);
end;
{ Restore locals }
Context^.ExecutionState.Locals := PWASMLocals(cs^.Entries[cs^.Top - 4].i64Value);
{ Pop call frame }
Dec(cs^.Top, 4);
{ Resume caller }
Context^.ExecutionState.IP := TWASMUInt32(return_ip);
exit;
end;
{ Normal block/loop/if end: advance past end byte }
Inc(Context^.ExecutionState.IP);
end;
end.
@@ -0,0 +1,23 @@
unit wasm.vm.opcode.f32const;
interface
uses wasm.types.context;
procedure _WASM_opcode_F32ConstOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.stack;
procedure _WASM_opcode_F32ConstOp(Context : PWASMProcessContext);
var
value : TWASMFloat;
begin
Inc(Context^.ExecutionState.IP);
value := TWASMPFloat(@Context^.ExecutionState.Code[Context^.ExecutionState.IP])^;
Inc(Context^.ExecutionState.IP, 4);
wasm.types.stack.pushf32(Context^.ExecutionState.Operand_Stack, value);
end;
end.
@@ -0,0 +1,25 @@
unit wasm.vm.opcode.f32eq;
interface
uses wasm.types.context;
procedure _WASM_opcode_F32EqOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.stack;
procedure _WASM_opcode_F32EqOp(Context : PWASMProcessContext);
var a, b : TWASMFloat;
begin
Inc(Context^.ExecutionState.IP);
b := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
a := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
if a = b then
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 1)
else
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 0);
end;
end.
@@ -0,0 +1,25 @@
unit wasm.vm.opcode.f32ge;
interface
uses wasm.types.context;
procedure _WASM_opcode_F32GeOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.stack;
procedure _WASM_opcode_F32GeOp(Context : PWASMProcessContext);
var a, b : TWASMFloat;
begin
Inc(Context^.ExecutionState.IP);
b := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
a := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
if a >= b then
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 1)
else
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 0);
end;
end.
@@ -0,0 +1,25 @@
unit wasm.vm.opcode.f32gt;
interface
uses wasm.types.context;
procedure _WASM_opcode_F32GtOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.stack;
procedure _WASM_opcode_F32GtOp(Context : PWASMProcessContext);
var a, b : TWASMFloat;
begin
Inc(Context^.ExecutionState.IP);
b := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
a := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
if a > b then
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 1)
else
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 0);
end;
end.
@@ -0,0 +1,25 @@
unit wasm.vm.opcode.f32le;
interface
uses wasm.types.context;
procedure _WASM_opcode_F32LeOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.stack;
procedure _WASM_opcode_F32LeOp(Context : PWASMProcessContext);
var a, b : TWASMFloat;
begin
Inc(Context^.ExecutionState.IP);
b := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
a := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
if a <= b then
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 1)
else
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 0);
end;
end.
@@ -0,0 +1,29 @@
unit wasm.vm.opcode.f32load;
interface
uses wasm.types.context;
procedure _WASM_opcode_F32LoadOp(Context : PWASMProcessContext);
implementation
uses console, leb128, wasm.types.builtin, wasm.types.heap, wasm.types.stack;
procedure _WASM_opcode_F32LoadOp(Context : PWASMProcessContext);
var align_val, offset_val : TWASMUInt32; bytesRead : TWASMUInt8; addr : TWASMUInt32; result_val : TWASMUInt32;
begin
Inc(Context^.ExecutionState.IP);
bytesRead := read_leb128_to_uint32(@Context^.ExecutionState.Code[Context^.ExecutionState.IP], TWASMPUInt8(Context^.ExecutionState.Code + Context^.ExecutionState.Limit), @align_val);
Inc(Context^.ExecutionState.IP, bytesRead);
bytesRead := read_leb128_to_uint32(@Context^.ExecutionState.Code[Context^.ExecutionState.IP], TWASMPUInt8(Context^.ExecutionState.Code + Context^.ExecutionState.Limit), @offset_val);
Inc(Context^.ExecutionState.IP, bytesRead);
addr := TWASMUInt32(wasm.types.stack.popi32(Context^.ExecutionState.Operand_Stack)) + offset_val;
if not wasm.types.heap.read_uint32(addr, Context^.ExecutionState.Memory, @result_val) then begin
console.writestringln('[wasm.vm.opcodes] Trap: f32.load out of bounds!');
Context^.ExecutionState.Running := false;
end else
wasm.types.stack.pushf32(Context^.ExecutionState.Operand_Stack, TWASMPFloat(@result_val)^);
end;
end.
@@ -0,0 +1,25 @@
unit wasm.vm.opcode.f32lt;
interface
uses wasm.types.context;
procedure _WASM_opcode_F32LtOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.stack;
procedure _WASM_opcode_F32LtOp(Context : PWASMProcessContext);
var a, b : TWASMFloat;
begin
Inc(Context^.ExecutionState.IP);
b := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
a := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
if a < b then
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 1)
else
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 0);
end;
end.
@@ -0,0 +1,25 @@
unit wasm.vm.opcode.f32ne;
interface
uses wasm.types.context;
procedure _WASM_opcode_F32NeOp(Context : PWASMProcessContext);
implementation
uses wasm.types.builtin, wasm.types.stack;
procedure _WASM_opcode_F32NeOp(Context : PWASMProcessContext);
var a, b : TWASMFloat;
begin
Inc(Context^.ExecutionState.IP);
b := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
a := wasm.types.stack.popf32(Context^.ExecutionState.Operand_Stack);
if a <> b then
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 1)
else
wasm.types.stack.pushi32(Context^.ExecutionState.Operand_Stack, 0);
end;
end.
Loaded 20 of 123 files, more files were not shown because too many files have changed in this diff. Show more