Merge branch 'feature/opcode-refactor' into develop
This commit is contained in:
commit
255ad4806e
123 files changed
+3590
-1885
No files matched your search
@@ -60,6 +60,7 @@ REM ── Build ─────────────────────
|
||||
-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"
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
Reference in new issue
Block a user