package interpreter
import (
"context"
"encoding/binary"
"errors"
"fmt"
"math"
"math/bits"
"slices"
"sync"
"unsafe"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/internal/expctxkeys"
"github.com/tetratelabs/wazero/internal/filecache"
"github.com/tetratelabs/wazero/internal/internalapi"
"github.com/tetratelabs/wazero/internal/moremath"
"github.com/tetratelabs/wazero/internal/wasm"
"github.com/tetratelabs/wazero/internal/wasmdebug"
"github.com/tetratelabs/wazero/internal/wasmruntime"
)
var callStackCeiling = 2000
type compiledFunctionWithCount struct {
funcs []compiledFunction
refCount int
}
type engine struct {
enabledFeatures api .CoreFeatures
compiledFunctions map [wasm .ModuleID ]*compiledFunctionWithCount
mux sync .Mutex
}
func NewEngine (_ context .Context , enabledFeatures api .CoreFeatures , _ filecache .Cache ) wasm .Engine {
return &engine {
enabledFeatures : enabledFeatures ,
compiledFunctions : map [wasm .ModuleID ]*compiledFunctionWithCount {},
}
}
func (e *engine ) Close () (err error ) {
e .mux .Lock ()
defer e .mux .Unlock ()
clear (e .compiledFunctions )
return
}
func (e *engine ) CompiledModuleCount () uint32 {
e .mux .Lock ()
defer e .mux .Unlock ()
return uint32 (len (e .compiledFunctions ))
}
func (e *engine ) DeleteCompiledModule (m *wasm .Module ) {
e .deleteCompiledFunctions (m )
}
func (e *engine ) deleteCompiledFunctions (module *wasm .Module ) {
e .mux .Lock ()
defer e .mux .Unlock ()
cf , ok := e .compiledFunctions [module .ID ]
if !ok {
return
}
cf .refCount --
if cf .refCount > 0 {
return
}
delete (e .compiledFunctions , module .ID )
}
func (e *engine ) addCompiledFunctions (module *wasm .Module , fs []compiledFunction ) {
e .mux .Lock ()
defer e .mux .Unlock ()
if c , ok := e .compiledFunctions [module .ID ]; ok {
c .refCount ++
return
}
e .compiledFunctions [module .ID ] = &compiledFunctionWithCount {funcs : fs , refCount : 1 }
}
func (e *engine ) getCompiledFunctions (module *wasm .Module , increaseRefCount bool ) (fs []compiledFunction , ok bool ) {
e .mux .Lock ()
defer e .mux .Unlock ()
cf , ok := e .compiledFunctions [module .ID ]
if ok {
fs = cf .funcs
if increaseRefCount {
cf .refCount ++
}
}
return
}
type moduleEngine struct {
functions []function
parentEngine *engine
}
func (e *moduleEngine ) GetGlobalValue (wasm .Index ) (lo , hi uint64 ) {
panic ("BUG: GetGlobalValue should never be called on interpreter mode" )
}
func (e *moduleEngine ) SetGlobalValue (idx wasm .Index , lo , hi uint64 ) {
panic ("BUG: SetGlobalValue should never be called on interpreter mode" )
}
func (e *moduleEngine ) OwnsGlobals () bool { return false }
func (e *moduleEngine ) MemoryGrown () {}
type callEngine struct {
internalapi .WazeroOnlyType
stack []uint64
frames []*callFrame
f *function
stackIterator stackIterator
}
func (e *moduleEngine ) newCallEngine (compiled *function ) *callEngine {
return &callEngine {f : compiled }
}
func (ce *callEngine ) pushValue (v uint64 ) {
ce .stack = append (ce .stack , v )
}
func (ce *callEngine ) pushValues (v []uint64 ) {
ce .stack = append (ce .stack , v ...)
}
func (ce *callEngine ) popValue () (v uint64 ) {
stackTopIndex := len (ce .stack ) - 1
v = ce .stack [stackTopIndex ]
ce .stack = ce .stack [:stackTopIndex ]
return
}
func (ce *callEngine ) popValues (v []uint64 ) {
stackTopIndex := len (ce .stack ) - len (v )
copy (v , ce .stack [stackTopIndex :])
ce .stack = ce .stack [:stackTopIndex ]
}
func (ce *callEngine ) peekValues (count int ) []uint64 {
if count == 0 {
return nil
}
stackLen := len (ce .stack )
return ce .stack [stackLen -count : stackLen ]
}
func (ce *callEngine ) drop (raw uint64 ) {
r := inclusiveRangeFromU64 (raw )
if r .Start == -1 {
return
} else if r .Start == 0 {
ce .stack = ce .stack [:int32 (len (ce .stack ))-1 -r .End ]
} else {
newStack := ce .stack [:int32 (len (ce .stack ))-1 -r .End ]
newStack = append (newStack , ce .stack [int32 (len (ce .stack ))-r .Start :]...)
ce .stack = newStack
}
}
func (ce *callEngine ) pushFrame (frame *callFrame ) {
if callStackCeiling <= len (ce .frames ) {
panic (wasmruntime .ErrRuntimeStackOverflow )
}
ce .frames = append (ce .frames , frame )
}
func (ce *callEngine ) popFrame () (frame *callFrame ) {
oneLess := len (ce .frames ) - 1
frame = ce .frames [oneLess ]
ce .frames = ce .frames [:oneLess ]
return
}
type callFrame struct {
pc uint64
f *function
base int
}
type compiledFunction struct {
source *wasm .Module
body []unionOperation
listener experimental .FunctionListener
offsetsInWasmBinary []uint64
hostFn interface {}
ensureTermination bool
index wasm .Index
}
type function struct {
funcType *wasm .FunctionType
moduleInstance *wasm .ModuleInstance
typeID wasm .FunctionTypeID
parent *compiledFunction
}
func functionFromUintptr(ptr uintptr ) *function {
var wrapped *uintptr = &ptr
return *(**function )(unsafe .Pointer (wrapped ))
}
type snapshot struct {
stack []uint64
frames []*callFrame
pc uint64
ret []uint64
ce *callEngine
}
func (ce *callEngine ) Snapshot () experimental .Snapshot {
return &snapshot {
stack : slices .Clone (ce .stack ),
frames : slices .Clone (ce .frames ),
ce : ce ,
}
}
func (s *snapshot ) Restore (ret []uint64 ) {
s .ret = ret
panic (s )
}
func (s *snapshot ) doRestore () {
ce := s .ce
ce .stack = s .stack
ce .frames = s .frames
ce .frames [len (ce .frames )-1 ].pc = s .pc
copy (ce .stack [len (ce .stack )-len (s .ret ):], s .ret )
}
func (s *snapshot ) Error () string {
return "unhandled snapshot restore, this generally indicates restore was called from a different " +
"exported function invocation than snapshot"
}
type stackIterator struct {
stack []uint64
frames []*callFrame
started bool
fn *function
pc uint64
}
func (si *stackIterator ) reset (stack []uint64 , frames []*callFrame , f *function ) {
si .fn = f
si .pc = 0
si .stack = stack
si .frames = frames
si .started = false
}
func (si *stackIterator ) clear () {
si .stack = nil
si .frames = nil
si .started = false
si .fn = nil
}
func (si *stackIterator ) Next () bool {
if !si .started {
si .started = true
return true
}
if len (si .frames ) == 0 {
return false
}
frame := si .frames [len (si .frames )-1 ]
si .stack = si .stack [:frame .base ]
si .fn = frame .f
si .pc = frame .pc
si .frames = si .frames [:len (si .frames )-1 ]
return true
}
func (si *stackIterator ) Function () experimental .InternalFunction {
return internalFunction {si .fn }
}
func (si *stackIterator ) ProgramCounter () experimental .ProgramCounter {
return experimental .ProgramCounter (si .pc )
}
type internalFunction struct { *function }
func (f internalFunction ) Definition () api .FunctionDefinition {
return f .definition ()
}
func (f internalFunction ) SourceOffsetForPC (pc experimental .ProgramCounter ) uint64 {
offsetsMap := f .parent .offsetsInWasmBinary
if uint64 (pc ) < uint64 (len (offsetsMap )) {
return offsetsMap [pc ]
}
return 0
}
const callFrameStackSize = 0
func (e *engine ) CompileModule (_ context .Context , module *wasm .Module , listeners []experimental .FunctionListener , ensureTermination bool ) error {
if _ , ok := e .getCompiledFunctions (module , true ); ok {
return nil
}
funcs := make ([]compiledFunction , len (module .FunctionSection ))
irCompiler , err := newCompiler (e .enabledFeatures , callFrameStackSize , module , ensureTermination )
if err != nil {
return err
}
imported := module .ImportFunctionCount
for i := range module .CodeSection {
var lsn experimental .FunctionListener
if i < len (listeners ) {
lsn = listeners [i ]
}
compiled := &funcs [i ]
if codeSeg := &module .CodeSection [i ]; codeSeg .GoFunc != nil {
compiled .hostFn = codeSeg .GoFunc
} else {
ir , err := irCompiler .Next ()
if err != nil {
return err
}
err = e .lowerIR (ir , compiled )
if err != nil {
def := module .FunctionDefinition (uint32 (i ) + module .ImportFunctionCount )
return fmt .Errorf ("failed to lower func[%s] to interpreterir: %w" , def .DebugName (), err )
}
}
compiled .source = module
compiled .ensureTermination = ensureTermination
compiled .listener = lsn
compiled .index = imported + uint32 (i )
}
e .addCompiledFunctions (module , funcs )
return nil
}
func (e *engine ) NewModuleEngine (module *wasm .Module , instance *wasm .ModuleInstance ) (wasm .ModuleEngine , error ) {
me := &moduleEngine {
parentEngine : e ,
functions : make ([]function , len (module .FunctionSection )+int (module .ImportFunctionCount )),
}
codes , ok := e .getCompiledFunctions (module , false )
if !ok {
return nil , errors .New ("source module must be compiled before instantiation" )
}
for i := range codes {
c := &codes [i ]
offset := i + int (module .ImportFunctionCount )
typeIndex := module .FunctionSection [i ]
me .functions [offset ] = function {
moduleInstance : instance ,
typeID : instance .TypeIDs [typeIndex ],
funcType : &module .TypeSection [typeIndex ],
parent : c ,
}
}
return me , nil
}
func (e *engine ) lowerIR (ir *compilationResult , ret *compiledFunction ) error {
ret .body = slices .Clone (ir .Operations )
if offsets := ir .IROperationSourceOffsetsInWasmBinary ; len (offsets ) > 0 {
ret .offsetsInWasmBinary = slices .Clone (offsets )
}
labelAddressResolutions := [labelKindNum ][]uint64 {}
for i := range ret .body {
op := &ret .body [i ]
switch op .Kind {
case operationKindLabel :
label := label (op .U1 )
address := uint64 (i )
kind , fid := label .Kind (), label .FrameID ()
frameToAddresses := labelAddressResolutions [label .Kind ()]
if diff := fid - len (frameToAddresses ) + 1 ; diff > 0 {
frameToAddresses = append (frameToAddresses , make ([]uint64 , diff )...)
}
frameToAddresses [fid ] = address
labelAddressResolutions [kind ] = frameToAddresses
}
}
for i := range ret .body {
op := &ret .body [i ]
switch op .Kind {
case operationKindBr :
e .setLabelAddress (&op .U1 , label (op .U1 ), labelAddressResolutions )
case operationKindBrIf :
e .setLabelAddress (&op .U1 , label (op .U1 ), labelAddressResolutions )
e .setLabelAddress (&op .U2 , label (op .U2 ), labelAddressResolutions )
case operationKindBrTable :
for j := 0 ; j < len (op .Us ); j += 2 {
target := op .Us [j ]
e .setLabelAddress (&op .Us [j ], label (target ), labelAddressResolutions )
}
case operationKindTailCallReturnCallIndirect :
e .setLabelAddress (&op .Us [1 ], label (op .Us [1 ]), labelAddressResolutions )
}
}
return nil
}
func (e *engine ) setLabelAddress (op *uint64 , label label , labelAddressResolutions [labelKindNum ][]uint64 ) {
if label .IsReturnTarget () {
*op = math .MaxUint64
} else {
*op = labelAddressResolutions [label .Kind ()][label .FrameID ()]
}
}
func (e *moduleEngine ) ResolveImportedFunction (index , descFunc , indexInImportedModule wasm .Index , importedModuleEngine wasm .ModuleEngine ) {
imported := importedModuleEngine .(*moduleEngine )
e .functions [index ] = imported .functions [indexInImportedModule ]
}
func (e *moduleEngine ) ResolveImportedMemory (wasm .ModuleEngine ) {}
func (e *moduleEngine ) DoneInstantiation () {}
func (e *moduleEngine ) FunctionInstanceReference (funcIndex wasm .Index ) wasm .Reference {
return uintptr (unsafe .Pointer (&e .functions [funcIndex ]))
}
func (e *moduleEngine ) NewFunction (index wasm .Index ) (ce api .Function ) {
compiled := &e .functions [index ]
return e .newCallEngine (compiled )
}
func (e *moduleEngine ) LookupFunction (t *wasm .TableInstance , typeId wasm .FunctionTypeID , tableOffset wasm .Index ) (*wasm .ModuleInstance , wasm .Index ) {
if tableOffset >= uint32 (len (t .References )) {
panic (wasmruntime .ErrRuntimeInvalidTableAccess )
}
rawPtr := t .References [tableOffset ]
if rawPtr == 0 {
panic (wasmruntime .ErrRuntimeInvalidTableAccess )
}
tf := functionFromUintptr (rawPtr )
if tf .typeID != typeId {
panic (wasmruntime .ErrRuntimeIndirectCallTypeMismatch )
}
return tf .moduleInstance , tf .parent .index
}
func (ce *callEngine ) Definition () api .FunctionDefinition {
return ce .f .definition ()
}
func (f *function ) definition () api .FunctionDefinition {
compiled := f .parent
return compiled .source .FunctionDefinition (compiled .index )
}
func (ce *callEngine ) Call (ctx context .Context , params ...uint64 ) (results []uint64 , err error ) {
ft := ce .f .funcType
if n := ft .ParamNumInUint64 ; n != len (params ) {
return nil , fmt .Errorf ("expected %d params, but passed %d" , n , len (params ))
}
return ce .call (ctx , params , nil )
}
func (ce *callEngine ) CallWithStack (ctx context .Context , stack []uint64 ) error {
params , results , err := wasm .SplitCallStack (ce .f .funcType , stack )
if err != nil {
return err
}
_, err = ce .call (ctx , params , results )
return err
}
func (ce *callEngine ) call (ctx context .Context , params , results []uint64 ) (_ []uint64 , err error ) {
m := ce .f .moduleInstance
if ce .f .parent .ensureTermination {
select {
case <- ctx .Done ():
m .CloseWithCtxErr (ctx )
return nil , m .FailIfClosed ()
default :
}
}
if ctx .Value (expctxkeys .EnableSnapshotterKey {}) != nil {
ctx = context .WithValue (ctx , expctxkeys .SnapshotterKey {}, ce )
}
defer func () {
if err == nil {
err = m .FailIfClosed ()
}
if v := recover (); v != nil {
err = ce .recoverOnCall (ctx , m , v )
}
}()
ce .pushValues (params )
if ce .f .parent .ensureTermination {
done := m .CloseModuleOnCanceledOrTimeout (ctx )
defer done ()
}
ce .callFunction (ctx , m , ce .f )
ft := ce .f .funcType
if results == nil && ft .ResultNumInUint64 > 0 {
results = make ([]uint64 , ft .ResultNumInUint64 )
}
ce .popValues (results )
return results , nil
}
type functionListenerInvocation struct {
experimental .FunctionListener
def api .FunctionDefinition
}
func (ce *callEngine ) recoverOnCall (ctx context .Context , m *wasm .ModuleInstance , v interface {}) (err error ) {
if s , ok := v .(*snapshot ); ok {
panic (s )
}
builder := wasmdebug .NewErrorBuilder ()
frameCount := len (ce .frames )
functionListeners := make ([]functionListenerInvocation , 0 , 16 )
if frameCount > wasmdebug .MaxFrames {
frameCount = wasmdebug .MaxFrames
}
for i := 0 ; i < frameCount ; i ++ {
frame := ce .popFrame ()
f := frame .f
def := f .definition ()
var sources []string
if parent := frame .f .parent ; parent .body != nil && len (parent .offsetsInWasmBinary ) > 0 {
sources = parent .source .DWARFLines .Line (parent .offsetsInWasmBinary [frame .pc ])
}
builder .AddFrame (def .DebugName (), def .ParamTypes (), def .ResultTypes (), sources )
if f .parent .listener != nil {
functionListeners = append (functionListeners , functionListenerInvocation {
FunctionListener : f .parent .listener ,
def : f .definition (),
})
}
}
err = builder .FromRecovered (v )
for i := range functionListeners {
functionListeners [i ].Abort (ctx , m , functionListeners [i ].def , err )
}
ce .stack , ce .frames = ce .stack [:0 ], ce .frames [:0 ]
return
}
func (ce *callEngine ) callFunction (ctx context .Context , m *wasm .ModuleInstance , f *function ) {
if f .parent .hostFn != nil {
ce .callGoFuncWithStack (ctx , m , f )
} else if lsn := f .parent .listener ; lsn != nil {
ce .callNativeFuncWithListener (ctx , m , f , lsn )
} else {
ce .callNativeFunc (ctx , m , f )
}
}
func (ce *callEngine ) callGoFunc (ctx context .Context , m *wasm .ModuleInstance , f *function , stack []uint64 ) {
typ := f .funcType
lsn := f .parent .listener
if lsn != nil {
params := stack [:typ .ParamNumInUint64 ]
ce .stackIterator .reset (ce .stack , ce .frames , f )
lsn .Before (ctx , m , f .definition (), params , &ce .stackIterator )
ce .stackIterator .clear ()
}
frame := &callFrame {f : f , base : len (ce .stack )}
ce .pushFrame (frame )
fn := f .parent .hostFn
switch fn := fn .(type ) {
case api .GoModuleFunction :
fn .Call (ctx , m , stack )
case api .GoFunction :
fn .Call (ctx , stack )
}
ce .popFrame ()
if lsn != nil {
results := stack [:typ .ResultNumInUint64 ]
lsn .After (ctx , m , f .definition (), results )
}
}
func (ce *callEngine ) callNativeFunc (ctx context .Context , m *wasm .ModuleInstance , f *function ) {
frame := &callFrame {f : f , base : len (ce .stack )}
moduleInst := f .moduleInstance
functions := moduleInst .Engine .(*moduleEngine ).functions
memoryInst := moduleInst .MemoryInstance
globals := moduleInst .Globals
tables := moduleInst .Tables
typeIDs := moduleInst .TypeIDs
dataInstances := moduleInst .DataInstances
elementInstances := moduleInst .ElementInstances
ce .pushFrame (frame )
body := frame .f .parent .body
bodyLen := uint64 (len (body ))
for frame .pc < bodyLen {
op := &body [frame .pc ]
switch op .Kind {
case operationKindBuiltinFunctionCheckExitCode :
if err := m .FailIfClosed (); err != nil {
panic (err )
}
frame .pc ++
case operationKindUnreachable :
panic (wasmruntime .ErrRuntimeUnreachable )
case operationKindBr :
frame .pc = op .U1
case operationKindBrIf :
if ce .popValue () > 0 {
ce .drop (op .U3 )
frame .pc = op .U1
} else {
frame .pc = op .U2
}
case operationKindBrTable :
v := ce .popValue ()
defaultAt := uint64 (len (op .Us ))/2 - 1
if v > defaultAt {
v = defaultAt
}
v *= 2
ce .drop (op .Us [v +1 ])
frame .pc = op .Us [v ]
case operationKindCall :
func () {
if ctx .Value (expctxkeys .EnableSnapshotterKey {}) != nil {
defer func () {
if r := recover (); r != nil {
if s , ok := r .(*snapshot ); ok && s .ce == ce {
s .doRestore ()
frame = ce .frames [len (ce .frames )-1 ]
body = frame .f .parent .body
bodyLen = uint64 (len (body ))
} else {
panic (r )
}
}
}()
}
ce .callFunction (ctx , f .moduleInstance , &functions [op .U1 ])
}()
frame .pc ++
case operationKindCallIndirect :
offset := ce .popValue ()
table := tables [op .U2 ]
tf := ce .functionForOffset (table , offset , typeIDs [op .U1 ])
ce .callFunction (ctx , f .moduleInstance , tf )
frame .pc ++
case operationKindDrop :
ce .drop (op .U1 )
frame .pc ++
case operationKindSelect :
c := ce .popValue ()
if op .B3 {
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
if c == 0 {
_, _ = ce .popValue (), ce .popValue ()
ce .pushValue (x2Lo )
ce .pushValue (x2Hi )
}
} else {
v2 := ce .popValue ()
if c == 0 {
_ = ce .popValue ()
ce .pushValue (v2 )
}
}
frame .pc ++
case operationKindPick :
index := len (ce .stack ) - 1 - int (op .U1 )
ce .pushValue (ce .stack [index ])
if op .B3 {
ce .pushValue (ce .stack [index +1 ])
}
frame .pc ++
case operationKindSet :
if op .B3 {
lowIndex := len (ce .stack ) - 1 - int (op .U1 )
highIndex := lowIndex + 1
hi , lo := ce .popValue (), ce .popValue ()
ce .stack [lowIndex ], ce .stack [highIndex ] = lo , hi
} else {
index := len (ce .stack ) - 1 - int (op .U1 )
ce .stack [index ] = ce .popValue ()
}
frame .pc ++
case operationKindGlobalGet :
g := globals [op .U1 ]
ce .pushValue (g .Val )
if g .Type .ValType == wasm .ValueTypeV128 {
ce .pushValue (g .ValHi )
}
frame .pc ++
case operationKindGlobalSet :
g := globals [op .U1 ]
if g .Type .ValType == wasm .ValueTypeV128 {
g .ValHi = ce .popValue ()
}
g .Val = ce .popValue ()
frame .pc ++
case operationKindLoad :
offset := ce .popMemoryOffset (op )
switch unsignedType (op .B1 ) {
case unsignedTypeI32 , unsignedTypeF32 :
if val , ok := memoryInst .ReadUint32Le (offset ); !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
} else {
ce .pushValue (uint64 (val ))
}
case unsignedTypeI64 , unsignedTypeF64 :
if val , ok := memoryInst .ReadUint64Le (offset ); !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
} else {
ce .pushValue (val )
}
}
frame .pc ++
case operationKindLoad8 :
val , ok := memoryInst .ReadByte (ce .popMemoryOffset (op ))
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
switch signedInt (op .B1 ) {
case signedInt32 :
ce .pushValue (uint64 (uint32 (int8 (val ))))
case signedInt64 :
ce .pushValue (uint64 (int8 (val )))
case signedUint32 , signedUint64 :
ce .pushValue (uint64 (val ))
}
frame .pc ++
case operationKindLoad16 :
val , ok := memoryInst .ReadUint16Le (ce .popMemoryOffset (op ))
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
switch signedInt (op .B1 ) {
case signedInt32 :
ce .pushValue (uint64 (uint32 (int16 (val ))))
case signedInt64 :
ce .pushValue (uint64 (int16 (val )))
case signedUint32 , signedUint64 :
ce .pushValue (uint64 (val ))
}
frame .pc ++
case operationKindLoad32 :
val , ok := memoryInst .ReadUint32Le (ce .popMemoryOffset (op ))
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if op .B1 == 1 {
ce .pushValue (uint64 (int32 (val )))
} else {
ce .pushValue (uint64 (val ))
}
frame .pc ++
case operationKindStore :
val := ce .popValue ()
offset := ce .popMemoryOffset (op )
switch unsignedType (op .B1 ) {
case unsignedTypeI32 , unsignedTypeF32 :
if !memoryInst .WriteUint32Le (offset , uint32 (val )) {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
case unsignedTypeI64 , unsignedTypeF64 :
if !memoryInst .WriteUint64Le (offset , val ) {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
}
frame .pc ++
case operationKindStore8 :
val := byte (ce .popValue ())
offset := ce .popMemoryOffset (op )
if !memoryInst .WriteByte (offset , val ) {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
frame .pc ++
case operationKindStore16 :
val := uint16 (ce .popValue ())
offset := ce .popMemoryOffset (op )
if !memoryInst .WriteUint16Le (offset , val ) {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
frame .pc ++
case operationKindStore32 :
val := uint32 (ce .popValue ())
offset := ce .popMemoryOffset (op )
if !memoryInst .WriteUint32Le (offset , val ) {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
frame .pc ++
case operationKindMemorySize :
ce .pushValue (uint64 (memoryInst .Pages ()))
frame .pc ++
case operationKindMemoryGrow :
n := ce .popValue ()
if res , ok := memoryInst .Grow (uint32 (n )); !ok {
ce .pushValue (uint64 (0xffffffff ))
} else {
ce .pushValue (uint64 (res ))
}
frame .pc ++
case operationKindConstI32 , operationKindConstI64 ,
operationKindConstF32 , operationKindConstF64 :
ce .pushValue (op .U1 )
frame .pc ++
case operationKindEq :
var b bool
switch unsignedType (op .B1 ) {
case unsignedTypeI32 :
v2 , v1 := ce .popValue (), ce .popValue ()
b = uint32 (v1 ) == uint32 (v2 )
case unsignedTypeI64 :
v2 , v1 := ce .popValue (), ce .popValue ()
b = v1 == v2
case unsignedTypeF32 :
v2 , v1 := ce .popValue (), ce .popValue ()
b = math .Float32frombits (uint32 (v2 )) == math .Float32frombits (uint32 (v1 ))
case unsignedTypeF64 :
v2 , v1 := ce .popValue (), ce .popValue ()
b = math .Float64frombits (v2 ) == math .Float64frombits (v1 )
}
if b {
ce .pushValue (1 )
} else {
ce .pushValue (0 )
}
frame .pc ++
case operationKindNe :
var b bool
switch unsignedType (op .B1 ) {
case unsignedTypeI32 , unsignedTypeI64 :
v2 , v1 := ce .popValue (), ce .popValue ()
b = v1 != v2
case unsignedTypeF32 :
v2 , v1 := ce .popValue (), ce .popValue ()
b = math .Float32frombits (uint32 (v2 )) != math .Float32frombits (uint32 (v1 ))
case unsignedTypeF64 :
v2 , v1 := ce .popValue (), ce .popValue ()
b = math .Float64frombits (v2 ) != math .Float64frombits (v1 )
}
if b {
ce .pushValue (1 )
} else {
ce .pushValue (0 )
}
frame .pc ++
case operationKindEqz :
if ce .popValue () == 0 {
ce .pushValue (1 )
} else {
ce .pushValue (0 )
}
frame .pc ++
case operationKindLt :
v2 := ce .popValue ()
v1 := ce .popValue ()
var b bool
switch signedType (op .B1 ) {
case signedTypeInt32 :
b = int32 (v1 ) < int32 (v2 )
case signedTypeInt64 :
b = int64 (v1 ) < int64 (v2 )
case signedTypeUint32 , signedTypeUint64 :
b = v1 < v2
case signedTypeFloat32 :
b = math .Float32frombits (uint32 (v1 )) < math .Float32frombits (uint32 (v2 ))
case signedTypeFloat64 :
b = math .Float64frombits (v1 ) < math .Float64frombits (v2 )
}
if b {
ce .pushValue (1 )
} else {
ce .pushValue (0 )
}
frame .pc ++
case operationKindGt :
v2 := ce .popValue ()
v1 := ce .popValue ()
var b bool
switch signedType (op .B1 ) {
case signedTypeInt32 :
b = int32 (v1 ) > int32 (v2 )
case signedTypeInt64 :
b = int64 (v1 ) > int64 (v2 )
case signedTypeUint32 , signedTypeUint64 :
b = v1 > v2
case signedTypeFloat32 :
b = math .Float32frombits (uint32 (v1 )) > math .Float32frombits (uint32 (v2 ))
case signedTypeFloat64 :
b = math .Float64frombits (v1 ) > math .Float64frombits (v2 )
}
if b {
ce .pushValue (1 )
} else {
ce .pushValue (0 )
}
frame .pc ++
case operationKindLe :
v2 := ce .popValue ()
v1 := ce .popValue ()
var b bool
switch signedType (op .B1 ) {
case signedTypeInt32 :
b = int32 (v1 ) <= int32 (v2 )
case signedTypeInt64 :
b = int64 (v1 ) <= int64 (v2 )
case signedTypeUint32 , signedTypeUint64 :
b = v1 <= v2
case signedTypeFloat32 :
b = math .Float32frombits (uint32 (v1 )) <= math .Float32frombits (uint32 (v2 ))
case signedTypeFloat64 :
b = math .Float64frombits (v1 ) <= math .Float64frombits (v2 )
}
if b {
ce .pushValue (1 )
} else {
ce .pushValue (0 )
}
frame .pc ++
case operationKindGe :
v2 := ce .popValue ()
v1 := ce .popValue ()
var b bool
switch signedType (op .B1 ) {
case signedTypeInt32 :
b = int32 (v1 ) >= int32 (v2 )
case signedTypeInt64 :
b = int64 (v1 ) >= int64 (v2 )
case signedTypeUint32 , signedTypeUint64 :
b = v1 >= v2
case signedTypeFloat32 :
b = math .Float32frombits (uint32 (v1 )) >= math .Float32frombits (uint32 (v2 ))
case signedTypeFloat64 :
b = math .Float64frombits (v1 ) >= math .Float64frombits (v2 )
}
if b {
ce .pushValue (1 )
} else {
ce .pushValue (0 )
}
frame .pc ++
case operationKindAdd :
v2 := ce .popValue ()
v1 := ce .popValue ()
switch unsignedType (op .B1 ) {
case unsignedTypeI32 :
v := uint32 (v1 ) + uint32 (v2 )
ce .pushValue (uint64 (v ))
case unsignedTypeI64 :
ce .pushValue (v1 + v2 )
case unsignedTypeF32 :
ce .pushValue (addFloat32bits (uint32 (v1 ), uint32 (v2 )))
case unsignedTypeF64 :
v := math .Float64frombits (v1 ) + math .Float64frombits (v2 )
ce .pushValue (math .Float64bits (v ))
}
frame .pc ++
case operationKindSub :
v2 := ce .popValue ()
v1 := ce .popValue ()
switch unsignedType (op .B1 ) {
case unsignedTypeI32 :
ce .pushValue (uint64 (uint32 (v1 ) - uint32 (v2 )))
case unsignedTypeI64 :
ce .pushValue (v1 - v2 )
case unsignedTypeF32 :
ce .pushValue (subFloat32bits (uint32 (v1 ), uint32 (v2 )))
case unsignedTypeF64 :
v := math .Float64frombits (v1 ) - math .Float64frombits (v2 )
ce .pushValue (math .Float64bits (v ))
}
frame .pc ++
case operationKindMul :
v2 := ce .popValue ()
v1 := ce .popValue ()
switch unsignedType (op .B1 ) {
case unsignedTypeI32 :
ce .pushValue (uint64 (uint32 (v1 ) * uint32 (v2 )))
case unsignedTypeI64 :
ce .pushValue (v1 * v2 )
case unsignedTypeF32 :
ce .pushValue (mulFloat32bits (uint32 (v1 ), uint32 (v2 )))
case unsignedTypeF64 :
v := math .Float64frombits (v2 ) * math .Float64frombits (v1 )
ce .pushValue (math .Float64bits (v ))
}
frame .pc ++
case operationKindClz :
v := ce .popValue ()
if op .B1 == 0 {
ce .pushValue (uint64 (bits .LeadingZeros32 (uint32 (v ))))
} else {
ce .pushValue (uint64 (bits .LeadingZeros64 (v )))
}
frame .pc ++
case operationKindCtz :
v := ce .popValue ()
if op .B1 == 0 {
ce .pushValue (uint64 (bits .TrailingZeros32 (uint32 (v ))))
} else {
ce .pushValue (uint64 (bits .TrailingZeros64 (v )))
}
frame .pc ++
case operationKindPopcnt :
v := ce .popValue ()
if op .B1 == 0 {
ce .pushValue (uint64 (bits .OnesCount32 (uint32 (v ))))
} else {
ce .pushValue (uint64 (bits .OnesCount64 (v )))
}
frame .pc ++
case operationKindDiv :
t := signedType (op .B1 )
v2 , v1 := ce .popValue (), ce .popValue ()
switch t {
case signedTypeFloat32 , signedTypeFloat64 :
default :
if v2 == 0 {
panic (wasmruntime .ErrRuntimeIntegerDivideByZero )
}
}
switch t {
case signedTypeInt32 :
d := int32 (v2 )
n := int32 (v1 )
if n == math .MinInt32 && d == -1 {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
ce .pushValue (uint64 (uint32 (n / d )))
case signedTypeInt64 :
d := int64 (v2 )
n := int64 (v1 )
if n == math .MinInt64 && d == -1 {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
ce .pushValue (uint64 (n / d ))
case signedTypeUint32 :
d := uint32 (v2 )
n := uint32 (v1 )
ce .pushValue (uint64 (n / d ))
case signedTypeUint64 :
d := v2
n := v1
ce .pushValue (n / d )
case signedTypeFloat32 :
ce .pushValue (divFloat32bits (uint32 (v1 ), uint32 (v2 )))
case signedTypeFloat64 :
ce .pushValue (math .Float64bits (math .Float64frombits (v1 ) / math .Float64frombits (v2 )))
}
frame .pc ++
case operationKindRem :
v2 , v1 := ce .popValue (), ce .popValue ()
if v2 == 0 {
panic (wasmruntime .ErrRuntimeIntegerDivideByZero )
}
switch signedInt (op .B1 ) {
case signedInt32 :
d := int32 (v2 )
n := int32 (v1 )
ce .pushValue (uint64 (uint32 (n % d )))
case signedInt64 :
d := int64 (v2 )
n := int64 (v1 )
ce .pushValue (uint64 (n % d ))
case signedUint32 :
d := uint32 (v2 )
n := uint32 (v1 )
ce .pushValue (uint64 (n % d ))
case signedUint64 :
d := v2
n := v1
ce .pushValue (n % d )
}
frame .pc ++
case operationKindAnd :
v2 := ce .popValue ()
v1 := ce .popValue ()
if op .B1 == 0 {
ce .pushValue (uint64 (uint32 (v2 ) & uint32 (v1 )))
} else {
ce .pushValue (uint64 (v2 & v1 ))
}
frame .pc ++
case operationKindOr :
v2 := ce .popValue ()
v1 := ce .popValue ()
if op .B1 == 0 {
ce .pushValue (uint64 (uint32 (v2 ) | uint32 (v1 )))
} else {
ce .pushValue (uint64 (v2 | v1 ))
}
frame .pc ++
case operationKindXor :
v2 := ce .popValue ()
v1 := ce .popValue ()
if op .B1 == 0 {
ce .pushValue (uint64 (uint32 (v2 ) ^ uint32 (v1 )))
} else {
ce .pushValue (uint64 (v2 ^ v1 ))
}
frame .pc ++
case operationKindShl :
v2 := ce .popValue ()
v1 := ce .popValue ()
if op .B1 == 0 {
ce .pushValue (uint64 (uint32 (v1 ) << (uint32 (v2 ) % 32 )))
} else {
ce .pushValue (v1 << (v2 % 64 ))
}
frame .pc ++
case operationKindShr :
v2 := ce .popValue ()
v1 := ce .popValue ()
switch signedInt (op .B1 ) {
case signedInt32 :
ce .pushValue (uint64 (uint32 (int32 (v1 ) >> (uint32 (v2 ) % 32 ))))
case signedInt64 :
ce .pushValue (uint64 (int64 (v1 ) >> (v2 % 64 )))
case signedUint32 :
ce .pushValue (uint64 (uint32 (v1 ) >> (uint32 (v2 ) % 32 )))
case signedUint64 :
ce .pushValue (v1 >> (v2 % 64 ))
}
frame .pc ++
case operationKindRotl :
v2 := ce .popValue ()
v1 := ce .popValue ()
if op .B1 == 0 {
ce .pushValue (uint64 (bits .RotateLeft32 (uint32 (v1 ), int (v2 ))))
} else {
ce .pushValue (uint64 (bits .RotateLeft64 (v1 , int (v2 ))))
}
frame .pc ++
case operationKindRotr :
v2 := ce .popValue ()
v1 := ce .popValue ()
if op .B1 == 0 {
ce .pushValue (uint64 (bits .RotateLeft32 (uint32 (v1 ), -int (v2 ))))
} else {
ce .pushValue (uint64 (bits .RotateLeft64 (v1 , -int (v2 ))))
}
frame .pc ++
case operationKindAbs :
if op .B1 == 0 {
const mask uint32 = 1 << 31
ce .pushValue (uint64 (uint32 (ce .popValue ()) &^ mask ))
} else {
const mask uint64 = 1 << 63
ce .pushValue (ce .popValue () &^ mask )
}
frame .pc ++
case operationKindNeg :
if op .B1 == 0 {
v := -math .Float32frombits (uint32 (ce .popValue ()))
ce .pushValue (uint64 (math .Float32bits (v )))
} else {
v := -math .Float64frombits (ce .popValue ())
ce .pushValue (math .Float64bits (v ))
}
frame .pc ++
case operationKindCeil :
if op .B1 == 0 {
v := moremath .WasmCompatCeilF32 (math .Float32frombits (uint32 (ce .popValue ())))
ce .pushValue (uint64 (math .Float32bits (v )))
} else {
v := moremath .WasmCompatCeilF64 (math .Float64frombits (ce .popValue ()))
ce .pushValue (math .Float64bits (v ))
}
frame .pc ++
case operationKindFloor :
if op .B1 == 0 {
v := moremath .WasmCompatFloorF32 (math .Float32frombits (uint32 (ce .popValue ())))
ce .pushValue (uint64 (math .Float32bits (v )))
} else {
v := moremath .WasmCompatFloorF64 (math .Float64frombits (ce .popValue ()))
ce .pushValue (math .Float64bits (v ))
}
frame .pc ++
case operationKindTrunc :
if op .B1 == 0 {
v := moremath .WasmCompatTruncF32 (math .Float32frombits (uint32 (ce .popValue ())))
ce .pushValue (uint64 (math .Float32bits (v )))
} else {
v := moremath .WasmCompatTruncF64 (math .Float64frombits (ce .popValue ()))
ce .pushValue (math .Float64bits (v ))
}
frame .pc ++
case operationKindNearest :
if op .B1 == 0 {
f := math .Float32frombits (uint32 (ce .popValue ()))
ce .pushValue (uint64 (math .Float32bits (moremath .WasmCompatNearestF32 (f ))))
} else {
f := math .Float64frombits (ce .popValue ())
ce .pushValue (math .Float64bits (moremath .WasmCompatNearestF64 (f )))
}
frame .pc ++
case operationKindSqrt :
if op .B1 == 0 {
v := math .Sqrt (float64 (math .Float32frombits (uint32 (ce .popValue ()))))
ce .pushValue (uint64 (math .Float32bits (float32 (v ))))
} else {
v := math .Sqrt (math .Float64frombits (ce .popValue ()))
ce .pushValue (math .Float64bits (v ))
}
frame .pc ++
case operationKindMin :
if op .B1 == 0 {
ce .pushValue (wasmCompatMin32bits (uint32 (ce .popValue ()), uint32 (ce .popValue ())))
} else {
v2 := math .Float64frombits (ce .popValue ())
v1 := math .Float64frombits (ce .popValue ())
ce .pushValue (math .Float64bits (moremath .WasmCompatMin64 (v1 , v2 )))
}
frame .pc ++
case operationKindMax :
if op .B1 == 0 {
ce .pushValue (wasmCompatMax32bits (uint32 (ce .popValue ()), uint32 (ce .popValue ())))
} else {
v2 := math .Float64frombits (ce .popValue ())
v1 := math .Float64frombits (ce .popValue ())
ce .pushValue (math .Float64bits (moremath .WasmCompatMax64 (v1 , v2 )))
}
frame .pc ++
case operationKindCopysign :
if op .B1 == 0 {
v2 := uint32 (ce .popValue ())
v1 := uint32 (ce .popValue ())
const signbit = 1 << 31
ce .pushValue (uint64 (v1 &^signbit | v2 &signbit ))
} else {
v2 := ce .popValue ()
v1 := ce .popValue ()
const signbit = 1 << 63
ce .pushValue (v1 &^signbit | v2 &signbit )
}
frame .pc ++
case operationKindI32WrapFromI64 :
ce .pushValue (uint64 (uint32 (ce .popValue ())))
frame .pc ++
case operationKindITruncFromF :
if op .B1 == 0 {
switch signedInt (op .B2 ) {
case signedInt32 :
v := math .Trunc (float64 (math .Float32frombits (uint32 (ce .popValue ()))))
if math .IsNaN (v ) {
if op .B3 {
v = 0
} else {
panic (wasmruntime .ErrRuntimeInvalidConversionToInteger )
}
} else if v < math .MinInt32 || v > math .MaxInt32 {
if op .B3 {
if v < 0 {
v = math .MinInt32
} else {
v = math .MaxInt32
}
} else {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
}
ce .pushValue (uint64 (uint32 (int32 (v ))))
case signedInt64 :
v := math .Trunc (float64 (math .Float32frombits (uint32 (ce .popValue ()))))
res := int64 (v )
if math .IsNaN (v ) {
if op .B3 {
res = 0
} else {
panic (wasmruntime .ErrRuntimeInvalidConversionToInteger )
}
} else if v < math .MinInt64 || v >= math .MaxInt64 {
if op .B3 {
if v < 0 {
res = math .MinInt64
} else {
res = math .MaxInt64
}
} else {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
}
ce .pushValue (uint64 (res ))
case signedUint32 :
v := math .Trunc (float64 (math .Float32frombits (uint32 (ce .popValue ()))))
if math .IsNaN (v ) {
if op .B3 {
v = 0
} else {
panic (wasmruntime .ErrRuntimeInvalidConversionToInteger )
}
} else if v < 0 || v > math .MaxUint32 {
if op .B3 {
if v < 0 {
v = 0
} else {
v = math .MaxUint32
}
} else {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
}
ce .pushValue (uint64 (uint32 (v )))
case signedUint64 :
v := math .Trunc (float64 (math .Float32frombits (uint32 (ce .popValue ()))))
res := uint64 (v )
if math .IsNaN (v ) {
if op .B3 {
res = 0
} else {
panic (wasmruntime .ErrRuntimeInvalidConversionToInteger )
}
} else if v < 0 || v >= math .MaxUint64 {
if op .B3 {
if v < 0 {
res = 0
} else {
res = math .MaxUint64
}
} else {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
}
ce .pushValue (res )
}
} else {
switch signedInt (op .B2 ) {
case signedInt32 :
v := math .Trunc (math .Float64frombits (ce .popValue ()))
if math .IsNaN (v ) {
if op .B3 {
v = 0
} else {
panic (wasmruntime .ErrRuntimeInvalidConversionToInteger )
}
} else if v < math .MinInt32 || v > math .MaxInt32 {
if op .B3 {
if v < 0 {
v = math .MinInt32
} else {
v = math .MaxInt32
}
} else {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
}
ce .pushValue (uint64 (uint32 (int32 (v ))))
case signedInt64 :
v := math .Trunc (math .Float64frombits (ce .popValue ()))
res := int64 (v )
if math .IsNaN (v ) {
if op .B3 {
res = 0
} else {
panic (wasmruntime .ErrRuntimeInvalidConversionToInteger )
}
} else if v < math .MinInt64 || v >= math .MaxInt64 {
if op .B3 {
if v < 0 {
res = math .MinInt64
} else {
res = math .MaxInt64
}
} else {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
}
ce .pushValue (uint64 (res ))
case signedUint32 :
v := math .Trunc (math .Float64frombits (ce .popValue ()))
if math .IsNaN (v ) {
if op .B3 {
v = 0
} else {
panic (wasmruntime .ErrRuntimeInvalidConversionToInteger )
}
} else if v < 0 || v > math .MaxUint32 {
if op .B3 {
if v < 0 {
v = 0
} else {
v = math .MaxUint32
}
} else {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
}
ce .pushValue (uint64 (uint32 (v )))
case signedUint64 :
v := math .Trunc (math .Float64frombits (ce .popValue ()))
res := uint64 (v )
if math .IsNaN (v ) {
if op .B3 {
res = 0
} else {
panic (wasmruntime .ErrRuntimeInvalidConversionToInteger )
}
} else if v < 0 || v >= math .MaxUint64 {
if op .B3 {
if v < 0 {
res = 0
} else {
res = math .MaxUint64
}
} else {
panic (wasmruntime .ErrRuntimeIntegerOverflow )
}
}
ce .pushValue (res )
}
}
frame .pc ++
case operationKindFConvertFromI :
switch signedInt (op .B1 ) {
case signedInt32 :
if op .B2 == 0 {
v := float32 (int32 (ce .popValue ()))
ce .pushValue (uint64 (math .Float32bits (v )))
} else {
v := float64 (int32 (ce .popValue ()))
ce .pushValue (math .Float64bits (v ))
}
case signedInt64 :
if op .B2 == 0 {
v := float32 (int64 (ce .popValue ()))
ce .pushValue (uint64 (math .Float32bits (v )))
} else {
v := float64 (int64 (ce .popValue ()))
ce .pushValue (math .Float64bits (v ))
}
case signedUint32 :
if op .B2 == 0 {
v := float32 (uint32 (ce .popValue ()))
ce .pushValue (uint64 (math .Float32bits (v )))
} else {
v := float64 (uint32 (ce .popValue ()))
ce .pushValue (math .Float64bits (v ))
}
case signedUint64 :
if op .B2 == 0 {
v := float32 (ce .popValue ())
ce .pushValue (uint64 (math .Float32bits (v )))
} else {
v := float64 (ce .popValue ())
ce .pushValue (math .Float64bits (v ))
}
}
frame .pc ++
case operationKindF32DemoteFromF64 :
v := float32 (math .Float64frombits (ce .popValue ()))
ce .pushValue (uint64 (math .Float32bits (v )))
frame .pc ++
case operationKindF64PromoteFromF32 :
v := float64 (math .Float32frombits (uint32 (ce .popValue ())))
ce .pushValue (math .Float64bits (v ))
frame .pc ++
case operationKindExtend :
if op .B1 == 1 {
v := int64 (int32 (ce .popValue ()))
ce .pushValue (uint64 (v ))
} else {
v := uint64 (uint32 (ce .popValue ()))
ce .pushValue (v )
}
frame .pc ++
case operationKindSignExtend32From8 :
v := uint32 (int8 (ce .popValue ()))
ce .pushValue (uint64 (v ))
frame .pc ++
case operationKindSignExtend32From16 :
v := uint32 (int16 (ce .popValue ()))
ce .pushValue (uint64 (v ))
frame .pc ++
case operationKindSignExtend64From8 :
v := int64 (int8 (ce .popValue ()))
ce .pushValue (uint64 (v ))
frame .pc ++
case operationKindSignExtend64From16 :
v := int64 (int16 (ce .popValue ()))
ce .pushValue (uint64 (v ))
frame .pc ++
case operationKindSignExtend64From32 :
v := int64 (int32 (ce .popValue ()))
ce .pushValue (uint64 (v ))
frame .pc ++
case operationKindMemoryInit :
dataInstance := dataInstances [op .U1 ]
copySize := ce .popValue ()
inDataOffset := ce .popValue ()
inMemoryOffset := ce .popValue ()
if inDataOffset +copySize > uint64 (len (dataInstance )) ||
inMemoryOffset +copySize > uint64 (len (memoryInst .Buffer )) {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
} else if copySize != 0 {
copy (memoryInst .Buffer [inMemoryOffset :inMemoryOffset +copySize ], dataInstance [inDataOffset :])
}
frame .pc ++
case operationKindDataDrop :
dataInstances [op .U1 ] = nil
frame .pc ++
case operationKindMemoryCopy :
memLen := uint64 (len (memoryInst .Buffer ))
copySize := ce .popValue ()
sourceOffset := ce .popValue ()
destinationOffset := ce .popValue ()
if sourceOffset +copySize > memLen || destinationOffset +copySize > memLen {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
} else if copySize != 0 {
copy (memoryInst .Buffer [destinationOffset :],
memoryInst .Buffer [sourceOffset :sourceOffset +copySize ])
}
frame .pc ++
case operationKindMemoryFill :
fillSize := ce .popValue ()
value := byte (ce .popValue ())
offset := ce .popValue ()
if fillSize +offset > uint64 (len (memoryInst .Buffer )) {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
} else if fillSize != 0 {
buf := memoryInst .Buffer [offset : offset +fillSize ]
if value == 0 {
clear (buf )
} else {
buf [0 ] = value
for i := 1 ; i < len (buf ); {
chunk := min (i , 8192 )
i += copy (buf [i :], buf [:chunk ])
}
}
}
frame .pc ++
case operationKindTableInit :
elementInstance := elementInstances [op .U1 ]
copySize := ce .popValue ()
inElementOffset := ce .popValue ()
inTableOffset := ce .popValue ()
table := tables [op .U2 ]
if inElementOffset +copySize > uint64 (len (elementInstance )) ||
inTableOffset +copySize > uint64 (len (table .References )) {
panic (wasmruntime .ErrRuntimeInvalidTableAccess )
} else if copySize != 0 {
copy (table .References [inTableOffset :inTableOffset +copySize ], elementInstance [inElementOffset :])
}
frame .pc ++
case operationKindElemDrop :
elementInstances [op .U1 ] = nil
frame .pc ++
case operationKindTableCopy :
srcTable , dstTable := tables [op .U1 ].References , tables [op .U2 ].References
copySize := ce .popValue ()
sourceOffset := ce .popValue ()
destinationOffset := ce .popValue ()
if sourceOffset +copySize > uint64 (len (srcTable )) || destinationOffset +copySize > uint64 (len (dstTable )) {
panic (wasmruntime .ErrRuntimeInvalidTableAccess )
} else if copySize != 0 {
copy (dstTable [destinationOffset :], srcTable [sourceOffset :sourceOffset +copySize ])
}
frame .pc ++
case operationKindRefFunc :
ce .pushValue (uint64 (uintptr (unsafe .Pointer (&functions [op .U1 ]))))
frame .pc ++
case operationKindTableGet :
table := tables [op .U1 ]
offset := ce .popValue ()
if offset >= uint64 (len (table .References )) {
panic (wasmruntime .ErrRuntimeInvalidTableAccess )
}
ce .pushValue (uint64 (table .References [offset ]))
frame .pc ++
case operationKindTableSet :
table := tables [op .U1 ]
ref := ce .popValue ()
offset := ce .popValue ()
if offset >= uint64 (len (table .References )) {
panic (wasmruntime .ErrRuntimeInvalidTableAccess )
}
table .References [offset ] = uintptr (ref )
frame .pc ++
case operationKindTableSize :
table := tables [op .U1 ]
ce .pushValue (uint64 (len (table .References )))
frame .pc ++
case operationKindTableGrow :
table := tables [op .U1 ]
num , ref := ce .popValue (), ce .popValue ()
ret := table .Grow (uint32 (num ), uintptr (ref ))
ce .pushValue (uint64 (ret ))
frame .pc ++
case operationKindTableFill :
table := tables [op .U1 ]
num := ce .popValue ()
ref := uintptr (ce .popValue ())
offset := ce .popValue ()
if num +offset > uint64 (len (table .References )) {
panic (wasmruntime .ErrRuntimeInvalidTableAccess )
} else if num > 0 {
targetRegion := table .References [offset : offset +num ]
targetRegion [0 ] = ref
for i := 1 ; i < len (targetRegion ); i *= 2 {
copy (targetRegion [i :], targetRegion [:i ])
}
}
frame .pc ++
case operationKindV128Const :
lo , hi := op .U1 , op .U2
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Add :
yHigh , yLow := ce .popValue (), ce .popValue ()
xHigh , xLow := ce .popValue (), ce .popValue ()
switch op .B1 {
case shapeI8x16 :
ce .pushValue (
uint64 (uint8 (xLow >>8 )+uint8 (yLow >>8 ))<<8 | uint64 (uint8 (xLow )+uint8 (yLow )) |
uint64 (uint8 (xLow >>24 )+uint8 (yLow >>24 ))<<24 | uint64 (uint8 (xLow >>16 )+uint8 (yLow >>16 ))<<16 |
uint64 (uint8 (xLow >>40 )+uint8 (yLow >>40 ))<<40 | uint64 (uint8 (xLow >>32 )+uint8 (yLow >>32 ))<<32 |
uint64 (uint8 (xLow >>56 )+uint8 (yLow >>56 ))<<56 | uint64 (uint8 (xLow >>48 )+uint8 (yLow >>48 ))<<48 ,
)
ce .pushValue (
uint64 (uint8 (xHigh >>8 )+uint8 (yHigh >>8 ))<<8 | uint64 (uint8 (xHigh )+uint8 (yHigh )) |
uint64 (uint8 (xHigh >>24 )+uint8 (yHigh >>24 ))<<24 | uint64 (uint8 (xHigh >>16 )+uint8 (yHigh >>16 ))<<16 |
uint64 (uint8 (xHigh >>40 )+uint8 (yHigh >>40 ))<<40 | uint64 (uint8 (xHigh >>32 )+uint8 (yHigh >>32 ))<<32 |
uint64 (uint8 (xHigh >>56 )+uint8 (yHigh >>56 ))<<56 | uint64 (uint8 (xHigh >>48 )+uint8 (yHigh >>48 ))<<48 ,
)
case shapeI16x8 :
ce .pushValue (
uint64 (uint16 (xLow >>16 +yLow >>16 ))<<16 | uint64 (uint16 (xLow )+uint16 (yLow )) |
uint64 (uint16 (xLow >>48 +yLow >>48 ))<<48 | uint64 (uint16 (xLow >>32 +yLow >>32 ))<<32 ,
)
ce .pushValue (
uint64 (uint16 (xHigh >>16 )+uint16 (yHigh >>16 ))<<16 | uint64 (uint16 (xHigh )+uint16 (yHigh )) |
uint64 (uint16 (xHigh >>48 )+uint16 (yHigh >>48 ))<<48 | uint64 (uint16 (xHigh >>32 )+uint16 (yHigh >>32 ))<<32 ,
)
case shapeI32x4 :
ce .pushValue (uint64 (uint32 (xLow >>32 )+uint32 (yLow >>32 ))<<32 | uint64 (uint32 (xLow )+uint32 (yLow )))
ce .pushValue (uint64 (uint32 (xHigh >>32 )+uint32 (yHigh >>32 ))<<32 | uint64 (uint32 (xHigh )+uint32 (yHigh )))
case shapeI64x2 :
ce .pushValue (xLow + yLow )
ce .pushValue (xHigh + yHigh )
case shapeF32x4 :
ce .pushValue (
addFloat32bits (uint32 (xLow ), uint32 (yLow )) | addFloat32bits (uint32 (xLow >>32 ), uint32 (yLow >>32 ))<<32 ,
)
ce .pushValue (
addFloat32bits (uint32 (xHigh ), uint32 (yHigh )) | addFloat32bits (uint32 (xHigh >>32 ), uint32 (yHigh >>32 ))<<32 ,
)
case shapeF64x2 :
ce .pushValue (math .Float64bits (math .Float64frombits (xLow ) + math .Float64frombits (yLow )))
ce .pushValue (math .Float64bits (math .Float64frombits (xHigh ) + math .Float64frombits (yHigh )))
}
frame .pc ++
case operationKindV128Sub :
yHigh , yLow := ce .popValue (), ce .popValue ()
xHigh , xLow := ce .popValue (), ce .popValue ()
switch op .B1 {
case shapeI8x16 :
ce .pushValue (
uint64 (uint8 (xLow >>8 )-uint8 (yLow >>8 ))<<8 | uint64 (uint8 (xLow )-uint8 (yLow )) |
uint64 (uint8 (xLow >>24 )-uint8 (yLow >>24 ))<<24 | uint64 (uint8 (xLow >>16 )-uint8 (yLow >>16 ))<<16 |
uint64 (uint8 (xLow >>40 )-uint8 (yLow >>40 ))<<40 | uint64 (uint8 (xLow >>32 )-uint8 (yLow >>32 ))<<32 |
uint64 (uint8 (xLow >>56 )-uint8 (yLow >>56 ))<<56 | uint64 (uint8 (xLow >>48 )-uint8 (yLow >>48 ))<<48 ,
)
ce .pushValue (
uint64 (uint8 (xHigh >>8 )-uint8 (yHigh >>8 ))<<8 | uint64 (uint8 (xHigh )-uint8 (yHigh )) |
uint64 (uint8 (xHigh >>24 )-uint8 (yHigh >>24 ))<<24 | uint64 (uint8 (xHigh >>16 )-uint8 (yHigh >>16 ))<<16 |
uint64 (uint8 (xHigh >>40 )-uint8 (yHigh >>40 ))<<40 | uint64 (uint8 (xHigh >>32 )-uint8 (yHigh >>32 ))<<32 |
uint64 (uint8 (xHigh >>56 )-uint8 (yHigh >>56 ))<<56 | uint64 (uint8 (xHigh >>48 )-uint8 (yHigh >>48 ))<<48 ,
)
case shapeI16x8 :
ce .pushValue (
uint64 (uint16 (xLow >>16 )-uint16 (yLow >>16 ))<<16 | uint64 (uint16 (xLow )-uint16 (yLow )) |
uint64 (uint16 (xLow >>48 )-uint16 (yLow >>48 ))<<48 | uint64 (uint16 (xLow >>32 )-uint16 (yLow >>32 ))<<32 ,
)
ce .pushValue (
uint64 (uint16 (xHigh >>16 )-uint16 (yHigh >>16 ))<<16 | uint64 (uint16 (xHigh )-uint16 (yHigh )) |
uint64 (uint16 (xHigh >>48 )-uint16 (yHigh >>48 ))<<48 | uint64 (uint16 (xHigh >>32 )-uint16 (yHigh >>32 ))<<32 ,
)
case shapeI32x4 :
ce .pushValue (uint64 (uint32 (xLow >>32 -yLow >>32 ))<<32 | uint64 (uint32 (xLow )-uint32 (yLow )))
ce .pushValue (uint64 (uint32 (xHigh >>32 -yHigh >>32 ))<<32 | uint64 (uint32 (xHigh )-uint32 (yHigh )))
case shapeI64x2 :
ce .pushValue (xLow - yLow )
ce .pushValue (xHigh - yHigh )
case shapeF32x4 :
ce .pushValue (
subFloat32bits (uint32 (xLow ), uint32 (yLow )) | subFloat32bits (uint32 (xLow >>32 ), uint32 (yLow >>32 ))<<32 ,
)
ce .pushValue (
subFloat32bits (uint32 (xHigh ), uint32 (yHigh )) | subFloat32bits (uint32 (xHigh >>32 ), uint32 (yHigh >>32 ))<<32 ,
)
case shapeF64x2 :
ce .pushValue (math .Float64bits (math .Float64frombits (xLow ) - math .Float64frombits (yLow )))
ce .pushValue (math .Float64bits (math .Float64frombits (xHigh ) - math .Float64frombits (yHigh )))
}
frame .pc ++
case operationKindV128Load :
offset := ce .popMemoryOffset (op )
switch op .B1 {
case v128LoadType128 :
lo , ok := memoryInst .ReadUint64Le (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (lo )
hi , ok := memoryInst .ReadUint64Le (offset + 8 )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (hi )
case v128LoadType8x8s :
data , ok := memoryInst .Read (offset , 8 )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (
uint64 (uint16 (int8 (data [3 ])))<<48 | uint64 (uint16 (int8 (data [2 ])))<<32 | uint64 (uint16 (int8 (data [1 ])))<<16 | uint64 (uint16 (int8 (data [0 ]))),
)
ce .pushValue (
uint64 (uint16 (int8 (data [7 ])))<<48 | uint64 (uint16 (int8 (data [6 ])))<<32 | uint64 (uint16 (int8 (data [5 ])))<<16 | uint64 (uint16 (int8 (data [4 ]))),
)
case v128LoadType8x8u :
data , ok := memoryInst .Read (offset , 8 )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (
uint64 (data [3 ])<<48 | uint64 (data [2 ])<<32 | uint64 (data [1 ])<<16 | uint64 (data [0 ]),
)
ce .pushValue (
uint64 (data [7 ])<<48 | uint64 (data [6 ])<<32 | uint64 (data [5 ])<<16 | uint64 (data [4 ]),
)
case v128LoadType16x4s :
data , ok := memoryInst .Read (offset , 8 )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (
uint64 (int16 (binary .LittleEndian .Uint16 (data [2 :])))<<32 |
uint64 (uint32 (int16 (binary .LittleEndian .Uint16 (data )))),
)
ce .pushValue (
uint64 (uint32 (int16 (binary .LittleEndian .Uint16 (data [6 :]))))<<32 |
uint64 (uint32 (int16 (binary .LittleEndian .Uint16 (data [4 :])))),
)
case v128LoadType16x4u :
data , ok := memoryInst .Read (offset , 8 )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (
uint64 (binary .LittleEndian .Uint16 (data [2 :]))<<32 | uint64 (binary .LittleEndian .Uint16 (data )),
)
ce .pushValue (
uint64 (binary .LittleEndian .Uint16 (data [6 :]))<<32 | uint64 (binary .LittleEndian .Uint16 (data [4 :])),
)
case v128LoadType32x2s :
data , ok := memoryInst .Read (offset , 8 )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (uint64 (int32 (binary .LittleEndian .Uint32 (data ))))
ce .pushValue (uint64 (int32 (binary .LittleEndian .Uint32 (data [4 :]))))
case v128LoadType32x2u :
data , ok := memoryInst .Read (offset , 8 )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (uint64 (binary .LittleEndian .Uint32 (data )))
ce .pushValue (uint64 (binary .LittleEndian .Uint32 (data [4 :])))
case v128LoadType8Splat :
v , ok := memoryInst .ReadByte (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
v8 := uint64 (v )<<56 | uint64 (v )<<48 | uint64 (v )<<40 | uint64 (v )<<32 |
uint64 (v )<<24 | uint64 (v )<<16 | uint64 (v )<<8 | uint64 (v )
ce .pushValue (v8 )
ce .pushValue (v8 )
case v128LoadType16Splat :
v , ok := memoryInst .ReadUint16Le (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
v4 := uint64 (v )<<48 | uint64 (v )<<32 | uint64 (v )<<16 | uint64 (v )
ce .pushValue (v4 )
ce .pushValue (v4 )
case v128LoadType32Splat :
v , ok := memoryInst .ReadUint32Le (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
vv := uint64 (v )<<32 | uint64 (v )
ce .pushValue (vv )
ce .pushValue (vv )
case v128LoadType64Splat :
lo , ok := memoryInst .ReadUint64Le (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (lo )
ce .pushValue (lo )
case v128LoadType32zero :
lo , ok := memoryInst .ReadUint32Le (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (uint64 (lo ))
ce .pushValue (0 )
case v128LoadType64zero :
lo , ok := memoryInst .ReadUint64Le (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (lo )
ce .pushValue (0 )
}
frame .pc ++
case operationKindV128LoadLane :
hi , lo := ce .popValue (), ce .popValue ()
offset := ce .popMemoryOffset (op )
switch op .B1 {
case 8 :
b , ok := memoryInst .ReadByte (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if op .B2 < 8 {
s := op .B2 << 3
lo = (lo & ^(0xff << s )) | uint64 (b )<<s
} else {
s := (op .B2 - 8 ) << 3
hi = (hi & ^(0xff << s )) | uint64 (b )<<s
}
case 16 :
b , ok := memoryInst .ReadUint16Le (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if op .B2 < 4 {
s := op .B2 << 4
lo = (lo & ^(0xff_ff << s )) | uint64 (b )<<s
} else {
s := (op .B2 - 4 ) << 4
hi = (hi & ^(0xff_ff << s )) | uint64 (b )<<s
}
case 32 :
b , ok := memoryInst .ReadUint32Le (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if op .B2 < 2 {
s := op .B2 << 5
lo = (lo & ^(0xff_ff_ff_ff << s )) | uint64 (b )<<s
} else {
s := (op .B2 - 2 ) << 5
hi = (hi & ^(0xff_ff_ff_ff << s )) | uint64 (b )<<s
}
case 64 :
b , ok := memoryInst .ReadUint64Le (offset )
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if op .B2 == 0 {
lo = b
} else {
hi = b
}
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Store :
hi , lo := ce .popValue (), ce .popValue ()
offset := ce .popMemoryOffset (op )
if uint64 (offset )+8 > math .MaxUint32 {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if ok := memoryInst .WriteUint64Le (offset +8 , hi ); !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if ok := memoryInst .WriteUint64Le (offset , lo ); !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
frame .pc ++
case operationKindV128StoreLane :
hi , lo := ce .popValue (), ce .popValue ()
offset := ce .popMemoryOffset (op )
var ok bool
switch op .B1 {
case 8 :
if op .B2 < 8 {
ok = memoryInst .WriteByte (offset , byte (lo >>(op .B2 *8 )))
} else {
ok = memoryInst .WriteByte (offset , byte (hi >>((op .B2 -8 )*8 )))
}
case 16 :
if op .B2 < 4 {
ok = memoryInst .WriteUint16Le (offset , uint16 (lo >>(op .B2 *16 )))
} else {
ok = memoryInst .WriteUint16Le (offset , uint16 (hi >>((op .B2 -4 )*16 )))
}
case 32 :
if op .B2 < 2 {
ok = memoryInst .WriteUint32Le (offset , uint32 (lo >>(op .B2 *32 )))
} else {
ok = memoryInst .WriteUint32Le (offset , uint32 (hi >>((op .B2 -2 )*32 )))
}
case 64 :
if op .B2 == 0 {
ok = memoryInst .WriteUint64Le (offset , lo )
} else {
ok = memoryInst .WriteUint64Le (offset , hi )
}
}
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
frame .pc ++
case operationKindV128ReplaceLane :
v := ce .popValue ()
hi , lo := ce .popValue (), ce .popValue ()
switch op .B1 {
case shapeI8x16 :
if op .B2 < 8 {
s := op .B2 << 3
lo = (lo & ^(0xff << s )) | uint64 (byte (v ))<<s
} else {
s := (op .B2 - 8 ) << 3
hi = (hi & ^(0xff << s )) | uint64 (byte (v ))<<s
}
case shapeI16x8 :
if op .B2 < 4 {
s := op .B2 << 4
lo = (lo & ^(0xff_ff << s )) | uint64 (uint16 (v ))<<s
} else {
s := (op .B2 - 4 ) << 4
hi = (hi & ^(0xff_ff << s )) | uint64 (uint16 (v ))<<s
}
case shapeI32x4 , shapeF32x4 :
if op .B2 < 2 {
s := op .B2 << 5
lo = (lo & ^(0xff_ff_ff_ff << s )) | uint64 (uint32 (v ))<<s
} else {
s := (op .B2 - 2 ) << 5
hi = (hi & ^(0xff_ff_ff_ff << s )) | uint64 (uint32 (v ))<<s
}
case shapeI64x2 , shapeF64x2 :
if op .B2 == 0 {
lo = v
} else {
hi = v
}
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128ExtractLane :
hi , lo := ce .popValue (), ce .popValue ()
var v uint64
switch op .B1 {
case shapeI8x16 :
var u8 byte
if op .B2 < 8 {
u8 = byte (lo >> (op .B2 * 8 ))
} else {
u8 = byte (hi >> ((op .B2 - 8 ) * 8 ))
}
if op .B3 {
v = uint64 (uint32 (int8 (u8 )))
} else {
v = uint64 (u8 )
}
case shapeI16x8 :
var u16 uint16
if op .B2 < 4 {
u16 = uint16 (lo >> (op .B2 * 16 ))
} else {
u16 = uint16 (hi >> ((op .B2 - 4 ) * 16 ))
}
if op .B3 {
v = uint64 (uint32 (int16 (u16 )))
} else {
v = uint64 (u16 )
}
case shapeI32x4 , shapeF32x4 :
if op .B2 < 2 {
v = uint64 (uint32 (lo >> (op .B2 * 32 )))
} else {
v = uint64 (uint32 (hi >> ((op .B2 - 2 ) * 32 )))
}
case shapeI64x2 , shapeF64x2 :
if op .B2 == 0 {
v = lo
} else {
v = hi
}
}
ce .pushValue (v )
frame .pc ++
case operationKindV128Splat :
v := ce .popValue ()
var hi , lo uint64
switch op .B1 {
case shapeI8x16 :
v8 := uint64 (byte (v ))<<56 | uint64 (byte (v ))<<48 | uint64 (byte (v ))<<40 | uint64 (byte (v ))<<32 |
uint64 (byte (v ))<<24 | uint64 (byte (v ))<<16 | uint64 (byte (v ))<<8 | uint64 (byte (v ))
hi , lo = v8 , v8
case shapeI16x8 :
v4 := uint64 (uint16 (v ))<<48 | uint64 (uint16 (v ))<<32 | uint64 (uint16 (v ))<<16 | uint64 (uint16 (v ))
hi , lo = v4 , v4
case shapeI32x4 , shapeF32x4 :
v2 := uint64 (uint32 (v ))<<32 | uint64 (uint32 (v ))
lo , hi = v2 , v2
case shapeI64x2 , shapeF64x2 :
lo , hi = v , v
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Swizzle :
idxHi , idxLo := ce .popValue (), ce .popValue ()
baseHi , baseLo := ce .popValue (), ce .popValue ()
var newVal [16 ]byte
for i := 0 ; i < 16 ; i ++ {
var id byte
if i < 8 {
id = byte (idxLo >> (i * 8 ))
} else {
id = byte (idxHi >> ((i - 8 ) * 8 ))
}
if id < 8 {
newVal [i ] = byte (baseLo >> (id * 8 ))
} else if id < 16 {
newVal [i ] = byte (baseHi >> ((id - 8 ) * 8 ))
}
}
ce .pushValue (binary .LittleEndian .Uint64 (newVal [:8 ]))
ce .pushValue (binary .LittleEndian .Uint64 (newVal [8 :]))
frame .pc ++
case operationKindV128Shuffle :
xHi , xLo , yHi , yLo := ce .popValue (), ce .popValue (), ce .popValue (), ce .popValue ()
var newVal [16 ]byte
for i , l := range op .Us {
if l < 8 {
newVal [i ] = byte (yLo >> (l * 8 ))
} else if l < 16 {
newVal [i ] = byte (yHi >> ((l - 8 ) * 8 ))
} else if l < 24 {
newVal [i ] = byte (xLo >> ((l - 16 ) * 8 ))
} else if l < 32 {
newVal [i ] = byte (xHi >> ((l - 24 ) * 8 ))
}
}
ce .pushValue (binary .LittleEndian .Uint64 (newVal [:8 ]))
ce .pushValue (binary .LittleEndian .Uint64 (newVal [8 :]))
frame .pc ++
case operationKindV128AnyTrue :
hi , lo := ce .popValue (), ce .popValue ()
if hi != 0 || lo != 0 {
ce .pushValue (1 )
} else {
ce .pushValue (0 )
}
frame .pc ++
case operationKindV128AllTrue :
hi , lo := ce .popValue (), ce .popValue ()
var ret bool
switch op .B1 {
case shapeI8x16 :
ret = (uint8 (lo ) != 0 ) && (uint8 (lo >>8 ) != 0 ) && (uint8 (lo >>16 ) != 0 ) && (uint8 (lo >>24 ) != 0 ) &&
(uint8 (lo >>32 ) != 0 ) && (uint8 (lo >>40 ) != 0 ) && (uint8 (lo >>48 ) != 0 ) && (uint8 (lo >>56 ) != 0 ) &&
(uint8 (hi ) != 0 ) && (uint8 (hi >>8 ) != 0 ) && (uint8 (hi >>16 ) != 0 ) && (uint8 (hi >>24 ) != 0 ) &&
(uint8 (hi >>32 ) != 0 ) && (uint8 (hi >>40 ) != 0 ) && (uint8 (hi >>48 ) != 0 ) && (uint8 (hi >>56 ) != 0 )
case shapeI16x8 :
ret = (uint16 (lo ) != 0 ) && (uint16 (lo >>16 ) != 0 ) && (uint16 (lo >>32 ) != 0 ) && (uint16 (lo >>48 ) != 0 ) &&
(uint16 (hi ) != 0 ) && (uint16 (hi >>16 ) != 0 ) && (uint16 (hi >>32 ) != 0 ) && (uint16 (hi >>48 ) != 0 )
case shapeI32x4 :
ret = (uint32 (lo ) != 0 ) && (uint32 (lo >>32 ) != 0 ) &&
(uint32 (hi ) != 0 ) && (uint32 (hi >>32 ) != 0 )
case shapeI64x2 :
ret = (lo != 0 ) &&
(hi != 0 )
}
if ret {
ce .pushValue (1 )
} else {
ce .pushValue (0 )
}
frame .pc ++
case operationKindV128BitMask :
hi , lo := ce .popValue (), ce .popValue ()
var res uint64
switch op .B1 {
case shapeI8x16 :
for i := 0 ; i < 8 ; i ++ {
if int8 (lo >>(i *8 )) < 0 {
res |= 1 << i
}
}
for i := 0 ; i < 8 ; i ++ {
if int8 (hi >>(i *8 )) < 0 {
res |= 1 << (i + 8 )
}
}
case shapeI16x8 :
for i := 0 ; i < 4 ; i ++ {
if int16 (lo >>(i *16 )) < 0 {
res |= 1 << i
}
}
for i := 0 ; i < 4 ; i ++ {
if int16 (hi >>(i *16 )) < 0 {
res |= 1 << (i + 4 )
}
}
case shapeI32x4 :
for i := 0 ; i < 2 ; i ++ {
if int32 (lo >>(i *32 )) < 0 {
res |= 1 << i
}
}
for i := 0 ; i < 2 ; i ++ {
if int32 (hi >>(i *32 )) < 0 {
res |= 1 << (i + 2 )
}
}
case shapeI64x2 :
if int64 (lo ) < 0 {
res |= 0b01
}
if int (hi ) < 0 {
res |= 0b10
}
}
ce .pushValue (res )
frame .pc ++
case operationKindV128And :
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
x1Hi , x1Lo := ce .popValue (), ce .popValue ()
ce .pushValue (x1Lo & x2Lo )
ce .pushValue (x1Hi & x2Hi )
frame .pc ++
case operationKindV128Not :
hi , lo := ce .popValue (), ce .popValue ()
ce .pushValue (^lo )
ce .pushValue (^hi )
frame .pc ++
case operationKindV128Or :
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
x1Hi , x1Lo := ce .popValue (), ce .popValue ()
ce .pushValue (x1Lo | x2Lo )
ce .pushValue (x1Hi | x2Hi )
frame .pc ++
case operationKindV128Xor :
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
x1Hi , x1Lo := ce .popValue (), ce .popValue ()
ce .pushValue (x1Lo ^ x2Lo )
ce .pushValue (x1Hi ^ x2Hi )
frame .pc ++
case operationKindV128Bitselect :
cHi , cLo := ce .popValue (), ce .popValue ()
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
x1Hi , x1Lo := ce .popValue (), ce .popValue ()
ce .pushValue ((x1Lo & cLo ) | (x2Lo & (^cLo )))
ce .pushValue ((x1Hi & cHi ) | (x2Hi & (^cHi )))
frame .pc ++
case operationKindV128AndNot :
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
x1Hi , x1Lo := ce .popValue (), ce .popValue ()
ce .pushValue (x1Lo & (^x2Lo ))
ce .pushValue (x1Hi & (^x2Hi ))
frame .pc ++
case operationKindV128Shl :
s := ce .popValue ()
hi , lo := ce .popValue (), ce .popValue ()
switch op .B1 {
case shapeI8x16 :
s = s % 8
lo = uint64 (uint8 (lo <<s )) |
uint64 (uint8 ((lo >>8 )<<s ))<<8 |
uint64 (uint8 ((lo >>16 )<<s ))<<16 |
uint64 (uint8 ((lo >>24 )<<s ))<<24 |
uint64 (uint8 ((lo >>32 )<<s ))<<32 |
uint64 (uint8 ((lo >>40 )<<s ))<<40 |
uint64 (uint8 ((lo >>48 )<<s ))<<48 |
uint64 (uint8 ((lo >>56 )<<s ))<<56
hi = uint64 (uint8 (hi <<s )) |
uint64 (uint8 ((hi >>8 )<<s ))<<8 |
uint64 (uint8 ((hi >>16 )<<s ))<<16 |
uint64 (uint8 ((hi >>24 )<<s ))<<24 |
uint64 (uint8 ((hi >>32 )<<s ))<<32 |
uint64 (uint8 ((hi >>40 )<<s ))<<40 |
uint64 (uint8 ((hi >>48 )<<s ))<<48 |
uint64 (uint8 ((hi >>56 )<<s ))<<56
case shapeI16x8 :
s = s % 16
lo = uint64 (uint16 (lo <<s )) |
uint64 (uint16 ((lo >>16 )<<s ))<<16 |
uint64 (uint16 ((lo >>32 )<<s ))<<32 |
uint64 (uint16 ((lo >>48 )<<s ))<<48
hi = uint64 (uint16 (hi <<s )) |
uint64 (uint16 ((hi >>16 )<<s ))<<16 |
uint64 (uint16 ((hi >>32 )<<s ))<<32 |
uint64 (uint16 ((hi >>48 )<<s ))<<48
case shapeI32x4 :
s = s % 32
lo = uint64 (uint32 (lo <<s )) | uint64 (uint32 ((lo >>32 )<<s ))<<32
hi = uint64 (uint32 (hi <<s )) | uint64 (uint32 ((hi >>32 )<<s ))<<32
case shapeI64x2 :
s = s % 64
lo = lo << s
hi = hi << s
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Shr :
s := ce .popValue ()
hi , lo := ce .popValue (), ce .popValue ()
switch op .B1 {
case shapeI8x16 :
s = s % 8
if op .B3 {
lo = uint64 (uint8 (int8 (lo )>>s )) |
uint64 (uint8 (int8 (lo >>8 )>>s ))<<8 |
uint64 (uint8 (int8 (lo >>16 )>>s ))<<16 |
uint64 (uint8 (int8 (lo >>24 )>>s ))<<24 |
uint64 (uint8 (int8 (lo >>32 )>>s ))<<32 |
uint64 (uint8 (int8 (lo >>40 )>>s ))<<40 |
uint64 (uint8 (int8 (lo >>48 )>>s ))<<48 |
uint64 (uint8 (int8 (lo >>56 )>>s ))<<56
hi = uint64 (uint8 (int8 (hi )>>s )) |
uint64 (uint8 (int8 (hi >>8 )>>s ))<<8 |
uint64 (uint8 (int8 (hi >>16 )>>s ))<<16 |
uint64 (uint8 (int8 (hi >>24 )>>s ))<<24 |
uint64 (uint8 (int8 (hi >>32 )>>s ))<<32 |
uint64 (uint8 (int8 (hi >>40 )>>s ))<<40 |
uint64 (uint8 (int8 (hi >>48 )>>s ))<<48 |
uint64 (uint8 (int8 (hi >>56 )>>s ))<<56
} else {
lo = uint64 (uint8 (lo )>>s ) |
uint64 (uint8 (lo >>8 )>>s )<<8 |
uint64 (uint8 (lo >>16 )>>s )<<16 |
uint64 (uint8 (lo >>24 )>>s )<<24 |
uint64 (uint8 (lo >>32 )>>s )<<32 |
uint64 (uint8 (lo >>40 )>>s )<<40 |
uint64 (uint8 (lo >>48 )>>s )<<48 |
uint64 (uint8 (lo >>56 )>>s )<<56
hi = uint64 (uint8 (hi )>>s ) |
uint64 (uint8 (hi >>8 )>>s )<<8 |
uint64 (uint8 (hi >>16 )>>s )<<16 |
uint64 (uint8 (hi >>24 )>>s )<<24 |
uint64 (uint8 (hi >>32 )>>s )<<32 |
uint64 (uint8 (hi >>40 )>>s )<<40 |
uint64 (uint8 (hi >>48 )>>s )<<48 |
uint64 (uint8 (hi >>56 )>>s )<<56
}
case shapeI16x8 :
s = s % 16
if op .B3 {
lo = uint64 (uint16 (int16 (lo )>>s )) |
uint64 (uint16 (int16 (lo >>16 )>>s ))<<16 |
uint64 (uint16 (int16 (lo >>32 )>>s ))<<32 |
uint64 (uint16 (int16 (lo >>48 )>>s ))<<48
hi = uint64 (uint16 (int16 (hi )>>s )) |
uint64 (uint16 (int16 (hi >>16 )>>s ))<<16 |
uint64 (uint16 (int16 (hi >>32 )>>s ))<<32 |
uint64 (uint16 (int16 (hi >>48 )>>s ))<<48
} else {
lo = uint64 (uint16 (lo )>>s ) |
uint64 (uint16 (lo >>16 )>>s )<<16 |
uint64 (uint16 (lo >>32 )>>s )<<32 |
uint64 (uint16 (lo >>48 )>>s )<<48
hi = uint64 (uint16 (hi )>>s ) |
uint64 (uint16 (hi >>16 )>>s )<<16 |
uint64 (uint16 (hi >>32 )>>s )<<32 |
uint64 (uint16 (hi >>48 )>>s )<<48
}
case shapeI32x4 :
s = s % 32
if op .B3 {
lo = uint64 (uint32 (int32 (lo )>>s )) | uint64 (uint32 (int32 (lo >>32 )>>s ))<<32
hi = uint64 (uint32 (int32 (hi )>>s )) | uint64 (uint32 (int32 (hi >>32 )>>s ))<<32
} else {
lo = uint64 (uint32 (lo )>>s ) | uint64 (uint32 (lo >>32 )>>s )<<32
hi = uint64 (uint32 (hi )>>s ) | uint64 (uint32 (hi >>32 )>>s )<<32
}
case shapeI64x2 :
s = s % 64
if op .B3 {
lo = uint64 (int64 (lo ) >> s )
hi = uint64 (int64 (hi ) >> s )
} else {
lo = lo >> s
hi = hi >> s
}
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Cmp :
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
x1Hi , x1Lo := ce .popValue (), ce .popValue ()
var result []bool
switch op .B1 {
case v128CmpTypeI8x16Eq :
result = []bool {
byte (x1Lo >>0 ) == byte (x2Lo >>0 ), byte (x1Lo >>8 ) == byte (x2Lo >>8 ),
byte (x1Lo >>16 ) == byte (x2Lo >>16 ), byte (x1Lo >>24 ) == byte (x2Lo >>24 ),
byte (x1Lo >>32 ) == byte (x2Lo >>32 ), byte (x1Lo >>40 ) == byte (x2Lo >>40 ),
byte (x1Lo >>48 ) == byte (x2Lo >>48 ), byte (x1Lo >>56 ) == byte (x2Lo >>56 ),
byte (x1Hi >>0 ) == byte (x2Hi >>0 ), byte (x1Hi >>8 ) == byte (x2Hi >>8 ),
byte (x1Hi >>16 ) == byte (x2Hi >>16 ), byte (x1Hi >>24 ) == byte (x2Hi >>24 ),
byte (x1Hi >>32 ) == byte (x2Hi >>32 ), byte (x1Hi >>40 ) == byte (x2Hi >>40 ),
byte (x1Hi >>48 ) == byte (x2Hi >>48 ), byte (x1Hi >>56 ) == byte (x2Hi >>56 ),
}
case v128CmpTypeI8x16Ne :
result = []bool {
byte (x1Lo >>0 ) != byte (x2Lo >>0 ), byte (x1Lo >>8 ) != byte (x2Lo >>8 ),
byte (x1Lo >>16 ) != byte (x2Lo >>16 ), byte (x1Lo >>24 ) != byte (x2Lo >>24 ),
byte (x1Lo >>32 ) != byte (x2Lo >>32 ), byte (x1Lo >>40 ) != byte (x2Lo >>40 ),
byte (x1Lo >>48 ) != byte (x2Lo >>48 ), byte (x1Lo >>56 ) != byte (x2Lo >>56 ),
byte (x1Hi >>0 ) != byte (x2Hi >>0 ), byte (x1Hi >>8 ) != byte (x2Hi >>8 ),
byte (x1Hi >>16 ) != byte (x2Hi >>16 ), byte (x1Hi >>24 ) != byte (x2Hi >>24 ),
byte (x1Hi >>32 ) != byte (x2Hi >>32 ), byte (x1Hi >>40 ) != byte (x2Hi >>40 ),
byte (x1Hi >>48 ) != byte (x2Hi >>48 ), byte (x1Hi >>56 ) != byte (x2Hi >>56 ),
}
case v128CmpTypeI8x16LtS :
result = []bool {
int8 (x1Lo >>0 ) < int8 (x2Lo >>0 ), int8 (x1Lo >>8 ) < int8 (x2Lo >>8 ),
int8 (x1Lo >>16 ) < int8 (x2Lo >>16 ), int8 (x1Lo >>24 ) < int8 (x2Lo >>24 ),
int8 (x1Lo >>32 ) < int8 (x2Lo >>32 ), int8 (x1Lo >>40 ) < int8 (x2Lo >>40 ),
int8 (x1Lo >>48 ) < int8 (x2Lo >>48 ), int8 (x1Lo >>56 ) < int8 (x2Lo >>56 ),
int8 (x1Hi >>0 ) < int8 (x2Hi >>0 ), int8 (x1Hi >>8 ) < int8 (x2Hi >>8 ),
int8 (x1Hi >>16 ) < int8 (x2Hi >>16 ), int8 (x1Hi >>24 ) < int8 (x2Hi >>24 ),
int8 (x1Hi >>32 ) < int8 (x2Hi >>32 ), int8 (x1Hi >>40 ) < int8 (x2Hi >>40 ),
int8 (x1Hi >>48 ) < int8 (x2Hi >>48 ), int8 (x1Hi >>56 ) < int8 (x2Hi >>56 ),
}
case v128CmpTypeI8x16LtU :
result = []bool {
byte (x1Lo >>0 ) < byte (x2Lo >>0 ), byte (x1Lo >>8 ) < byte (x2Lo >>8 ),
byte (x1Lo >>16 ) < byte (x2Lo >>16 ), byte (x1Lo >>24 ) < byte (x2Lo >>24 ),
byte (x1Lo >>32 ) < byte (x2Lo >>32 ), byte (x1Lo >>40 ) < byte (x2Lo >>40 ),
byte (x1Lo >>48 ) < byte (x2Lo >>48 ), byte (x1Lo >>56 ) < byte (x2Lo >>56 ),
byte (x1Hi >>0 ) < byte (x2Hi >>0 ), byte (x1Hi >>8 ) < byte (x2Hi >>8 ),
byte (x1Hi >>16 ) < byte (x2Hi >>16 ), byte (x1Hi >>24 ) < byte (x2Hi >>24 ),
byte (x1Hi >>32 ) < byte (x2Hi >>32 ), byte (x1Hi >>40 ) < byte (x2Hi >>40 ),
byte (x1Hi >>48 ) < byte (x2Hi >>48 ), byte (x1Hi >>56 ) < byte (x2Hi >>56 ),
}
case v128CmpTypeI8x16GtS :
result = []bool {
int8 (x1Lo >>0 ) > int8 (x2Lo >>0 ), int8 (x1Lo >>8 ) > int8 (x2Lo >>8 ),
int8 (x1Lo >>16 ) > int8 (x2Lo >>16 ), int8 (x1Lo >>24 ) > int8 (x2Lo >>24 ),
int8 (x1Lo >>32 ) > int8 (x2Lo >>32 ), int8 (x1Lo >>40 ) > int8 (x2Lo >>40 ),
int8 (x1Lo >>48 ) > int8 (x2Lo >>48 ), int8 (x1Lo >>56 ) > int8 (x2Lo >>56 ),
int8 (x1Hi >>0 ) > int8 (x2Hi >>0 ), int8 (x1Hi >>8 ) > int8 (x2Hi >>8 ),
int8 (x1Hi >>16 ) > int8 (x2Hi >>16 ), int8 (x1Hi >>24 ) > int8 (x2Hi >>24 ),
int8 (x1Hi >>32 ) > int8 (x2Hi >>32 ), int8 (x1Hi >>40 ) > int8 (x2Hi >>40 ),
int8 (x1Hi >>48 ) > int8 (x2Hi >>48 ), int8 (x1Hi >>56 ) > int8 (x2Hi >>56 ),
}
case v128CmpTypeI8x16GtU :
result = []bool {
byte (x1Lo >>0 ) > byte (x2Lo >>0 ), byte (x1Lo >>8 ) > byte (x2Lo >>8 ),
byte (x1Lo >>16 ) > byte (x2Lo >>16 ), byte (x1Lo >>24 ) > byte (x2Lo >>24 ),
byte (x1Lo >>32 ) > byte (x2Lo >>32 ), byte (x1Lo >>40 ) > byte (x2Lo >>40 ),
byte (x1Lo >>48 ) > byte (x2Lo >>48 ), byte (x1Lo >>56 ) > byte (x2Lo >>56 ),
byte (x1Hi >>0 ) > byte (x2Hi >>0 ), byte (x1Hi >>8 ) > byte (x2Hi >>8 ),
byte (x1Hi >>16 ) > byte (x2Hi >>16 ), byte (x1Hi >>24 ) > byte (x2Hi >>24 ),
byte (x1Hi >>32 ) > byte (x2Hi >>32 ), byte (x1Hi >>40 ) > byte (x2Hi >>40 ),
byte (x1Hi >>48 ) > byte (x2Hi >>48 ), byte (x1Hi >>56 ) > byte (x2Hi >>56 ),
}
case v128CmpTypeI8x16LeS :
result = []bool {
int8 (x1Lo >>0 ) <= int8 (x2Lo >>0 ), int8 (x1Lo >>8 ) <= int8 (x2Lo >>8 ),
int8 (x1Lo >>16 ) <= int8 (x2Lo >>16 ), int8 (x1Lo >>24 ) <= int8 (x2Lo >>24 ),
int8 (x1Lo >>32 ) <= int8 (x2Lo >>32 ), int8 (x1Lo >>40 ) <= int8 (x2Lo >>40 ),
int8 (x1Lo >>48 ) <= int8 (x2Lo >>48 ), int8 (x1Lo >>56 ) <= int8 (x2Lo >>56 ),
int8 (x1Hi >>0 ) <= int8 (x2Hi >>0 ), int8 (x1Hi >>8 ) <= int8 (x2Hi >>8 ),
int8 (x1Hi >>16 ) <= int8 (x2Hi >>16 ), int8 (x1Hi >>24 ) <= int8 (x2Hi >>24 ),
int8 (x1Hi >>32 ) <= int8 (x2Hi >>32 ), int8 (x1Hi >>40 ) <= int8 (x2Hi >>40 ),
int8 (x1Hi >>48 ) <= int8 (x2Hi >>48 ), int8 (x1Hi >>56 ) <= int8 (x2Hi >>56 ),
}
case v128CmpTypeI8x16LeU :
result = []bool {
byte (x1Lo >>0 ) <= byte (x2Lo >>0 ), byte (x1Lo >>8 ) <= byte (x2Lo >>8 ),
byte (x1Lo >>16 ) <= byte (x2Lo >>16 ), byte (x1Lo >>24 ) <= byte (x2Lo >>24 ),
byte (x1Lo >>32 ) <= byte (x2Lo >>32 ), byte (x1Lo >>40 ) <= byte (x2Lo >>40 ),
byte (x1Lo >>48 ) <= byte (x2Lo >>48 ), byte (x1Lo >>56 ) <= byte (x2Lo >>56 ),
byte (x1Hi >>0 ) <= byte (x2Hi >>0 ), byte (x1Hi >>8 ) <= byte (x2Hi >>8 ),
byte (x1Hi >>16 ) <= byte (x2Hi >>16 ), byte (x1Hi >>24 ) <= byte (x2Hi >>24 ),
byte (x1Hi >>32 ) <= byte (x2Hi >>32 ), byte (x1Hi >>40 ) <= byte (x2Hi >>40 ),
byte (x1Hi >>48 ) <= byte (x2Hi >>48 ), byte (x1Hi >>56 ) <= byte (x2Hi >>56 ),
}
case v128CmpTypeI8x16GeS :
result = []bool {
int8 (x1Lo >>0 ) >= int8 (x2Lo >>0 ), int8 (x1Lo >>8 ) >= int8 (x2Lo >>8 ),
int8 (x1Lo >>16 ) >= int8 (x2Lo >>16 ), int8 (x1Lo >>24 ) >= int8 (x2Lo >>24 ),
int8 (x1Lo >>32 ) >= int8 (x2Lo >>32 ), int8 (x1Lo >>40 ) >= int8 (x2Lo >>40 ),
int8 (x1Lo >>48 ) >= int8 (x2Lo >>48 ), int8 (x1Lo >>56 ) >= int8 (x2Lo >>56 ),
int8 (x1Hi >>0 ) >= int8 (x2Hi >>0 ), int8 (x1Hi >>8 ) >= int8 (x2Hi >>8 ),
int8 (x1Hi >>16 ) >= int8 (x2Hi >>16 ), int8 (x1Hi >>24 ) >= int8 (x2Hi >>24 ),
int8 (x1Hi >>32 ) >= int8 (x2Hi >>32 ), int8 (x1Hi >>40 ) >= int8 (x2Hi >>40 ),
int8 (x1Hi >>48 ) >= int8 (x2Hi >>48 ), int8 (x1Hi >>56 ) >= int8 (x2Hi >>56 ),
}
case v128CmpTypeI8x16GeU :
result = []bool {
byte (x1Lo >>0 ) >= byte (x2Lo >>0 ), byte (x1Lo >>8 ) >= byte (x2Lo >>8 ),
byte (x1Lo >>16 ) >= byte (x2Lo >>16 ), byte (x1Lo >>24 ) >= byte (x2Lo >>24 ),
byte (x1Lo >>32 ) >= byte (x2Lo >>32 ), byte (x1Lo >>40 ) >= byte (x2Lo >>40 ),
byte (x1Lo >>48 ) >= byte (x2Lo >>48 ), byte (x1Lo >>56 ) >= byte (x2Lo >>56 ),
byte (x1Hi >>0 ) >= byte (x2Hi >>0 ), byte (x1Hi >>8 ) >= byte (x2Hi >>8 ),
byte (x1Hi >>16 ) >= byte (x2Hi >>16 ), byte (x1Hi >>24 ) >= byte (x2Hi >>24 ),
byte (x1Hi >>32 ) >= byte (x2Hi >>32 ), byte (x1Hi >>40 ) >= byte (x2Hi >>40 ),
byte (x1Hi >>48 ) >= byte (x2Hi >>48 ), byte (x1Hi >>56 ) >= byte (x2Hi >>56 ),
}
case v128CmpTypeI16x8Eq :
result = []bool {
uint16 (x1Lo >>0 ) == uint16 (x2Lo >>0 ), uint16 (x1Lo >>16 ) == uint16 (x2Lo >>16 ),
uint16 (x1Lo >>32 ) == uint16 (x2Lo >>32 ), uint16 (x1Lo >>48 ) == uint16 (x2Lo >>48 ),
uint16 (x1Hi >>0 ) == uint16 (x2Hi >>0 ), uint16 (x1Hi >>16 ) == uint16 (x2Hi >>16 ),
uint16 (x1Hi >>32 ) == uint16 (x2Hi >>32 ), uint16 (x1Hi >>48 ) == uint16 (x2Hi >>48 ),
}
case v128CmpTypeI16x8Ne :
result = []bool {
uint16 (x1Lo >>0 ) != uint16 (x2Lo >>0 ), uint16 (x1Lo >>16 ) != uint16 (x2Lo >>16 ),
uint16 (x1Lo >>32 ) != uint16 (x2Lo >>32 ), uint16 (x1Lo >>48 ) != uint16 (x2Lo >>48 ),
uint16 (x1Hi >>0 ) != uint16 (x2Hi >>0 ), uint16 (x1Hi >>16 ) != uint16 (x2Hi >>16 ),
uint16 (x1Hi >>32 ) != uint16 (x2Hi >>32 ), uint16 (x1Hi >>48 ) != uint16 (x2Hi >>48 ),
}
case v128CmpTypeI16x8LtS :
result = []bool {
int16 (x1Lo >>0 ) < int16 (x2Lo >>0 ), int16 (x1Lo >>16 ) < int16 (x2Lo >>16 ),
int16 (x1Lo >>32 ) < int16 (x2Lo >>32 ), int16 (x1Lo >>48 ) < int16 (x2Lo >>48 ),
int16 (x1Hi >>0 ) < int16 (x2Hi >>0 ), int16 (x1Hi >>16 ) < int16 (x2Hi >>16 ),
int16 (x1Hi >>32 ) < int16 (x2Hi >>32 ), int16 (x1Hi >>48 ) < int16 (x2Hi >>48 ),
}
case v128CmpTypeI16x8LtU :
result = []bool {
uint16 (x1Lo >>0 ) < uint16 (x2Lo >>0 ), uint16 (x1Lo >>16 ) < uint16 (x2Lo >>16 ),
uint16 (x1Lo >>32 ) < uint16 (x2Lo >>32 ), uint16 (x1Lo >>48 ) < uint16 (x2Lo >>48 ),
uint16 (x1Hi >>0 ) < uint16 (x2Hi >>0 ), uint16 (x1Hi >>16 ) < uint16 (x2Hi >>16 ),
uint16 (x1Hi >>32 ) < uint16 (x2Hi >>32 ), uint16 (x1Hi >>48 ) < uint16 (x2Hi >>48 ),
}
case v128CmpTypeI16x8GtS :
result = []bool {
int16 (x1Lo >>0 ) > int16 (x2Lo >>0 ), int16 (x1Lo >>16 ) > int16 (x2Lo >>16 ),
int16 (x1Lo >>32 ) > int16 (x2Lo >>32 ), int16 (x1Lo >>48 ) > int16 (x2Lo >>48 ),
int16 (x1Hi >>0 ) > int16 (x2Hi >>0 ), int16 (x1Hi >>16 ) > int16 (x2Hi >>16 ),
int16 (x1Hi >>32 ) > int16 (x2Hi >>32 ), int16 (x1Hi >>48 ) > int16 (x2Hi >>48 ),
}
case v128CmpTypeI16x8GtU :
result = []bool {
uint16 (x1Lo >>0 ) > uint16 (x2Lo >>0 ), uint16 (x1Lo >>16 ) > uint16 (x2Lo >>16 ),
uint16 (x1Lo >>32 ) > uint16 (x2Lo >>32 ), uint16 (x1Lo >>48 ) > uint16 (x2Lo >>48 ),
uint16 (x1Hi >>0 ) > uint16 (x2Hi >>0 ), uint16 (x1Hi >>16 ) > uint16 (x2Hi >>16 ),
uint16 (x1Hi >>32 ) > uint16 (x2Hi >>32 ), uint16 (x1Hi >>48 ) > uint16 (x2Hi >>48 ),
}
case v128CmpTypeI16x8LeS :
result = []bool {
int16 (x1Lo >>0 ) <= int16 (x2Lo >>0 ), int16 (x1Lo >>16 ) <= int16 (x2Lo >>16 ),
int16 (x1Lo >>32 ) <= int16 (x2Lo >>32 ), int16 (x1Lo >>48 ) <= int16 (x2Lo >>48 ),
int16 (x1Hi >>0 ) <= int16 (x2Hi >>0 ), int16 (x1Hi >>16 ) <= int16 (x2Hi >>16 ),
int16 (x1Hi >>32 ) <= int16 (x2Hi >>32 ), int16 (x1Hi >>48 ) <= int16 (x2Hi >>48 ),
}
case v128CmpTypeI16x8LeU :
result = []bool {
uint16 (x1Lo >>0 ) <= uint16 (x2Lo >>0 ), uint16 (x1Lo >>16 ) <= uint16 (x2Lo >>16 ),
uint16 (x1Lo >>32 ) <= uint16 (x2Lo >>32 ), uint16 (x1Lo >>48 ) <= uint16 (x2Lo >>48 ),
uint16 (x1Hi >>0 ) <= uint16 (x2Hi >>0 ), uint16 (x1Hi >>16 ) <= uint16 (x2Hi >>16 ),
uint16 (x1Hi >>32 ) <= uint16 (x2Hi >>32 ), uint16 (x1Hi >>48 ) <= uint16 (x2Hi >>48 ),
}
case v128CmpTypeI16x8GeS :
result = []bool {
int16 (x1Lo >>0 ) >= int16 (x2Lo >>0 ), int16 (x1Lo >>16 ) >= int16 (x2Lo >>16 ),
int16 (x1Lo >>32 ) >= int16 (x2Lo >>32 ), int16 (x1Lo >>48 ) >= int16 (x2Lo >>48 ),
int16 (x1Hi >>0 ) >= int16 (x2Hi >>0 ), int16 (x1Hi >>16 ) >= int16 (x2Hi >>16 ),
int16 (x1Hi >>32 ) >= int16 (x2Hi >>32 ), int16 (x1Hi >>48 ) >= int16 (x2Hi >>48 ),
}
case v128CmpTypeI16x8GeU :
result = []bool {
uint16 (x1Lo >>0 ) >= uint16 (x2Lo >>0 ), uint16 (x1Lo >>16 ) >= uint16 (x2Lo >>16 ),
uint16 (x1Lo >>32 ) >= uint16 (x2Lo >>32 ), uint16 (x1Lo >>48 ) >= uint16 (x2Lo >>48 ),
uint16 (x1Hi >>0 ) >= uint16 (x2Hi >>0 ), uint16 (x1Hi >>16 ) >= uint16 (x2Hi >>16 ),
uint16 (x1Hi >>32 ) >= uint16 (x2Hi >>32 ), uint16 (x1Hi >>48 ) >= uint16 (x2Hi >>48 ),
}
case v128CmpTypeI32x4Eq :
result = []bool {
uint32 (x1Lo >>0 ) == uint32 (x2Lo >>0 ), uint32 (x1Lo >>32 ) == uint32 (x2Lo >>32 ),
uint32 (x1Hi >>0 ) == uint32 (x2Hi >>0 ), uint32 (x1Hi >>32 ) == uint32 (x2Hi >>32 ),
}
case v128CmpTypeI32x4Ne :
result = []bool {
uint32 (x1Lo >>0 ) != uint32 (x2Lo >>0 ), uint32 (x1Lo >>32 ) != uint32 (x2Lo >>32 ),
uint32 (x1Hi >>0 ) != uint32 (x2Hi >>0 ), uint32 (x1Hi >>32 ) != uint32 (x2Hi >>32 ),
}
case v128CmpTypeI32x4LtS :
result = []bool {
int32 (x1Lo >>0 ) < int32 (x2Lo >>0 ), int32 (x1Lo >>32 ) < int32 (x2Lo >>32 ),
int32 (x1Hi >>0 ) < int32 (x2Hi >>0 ), int32 (x1Hi >>32 ) < int32 (x2Hi >>32 ),
}
case v128CmpTypeI32x4LtU :
result = []bool {
uint32 (x1Lo >>0 ) < uint32 (x2Lo >>0 ), uint32 (x1Lo >>32 ) < uint32 (x2Lo >>32 ),
uint32 (x1Hi >>0 ) < uint32 (x2Hi >>0 ), uint32 (x1Hi >>32 ) < uint32 (x2Hi >>32 ),
}
case v128CmpTypeI32x4GtS :
result = []bool {
int32 (x1Lo >>0 ) > int32 (x2Lo >>0 ), int32 (x1Lo >>32 ) > int32 (x2Lo >>32 ),
int32 (x1Hi >>0 ) > int32 (x2Hi >>0 ), int32 (x1Hi >>32 ) > int32 (x2Hi >>32 ),
}
case v128CmpTypeI32x4GtU :
result = []bool {
uint32 (x1Lo >>0 ) > uint32 (x2Lo >>0 ), uint32 (x1Lo >>32 ) > uint32 (x2Lo >>32 ),
uint32 (x1Hi >>0 ) > uint32 (x2Hi >>0 ), uint32 (x1Hi >>32 ) > uint32 (x2Hi >>32 ),
}
case v128CmpTypeI32x4LeS :
result = []bool {
int32 (x1Lo >>0 ) <= int32 (x2Lo >>0 ), int32 (x1Lo >>32 ) <= int32 (x2Lo >>32 ),
int32 (x1Hi >>0 ) <= int32 (x2Hi >>0 ), int32 (x1Hi >>32 ) <= int32 (x2Hi >>32 ),
}
case v128CmpTypeI32x4LeU :
result = []bool {
uint32 (x1Lo >>0 ) <= uint32 (x2Lo >>0 ), uint32 (x1Lo >>32 ) <= uint32 (x2Lo >>32 ),
uint32 (x1Hi >>0 ) <= uint32 (x2Hi >>0 ), uint32 (x1Hi >>32 ) <= uint32 (x2Hi >>32 ),
}
case v128CmpTypeI32x4GeS :
result = []bool {
int32 (x1Lo >>0 ) >= int32 (x2Lo >>0 ), int32 (x1Lo >>32 ) >= int32 (x2Lo >>32 ),
int32 (x1Hi >>0 ) >= int32 (x2Hi >>0 ), int32 (x1Hi >>32 ) >= int32 (x2Hi >>32 ),
}
case v128CmpTypeI32x4GeU :
result = []bool {
uint32 (x1Lo >>0 ) >= uint32 (x2Lo >>0 ), uint32 (x1Lo >>32 ) >= uint32 (x2Lo >>32 ),
uint32 (x1Hi >>0 ) >= uint32 (x2Hi >>0 ), uint32 (x1Hi >>32 ) >= uint32 (x2Hi >>32 ),
}
case v128CmpTypeI64x2Eq :
result = []bool {x1Lo == x2Lo , x1Hi == x2Hi }
case v128CmpTypeI64x2Ne :
result = []bool {x1Lo != x2Lo , x1Hi != x2Hi }
case v128CmpTypeI64x2LtS :
result = []bool {int64 (x1Lo ) < int64 (x2Lo ), int64 (x1Hi ) < int64 (x2Hi )}
case v128CmpTypeI64x2GtS :
result = []bool {int64 (x1Lo ) > int64 (x2Lo ), int64 (x1Hi ) > int64 (x2Hi )}
case v128CmpTypeI64x2LeS :
result = []bool {int64 (x1Lo ) <= int64 (x2Lo ), int64 (x1Hi ) <= int64 (x2Hi )}
case v128CmpTypeI64x2GeS :
result = []bool {int64 (x1Lo ) >= int64 (x2Lo ), int64 (x1Hi ) >= int64 (x2Hi )}
case v128CmpTypeF32x4Eq :
result = []bool {
math .Float32frombits (uint32 (x1Lo >>0 )) == math .Float32frombits (uint32 (x2Lo >>0 )),
math .Float32frombits (uint32 (x1Lo >>32 )) == math .Float32frombits (uint32 (x2Lo >>32 )),
math .Float32frombits (uint32 (x1Hi >>0 )) == math .Float32frombits (uint32 (x2Hi >>0 )),
math .Float32frombits (uint32 (x1Hi >>32 )) == math .Float32frombits (uint32 (x2Hi >>32 )),
}
case v128CmpTypeF32x4Ne :
result = []bool {
math .Float32frombits (uint32 (x1Lo >>0 )) != math .Float32frombits (uint32 (x2Lo >>0 )),
math .Float32frombits (uint32 (x1Lo >>32 )) != math .Float32frombits (uint32 (x2Lo >>32 )),
math .Float32frombits (uint32 (x1Hi >>0 )) != math .Float32frombits (uint32 (x2Hi >>0 )),
math .Float32frombits (uint32 (x1Hi >>32 )) != math .Float32frombits (uint32 (x2Hi >>32 )),
}
case v128CmpTypeF32x4Lt :
result = []bool {
math .Float32frombits (uint32 (x1Lo >>0 )) < math .Float32frombits (uint32 (x2Lo >>0 )),
math .Float32frombits (uint32 (x1Lo >>32 )) < math .Float32frombits (uint32 (x2Lo >>32 )),
math .Float32frombits (uint32 (x1Hi >>0 )) < math .Float32frombits (uint32 (x2Hi >>0 )),
math .Float32frombits (uint32 (x1Hi >>32 )) < math .Float32frombits (uint32 (x2Hi >>32 )),
}
case v128CmpTypeF32x4Gt :
result = []bool {
math .Float32frombits (uint32 (x1Lo >>0 )) > math .Float32frombits (uint32 (x2Lo >>0 )),
math .Float32frombits (uint32 (x1Lo >>32 )) > math .Float32frombits (uint32 (x2Lo >>32 )),
math .Float32frombits (uint32 (x1Hi >>0 )) > math .Float32frombits (uint32 (x2Hi >>0 )),
math .Float32frombits (uint32 (x1Hi >>32 )) > math .Float32frombits (uint32 (x2Hi >>32 )),
}
case v128CmpTypeF32x4Le :
result = []bool {
math .Float32frombits (uint32 (x1Lo >>0 )) <= math .Float32frombits (uint32 (x2Lo >>0 )),
math .Float32frombits (uint32 (x1Lo >>32 )) <= math .Float32frombits (uint32 (x2Lo >>32 )),
math .Float32frombits (uint32 (x1Hi >>0 )) <= math .Float32frombits (uint32 (x2Hi >>0 )),
math .Float32frombits (uint32 (x1Hi >>32 )) <= math .Float32frombits (uint32 (x2Hi >>32 )),
}
case v128CmpTypeF32x4Ge :
result = []bool {
math .Float32frombits (uint32 (x1Lo >>0 )) >= math .Float32frombits (uint32 (x2Lo >>0 )),
math .Float32frombits (uint32 (x1Lo >>32 )) >= math .Float32frombits (uint32 (x2Lo >>32 )),
math .Float32frombits (uint32 (x1Hi >>0 )) >= math .Float32frombits (uint32 (x2Hi >>0 )),
math .Float32frombits (uint32 (x1Hi >>32 )) >= math .Float32frombits (uint32 (x2Hi >>32 )),
}
case v128CmpTypeF64x2Eq :
result = []bool {
math .Float64frombits (x1Lo ) == math .Float64frombits (x2Lo ),
math .Float64frombits (x1Hi ) == math .Float64frombits (x2Hi ),
}
case v128CmpTypeF64x2Ne :
result = []bool {
math .Float64frombits (x1Lo ) != math .Float64frombits (x2Lo ),
math .Float64frombits (x1Hi ) != math .Float64frombits (x2Hi ),
}
case v128CmpTypeF64x2Lt :
result = []bool {
math .Float64frombits (x1Lo ) < math .Float64frombits (x2Lo ),
math .Float64frombits (x1Hi ) < math .Float64frombits (x2Hi ),
}
case v128CmpTypeF64x2Gt :
result = []bool {
math .Float64frombits (x1Lo ) > math .Float64frombits (x2Lo ),
math .Float64frombits (x1Hi ) > math .Float64frombits (x2Hi ),
}
case v128CmpTypeF64x2Le :
result = []bool {
math .Float64frombits (x1Lo ) <= math .Float64frombits (x2Lo ),
math .Float64frombits (x1Hi ) <= math .Float64frombits (x2Hi ),
}
case v128CmpTypeF64x2Ge :
result = []bool {
math .Float64frombits (x1Lo ) >= math .Float64frombits (x2Lo ),
math .Float64frombits (x1Hi ) >= math .Float64frombits (x2Hi ),
}
}
var retLo , retHi uint64
laneNum := len (result )
switch laneNum {
case 16 :
for i , b := range result {
if b {
if i < 8 {
retLo |= 0xff << (i * 8 )
} else {
retHi |= 0xff << ((i - 8 ) * 8 )
}
}
}
case 8 :
for i , b := range result {
if b {
if i < 4 {
retLo |= 0xffff << (i * 16 )
} else {
retHi |= 0xffff << ((i - 4 ) * 16 )
}
}
}
case 4 :
for i , b := range result {
if b {
if i < 2 {
retLo |= 0xffff_ffff << (i * 32 )
} else {
retHi |= 0xffff_ffff << ((i - 2 ) * 32 )
}
}
}
case 2 :
if result [0 ] {
retLo = ^uint64 (0 )
}
if result [1 ] {
retHi = ^uint64 (0 )
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128AddSat :
x2hi , x2Lo := ce .popValue (), ce .popValue ()
x1hi , x1Lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
switch op .B1 {
case shapeI8x16 :
for i := 0 ; i < 16 ; i ++ {
var v , w byte
if i < 8 {
v , w = byte (x1Lo >>(i *8 )), byte (x2Lo >>(i *8 ))
} else {
v , w = byte (x1hi >>((i -8 )*8 )), byte (x2hi >>((i -8 )*8 ))
}
var uv uint64
if op .B3 {
if subbed := int64 (int8 (v )) + int64 (int8 (w )); subbed < math .MinInt8 {
uv = uint64 (byte (0x80 ))
} else if subbed > math .MaxInt8 {
uv = uint64 (byte (0x7f ))
} else {
uv = uint64 (byte (int8 (subbed )))
}
} else {
if subbed := int64 (v ) + int64 (w ); subbed < 0 {
uv = uint64 (byte (0 ))
} else if subbed > math .MaxUint8 {
uv = uint64 (byte (0xff ))
} else {
uv = uint64 (byte (subbed ))
}
}
if i < 8 {
retLo |= uv << (i * 8 )
} else {
retHi |= uv << ((i - 8 ) * 8 )
}
}
case shapeI16x8 :
for i := 0 ; i < 8 ; i ++ {
var v , w uint16
if i < 4 {
v , w = uint16 (x1Lo >>(i *16 )), uint16 (x2Lo >>(i *16 ))
} else {
v , w = uint16 (x1hi >>((i -4 )*16 )), uint16 (x2hi >>((i -4 )*16 ))
}
var uv uint64
if op .B3 {
if added := int64 (int16 (v )) + int64 (int16 (w )); added < math .MinInt16 {
uv = uint64 (uint16 (0x8000 ))
} else if added > math .MaxInt16 {
uv = uint64 (uint16 (0x7fff ))
} else {
uv = uint64 (uint16 (int16 (added )))
}
} else {
if added := int64 (v ) + int64 (w ); added < 0 {
uv = uint64 (uint16 (0 ))
} else if added > math .MaxUint16 {
uv = uint64 (uint16 (0xffff ))
} else {
uv = uint64 (uint16 (added ))
}
}
if i < 4 {
retLo |= uv << (i * 16 )
} else {
retHi |= uv << ((i - 4 ) * 16 )
}
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128SubSat :
x2hi , x2Lo := ce .popValue (), ce .popValue ()
x1hi , x1Lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
switch op .B1 {
case shapeI8x16 :
for i := 0 ; i < 16 ; i ++ {
var v , w byte
if i < 8 {
v , w = byte (x1Lo >>(i *8 )), byte (x2Lo >>(i *8 ))
} else {
v , w = byte (x1hi >>((i -8 )*8 )), byte (x2hi >>((i -8 )*8 ))
}
var uv uint64
if op .B3 {
if subbed := int64 (int8 (v )) - int64 (int8 (w )); subbed < math .MinInt8 {
uv = uint64 (byte (0x80 ))
} else if subbed > math .MaxInt8 {
uv = uint64 (byte (0x7f ))
} else {
uv = uint64 (byte (int8 (subbed )))
}
} else {
if subbed := int64 (v ) - int64 (w ); subbed < 0 {
uv = uint64 (byte (0 ))
} else if subbed > math .MaxUint8 {
uv = uint64 (byte (0xff ))
} else {
uv = uint64 (byte (subbed ))
}
}
if i < 8 {
retLo |= uv << (i * 8 )
} else {
retHi |= uv << ((i - 8 ) * 8 )
}
}
case shapeI16x8 :
for i := 0 ; i < 8 ; i ++ {
var v , w uint16
if i < 4 {
v , w = uint16 (x1Lo >>(i *16 )), uint16 (x2Lo >>(i *16 ))
} else {
v , w = uint16 (x1hi >>((i -4 )*16 )), uint16 (x2hi >>((i -4 )*16 ))
}
var uv uint64
if op .B3 {
if subbed := int64 (int16 (v )) - int64 (int16 (w )); subbed < math .MinInt16 {
uv = uint64 (uint16 (0x8000 ))
} else if subbed > math .MaxInt16 {
uv = uint64 (uint16 (0x7fff ))
} else {
uv = uint64 (uint16 (int16 (subbed )))
}
} else {
if subbed := int64 (v ) - int64 (w ); subbed < 0 {
uv = uint64 (uint16 (0 ))
} else if subbed > math .MaxUint16 {
uv = uint64 (uint16 (0xffff ))
} else {
uv = uint64 (uint16 (subbed ))
}
}
if i < 4 {
retLo |= uv << (i * 16 )
} else {
retHi |= uv << ((i - 4 ) * 16 )
}
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Mul :
x2hi , x2lo := ce .popValue (), ce .popValue ()
x1hi , x1lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
switch op .B1 {
case shapeI16x8 :
retHi = uint64 (uint16 (x1hi )*uint16 (x2hi )) | (uint64 (uint16 (x1hi >>16 )*uint16 (x2hi >>16 )) << 16 ) |
(uint64 (uint16 (x1hi >>32 )*uint16 (x2hi >>32 )) << 32 ) | (uint64 (uint16 (x1hi >>48 )*uint16 (x2hi >>48 )) << 48 )
retLo = uint64 (uint16 (x1lo )*uint16 (x2lo )) | (uint64 (uint16 (x1lo >>16 )*uint16 (x2lo >>16 )) << 16 ) |
(uint64 (uint16 (x1lo >>32 )*uint16 (x2lo >>32 )) << 32 ) | (uint64 (uint16 (x1lo >>48 )*uint16 (x2lo >>48 )) << 48 )
case shapeI32x4 :
retHi = uint64 (uint32 (x1hi )*uint32 (x2hi )) | (uint64 (uint32 (x1hi >>32 )*uint32 (x2hi >>32 )) << 32 )
retLo = uint64 (uint32 (x1lo )*uint32 (x2lo )) | (uint64 (uint32 (x1lo >>32 )*uint32 (x2lo >>32 )) << 32 )
case shapeI64x2 :
retHi = x1hi * x2hi
retLo = x1lo * x2lo
case shapeF32x4 :
retHi = mulFloat32bits (uint32 (x1hi ), uint32 (x2hi )) | mulFloat32bits (uint32 (x1hi >>32 ), uint32 (x2hi >>32 ))<<32
retLo = mulFloat32bits (uint32 (x1lo ), uint32 (x2lo )) | mulFloat32bits (uint32 (x1lo >>32 ), uint32 (x2lo >>32 ))<<32
case shapeF64x2 :
retHi = math .Float64bits (math .Float64frombits (x1hi ) * math .Float64frombits (x2hi ))
retLo = math .Float64bits (math .Float64frombits (x1lo ) * math .Float64frombits (x2lo ))
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Div :
x2hi , x2lo := ce .popValue (), ce .popValue ()
x1hi , x1lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
if op .B1 == shapeF64x2 {
retHi = math .Float64bits (math .Float64frombits (x1hi ) / math .Float64frombits (x2hi ))
retLo = math .Float64bits (math .Float64frombits (x1lo ) / math .Float64frombits (x2lo ))
} else {
retHi = divFloat32bits (uint32 (x1hi ), uint32 (x2hi )) | divFloat32bits (uint32 (x1hi >>32 ), uint32 (x2hi >>32 ))<<32
retLo = divFloat32bits (uint32 (x1lo ), uint32 (x2lo )) | divFloat32bits (uint32 (x1lo >>32 ), uint32 (x2lo >>32 ))<<32
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Neg :
hi , lo := ce .popValue (), ce .popValue ()
switch op .B1 {
case shapeI8x16 :
lo = uint64 (-byte (lo )) | (uint64 (-byte (lo >>8 )) << 8 ) |
(uint64 (-byte (lo >>16 )) << 16 ) | (uint64 (-byte (lo >>24 )) << 24 ) |
(uint64 (-byte (lo >>32 )) << 32 ) | (uint64 (-byte (lo >>40 )) << 40 ) |
(uint64 (-byte (lo >>48 )) << 48 ) | (uint64 (-byte (lo >>56 )) << 56 )
hi = uint64 (-byte (hi )) | (uint64 (-byte (hi >>8 )) << 8 ) |
(uint64 (-byte (hi >>16 )) << 16 ) | (uint64 (-byte (hi >>24 )) << 24 ) |
(uint64 (-byte (hi >>32 )) << 32 ) | (uint64 (-byte (hi >>40 )) << 40 ) |
(uint64 (-byte (hi >>48 )) << 48 ) | (uint64 (-byte (hi >>56 )) << 56 )
case shapeI16x8 :
hi = uint64 (-uint16 (hi )) | (uint64 (-uint16 (hi >>16 )) << 16 ) |
(uint64 (-uint16 (hi >>32 )) << 32 ) | (uint64 (-uint16 (hi >>48 )) << 48 )
lo = uint64 (-uint16 (lo )) | (uint64 (-uint16 (lo >>16 )) << 16 ) |
(uint64 (-uint16 (lo >>32 )) << 32 ) | (uint64 (-uint16 (lo >>48 )) << 48 )
case shapeI32x4 :
hi = uint64 (-uint32 (hi )) | (uint64 (-uint32 (hi >>32 )) << 32 )
lo = uint64 (-uint32 (lo )) | (uint64 (-uint32 (lo >>32 )) << 32 )
case shapeI64x2 :
hi = -hi
lo = -lo
case shapeF32x4 :
hi = uint64 (math .Float32bits (-math .Float32frombits (uint32 (hi )))) |
(uint64 (math .Float32bits (-math .Float32frombits (uint32 (hi >>32 )))) << 32 )
lo = uint64 (math .Float32bits (-math .Float32frombits (uint32 (lo )))) |
(uint64 (math .Float32bits (-math .Float32frombits (uint32 (lo >>32 )))) << 32 )
case shapeF64x2 :
hi = math .Float64bits (-math .Float64frombits (hi ))
lo = math .Float64bits (-math .Float64frombits (lo ))
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Sqrt :
hi , lo := ce .popValue (), ce .popValue ()
if op .B1 == shapeF64x2 {
hi = math .Float64bits (math .Sqrt (math .Float64frombits (hi )))
lo = math .Float64bits (math .Sqrt (math .Float64frombits (lo )))
} else {
hi = uint64 (math .Float32bits (float32 (math .Sqrt (float64 (math .Float32frombits (uint32 (hi ))))))) |
(uint64 (math .Float32bits (float32 (math .Sqrt (float64 (math .Float32frombits (uint32 (hi >>32 ))))))) << 32 )
lo = uint64 (math .Float32bits (float32 (math .Sqrt (float64 (math .Float32frombits (uint32 (lo ))))))) |
(uint64 (math .Float32bits (float32 (math .Sqrt (float64 (math .Float32frombits (uint32 (lo >>32 ))))))) << 32 )
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Abs :
hi , lo := ce .popValue (), ce .popValue ()
switch op .B1 {
case shapeI8x16 :
lo = uint64 (i8Abs (byte (lo ))) | (uint64 (i8Abs (byte (lo >>8 ))) << 8 ) |
(uint64 (i8Abs (byte (lo >>16 ))) << 16 ) | (uint64 (i8Abs (byte (lo >>24 ))) << 24 ) |
(uint64 (i8Abs (byte (lo >>32 ))) << 32 ) | (uint64 (i8Abs (byte (lo >>40 ))) << 40 ) |
(uint64 (i8Abs (byte (lo >>48 ))) << 48 ) | (uint64 (i8Abs (byte (lo >>56 ))) << 56 )
hi = uint64 (i8Abs (byte (hi ))) | (uint64 (i8Abs (byte (hi >>8 ))) << 8 ) |
(uint64 (i8Abs (byte (hi >>16 ))) << 16 ) | (uint64 (i8Abs (byte (hi >>24 ))) << 24 ) |
(uint64 (i8Abs (byte (hi >>32 ))) << 32 ) | (uint64 (i8Abs (byte (hi >>40 ))) << 40 ) |
(uint64 (i8Abs (byte (hi >>48 ))) << 48 ) | (uint64 (i8Abs (byte (hi >>56 ))) << 56 )
case shapeI16x8 :
hi = uint64 (i16Abs (uint16 (hi ))) | (uint64 (i16Abs (uint16 (hi >>16 ))) << 16 ) |
(uint64 (i16Abs (uint16 (hi >>32 ))) << 32 ) | (uint64 (i16Abs (uint16 (hi >>48 ))) << 48 )
lo = uint64 (i16Abs (uint16 (lo ))) | (uint64 (i16Abs (uint16 (lo >>16 ))) << 16 ) |
(uint64 (i16Abs (uint16 (lo >>32 ))) << 32 ) | (uint64 (i16Abs (uint16 (lo >>48 ))) << 48 )
case shapeI32x4 :
hi = uint64 (i32Abs (uint32 (hi ))) | (uint64 (i32Abs (uint32 (hi >>32 ))) << 32 )
lo = uint64 (i32Abs (uint32 (lo ))) | (uint64 (i32Abs (uint32 (lo >>32 ))) << 32 )
case shapeI64x2 :
if int64 (hi ) < 0 {
hi = -hi
}
if int64 (lo ) < 0 {
lo = -lo
}
case shapeF32x4 :
hi = hi &^ (1 <<31 | 1 <<63 )
lo = lo &^ (1 <<31 | 1 <<63 )
case shapeF64x2 :
hi = hi &^ (1 << 63 )
lo = lo &^ (1 << 63 )
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Popcnt :
hi , lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
for i := 0 ; i < 16 ; i ++ {
var v byte
if i < 8 {
v = byte (lo >> (i * 8 ))
} else {
v = byte (hi >> ((i - 8 ) * 8 ))
}
var cnt uint64
for i := 0 ; i < 8 ; i ++ {
if (v >>i )&0b1 != 0 {
cnt ++
}
}
if i < 8 {
retLo |= cnt << (i * 8 )
} else {
retHi |= cnt << ((i - 8 ) * 8 )
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Min :
x2hi , x2lo := ce .popValue (), ce .popValue ()
x1hi , x1lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
switch op .B1 {
case shapeI8x16 :
if op .B3 {
retLo = uint64 (i8MinS (uint8 (x1lo >>8 ), uint8 (x2lo >>8 )))<<8 | uint64 (i8MinS (uint8 (x1lo ), uint8 (x2lo ))) |
uint64 (i8MinS (uint8 (x1lo >>24 ), uint8 (x2lo >>24 )))<<24 | uint64 (i8MinS (uint8 (x1lo >>16 ), uint8 (x2lo >>16 )))<<16 |
uint64 (i8MinS (uint8 (x1lo >>40 ), uint8 (x2lo >>40 )))<<40 | uint64 (i8MinS (uint8 (x1lo >>32 ), uint8 (x2lo >>32 )))<<32 |
uint64 (i8MinS (uint8 (x1lo >>56 ), uint8 (x2lo >>56 )))<<56 | uint64 (i8MinS (uint8 (x1lo >>48 ), uint8 (x2lo >>48 )))<<48
retHi = uint64 (i8MinS (uint8 (x1hi >>8 ), uint8 (x2hi >>8 )))<<8 | uint64 (i8MinS (uint8 (x1hi ), uint8 (x2hi ))) |
uint64 (i8MinS (uint8 (x1hi >>24 ), uint8 (x2hi >>24 )))<<24 | uint64 (i8MinS (uint8 (x1hi >>16 ), uint8 (x2hi >>16 )))<<16 |
uint64 (i8MinS (uint8 (x1hi >>40 ), uint8 (x2hi >>40 )))<<40 | uint64 (i8MinS (uint8 (x1hi >>32 ), uint8 (x2hi >>32 )))<<32 |
uint64 (i8MinS (uint8 (x1hi >>56 ), uint8 (x2hi >>56 )))<<56 | uint64 (i8MinS (uint8 (x1hi >>48 ), uint8 (x2hi >>48 )))<<48
} else {
retLo = uint64 (i8MinU (uint8 (x1lo >>8 ), uint8 (x2lo >>8 )))<<8 | uint64 (i8MinU (uint8 (x1lo ), uint8 (x2lo ))) |
uint64 (i8MinU (uint8 (x1lo >>24 ), uint8 (x2lo >>24 )))<<24 | uint64 (i8MinU (uint8 (x1lo >>16 ), uint8 (x2lo >>16 )))<<16 |
uint64 (i8MinU (uint8 (x1lo >>40 ), uint8 (x2lo >>40 )))<<40 | uint64 (i8MinU (uint8 (x1lo >>32 ), uint8 (x2lo >>32 )))<<32 |
uint64 (i8MinU (uint8 (x1lo >>56 ), uint8 (x2lo >>56 )))<<56 | uint64 (i8MinU (uint8 (x1lo >>48 ), uint8 (x2lo >>48 )))<<48
retHi = uint64 (i8MinU (uint8 (x1hi >>8 ), uint8 (x2hi >>8 )))<<8 | uint64 (i8MinU (uint8 (x1hi ), uint8 (x2hi ))) |
uint64 (i8MinU (uint8 (x1hi >>24 ), uint8 (x2hi >>24 )))<<24 | uint64 (i8MinU (uint8 (x1hi >>16 ), uint8 (x2hi >>16 )))<<16 |
uint64 (i8MinU (uint8 (x1hi >>40 ), uint8 (x2hi >>40 )))<<40 | uint64 (i8MinU (uint8 (x1hi >>32 ), uint8 (x2hi >>32 )))<<32 |
uint64 (i8MinU (uint8 (x1hi >>56 ), uint8 (x2hi >>56 )))<<56 | uint64 (i8MinU (uint8 (x1hi >>48 ), uint8 (x2hi >>48 )))<<48
}
case shapeI16x8 :
if op .B3 {
retLo = uint64 (i16MinS (uint16 (x1lo ), uint16 (x2lo ))) |
uint64 (i16MinS (uint16 (x1lo >>16 ), uint16 (x2lo >>16 )))<<16 |
uint64 (i16MinS (uint16 (x1lo >>32 ), uint16 (x2lo >>32 )))<<32 |
uint64 (i16MinS (uint16 (x1lo >>48 ), uint16 (x2lo >>48 )))<<48
retHi = uint64 (i16MinS (uint16 (x1hi ), uint16 (x2hi ))) |
uint64 (i16MinS (uint16 (x1hi >>16 ), uint16 (x2hi >>16 )))<<16 |
uint64 (i16MinS (uint16 (x1hi >>32 ), uint16 (x2hi >>32 )))<<32 |
uint64 (i16MinS (uint16 (x1hi >>48 ), uint16 (x2hi >>48 )))<<48
} else {
retLo = uint64 (i16MinU (uint16 (x1lo ), uint16 (x2lo ))) |
uint64 (i16MinU (uint16 (x1lo >>16 ), uint16 (x2lo >>16 )))<<16 |
uint64 (i16MinU (uint16 (x1lo >>32 ), uint16 (x2lo >>32 )))<<32 |
uint64 (i16MinU (uint16 (x1lo >>48 ), uint16 (x2lo >>48 )))<<48
retHi = uint64 (i16MinU (uint16 (x1hi ), uint16 (x2hi ))) |
uint64 (i16MinU (uint16 (x1hi >>16 ), uint16 (x2hi >>16 )))<<16 |
uint64 (i16MinU (uint16 (x1hi >>32 ), uint16 (x2hi >>32 )))<<32 |
uint64 (i16MinU (uint16 (x1hi >>48 ), uint16 (x2hi >>48 )))<<48
}
case shapeI32x4 :
if op .B3 {
retLo = uint64 (i32MinS (uint32 (x1lo ), uint32 (x2lo ))) |
uint64 (i32MinS (uint32 (x1lo >>32 ), uint32 (x2lo >>32 )))<<32
retHi = uint64 (i32MinS (uint32 (x1hi ), uint32 (x2hi ))) |
uint64 (i32MinS (uint32 (x1hi >>32 ), uint32 (x2hi >>32 )))<<32
} else {
retLo = uint64 (i32MinU (uint32 (x1lo ), uint32 (x2lo ))) |
uint64 (i32MinU (uint32 (x1lo >>32 ), uint32 (x2lo >>32 )))<<32
retHi = uint64 (i32MinU (uint32 (x1hi ), uint32 (x2hi ))) |
uint64 (i32MinU (uint32 (x1hi >>32 ), uint32 (x2hi >>32 )))<<32
}
case shapeF32x4 :
retHi = wasmCompatMin32bits (uint32 (x1hi ), uint32 (x2hi )) |
wasmCompatMin32bits (uint32 (x1hi >>32 ), uint32 (x2hi >>32 ))<<32
retLo = wasmCompatMin32bits (uint32 (x1lo ), uint32 (x2lo )) |
wasmCompatMin32bits (uint32 (x1lo >>32 ), uint32 (x2lo >>32 ))<<32
case shapeF64x2 :
retHi = math .Float64bits (moremath .WasmCompatMin64 (
math .Float64frombits (x1hi ),
math .Float64frombits (x2hi ),
))
retLo = math .Float64bits (moremath .WasmCompatMin64 (
math .Float64frombits (x1lo ),
math .Float64frombits (x2lo ),
))
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Max :
x2hi , x2lo := ce .popValue (), ce .popValue ()
x1hi , x1lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
switch op .B1 {
case shapeI8x16 :
if op .B3 {
retLo = uint64 (i8MaxS (uint8 (x1lo >>8 ), uint8 (x2lo >>8 )))<<8 | uint64 (i8MaxS (uint8 (x1lo ), uint8 (x2lo ))) |
uint64 (i8MaxS (uint8 (x1lo >>24 ), uint8 (x2lo >>24 )))<<24 | uint64 (i8MaxS (uint8 (x1lo >>16 ), uint8 (x2lo >>16 )))<<16 |
uint64 (i8MaxS (uint8 (x1lo >>40 ), uint8 (x2lo >>40 )))<<40 | uint64 (i8MaxS (uint8 (x1lo >>32 ), uint8 (x2lo >>32 )))<<32 |
uint64 (i8MaxS (uint8 (x1lo >>56 ), uint8 (x2lo >>56 )))<<56 | uint64 (i8MaxS (uint8 (x1lo >>48 ), uint8 (x2lo >>48 )))<<48
retHi = uint64 (i8MaxS (uint8 (x1hi >>8 ), uint8 (x2hi >>8 )))<<8 | uint64 (i8MaxS (uint8 (x1hi ), uint8 (x2hi ))) |
uint64 (i8MaxS (uint8 (x1hi >>24 ), uint8 (x2hi >>24 )))<<24 | uint64 (i8MaxS (uint8 (x1hi >>16 ), uint8 (x2hi >>16 )))<<16 |
uint64 (i8MaxS (uint8 (x1hi >>40 ), uint8 (x2hi >>40 )))<<40 | uint64 (i8MaxS (uint8 (x1hi >>32 ), uint8 (x2hi >>32 )))<<32 |
uint64 (i8MaxS (uint8 (x1hi >>56 ), uint8 (x2hi >>56 )))<<56 | uint64 (i8MaxS (uint8 (x1hi >>48 ), uint8 (x2hi >>48 )))<<48
} else {
retLo = uint64 (i8MaxU (uint8 (x1lo >>8 ), uint8 (x2lo >>8 )))<<8 | uint64 (i8MaxU (uint8 (x1lo ), uint8 (x2lo ))) |
uint64 (i8MaxU (uint8 (x1lo >>24 ), uint8 (x2lo >>24 )))<<24 | uint64 (i8MaxU (uint8 (x1lo >>16 ), uint8 (x2lo >>16 )))<<16 |
uint64 (i8MaxU (uint8 (x1lo >>40 ), uint8 (x2lo >>40 )))<<40 | uint64 (i8MaxU (uint8 (x1lo >>32 ), uint8 (x2lo >>32 )))<<32 |
uint64 (i8MaxU (uint8 (x1lo >>56 ), uint8 (x2lo >>56 )))<<56 | uint64 (i8MaxU (uint8 (x1lo >>48 ), uint8 (x2lo >>48 )))<<48
retHi = uint64 (i8MaxU (uint8 (x1hi >>8 ), uint8 (x2hi >>8 )))<<8 | uint64 (i8MaxU (uint8 (x1hi ), uint8 (x2hi ))) |
uint64 (i8MaxU (uint8 (x1hi >>24 ), uint8 (x2hi >>24 )))<<24 | uint64 (i8MaxU (uint8 (x1hi >>16 ), uint8 (x2hi >>16 )))<<16 |
uint64 (i8MaxU (uint8 (x1hi >>40 ), uint8 (x2hi >>40 )))<<40 | uint64 (i8MaxU (uint8 (x1hi >>32 ), uint8 (x2hi >>32 )))<<32 |
uint64 (i8MaxU (uint8 (x1hi >>56 ), uint8 (x2hi >>56 )))<<56 | uint64 (i8MaxU (uint8 (x1hi >>48 ), uint8 (x2hi >>48 )))<<48
}
case shapeI16x8 :
if op .B3 {
retLo = uint64 (i16MaxS (uint16 (x1lo ), uint16 (x2lo ))) |
uint64 (i16MaxS (uint16 (x1lo >>16 ), uint16 (x2lo >>16 )))<<16 |
uint64 (i16MaxS (uint16 (x1lo >>32 ), uint16 (x2lo >>32 )))<<32 |
uint64 (i16MaxS (uint16 (x1lo >>48 ), uint16 (x2lo >>48 )))<<48
retHi = uint64 (i16MaxS (uint16 (x1hi ), uint16 (x2hi ))) |
uint64 (i16MaxS (uint16 (x1hi >>16 ), uint16 (x2hi >>16 )))<<16 |
uint64 (i16MaxS (uint16 (x1hi >>32 ), uint16 (x2hi >>32 )))<<32 |
uint64 (i16MaxS (uint16 (x1hi >>48 ), uint16 (x2hi >>48 )))<<48
} else {
retLo = uint64 (i16MaxU (uint16 (x1lo ), uint16 (x2lo ))) |
uint64 (i16MaxU (uint16 (x1lo >>16 ), uint16 (x2lo >>16 )))<<16 |
uint64 (i16MaxU (uint16 (x1lo >>32 ), uint16 (x2lo >>32 )))<<32 |
uint64 (i16MaxU (uint16 (x1lo >>48 ), uint16 (x2lo >>48 )))<<48
retHi = uint64 (i16MaxU (uint16 (x1hi ), uint16 (x2hi ))) |
uint64 (i16MaxU (uint16 (x1hi >>16 ), uint16 (x2hi >>16 )))<<16 |
uint64 (i16MaxU (uint16 (x1hi >>32 ), uint16 (x2hi >>32 )))<<32 |
uint64 (i16MaxU (uint16 (x1hi >>48 ), uint16 (x2hi >>48 )))<<48
}
case shapeI32x4 :
if op .B3 {
retLo = uint64 (i32MaxS (uint32 (x1lo ), uint32 (x2lo ))) |
uint64 (i32MaxS (uint32 (x1lo >>32 ), uint32 (x2lo >>32 )))<<32
retHi = uint64 (i32MaxS (uint32 (x1hi ), uint32 (x2hi ))) |
uint64 (i32MaxS (uint32 (x1hi >>32 ), uint32 (x2hi >>32 )))<<32
} else {
retLo = uint64 (i32MaxU (uint32 (x1lo ), uint32 (x2lo ))) |
uint64 (i32MaxU (uint32 (x1lo >>32 ), uint32 (x2lo >>32 )))<<32
retHi = uint64 (i32MaxU (uint32 (x1hi ), uint32 (x2hi ))) |
uint64 (i32MaxU (uint32 (x1hi >>32 ), uint32 (x2hi >>32 )))<<32
}
case shapeF32x4 :
retHi = wasmCompatMax32bits (uint32 (x1hi ), uint32 (x2hi )) |
wasmCompatMax32bits (uint32 (x1hi >>32 ), uint32 (x2hi >>32 ))<<32
retLo = wasmCompatMax32bits (uint32 (x1lo ), uint32 (x2lo )) |
wasmCompatMax32bits (uint32 (x1lo >>32 ), uint32 (x2lo >>32 ))<<32
case shapeF64x2 :
retHi = math .Float64bits (moremath .WasmCompatMax64 (
math .Float64frombits (x1hi ),
math .Float64frombits (x2hi ),
))
retLo = math .Float64bits (moremath .WasmCompatMax64 (
math .Float64frombits (x1lo ),
math .Float64frombits (x2lo ),
))
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128AvgrU :
x2hi , x2lo := ce .popValue (), ce .popValue ()
x1hi , x1lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
switch op .B1 {
case shapeI8x16 :
retLo = uint64 (i8RoundingAverage (uint8 (x1lo >>8 ), uint8 (x2lo >>8 )))<<8 | uint64 (i8RoundingAverage (uint8 (x1lo ), uint8 (x2lo ))) |
uint64 (i8RoundingAverage (uint8 (x1lo >>24 ), uint8 (x2lo >>24 )))<<24 | uint64 (i8RoundingAverage (uint8 (x1lo >>16 ), uint8 (x2lo >>16 )))<<16 |
uint64 (i8RoundingAverage (uint8 (x1lo >>40 ), uint8 (x2lo >>40 )))<<40 | uint64 (i8RoundingAverage (uint8 (x1lo >>32 ), uint8 (x2lo >>32 )))<<32 |
uint64 (i8RoundingAverage (uint8 (x1lo >>56 ), uint8 (x2lo >>56 )))<<56 | uint64 (i8RoundingAverage (uint8 (x1lo >>48 ), uint8 (x2lo >>48 )))<<48
retHi = uint64 (i8RoundingAverage (uint8 (x1hi >>8 ), uint8 (x2hi >>8 )))<<8 | uint64 (i8RoundingAverage (uint8 (x1hi ), uint8 (x2hi ))) |
uint64 (i8RoundingAverage (uint8 (x1hi >>24 ), uint8 (x2hi >>24 )))<<24 | uint64 (i8RoundingAverage (uint8 (x1hi >>16 ), uint8 (x2hi >>16 )))<<16 |
uint64 (i8RoundingAverage (uint8 (x1hi >>40 ), uint8 (x2hi >>40 )))<<40 | uint64 (i8RoundingAverage (uint8 (x1hi >>32 ), uint8 (x2hi >>32 )))<<32 |
uint64 (i8RoundingAverage (uint8 (x1hi >>56 ), uint8 (x2hi >>56 )))<<56 | uint64 (i8RoundingAverage (uint8 (x1hi >>48 ), uint8 (x2hi >>48 )))<<48
case shapeI16x8 :
retLo = uint64 (i16RoundingAverage (uint16 (x1lo ), uint16 (x2lo ))) |
uint64 (i16RoundingAverage (uint16 (x1lo >>16 ), uint16 (x2lo >>16 )))<<16 |
uint64 (i16RoundingAverage (uint16 (x1lo >>32 ), uint16 (x2lo >>32 )))<<32 |
uint64 (i16RoundingAverage (uint16 (x1lo >>48 ), uint16 (x2lo >>48 )))<<48
retHi = uint64 (i16RoundingAverage (uint16 (x1hi ), uint16 (x2hi ))) |
uint64 (i16RoundingAverage (uint16 (x1hi >>16 ), uint16 (x2hi >>16 )))<<16 |
uint64 (i16RoundingAverage (uint16 (x1hi >>32 ), uint16 (x2hi >>32 )))<<32 |
uint64 (i16RoundingAverage (uint16 (x1hi >>48 ), uint16 (x2hi >>48 )))<<48
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Pmin :
x2hi , x2lo := ce .popValue (), ce .popValue ()
x1hi , x1lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
if op .B1 == shapeF32x4 {
if flt32 (math .Float32frombits (uint32 (x2lo )), math .Float32frombits (uint32 (x1lo ))) {
retLo = x2lo & 0x00000000_ffffffff
} else {
retLo = x1lo & 0x00000000_ffffffff
}
if flt32 (math .Float32frombits (uint32 (x2lo >>32 )), math .Float32frombits (uint32 (x1lo >>32 ))) {
retLo |= x2lo & 0xffffffff_00000000
} else {
retLo |= x1lo & 0xffffffff_00000000
}
if flt32 (math .Float32frombits (uint32 (x2hi )), math .Float32frombits (uint32 (x1hi ))) {
retHi = x2hi & 0x00000000_ffffffff
} else {
retHi = x1hi & 0x00000000_ffffffff
}
if flt32 (math .Float32frombits (uint32 (x2hi >>32 )), math .Float32frombits (uint32 (x1hi >>32 ))) {
retHi |= x2hi & 0xffffffff_00000000
} else {
retHi |= x1hi & 0xffffffff_00000000
}
} else {
if flt64 (math .Float64frombits (x2lo ), math .Float64frombits (x1lo )) {
retLo = x2lo
} else {
retLo = x1lo
}
if flt64 (math .Float64frombits (x2hi ), math .Float64frombits (x1hi )) {
retHi = x2hi
} else {
retHi = x1hi
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Pmax :
x2hi , x2lo := ce .popValue (), ce .popValue ()
x1hi , x1lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
if op .B1 == shapeF32x4 {
if flt32 (math .Float32frombits (uint32 (x1lo )), math .Float32frombits (uint32 (x2lo ))) {
retLo = x2lo & 0x00000000_ffffffff
} else {
retLo = x1lo & 0x00000000_ffffffff
}
if flt32 (math .Float32frombits (uint32 (x1lo >>32 )), math .Float32frombits (uint32 (x2lo >>32 ))) {
retLo |= x2lo & 0xffffffff_00000000
} else {
retLo |= x1lo & 0xffffffff_00000000
}
if flt32 (math .Float32frombits (uint32 (x1hi )), math .Float32frombits (uint32 (x2hi ))) {
retHi = x2hi & 0x00000000_ffffffff
} else {
retHi = x1hi & 0x00000000_ffffffff
}
if flt32 (math .Float32frombits (uint32 (x1hi >>32 )), math .Float32frombits (uint32 (x2hi >>32 ))) {
retHi |= x2hi & 0xffffffff_00000000
} else {
retHi |= x1hi & 0xffffffff_00000000
}
} else {
if flt64 (math .Float64frombits (x1lo ), math .Float64frombits (x2lo )) {
retLo = x2lo
} else {
retLo = x1lo
}
if flt64 (math .Float64frombits (x1hi ), math .Float64frombits (x2hi )) {
retHi = x2hi
} else {
retHi = x1hi
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Ceil :
hi , lo := ce .popValue (), ce .popValue ()
if op .B1 == shapeF32x4 {
lo = uint64 (math .Float32bits (moremath .WasmCompatCeilF32 (math .Float32frombits (uint32 (lo ))))) |
(uint64 (math .Float32bits (moremath .WasmCompatCeilF32 (math .Float32frombits (uint32 (lo >>32 ))))) << 32 )
hi = uint64 (math .Float32bits (moremath .WasmCompatCeilF32 (math .Float32frombits (uint32 (hi ))))) |
(uint64 (math .Float32bits (moremath .WasmCompatCeilF32 (math .Float32frombits (uint32 (hi >>32 ))))) << 32 )
} else {
lo = math .Float64bits (moremath .WasmCompatCeilF64 (math .Float64frombits (lo )))
hi = math .Float64bits (moremath .WasmCompatCeilF64 (math .Float64frombits (hi )))
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Floor :
hi , lo := ce .popValue (), ce .popValue ()
if op .B1 == shapeF32x4 {
lo = uint64 (math .Float32bits (moremath .WasmCompatFloorF32 (math .Float32frombits (uint32 (lo ))))) |
(uint64 (math .Float32bits (moremath .WasmCompatFloorF32 (math .Float32frombits (uint32 (lo >>32 ))))) << 32 )
hi = uint64 (math .Float32bits (moremath .WasmCompatFloorF32 (math .Float32frombits (uint32 (hi ))))) |
(uint64 (math .Float32bits (moremath .WasmCompatFloorF32 (math .Float32frombits (uint32 (hi >>32 ))))) << 32 )
} else {
lo = math .Float64bits (moremath .WasmCompatFloorF64 (math .Float64frombits (lo )))
hi = math .Float64bits (moremath .WasmCompatFloorF64 (math .Float64frombits (hi )))
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Trunc :
hi , lo := ce .popValue (), ce .popValue ()
if op .B1 == shapeF32x4 {
lo = uint64 (math .Float32bits (moremath .WasmCompatTruncF32 (math .Float32frombits (uint32 (lo ))))) |
(uint64 (math .Float32bits (moremath .WasmCompatTruncF32 (math .Float32frombits (uint32 (lo >>32 ))))) << 32 )
hi = uint64 (math .Float32bits (moremath .WasmCompatTruncF32 (math .Float32frombits (uint32 (hi ))))) |
(uint64 (math .Float32bits (moremath .WasmCompatTruncF32 (math .Float32frombits (uint32 (hi >>32 ))))) << 32 )
} else {
lo = math .Float64bits (moremath .WasmCompatTruncF64 (math .Float64frombits (lo )))
hi = math .Float64bits (moremath .WasmCompatTruncF64 (math .Float64frombits (hi )))
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Nearest :
hi , lo := ce .popValue (), ce .popValue ()
if op .B1 == shapeF32x4 {
lo = uint64 (math .Float32bits (moremath .WasmCompatNearestF32 (math .Float32frombits (uint32 (lo ))))) |
(uint64 (math .Float32bits (moremath .WasmCompatNearestF32 (math .Float32frombits (uint32 (lo >>32 ))))) << 32 )
hi = uint64 (math .Float32bits (moremath .WasmCompatNearestF32 (math .Float32frombits (uint32 (hi ))))) |
(uint64 (math .Float32bits (moremath .WasmCompatNearestF32 (math .Float32frombits (uint32 (hi >>32 ))))) << 32 )
} else {
lo = math .Float64bits (moremath .WasmCompatNearestF64 (math .Float64frombits (lo )))
hi = math .Float64bits (moremath .WasmCompatNearestF64 (math .Float64frombits (hi )))
}
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128Extend :
hi , lo := ce .popValue (), ce .popValue ()
var origin uint64
if op .B3 {
origin = lo
} else {
origin = hi
}
signed := op .B2 == 1
var retHi , retLo uint64
switch op .B1 {
case shapeI8x16 :
for i := 0 ; i < 8 ; i ++ {
v8 := byte (origin >> (i * 8 ))
var v16 uint16
if signed {
v16 = uint16 (int8 (v8 ))
} else {
v16 = uint16 (v8 )
}
if i < 4 {
retLo |= uint64 (v16 ) << (i * 16 )
} else {
retHi |= uint64 (v16 ) << ((i - 4 ) * 16 )
}
}
case shapeI16x8 :
for i := 0 ; i < 4 ; i ++ {
v16 := uint16 (origin >> (i * 16 ))
var v32 uint32
if signed {
v32 = uint32 (int16 (v16 ))
} else {
v32 = uint32 (v16 )
}
if i < 2 {
retLo |= uint64 (v32 ) << (i * 32 )
} else {
retHi |= uint64 (v32 ) << ((i - 2 ) * 32 )
}
}
case shapeI32x4 :
v32Lo := uint32 (origin )
v32Hi := uint32 (origin >> 32 )
if signed {
retLo = uint64 (int32 (v32Lo ))
retHi = uint64 (int32 (v32Hi ))
} else {
retLo = uint64 (v32Lo )
retHi = uint64 (v32Hi )
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128ExtMul :
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
x1Hi , x1Lo := ce .popValue (), ce .popValue ()
var x1 , x2 uint64
if op .B3 {
x1 , x2 = x1Lo , x2Lo
} else {
x1 , x2 = x1Hi , x2Hi
}
signed := op .B2 == 1
var retLo , retHi uint64
switch op .B1 {
case shapeI8x16 :
for i := 0 ; i < 8 ; i ++ {
v1 , v2 := byte (x1 >>(i *8 )), byte (x2 >>(i *8 ))
var v16 uint16
if signed {
v16 = uint16 (int16 (int8 (v1 )) * int16 (int8 (v2 )))
} else {
v16 = uint16 (v1 ) * uint16 (v2 )
}
if i < 4 {
retLo |= uint64 (v16 ) << (i * 16 )
} else {
retHi |= uint64 (v16 ) << ((i - 4 ) * 16 )
}
}
case shapeI16x8 :
for i := 0 ; i < 4 ; i ++ {
v1 , v2 := uint16 (x1 >>(i *16 )), uint16 (x2 >>(i *16 ))
var v32 uint32
if signed {
v32 = uint32 (int32 (int16 (v1 )) * int32 (int16 (v2 )))
} else {
v32 = uint32 (v1 ) * uint32 (v2 )
}
if i < 2 {
retLo |= uint64 (v32 ) << (i * 32 )
} else {
retHi |= uint64 (v32 ) << ((i - 2 ) * 32 )
}
}
case shapeI32x4 :
v1Lo , v2Lo := uint32 (x1 ), uint32 (x2 )
v1Hi , v2Hi := uint32 (x1 >>32 ), uint32 (x2 >>32 )
if signed {
retLo = uint64 (int64 (int32 (v1Lo )) * int64 (int32 (v2Lo )))
retHi = uint64 (int64 (int32 (v1Hi )) * int64 (int32 (v2Hi )))
} else {
retLo = uint64 (v1Lo ) * uint64 (v2Lo )
retHi = uint64 (v1Hi ) * uint64 (v2Hi )
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Q15mulrSatS :
x2hi , x2Lo := ce .popValue (), ce .popValue ()
x1hi , x1Lo := ce .popValue (), ce .popValue ()
var retLo , retHi uint64
for i := 0 ; i < 8 ; i ++ {
var v , w int16
if i < 4 {
v , w = int16 (uint16 (x1Lo >>(i *16 ))), int16 (uint16 (x2Lo >>(i *16 )))
} else {
v , w = int16 (uint16 (x1hi >>((i -4 )*16 ))), int16 (uint16 (x2hi >>((i -4 )*16 )))
}
var uv uint64
if calc := ((int32 (v ) * int32 (w )) + 0x4000 ) >> 15 ; calc < math .MinInt16 {
uv = uint64 (uint16 (0x8000 ))
} else if calc > math .MaxInt16 {
uv = uint64 (uint16 (0x7fff ))
} else {
uv = uint64 (uint16 (int16 (calc )))
}
if i < 4 {
retLo |= uv << (i * 16 )
} else {
retHi |= uv << ((i - 4 ) * 16 )
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128ExtAddPairwise :
hi , lo := ce .popValue (), ce .popValue ()
signed := op .B3
var retLo , retHi uint64
switch op .B1 {
case shapeI8x16 :
for i := 0 ; i < 8 ; i ++ {
var v1 , v2 byte
if i < 4 {
v1 , v2 = byte (lo >>((i *2 )*8 )), byte (lo >>((i *2 +1 )*8 ))
} else {
v1 , v2 = byte (hi >>(((i -4 )*2 )*8 )), byte (hi >>(((i -4 )*2 +1 )*8 ))
}
var v16 uint16
if signed {
v16 = uint16 (int16 (int8 (v1 )) + int16 (int8 (v2 )))
} else {
v16 = uint16 (v1 ) + uint16 (v2 )
}
if i < 4 {
retLo |= uint64 (v16 ) << (i * 16 )
} else {
retHi |= uint64 (v16 ) << ((i - 4 ) * 16 )
}
}
case shapeI16x8 :
for i := 0 ; i < 4 ; i ++ {
var v1 , v2 uint16
if i < 2 {
v1 , v2 = uint16 (lo >>((i *2 )*16 )), uint16 (lo >>((i *2 +1 )*16 ))
} else {
v1 , v2 = uint16 (hi >>(((i -2 )*2 )*16 )), uint16 (hi >>(((i -2 )*2 +1 )*16 ))
}
var v32 uint32
if signed {
v32 = uint32 (int32 (int16 (v1 )) + int32 (int16 (v2 )))
} else {
v32 = uint32 (v1 ) + uint32 (v2 )
}
if i < 2 {
retLo |= uint64 (v32 ) << (i * 32 )
} else {
retHi |= uint64 (v32 ) << ((i - 2 ) * 32 )
}
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128FloatPromote :
_ , toPromote := ce .popValue (), ce .popValue ()
ce .pushValue (math .Float64bits (float64 (math .Float32frombits (uint32 (toPromote )))))
ce .pushValue (math .Float64bits (float64 (math .Float32frombits (uint32 (toPromote >> 32 )))))
frame .pc ++
case operationKindV128FloatDemote :
hi , lo := ce .popValue (), ce .popValue ()
ce .pushValue (
uint64 (math .Float32bits (float32 (math .Float64frombits (lo )))) |
(uint64 (math .Float32bits (float32 (math .Float64frombits (hi )))) << 32 ),
)
ce .pushValue (0 )
frame .pc ++
case operationKindV128FConvertFromI :
hi , lo := ce .popValue (), ce .popValue ()
v1 , v2 , v3 , v4 := uint32 (lo ), uint32 (lo >>32 ), uint32 (hi ), uint32 (hi >>32 )
signed := op .B3
var retLo , retHi uint64
switch op .B1 {
case shapeF32x4 :
if signed {
retLo = uint64 (math .Float32bits (float32 (int32 (v1 )))) |
(uint64 (math .Float32bits (float32 (int32 (v2 )))) << 32 )
retHi = uint64 (math .Float32bits (float32 (int32 (v3 )))) |
(uint64 (math .Float32bits (float32 (int32 (v4 )))) << 32 )
} else {
retLo = uint64 (math .Float32bits (float32 (v1 ))) |
(uint64 (math .Float32bits (float32 (v2 ))) << 32 )
retHi = uint64 (math .Float32bits (float32 (v3 ))) |
(uint64 (math .Float32bits (float32 (v4 ))) << 32 )
}
case shapeF64x2 :
if signed {
retLo , retHi = math .Float64bits (float64 (int32 (v1 ))), math .Float64bits (float64 (int32 (v2 )))
} else {
retLo , retHi = math .Float64bits (float64 (v1 )), math .Float64bits (float64 (v2 ))
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Narrow :
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
x1Hi , x1Lo := ce .popValue (), ce .popValue ()
signed := op .B3
var retLo , retHi uint64
switch op .B1 {
case shapeI16x8 :
for i := 0 ; i < 8 ; i ++ {
var v16 uint16
if i < 4 {
v16 = uint16 (x1Lo >> (i * 16 ))
} else {
v16 = uint16 (x1Hi >> ((i - 4 ) * 16 ))
}
var v byte
if signed {
if s := int16 (v16 ); s > math .MaxInt8 {
v = math .MaxInt8
} else if s < math .MinInt8 {
s = math .MinInt8
v = byte (s )
} else {
v = byte (v16 )
}
} else {
if s := int16 (v16 ); s > math .MaxUint8 {
v = math .MaxUint8
} else if s < 0 {
v = 0
} else {
v = byte (v16 )
}
}
retLo |= uint64 (v ) << (i * 8 )
}
for i := 0 ; i < 8 ; i ++ {
var v16 uint16
if i < 4 {
v16 = uint16 (x2Lo >> (i * 16 ))
} else {
v16 = uint16 (x2Hi >> ((i - 4 ) * 16 ))
}
var v byte
if signed {
if s := int16 (v16 ); s > math .MaxInt8 {
v = math .MaxInt8
} else if s < math .MinInt8 {
s = math .MinInt8
v = byte (s )
} else {
v = byte (v16 )
}
} else {
if s := int16 (v16 ); s > math .MaxUint8 {
v = math .MaxUint8
} else if s < 0 {
v = 0
} else {
v = byte (v16 )
}
}
retHi |= uint64 (v ) << (i * 8 )
}
case shapeI32x4 :
for i := 0 ; i < 4 ; i ++ {
var v32 uint32
if i < 2 {
v32 = uint32 (x1Lo >> (i * 32 ))
} else {
v32 = uint32 (x1Hi >> ((i - 2 ) * 32 ))
}
var v uint16
if signed {
if s := int32 (v32 ); s > math .MaxInt16 {
v = math .MaxInt16
} else if s < math .MinInt16 {
s = math .MinInt16
v = uint16 (s )
} else {
v = uint16 (v32 )
}
} else {
if s := int32 (v32 ); s > math .MaxUint16 {
v = math .MaxUint16
} else if s < 0 {
v = 0
} else {
v = uint16 (v32 )
}
}
retLo |= uint64 (v ) << (i * 16 )
}
for i := 0 ; i < 4 ; i ++ {
var v32 uint32
if i < 2 {
v32 = uint32 (x2Lo >> (i * 32 ))
} else {
v32 = uint32 (x2Hi >> ((i - 2 ) * 32 ))
}
var v uint16
if signed {
if s := int32 (v32 ); s > math .MaxInt16 {
v = math .MaxInt16
} else if s < math .MinInt16 {
s = math .MinInt16
v = uint16 (s )
} else {
v = uint16 (v32 )
}
} else {
if s := int32 (v32 ); s > math .MaxUint16 {
v = math .MaxUint16
} else if s < 0 {
v = 0
} else {
v = uint16 (v32 )
}
}
retHi |= uint64 (v ) << (i * 16 )
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindV128Dot :
x2Hi , x2Lo := ce .popValue (), ce .popValue ()
x1Hi , x1Lo := ce .popValue (), ce .popValue ()
lo , hi := v128Dot (x1Hi , x1Lo , x2Hi , x2Lo )
ce .pushValue (lo )
ce .pushValue (hi )
frame .pc ++
case operationKindV128ITruncSatFromF :
hi , lo := ce .popValue (), ce .popValue ()
signed := op .B3
var retLo , retHi uint64
switch op .B1 {
case shapeF32x4 :
for i , f64 := range [4 ]float64 {
math .Trunc (float64 (math .Float32frombits (uint32 (lo )))),
math .Trunc (float64 (math .Float32frombits (uint32 (lo >> 32 )))),
math .Trunc (float64 (math .Float32frombits (uint32 (hi )))),
math .Trunc (float64 (math .Float32frombits (uint32 (hi >> 32 )))),
} {
var v uint32
if math .IsNaN (f64 ) {
v = 0
} else if signed {
if f64 < math .MinInt32 {
f64 = math .MinInt32
} else if f64 > math .MaxInt32 {
f64 = math .MaxInt32
}
v = uint32 (int32 (f64 ))
} else {
if f64 < 0 {
f64 = 0
} else if f64 > math .MaxUint32 {
f64 = math .MaxUint32
}
v = uint32 (f64 )
}
if i < 2 {
retLo |= uint64 (v ) << (i * 32 )
} else {
retHi |= uint64 (v ) << ((i - 2 ) * 32 )
}
}
case shapeF64x2 :
for i , f := range [2 ]float64 {
math .Trunc (math .Float64frombits (lo )),
math .Trunc (math .Float64frombits (hi )),
} {
var v uint32
if math .IsNaN (f ) {
v = 0
} else if signed {
if f < math .MinInt32 {
f = math .MinInt32
} else if f > math .MaxInt32 {
f = math .MaxInt32
}
v = uint32 (int32 (f ))
} else {
if f < 0 {
f = 0
} else if f > math .MaxUint32 {
f = math .MaxUint32
}
v = uint32 (f )
}
retLo |= uint64 (v ) << (i * 32 )
}
}
ce .pushValue (retLo )
ce .pushValue (retHi )
frame .pc ++
case operationKindAtomicMemoryWait :
timeout := int64 (ce .popValue ())
exp := ce .popValue ()
offset := ce .popMemoryOffset (op )
if !memoryInst .Shared {
panic (wasmruntime .ErrRuntimeExpectedSharedMemory )
}
switch unsignedType (op .B1 ) {
case unsignedTypeI32 :
if offset %4 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
if int (offset ) > len (memoryInst .Buffer )-4 {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (memoryInst .Wait32 (offset , uint32 (exp ), timeout , func (mem *wasm .MemoryInstance , offset uint32 ) uint32 {
mem .Mux .Lock ()
defer mem .Mux .Unlock ()
value , _ := mem .ReadUint32Le (offset )
return value
}))
case unsignedTypeI64 :
if offset %8 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
if int (offset ) > len (memoryInst .Buffer )-8 {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (memoryInst .Wait64 (offset , exp , timeout , func (mem *wasm .MemoryInstance , offset uint32 ) uint64 {
mem .Mux .Lock ()
defer mem .Mux .Unlock ()
value , _ := mem .ReadUint64Le (offset )
return value
}))
}
frame .pc ++
case operationKindAtomicMemoryNotify :
count := ce .popValue ()
offset := ce .popMemoryOffset (op )
if offset %4 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
if offset >= memoryInst .Size () {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
res := memoryInst .Notify (offset , uint32 (count ))
ce .pushValue (uint64 (res ))
frame .pc ++
case operationKindAtomicFence :
if memoryInst != nil {
memoryInst .Mux .Lock ()
memoryInst .Mux .Unlock ()
}
frame .pc ++
case operationKindAtomicLoad :
offset := ce .popMemoryOffset (op )
switch unsignedType (op .B1 ) {
case unsignedTypeI32 :
if offset %4 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
val , ok := memoryInst .ReadUint32Le (offset )
memoryInst .Mux .Unlock ()
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (uint64 (val ))
case unsignedTypeI64 :
if offset %8 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
val , ok := memoryInst .ReadUint64Le (offset )
memoryInst .Mux .Unlock ()
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (val )
}
frame .pc ++
case operationKindAtomicLoad8 :
offset := ce .popMemoryOffset (op )
memoryInst .Mux .Lock ()
val , ok := memoryInst .ReadByte (offset )
memoryInst .Mux .Unlock ()
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (uint64 (val ))
frame .pc ++
case operationKindAtomicLoad16 :
offset := ce .popMemoryOffset (op )
if offset %2 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
val , ok := memoryInst .ReadUint16Le (offset )
memoryInst .Mux .Unlock ()
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
ce .pushValue (uint64 (val ))
frame .pc ++
case operationKindAtomicStore :
val := ce .popValue ()
offset := ce .popMemoryOffset (op )
switch unsignedType (op .B1 ) {
case unsignedTypeI32 :
if offset %4 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
ok := memoryInst .WriteUint32Le (offset , uint32 (val ))
memoryInst .Mux .Unlock ()
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
case unsignedTypeI64 :
if offset %8 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
ok := memoryInst .WriteUint64Le (offset , val )
memoryInst .Mux .Unlock ()
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
}
frame .pc ++
case operationKindAtomicStore8 :
val := byte (ce .popValue ())
offset := ce .popMemoryOffset (op )
memoryInst .Mux .Lock ()
ok := memoryInst .WriteByte (offset , val )
memoryInst .Mux .Unlock ()
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
frame .pc ++
case operationKindAtomicStore16 :
val := uint16 (ce .popValue ())
offset := ce .popMemoryOffset (op )
if offset %2 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
ok := memoryInst .WriteUint16Le (offset , val )
memoryInst .Mux .Unlock ()
if !ok {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
frame .pc ++
case operationKindAtomicRMW :
val := ce .popValue ()
offset := ce .popMemoryOffset (op )
switch unsignedType (op .B1 ) {
case unsignedTypeI32 :
if offset %4 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
old , ok := memoryInst .ReadUint32Le (offset )
if !ok {
memoryInst .Mux .Unlock ()
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
var newVal uint32
switch atomicArithmeticOp (op .B2 ) {
case atomicArithmeticOpAdd :
newVal = old + uint32 (val )
case atomicArithmeticOpSub :
newVal = old - uint32 (val )
case atomicArithmeticOpAnd :
newVal = old & uint32 (val )
case atomicArithmeticOpOr :
newVal = old | uint32 (val )
case atomicArithmeticOpXor :
newVal = old ^ uint32 (val )
case atomicArithmeticOpNop :
newVal = uint32 (val )
}
memoryInst .WriteUint32Le (offset , newVal )
memoryInst .Mux .Unlock ()
ce .pushValue (uint64 (old ))
case unsignedTypeI64 :
if offset %8 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
old , ok := memoryInst .ReadUint64Le (offset )
if !ok {
memoryInst .Mux .Unlock ()
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
var newVal uint64
switch atomicArithmeticOp (op .B2 ) {
case atomicArithmeticOpAdd :
newVal = old + val
case atomicArithmeticOpSub :
newVal = old - val
case atomicArithmeticOpAnd :
newVal = old & val
case atomicArithmeticOpOr :
newVal = old | val
case atomicArithmeticOpXor :
newVal = old ^ val
case atomicArithmeticOpNop :
newVal = val
}
memoryInst .WriteUint64Le (offset , newVal )
memoryInst .Mux .Unlock ()
ce .pushValue (old )
}
frame .pc ++
case operationKindAtomicRMW8 :
val := ce .popValue ()
offset := ce .popMemoryOffset (op )
memoryInst .Mux .Lock ()
old , ok := memoryInst .ReadByte (offset )
if !ok {
memoryInst .Mux .Unlock ()
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
arg := byte (val )
var newVal byte
switch atomicArithmeticOp (op .B2 ) {
case atomicArithmeticOpAdd :
newVal = old + arg
case atomicArithmeticOpSub :
newVal = old - arg
case atomicArithmeticOpAnd :
newVal = old & arg
case atomicArithmeticOpOr :
newVal = old | arg
case atomicArithmeticOpXor :
newVal = old ^ arg
case atomicArithmeticOpNop :
newVal = arg
}
memoryInst .WriteByte (offset , newVal )
memoryInst .Mux .Unlock ()
ce .pushValue (uint64 (old ))
frame .pc ++
case operationKindAtomicRMW16 :
val := ce .popValue ()
offset := ce .popMemoryOffset (op )
if offset %2 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
old , ok := memoryInst .ReadUint16Le (offset )
if !ok {
memoryInst .Mux .Unlock ()
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
arg := uint16 (val )
var newVal uint16
switch atomicArithmeticOp (op .B2 ) {
case atomicArithmeticOpAdd :
newVal = old + arg
case atomicArithmeticOpSub :
newVal = old - arg
case atomicArithmeticOpAnd :
newVal = old & arg
case atomicArithmeticOpOr :
newVal = old | arg
case atomicArithmeticOpXor :
newVal = old ^ arg
case atomicArithmeticOpNop :
newVal = arg
}
memoryInst .WriteUint16Le (offset , newVal )
memoryInst .Mux .Unlock ()
ce .pushValue (uint64 (old ))
frame .pc ++
case operationKindAtomicRMWCmpxchg :
rep := ce .popValue ()
exp := ce .popValue ()
offset := ce .popMemoryOffset (op )
switch unsignedType (op .B1 ) {
case unsignedTypeI32 :
if offset %4 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
old , ok := memoryInst .ReadUint32Le (offset )
if !ok {
memoryInst .Mux .Unlock ()
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if old == uint32 (exp ) {
memoryInst .WriteUint32Le (offset , uint32 (rep ))
}
memoryInst .Mux .Unlock ()
ce .pushValue (uint64 (old ))
case unsignedTypeI64 :
if offset %8 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
old , ok := memoryInst .ReadUint64Le (offset )
if !ok {
memoryInst .Mux .Unlock ()
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if old == exp {
memoryInst .WriteUint64Le (offset , rep )
}
memoryInst .Mux .Unlock ()
ce .pushValue (old )
}
frame .pc ++
case operationKindAtomicRMW8Cmpxchg :
rep := byte (ce .popValue ())
exp := byte (ce .popValue ())
offset := ce .popMemoryOffset (op )
memoryInst .Mux .Lock ()
old , ok := memoryInst .ReadByte (offset )
if !ok {
memoryInst .Mux .Unlock ()
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if old == exp {
memoryInst .WriteByte (offset , rep )
}
memoryInst .Mux .Unlock ()
ce .pushValue (uint64 (old ))
frame .pc ++
case operationKindAtomicRMW16Cmpxchg :
rep := uint16 (ce .popValue ())
exp := uint16 (ce .popValue ())
offset := ce .popMemoryOffset (op )
if offset %2 != 0 {
panic (wasmruntime .ErrRuntimeUnalignedAtomic )
}
memoryInst .Mux .Lock ()
old , ok := memoryInst .ReadUint16Le (offset )
if !ok {
memoryInst .Mux .Unlock ()
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
if old == exp {
memoryInst .WriteUint16Le (offset , rep )
}
memoryInst .Mux .Unlock ()
ce .pushValue (uint64 (old ))
frame .pc ++
case operationKindTailCallReturnCall :
f := &functions [op .U1 ]
ce .dropForTailCall (frame , f )
body , bodyLen = ce .resetPc (frame , f )
case operationKindTailCallReturnCallIndirect :
offset := ce .popValue ()
table := tables [op .U2 ]
tf := ce .functionForOffset (table , offset , typeIDs [op .U1 ])
if tf .moduleInstance != f .moduleInstance {
ce .callFunction (ctx , f .moduleInstance , tf )
ce .drop (op .Us [0 ])
frame .pc = op .Us [1 ]
continue
}
ce .dropForTailCall (frame , tf )
body , bodyLen = ce .resetPc (frame , tf )
default :
frame .pc ++
}
}
ce .popFrame ()
}
func (ce *callEngine ) dropForTailCall (frame *callFrame , f *function ) {
base := frame .base - frame .f .funcType .ParamNumInUint64
paramCount := f .funcType .ParamNumInUint64
ce .stack = append (ce .stack [:base ], ce .stack [len (ce .stack )-paramCount :]...)
}
func (ce *callEngine ) resetPc (frame *callFrame , f *function ) (body []unionOperation , bodyLen uint64 ) {
frame .f = f
frame .base = len (ce .stack )
frame .pc = 0
body = frame .f .parent .body
bodyLen = uint64 (len (body ))
return body , bodyLen
}
func (ce *callEngine ) functionForOffset (table *wasm .TableInstance , offset uint64 , expectedTypeID wasm .FunctionTypeID ) *function {
if offset >= uint64 (len (table .References )) {
panic (wasmruntime .ErrRuntimeInvalidTableAccess )
}
rawPtr := table .References [offset ]
if rawPtr == 0 {
panic (wasmruntime .ErrRuntimeInvalidTableAccess )
}
tf := functionFromUintptr (rawPtr )
if tf .typeID != expectedTypeID {
panic (wasmruntime .ErrRuntimeIndirectCallTypeMismatch )
}
return tf
}
func wasmCompatMax32bits(v1 , v2 uint32 ) uint64 {
return uint64 (math .Float32bits (moremath .WasmCompatMax32 (
math .Float32frombits (v1 ),
math .Float32frombits (v2 ),
)))
}
func wasmCompatMin32bits(v1 , v2 uint32 ) uint64 {
return uint64 (math .Float32bits (moremath .WasmCompatMin32 (
math .Float32frombits (v1 ),
math .Float32frombits (v2 ),
)))
}
func addFloat32bits(v1 , v2 uint32 ) uint64 {
return uint64 (math .Float32bits (math .Float32frombits (v1 ) + math .Float32frombits (v2 )))
}
func subFloat32bits(v1 , v2 uint32 ) uint64 {
return uint64 (math .Float32bits (math .Float32frombits (v1 ) - math .Float32frombits (v2 )))
}
func mulFloat32bits(v1 , v2 uint32 ) uint64 {
return uint64 (math .Float32bits (math .Float32frombits (v1 ) * math .Float32frombits (v2 )))
}
func divFloat32bits(v1 , v2 uint32 ) uint64 {
return uint64 (math .Float32bits (math .Float32frombits (v1 ) / math .Float32frombits (v2 )))
}
func flt32(z1 , z2 float32 ) bool {
if z1 != z1 || z2 != z2 {
return false
} else if z1 == z2 {
return false
} else if math .IsInf (float64 (z1 ), 1 ) {
return false
} else if math .IsInf (float64 (z1 ), -1 ) {
return true
} else if math .IsInf (float64 (z2 ), 1 ) {
return true
} else if math .IsInf (float64 (z2 ), -1 ) {
return false
}
return z1 < z2
}
func flt64(z1 , z2 float64 ) bool {
if z1 != z1 || z2 != z2 {
return false
} else if z1 == z2 {
return false
} else if math .IsInf (z1 , 1 ) {
return false
} else if math .IsInf (z1 , -1 ) {
return true
} else if math .IsInf (z2 , 1 ) {
return true
} else if math .IsInf (z2 , -1 ) {
return false
}
return z1 < z2
}
func i8RoundingAverage(v1 , v2 byte ) byte {
return byte ((uint16 (v1 ) + uint16 (v2 ) + uint16 (1 )) / 2 )
}
func i16RoundingAverage(v1 , v2 uint16 ) uint16 {
return uint16 ((uint32 (v1 ) + uint32 (v2 ) + 1 ) / 2 )
}
func i8Abs(v byte ) byte {
if i := int8 (v ); i < 0 {
return byte (-i )
} else {
return byte (i )
}
}
func i8MaxU(v1 , v2 byte ) byte {
if v1 < v2 {
return v2
} else {
return v1
}
}
func i8MinU(v1 , v2 byte ) byte {
if v1 > v2 {
return v2
} else {
return v1
}
}
func i8MaxS(v1 , v2 byte ) byte {
if int8 (v1 ) < int8 (v2 ) {
return v2
} else {
return v1
}
}
func i8MinS(v1 , v2 byte ) byte {
if int8 (v1 ) > int8 (v2 ) {
return v2
} else {
return v1
}
}
func i16MaxU(v1 , v2 uint16 ) uint16 {
if v1 < v2 {
return v2
} else {
return v1
}
}
func i16MinU(v1 , v2 uint16 ) uint16 {
if v1 > v2 {
return v2
} else {
return v1
}
}
func i16MaxS(v1 , v2 uint16 ) uint16 {
if int16 (v1 ) < int16 (v2 ) {
return v2
} else {
return v1
}
}
func i16MinS(v1 , v2 uint16 ) uint16 {
if int16 (v1 ) > int16 (v2 ) {
return v2
} else {
return v1
}
}
func i32MaxU(v1 , v2 uint32 ) uint32 {
if v1 < v2 {
return v2
} else {
return v1
}
}
func i32MinU(v1 , v2 uint32 ) uint32 {
if v1 > v2 {
return v2
} else {
return v1
}
}
func i32MaxS(v1 , v2 uint32 ) uint32 {
if int32 (v1 ) < int32 (v2 ) {
return v2
} else {
return v1
}
}
func i32MinS(v1 , v2 uint32 ) uint32 {
if int32 (v1 ) > int32 (v2 ) {
return v2
} else {
return v1
}
}
func i16Abs(v uint16 ) uint16 {
if i := int16 (v ); i < 0 {
return uint16 (-i )
} else {
return uint16 (i )
}
}
func i32Abs(v uint32 ) uint32 {
if i := int32 (v ); i < 0 {
return uint32 (-i )
} else {
return uint32 (i )
}
}
func (ce *callEngine ) callNativeFuncWithListener (ctx context .Context , m *wasm .ModuleInstance , f *function , fnl experimental .FunctionListener ) context .Context {
def , typ := f .definition (), f .funcType
ce .stackIterator .reset (ce .stack , ce .frames , f )
fnl .Before (ctx , m , def , ce .peekValues (typ .ParamNumInUint64 ), &ce .stackIterator )
ce .stackIterator .clear ()
ce .callNativeFunc (ctx , m , f )
fnl .After (ctx , m , def , ce .peekValues (typ .ResultNumInUint64 ))
return ctx
}
func (ce *callEngine ) popMemoryOffset (op *unionOperation ) uint32 {
offset := op .U2 + ce .popValue ()
if offset > math .MaxUint32 {
panic (wasmruntime .ErrRuntimeOutOfBoundsMemoryAccess )
}
return uint32 (offset )
}
func (ce *callEngine ) callGoFuncWithStack (ctx context .Context , m *wasm .ModuleInstance , f *function ) {
typ := f .funcType
paramLen := typ .ParamNumInUint64
resultLen := typ .ResultNumInUint64
stackLen := paramLen
if growLen := resultLen - paramLen ; growLen > 0 {
ce .stack = append (ce .stack , make ([]uint64 , growLen )...)
stackLen += growLen
}
stack := ce .stack [len (ce .stack )-stackLen :]
ce .callGoFunc (ctx , m , f , stack )
if shrinkLen := paramLen - resultLen ; shrinkLen > 0 {
ce .stack = ce .stack [0 : len (ce .stack )-shrinkLen ]
}
}
func v128Dot(x1Hi , x1Lo , x2Hi , x2Lo uint64 ) (uint64 , uint64 ) {
r1 := int32 (int16 (x1Lo >>0 )) * int32 (int16 (x2Lo >>0 ))
r2 := int32 (int16 (x1Lo >>16 )) * int32 (int16 (x2Lo >>16 ))
r3 := int32 (int16 (x1Lo >>32 )) * int32 (int16 (x2Lo >>32 ))
r4 := int32 (int16 (x1Lo >>48 )) * int32 (int16 (x2Lo >>48 ))
r5 := int32 (int16 (x1Hi >>0 )) * int32 (int16 (x2Hi >>0 ))
r6 := int32 (int16 (x1Hi >>16 )) * int32 (int16 (x2Hi >>16 ))
r7 := int32 (int16 (x1Hi >>32 )) * int32 (int16 (x2Hi >>32 ))
r8 := int32 (int16 (x1Hi >>48 )) * int32 (int16 (x2Hi >>48 ))
return uint64 (uint32 (r1 +r2 )) | (uint64 (uint32 (r3 +r4 )) << 32 ), uint64 (uint32 (r5 +r6 )) | (uint64 (uint32 (r7 +r8 )) << 32 )
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .